@@ -8,6 +8,7 @@ import { cn } from "@/lib/utils"
88import { BuyMenu } from "@/components/BuyMenu"
99import { WorkflowCalculatorDialog } from "@/components/dialogs/WorkflowCalculatorDialog"
1010import { Slider } from "@/components/ui/Slider"
11+ import { Switch , type SwitchOption } from "@/components/ui/Switch"
1112import { IconCheck } from "@tabler/icons-react"
1213import type { CSSProperties , ReactNode } from "react"
1314import { useState } from "react"
@@ -91,17 +92,10 @@ interface AdditionalFeatureCardProps {
9192 formattedPrice : string
9293}
9394
94- interface PaymentPeriodSwitchProps {
95- content : SubscriptionConfigData [ "paymentPeriod" ]
96- locale : AppLocale
97- value : PaymentPeriod
98- onChange : ( value : PaymentPeriod ) => void
99- }
100-
10195const paymentPeriodOptions = [
102- { value : "monthly" , textKey : "monthlyText" , indicatorClassName : "translate-x-0" } ,
103- { value : "quarterly" , textKey : "quarterlyText" , indicatorClassName : "translate-x-full" } ,
104- { value : "yearly" , textKey : "yearlyText" , indicatorClassName : "translate-x-[200%]" } ,
96+ { value : "monthly" , textKey : "monthlyText" } ,
97+ { value : "quarterly" , textKey : "quarterlyText" } ,
98+ { value : "yearly" , textKey : "yearlyText" } ,
10599] as const
106100
107101function OptionCard ( { title, description, active, onClick, icon, disabled = false , accent = "aqua" } : OptionCardProps ) {
@@ -138,49 +132,6 @@ function OptionCard({ title, description, active, onClick, icon, disabled = fals
138132 )
139133}
140134
141- function PaymentPeriodSwitch ( { content, locale, value, onChange } : PaymentPeriodSwitchProps ) {
142- const activeOption = paymentPeriodOptions . find ( ( option ) => option . value === value ) ?? paymentPeriodOptions [ 0 ]
143-
144- return (
145- < div className = "space-y-3" >
146- < div >
147- < p className = "text-base text-secondary" > { content . label } </ p >
148- < p className = "mt-1 text-sm text-tertiary" > { content . description } </ p >
149- </ div >
150- < div className = "relative grid grid-cols-3 overflow-hidden rounded-2xl border border-white/10 bg-white/3 p-1" >
151- < div
152- className = { cn (
153- "absolute left-1 top-1 h-[calc(100%-0.5rem)] w-[calc((100%-0.5rem)/3)] rounded-xl bg-white/10 transition-transform duration-300 ease-out" ,
154- activeOption . indicatorClassName
155- ) }
156- />
157- { paymentPeriodOptions . map ( ( option ) => {
158- const active = value === option . value
159- const discount = getPaymentPeriodDiscount ( option . value , content )
160-
161- return (
162- < button
163- key = { option . value }
164- type = "button"
165- onClick = { ( ) => onChange ( option . value ) }
166- className = { cn ( "relative z-10 min-w-0 rounded-xl px-3 py-2 text-sm font-medium transition-colors" , active ? "text-white" : "text-secondary hover:text-white" ) }
167- >
168- < span className = "inline-flex min-w-0 items-center justify-center gap-1" >
169- < span className = "min-w-0 truncate" > { content [ option . textKey ] } </ span >
170- { discount > 0 ? (
171- < span className = { cn ( "shrink-0 rounded-full -mt-3 px-1 py-0.5 text-[10px] tracking-wider leading-none bg-brand/15 text-brand" ) } >
172- -{ formatDiscountBadge ( discount , locale ) }
173- </ span >
174- ) : null }
175- </ span >
176- </ button >
177- )
178- } ) }
179- </ div >
180- </ div >
181- )
182- }
183-
184135function FeatureRow ( { icon, title, description } : FeatureRowProps ) {
185136 return (
186137 < div className = "flex flex-col gap-2" >
@@ -282,6 +233,15 @@ export function SubscriptionConfigurator({ locale, content, icons }: { locale: A
282233 const paymentPeriodSuffix = getPaymentPeriodSuffix ( selection . paymentPeriod , content . paymentPeriod )
283234 const totalBeforeDiscount = workflowExecutionPrice + aiTokenPrice + additionalFeaturesPrice
284235 const totalPrice = totalBeforeDiscount * ( 1 - paymentPeriodDiscount )
236+ const paymentPeriodSwitchOptions : SwitchOption < PaymentPeriod > [ ] = paymentPeriodOptions . map ( ( option ) => {
237+ const discount = getPaymentPeriodDiscount ( option . value , content . paymentPeriod )
238+
239+ return {
240+ value : option . value ,
241+ label : content . paymentPeriod [ option . textKey ] ,
242+ badge : discount > 0 ? `-${ formatDiscountBadge ( discount , locale ) } ` : null ,
243+ }
244+ } )
285245
286246 const subscribeHref = ( ( ) => {
287247 const searchParams = new URLSearchParams ( {
@@ -324,9 +284,10 @@ export function SubscriptionConfigurator({ locale, content, icons }: { locale: A
324284 < div className = "relative z-10 flex flex-col gap-8" >
325285 < h2 className = "text-2xl font-semibold text-white lg:text-3xl" > { content . optionsPanelHeading } </ h2 >
326286
327- < PaymentPeriodSwitch
328- content = { content . paymentPeriod }
329- locale = { locale }
287+ < Switch
288+ label = { content . paymentPeriod . label }
289+ description = { content . paymentPeriod . description }
290+ options = { paymentPeriodSwitchOptions }
330291 value = { selection . paymentPeriod }
331292 onChange = { ( paymentPeriod ) => setSelection ( ( current ) => ( { ...current , paymentPeriod } ) ) }
332293 />
0 commit comments