import { Trans, useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { Button, H2Title, IconCalendarEvent, IconCircleX, IconCreditCard, Section, } from 'twenty-ui'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage'; import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import { OnboardingStatus, SubscriptionInterval, useBillingPortalSessionQuery, useUpdateBillingSubscriptionMutation, } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; type SwitchInfo = { newInterval: SubscriptionInterval; to: string; from: string; impact: string; }; export const SettingsBilling = () => { const { t } = useLingui(); const MONTHLY_SWITCH_INFO: SwitchInfo = { newInterval: SubscriptionInterval.Year, to: t`to yearly`, from: t`from monthly to yearly`, impact: t`You will be charged immediately for the full year.`, }; const YEARLY_SWITCH_INFO: SwitchInfo = { newInterval: SubscriptionInterval.Month, to: t`to monthly`, from: t`from yearly to monthly`, impact: t`Your credit balance will be used to pay the monthly bills.`, }; const SWITCH_INFOS = { year: YEARLY_SWITCH_INFO, month: MONTHLY_SWITCH_INFO, }; const { enqueueSnackBar } = useSnackBar(); const onboardingStatus = useOnboardingStatus(); const subscriptionStatus = useSubscriptionStatus(); const currentWorkspace = useRecoilValue(currentWorkspaceState); const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); const switchingInfo = currentWorkspace?.currentBillingSubscription?.interval === SubscriptionInterval.Year ? SWITCH_INFOS.year : SWITCH_INFOS.month; const [isSwitchingIntervalModalOpen, setIsSwitchingIntervalModalOpen] = useState(false); const [updateBillingSubscription] = useUpdateBillingSubscriptionMutation(); const { data, loading } = useBillingPortalSessionQuery({ variables: { returnUrlPath: '/settings/billing', }, }); const billingPortalButtonDisabled = loading || !isDefined(data) || !isDefined(data.billingPortalSession.url); const switchIntervalButtonDisabled = onboardingStatus !== OnboardingStatus.Completed; const cancelPlanButtonDisabled = billingPortalButtonDisabled || onboardingStatus !== OnboardingStatus.Completed; const openBillingPortal = () => { if (isDefined(data) && isDefined(data.billingPortalSession.url)) { window.location.replace(data.billingPortalSession.url); } }; const openSwitchingIntervalModal = () => { setIsSwitchingIntervalModalOpen(true); }; const from = switchingInfo.from; const to = switchingInfo.to; const impact = switchingInfo.impact; const switchInterval = async () => { try { await updateBillingSubscription(); if (isDefined(currentWorkspace?.currentBillingSubscription)) { const newCurrentWorkspace = { ...currentWorkspace, currentBillingSubscription: { ...currentWorkspace?.currentBillingSubscription, interval: switchingInfo.newInterval, }, }; setCurrentWorkspace(newCurrentWorkspace); } enqueueSnackBar(t`Subscription has been switched ${to}`, { variant: SnackBarVariant.Success, }); } catch (error: any) { enqueueSnackBar(t`Error while switching subscription ${to}.`, { variant: SnackBarVariant.Error, }); } }; return ( Workspace, href: getSettingsPagePath(SettingsPath.Workspace), }, { children: Billing }, ]} > {isDefined(subscriptionStatus) && ( <>
)}
); };