@ -1,18 +1,18 @@
'use client'
'use client'
import type { FC } from 'react'
import type { FC , ReactNode } from 'react'
import React from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector '
import { RiApps2Line, RiBook2Line , RiBrain2Line , RiChatAiLine , RiFileEditLine , RiFolder6Line , RiGroupLine , RiHardDrive3Line , RiHistoryLine , RiProgress3Line , RiQuestionLine , RiSeoLine } from '@remixicon/react '
import { Plan } from '../type'
import { Plan } from '../type'
import { ALL_PLANS , NUM_INFINITE , contactSalesUrl , contractSales , unAvailable } from '../config'
import { ALL_PLANS , NUM_INFINITE , contactSalesUrl } from '../config'
import Toast from '../../base/toast'
import Toast from '../../base/toast'
import Tooltip from '../../base/tooltip'
import Tooltip from '../../base/tooltip'
import Divider from '../../base/divider'
import { ArCube1 , Group2 , Keyframe , SparklesSoft } from '../../base/icons/src/public/billing'
import { PlanRange } from './select-plan-range'
import { PlanRange } from './select-plan-range'
import cn from '@/utils/classnames'
import cn from '@/utils/classnames'
import { useAppContext } from '@/context/app-context'
import { useAppContext } from '@/context/app-context'
import { fetchSubscriptionUrls } from '@/service/billing'
import { fetchSubscriptionUrls } from '@/service/billing'
import { LanguagesSupported } from '@/i18n/language'
import I18n from '@/context/i18n'
type Props = {
type Props = {
currentPlan : Plan
currentPlan : Plan
@ -21,45 +21,49 @@ type Props = {
canPay : boolean
canPay : boolean
}
}
const KeyValue = ( { label, value , tooltip } : { label : string ; value : string | number | JSX . Element ; tooltip? : string } ) = > {
const KeyValue = ( { icon, label , tooltip } : { icon : ReactNode ; label : string ; tooltip? : string } ) = > {
return (
return (
< div className = 'mt-3.5 leading-[125%] text-[13px] font-medium' >
< div className = 'flex text-text-tertiary' >
< div className = 'flex items-center text-gray-500 space-x-1' >
< div className = 'size-4 flex items-center justify-center' >
< div > { label } < / div >
{ icon }
< / div >
< div className = 'ml-2 mr-0.5 text-text-primary system-sm-regular' > { label } < / div >
{ tooltip && (
{ tooltip && (
< Tooltip
< Tooltip
popupContent = {
asChild
< div className = 'w-[200px]' > { tooltip } < / div >
popupContent = { tooltip }
}
popupClassName = 'w-[200px]'
/ >
>
) }
< div className = 'size-4 flex items-center justify-center' >
< RiQuestionLine className = 'text-text-secondary' / >
< / div >
< / div >
< div className = 'mt-0.5 text-gray-900' > { value } < / div >
< / Tooltip >
) }
< / div >
< / div >
)
)
}
}
const priceClassName = 'leading-[ 32px] text-[28px] font-bold text-gray-900 '
const priceClassName = 'leading-[ 125%] text-[28px] font-bold text-text-primary '
const style = {
const style = {
[ Plan . sandbox ] : {
[ Plan . sandbox ] : {
bg: 'bg-[#F2F4F7]' ,
icon: < ArCube1 className = 'text-text-primary size-7' / > ,
title: 'text-gray-9 00',
description: 'text-util-colors-gray-gray-6 00',
hoverAndActive: ' ',
btnStyle: 'bg-components-button-secondary-bg hover:bg-components-button-secondary-bg-hover border-[0.5px] border-components-button-secondary-border text-text-primary ',
} ,
} ,
[ Plan . professional ] : {
[ Plan . professional ] : {
bg: 'bg-[#E0F2FE]' ,
icon: < Keyframe className = 'text-util-colors-blue-brand-blue-brand-600 size-7' / > ,
title: 'text-[#026AA2] ',
description: 'text-util-colors-blue-brand-blue-brand-600 ',
hoverAndActive: 'hover:shadow-lg hover:!text-white hover:!bg-[#0086C9] hover:!border-[#026AA2] active:!text-white active:!bg-[#026AA2] active:!border-[#026AA2] ',
btnStyle: 'bg-components-button-primary-bg hover:bg-components-button-primary-bg-hover border border-component-button-primary-border text-components-button-primary-text ',
} ,
} ,
[ Plan . team ] : {
[ Plan . team ] : {
bg: 'bg-[#E0EAFF]' ,
icon: < Group2 className = 'text-util-colors-indigo-indigo-600 size-7' / > ,
title: 'text-[#3538CD] ',
description: 'text-util-colors-indigo-indigo-600 ',
hoverAndActive: 'hover:shadow-lg hover:!text-white hover:!bg-[#444CE7] hover:!border-[#3538CD] active:!text-white active:!bg-[#3538CD] active:!border-[#3538CD] ',
btnStyle: 'bg-components-button-indigo-bg hover:bg-components-button-indigo-bg-hover border border-components-button-primary-border text-components-button-primary-text ',
} ,
} ,
[ Plan . enterprise ] : {
[ Plan . enterprise ] : {
bg: 'bg-[#FFEED 3]',
icon: 'text-[#DC680 3]',
title: 'text-[#DC6803] ',
description: ' ',
hoverAndActiv e: 'hover:shadow-lg hover:!text-white hover:!bg-[#F79009] hover:!border-[#DC6803] active:!text-white active:!bg-[#DC6803] active:!border-[#DC6803]' ,
btnStyl e: 'hover:shadow-lg hover:!text-white hover:!bg-[#F79009] hover:!border-[#DC6803] active:!text-white active:!bg-[#DC6803] active:!border-[#DC6803]' ,
} ,
} ,
}
}
const PlanItem : FC < Props > = ( {
const PlanItem : FC < Props > = ( {
@ -69,9 +73,9 @@ const PlanItem: FC<Props> = ({
canPay ,
canPay ,
} ) = > {
} ) = > {
const { t } = useTranslation ( )
const { t } = useTranslation ( )
const { locale } = useContext ( I18n )
// const { locale } = useContext(I18n)
const isZh = locale === LanguagesSupported [ 1 ]
// const isZh = locale === LanguagesSupported[1]
const [ loading , setLoading ] = React . useState ( false )
const [ loading , setLoading ] = React . useState ( false )
const i18nPrefix = ` billing.plans. ${ plan } `
const i18nPrefix = ` billing.plans. ${ plan } `
const isFreePlan = plan === Plan . sandbox
const isFreePlan = plan === Plan . sandbox
@ -82,13 +86,13 @@ const PlanItem: FC<Props> = ({
const isCurrent = plan === currentPlan
const isCurrent = plan === currentPlan
const isPlanDisabled = planInfo . level <= ALL_PLANS [ currentPlan ] . level || ( ! canPay && plan !== Plan . enterprise )
const isPlanDisabled = planInfo . level <= ALL_PLANS [ currentPlan ] . level || ( ! canPay && plan !== Plan . enterprise )
const { isCurrentWorkspaceManager } = useAppContext ( )
const { isCurrentWorkspaceManager } = useAppContext ( )
const messagesRequest = ( ( ) = > {
// const messagesRequest = (() => {
const value = planInfo . messageRequest [ isZh ? 'zh' : 'en' ]
// const value = planInfo.messageRequest[isZh ? 'zh' : 'en']
if ( value === contractSales )
// if (value === contractSales)
return t ( 'billing.plansCommon.contractSales' )
// return t('billing.plansCommon.contractSales')
return value
// return value
} ) ( )
// })()
const btnText = ( ( ) = > {
const btnText = ( ( ) = > {
if ( ! canPay && plan !== Plan . enterprise )
if ( ! canPay && plan !== Plan . enterprise )
return t ( 'billing.plansCommon.contractOwner' )
return t ( 'billing.plansCommon.contractOwner' )
@ -98,85 +102,85 @@ const PlanItem: FC<Props> = ({
return ( {
return ( {
[ Plan . sandbox ] : t ( 'billing.plansCommon.startForFree' ) ,
[ Plan . sandbox ] : t ( 'billing.plansCommon.startForFree' ) ,
[ Plan . professional ] : < > { t ( 'billing.plansCommon.getStarted With ') } < span className = 'capitalize' > & nbsp ; { plan } < / span > < / > ,
[ Plan . professional ] : t ( 'billing.plansCommon.getStarted ') ,
[ Plan . team ] : < > { t ( 'billing.plansCommon.getStarted With ') } < span className = 'capitalize' > & nbsp ; { plan } < / span > < / > ,
[ Plan . team ] : t ( 'billing.plansCommon.getStarted ') ,
[ Plan . enterprise ] : t ( 'billing.plansCommon.talkToSales' ) ,
[ Plan . enterprise ] : t ( 'billing.plansCommon.talkToSales' ) ,
} ) [ plan ]
} ) [ plan ]
} ) ( )
} ) ( )
const comingSoon = (
// const comingSoon = (
< div className = 'leading-[12px] text-[9px] font-semibold text-[#3538CD] uppercase' > { t ( 'billing.plansCommon.comingSoon' ) } < / div >
// <div className='leading-[12px] text-[9px] font-semibold text-[#3538CD] uppercase'>{t('billing.plansCommon.comingSoon')}</div>
)
// )
const supportContent = ( ( ) = > {
// const supportContent = (() => {
switch ( plan ) {
// switch (plan) {
case Plan . sandbox :
// case Plan.sandbox:
return ( < div className = 'space-y-3.5' >
// return (<div className='space-y-3.5'>
< div > { t ( 'billing.plansCommon.supportItems.communityForums' ) } < / div >
// <div>{t('billing.plansCommon.supportItems.communityForums')}</div>
< div > { t ( 'billing.plansCommon.supportItems.agentMode' ) } < / div >
// <div>{t('billing.plansCommon.supportItems.agentMode')}</div>
< div className = 'flex items-center space-x-1' >
// <div className='flex items-center space-x-1'>
< div className = 'flex items-center' >
// <div className='flex items-center'>
< div className = 'mr-0.5' > & nbsp ; { t ( 'billing.plansCommon.supportItems.workflow' ) } < / div >
// <div className='mr-0.5'> {t('billing.plansCommon.supportItems.workflow')}</div>
< / div >
// </div>
< / div >
// </div>
< / div > )
// </div>)
case Plan . professional :
// case Plan.professional:
return (
// return (
< div >
// <div>
< div > { t ( 'billing.plansCommon.supportItems.emailSupport' ) } < / div >
// <div>{t('billing.plansCommon.supportItems.emailSupport')}</div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div > + { t ( 'billing.plansCommon.supportItems.logoChange' ) } < / div >
// <div>+ {t( 'billing.plansCommon.supportItems.logoChange')}</div>
< / div >
// </div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div > + { t ( 'billing.plansCommon.supportItems.bulkUpload' ) } < / div >
// <div>+ {t( 'billing.plansCommon.supportItems.bulkUpload')}</div>
< / div >
// </div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< span > + < / span >
// <span>+ </span>
< div > { t ( 'billing.plansCommon.supportItems.llmLoadingBalancing' ) } < / div >
// <div>{t('billing.plansCommon.supportItems.llmLoadingBalancing')}</div>
< Tooltip
// <Tooltip
popupContent = {
// popupContent={
< div className = 'w-[200px]' > { t ( 'billing.plansCommon.supportItems.llmLoadingBalancingTooltip' ) } < / div >
// <div className='w-[200px]'>{t('billing.plansCommon.supportItems.llmLoadingBalancingTooltip')}</div>
}
// }
/ >
// />
< / div >
// </div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div className = 'flex items-center' >
// <div className='flex items-center'>
+
// +
< div className = 'mr-0.5' > & nbsp ; { t ( 'billing.plansCommon.supportItems.ragAPIRequest' ) } < / div >
// <div className='mr-0.5'> {t('billing.plansCommon.supportItems.ragAPIRequest')}</div>
< Tooltip
// <Tooltip
popupContent = {
// popupContent={
< div className = 'w-[200px]' > { t ( 'billing.plansCommon.ragAPIRequestTooltip' ) } < / div >
// <div className='w-[200px]'>{t('billing.plansCommon.ragAPIRequestTooltip')}</div>
}
// }
/ >
// />
< / div >
// </div>
< div > { comingSoon } < / div >
// <div>{comingSoon}</div>
< / div >
// </div>
< / div >
// </div>
)
// )
case Plan . team :
// case Plan.team:
return (
// return (
< div >
// <div>
< div > { t ( 'billing.plansCommon.supportItems.priorityEmail' ) } < / div >
// <div>{t('billing.plansCommon.supportItems.priorityEmail')}</div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div > + { t ( 'billing.plansCommon.supportItems.SSOAuthentication' ) } < / div >
// <div>+ {t( 'billing.plansCommon.supportItems.SSOAuthentication')}</div>
< div > { comingSoon } < / div >
// <div>{comingSoon}</div>
< / div >
// </div>
< / div >
// </div>
)
// )
case Plan . enterprise :
// case Plan.enterprise:
return (
// return (
< div >
// <div>
< div > { t ( 'billing.plansCommon.supportItems.personalizedSupport' ) } < / div >
// <div>{t( 'billing.plansCommon.supportItems.personalizedSupport')}</div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div > + { t ( 'billing.plansCommon.supportItems.dedicatedAPISupport' ) } < / div >
// <div>+ {t( 'billing.plansCommon.supportItems.dedicatedAPISupport')}</div>
< / div >
// </div>
< div className = 'mt-3.5 flex items-center space-x-1' >
// <div className='mt-3.5 flex items-center space-x-1'>
< div > + { t ( 'billing.plansCommon.supportItems.customIntegration' ) } < / div >
// <div>+ {t( 'billing.plansCommon.supportItems.customIntegration')}</div>
< / div >
// </div>
< / div >
// </div>
)
// )
default :
// default:
return ''
// return ''
}
// }
} ) ( )
// })()
const handleGetPayUrl = async ( ) = > {
const handleGetPayUrl = async ( ) = > {
if ( loading )
if ( loading )
return
return
@ -211,14 +215,23 @@ const PlanItem: FC<Props> = ({
}
}
}
}
return (
return (
< div className = { cn ( isMostPopularPlan ? 'bg-[#0086C9] p-0.5' : 'pt-7' , 'flex flex-col min-w-[290px] w-[290px] rounded-xl' ) } >
< div className = { cn ( 'flex flex-col w-[373px] p-6 border-[0.5px] border-effects-highlight-lightmode-off bg-background-section-burn rounded-2xl' ,
{ isMostPopularPlan && (
isMostPopularPlan ? 'shadow-lg backdrop-blur-[5px] border-effects-highlight' : 'hover:shadow-lg hover:backdrop-blur-[5px] hover:border-effects-highlight' ,
< div className = 'flex items-center h-7 justify-center leading-[12px] text-xs font-medium text-[#F5F8FF]' > { t ( 'billing.plansCommon.mostPopular' ) } < / div >
) } >
) }
< div className = 'flex flex-col gap-y-1' >
< div className = { cn ( style [ plan ] . bg , 'grow px-6 py-6 rounded-[10px]' ) } >
{ style [ plan ] . icon }
< div className = { cn ( style [ plan ] . title , 'mb-1 leading-[125%] text-lg font-semibold' ) } > { t ( ` ${ i18nPrefix } .name ` ) } < / div >
< div className = 'flex items-center' >
< div className = { cn ( isFreePlan ? 'mb-5 text-[#FB6514]' : 'mb-4 text-gray-500' , 'h-8 leading-[125%] text-[13px] font-normal' ) } > { t ( ` ${ i18nPrefix } .description ` ) } < / div >
< div className = 'leading-[125%] text-lg font-semibold uppercase text-text-primary' > { t ( ` ${ i18nPrefix } .name ` ) } < / div >
{ isMostPopularPlan && < div className = 'ml-1 px-1 py-[3px] flex items-center justify-center rounded-full border-[0.5px] shadow-xs bg-price-premium-badge-background text-components-premium-badge-grey-text-stop-0' >
< div className = 'pl-0.5' >
< SparklesSoft className = 'size-3' / >
< / div >
< span className = 'px-0.5 system-2xs-semibold-uppercase bg-clip-text bg-price-premium-text-background text-transparent' > Popular < / span >
< / div > }
< / div >
< div className = { cn ( style [ plan ] . description , 'system-sm-regular' ) } > { t ( ` ${ i18nPrefix } .description ` ) } < / div >
< / div >
< div className = 'my-5' >
{ /* Price */ }
{ /* Price */ }
{ isFreePlan && (
{ isFreePlan && (
< div className = { priceClassName } > { t ( 'billing.plansCommon.free' ) } < / div >
< div className = { priceClassName } > { t ( 'billing.plansCommon.free' ) } < / div >
@ -227,74 +240,80 @@ const PlanItem: FC<Props> = ({
< div className = { priceClassName } > { t ( 'billing.plansCommon.contactSales' ) } < / div >
< div className = { priceClassName } > { t ( 'billing.plansCommon.contactSales' ) } < / div >
) }
) }
{ ! isFreePlan && ! isEnterprisePlan && (
{ ! isFreePlan && ! isEnterprisePlan && (
< div className = 'flex items-end h-9 '>
< div className = 'flex items-end '>
< div className = { priceClassName } > $ { isYear ? planInfo . price * 10 : planInfo.price } < / div >
< div className = { priceClassName } > $ { isYear ? planInfo . price * 10 : planInfo.price } < / div >
< div className = 'ml-1' >
< div className = 'ml-1 flex flex-col' >
{ isYear && < div className = 'leading-[18px] text-xs font-medium text-[#F26725]' > { t ( 'billing.plansCommon.save' ) } $ { planInfo . price * 2 } < / div > }
{ isYear && < div className = 'leading-[14px] text-[14px] font-normal italic text-text-warning' > { t ( 'billing.plansCommon.save' ) } $ { planInfo . price * 2 } < / div > }
< div className = 'leading-[18px] text-[15px] font-normal text-gray-500' > / { t ( ` billing.plansCommon. ${ ! isYear ? 'month' : 'year' } ` ) } < / div >
< div className = 'leading-normal text-[14px] font-normal text-text-tertiary' >
{ t ( 'billing.plansCommon.priceTip' ) }
{ t ( ` billing.plansCommon. ${ ! isYear ? 'month' : 'year' } ` ) } < / div >
< / div >
< / div >
< / div >
< / div >
) }
) }
< / div >
< div
< div
className = { cn ( isMostPopularPlan && ! isCurrent && '!bg-[#444CE7] !text-white !border !border-[#3538CD] shadow-sm' , isPlanDisabled ? 'opacity-30' : ` ${ style [ plan ] . hoverAndActive } cursor-pointer ` , 'mt-4 flex h-11 items-center justify-center border-[2px] border-gray-900 rounded-3xl text-sm font-semibold text-gray-900' ) }
className = { cn ( 'flex py-3 px-5 rounded-full justify-center items-center h-[42px]' ,
style [ plan ] . btnStyle ,
isPlanDisabled ? 'opacity-30 cursor-not-allowed' : 'cursor-pointer ' ) }
onClick = { handleGetPayUrl }
onClick = { handleGetPayUrl }
>
>
{ btnText }
{ btnText }
< / div >
< / div >
< div className = 'flex flex-col gap-y-3 mt-6' >
< div className = 'my-4 h-[1px] bg-black/5' > < / div >
< div className = 'leading-[125%] text-[13px] font-normal text-gray-900' >
{ t ( ` ${ i18nPrefix } .includesTitle ` ) }
< / div >
< KeyValue
< KeyValue
label = { t ( 'billing.plansCommon.messageRequest.title' ) }
icon = { < RiChatAiLine / > }
value = { messagesRequest }
label = { isFreePlan
? t ( 'billing.plansCommon.messageRequest.title' , { count : planInfo.messageRequest } )
: t ( 'billing.plansCommon.messageRequest.titlePerMonth' , { count : planInfo.messageRequest } ) }
tooltip = { t ( 'billing.plansCommon.messageRequest.tooltip' ) as string }
tooltip = { t ( 'billing.plansCommon.messageRequest.tooltip' ) as string }
/ >
/ >
< KeyValue
< KeyValue
icon = { < RiBrain2Line / > }
label = { t ( 'billing.plansCommon.modelProviders' ) }
label = { t ( 'billing.plansCommon.modelProviders' ) }
value = { planInfo . modelProviders }
/ >
/ >
< KeyValue
< KeyValue
label= { t ( 'billing.plansCommon.teamMembers' ) }
icon= { < RiFolder6Line / > }
value= { planInfo . teamMembers === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : planInfo . teamMembers }
label= { t ( 'billing.plansCommon.teamWorkspace' , { count : planInfo.teamWorkspace } ) }
/ >
/ >
< KeyValue
< KeyValue
label= { t ( 'billing.plansCommon.buildApps' ) }
icon= { < RiGroupLine / > }
value= { planInfo . buildApps === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : planInfo . buildApps }
label= { t ( 'billing.plansCommon.teamMember' , { count : planInfo.teamMembers } ) }
/ >
/ >
< KeyValue
< KeyValue
label = { t ( 'billing.plansCommon.vectorSpace' ) }
icon = { < RiApps2Line / > }
value = { planInfo . vectorSpace === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : ( planInfo . vectorSpace >= 1000 ? ` ${ planInfo . vectorSpace / 1000 } G ` : ` ${ planInfo . vectorSpace } MB ` ) }
label = { t ( 'billing.plansCommon.buildApps' , { count : planInfo.buildApps } ) }
tooltip = { t ( 'billing.plansCommon.vectorSpaceBillingTooltip' ) as string }
/ >
/ >
< Divider bgStyle = 'gradient' / >
< KeyValue
< KeyValue
label = { t ( 'billing.plansCommon.documentsUploadQuota' ) }
icon = { < RiBook2Line / > }
value = { planInfo . vectorSpace === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : planInfo . documentsUploadQuota }
label = { t ( 'billing.plansCommon.documents' , { count : planInfo.documents } ) }
tooltip = { t ( 'billing.plansCommon.documentsTooltip' ) as string }
/ >
/ >
< KeyValue
< KeyValue
label = { t ( 'billing.plansCommon.documentProcessingPriority' ) }
icon = { < RiHardDrive3Line / > }
value = { t ( ` billing.plansCommon.priority. ${ planInfo . documentProcessingPriority } ` ) as string }
label = { t ( 'billing.plansCommon.vectorSpace' , { size : planInfo.vectorSpace } ) }
tooltip = { t ( 'billing.plansCommon.vectorSpaceTooltip' ) as string }
/ >
/ >
< KeyValue
< KeyValue
label= { t ( 'billing.plansCommon.annotatedResponse.title' ) }
icon= { < RiSeoLine / > }
value= { planInfo . annotatedResponse === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : ` ${ planInfo . annotatedResponse } ` }
label= { t ( 'billing.plansCommon.documentsRequestQuota' , { count : planInfo.documentsRequestQuota } ) }
tooltip = { t ( 'billing.plansCommon. annotatedResponse.t ooltip') as string }
tooltip = { t ( 'billing.plansCommon. documentsRequestQuotaT ooltip') as string }
/ >
/ >
< KeyValue
< KeyValue
label= { t ( 'billing.plansCommon.logsHistory' ) }
icon= { < RiProgress3Line / > }
value= { planInfo . logHistory === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : ` ${ planInfo . logHistory } ${ t ( 'billing.plansCommon.days' ) } ` }
label= { [ t ( ` billing.plansCommon.priority. ${ planInfo . documentProcessingPriority } ` ) , t ( 'billing.plansCommon.documentProcessingPriority' ) ] . join ( ' ' ) }
/ >
/ >
< Divider bgStyle = 'gradient' / >
< KeyValue
< KeyValue
label = { t ( 'billing.plansCommon.customTools' ) }
icon = { < RiFileEditLine / > }
value = { planInfo . customTools === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : ( planInfo . customTools === unAvailable ? t ( 'billing.plansCommon.unavailable' ) as string : ` ${ planInfo . customTools } ` ) }
label = { t ( 'billing.plansCommon.annotatedResponse.title' , { count : planInfo.annotatedResponse } ) }
tooltip = { t ( 'billing.plansCommon.annotatedResponse.tooltip' ) as string }
/ >
/ >
< KeyValue
< KeyValue
label= { t ( 'billing.plansCommon.support' ) }
icon= { < RiHistoryLine / > }
value= { supportContent }
label= { t ( 'billing.plansCommon.logsHistory' , { days : planInfo.logHistory === NUM_INFINITE ? t ( 'billing.plansCommon.unlimited' ) as string : ` ${ planInfo . logHistory } ${ t ( 'billing.plansCommon.days' ) } ` } ) }
/ >
/ >
< / div >
< / div >
< / div >
< / div >