'use client' import type { FC } from 'react' import type { BasicPlan } from '../../../type' import * as React from 'react' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useAppContext } from '@/context/app-context' import { useAsyncWindowOpen } from '@/hooks/use-async-window-open' import { fetchBillingUrl, fetchSubscriptionUrls } from '@/service/billing' import Toast from '../../../../base/toast' import { ALL_PLANS } from '../../../config' import { Plan } from '../../../type' import { Professional, Sandbox, Team } from '../../assets' import { PlanRange } from '../../plan-switcher/plan-range-switcher' import Button from './button' import List from './list' const ICON_MAP = { [Plan.sandbox]: , [Plan.professional]: , [Plan.team]: , } type CloudPlanItemProps = { currentPlan: BasicPlan plan: BasicPlan planRange: PlanRange canPay: boolean } const CloudPlanItem: FC = ({ plan, currentPlan, planRange, }) => { const { t } = useTranslation() const [loading, setLoading] = React.useState(false) const i18nPrefix = `billing.plans.${plan}` const isFreePlan = plan === Plan.sandbox const isMostPopularPlan = plan === Plan.professional const planInfo = ALL_PLANS[plan] const isYear = planRange === PlanRange.yearly const isCurrent = plan === currentPlan const isCurrentPaidPlan = isCurrent && !isFreePlan const isPlanDisabled = isCurrentPaidPlan ? false : planInfo.level <= ALL_PLANS[currentPlan].level const { isCurrentWorkspaceManager } = useAppContext() const openAsyncWindow = useAsyncWindowOpen() const btnText = useMemo(() => { if (isCurrent) return t('billing.plansCommon.currentPlan') return ({ [Plan.sandbox]: t('billing.plansCommon.startForFree'), [Plan.professional]: t('billing.plansCommon.startBuilding'), [Plan.team]: t('billing.plansCommon.getStarted'), })[plan] }, [isCurrent, plan, t]) const handleGetPayUrl = async () => { if (loading) return if (isPlanDisabled) return if (!isCurrentWorkspaceManager) { Toast.notify({ type: 'error', message: t('billing.buyPermissionDeniedTip'), className: 'z-[1001]', }) return } setLoading(true) try { if (isCurrentPaidPlan) { await openAsyncWindow(async () => { const res = await fetchBillingUrl() if (res.url) return res.url throw new Error('Failed to open billing page') }, { onError: (err) => { Toast.notify({ type: 'error', message: err.message || String(err) }) }, }) return } if (isFreePlan) return const res = await fetchSubscriptionUrls(plan, isYear ? 'year' : 'month') // Adb Block additional tracking block the gtag, so we need to redirect directly window.location.href = res.url } finally { setLoading(false) } } return (
{ICON_MAP[plan]}
{t(`${i18nPrefix}.name` as any) as string}
{ isMostPopularPlan && (
{t('billing.plansCommon.mostPopular')}
) }
{t(`${i18nPrefix}.description` as any) as string}
{/* Price */}
{isFreePlan && ( {t('billing.plansCommon.free')} )} {!isFreePlan && ( <> {isYear && ( $ {planInfo.price * 12} )} $ {isYear ? planInfo.price * 10 : planInfo.price} {t('billing.plansCommon.priceTip')} {t(`billing.plansCommon.${!isYear ? 'month' : 'year'}`)} )}
) } export default React.memo(CloudPlanItem)