Update billing page ctas (#12459)
## Before  ## After <img width="1056" alt="image" src="https://github.com/user-attachments/assets/4a51b7c7-898b-485f-95e8-97911292f2b1" /> <img width="1299" alt="image" src="https://github.com/user-attachments/assets/44e5e545-a660-455a-91be-3b139ccb9f30" /> <img width="1180" alt="image" src="https://github.com/user-attachments/assets/0ca765a7-1d9a-473a-b7d2-c6f9b1a72417" /> <img width="963" alt="image" src="https://github.com/user-attachments/assets/b620fd8a-61c9-4dd3-a3b1-e4ba940371e4" /> <img width="863" alt="image" src="https://github.com/user-attachments/assets/a0d2dcb5-19e5-4f83-80d4-ad5a715f1e5f" /> --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { HttpResponse, graphql } from 'msw';
|
||||
|
||||
import { BILLING_BASE_PRODUCT_PRICES } from '@/billing/graphql/billingBaseProductPrices';
|
||||
import { BILLING_BASE_PRODUCT_PRICES } from '@/billing/graphql/queries/billingBaseProductPrices';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import {
|
||||
|
||||
@ -1,56 +1,41 @@
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { SettingsBillingMonthlyCreditsSection } from '@/billing/components/SettingsBillingMonthlyCreditsSection';
|
||||
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
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 { useModal } from '@/ui/layout/modal/hooks/useModal';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
H2Title,
|
||||
IconCalendarEvent,
|
||||
IconCircleX,
|
||||
IconCreditCard,
|
||||
} from 'twenty-ui/display';
|
||||
import { H2Title, IconCircleX, IconCreditCard } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import {
|
||||
SubscriptionInterval,
|
||||
SubscriptionStatus,
|
||||
useBillingPortalSessionQuery,
|
||||
useSwitchSubscriptionToYearlyIntervalMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
|
||||
const SWITCH_BILLING_INTERVAL_MODAL_ID = 'switch-billing-interval-modal';
|
||||
import { SettingsBillingSubscriptionInfo } from '@/billing/components/SettingsBillingSubscriptionInfo';
|
||||
|
||||
export const SettingsBilling = () => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const { redirect } = useRedirect();
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const subscriptions = currentWorkspace?.billingSubscriptions;
|
||||
|
||||
const hasSubscriptions = (subscriptions?.length ?? 0) > 0;
|
||||
|
||||
const subscriptionStatus = useSubscriptionStatus();
|
||||
|
||||
const hasNotCanceledCurrentSubscription =
|
||||
isDefined(subscriptionStatus) &&
|
||||
subscriptionStatus !== SubscriptionStatus.Canceled;
|
||||
|
||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||
|
||||
const [switchToYearlyInterval] =
|
||||
useSwitchSubscriptionToYearlyIntervalMutation();
|
||||
const { data, loading } = useBillingPortalSessionQuery({
|
||||
variables: {
|
||||
returnUrlPath: '/settings/billing',
|
||||
@ -67,31 +52,6 @@ export const SettingsBilling = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const { openModal } = useModal();
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer
|
||||
title={t`Billing`}
|
||||
@ -104,12 +64,15 @@ export const SettingsBilling = () => {
|
||||
]}
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
{hasNotCanceledCurrentSubscription && (
|
||||
<SettingsBillingSubscriptionInfo />
|
||||
)}
|
||||
{hasNotCanceledCurrentSubscription && (
|
||||
<SettingsBillingMonthlyCreditsSection />
|
||||
)}
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Manage your subscription`}
|
||||
title={t`Manage billing information`}
|
||||
description={t`Edit payment method, see your invoices and more`}
|
||||
/>
|
||||
<Button
|
||||
@ -120,45 +83,23 @@ export const SettingsBilling = () => {
|
||||
disabled={billingPortalButtonDisabled}
|
||||
/>
|
||||
</Section>
|
||||
{currentWorkspace?.currentBillingSubscription?.interval ===
|
||||
SubscriptionInterval.Month && (
|
||||
{hasNotCanceledCurrentSubscription && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Edit billing interval`}
|
||||
description={t`Switch from monthly to yearly`}
|
||||
title={t`Cancel your subscription`}
|
||||
description={t`Your workspace will be disabled`}
|
||||
/>
|
||||
<Button
|
||||
Icon={IconCalendarEvent}
|
||||
title={t`Switch to yearly`}
|
||||
Icon={IconCircleX}
|
||||
title={t`Cancel Plan`}
|
||||
variant="secondary"
|
||||
onClick={() => openModal(SWITCH_BILLING_INTERVAL_MODAL_ID)}
|
||||
disabled={!hasNotCanceledCurrentSubscription}
|
||||
accent="danger"
|
||||
onClick={openBillingPortal}
|
||||
disabled={billingPortalButtonDisabled}
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Cancel your subscription`}
|
||||
description={t`Your workspace will be disabled`}
|
||||
/>
|
||||
<Button
|
||||
Icon={IconCircleX}
|
||||
title={t`Cancel Plan`}
|
||||
variant="secondary"
|
||||
accent="danger"
|
||||
onClick={openBillingPortal}
|
||||
disabled={!hasNotCanceledCurrentSubscription}
|
||||
/>
|
||||
</Section>
|
||||
</SettingsPageContainer>
|
||||
<ConfirmationModal
|
||||
modalId={SWITCH_BILLING_INTERVAL_MODAL_ID}
|
||||
title={t`Switch billing to yearly`}
|
||||
subtitle={t`Are you sure that you want to change your billing interval? You will be charged immediately for the full year.`}
|
||||
onConfirmClick={switchInterval}
|
||||
confirmButtonText={t`Change to yearly`}
|
||||
confirmButtonAccent={'blue'}
|
||||
/>
|
||||
</SubMenuTopBarContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user