import { SubscriptionInfoContainer } from '@/billing/components/SubscriptionInfoContainer'; import { SubscriptionInfoRowContainer } from '@/billing/components/SubscriptionInfoRowContainer'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { formatMonthlyPrices } from '@/billing/utils/formatMonthlyPrices'; 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 { useModal } from '@/ui/layout/modal/hooks/useModal'; import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { Tag } from 'twenty-ui/components'; import { H2Title, IconArrowUp, IconCalendarEvent, IconTag, IconUsers, } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { BillingPlanKey, BillingPlanOutput, BillingProductKey, SubscriptionInterval, SubscriptionStatus, useBillingBaseProductPricesQuery, useSwitchSubscriptionToEnterprisePlanMutation, useSwitchSubscriptionToYearlyIntervalMutation, } from '~/generated-metadata/graphql'; const SWITCH_BILLING_INTERVAL_MODAL_ID = 'switch-billing-interval-modal'; const SWITCH_BILLING_PLAN_MODAL_ID = 'switch-billing-plan-modal'; const StyledSwitchButtonContainer = styled.div` align-items: center; display: flex; gap: ${({ theme }) => theme.spacing(2)}; margin-top: ${({ theme }) => theme.spacing(4)}; `; export const SettingsBillingSubscriptionInfo = () => { const { t } = useLingui(); const { openModal } = useModal(); const { enqueueSnackBar } = useSnackBar(); const subscriptionStatus = useSubscriptionStatus(); const { data: pricesData } = useBillingBaseProductPricesQuery(); const [switchToYearlyInterval] = useSwitchSubscriptionToYearlyIntervalMutation(); const [switchToEnterprisePlan] = useSwitchSubscriptionToEnterprisePlanMutation(); const [currentWorkspace, setCurrentWorkspace] = useRecoilState( currentWorkspaceState, ); const isMonthlyPlan = currentWorkspace?.currentBillingSubscription?.interval === SubscriptionInterval.Month; const isYearlyPlan = currentWorkspace?.currentBillingSubscription?.interval === SubscriptionInterval.Year; const isProPlan = currentWorkspace?.currentBillingSubscription?.metadata['plan'] === BillingPlanKey.PRO; const isEnterprisePlan = currentWorkspace?.currentBillingSubscription?.metadata['plan'] === BillingPlanKey.ENTERPRISE; const canSwitchSubscription = subscriptionStatus !== SubscriptionStatus.PastDue; const planTag = isProPlan ? ( ) : isEnterprisePlan ? ( ) : undefined; const intervalLabel = isMonthlyPlan ? t`Monthly` : isYearlyPlan ? t`Yearly` : undefined; const seats = currentWorkspace?.currentBillingSubscription?.billingSubscriptionItems?.find( (item) => item.billingProduct?.metadata.productKey === BillingProductKey.BASE_PRODUCT, )?.quantity as number | undefined; const baseProductPrices = pricesData?.plans as BillingPlanOutput[]; const formattedPrices = formatMonthlyPrices(baseProductPrices); const yearlyPrice = formattedPrices?.[ currentWorkspace?.currentBillingSubscription?.metadata[ 'plan' ] as BillingPlanKey ]?.[SubscriptionInterval.Year]; const enterprisePrice = formattedPrices?.[BillingPlanKey.ENTERPRISE]?.[ currentWorkspace?.currentBillingSubscription?.interval as | SubscriptionInterval.Month | SubscriptionInterval.Year ]; const switchInterval = async () => { try { await switchToYearlyInterval(); if (isDefined(currentWorkspace?.currentBillingSubscription)) { const newCurrentWorkspace = { ...currentWorkspace, currentBillingSubscription: { ...currentWorkspace?.currentBillingSubscription, interval: SubscriptionInterval.Year, }, }; setCurrentWorkspace(newCurrentWorkspace); } enqueueSnackBar(t`Subscription has been switched to Yearly.`, { variant: SnackBarVariant.Success, }); } catch (error: any) { enqueueSnackBar(t`Error while switching subscription to Yearly.`, { variant: SnackBarVariant.Error, }); } }; const switchPlan = async () => { try { await switchToEnterprisePlan(); if (isDefined(currentWorkspace?.currentBillingSubscription)) { const newCurrentWorkspace = { ...currentWorkspace, currentBillingSubscription: { ...currentWorkspace?.currentBillingSubscription, metadata: { ...currentWorkspace?.currentBillingSubscription.metadata, plan: BillingPlanKey.ENTERPRISE, }, }, }; setCurrentWorkspace(newCurrentWorkspace); } enqueueSnackBar(t`Subscription has been switched to Organization Plan.`, { variant: SnackBarVariant.Success, }); } catch (error: any) { enqueueSnackBar( t`Error while switching subscription to Organization Plan.`, { variant: SnackBarVariant.Error, }, ); } }; return (
{isMonthlyPlan && (
); };