'use client' import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import { Plan } from '../type' import { ALL_PLANS, NUM_INFINITE, contactSalesUrl, contractSales, unAvailable } from '../config' import Toast from '../../base/toast' import Tooltip from '../../base/tooltip' import { PlanRange } from './select-plan-range' import cn from '@/utils/classnames' import { useAppContext } from '@/context/app-context' import { fetchSubscriptionUrls } from '@/service/billing' import { LanguagesSupported } from '@/i18n/language' import I18n from '@/context/i18n' type Props = { currentPlan: Plan plan: Plan planRange: PlanRange canPay: boolean } const KeyValue = ({ label, value, tooltip }: { label: string; value: string | number | JSX.Element; tooltip?: string }) => { return (
{label}
{tooltip && ( {tooltip}
} /> )}
{value}
) } const priceClassName = 'leading-[32px] text-[28px] font-bold text-gray-900' const style = { [Plan.sandbox]: { bg: 'bg-[#F2F4F7]', title: 'text-gray-900', hoverAndActive: '', }, [Plan.professional]: { bg: 'bg-[#E0F2FE]', title: 'text-[#026AA2]', hoverAndActive: 'hover:shadow-lg hover:!text-white hover:!bg-[#0086C9] hover:!border-[#026AA2] active:!text-white active:!bg-[#026AA2] active:!border-[#026AA2]', }, [Plan.team]: { bg: 'bg-[#E0EAFF]', title: 'text-[#3538CD]', hoverAndActive: 'hover:shadow-lg hover:!text-white hover:!bg-[#444CE7] hover:!border-[#3538CD] active:!text-white active:!bg-[#3538CD] active:!border-[#3538CD]', }, [Plan.enterprise]: { bg: 'bg-[#FFEED3]', title: 'text-[#DC6803]', hoverAndActive: 'hover:shadow-lg hover:!text-white hover:!bg-[#F79009] hover:!border-[#DC6803] active:!text-white active:!bg-[#DC6803] active:!border-[#DC6803]', }, } const PlanItem: FC = ({ plan, currentPlan, planRange, canPay, }) => { const { t } = useTranslation() const { locale } = useContext(I18n) const isZh = locale === LanguagesSupported[1] const [loading, setLoading] = React.useState(false) const i18nPrefix = `billing.plans.${plan}` const isFreePlan = plan === Plan.sandbox const isEnterprisePlan = plan === Plan.enterprise const isMostPopularPlan = plan === Plan.professional const planInfo = ALL_PLANS[plan] const isYear = planRange === PlanRange.yearly const isCurrent = plan === currentPlan const isPlanDisabled = planInfo.level <= ALL_PLANS[currentPlan].level || (!canPay && plan !== Plan.enterprise) const { isCurrentWorkspaceManager } = useAppContext() const messagesRequest = (() => { const value = planInfo.messageRequest[isZh ? 'zh' : 'en'] if (value === contractSales) return t('billing.plansCommon.contractSales') return value })() const btnText = (() => { if (!canPay && plan !== Plan.enterprise) return t('billing.plansCommon.contractOwner') if (isCurrent) return t('billing.plansCommon.currentPlan') return ({ [Plan.sandbox]: t('billing.plansCommon.startForFree'), [Plan.professional]: <>{t('billing.plansCommon.getStartedWith')} {plan}, [Plan.team]: <>{t('billing.plansCommon.getStartedWith')} {plan}, [Plan.enterprise]: t('billing.plansCommon.talkToSales'), })[plan] })() const comingSoon = (
{t('billing.plansCommon.comingSoon')}
) const supportContent = (() => { switch (plan) { case Plan.sandbox: return (
{t('billing.plansCommon.supportItems.communityForums')}
{t('billing.plansCommon.supportItems.agentMode')}
 {t('billing.plansCommon.supportItems.workflow')}
) case Plan.professional: return (
{t('billing.plansCommon.supportItems.emailSupport')}
+ {t('billing.plansCommon.supportItems.logoChange')}
+ {t('billing.plansCommon.supportItems.bulkUpload')}
+
{t('billing.plansCommon.supportItems.llmLoadingBalancing')}
{t('billing.plansCommon.supportItems.llmLoadingBalancingTooltip')}
} />
+
 {t('billing.plansCommon.supportItems.ragAPIRequest')}
{t('billing.plansCommon.ragAPIRequestTooltip')}
} />
{comingSoon}
) case Plan.team: return (
{t('billing.plansCommon.supportItems.priorityEmail')}
+ {t('billing.plansCommon.supportItems.SSOAuthentication')}
{comingSoon}
) case Plan.enterprise: return (
{t('billing.plansCommon.supportItems.personalizedSupport')}
+ {t('billing.plansCommon.supportItems.dedicatedAPISupport')}
+ {t('billing.plansCommon.supportItems.customIntegration')}
) default: return '' } })() const handleGetPayUrl = async () => { if (loading) return if (isPlanDisabled) return if (isFreePlan) return if (isEnterprisePlan) { window.location.href = contactSalesUrl return } // Only workspace manager can buy plan if (!isCurrentWorkspaceManager) { Toast.notify({ type: 'error', message: t('billing.buyPermissionDeniedTip'), className: 'z-[1001]', }) return } setLoading(true) try { 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 (
{isMostPopularPlan && (
{t('billing.plansCommon.mostPopular')}
)}
{t(`${i18nPrefix}.name`)}
{t(`${i18nPrefix}.description`)}
{/* Price */} {isFreePlan && (
{t('billing.plansCommon.free')}
)} {isEnterprisePlan && (
{t('billing.plansCommon.contactSales')}
)} {!isFreePlan && !isEnterprisePlan && (
${isYear ? planInfo.price * 10 : planInfo.price}
{isYear &&
{t('billing.plansCommon.save')}${planInfo.price * 2}
}
/{t(`billing.plansCommon.${!isYear ? 'month' : 'year'}`)}
)}
{btnText}
{t(`${i18nPrefix}.includesTitle`)}
= 1000 ? `${planInfo.vectorSpace / 1000}G` : `${planInfo.vectorSpace}MB`)} tooltip={t('billing.plansCommon.vectorSpaceBillingTooltip') as string} />
) } export default React.memo(PlanItem)