@@ -3,33 +3,35 @@ import type { Team } from "@/api/team";
3
3
import { Badge } from "@/components/ui/badge" ;
4
4
import { Button } from "@/components/ui/button" ;
5
5
import { ToolTipLabel } from "@/components/ui/tooltip" ;
6
- import { TrackedLinkTW } from "@/components/ui/tracked-link" ;
7
6
import { 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" ;
9
9
import type React from "react" ;
10
10
import { TEAM_PLANS } from "utils/pricing" ;
11
+ import { useTrack } from "../../../hooks/analytics/useTrack" ;
11
12
import { remainingDays } from "../../../utils/date-utils" ;
12
13
import type { GetBillingCheckoutUrlAction } from "../../actions/billing" ;
14
+ import type { ProductSKU } from "../../lib/billing" ;
13
15
import { CheckoutButton } from "../billing" ;
14
16
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
+ onClick ?: ( ) => void ;
21
+ } & (
22
+ | {
23
+ type : "link" ;
24
+ href : string ;
25
+ }
26
+ | {
27
+ type : "checkout" ;
28
+ }
29
+ ) ;
19
30
20
31
type PricingCardProps = {
21
32
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
- } ;
33
+ billingPlan : keyof typeof TEAM_PLANS ;
34
+ cta ?: PricingCardCta ;
33
35
ctaHint ?: string ;
34
36
highlighted ?: boolean ;
35
37
current ?: boolean ;
@@ -49,13 +51,23 @@ export const PricingCard: React.FC<PricingCardProps> = ({
49
51
const plan = TEAM_PLANS [ billingPlan ] ;
50
52
const isCustomPrice = typeof plan . price === "string" ;
51
53
54
+ const trackEvent = useTrack ( ) ;
52
55
const remainingTrialDays =
53
56
( activeTrialEndsAt ? remainingDays ( activeTrialEndsAt ) : 0 ) || 0 ;
54
57
58
+ const handleCTAClick = ( ) => {
59
+ cta ?. onClick ?.( ) ;
60
+ trackEvent ( {
61
+ category : "account" ,
62
+ label : `${ billingPlan } Plan` ,
63
+ action : "click" ,
64
+ } ) ;
65
+ } ;
66
+
55
67
return (
56
68
< div
57
69
className = { cn (
58
- "z-10 flex w-full flex-col gap-6 rounded-xl border border-border bg-card p-4 md:p-6 " ,
70
+ "z-10 flex w-full flex-col gap-4 rounded-xl border border-border bg-card p-4" ,
59
71
current && "border-blue-500" ,
60
72
highlighted && "border-active-border" ,
61
73
) }
@@ -71,44 +83,27 @@ export const PricingCard: React.FC<PricingCardProps> = ({
71
83
< div className = "flex flex-col gap-5" >
72
84
{ /* Title + Desc */ }
73
85
< div >
74
- < div className = "mb-2 flex flex-row items-center gap-2 " >
86
+ < div className = "mb-1 flex flex-row items-center gap-3 " >
75
87
< h3 className = "font-semibold text-2xl capitalize tracking-tight" >
76
88
{ plan . title }
77
89
</ h3 >
78
90
{ current && < Badge className = "capitalize" > Current plan</ Badge > }
79
91
</ div >
80
- < p className = "max-w-[320px] text-muted-foreground" >
92
+ < p className = "max-w-[320px] text-muted-foreground text-sm " >
81
93
{ plan . description }
82
94
</ p >
83
95
</ div >
84
96
85
97
{ /* Price */ }
86
98
< div className = "flex flex-col gap-0.5" >
87
99
< div className = "flex items-center gap-2" >
88
- < span className = "font-semibold text-3xl text-foreground tracking-tight" >
100
+ < span className = "font-semibold text-2xl text-foreground tracking-tight" >
89
101
${ plan . price }
90
102
</ span >
91
103
92
104
{ ! isCustomPrice && (
93
105
< span className = "text-muted-foreground" > / month</ span >
94
106
) }
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
- ) }
112
107
</ div >
113
108
114
109
{ remainingTrialDays > 0 && (
@@ -124,7 +119,7 @@ export const PricingCard: React.FC<PricingCardProps> = ({
124
119
125
120
< div className = "flex grow flex-col items-start gap-2 text-foreground" >
126
121
{ plan . subTitle && (
127
- < p className = "font-medium text-foreground" > { plan . subTitle } </ p >
122
+ < p className = "font-medium text-foreground text-sm " > { plan . subTitle } </ p >
128
123
) }
129
124
130
125
{ plan . features . map ( ( f ) => (
@@ -134,29 +129,30 @@ export const PricingCard: React.FC<PricingCardProps> = ({
134
129
135
130
{ cta && (
136
131
< div className = "flex flex-col gap-3" >
137
- { billingPlan !== "pro" ? (
132
+ { billingPlanToSkuMap [ billingPlan ] && cta . type === "checkout" && (
138
133
< CheckoutButton
139
134
buttonProps = { {
140
- variant : cta . variant || "outline" ,
141
- className : "gap-2 ",
142
- onClick : cta . onClick ,
135
+ variant : highlighted ? "default" : "outline" ,
136
+ className : highlighted ? undefined : "bg-background ",
137
+ onClick : handleCTAClick ,
143
138
} }
144
139
teamSlug = { teamSlug }
145
- sku = { billingPlan === "starter" ? "plan:starter" : "plan:growth" }
140
+ sku = { billingPlanToSkuMap [ billingPlan ] }
146
141
getBillingCheckoutUrl = { getBillingCheckoutUrl }
147
142
>
148
143
{ cta . title }
149
144
</ 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
- >
145
+ ) }
146
+
147
+ { cta . type === "link" && (
148
+ < Button
149
+ variant = { highlighted ? "default" : "outline" }
150
+ className = { highlighted ? undefined : "bg-background" }
151
+ asChild
152
+ >
153
+ < Link href = { cta . href } target = "_blank" onClick = { handleCTAClick } >
158
154
{ cta . title }
159
- </ TrackedLinkTW >
155
+ </ Link >
160
156
</ Button >
161
157
) }
162
158
@@ -171,6 +167,19 @@ export const PricingCard: React.FC<PricingCardProps> = ({
171
167
) ;
172
168
} ;
173
169
170
+ const billingPlanToSkuMap : Record < Team [ "billingPlan" ] , ProductSKU | undefined > =
171
+ {
172
+ starter : "plan:starter" ,
173
+ growth : "plan:growth" ,
174
+ accelerate : "plan:accelerate" ,
175
+ scale : "plan:scale" ,
176
+ // we can't render checkout buttons for these plans:
177
+ pro : undefined ,
178
+ free : undefined ,
179
+ growth_legacy : undefined ,
180
+ starter_legacy : undefined ,
181
+ } ;
182
+
174
183
type FeatureItemProps = {
175
184
text : string | string [ ] ;
176
185
} ;
0 commit comments