Fix sentry issue (#6719)
https://twenty-v7.sentry.io/issues/5677123076/?environment=prod&project=4507072499810304&query=is%3Aunresolved+issue.priority%3A%5Bhigh%2C+medium%5D&referrer=issue-stream&statsPeriod=7d&stream_index=12 Removes billing section when is_free_access_enabled
This commit is contained in:
@ -3,7 +3,6 @@ import {
|
||||
createBrowserRouter,
|
||||
createRoutesFromElements,
|
||||
Outlet,
|
||||
redirect,
|
||||
Route,
|
||||
RouterProvider,
|
||||
Routes,
|
||||
@ -192,14 +191,12 @@ const createRouter = (
|
||||
path={SettingsPath.AccountsEmails}
|
||||
element={<SettingsAccountsEmails />}
|
||||
/>
|
||||
<Route
|
||||
path={SettingsPath.Billing}
|
||||
element={<SettingsBilling />}
|
||||
loader={() => {
|
||||
if (!isBillingEnabled) return redirect(AppPath.Index);
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
{isBillingEnabled && (
|
||||
<Route
|
||||
path={SettingsPath.Billing}
|
||||
element={<SettingsBilling />}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
path={SettingsPath.WorkspaceMembersPage}
|
||||
element={<SettingsWorkspaceMembers />}
|
||||
@ -324,15 +321,19 @@ const createRouter = (
|
||||
|
||||
export const App = () => {
|
||||
const billing = useRecoilValue(billingState);
|
||||
const isFreeAccessEnabled = useIsFeatureEnabled('IS_FREE_ACCESS_ENABLED');
|
||||
const isCRMMigrationEnabled = useIsFeatureEnabled('IS_CRM_MIGRATION_ENABLED');
|
||||
const isServerlessFunctionSettingsEnabled = useIsFeatureEnabled(
|
||||
'IS_FUNCTION_SETTINGS_ENABLED',
|
||||
);
|
||||
|
||||
const isBillingPageEnabled =
|
||||
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
||||
|
||||
return (
|
||||
<RouterProvider
|
||||
router={createRouter(
|
||||
billing?.isBillingEnabled,
|
||||
isBillingPageEnabled,
|
||||
isCRMMigrationEnabled,
|
||||
isServerlessFunctionSettingsEnabled,
|
||||
)}
|
||||
|
||||
@ -215,6 +215,15 @@ export type ExchangeAuthCode = {
|
||||
refreshToken: AuthToken;
|
||||
};
|
||||
|
||||
export type ExecuteServerlessFunctionInput = {
|
||||
/** Id of the serverless function to execute */
|
||||
id: Scalars['UUID'];
|
||||
/** Payload in JSON format */
|
||||
payload?: InputMaybe<Scalars['JSON']>;
|
||||
/** Version of the serverless function to execute */
|
||||
version?: Scalars['String'];
|
||||
};
|
||||
|
||||
export type FeatureFlag = {
|
||||
__typename?: 'FeatureFlag';
|
||||
id: Scalars['UUID'];
|
||||
@ -287,6 +296,13 @@ export type FullName = {
|
||||
lastName: Scalars['String'];
|
||||
};
|
||||
|
||||
export type GetServerlessFunctionSourceCodeInput = {
|
||||
/** The id of the function. */
|
||||
id: Scalars['ID'];
|
||||
/** The version of the function */
|
||||
version?: Scalars['String'];
|
||||
};
|
||||
|
||||
export type InvalidatePassword = {
|
||||
__typename?: 'InvalidatePassword';
|
||||
/** Boolean that confirms query was dispatched */
|
||||
@ -343,8 +359,9 @@ export type Mutation = {
|
||||
generateJWT: AuthTokens;
|
||||
generateTransientToken: TransientToken;
|
||||
impersonate: Verify;
|
||||
publishServerlessFunction: ServerlessFunction;
|
||||
renewToken: AuthTokens;
|
||||
runWorkflowVersion: WorkflowTriggerResult;
|
||||
runWorkflowVersion: WorkflowRun;
|
||||
sendInviteLink: SendInviteLink;
|
||||
signUp: LoginToken;
|
||||
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||
@ -431,8 +448,7 @@ export type MutationExchangeAuthorizationCodeArgs = {
|
||||
|
||||
|
||||
export type MutationExecuteOneServerlessFunctionArgs = {
|
||||
id: Scalars['UUID'];
|
||||
payload?: InputMaybe<Scalars['JSON']>;
|
||||
input: ExecuteServerlessFunctionInput;
|
||||
};
|
||||
|
||||
|
||||
@ -452,6 +468,11 @@ export type MutationImpersonateArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationPublishServerlessFunctionArgs = {
|
||||
input: PublishServerlessFunctionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRenewTokenArgs = {
|
||||
appToken: Scalars['String'];
|
||||
};
|
||||
@ -594,6 +615,11 @@ export type ProductPricesEntity = {
|
||||
totalNumberOfPrices: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type PublishServerlessFunctionInput = {
|
||||
/** The id of the function. */
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
billingPortalSession: SessionEntity;
|
||||
@ -606,6 +632,7 @@ export type Query = {
|
||||
getAISQLQuery: AisqlQueryResult;
|
||||
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
||||
getProductPrices: ProductPricesEntity;
|
||||
getServerlessFunctionSourceCode: Scalars['String'];
|
||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||
getTimelineThreadsFromCompanyId: TimelineThreadsWithTotal;
|
||||
@ -649,6 +676,11 @@ export type QueryGetProductPricesArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetServerlessFunctionSourceCodeArgs = {
|
||||
input: GetServerlessFunctionSourceCodeInput;
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetTimelineCalendarEventsFromCompanyIdArgs = {
|
||||
companyId: Scalars['UUID'];
|
||||
page: Scalars['Int'];
|
||||
@ -768,9 +800,9 @@ export type ServerlessFunction = {
|
||||
createdAt: Scalars['DateTime'];
|
||||
description?: Maybe<Scalars['String']>;
|
||||
id: Scalars['UUID'];
|
||||
latestVersion?: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
runtime: Scalars['String'];
|
||||
sourceCodeFullPath: Scalars['String'];
|
||||
sourceCodeHash: Scalars['String'];
|
||||
syncStatus: ServerlessFunctionSyncStatus;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
@ -1054,10 +1086,9 @@ export type Verify = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export type WorkflowTriggerResult = {
|
||||
__typename?: 'WorkflowTriggerResult';
|
||||
/** Execution result in JSON format */
|
||||
result?: Maybe<Scalars['JSON']>;
|
||||
export type WorkflowRun = {
|
||||
__typename?: 'WorkflowRun';
|
||||
workflowRunId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type Workspace = {
|
||||
|
||||
@ -33,7 +33,10 @@ export const SettingsNavigationDrawerItems = () => {
|
||||
const isFunctionSettingsEnabled = useIsFeatureEnabled(
|
||||
'IS_FUNCTION_SETTINGS_ENABLED',
|
||||
);
|
||||
const isFreeAccessEnabled = useIsFeatureEnabled('IS_FREE_ACCESS_ENABLED');
|
||||
const isCRMMigrationEnabled = useIsFeatureEnabled('IS_CRM_MIGRATION_ENABLED');
|
||||
const isBillingPageEnabled =
|
||||
billing?.isBillingEnabled && !isFreeAccessEnabled;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -84,7 +87,7 @@ export const SettingsNavigationDrawerItems = () => {
|
||||
path={SettingsPath.WorkspaceMembersPage}
|
||||
Icon={IconUsers}
|
||||
/>
|
||||
{billing?.isBillingEnabled && (
|
||||
{isBillingPageEnabled && (
|
||||
<SettingsNavigationDrawerItem
|
||||
label="Billing"
|
||||
path={SettingsPath.Billing}
|
||||
|
||||
@ -24,7 +24,7 @@ describe('useServerlessFunctionUpdateFormState', () => {
|
||||
);
|
||||
useGetOneServerlessFunctionMock.useGetOneServerlessFunction.mockReturnValue(
|
||||
{
|
||||
serverlessFunction: { sourceCodeFullPath: undefined },
|
||||
serverlessFunction: { name: 'name' },
|
||||
},
|
||||
);
|
||||
const useGetOneServerlessFunctionSourceCodeMock = jest.requireMock(
|
||||
|
||||
@ -7,4 +7,5 @@ export type FeatureFlagKey =
|
||||
| 'IS_FUNCTION_SETTINGS_ENABLED'
|
||||
| 'IS_COPILOT_ENABLED'
|
||||
| 'IS_CRM_MIGRATION_ENABLED'
|
||||
| 'IS_FREE_ACCESS_ENABLED'
|
||||
| 'IS_MESSAGE_THREAD_SUBSCRIBER_ENABLED';
|
||||
|
||||
@ -38,7 +38,6 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
description: '',
|
||||
syncStatus: 'READY',
|
||||
runtime: 'nodejs18.x',
|
||||
sourceCodeFullPath: SOURCE_CODE_FULL_PATH,
|
||||
sourceCodeHash: '42d2734b3dc8a7b45a16803ed7f417bc',
|
||||
updatedAt: '2024-02-24T10:23:10.673Z',
|
||||
createdAt: '2024-02-24T10:23:10.673Z',
|
||||
|
||||
@ -43,7 +43,7 @@ export class BillingResolver {
|
||||
@Args() { returnUrlPath }: BillingSessionInput,
|
||||
) {
|
||||
return {
|
||||
url: await this.billingPortalWorkspaceService.computeBillingPortalSessionURL(
|
||||
url: await this.billingPortalWorkspaceService.computeBillingPortalSessionURLOrThrow(
|
||||
user.defaultWorkspaceId,
|
||||
returnUrlPath,
|
||||
),
|
||||
|
||||
@ -65,18 +65,22 @@ export class BillingPortalWorkspaceService {
|
||||
return session.url;
|
||||
}
|
||||
|
||||
async computeBillingPortalSessionURL(
|
||||
async computeBillingPortalSessionURLOrThrow(
|
||||
workspaceId: string,
|
||||
returnUrlPath?: string,
|
||||
) {
|
||||
const currentSubscriptionItem =
|
||||
const currentSubscription =
|
||||
await this.billingSubscriptionService.getCurrentBillingSubscriptionOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const stripeCustomerId = currentSubscriptionItem.stripeCustomerId;
|
||||
if (!currentSubscription) {
|
||||
throw new Error('Error: missing subscription');
|
||||
}
|
||||
|
||||
const stripeCustomerId = currentSubscription.stripeCustomerId;
|
||||
|
||||
if (!stripeCustomerId) {
|
||||
throw new Error('Error: missing stripeCustomerId');
|
||||
|
||||
Reference in New Issue
Block a user