'use client' import type { FC } from 'react' import { Button } from '@langgenius/dify-ui/button' import { RiBook2Line, RiFileEditLine, RiGroupLine } from '@remixicon/react' import { useUnmountedRef } from 'ahooks' import { useAtomValue } from 'jotai' import * as React from 'react' import { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { ApiAggregate, TriggerAll } from '@/app/components/base/icons/src/vender/workflow' import UsageInfo from '@/app/components/billing/usage-info' import { useSetEducationVerifying } from '@/app/education-apply/storage' import VerifyStateModal from '@/app/education-apply/verify-state-modal' import { IS_CLOUD_EDITION } from '@/config' import { userProfileEmailAtom } from '@/context/account-state' import { useModalContextSelector } from '@/context/modal-context' import { useProviderContext } from '@/context/provider-context' import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state' import { usePathname, useRouter } from '@/next/navigation' import { useEducationVerify } from '@/service/use-education' import { getDaysUntilEndOfMonth } from '@/utils/time' import Loading from '../../base/icons/src/public/thought/Loading' import { NUM_INFINITE } from '../config' import { useEducationDiscount } from '../hooks/use-education-discount' import { Plan, SelfHostedPlan } from '../type' import UpgradeBtn from '../upgrade-btn' import AppsInfo from '../usage-info/apps-info' import VectorSpaceInfo from '../usage-info/vector-space-info' import { Enterprise, Professional, Sandbox, Team } from './assets' type Props = Readonly<{ loc: string }> const PlanComp: FC = ({ loc }) => { const { t } = useTranslation() const router = useRouter() const path = usePathname() const userProfileEmail = useAtomValue(userProfileEmailAtom) const isCurrentWorkspaceManager = useAtomValue(isCurrentWorkspaceManagerAtom) const { plan, enableEducationPlan, allowRefreshEducationVerify, isEducationAccount } = useProviderContext() const isAboutToExpire = allowRefreshEducationVerify const { type } = plan const isEnterprisePlan = String(type) === SelfHostedPlan.enterprise const { usage, total, reset } = plan const triggerEventsResetInDays = type === Plan.professional && total.triggerEvents !== NUM_INFINITE ? (reset.triggerEvents ?? undefined) : undefined const apiRateLimitResetInDays = (() => { if (total.apiRateLimit === NUM_INFINITE) return undefined if (typeof reset.apiRateLimit === 'number') return reset.apiRateLimit if (type === Plan.sandbox) return getDaysUntilEndOfMonth() return undefined })() const [showModal, setShowModal] = React.useState(false) const { handleEducationDiscount, isEducationDiscountLoading } = useEducationDiscount() const { mutateAsync, isPending } = useEducationVerify() const setShowAccountSettingModal = useModalContextSelector((s) => s.setShowAccountSettingModal) const setEducationVerifying = useSetEducationVerifying() const unmountedRef = useUnmountedRef() const handleVerify = () => { if (isPending) return mutateAsync() .then((res) => { setEducationVerifying(null) if (unmountedRef.current) return router.push(`/education-apply?token=${res.token}`) }) .catch(() => { setShowModal(true) }) } useEffect(() => { // setShowAccountSettingModal would prevent navigation if (path.startsWith('/education-apply')) setShowAccountSettingModal(null) }, [path, setShowAccountSettingModal]) return (
{plan.type === Plan.sandbox && } {plan.type === Plan.professional && } {plan.type === Plan.team && } {isEnterprisePlan && }
{t(($) => $[`plans.${type}.name`], { ns: 'billing' })}
{t(($) => $[`plans.${type}.for`], { ns: 'billing' })}
{IS_CLOUD_EDITION && enableEducationPlan && (!isEducationAccount || isAboutToExpire) && ( )} {IS_CLOUD_EDITION && enableEducationPlan && isEducationAccount && type === Plan.sandbox && isCurrentWorkspaceManager && ( )} {IS_CLOUD_EDITION && !isEnterprisePlan && ( )}
{/* Plan detail */}
$['usagePage.teamMembers'], { ns: 'billing' })} usage={usage.teamMembers} total={total.teamMembers} /> $['usagePage.documentsUploadQuota'], { ns: 'billing' })} usage={usage.documentsUploadQuota} total={total.documentsUploadQuota} /> $['usagePage.annotationQuota'], { ns: 'billing' })} usage={usage.annotatedResponse} total={total.annotatedResponse} /> $['usagePage.triggerEvents'], { ns: 'billing' })} usage={usage.triggerEvents} total={total.triggerEvents} tooltip={t(($) => $['plansCommon.triggerEvents.tooltip'], { ns: 'billing' }) as string} resetInDays={triggerEventsResetInDays} /> $['plansCommon.apiRateLimit'], { ns: 'billing' })} usage={usage.apiRateLimit} total={total.apiRateLimit} tooltip={ total.apiRateLimit === NUM_INFINITE ? undefined : (t(($) => $['plansCommon.apiRateLimitTooltip'], { ns: 'billing' }) as string) } resetInDays={apiRateLimitResetInDays} />
$.rejectTitle, { ns: 'education' })} content={t(($) => $.rejectContent, { ns: 'education' })} onConfirm={() => setShowModal(false)} onCancel={() => setShowModal(false)} />
) } export default React.memo(PlanComp)