feat: redirect to Plan Required page if subscription status is not active (#2981)
* feat: redirect to Plan Required page if subscription status is not active Closes #2934 * feat: navigate to Plan Required in PageChangeEffect * feat: add Twenty logo to Plan Required modal * test: add Storybook story * Fix lint --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -77,6 +77,8 @@ export const CreateWorkspace = () => {
|
||||
setCurrentWorkspace({
|
||||
id: result.data?.updateWorkspace?.id ?? '',
|
||||
displayName: data.name,
|
||||
subscriptionStatus:
|
||||
result.data?.updateWorkspace?.subscriptionStatus ?? 'incomplete',
|
||||
allowImpersonation:
|
||||
result.data?.updateWorkspace?.allowImpersonation ?? false,
|
||||
});
|
||||
|
||||
50
packages/twenty-front/src/pages/auth/PlanRequired.tsx
Normal file
50
packages/twenty-front/src/pages/auth/PlanRequired.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { Logo } from '@/auth/components/Logo';
|
||||
import { SubTitle } from '@/auth/components/SubTitle';
|
||||
import { Title } from '@/auth/components/Title';
|
||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { billingState } from '@/client-config/states/billingState';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
|
||||
const StyledButtonContainer = styled.div`
|
||||
margin-top: ${({ theme }) => theme.spacing(8)};
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
export const PlanRequired = () => {
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
const billing = useRecoilValue(billingState);
|
||||
|
||||
const handleButtonClick = () => {
|
||||
billing?.billingUrl && window.location.replace(billing.billingUrl);
|
||||
};
|
||||
|
||||
useScopedHotkeys('enter', handleButtonClick, PageHotkeyScope.PlanRequired, [
|
||||
handleButtonClick,
|
||||
]);
|
||||
|
||||
if (onboardingStatus === OnboardingStatus.Completed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AnimatedEaseIn>
|
||||
<Logo />
|
||||
</AnimatedEaseIn>
|
||||
<Title>Plan required</Title>
|
||||
<SubTitle>
|
||||
Please select a subscription plan before proceeding to sign in.
|
||||
</SubTitle>
|
||||
<StyledButtonContainer>
|
||||
<MainButton title="Get started" onClick={handleButtonClick} fullWidth />
|
||||
</StyledButtonContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,36 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/test';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
|
||||
import { PlanRequired } from '../PlanRequired';
|
||||
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/PlanRequired',
|
||||
component: PlanRequired,
|
||||
decorators: [PageDecorator],
|
||||
args: { routePath: AppPath.PlanRequired },
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
cookie: {
|
||||
tokenPair: '{}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof PlanRequired>;
|
||||
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByRole('button', { name: 'Get started' });
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user