@@ -3,33 +3,36 @@ import type { Team } from "@/api/team";
33import { Badge } from "@/components/ui/badge" ;
44import { Button } from "@/components/ui/button" ;
55import { ToolTipLabel } from "@/components/ui/tooltip" ;
6- import { TrackedLinkTW } from "@/components/ui/tracked-link" ;
76import { cn } from "@/lib/utils" ;
8- import { CheckIcon , CircleAlertIcon , CircleDollarSignIcon } from "lucide-react" ;
7+ import { CheckIcon , CircleDollarSignIcon } from "lucide-react" ;
8+ import Link from "next/link" ;
99import type React from "react" ;
1010import { TEAM_PLANS } from "utils/pricing" ;
11+ import { useTrack } from "../../../hooks/analytics/useTrack" ;
1112import { remainingDays } from "../../../utils/date-utils" ;
1213import type { GetBillingCheckoutUrlAction } from "../../actions/billing" ;
14+ import type { ProductSKU } from "../../lib/billing" ;
1315import { CheckoutButton } from "../billing" ;
1416
15- type ButtonProps = React . ComponentProps < typeof Button > ;
16-
17- const PRO_CONTACT_US_URL =
18- "https://meetings.hubspot.com/sales-thirdweb/thirdweb-pro" ;
17+ type PricingCardCta = {
18+ hint ?: string ;
19+ title : string ;
20+ variant ?: "outline" | "default" ;
21+ onClick ?: ( ) => void ;
22+ } & (
23+ | {
24+ type : "link" ;
25+ href : string ;
26+ }
27+ | {
28+ type : "checkout" ;
29+ }
30+ ) ;
1931
2032type PricingCardProps = {
2133 teamSlug : string ;
22- billingPlan : Exclude < Team [ "billingPlan" ] , "free" > ;
23- cta ?: {
24- hint ?: string ;
25- title : string ;
26- tracking : {
27- category : string ;
28- label ?: string ;
29- } ;
30- variant ?: ButtonProps [ "variant" ] ;
31- onClick ?: ( ) => void ;
32- } ;
34+ billingPlan : keyof typeof TEAM_PLANS ;
35+ cta ?: PricingCardCta ;
3336 ctaHint ?: string ;
3437 highlighted ?: boolean ;
3538 current ?: boolean ;
@@ -49,13 +52,25 @@ export const PricingCard: React.FC<PricingCardProps> = ({
4952 const plan = TEAM_PLANS [ billingPlan ] ;
5053 const isCustomPrice = typeof plan . price === "string" ;
5154
55+ const trackEvent = useTrack ( ) ;
5256 const remainingTrialDays =
5357 ( activeTrialEndsAt ? remainingDays ( activeTrialEndsAt ) : 0 ) || 0 ;
5458
59+ const handleCTAClick = ( ) => {
60+ cta ?. onClick ?.( ) ;
61+ trackEvent ( {
62+ category : "account" ,
63+ label : `${ billingPlan } Plan` ,
64+ action : "click" ,
65+ } ) ;
66+ } ;
67+
68+ const ctaVariant = cta ?. variant || "outline" ;
69+
5570 return (
5671 < div
5772 className = { cn (
58- "z-10 flex w-full flex-col gap-6 rounded-xl border border-border bg-card p-4 md:p-6 " ,
73+ "z-10 flex w-full flex-col gap-4 rounded-xl border border-border bg-card p-4" ,
5974 current && "border-blue-500" ,
6075 highlighted && "border-active-border" ,
6176 ) }
@@ -71,44 +86,27 @@ export const PricingCard: React.FC<PricingCardProps> = ({
7186 < div className = "flex flex-col gap-5" >
7287 { /* Title + Desc */ }
7388 < div >
74- < div className = "mb-2 flex flex-row items-center gap-2 " >
89+ < div className = "mb-1 flex flex-row items-center gap-3 " >
7590 < h3 className = "font-semibold text-2xl capitalize tracking-tight" >
7691 { plan . title }
7792 </ h3 >
7893 { current && < Badge className = "capitalize" > Current plan</ Badge > }
7994 </ div >
80- < p className = "max-w-[320px] text-muted-foreground" >
95+ < p className = "max-w-[320px] text-muted-foreground text-sm " >
8196 { plan . description }
8297 </ p >
8398 </ div >
8499
85100 { /* Price */ }
86101 < div className = "flex flex-col gap-0.5" >
87102 < div className = "flex items-center gap-2" >
88- < span className = "font-semibold text-3xl text-foreground tracking-tight" >
103+ < span className = "font-semibold text-2xl text-foreground tracking-tight" >
89104 ${ plan . price }
90105 </ span >
91106
92107 { ! isCustomPrice && (
93108 < span className = "text-muted-foreground" > / month</ span >
94109 ) }
95-
96- { billingPlan === "starter" && (
97- < ToolTipLabel
98- contentClassName = "max-w-[320px]"
99- label = "We will place a temporary hold of $25 to verify your card, this will be immediately released back to you after verification."
100- >
101- < Button
102- asChild
103- variant = "ghost"
104- className = "h-auto w-auto p-1 text-muted-foreground hover:text-foreground"
105- >
106- < div >
107- < CircleAlertIcon className = "size-5 shrink-0" />
108- </ div >
109- </ Button >
110- </ ToolTipLabel >
111- ) }
112110 </ div >
113111
114112 { remainingTrialDays > 0 && (
@@ -124,7 +122,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
124122
125123 < div className = "flex grow flex-col items-start gap-2 text-foreground" >
126124 { plan . subTitle && (
127- < p className = "font-medium text-foreground" > { plan . subTitle } </ p >
125+ < p className = "font-medium text-foreground text-sm " > { plan . subTitle } </ p >
128126 ) }
129127
130128 { plan . features . map ( ( f ) => (
@@ -134,29 +132,30 @@ export const PricingCard: React.FC<PricingCardProps> = ({
134132
135133 { cta && (
136134 < div className = "flex flex-col gap-3" >
137- { billingPlan !== "pro" ? (
135+ { billingPlanToSkuMap [ billingPlan ] && cta . type === "checkout" && (
138136 < CheckoutButton
139137 buttonProps = { {
140- variant : cta . variant || "outline" ,
141- className : "gap-2" ,
142- onClick : cta . onClick ,
138+ variant : ctaVariant ,
139+ className : cn ( ctaVariant === "outline" && "bg-background" ) ,
140+ onClick : handleCTAClick ,
143141 } }
144142 teamSlug = { teamSlug }
145- sku = { billingPlan === "starter" ? "plan:starter" : "plan:growth" }
143+ sku = { billingPlanToSkuMap [ billingPlan ] }
146144 getBillingCheckoutUrl = { getBillingCheckoutUrl }
147145 >
148146 { cta . title }
149147 </ CheckoutButton >
150- ) : (
151- < Button variant = { cta . variant || "outline" } asChild >
152- < TrackedLinkTW
153- href = { PRO_CONTACT_US_URL }
154- label = { cta . tracking ?. label }
155- category = { cta . tracking ?. category }
156- target = "_blank"
157- >
148+ ) }
149+
150+ { cta . type === "link" && (
151+ < Button
152+ className = { cn ( ctaVariant === "outline" && "bg-background" ) }
153+ variant = { ctaVariant }
154+ asChild
155+ >
156+ < Link href = { cta . href } target = "_blank" onClick = { handleCTAClick } >
158157 { cta . title }
159- </ TrackedLinkTW >
158+ </ Link >
160159 </ Button >
161160 ) }
162161
@@ -171,6 +170,19 @@ export const PricingCard: React.FC<PricingCardProps> = ({
171170 ) ;
172171} ;
173172
173+ const billingPlanToSkuMap : Record < Team [ "billingPlan" ] , ProductSKU | undefined > =
174+ {
175+ starter : "plan:starter" ,
176+ growth : "plan:growth" ,
177+ accelerate : "plan:accelerate" ,
178+ scale : "plan:scale" ,
179+ // we can't render checkout buttons for these plans:
180+ pro : undefined ,
181+ free : undefined ,
182+ growth_legacy : undefined ,
183+ starter_legacy : undefined ,
184+ } ;
185+
174186type FeatureItemProps = {
175187 text : string | string [ ] ;
176188} ;
0 commit comments