mirror of
https://github.com/lingble/twenty.git
synced 2025-11-01 05:07:56 +00:00
5095 move onboardingstatus computation from frontend to backend (#5954)
- move front `onboardingStatus` computing to server side - add logic to `useSetNextOnboardingStatus` - update some missing redirections in `usePageChangeEffectNavigateLocation` - separate subscriptionStatus from onboardingStatus
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/Sn
|
|||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import { App } from '~/App';
|
import { App } from '~/App';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<typeof App> = {
|
const meta: Meta<typeof App> = {
|
||||||
title: 'App/App',
|
title: 'App/App',
|
||||||
@@ -67,9 +67,9 @@ export const DarkMode: Story = {
|
|||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
...mockedUsersData[0],
|
...mockedUserData,
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
...mockedUsersData[0].workspaceMember,
|
...mockedUserData.workspaceMember,
|
||||||
colorScheme: 'Dark',
|
colorScheme: 'Dark',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ export type Analytics = {
|
|||||||
success: Scalars['Boolean']['output'];
|
success: Scalars['Boolean']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiConfig = {
|
||||||
|
__typename?: 'ApiConfig';
|
||||||
|
mutationMaximumAffectedRecords: Scalars['Float']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiKeyToken = {
|
export type ApiKeyToken = {
|
||||||
__typename?: 'ApiKeyToken';
|
__typename?: 'ApiKeyToken';
|
||||||
token: Scalars['String']['output'];
|
token: Scalars['String']['output'];
|
||||||
@@ -98,8 +103,8 @@ export type Billing = {
|
|||||||
export type BillingSubscription = {
|
export type BillingSubscription = {
|
||||||
__typename?: 'BillingSubscription';
|
__typename?: 'BillingSubscription';
|
||||||
id: Scalars['UUID']['output'];
|
id: Scalars['UUID']['output'];
|
||||||
interval?: Maybe<Scalars['String']['output']>;
|
interval?: Maybe<SubscriptionInterval>;
|
||||||
status: Scalars['String']['output'];
|
status: SubscriptionStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BillingSubscriptionFilter = {
|
export type BillingSubscriptionFilter = {
|
||||||
@@ -142,6 +147,7 @@ export enum CaptchaDriverType {
|
|||||||
|
|
||||||
export type ClientConfig = {
|
export type ClientConfig = {
|
||||||
__typename?: 'ClientConfig';
|
__typename?: 'ClientConfig';
|
||||||
|
api: ApiConfig;
|
||||||
authProviders: AuthProviders;
|
authProviders: AuthProviders;
|
||||||
billing: Billing;
|
billing: Billing;
|
||||||
captcha: Captcha;
|
captcha: Captcha;
|
||||||
@@ -398,7 +404,9 @@ export type Mutation = {
|
|||||||
deleteOneRelation: Relation;
|
deleteOneRelation: Relation;
|
||||||
deleteOneRemoteServer: RemoteServer;
|
deleteOneRemoteServer: RemoteServer;
|
||||||
deleteUser: User;
|
deleteUser: User;
|
||||||
|
disablePostgresProxy: PostgresCredentials;
|
||||||
emailPasswordResetLink: EmailPasswordResetLink;
|
emailPasswordResetLink: EmailPasswordResetLink;
|
||||||
|
enablePostgresProxy: PostgresCredentials;
|
||||||
exchangeAuthorizationCode: ExchangeAuthCode;
|
exchangeAuthorizationCode: ExchangeAuthCode;
|
||||||
generateApiKeyToken: ApiKeyToken;
|
generateApiKeyToken: ApiKeyToken;
|
||||||
generateJWT: AuthTokens;
|
generateJWT: AuthTokens;
|
||||||
@@ -451,7 +459,7 @@ export type MutationChallengeArgs = {
|
|||||||
|
|
||||||
|
|
||||||
export type MutationCheckoutSessionArgs = {
|
export type MutationCheckoutSessionArgs = {
|
||||||
recurringInterval: Scalars['String']['input'];
|
recurringInterval: SubscriptionInterval;
|
||||||
successUrlPath?: InputMaybe<Scalars['String']['input']>;
|
successUrlPath?: InputMaybe<Scalars['String']['input']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -636,10 +644,14 @@ export type ObjectFieldsConnection = {
|
|||||||
pageInfo: PageInfo;
|
pageInfo: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Onboarding step */
|
/** Onboarding status */
|
||||||
export enum OnboardingStep {
|
export enum OnboardingStatus {
|
||||||
|
Completed = 'COMPLETED',
|
||||||
InviteTeam = 'INVITE_TEAM',
|
InviteTeam = 'INVITE_TEAM',
|
||||||
SyncEmail = 'SYNC_EMAIL'
|
PlanRequired = 'PLAN_REQUIRED',
|
||||||
|
ProfileCreation = 'PROFILE_CREATION',
|
||||||
|
SyncEmail = 'SYNC_EMAIL',
|
||||||
|
WorkspaceActivation = 'WORKSPACE_ACTIVATION'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnboardingStepSuccess = {
|
export type OnboardingStepSuccess = {
|
||||||
@@ -660,10 +672,18 @@ export type PageInfo = {
|
|||||||
startCursor?: Maybe<Scalars['ConnectionCursor']['output']>;
|
startCursor?: Maybe<Scalars['ConnectionCursor']['output']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PostgresCredentials = {
|
||||||
|
__typename?: 'PostgresCredentials';
|
||||||
|
id: Scalars['UUID']['output'];
|
||||||
|
password: Scalars['String']['output'];
|
||||||
|
user: Scalars['String']['output'];
|
||||||
|
workspaceId: Scalars['String']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type ProductPriceEntity = {
|
export type ProductPriceEntity = {
|
||||||
__typename?: 'ProductPriceEntity';
|
__typename?: 'ProductPriceEntity';
|
||||||
created: Scalars['Float']['output'];
|
created: Scalars['Float']['output'];
|
||||||
recurringInterval: Scalars['String']['output'];
|
recurringInterval: SubscriptionInterval;
|
||||||
stripePriceId: Scalars['String']['output'];
|
stripePriceId: Scalars['String']['output'];
|
||||||
unitAmount: Scalars['Float']['output'];
|
unitAmount: Scalars['Float']['output'];
|
||||||
};
|
};
|
||||||
@@ -688,6 +708,7 @@ export type Query = {
|
|||||||
findManyRemoteServersByType: Array<RemoteServer>;
|
findManyRemoteServersByType: Array<RemoteServer>;
|
||||||
findOneRemoteServerById: RemoteServer;
|
findOneRemoteServerById: RemoteServer;
|
||||||
findWorkspaceFromInviteHash: Workspace;
|
findWorkspaceFromInviteHash: Workspace;
|
||||||
|
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
||||||
getProductPrices: ProductPricesEntity;
|
getProductPrices: ProductPricesEntity;
|
||||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||||
@@ -912,6 +933,24 @@ export enum SortNulls {
|
|||||||
NullsLast = 'NULLS_LAST'
|
NullsLast = 'NULLS_LAST'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionInterval {
|
||||||
|
Day = 'Day',
|
||||||
|
Month = 'Month',
|
||||||
|
Week = 'Week',
|
||||||
|
Year = 'Year'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionStatus {
|
||||||
|
Active = 'Active',
|
||||||
|
Canceled = 'Canceled',
|
||||||
|
Incomplete = 'Incomplete',
|
||||||
|
IncompleteExpired = 'IncompleteExpired',
|
||||||
|
PastDue = 'PastDue',
|
||||||
|
Paused = 'Paused',
|
||||||
|
Trialing = 'Trialing',
|
||||||
|
Unpaid = 'Unpaid'
|
||||||
|
}
|
||||||
|
|
||||||
export type Support = {
|
export type Support = {
|
||||||
__typename?: 'Support';
|
__typename?: 'Support';
|
||||||
supportDriver: Scalars['String']['output'];
|
supportDriver: Scalars['String']['output'];
|
||||||
@@ -1084,7 +1123,7 @@ export type User = {
|
|||||||
firstName: Scalars['String']['output'];
|
firstName: Scalars['String']['output'];
|
||||||
id: Scalars['UUID']['output'];
|
id: Scalars['UUID']['output'];
|
||||||
lastName: Scalars['String']['output'];
|
lastName: Scalars['String']['output'];
|
||||||
onboardingStep?: Maybe<OnboardingStep>;
|
onboardingStatus?: Maybe<OnboardingStatus>;
|
||||||
passwordHash?: Maybe<Scalars['String']['output']>;
|
passwordHash?: Maybe<Scalars['String']['output']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetToken?: Maybe<Scalars['String']['output']>;
|
passwordResetToken?: Maybe<Scalars['String']['output']>;
|
||||||
@@ -1163,7 +1202,6 @@ export type Workspace = {
|
|||||||
id: Scalars['UUID']['output'];
|
id: Scalars['UUID']['output'];
|
||||||
inviteHash?: Maybe<Scalars['String']['output']>;
|
inviteHash?: Maybe<Scalars['String']['output']>;
|
||||||
logo?: Maybe<Scalars['String']['output']>;
|
logo?: Maybe<Scalars['String']['output']>;
|
||||||
subscriptionStatus: Scalars['String']['output'];
|
|
||||||
updatedAt: Scalars['DateTime']['output'];
|
updatedAt: Scalars['DateTime']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ export type Billing = {
|
|||||||
export type BillingSubscription = {
|
export type BillingSubscription = {
|
||||||
__typename?: 'BillingSubscription';
|
__typename?: 'BillingSubscription';
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
interval?: Maybe<Scalars['String']>;
|
interval?: Maybe<SubscriptionInterval>;
|
||||||
status: Scalars['String'];
|
status: SubscriptionStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BillingSubscriptionFilter = {
|
export type BillingSubscriptionFilter = {
|
||||||
@@ -347,7 +347,7 @@ export type MutationChallengeArgs = {
|
|||||||
|
|
||||||
|
|
||||||
export type MutationCheckoutSessionArgs = {
|
export type MutationCheckoutSessionArgs = {
|
||||||
recurringInterval: Scalars['String'];
|
recurringInterval: SubscriptionInterval;
|
||||||
successUrlPath?: InputMaybe<Scalars['String']>;
|
successUrlPath?: InputMaybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -467,10 +467,14 @@ export type ObjectFieldsConnection = {
|
|||||||
pageInfo: PageInfo;
|
pageInfo: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Onboarding step */
|
/** Onboarding status */
|
||||||
export enum OnboardingStep {
|
export enum OnboardingStatus {
|
||||||
|
Completed = 'COMPLETED',
|
||||||
InviteTeam = 'INVITE_TEAM',
|
InviteTeam = 'INVITE_TEAM',
|
||||||
SyncEmail = 'SYNC_EMAIL'
|
PlanRequired = 'PLAN_REQUIRED',
|
||||||
|
ProfileCreation = 'PROFILE_CREATION',
|
||||||
|
SyncEmail = 'SYNC_EMAIL',
|
||||||
|
WorkspaceActivation = 'WORKSPACE_ACTIVATION'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnboardingStepSuccess = {
|
export type OnboardingStepSuccess = {
|
||||||
@@ -502,7 +506,7 @@ export type PostgresCredentials = {
|
|||||||
export type ProductPriceEntity = {
|
export type ProductPriceEntity = {
|
||||||
__typename?: 'ProductPriceEntity';
|
__typename?: 'ProductPriceEntity';
|
||||||
created: Scalars['Float'];
|
created: Scalars['Float'];
|
||||||
recurringInterval: Scalars['String'];
|
recurringInterval: SubscriptionInterval;
|
||||||
stripePriceId: Scalars['String'];
|
stripePriceId: Scalars['String'];
|
||||||
unitAmount: Scalars['Float'];
|
unitAmount: Scalars['Float'];
|
||||||
};
|
};
|
||||||
@@ -684,6 +688,24 @@ export enum SortNulls {
|
|||||||
NullsLast = 'NULLS_LAST'
|
NullsLast = 'NULLS_LAST'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionInterval {
|
||||||
|
Day = 'Day',
|
||||||
|
Month = 'Month',
|
||||||
|
Week = 'Week',
|
||||||
|
Year = 'Year'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionStatus {
|
||||||
|
Active = 'Active',
|
||||||
|
Canceled = 'Canceled',
|
||||||
|
Incomplete = 'Incomplete',
|
||||||
|
IncompleteExpired = 'IncompleteExpired',
|
||||||
|
PastDue = 'PastDue',
|
||||||
|
Paused = 'Paused',
|
||||||
|
Trialing = 'Trialing',
|
||||||
|
Unpaid = 'Unpaid'
|
||||||
|
}
|
||||||
|
|
||||||
export type Support = {
|
export type Support = {
|
||||||
__typename?: 'Support';
|
__typename?: 'Support';
|
||||||
supportDriver: Scalars['String'];
|
supportDriver: Scalars['String'];
|
||||||
@@ -827,7 +849,7 @@ export type User = {
|
|||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
lastName: Scalars['String'];
|
lastName: Scalars['String'];
|
||||||
onboardingStep?: Maybe<OnboardingStep>;
|
onboardingStatus?: Maybe<OnboardingStatus>;
|
||||||
passwordHash?: Maybe<Scalars['String']>;
|
passwordHash?: Maybe<Scalars['String']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetToken?: Maybe<Scalars['String']>;
|
passwordResetToken?: Maybe<Scalars['String']>;
|
||||||
@@ -896,7 +918,6 @@ export type Workspace = {
|
|||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
inviteHash?: Maybe<Scalars['String']>;
|
inviteHash?: Maybe<Scalars['String']>;
|
||||||
logo?: Maybe<Scalars['String']>;
|
logo?: Maybe<Scalars['String']>;
|
||||||
subscriptionStatus: Scalars['String'];
|
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1156,7 +1177,7 @@ export type ImpersonateMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type RenewTokenMutationVariables = Exact<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
appToken: Scalars['String'];
|
appToken: Scalars['String'];
|
||||||
@@ -1188,7 +1209,7 @@ export type VerifyMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type CheckUserExistsQueryVariables = Exact<{
|
export type CheckUserExistsQueryVariables = Exact<{
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@@ -1213,7 +1234,7 @@ export type BillingPortalSessionQueryVariables = Exact<{
|
|||||||
export type BillingPortalSessionQuery = { __typename?: 'Query', billingPortalSession: { __typename?: 'SessionEntity', url?: string | null } };
|
export type BillingPortalSessionQuery = { __typename?: 'Query', billingPortalSession: { __typename?: 'SessionEntity', url?: string | null } };
|
||||||
|
|
||||||
export type CheckoutSessionMutationVariables = Exact<{
|
export type CheckoutSessionMutationVariables = Exact<{
|
||||||
recurringInterval: Scalars['String'];
|
recurringInterval: SubscriptionInterval;
|
||||||
successUrlPath?: InputMaybe<Scalars['String']>;
|
successUrlPath?: InputMaybe<Scalars['String']>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
@@ -1225,7 +1246,7 @@ export type GetProductPricesQueryVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetProductPricesQuery = { __typename?: 'Query', getProductPrices: { __typename?: 'ProductPricesEntity', productPrices: Array<{ __typename?: 'ProductPriceEntity', created: number, recurringInterval: string, stripePriceId: string, unitAmount: number }> } };
|
export type GetProductPricesQuery = { __typename?: 'Query', getProductPrices: { __typename?: 'ProductPricesEntity', productPrices: Array<{ __typename?: 'ProductPriceEntity', created: number, recurringInterval: SubscriptionInterval, stripePriceId: string, unitAmount: number }> } };
|
||||||
|
|
||||||
export type UpdateBillingSubscriptionMutationVariables = Exact<{ [key: string]: never; }>;
|
export type UpdateBillingSubscriptionMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@@ -1242,7 +1263,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]
|
|||||||
|
|
||||||
export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } };
|
export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } };
|
||||||
|
|
||||||
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> };
|
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> };
|
||||||
|
|
||||||
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@@ -1259,7 +1280,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
|
|||||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
||||||
|
|
||||||
export type AddUserToWorkspaceMutationVariables = Exact<{
|
export type AddUserToWorkspaceMutationVariables = Exact<{
|
||||||
inviteHash: Scalars['String'];
|
inviteHash: Scalars['String'];
|
||||||
@@ -1292,7 +1313,7 @@ export type UpdateWorkspaceMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type UpdateWorkspaceMutation = { __typename?: 'Mutation', updateWorkspace: { __typename?: 'Workspace', id: any, domainName?: string | null, displayName?: string | null, logo?: string | null, allowImpersonation: boolean, subscriptionStatus: string } };
|
export type UpdateWorkspaceMutation = { __typename?: 'Mutation', updateWorkspace: { __typename?: 'Workspace', id: any, domainName?: string | null, displayName?: string | null, logo?: string | null, allowImpersonation: boolean } };
|
||||||
|
|
||||||
export type UploadWorkspaceLogoMutationVariables = Exact<{
|
export type UploadWorkspaceLogoMutationVariables = Exact<{
|
||||||
file: Scalars['Upload'];
|
file: Scalars['Upload'];
|
||||||
@@ -1403,7 +1424,7 @@ export const UserQueryFragmentFragmentDoc = gql`
|
|||||||
email
|
email
|
||||||
canImpersonate
|
canImpersonate
|
||||||
supportUserHash
|
supportUserHash
|
||||||
onboardingStep
|
onboardingStatus
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
name {
|
name {
|
||||||
@@ -1421,7 +1442,6 @@ export const UserQueryFragmentFragmentDoc = gql`
|
|||||||
domainName
|
domainName
|
||||||
inviteHash
|
inviteHash
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
subscriptionStatus
|
|
||||||
activationStatus
|
activationStatus
|
||||||
featureFlags {
|
featureFlags {
|
||||||
id
|
id
|
||||||
@@ -2221,7 +2241,7 @@ export type BillingPortalSessionQueryHookResult = ReturnType<typeof useBillingPo
|
|||||||
export type BillingPortalSessionLazyQueryHookResult = ReturnType<typeof useBillingPortalSessionLazyQuery>;
|
export type BillingPortalSessionLazyQueryHookResult = ReturnType<typeof useBillingPortalSessionLazyQuery>;
|
||||||
export type BillingPortalSessionQueryResult = Apollo.QueryResult<BillingPortalSessionQuery, BillingPortalSessionQueryVariables>;
|
export type BillingPortalSessionQueryResult = Apollo.QueryResult<BillingPortalSessionQuery, BillingPortalSessionQueryVariables>;
|
||||||
export const CheckoutSessionDocument = gql`
|
export const CheckoutSessionDocument = gql`
|
||||||
mutation CheckoutSession($recurringInterval: String!, $successUrlPath: String) {
|
mutation CheckoutSession($recurringInterval: SubscriptionInterval!, $successUrlPath: String) {
|
||||||
checkoutSession(
|
checkoutSession(
|
||||||
recurringInterval: $recurringInterval
|
recurringInterval: $recurringInterval
|
||||||
successUrlPath: $successUrlPath
|
successUrlPath: $successUrlPath
|
||||||
@@ -2663,7 +2683,6 @@ export const UpdateWorkspaceDocument = gql`
|
|||||||
displayName
|
displayName
|
||||||
logo
|
logo
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
subscriptionStatus
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMet
|
|||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const objectMetadataItem = getObjectMetadataItemsMock()[0];
|
const objectMetadataItem = getObjectMetadataItemsMock()[0];
|
||||||
jest.mock('@/object-metadata/hooks/useObjectMetadataItem');
|
jest.mock('@/object-metadata/hooks/useObjectMetadataItem');
|
||||||
@@ -36,7 +36,7 @@ const renderHooks = (withCurrentUser: boolean) => {
|
|||||||
() => {
|
() => {
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
if (withCurrentUser) {
|
if (withCurrentUser) {
|
||||||
setCurrentUser(mockedUsersData[0]);
|
setCurrentUser(mockedUserData);
|
||||||
}
|
}
|
||||||
return useDefaultHomePagePath();
|
return useDefaultHomePagePath();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,15 +1,26 @@
|
|||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
|
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
|
||||||
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
||||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||||
import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation';
|
import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation';
|
||||||
|
|
||||||
jest.mock('@/auth/hooks/useOnboardingStatus');
|
jest.mock('@/onboarding/hooks/useOnboardingStatus');
|
||||||
const setupMockOnboardingStatus = (onboardingStatus: OnboardingStatus) => {
|
const setupMockOnboardingStatus = (
|
||||||
|
onboardingStatus: OnboardingStatus | undefined,
|
||||||
|
) => {
|
||||||
jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus);
|
jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.mock('@/workspace/hooks/useSubscriptionStatus');
|
||||||
|
const setupMockSubscriptionStatus = (
|
||||||
|
subscriptionStatus: SubscriptionStatus | undefined,
|
||||||
|
) => {
|
||||||
|
jest.mocked(useSubscriptionStatus).mockReturnValueOnce(subscriptionStatus);
|
||||||
|
};
|
||||||
|
|
||||||
jest.mock('~/hooks/useIsMatchingLocation');
|
jest.mock('~/hooks/useIsMatchingLocation');
|
||||||
const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation);
|
const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation);
|
||||||
|
|
||||||
@@ -19,281 +30,276 @@ const setupMockIsMatchingLocation = (pathname: string) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.mock('@/auth/hooks/useIsLogged');
|
||||||
|
const setupMockIsLogged = (isLogged: boolean) => {
|
||||||
|
jest.mocked(useIsLogged).mockReturnValueOnce(isLogged);
|
||||||
|
};
|
||||||
|
|
||||||
const defaultHomePagePath = '/objects/companies';
|
const defaultHomePagePath = '/objects/companies';
|
||||||
|
|
||||||
jest.mock('~/hooks/useDefaultHomePagePath');
|
jest.mock('~/hooks/useDefaultHomePagePath');
|
||||||
jest.mocked(useDefaultHomePagePath).mockReturnValue({
|
jest.mocked(useDefaultHomePagePath).mockReturnValue({
|
||||||
defaultHomePagePath: '/objects/companies',
|
defaultHomePagePath,
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingUserCreation, res: undefined },
|
{ loc: AppPath.Verify, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingUserCreation, res: undefined },
|
{ loc: AppPath.SignInUp, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Incomplete, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Canceled, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Unpaid, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingUserCreation, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Incomplete, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Canceled, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Unpaid, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingUserCreation, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.CreateProfile, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: undefined },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.SyncEmails, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: undefined },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.InviteTeam, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: undefined },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: undefined },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: undefined },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: undefined },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.PlanRequired, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.PastDue, res: defaultHomePagePath },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.Index, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Completed, res: defaultHomePagePath },
|
{ loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
|
||||||
|
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.TasksPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Canceled, res: undefined },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Unpaid, res: undefined },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.Impersonate, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.Authorize, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
|
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Canceled, res: '/settings/billing' },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Unpaid, res: '/settings/billing' },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.PastDue, res: undefined },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp },
|
{ loc: AppPath.NotFound, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('usePageChangeEffectNavigateLocation', () => {
|
describe('usePageChangeEffectNavigateLocation', () => {
|
||||||
testCases.forEach((testCase) => {
|
testCases.forEach((testCase) => {
|
||||||
it(`with location ${testCase.loc} and onboardingStatus ${testCase.status} should return ${testCase.res}`, () => {
|
it(`with location ${testCase.loc} and onboardingStatus ${testCase.onboardingStatus} and subscriptionStatus ${testCase.subscriptionStatus} should return ${testCase.res}`, () => {
|
||||||
setupMockIsMatchingLocation(testCase.loc);
|
setupMockIsMatchingLocation(testCase.loc);
|
||||||
setupMockOnboardingStatus(testCase.status);
|
setupMockOnboardingStatus(testCase.onboardingStatus);
|
||||||
|
setupMockSubscriptionStatus(testCase.subscriptionStatus);
|
||||||
|
setupMockIsLogged(testCase.isLoggedIn);
|
||||||
expect(usePageChangeEffectNavigateLocation()).toEqual(testCase.res);
|
expect(usePageChangeEffectNavigateLocation()).toEqual(testCase.res);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('tests should be exhaustive', () => {
|
describe('tests should be exhaustive', () => {
|
||||||
it('all location and onboarding status should be tested', () => {
|
it('all location and onboarding status should be tested', () => {
|
||||||
|
const untestedSubscriptionStatus = [
|
||||||
|
SubscriptionStatus.Incomplete,
|
||||||
|
SubscriptionStatus.IncompleteExpired,
|
||||||
|
SubscriptionStatus.Paused,
|
||||||
|
SubscriptionStatus.Trialing,
|
||||||
|
];
|
||||||
expect(testCases.length).toEqual(
|
expect(testCases.length).toEqual(
|
||||||
Object.keys(AppPath).length * Object.keys(OnboardingStatus).length,
|
Object.keys(AppPath).length *
|
||||||
|
(Object.keys(OnboardingStatus).length +
|
||||||
|
(Object.keys(SubscriptionStatus).length -
|
||||||
|
untestedSubscriptionStatus.length)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
|
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
|
||||||
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
|
||||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const usePageChangeEffectNavigateLocation = () => {
|
export const usePageChangeEffectNavigateLocation = () => {
|
||||||
const isMatchingLocation = useIsMatchingLocation();
|
const isMatchingLocation = useIsMatchingLocation();
|
||||||
|
const isLoggedIn = useIsLogged();
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
const subscriptionStatus = useSubscriptionStatus();
|
||||||
const { defaultHomePagePath } = useDefaultHomePagePath();
|
const { defaultHomePagePath } = useDefaultHomePagePath();
|
||||||
|
|
||||||
const isMatchingOpenRoute =
|
const isMatchingOpenRoute =
|
||||||
@@ -33,25 +37,28 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!isLoggedIn && !isMatchingOngoingUserCreationRoute) {
|
||||||
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
|
|
||||||
!isMatchingOngoingUserCreationRoute
|
|
||||||
) {
|
|
||||||
return AppPath.SignInUp;
|
return AppPath.SignInUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.Incomplete &&
|
onboardingStatus === OnboardingStatus.PlanRequired &&
|
||||||
!isMatchingLocation(AppPath.PlanRequired)
|
!isMatchingLocation(AppPath.PlanRequired)
|
||||||
) {
|
) {
|
||||||
return AppPath.PlanRequired;
|
return AppPath.PlanRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isDefined(onboardingStatus) &&
|
subscriptionStatus === SubscriptionStatus.Unpaid &&
|
||||||
[OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes(
|
!isMatchingLocation(AppPath.SettingsCatchAll)
|
||||||
onboardingStatus,
|
) {
|
||||||
) &&
|
return `${AppPath.SettingsCatchAll.replace('/*', '')}/${
|
||||||
|
SettingsPath.Billing
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
subscriptionStatus === SubscriptionStatus.Canceled &&
|
||||||
!(
|
!(
|
||||||
isMatchingLocation(AppPath.SettingsCatchAll) ||
|
isMatchingLocation(AppPath.SettingsCatchAll) ||
|
||||||
isMatchingLocation(AppPath.PlanRequired)
|
isMatchingLocation(AppPath.PlanRequired)
|
||||||
@@ -63,7 +70,7 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingWorkspaceActivation &&
|
onboardingStatus === OnboardingStatus.WorkspaceActivation &&
|
||||||
!isMatchingLocation(AppPath.CreateWorkspace) &&
|
!isMatchingLocation(AppPath.CreateWorkspace) &&
|
||||||
!isMatchingLocation(AppPath.PlanRequiredSuccess)
|
!isMatchingLocation(AppPath.PlanRequiredSuccess)
|
||||||
) {
|
) {
|
||||||
@@ -71,21 +78,21 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingProfileCreation &&
|
onboardingStatus === OnboardingStatus.ProfileCreation &&
|
||||||
!isMatchingLocation(AppPath.CreateProfile)
|
!isMatchingLocation(AppPath.CreateProfile)
|
||||||
) {
|
) {
|
||||||
return AppPath.CreateProfile;
|
return AppPath.CreateProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingSyncEmail &&
|
onboardingStatus === OnboardingStatus.SyncEmail &&
|
||||||
!isMatchingLocation(AppPath.SyncEmails)
|
!isMatchingLocation(AppPath.SyncEmails)
|
||||||
) {
|
) {
|
||||||
return AppPath.SyncEmails;
|
return AppPath.SyncEmails;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.OngoingInviteTeam &&
|
onboardingStatus === OnboardingStatus.InviteTeam &&
|
||||||
!isMatchingLocation(AppPath.InviteTeam)
|
!isMatchingLocation(AppPath.InviteTeam)
|
||||||
) {
|
) {
|
||||||
return AppPath.InviteTeam;
|
return AppPath.InviteTeam;
|
||||||
@@ -93,15 +100,9 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.Completed &&
|
onboardingStatus === OnboardingStatus.Completed &&
|
||||||
isMatchingOnboardingRoute
|
|
||||||
) {
|
|
||||||
return defaultHomePagePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
onboardingStatus === OnboardingStatus.CompletedWithoutSubscription &&
|
|
||||||
isMatchingOnboardingRoute &&
|
isMatchingOnboardingRoute &&
|
||||||
!isMatchingLocation(AppPath.PlanRequired)
|
subscriptionStatus !== SubscriptionStatus.Canceled &&
|
||||||
|
(isDefined(subscriptionStatus) || !isMatchingLocation(AppPath.PlanRequired))
|
||||||
) {
|
) {
|
||||||
return defaultHomePagePath;
|
return defaultHomePagePath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks, metadataGraphql } from '~/testing/graphqlMocks';
|
import { graphqlMocks, metadataGraphql } from '~/testing/graphqlMocks';
|
||||||
import { mockedClientConfig } from '~/testing/mock-data/config';
|
import { mockedClientConfig } from '~/testing/mock-data/config';
|
||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const userMetadataLoaderMocks = {
|
const userMetadataLoaderMocks = {
|
||||||
msw: {
|
msw: {
|
||||||
@@ -22,7 +22,7 @@ const userMetadataLoaderMocks = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedUsersData[0],
|
currentUser: mockedUserData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,373 +0,0 @@
|
|||||||
import { act } from 'react-dom/test-utils';
|
|
||||||
import { renderHook } from '@testing-library/react';
|
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
||||||
import { CurrentUser, currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
|
||||||
import {
|
|
||||||
CurrentWorkspace,
|
|
||||||
currentWorkspaceState,
|
|
||||||
} from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState';
|
|
||||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
|
||||||
|
|
||||||
const tokenPair = {
|
|
||||||
accessToken: { token: 'accessToken', expiresAt: 'expiresAt' },
|
|
||||||
refreshToken: { token: 'refreshToken', expiresAt: 'expiresAt' },
|
|
||||||
};
|
|
||||||
const billing = {
|
|
||||||
billingUrl: 'testing.com',
|
|
||||||
isBillingEnabled: true,
|
|
||||||
};
|
|
||||||
const currentUser = {
|
|
||||||
id: '1',
|
|
||||||
email: 'test@test',
|
|
||||||
supportUserHash: '1',
|
|
||||||
canImpersonate: false,
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser;
|
|
||||||
const currentWorkspace = {
|
|
||||||
activationStatus: 'active',
|
|
||||||
id: '1',
|
|
||||||
allowImpersonation: true,
|
|
||||||
currentBillingSubscription: {
|
|
||||||
status: 'trialing',
|
|
||||||
},
|
|
||||||
} as CurrentWorkspace;
|
|
||||||
const currentWorkspaceMember = {
|
|
||||||
id: '1',
|
|
||||||
locale: '',
|
|
||||||
name: {
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderHooks = () => {
|
|
||||||
const { result } = renderHook(
|
|
||||||
() => {
|
|
||||||
const onboardingStatus = useOnboardingStatus();
|
|
||||||
const setBilling = useSetRecoilState(billingState);
|
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
|
||||||
const setCurrentWorkspaceMember = useSetRecoilState(
|
|
||||||
currentWorkspaceMemberState,
|
|
||||||
);
|
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
|
||||||
const setTokenPair = useSetRecoilState(tokenPairState);
|
|
||||||
const setVerifyPending = useSetRecoilState(isVerifyPendingState);
|
|
||||||
|
|
||||||
return {
|
|
||||||
onboardingStatus,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
setTokenPair,
|
|
||||||
setVerifyPending,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wrapper: RecoilRoot,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return { result };
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('useOnboardingStatus', () => {
|
|
||||||
it('should return "ongoing_user_creation" when user is not logged in', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('ongoing_user_creation');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "incomplete"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember(currentWorkspaceMember);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('incomplete');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "canceled"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'canceled',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('canceled');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "ongoing_workspace_activation"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const { setTokenPair, setBilling, setCurrentUser, setCurrentWorkspace } =
|
|
||||||
result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
activationStatus: 'inactive',
|
|
||||||
subscriptionStatus: 'active',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe(
|
|
||||||
'ongoing_workspace_activation',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "ongoing_profile_creation"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'active',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember(currentWorkspaceMember);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('ongoing_profile_creation');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "ongoing_sync_email"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser({
|
|
||||||
...currentUser,
|
|
||||||
onboardingStep: OnboardingStep.SyncEmail,
|
|
||||||
});
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'active',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('ongoing_sync_email');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "ongoing_invite_team"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser({
|
|
||||||
...currentUser,
|
|
||||||
onboardingStep: OnboardingStep.InviteTeam,
|
|
||||||
});
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'active',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('ongoing_invite_team');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "completed"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'active',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('completed');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "past_due"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'past_due',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('past_due');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "unpaid"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'unpaid',
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe('unpaid');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "completed_without_subscription"', async () => {
|
|
||||||
const { result } = renderHooks();
|
|
||||||
const {
|
|
||||||
setTokenPair,
|
|
||||||
setBilling,
|
|
||||||
setCurrentUser,
|
|
||||||
setCurrentWorkspace,
|
|
||||||
setCurrentWorkspaceMember,
|
|
||||||
} = result.current;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
setTokenPair(tokenPair);
|
|
||||||
setBilling(billing);
|
|
||||||
setCurrentUser(currentUser);
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
subscriptionStatus: 'trialing',
|
|
||||||
currentBillingSubscription: null,
|
|
||||||
});
|
|
||||||
setCurrentWorkspaceMember({
|
|
||||||
...currentWorkspaceMember,
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.onboardingStatus).toBe(
|
|
||||||
'completed_without_subscription',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
|
||||||
|
|
||||||
import { useIsLogged } from '../hooks/useIsLogged';
|
|
||||||
import {
|
|
||||||
getOnboardingStatus,
|
|
||||||
OnboardingStatus,
|
|
||||||
} from '../utils/getOnboardingStatus';
|
|
||||||
|
|
||||||
export const useOnboardingStatus = (): OnboardingStatus | undefined => {
|
|
||||||
const billing = useRecoilValue(billingState);
|
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
|
||||||
const isLoggedIn = useIsLogged();
|
|
||||||
|
|
||||||
return getOnboardingStatus({
|
|
||||||
isLoggedIn,
|
|
||||||
currentWorkspaceMember,
|
|
||||||
currentWorkspace,
|
|
||||||
currentUser,
|
|
||||||
isBillingEnabled: billing?.isBillingEnabled || false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -4,7 +4,7 @@ import { User } from '~/generated/graphql';
|
|||||||
|
|
||||||
export type CurrentUser = Pick<
|
export type CurrentUser = Pick<
|
||||||
User,
|
User,
|
||||||
'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStep'
|
'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStatus'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const currentUserState = createState<CurrentUser | null>({
|
export const currentUserState = createState<CurrentUser | null>({
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ export type CurrentWorkspace = Pick<
|
|||||||
| 'displayName'
|
| 'displayName'
|
||||||
| 'allowImpersonation'
|
| 'allowImpersonation'
|
||||||
| 'featureFlags'
|
| 'featureFlags'
|
||||||
| 'subscriptionStatus'
|
|
||||||
| 'activationStatus'
|
| 'activationStatus'
|
||||||
| 'currentBillingSubscription'
|
| 'currentBillingSubscription'
|
||||||
| 'currentCacheVersion'
|
| 'currentCacheVersion'
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
import { CurrentUser } from '@/auth/states/currentUserState';
|
|
||||||
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { getOnboardingStatus } from '../getOnboardingStatus';
|
|
||||||
|
|
||||||
describe('getOnboardingStatus', () => {
|
|
||||||
it('should return the correct status', () => {
|
|
||||||
const ongoingUserCreation = getOnboardingStatus({
|
|
||||||
isLoggedIn: false,
|
|
||||||
currentWorkspaceMember: null,
|
|
||||||
currentWorkspace: null,
|
|
||||||
currentUser: null,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ongoingWorkspaceActivation = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: null,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'inactive',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ongoingProfileCreation = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ongoingSyncEmail = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: OnboardingStep.SyncEmail,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ongoingInviteTeam = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: OnboardingStep.InviteTeam,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const completed = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const incomplete = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const incompleteButBillingDisabled = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const canceled = getOnboardingStatus({
|
|
||||||
isLoggedIn: true,
|
|
||||||
currentWorkspaceMember: {
|
|
||||||
id: '1',
|
|
||||||
name: {
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Doe',
|
|
||||||
},
|
|
||||||
} as WorkspaceMember,
|
|
||||||
currentWorkspace: {
|
|
||||||
id: '1',
|
|
||||||
activationStatus: 'active',
|
|
||||||
subscriptionStatus: 'canceled',
|
|
||||||
} as CurrentWorkspace,
|
|
||||||
currentUser: {
|
|
||||||
onboardingStep: null,
|
|
||||||
} as CurrentUser,
|
|
||||||
isBillingEnabled: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(ongoingUserCreation).toBe('ongoing_user_creation');
|
|
||||||
expect(ongoingWorkspaceActivation).toBe('ongoing_workspace_activation');
|
|
||||||
expect(ongoingProfileCreation).toBe('ongoing_profile_creation');
|
|
||||||
expect(ongoingSyncEmail).toBe('ongoing_sync_email');
|
|
||||||
expect(ongoingInviteTeam).toBe('ongoing_invite_team');
|
|
||||||
expect(completed).toBe('completed');
|
|
||||||
expect(incomplete).toBe('incomplete');
|
|
||||||
expect(canceled).toBe('canceled');
|
|
||||||
expect(incompleteButBillingDisabled).toBe('completed');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import { CurrentUser } from '@/auth/states/currentUserState';
|
|
||||||
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
|
||||||
|
|
||||||
export enum OnboardingStatus {
|
|
||||||
Incomplete = 'incomplete',
|
|
||||||
Canceled = 'canceled',
|
|
||||||
Unpaid = 'unpaid',
|
|
||||||
PastDue = 'past_due',
|
|
||||||
OngoingUserCreation = 'ongoing_user_creation',
|
|
||||||
OngoingWorkspaceActivation = 'ongoing_workspace_activation',
|
|
||||||
OngoingProfileCreation = 'ongoing_profile_creation',
|
|
||||||
OngoingSyncEmail = 'ongoing_sync_email',
|
|
||||||
OngoingInviteTeam = 'ongoing_invite_team',
|
|
||||||
Completed = 'completed',
|
|
||||||
CompletedWithoutSubscription = 'completed_without_subscription',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getOnboardingStatus = ({
|
|
||||||
isLoggedIn,
|
|
||||||
currentWorkspaceMember,
|
|
||||||
currentWorkspace,
|
|
||||||
currentUser,
|
|
||||||
isBillingEnabled,
|
|
||||||
}: {
|
|
||||||
isLoggedIn: boolean;
|
|
||||||
currentWorkspaceMember: Omit<
|
|
||||||
WorkspaceMember,
|
|
||||||
'createdAt' | 'updatedAt' | 'userId' | 'userEmail' | '__typename'
|
|
||||||
> | null;
|
|
||||||
currentWorkspace: CurrentWorkspace | null;
|
|
||||||
currentUser: CurrentUser | null;
|
|
||||||
isBillingEnabled: boolean;
|
|
||||||
}) => {
|
|
||||||
if (!isLoggedIn) {
|
|
||||||
return OnboardingStatus.OngoingUserCreation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// After SignInUp, the user should have a current workspace assigned.
|
|
||||||
// If not, it indicates that the data is still being requested.
|
|
||||||
if (!currentWorkspace || !currentUser) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
isBillingEnabled &&
|
|
||||||
currentWorkspace.subscriptionStatus === 'incomplete'
|
|
||||||
) {
|
|
||||||
return OnboardingStatus.Incomplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentWorkspace.activationStatus !== 'active') {
|
|
||||||
return OnboardingStatus.OngoingWorkspaceActivation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!currentWorkspaceMember?.name.firstName ||
|
|
||||||
!currentWorkspaceMember?.name.lastName
|
|
||||||
) {
|
|
||||||
return OnboardingStatus.OngoingProfileCreation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUser.onboardingStep === OnboardingStep.SyncEmail) {
|
|
||||||
return OnboardingStatus.OngoingSyncEmail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUser.onboardingStep === OnboardingStep.InviteTeam) {
|
|
||||||
return OnboardingStatus.OngoingInviteTeam;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'canceled') {
|
|
||||||
return OnboardingStatus.Canceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'past_due') {
|
|
||||||
return OnboardingStatus.PastDue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'unpaid') {
|
|
||||||
return OnboardingStatus.Unpaid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBillingEnabled && !currentWorkspace.currentBillingSubscription) {
|
|
||||||
return OnboardingStatus.CompletedWithoutSubscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OnboardingStatus.Completed;
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,7 @@ import { gql } from '@apollo/client';
|
|||||||
|
|
||||||
export const CHECKOUT_SESSION = gql`
|
export const CHECKOUT_SESSION = gql`
|
||||||
mutation CheckoutSession(
|
mutation CheckoutSession(
|
||||||
$recurringInterval: String!
|
$recurringInterval: SubscriptionInterval!
|
||||||
$successUrlPath: String
|
$successUrlPath: String
|
||||||
) {
|
) {
|
||||||
checkoutSession(
|
checkoutSession(
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { CurrentUser, currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||||
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
|
|
||||||
|
const tokenPair = {
|
||||||
|
accessToken: { token: 'accessToken', expiresAt: 'expiresAt' },
|
||||||
|
refreshToken: { token: 'refreshToken', expiresAt: 'expiresAt' },
|
||||||
|
};
|
||||||
|
const currentUser = {
|
||||||
|
id: '1',
|
||||||
|
onboardingStatus: null,
|
||||||
|
} as CurrentUser;
|
||||||
|
|
||||||
|
const renderHooks = () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() => {
|
||||||
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
|
const setTokenPair = useSetRecoilState(tokenPairState);
|
||||||
|
|
||||||
|
return {
|
||||||
|
onboardingStatus,
|
||||||
|
setCurrentUser,
|
||||||
|
setTokenPair,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapper: RecoilRoot,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return { result };
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('useOnboardingStatus', () => {
|
||||||
|
it(`should return "undefined" when user is not logged in`, async () => {
|
||||||
|
const { result } = renderHooks();
|
||||||
|
expect(result.current.onboardingStatus).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.values(OnboardingStatus).forEach((onboardingStatus) => {
|
||||||
|
it(`should return "${onboardingStatus}"`, async () => {
|
||||||
|
const { result } = renderHooks();
|
||||||
|
const { setTokenPair, setCurrentUser } = result.current;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
setTokenPair(tokenPair);
|
||||||
|
setCurrentUser({
|
||||||
|
...currentUser,
|
||||||
|
onboardingStatus,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.onboardingStatus).toBe(onboardingStatus);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
import { RecoilRoot, useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
|
||||||
|
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
|
||||||
|
import {
|
||||||
|
mockDefaultWorkspace,
|
||||||
|
mockedUserData,
|
||||||
|
} from '~/testing/mock-data/users';
|
||||||
|
|
||||||
|
jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
|
||||||
|
useFindManyRecords: jest.fn(),
|
||||||
|
}));
|
||||||
|
const setupMockWorkspaceMembers = (withManyWorkspaceMembers = false) => {
|
||||||
|
jest
|
||||||
|
.requireMock('@/object-record/hooks/useFindManyRecords')
|
||||||
|
.useFindManyRecords.mockReturnValue({
|
||||||
|
records: withManyWorkspaceMembers ? [{}, {}] : [{}],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHooks = (
|
||||||
|
onboardingStatus: OnboardingStatus,
|
||||||
|
withCurrentBillingSubscription: boolean,
|
||||||
|
) => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() => {
|
||||||
|
const [currentUser, setCurrentUser] = useRecoilState(currentUserState);
|
||||||
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
|
const setNextOnboardingStatus = useSetNextOnboardingStatus();
|
||||||
|
return {
|
||||||
|
currentUser,
|
||||||
|
setCurrentUser,
|
||||||
|
setCurrentWorkspace,
|
||||||
|
setNextOnboardingStatus,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapper: RecoilRoot,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
act(() => {
|
||||||
|
result.current.setCurrentUser({ ...mockedUserData, onboardingStatus });
|
||||||
|
result.current.setCurrentWorkspace({
|
||||||
|
...mockDefaultWorkspace,
|
||||||
|
currentBillingSubscription: withCurrentBillingSubscription
|
||||||
|
? { id: v4(), status: SubscriptionStatus.Active }
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
result.current.setNextOnboardingStatus();
|
||||||
|
});
|
||||||
|
return result.current.currentUser?.onboardingStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('useSetNextOnboardingStatus', () => {
|
||||||
|
it('should set next onboarding status for ProfileCreation', () => {
|
||||||
|
setupMockWorkspaceMembers();
|
||||||
|
const nextOnboardingStatus = renderHooks(
|
||||||
|
OnboardingStatus.ProfileCreation,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(nextOnboardingStatus).toEqual(OnboardingStatus.SyncEmail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set next onboarding status for SyncEmail', () => {
|
||||||
|
setupMockWorkspaceMembers();
|
||||||
|
const nextOnboardingStatus = renderHooks(OnboardingStatus.SyncEmail, false);
|
||||||
|
expect(nextOnboardingStatus).toEqual(OnboardingStatus.InviteTeam);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip invite when workspaceMembers exist', () => {
|
||||||
|
setupMockWorkspaceMembers(true);
|
||||||
|
const nextOnboardingStatus = renderHooks(OnboardingStatus.SyncEmail, true);
|
||||||
|
expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set next onboarding status for Completed', () => {
|
||||||
|
setupMockWorkspaceMembers();
|
||||||
|
const nextOnboardingStatus = renderHooks(OnboardingStatus.InviteTeam, true);
|
||||||
|
expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useOnboardingStatus = (): OnboardingStatus | null | undefined => {
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
return currentUser?.onboardingStatus;
|
||||||
|
};
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { CurrentUser, currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
const getNextOnboardingStatus = (
|
||||||
|
currentUser: CurrentUser | null,
|
||||||
|
workspaceMembers: WorkspaceMember[],
|
||||||
|
) => {
|
||||||
|
if (currentUser?.onboardingStatus === OnboardingStatus.ProfileCreation) {
|
||||||
|
return OnboardingStatus.SyncEmail;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
currentUser?.onboardingStatus === OnboardingStatus.SyncEmail &&
|
||||||
|
workspaceMembers.length === 1
|
||||||
|
) {
|
||||||
|
return OnboardingStatus.InviteTeam;
|
||||||
|
}
|
||||||
|
return OnboardingStatus.Completed;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSetNextOnboardingStatus = () => {
|
||||||
|
const { records: workspaceMembers } = useFindManyRecords<WorkspaceMember>({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||||
|
});
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
|
return useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
() => {
|
||||||
|
const nextOnboardingStatus = getNextOnboardingStatus(
|
||||||
|
currentUser,
|
||||||
|
workspaceMembers,
|
||||||
|
);
|
||||||
|
set(currentUserState, (current) => {
|
||||||
|
if (isDefined(current)) {
|
||||||
|
return {
|
||||||
|
...current,
|
||||||
|
onboardingStatus: nextOnboardingStatus,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[workspaceMembers, currentUser],
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
|
||||||
|
|
||||||
const getNextOnboardingStep = (
|
|
||||||
currentOnboardingStep: OnboardingStep,
|
|
||||||
workspaceMembers: WorkspaceMember[],
|
|
||||||
) => {
|
|
||||||
if (currentOnboardingStep === OnboardingStep.SyncEmail) {
|
|
||||||
return workspaceMembers && workspaceMembers.length > 1
|
|
||||||
? null
|
|
||||||
: OnboardingStep.InviteTeam;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useSetNextOnboardingStep = () => {
|
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
|
||||||
const { records: workspaceMembers } = useFindManyRecords<WorkspaceMember>({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
|
||||||
});
|
|
||||||
return useRecoilCallback(
|
|
||||||
() => (currentOnboardingStep: OnboardingStep) => {
|
|
||||||
setCurrentUser(
|
|
||||||
(current) =>
|
|
||||||
({
|
|
||||||
...current,
|
|
||||||
onboardingStep: getNextOnboardingStep(
|
|
||||||
currentOnboardingStep,
|
|
||||||
workspaceMembers,
|
|
||||||
),
|
|
||||||
}) as any,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[setCurrentUser, workspaceMembers],
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -10,7 +10,7 @@ import { supportChatState } from '@/client-config/states/supportChatState';
|
|||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import {
|
import {
|
||||||
mockDefaultWorkspace,
|
mockDefaultWorkspace,
|
||||||
mockedUsersData,
|
mockedUserData,
|
||||||
mockedWorkspaceMemberData,
|
mockedWorkspaceMemberData,
|
||||||
} from '~/testing/mock-data/users';
|
} from '~/testing/mock-data/users';
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ const meta: Meta<typeof SupportChat> = {
|
|||||||
|
|
||||||
setCurrentWorkspace(mockDefaultWorkspace);
|
setCurrentWorkspace(mockDefaultWorkspace);
|
||||||
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
||||||
setCurrentUser(mockedUsersData[0]);
|
setCurrentUser(mockedUserData);
|
||||||
setSupportChat({ supportDriver: 'front', supportFrontChatId: '1234' });
|
setSupportChat({ supportDriver: 'front', supportFrontChatId: '1234' });
|
||||||
|
|
||||||
return <Story />;
|
return <Story />;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import { css, useTheme } from '@emotion/react';
|
import { css, useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { IconInfoCircle } from 'twenty-ui';
|
import { IconInfoCircle } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
|
|
||||||
export type InfoAccent = 'blue' | 'danger';
|
export type InfoAccent = 'blue' | 'danger';
|
||||||
@@ -11,6 +13,7 @@ export type InfoProps = {
|
|||||||
text: string;
|
text: string;
|
||||||
buttonTitle?: string;
|
buttonTitle?: string;
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
|
to?: AppPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledTextContainer = styled.div`
|
const StyledTextContainer = styled.div`
|
||||||
@@ -30,6 +33,7 @@ const StyledInfo = styled.div<Pick<InfoProps, 'accent'>>`
|
|||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
max-width: 512px;
|
max-width: 512px;
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
padding: ${({ theme }) => theme.spacing(2)};
|
||||||
${({ theme, accent }) => {
|
${({ theme, accent }) => {
|
||||||
switch (accent) {
|
switch (accent) {
|
||||||
@@ -46,11 +50,17 @@ const StyledInfo = styled.div<Pick<InfoProps, 'accent'>>`
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledLink = styled(Link)`
|
||||||
|
text-decoration: none;
|
||||||
|
`;
|
||||||
|
|
||||||
export const Info = ({
|
export const Info = ({
|
||||||
accent = 'blue',
|
accent = 'blue',
|
||||||
text,
|
text,
|
||||||
buttonTitle,
|
buttonTitle,
|
||||||
onClick,
|
onClick,
|
||||||
|
to,
|
||||||
}: InfoProps) => {
|
}: InfoProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
@@ -59,12 +69,23 @@ export const Info = ({
|
|||||||
<StyledIconInfoCircle size={theme.icon.size.md} />
|
<StyledIconInfoCircle size={theme.icon.size.md} />
|
||||||
{text}
|
{text}
|
||||||
</StyledTextContainer>
|
</StyledTextContainer>
|
||||||
{buttonTitle && onClick && (
|
{buttonTitle && to && (
|
||||||
|
<StyledLink to={to}>
|
||||||
|
<Button
|
||||||
|
title={buttonTitle}
|
||||||
|
size={'small'}
|
||||||
|
variant={'secondary'}
|
||||||
|
accent={accent}
|
||||||
|
/>
|
||||||
|
</StyledLink>
|
||||||
|
)}
|
||||||
|
{buttonTitle && onClick && !to && (
|
||||||
<Button
|
<Button
|
||||||
title={buttonTitle}
|
title={buttonTitle}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
variant={'secondary'}
|
variant={'secondary'}
|
||||||
|
accent={accent}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledInfo>
|
</StyledInfo>
|
||||||
|
|||||||
@@ -1,18 +1,34 @@
|
|||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||||
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
|
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
|
||||||
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
|
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
|
||||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||||
|
|
||||||
jest.mock('@/auth/hooks/useOnboardingStatus');
|
jest.mock('@/onboarding/hooks/useOnboardingStatus');
|
||||||
const setupMockOnboardingStatus = (onboardingStatus: OnboardingStatus) => {
|
const setupMockOnboardingStatus = (
|
||||||
|
onboardingStatus: OnboardingStatus | undefined,
|
||||||
|
) => {
|
||||||
jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus);
|
jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.mock('@/workspace/hooks/useSubscriptionStatus');
|
||||||
|
const setupMockSubscriptionStatus = (
|
||||||
|
subscriptionStatus: SubscriptionStatus | undefined,
|
||||||
|
) => {
|
||||||
|
jest.mocked(useSubscriptionStatus).mockReturnValueOnce(subscriptionStatus);
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('@/auth/hooks/useIsLogged');
|
||||||
|
const setupMockIsLogged = (isLogged: boolean) => {
|
||||||
|
jest.mocked(useIsLogged).mockReturnValueOnce(isLogged);
|
||||||
|
};
|
||||||
|
|
||||||
jest.mock('~/hooks/useIsMatchingLocation');
|
jest.mock('~/hooks/useIsMatchingLocation');
|
||||||
const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation);
|
const mockUseIsMatchingLocation = jest.mocked(useIsMatchingLocation);
|
||||||
|
|
||||||
@@ -39,264 +55,245 @@ const getResult = (isDefaultLayoutAuthModalVisible = true) =>
|
|||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Incomplete, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingUserCreation, res: false },
|
{ loc: AppPath.Verify, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Verify, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.SignInUp, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SignInUp, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Canceled, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Unpaid, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.PastDue, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.Invite, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: true },
|
{ loc: AppPath.Invite, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
|
||||||
|
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Canceled, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Unpaid, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.PastDue, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: true },
|
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
|
||||||
|
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SyncEmails, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.InviteTeam, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
|
||||||
|
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.Index, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Index, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.TasksPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.TasksPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.OpportunitiesPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.RecordIndexPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.RecordShowPage, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SettingsCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.DevelopersCatchAll, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.Impersonate, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Impersonate, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.Authorize, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Authorize, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.NotFoundWildcard, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
|
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Canceled, res: false },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.PastDue, res: false },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingUserCreation, res: true },
|
{ loc: AppPath.NotFound, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.NotFound, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('useShowAuthModal', () => {
|
describe('useShowAuthModal', () => {
|
||||||
testCases.forEach((testCase) => {
|
testCases.forEach((testCase) => {
|
||||||
it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.status} should return ${testCase.res}`, () => {
|
it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.onboardingStatus} should return ${testCase.res}`, () => {
|
||||||
setupMockOnboardingStatus(testCase.status);
|
setupMockOnboardingStatus(testCase.onboardingStatus);
|
||||||
|
setupMockSubscriptionStatus(testCase.subscriptionStatus);
|
||||||
setupMockIsMatchingLocation(testCase.loc);
|
setupMockIsMatchingLocation(testCase.loc);
|
||||||
|
setupMockIsLogged(testCase.isLogged);
|
||||||
const { result } = getResult();
|
const { result } = getResult();
|
||||||
if (testCase.res) {
|
if (testCase.res) {
|
||||||
expect(result.current).toBeTruthy();
|
expect(result.current).toBeTruthy();
|
||||||
@@ -309,13 +306,17 @@ describe('useShowAuthModal', () => {
|
|||||||
describe('test with token validation loading', () => {
|
describe('test with token validation loading', () => {
|
||||||
it(`with appPath ${AppPath.Invite} and isDefaultLayoutAuthModalVisible=false`, () => {
|
it(`with appPath ${AppPath.Invite} and isDefaultLayoutAuthModalVisible=false`, () => {
|
||||||
setupMockOnboardingStatus(OnboardingStatus.Completed);
|
setupMockOnboardingStatus(OnboardingStatus.Completed);
|
||||||
|
setupMockSubscriptionStatus(SubscriptionStatus.Active);
|
||||||
setupMockIsMatchingLocation(AppPath.Invite);
|
setupMockIsMatchingLocation(AppPath.Invite);
|
||||||
|
setupMockIsLogged(true);
|
||||||
const { result } = getResult(false);
|
const { result } = getResult(false);
|
||||||
expect(result.current).toBeFalsy();
|
expect(result.current).toBeFalsy();
|
||||||
});
|
});
|
||||||
it(`with appPath ${AppPath.ResetPassword} and isDefaultLayoutAuthModalVisible=false`, () => {
|
it(`with appPath ${AppPath.ResetPassword} and isDefaultLayoutAuthModalVisible=false`, () => {
|
||||||
setupMockOnboardingStatus(OnboardingStatus.Completed);
|
setupMockOnboardingStatus(OnboardingStatus.Completed);
|
||||||
|
setupMockSubscriptionStatus(SubscriptionStatus.Active);
|
||||||
setupMockIsMatchingLocation(AppPath.ResetPassword);
|
setupMockIsMatchingLocation(AppPath.ResetPassword);
|
||||||
|
setupMockIsLogged(true);
|
||||||
const { result } = getResult(false);
|
const { result } = getResult(false);
|
||||||
expect(result.current).toBeFalsy();
|
expect(result.current).toBeFalsy();
|
||||||
});
|
});
|
||||||
@@ -323,8 +324,17 @@ describe('useShowAuthModal', () => {
|
|||||||
|
|
||||||
describe('tests should be exhaustive', () => {
|
describe('tests should be exhaustive', () => {
|
||||||
it('all location and onboarding status should be tested', () => {
|
it('all location and onboarding status should be tested', () => {
|
||||||
|
const untestedSubscriptionStatus = [
|
||||||
|
SubscriptionStatus.Active,
|
||||||
|
SubscriptionStatus.IncompleteExpired,
|
||||||
|
SubscriptionStatus.Paused,
|
||||||
|
SubscriptionStatus.Trialing,
|
||||||
|
];
|
||||||
expect(testCases.length).toEqual(
|
expect(testCases.length).toEqual(
|
||||||
Object.keys(AppPath).length * Object.keys(OnboardingStatus).length,
|
Object.keys(AppPath).length *
|
||||||
|
(Object.keys(OnboardingStatus).length +
|
||||||
|
(Object.keys(SubscriptionStatus).length -
|
||||||
|
untestedSubscriptionStatus.length)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
|
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
|
||||||
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
|
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
|
||||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useShowAuthModal = () => {
|
export const useShowAuthModal = () => {
|
||||||
const isMatchingLocation = useIsMatchingLocation();
|
const isMatchingLocation = useIsMatchingLocation();
|
||||||
|
const isLoggedIn = useIsLogged();
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
const subscriptionStatus = useSubscriptionStatus();
|
||||||
const isDefaultLayoutAuthModalVisible = useRecoilValue(
|
const isDefaultLayoutAuthModalVisible = useRecoilValue(
|
||||||
isDefaultLayoutAuthModalVisibleState,
|
isDefaultLayoutAuthModalVisibleState,
|
||||||
);
|
);
|
||||||
@@ -24,21 +29,28 @@ export const useShowAuthModal = () => {
|
|||||||
return isDefaultLayoutAuthModalVisible;
|
return isDefaultLayoutAuthModalVisible;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
OnboardingStatus.Incomplete === onboardingStatus ||
|
!isLoggedIn ||
|
||||||
OnboardingStatus.OngoingUserCreation === onboardingStatus ||
|
onboardingStatus === OnboardingStatus.PlanRequired ||
|
||||||
OnboardingStatus.OngoingProfileCreation === onboardingStatus ||
|
onboardingStatus === OnboardingStatus.ProfileCreation ||
|
||||||
OnboardingStatus.OngoingWorkspaceActivation === onboardingStatus ||
|
onboardingStatus === OnboardingStatus.WorkspaceActivation ||
|
||||||
OnboardingStatus.OngoingSyncEmail === onboardingStatus ||
|
onboardingStatus === OnboardingStatus.SyncEmail ||
|
||||||
OnboardingStatus.OngoingInviteTeam === onboardingStatus
|
onboardingStatus === OnboardingStatus.InviteTeam
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (isMatchingLocation(AppPath.PlanRequired)) {
|
if (isMatchingLocation(AppPath.PlanRequired)) {
|
||||||
return (
|
return (
|
||||||
OnboardingStatus.CompletedWithoutSubscription === onboardingStatus ||
|
(onboardingStatus === OnboardingStatus.Completed &&
|
||||||
OnboardingStatus.Canceled === onboardingStatus
|
!isDefined(subscriptionStatus)) ||
|
||||||
|
subscriptionStatus === SubscriptionStatus.Canceled
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}, [isDefaultLayoutAuthModalVisible, isMatchingLocation, onboardingStatus]);
|
}, [
|
||||||
|
isLoggedIn,
|
||||||
|
isDefaultLayoutAuthModalVisible,
|
||||||
|
isMatchingLocation,
|
||||||
|
onboardingStatus,
|
||||||
|
subscriptionStatus,
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const USER_QUERY_FRAGMENT = gql`
|
|||||||
email
|
email
|
||||||
canImpersonate
|
canImpersonate
|
||||||
supportUserHash
|
supportUserHash
|
||||||
onboardingStep
|
onboardingStatus
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
name {
|
name {
|
||||||
@@ -26,7 +26,6 @@ export const USER_QUERY_FRAGMENT = gql`
|
|||||||
domainName
|
domainName
|
||||||
inviteHash
|
inviteHash
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
subscriptionStatus
|
|
||||||
activationStatus
|
activationStatus
|
||||||
featureFlags {
|
featureFlags {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export const UPDATE_WORKSPACE = gql`
|
|||||||
displayName
|
displayName
|
||||||
logo
|
logo
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
subscriptionStatus
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CurrentWorkspace,
|
||||||
|
currentWorkspaceState,
|
||||||
|
} from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
|
import { SubscriptionStatus } from '~/generated/graphql';
|
||||||
|
|
||||||
|
const currentWorkspace = {
|
||||||
|
id: '1',
|
||||||
|
currentBillingSubscription: { status: SubscriptionStatus.Incomplete },
|
||||||
|
activationStatus: 'active',
|
||||||
|
allowImpersonation: true,
|
||||||
|
} as CurrentWorkspace;
|
||||||
|
|
||||||
|
const renderHooks = () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() => {
|
||||||
|
const subscriptionStatus = useSubscriptionStatus();
|
||||||
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscriptionStatus,
|
||||||
|
setCurrentWorkspace,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapper: RecoilRoot,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return { result };
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('useSubscriptionStatus', () => {
|
||||||
|
Object.values(SubscriptionStatus).forEach((subscriptionStatus) => {
|
||||||
|
it(`should return "${subscriptionStatus}"`, async () => {
|
||||||
|
const { result } = renderHooks();
|
||||||
|
const { setCurrentWorkspace } = result.current;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
setCurrentWorkspace({
|
||||||
|
...currentWorkspace,
|
||||||
|
currentBillingSubscription: {
|
||||||
|
id: v4(),
|
||||||
|
status: subscriptionStatus,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.subscriptionStatus).toBe(subscriptionStatus);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { SubscriptionStatus } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useSubscriptionStatus = (): SubscriptionStatus | undefined => {
|
||||||
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
return currentWorkspace?.currentBillingSubscription?.status;
|
||||||
|
};
|
||||||
@@ -4,14 +4,21 @@ import { within } from '@storybook/test';
|
|||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
import { ValidatePasswordResetTokenDocument } from '~/generated/graphql';
|
import {
|
||||||
|
OnboardingStatus,
|
||||||
|
ValidatePasswordResetTokenDocument,
|
||||||
|
} from '~/generated/graphql';
|
||||||
import { PasswordReset } from '~/pages/auth/PasswordReset';
|
import { PasswordReset } from '~/pages/auth/PasswordReset';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
|
const mockedOnboardingUsersData = mockedOnboardingUserData(
|
||||||
|
OnboardingStatus.Completed,
|
||||||
|
);
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Auth/PasswordReset',
|
title: 'Pages/Auth/PasswordReset',
|
||||||
@@ -30,8 +37,8 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
validatePasswordResetToken: {
|
validatePasswordResetToken: {
|
||||||
id: mockedOnboardingUsersData[0].id,
|
id: mockedOnboardingUsersData.id,
|
||||||
email: mockedOnboardingUsersData[0].email,
|
email: mockedOnboardingUsersData.email,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -40,7 +47,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
currentUser: mockedOnboardingUsersData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { ActionLink } from '@/ui/navigation/link/components/ActionLink';
|
|||||||
import { CAL_LINK } from '@/ui/navigation/link/constants/Cal';
|
import { CAL_LINK } from '@/ui/navigation/link/constants/Cal';
|
||||||
import {
|
import {
|
||||||
ProductPriceEntity,
|
ProductPriceEntity,
|
||||||
|
SubscriptionInterval,
|
||||||
useCheckoutSessionMutation,
|
useCheckoutSessionMutation,
|
||||||
useGetProductPricesQuery,
|
useGetProductPricesQuery,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
@@ -75,7 +76,7 @@ const benefits = [
|
|||||||
export const ChooseYourPlan = () => {
|
export const ChooseYourPlan = () => {
|
||||||
const billing = useRecoilValue(billingState);
|
const billing = useRecoilValue(billingState);
|
||||||
|
|
||||||
const [planSelected, setPlanSelected] = useState('month');
|
const [planSelected, setPlanSelected] = useState(SubscriptionInterval.Month);
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export const ChooseYourPlan = () => {
|
|||||||
|
|
||||||
const [checkoutSession] = useCheckoutSessionMutation();
|
const [checkoutSession] = useCheckoutSessionMutation();
|
||||||
|
|
||||||
const handlePlanChange = (type?: string) => {
|
const handlePlanChange = (type?: SubscriptionInterval) => {
|
||||||
return () => {
|
return () => {
|
||||||
if (isNonEmptyString(type) && planSelected !== type) {
|
if (isNonEmptyString(type) && planSelected !== type) {
|
||||||
setPlanSelected(type);
|
setPlanSelected(type);
|
||||||
@@ -101,11 +102,11 @@ export const ChooseYourPlan = () => {
|
|||||||
price: ProductPriceEntity,
|
price: ProductPriceEntity,
|
||||||
prices: ProductPriceEntity[],
|
prices: ProductPriceEntity[],
|
||||||
): string => {
|
): string => {
|
||||||
if (price.recurringInterval !== 'year') {
|
if (price.recurringInterval !== SubscriptionInterval.Year) {
|
||||||
return 'Cancel anytime';
|
return 'Cancel anytime';
|
||||||
}
|
}
|
||||||
const monthPrice = prices.filter(
|
const monthPrice = prices.filter(
|
||||||
(price) => price.recurringInterval === 'month',
|
(price) => price.recurringInterval === SubscriptionInterval.Month,
|
||||||
)?.[0];
|
)?.[0];
|
||||||
if (
|
if (
|
||||||
isDefined(monthPrice) &&
|
isDefined(monthPrice) &&
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import { SubTitle } from '@/auth/components/SubTitle';
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
|
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
|
||||||
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
@@ -22,6 +22,8 @@ import { MainButton } from '@/ui/input/button/components/MainButton';
|
|||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
const StyledContentContainer = styled.div`
|
const StyledContentContainer = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -55,11 +57,11 @@ type Form = z.infer<typeof validationSchema>;
|
|||||||
|
|
||||||
export const CreateProfile = () => {
|
export const CreateProfile = () => {
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
const setNextOnboardingStatus = useSetNextOnboardingStatus();
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
||||||
currentWorkspaceMemberState,
|
currentWorkspaceMemberState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { updateOneRecord } = useUpdateOneRecord<WorkspaceMember>({
|
const { updateOneRecord } = useUpdateOneRecord<WorkspaceMember>({
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||||
});
|
});
|
||||||
@@ -100,17 +102,20 @@ export const CreateProfile = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
setCurrentWorkspaceMember(
|
setCurrentWorkspaceMember((current) => {
|
||||||
(current) =>
|
if (isDefined(current)) {
|
||||||
({
|
return {
|
||||||
...current,
|
...current,
|
||||||
name: {
|
name: {
|
||||||
firstName: data.firstName,
|
firstName: data.firstName,
|
||||||
lastName: data.lastName,
|
lastName: data.lastName,
|
||||||
},
|
},
|
||||||
colorScheme: 'System',
|
colorScheme: 'System',
|
||||||
}) as any,
|
};
|
||||||
);
|
}
|
||||||
|
return current;
|
||||||
|
});
|
||||||
|
setNextOnboardingStatus();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
enqueueSnackBar(error?.message, {
|
enqueueSnackBar(error?.message, {
|
||||||
variant: SnackBarVariant.Error,
|
variant: SnackBarVariant.Error,
|
||||||
@@ -119,6 +124,7 @@ export const CreateProfile = () => {
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
currentWorkspaceMember?.id,
|
currentWorkspaceMember?.id,
|
||||||
|
setNextOnboardingStatus,
|
||||||
enqueueSnackBar,
|
enqueueSnackBar,
|
||||||
setCurrentWorkspaceMember,
|
setCurrentWorkspaceMember,
|
||||||
updateOneRecord,
|
updateOneRecord,
|
||||||
@@ -137,7 +143,7 @@ export const CreateProfile = () => {
|
|||||||
PageHotkeyScope.CreateProfile,
|
PageHotkeyScope.CreateProfile,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (onboardingStatus !== OnboardingStatus.OngoingProfileCreation) {
|
if (onboardingStatus !== OnboardingStatus.ProfileCreation) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,18 +9,20 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import { SubTitle } from '@/auth/components/SubTitle';
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
||||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
|
||||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||||
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||||
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||||
import { Loader } from '@/ui/feedback/loader/components/Loader';
|
import { Loader } from '@/ui/feedback/loader/components/Loader';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { useActivateWorkspaceMutation } from '~/generated/graphql';
|
import {
|
||||||
|
OnboardingStatus,
|
||||||
|
useActivateWorkspaceMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
const StyledContentContainer = styled.div`
|
const StyledContentContainer = styled.div`
|
||||||
@@ -105,7 +107,7 @@ export const CreateWorkspace = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceActivation) {
|
if (onboardingStatus !== OnboardingStatus.WorkspaceActivation) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { SubTitle } from '@/auth/components/SubTitle';
|
|||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep';
|
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
import { SeparatorLineText } from '@/ui/display/text/components/SeparatorLineText';
|
import { SeparatorLineText } from '@/ui/display/text/components/SeparatorLineText';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
@@ -27,7 +27,10 @@ import { MainButton } from '@/ui/input/button/components/MainButton';
|
|||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { AnimatedTranslation } from '@/ui/utilities/animation/components/AnimatedTranslation';
|
import { AnimatedTranslation } from '@/ui/utilities/animation/components/AnimatedTranslation';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { OnboardingStep, useSendInviteLinkMutation } from '~/generated/graphql';
|
import {
|
||||||
|
OnboardingStatus,
|
||||||
|
useSendInviteLinkMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
const StyledAnimatedContainer = styled.div`
|
const StyledAnimatedContainer = styled.div`
|
||||||
@@ -63,7 +66,7 @@ export const InviteTeam = () => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const [sendInviteLink] = useSendInviteLinkMutation();
|
const [sendInviteLink] = useSendInviteLinkMutation();
|
||||||
const setNextOnboardingStep = useSetNextOnboardingStep();
|
const setNextOnboardingStatus = useSetNextOnboardingStatus();
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const {
|
const {
|
||||||
@@ -133,7 +136,7 @@ export const InviteTeam = () => {
|
|||||||
);
|
);
|
||||||
const result = await sendInviteLink({ variables: { emails } });
|
const result = await sendInviteLink({ variables: { emails } });
|
||||||
|
|
||||||
setNextOnboardingStep(OnboardingStep.InviteTeam);
|
setNextOnboardingStatus();
|
||||||
|
|
||||||
if (isDefined(result.errors)) {
|
if (isDefined(result.errors)) {
|
||||||
throw result.errors;
|
throw result.errors;
|
||||||
@@ -145,7 +148,7 @@ export const InviteTeam = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[enqueueSnackBar, sendInviteLink, setNextOnboardingStep],
|
[enqueueSnackBar, sendInviteLink, setNextOnboardingStatus],
|
||||||
);
|
);
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
@@ -157,7 +160,7 @@ export const InviteTeam = () => {
|
|||||||
[handleSubmit],
|
[handleSubmit],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (currentUser?.onboardingStep !== OnboardingStep.InviteTeam) {
|
if (currentUser?.onboardingStatus !== OnboardingStatus.InviteTeam) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { IconCheck, RGBA } from 'twenty-ui';
|
import { IconCheck, RGBA } from 'twenty-ui';
|
||||||
|
|
||||||
import { SubTitle } from '@/auth/components/SubTitle';
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
||||||
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
|
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledCheckContainer = styled.div`
|
const StyledCheckContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -29,8 +32,14 @@ const StyledButtonContainer = styled.div`
|
|||||||
|
|
||||||
export const PaymentSuccess = () => {
|
export const PaymentSuccess = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
const color =
|
const color =
|
||||||
theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10;
|
theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10;
|
||||||
|
|
||||||
|
if (currentUser?.onboardingStatus === OnboardingStatus.Completed) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AnimatedEaseIn>
|
<AnimatedEaseIn>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { SubTitle } from '@/auth/components/SubTitle';
|
|||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard';
|
import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard';
|
||||||
import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep';
|
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
|
||||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
@@ -19,7 +19,7 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|||||||
import {
|
import {
|
||||||
CalendarChannelVisibility,
|
CalendarChannelVisibility,
|
||||||
MessageChannelVisibility,
|
MessageChannelVisibility,
|
||||||
OnboardingStep,
|
OnboardingStatus,
|
||||||
useSkipSyncEmailOnboardingStepMutation,
|
useSkipSyncEmailOnboardingStepMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
@@ -40,12 +40,12 @@ const StyledActionLinkContainer = styled.div`
|
|||||||
export const SyncEmails = () => {
|
export const SyncEmails = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||||
const setNextOnboardingStep = useSetNextOnboardingStep();
|
const setNextOnboardingStatus = useSetNextOnboardingStatus();
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
const [visibility, setVisibility] = useState<MessageChannelVisibility>(
|
const [visibility, setVisibility] = useState<MessageChannelVisibility>(
|
||||||
MessageChannelVisibility.ShareEverything,
|
MessageChannelVisibility.ShareEverything,
|
||||||
);
|
);
|
||||||
const [skipSyncEmailOnboardingStepMutation] =
|
const [skipSyncEmailOnboardingStatusMutation] =
|
||||||
useSkipSyncEmailOnboardingStepMutation();
|
useSkipSyncEmailOnboardingStepMutation();
|
||||||
|
|
||||||
const handleButtonClick = async () => {
|
const handleButtonClick = async () => {
|
||||||
@@ -62,8 +62,8 @@ export const SyncEmails = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const continueWithoutSync = async () => {
|
const continueWithoutSync = async () => {
|
||||||
await skipSyncEmailOnboardingStepMutation();
|
await skipSyncEmailOnboardingStatusMutation();
|
||||||
setNextOnboardingStep(OnboardingStep.SyncEmail);
|
setNextOnboardingStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
@@ -75,7 +75,7 @@ export const SyncEmails = () => {
|
|||||||
[continueWithoutSync],
|
[continueWithoutSync],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (currentUser?.onboardingStep !== OnboardingStep.SyncEmail) {
|
if (currentUser?.onboardingStatus !== OnboardingStatus.SyncEmail) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw';
|
|||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan';
|
import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
import { sleep } from '~/utils/sleep';
|
import { sleep } from '~/utils/sleep';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
@@ -25,7 +26,9 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
currentUser: mockedOnboardingUserData(
|
||||||
|
OnboardingStatus.PlanRequired,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw';
|
|||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { CreateProfile } from '~/pages/onboarding/CreateProfile';
|
import { CreateProfile } from '~/pages/onboarding/CreateProfile';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Onboarding/CreateProfile',
|
title: 'Pages/Onboarding/CreateProfile',
|
||||||
@@ -24,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
currentUser: mockedOnboardingUserData(
|
||||||
|
OnboardingStatus.ProfileCreation,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -2,30 +2,22 @@ import { getOperationName } from '@apollo/client/utilities';
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace';
|
import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Onboarding/CreateWorkspace',
|
title: 'Pages/Onboarding/CreateWorkspace',
|
||||||
component: CreateWorkspace,
|
component: CreateWorkspace,
|
||||||
decorators: [
|
decorators: [PageDecorator],
|
||||||
(Story) => {
|
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
|
||||||
setCurrentWorkspace(mockedOnboardingUsersData[1].defaultWorkspace);
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
PageDecorator,
|
|
||||||
],
|
|
||||||
args: { routePath: AppPath.CreateWorkspace },
|
args: { routePath: AppPath.CreateWorkspace },
|
||||||
parameters: {
|
parameters: {
|
||||||
msw: {
|
msw: {
|
||||||
@@ -33,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[1],
|
currentUser: mockedOnboardingUserData(
|
||||||
|
OnboardingStatus.WorkspaceActivation,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { AppPath } from '~/modules/types/AppPath';
|
import { AppPath } from '~/modules/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
||||||
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Onboarding/InviteTeam',
|
title: 'Pages/Onboarding/InviteTeam',
|
||||||
@@ -25,10 +25,9 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: {
|
currentUser: mockedOnboardingUserData(
|
||||||
...mockedOnboardingUsersData[0],
|
OnboardingStatus.InviteTeam,
|
||||||
onboardingStep: OnboardingStep.InviteTeam,
|
),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { graphql, HttpResponse } from 'msw';
|
|||||||
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||||
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
||||||
import {
|
import {
|
||||||
PageDecorator,
|
PageDecorator,
|
||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Onboarding/PaymentSuccess',
|
title: 'Pages/Onboarding/PaymentSuccess',
|
||||||
@@ -24,7 +25,9 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
currentUser: mockedOnboardingUserData(
|
||||||
|
OnboardingStatus.WorkspaceActivation,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
import { OnboardingStep } from '~/generated/graphql';
|
import { OnboardingStatus } from '~/generated/graphql';
|
||||||
import { AppPath } from '~/modules/types/AppPath';
|
import { AppPath } from '~/modules/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
||||||
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
PageDecoratorArgs,
|
PageDecoratorArgs,
|
||||||
} from '~/testing/decorators/PageDecorator';
|
} from '~/testing/decorators/PageDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
import { mockedOnboardingUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
const meta: Meta<PageDecoratorArgs> = {
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
title: 'Pages/Onboarding/SyncEmails',
|
title: 'Pages/Onboarding/SyncEmails',
|
||||||
@@ -25,10 +25,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: {
|
currentUser: mockedOnboardingUserData(OnboardingStatus.SyncEmail),
|
||||||
...mockedOnboardingUsersData[0],
|
|
||||||
onboardingStep: OnboardingStep.SyncEmail,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ import {
|
|||||||
IconCurrencyDollar,
|
IconCurrencyDollar,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
|
||||||
import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage';
|
import { SettingsBillingCoverImage } from '@/billing/components/SettingsBillingCoverImage';
|
||||||
|
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SupportChat } from '@/support/components/SupportChat';
|
import { SupportChat } from '@/support/components/SupportChat';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
@@ -24,8 +23,11 @@ import { Button } from '@/ui/input/button/components/Button';
|
|||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { UndecoratedLink } from '@/ui/navigation/link/components/UndecoratedLink';
|
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
|
||||||
import {
|
import {
|
||||||
|
OnboardingStatus,
|
||||||
|
SubscriptionInterval,
|
||||||
|
SubscriptionStatus,
|
||||||
useBillingPortalSessionQuery,
|
useBillingPortalSessionQuery,
|
||||||
useUpdateBillingSubscriptionMutation,
|
useUpdateBillingSubscriptionMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
@@ -40,21 +42,21 @@ const StyledInvisibleChat = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type SwitchInfo = {
|
type SwitchInfo = {
|
||||||
newInterval: string;
|
newInterval: SubscriptionInterval;
|
||||||
to: string;
|
to: string;
|
||||||
from: string;
|
from: string;
|
||||||
impact: string;
|
impact: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MONTHLY_SWITCH_INFO: SwitchInfo = {
|
const MONTHLY_SWITCH_INFO: SwitchInfo = {
|
||||||
newInterval: 'year',
|
newInterval: SubscriptionInterval.Year,
|
||||||
to: 'to yearly',
|
to: 'to yearly',
|
||||||
from: 'from monthly to yearly',
|
from: 'from monthly to yearly',
|
||||||
impact: 'You will be charged immediately for the full year.',
|
impact: 'You will be charged immediately for the full year.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const YEARLY_SWITCH_INFO: SwitchInfo = {
|
const YEARLY_SWITCH_INFO: SwitchInfo = {
|
||||||
newInterval: 'month',
|
newInterval: SubscriptionInterval.Month,
|
||||||
to: 'to monthly',
|
to: 'to monthly',
|
||||||
from: 'from yearly to monthly',
|
from: 'from yearly to monthly',
|
||||||
impact: 'Your credit balance will be used to pay the monthly bills.',
|
impact: 'Your credit balance will be used to pay the monthly bills.',
|
||||||
@@ -68,10 +70,12 @@ const SWITCH_INFOS = {
|
|||||||
export const SettingsBilling = () => {
|
export const SettingsBilling = () => {
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
const subscriptionStatus = useSubscriptionStatus();
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
const switchingInfo =
|
const switchingInfo =
|
||||||
currentWorkspace?.currentBillingSubscription?.interval === 'year'
|
currentWorkspace?.currentBillingSubscription?.interval ===
|
||||||
|
SubscriptionInterval.Year
|
||||||
? SWITCH_INFOS.year
|
? SWITCH_INFOS.year
|
||||||
: SWITCH_INFOS.month;
|
: SWITCH_INFOS.month;
|
||||||
const [isSwitchingIntervalModalOpen, setIsSwitchingIntervalModalOpen] =
|
const [isSwitchingIntervalModalOpen, setIsSwitchingIntervalModalOpen] =
|
||||||
@@ -94,14 +98,15 @@ export const SettingsBilling = () => {
|
|||||||
onboardingStatus !== OnboardingStatus.Completed;
|
onboardingStatus !== OnboardingStatus.Completed;
|
||||||
|
|
||||||
const displayPaymentFailInfo =
|
const displayPaymentFailInfo =
|
||||||
onboardingStatus === OnboardingStatus.PastDue ||
|
subscriptionStatus === SubscriptionStatus.PastDue ||
|
||||||
onboardingStatus === OnboardingStatus.Unpaid;
|
subscriptionStatus === SubscriptionStatus.Unpaid;
|
||||||
|
|
||||||
const displaySubscriptionCanceledInfo =
|
const displaySubscriptionCanceledInfo =
|
||||||
onboardingStatus === OnboardingStatus.Canceled;
|
subscriptionStatus === SubscriptionStatus.Canceled;
|
||||||
|
|
||||||
const displaySubscribeInfo =
|
const displaySubscribeInfo =
|
||||||
onboardingStatus === OnboardingStatus.CompletedWithoutSubscription;
|
onboardingStatus === OnboardingStatus.Completed &&
|
||||||
|
!isDefined(subscriptionStatus);
|
||||||
|
|
||||||
const openBillingPortal = () => {
|
const openBillingPortal = () => {
|
||||||
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
||||||
@@ -153,22 +158,20 @@ export const SettingsBilling = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{displaySubscriptionCanceledInfo && (
|
{displaySubscriptionCanceledInfo && (
|
||||||
<UndecoratedLink to={AppPath.PlanRequired}>
|
<Info
|
||||||
<Info
|
text={'Subscription canceled. Please start a new one'}
|
||||||
text={'Subscription canceled. Please start a new one'}
|
buttonTitle={'Subscribe'}
|
||||||
buttonTitle={'Subscribe'}
|
accent={'danger'}
|
||||||
accent={'danger'}
|
to={AppPath.PlanRequired}
|
||||||
/>
|
/>
|
||||||
</UndecoratedLink>
|
|
||||||
)}
|
)}
|
||||||
{displaySubscribeInfo ? (
|
{displaySubscribeInfo ? (
|
||||||
<UndecoratedLink to={AppPath.PlanRequired}>
|
<Info
|
||||||
<Info
|
text={'Your workspace does not have an active subscription'}
|
||||||
text={'Your workspace does not have an active subscription'}
|
buttonTitle={'Subscribe'}
|
||||||
buttonTitle={'Subscribe'}
|
accent={'danger'}
|
||||||
accent={'danger'}
|
to={AppPath.PlanRequired}
|
||||||
/>
|
/>
|
||||||
</UndecoratedLink>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/Obje
|
|||||||
import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext';
|
import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField';
|
import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField';
|
||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||||
|
|
||||||
export const ObjectMetadataItemsDecorator: Decorator = (Story) => {
|
export const ObjectMetadataItemsDecorator: Decorator = (Story) => {
|
||||||
@@ -20,7 +20,7 @@ export const ObjectMetadataItemsDecorator: Decorator = (Story) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
|
setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
|
||||||
setCurrentUser(mockedUsersData[0]);
|
setCurrentUser(mockedUserData);
|
||||||
}, [setCurrentUser, setCurrentWorkspaceMember]);
|
}, [setCurrentUser, setCurrentWorkspaceMember]);
|
||||||
|
|
||||||
const chipGeneratorPerObjectPerField = useMemo(() => {
|
const chipGeneratorPerObjectPerField = useMemo(() => {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { mockedClientConfig } from '~/testing/mock-data/config';
|
|||||||
import { mockedObjectMetadataItemsQueryResult } from '~/testing/mock-data/metadata';
|
import { mockedObjectMetadataItemsQueryResult } from '~/testing/mock-data/metadata';
|
||||||
import { getPeopleMock } from '~/testing/mock-data/people';
|
import { getPeopleMock } from '~/testing/mock-data/people';
|
||||||
import { mockedRemoteTables } from '~/testing/mock-data/remote-tables';
|
import { mockedRemoteTables } from '~/testing/mock-data/remote-tables';
|
||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
import { mockedViewsData } from '~/testing/mock-data/views';
|
import { mockedViewsData } from '~/testing/mock-data/views';
|
||||||
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export const graphqlMocks = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedUsersData[0],
|
currentUser: mockedUserData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -38,4 +38,5 @@ export const mockedClientConfig: ClientConfig = {
|
|||||||
siteKey: 'MOCKED_SITE_KEY',
|
siteKey: 'MOCKED_SITE_KEY',
|
||||||
__typename: 'Captcha',
|
__typename: 'Captcha',
|
||||||
},
|
},
|
||||||
|
api: { mutationMaximumAffectedRecords: 100 },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
import { User, Workspace } from '~/generated/graphql';
|
import {
|
||||||
|
OnboardingStatus,
|
||||||
|
SubscriptionInterval,
|
||||||
|
SubscriptionStatus,
|
||||||
|
User,
|
||||||
|
Workspace,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
type MockedUser = Pick<
|
type MockedUser = Pick<
|
||||||
User,
|
User,
|
||||||
@@ -10,7 +16,7 @@ type MockedUser = Pick<
|
|||||||
| 'canImpersonate'
|
| 'canImpersonate'
|
||||||
| '__typename'
|
| '__typename'
|
||||||
| 'supportUserHash'
|
| 'supportUserHash'
|
||||||
| 'onboardingStep'
|
| 'onboardingStatus'
|
||||||
> & {
|
> & {
|
||||||
workspaceMember: WorkspaceMember | null;
|
workspaceMember: WorkspaceMember | null;
|
||||||
locale: string;
|
locale: string;
|
||||||
@@ -30,7 +36,6 @@ export const mockDefaultWorkspace: Workspace = {
|
|||||||
inviteHash: 'twenty.com-invite-hash',
|
inviteHash: 'twenty.com-invite-hash',
|
||||||
logo: workspaceLogoUrl,
|
logo: workspaceLogoUrl,
|
||||||
allowImpersonation: true,
|
allowImpersonation: true,
|
||||||
subscriptionStatus: 'active',
|
|
||||||
activationStatus: 'active',
|
activationStatus: 'active',
|
||||||
featureFlags: [
|
featureFlags: [
|
||||||
{
|
{
|
||||||
@@ -58,8 +63,8 @@ export const mockDefaultWorkspace: Workspace = {
|
|||||||
currentBillingSubscription: {
|
currentBillingSubscription: {
|
||||||
__typename: 'BillingSubscription',
|
__typename: 'BillingSubscription',
|
||||||
id: '7efbc3f7-6e5e-4128-957e-8d86808cdf6a',
|
id: '7efbc3f7-6e5e-4128-957e-8d86808cdf6a',
|
||||||
interval: 'month',
|
interval: SubscriptionInterval.Month,
|
||||||
status: 'active',
|
status: SubscriptionStatus.Active,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,49 +84,26 @@ export const mockedWorkspaceMemberData: WorkspaceMember = {
|
|||||||
userEmail: 'charles@test.com',
|
userEmail: 'charles@test.com',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockedUsersData: Array<MockedUser> = [
|
export const mockedUserData: MockedUser = {
|
||||||
{
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
__typename: 'User',
|
||||||
__typename: 'User',
|
email: 'charles@test.com',
|
||||||
email: 'charles@test.com',
|
firstName: 'Charles',
|
||||||
firstName: 'Charles',
|
lastName: 'Test',
|
||||||
lastName: 'Test',
|
canImpersonate: false,
|
||||||
canImpersonate: false,
|
supportUserHash:
|
||||||
supportUserHash:
|
'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d',
|
||||||
'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d',
|
workspaceMember: mockedWorkspaceMemberData,
|
||||||
workspaceMember: mockedWorkspaceMemberData,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
defaultWorkspace: mockDefaultWorkspace,
|
locale: 'en',
|
||||||
locale: 'en',
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
onboardingStatus: OnboardingStatus.Completed,
|
||||||
onboardingStep: null,
|
};
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
|
||||||
__typename: 'User',
|
|
||||||
email: 'felix@test.com',
|
|
||||||
firstName: 'Felix',
|
|
||||||
lastName: 'Test',
|
|
||||||
canImpersonate: false,
|
|
||||||
supportUserHash:
|
|
||||||
'54ac3986035961724cdb9a7a30c70e6463a4b68f0ecd2014c727171a82144b74',
|
|
||||||
workspaceMember: {
|
|
||||||
...mockedWorkspaceMemberData,
|
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
|
||||||
name: {
|
|
||||||
firstName: 'Felix',
|
|
||||||
lastName: 'Test',
|
|
||||||
},
|
|
||||||
userId: '81aeb270-d689-4515-bd5d-35dbe956da3b',
|
|
||||||
},
|
|
||||||
defaultWorkspace: mockDefaultWorkspace,
|
|
||||||
locale: 'en',
|
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
|
||||||
onboardingStep: null,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const mockedOnboardingUsersData: Array<MockedUser> = [
|
export const mockedOnboardingUserData = (
|
||||||
{
|
onboardingStatus?: OnboardingStatus,
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
||||||
__typename: 'User',
|
__typename: 'User',
|
||||||
email: 'workspace-onboarding@test.com',
|
email: 'workspace-onboarding@test.com',
|
||||||
@@ -130,35 +112,10 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
supportUserHash:
|
supportUserHash:
|
||||||
'4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254',
|
'4fb61d34ed3a4aeda2476d4b308b5162db9e1809b2b8277e6fdc6efc4a609254',
|
||||||
workspaceMember: {
|
workspaceMember: null,
|
||||||
...mockedWorkspaceMemberData,
|
|
||||||
id: 'd454f075-c72f-4ebe-bac7-d28e75e74a23',
|
|
||||||
name: {
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
userId: '7f793378-b939-43b7-8642-292c9510754c',
|
|
||||||
},
|
|
||||||
defaultWorkspace: mockDefaultWorkspace,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
onboardingStep: null,
|
onboardingStatus: onboardingStatus || null,
|
||||||
},
|
};
|
||||||
{
|
};
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
|
||||||
__typename: 'User',
|
|
||||||
email: 'profile-onboarding@test.com',
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
canImpersonate: false,
|
|
||||||
workspaceMember: null,
|
|
||||||
defaultWorkspace: {
|
|
||||||
...mockDefaultWorkspace,
|
|
||||||
activationStatus: 'inactive',
|
|
||||||
},
|
|
||||||
locale: 'en',
|
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
|
||||||
onboardingStep: null,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,61 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class UseEnumForSubscriptionStatusInterval1719327438923
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = 'UseEnumForSubscriptionStatusInterval1719327438923';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TYPE "core"."billingSubscription_status_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE "core"."billingSubscription_status_enum" USING "status"::"core"."billingSubscription_status_enum"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" SET NOT NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TYPE "core"."billingSubscription_interval_enum" AS ENUM('day', 'month', 'week', 'year')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE "core"."billingSubscription_interval_enum" USING "interval"::"core"."billingSubscription_interval_enum"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TYPE "core"."workspace_subscriptionstatus_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" DROP DEFAULT`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE "core"."workspace_subscriptionstatus_enum" USING "subscriptionStatus"::"core"."workspace_subscriptionstatus_enum"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" SET NOT NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" SET DEFAULT 'incomplete'::"core"."workspace_subscriptionstatus_enum"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ALTER COLUMN "subscriptionStatus" TYPE text`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP TYPE "core"."workspace_subscriptionstatus_enum"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."billingSubscription" ALTER COLUMN "interval" TYPE text`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP TYPE "core"."billingSubscription_interval_enum"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."billingSubscription" ALTER COLUMN "status" TYPE text`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP TYPE "core"."billingSubscription_status_enum"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class RemoveSubscriptionStatusFromCoreWorkspace1719494707738
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = 'RemoveSubscriptionStatusFromCoreWorkspace1719494707738';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" DROP COLUMN "subscriptionStatus"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP TYPE "core"."workspace_subscriptionstatus_enum"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TYPE "core"."workspace_subscriptionstatus_enum" AS ENUM('active', 'canceled', 'incomplete', 'incomplete_expired', 'past_due', 'paused', 'trialing', 'unpaid')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."workspace" ADD "subscriptionStatus" "core"."workspace_subscriptionstatus_enum" NOT NULL DEFAULT 'incomplete'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/stan
|
|||||||
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
||||||
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||||
|
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
||||||
|
|
||||||
import { AuthResolver } from './auth.resolver';
|
import { AuthResolver } from './auth.resolver';
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ const jwtModule = JwtModule.registerAsync({
|
|||||||
]),
|
]),
|
||||||
HttpModule,
|
HttpModule,
|
||||||
UserWorkspaceModule,
|
UserWorkspaceModule,
|
||||||
|
WorkspaceModule,
|
||||||
OnboardingModule,
|
OnboardingModule,
|
||||||
TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]),
|
TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]),
|
||||||
WorkspaceDataSourceModule,
|
WorkspaceDataSourceModule,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm
|
|||||||
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
||||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
|
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
|
||||||
|
|
||||||
describe('SignInUpService', () => {
|
describe('SignInUpService', () => {
|
||||||
let service: SignInUpService;
|
let service: SignInUpService;
|
||||||
@@ -40,6 +41,10 @@ describe('SignInUpService', () => {
|
|||||||
provide: HttpService,
|
provide: HttpService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: WorkspaceService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { FileUploadService } from 'src/engine/core-modules/file/file-upload/serv
|
|||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { getImageBufferFromUrl } from 'src/utils/image';
|
import { getImageBufferFromUrl } from 'src/utils/image';
|
||||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
|
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
|
||||||
|
|
||||||
export type SignInUpServiceInput = {
|
export type SignInUpServiceInput = {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -44,6 +45,7 @@ export class SignInUpService {
|
|||||||
@InjectRepository(User, 'core')
|
@InjectRepository(User, 'core')
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
private readonly userWorkspaceService: UserWorkspaceService,
|
private readonly userWorkspaceService: UserWorkspaceService,
|
||||||
|
private readonly workspaceService: WorkspaceService,
|
||||||
private readonly httpService: HttpService,
|
private readonly httpService: HttpService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
@@ -142,10 +144,12 @@ export class SignInUpService {
|
|||||||
ForbiddenException,
|
ForbiddenException,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isWorkspaceActivated =
|
||||||
|
await this.workspaceService.isWorkspaceActivated(workspace.id);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
!this.environmentService.get('IS_BILLING_ENABLED') ||
|
isWorkspaceActivated,
|
||||||
workspace.subscriptionStatus !== 'incomplete',
|
'Workspace is not ready to welcome new members',
|
||||||
'Workspace subscription status is incomplete',
|
|
||||||
ForbiddenException,
|
ForbiddenException,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -199,7 +203,6 @@ export class SignInUpService {
|
|||||||
displayName: '',
|
displayName: '',
|
||||||
domainName: '',
|
domainName: '',
|
||||||
inviteHash: v4(),
|
inviteHash: v4(),
|
||||||
subscriptionStatus: 'incomplete',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const workspace = await this.workspaceRepository.save(workspaceToCreate);
|
const workspace = await this.workspaceRepository.save(workspaceToCreate);
|
||||||
|
|||||||
@@ -10,13 +10,19 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|||||||
import { BillingResolver } from 'src/engine/core-modules/billing/billing.resolver';
|
import { BillingResolver } from 'src/engine/core-modules/billing/billing.resolver';
|
||||||
import { BillingWorkspaceMemberListener } from 'src/engine/core-modules/billing/listeners/billing-workspace-member.listener';
|
import { BillingWorkspaceMemberListener } from 'src/engine/core-modules/billing/listeners/billing-workspace-member.listener';
|
||||||
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||||
|
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
StripeModule,
|
StripeModule,
|
||||||
UserWorkspaceModule,
|
UserWorkspaceModule,
|
||||||
TypeOrmModule.forFeature(
|
TypeOrmModule.forFeature(
|
||||||
[BillingSubscription, BillingSubscriptionItem, Workspace],
|
[
|
||||||
|
BillingSubscription,
|
||||||
|
BillingSubscriptionItem,
|
||||||
|
Workspace,
|
||||||
|
FeatureFlagEntity,
|
||||||
|
],
|
||||||
'core',
|
'core',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,17 +2,25 @@ import { Injectable, Logger } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
|
||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
import { Not, Repository } from 'typeorm';
|
import { In, Not, Repository } from 'typeorm';
|
||||||
|
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';
|
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';
|
||||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
import {
|
||||||
|
BillingSubscription,
|
||||||
|
SubscriptionInterval,
|
||||||
|
SubscriptionStatus,
|
||||||
|
} from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity';
|
import { ProductPriceEntity } from 'src/engine/core-modules/billing/dto/product-price.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
|
import {
|
||||||
|
FeatureFlagEntity,
|
||||||
|
FeatureFlagKeys,
|
||||||
|
} from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
|
|
||||||
export enum AvailableProduct {
|
export enum AvailableProduct {
|
||||||
BasePlan = 'base-plan',
|
BasePlan = 'base-plan',
|
||||||
@@ -34,12 +42,45 @@ export class BillingService {
|
|||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
@InjectRepository(BillingSubscription, 'core')
|
@InjectRepository(BillingSubscription, 'core')
|
||||||
private readonly billingSubscriptionRepository: Repository<BillingSubscription>,
|
private readonly billingSubscriptionRepository: Repository<BillingSubscription>,
|
||||||
|
@InjectRepository(FeatureFlagEntity, 'core')
|
||||||
|
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
|
||||||
@InjectRepository(BillingSubscriptionItem, 'core')
|
@InjectRepository(BillingSubscriptionItem, 'core')
|
||||||
private readonly billingSubscriptionItemRepository: Repository<BillingSubscriptionItem>,
|
private readonly billingSubscriptionItemRepository: Repository<BillingSubscriptionItem>,
|
||||||
@InjectRepository(Workspace, 'core')
|
@InjectRepository(Workspace, 'core')
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
async getActiveSubscriptionWorkspaceIds() {
|
||||||
|
return (
|
||||||
|
await this.workspaceRepository.find({
|
||||||
|
where: this.environmentService.get('IS_BILLING_ENABLED')
|
||||||
|
? {
|
||||||
|
currentBillingSubscription: {
|
||||||
|
status: In([
|
||||||
|
SubscriptionStatus.Active,
|
||||||
|
SubscriptionStatus.Trialing,
|
||||||
|
SubscriptionStatus.PastDue,
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {},
|
||||||
|
select: ['id'],
|
||||||
|
})
|
||||||
|
).map((workspace) => workspace.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async isBillingEnabledForWorkspace(workspaceId: string) {
|
||||||
|
const isFreeAccessEnabled = await this.featureFlagRepository.findOneBy({
|
||||||
|
workspaceId,
|
||||||
|
key: FeatureFlagKeys.IsFreeAccessEnabled,
|
||||||
|
value: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
!isFreeAccessEnabled && this.environmentService.get('IS_BILLING_ENABLED')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getProductStripeId(product: AvailableProduct) {
|
getProductStripeId(product: AvailableProduct) {
|
||||||
if (product === AvailableProduct.BasePlan) {
|
if (product === AvailableProduct.BasePlan) {
|
||||||
return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID');
|
return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID');
|
||||||
@@ -84,13 +125,13 @@ export class BillingService {
|
|||||||
}) {
|
}) {
|
||||||
const notCanceledSubscriptions =
|
const notCanceledSubscriptions =
|
||||||
await this.billingSubscriptionRepository.find({
|
await this.billingSubscriptionRepository.find({
|
||||||
where: { ...criteria, status: Not('canceled') },
|
where: { ...criteria, status: Not(SubscriptionStatus.Canceled) },
|
||||||
relations: ['billingSubscriptionItems'],
|
relations: ['billingSubscriptionItems'],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
notCanceledSubscriptions.length <= 1,
|
notCanceledSubscriptions.length <= 1,
|
||||||
`More than on not canceled subscription for workspace ${criteria.workspaceId}`,
|
`More than one not canceled subscription for workspace ${criteria.workspaceId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return notCanceledSubscriptions?.[0];
|
return notCanceledSubscriptions?.[0];
|
||||||
@@ -171,7 +212,9 @@ export class BillingService {
|
|||||||
workspaceId: user.defaultWorkspaceId,
|
workspaceId: user.defaultWorkspaceId,
|
||||||
});
|
});
|
||||||
const newInterval =
|
const newInterval =
|
||||||
billingSubscription?.interval === 'year' ? 'month' : 'year';
|
billingSubscription?.interval === SubscriptionInterval.Year
|
||||||
|
? SubscriptionInterval.Month
|
||||||
|
: SubscriptionInterval.Year;
|
||||||
const billingSubscriptionItem = await this.getBillingSubscriptionItem(
|
const billingSubscriptionItem = await this.getBillingSubscriptionItem(
|
||||||
user.defaultWorkspaceId,
|
user.defaultWorkspaceId,
|
||||||
);
|
);
|
||||||
@@ -265,10 +308,6 @@ export class BillingService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.workspaceRepository.update(workspaceId, {
|
|
||||||
subscriptionStatus: data.object.status,
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.billingSubscriptionRepository.upsert(
|
await this.billingSubscriptionRepository.upsert(
|
||||||
{
|
{
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
@@ -302,5 +341,10 @@ export class BillingService {
|
|||||||
skipUpdateIfNoValuesChanged: true,
|
skipUpdateIfNoValuesChanged: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await this.featureFlagRepository.delete({
|
||||||
|
workspaceId,
|
||||||
|
key: FeatureFlagKeys.IsFreeAccessEnabled,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import { ArgsType, Field } from '@nestjs/graphql';
|
|||||||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
|
|
||||||
|
import { SubscriptionInterval } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class CheckoutSessionInput {
|
export class CheckoutSessionInput {
|
||||||
@Field(() => String)
|
@Field(() => SubscriptionInterval)
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
recurringInterval: Stripe.Price.Recurring.Interval;
|
recurringInterval: Stripe.Price.Recurring.Interval;
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { Field, ObjectType } from '@nestjs/graphql';
|
|||||||
|
|
||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
|
|
||||||
|
import { SubscriptionInterval } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class ProductPriceEntity {
|
export class ProductPriceEntity {
|
||||||
@Field(() => String)
|
@Field(() => SubscriptionInterval)
|
||||||
recurringInterval: Stripe.Price.Recurring.Interval;
|
recurringInterval: Stripe.Price.Recurring.Interval;
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
@@ -18,6 +18,27 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|||||||
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||||
|
|
||||||
|
export enum SubscriptionStatus {
|
||||||
|
Active = 'active',
|
||||||
|
Canceled = 'canceled',
|
||||||
|
Incomplete = 'incomplete',
|
||||||
|
IncompleteExpired = 'incomplete_expired',
|
||||||
|
PastDue = 'past_due',
|
||||||
|
Paused = 'paused',
|
||||||
|
Trialing = 'trialing',
|
||||||
|
Unpaid = 'unpaid',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SubscriptionInterval {
|
||||||
|
Day = 'day',
|
||||||
|
Month = 'month',
|
||||||
|
Week = 'week',
|
||||||
|
Year = 'year',
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' });
|
||||||
|
registerEnumType(SubscriptionInterval, { name: 'SubscriptionInterval' });
|
||||||
|
|
||||||
@Entity({ name: 'billingSubscription', schema: 'core' })
|
@Entity({ name: 'billingSubscription', schema: 'core' })
|
||||||
@ObjectType('BillingSubscription')
|
@ObjectType('BillingSubscription')
|
||||||
export class BillingSubscription {
|
export class BillingSubscription {
|
||||||
@@ -49,12 +70,20 @@ export class BillingSubscription {
|
|||||||
@Column({ unique: true, nullable: false })
|
@Column({ unique: true, nullable: false })
|
||||||
stripeSubscriptionId: string;
|
stripeSubscriptionId: string;
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => SubscriptionStatus)
|
||||||
@Column({ type: 'text', nullable: false })
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: Object.values(SubscriptionStatus),
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
status: Stripe.Subscription.Status;
|
status: Stripe.Subscription.Status;
|
||||||
|
|
||||||
@Field(() => String, { nullable: true })
|
@Field(() => SubscriptionInterval, { nullable: true })
|
||||||
@Column({ type: 'text', nullable: true })
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: Object.values(SubscriptionInterval),
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
interval: Stripe.Price.Recurring.Interval;
|
interval: Stripe.Price.Recurring.Interval;
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ import {
|
|||||||
UpdateSubscriptionJob,
|
UpdateSubscriptionJob,
|
||||||
UpdateSubscriptionJobData,
|
UpdateSubscriptionJobData,
|
||||||
} from 'src/engine/core-modules/billing/jobs/update-subscription.job';
|
} from 'src/engine/core-modules/billing/jobs/update-subscription.job';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BillingWorkspaceMemberListener {
|
export class BillingWorkspaceMemberListener {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectMessageQueue(MessageQueue.billingQueue)
|
@InjectMessageQueue(MessageQueue.billingQueue)
|
||||||
private readonly messageQueueService: MessageQueueService,
|
private readonly messageQueueService: MessageQueueService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly billingService: BillingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@OnEvent('workspaceMember.created')
|
@OnEvent('workspaceMember.created')
|
||||||
@@ -25,7 +25,12 @@ export class BillingWorkspaceMemberListener {
|
|||||||
async handleCreateOrDeleteEvent(
|
async handleCreateOrDeleteEvent(
|
||||||
payload: ObjectRecordCreateEvent<WorkspaceMemberWorkspaceEntity>,
|
payload: ObjectRecordCreateEvent<WorkspaceMemberWorkspaceEntity>,
|
||||||
) {
|
) {
|
||||||
if (!this.environmentService.get('IS_BILLING_ENABLED')) {
|
const isBillingEnabledForWorkspace =
|
||||||
|
await this.billingService.isBillingEnabledForWorkspace(
|
||||||
|
payload.workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isBillingEnabledForWorkspace) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export enum FeatureFlagKeys {
|
|||||||
IsStripeIntegrationEnabled = 'IS_STRIPE_INTEGRATION_ENABLED',
|
IsStripeIntegrationEnabled = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||||
IsContactCreationForSentAndReceivedEmailsEnabled = 'IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED',
|
IsContactCreationForSentAndReceivedEmailsEnabled = 'IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED',
|
||||||
IsGoogleCalendarSyncV2Enabled = 'IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED',
|
IsGoogleCalendarSyncV2Enabled = 'IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED',
|
||||||
|
IsFreeAccessEnabled = 'IS_FREE_ACCESS_ENABLED',
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity({ name: 'featureFlag', schema: 'core' })
|
@Entity({ name: 'featureFlag', schema: 'core' })
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export enum OnboardingStatus {
|
||||||
|
PLAN_REQUIRED = 'PLAN_REQUIRED',
|
||||||
|
WORKSPACE_ACTIVATION = 'WORKSPACE_ACTIVATION',
|
||||||
|
PROFILE_CREATION = 'PROFILE_CREATION',
|
||||||
|
SYNC_EMAIL = 'SYNC_EMAIL',
|
||||||
|
INVITE_TEAM = 'INVITE_TEAM',
|
||||||
|
COMPLETED = 'COMPLETED',
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export enum OnboardingStep {
|
|
||||||
SYNC_EMAIL = 'SYNC_EMAIL',
|
|
||||||
INVITE_TEAM = 'INVITE_TEAM',
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,19 @@ import { OnboardingResolver } from 'src/engine/core-modules/onboarding/onboardin
|
|||||||
import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module';
|
import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module';
|
||||||
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||||
|
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
||||||
|
import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module';
|
||||||
|
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DataSourceModule, UserWorkspaceModule, KeyValuePairModule],
|
imports: [
|
||||||
|
DataSourceModule,
|
||||||
|
WorkspaceManagerModule,
|
||||||
|
UserWorkspaceModule,
|
||||||
|
KeyValuePairModule,
|
||||||
|
EnvironmentModule,
|
||||||
|
BillingModule,
|
||||||
|
],
|
||||||
exports: [OnboardingService],
|
exports: [OnboardingService],
|
||||||
providers: [OnboardingService, OnboardingResolver],
|
providers: [OnboardingService, OnboardingResolver],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service';
|
import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service';
|
||||||
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
||||||
|
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||||
|
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||||
|
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
||||||
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
|
import { SubscriptionStatus } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
enum OnboardingStepValues {
|
enum OnboardingStepValues {
|
||||||
SKIPPED = 'SKIPPED',
|
SKIPPED = 'SKIPPED',
|
||||||
@@ -26,29 +33,71 @@ type OnboardingKeyValueType = {
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class OnboardingService {
|
export class OnboardingService {
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly billingService: BillingService,
|
||||||
|
private readonly workspaceManagerService: WorkspaceManagerService,
|
||||||
private readonly userWorkspaceService: UserWorkspaceService,
|
private readonly userWorkspaceService: UserWorkspaceService,
|
||||||
private readonly keyValuePairService: KeyValuePairService<OnboardingKeyValueType>,
|
private readonly keyValuePairService: KeyValuePairService<OnboardingKeyValueType>,
|
||||||
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
||||||
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
||||||
|
@InjectWorkspaceRepository(WorkspaceMemberWorkspaceEntity)
|
||||||
|
private readonly workspaceMemberRepository: WorkspaceRepository<WorkspaceMemberWorkspaceEntity>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private async isSyncEmailOnboardingStep(user: User, workspace: Workspace) {
|
private async isSubscriptionIncompleteOnboardingStatus(user: User) {
|
||||||
|
const isBillingEnabledForWorkspace =
|
||||||
|
await this.billingService.isBillingEnabledForWorkspace(
|
||||||
|
user.defaultWorkspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isBillingEnabledForWorkspace) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentBillingSubscription =
|
||||||
|
await this.billingService.getCurrentBillingSubscription({
|
||||||
|
workspaceId: user.defaultWorkspaceId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
!isDefined(currentBillingSubscription) ||
|
||||||
|
currentBillingSubscription?.status === SubscriptionStatus.Incomplete
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async isWorkspaceActivationOnboardingStatus(user: User) {
|
||||||
|
return !(await this.workspaceManagerService.doesDataSourceExist(
|
||||||
|
user.defaultWorkspaceId,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async isProfileCreationOnboardingStatus(user: User) {
|
||||||
|
const workspaceMember = await this.workspaceMemberRepository.findOneBy({
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
workspaceMember &&
|
||||||
|
(!workspaceMember.name.firstName || !workspaceMember.name.lastName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async isSyncEmailOnboardingStatus(user: User) {
|
||||||
const syncEmailValue = await this.keyValuePairService.get({
|
const syncEmailValue = await this.keyValuePairService.get({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
workspaceId: workspace.id,
|
workspaceId: user.defaultWorkspaceId,
|
||||||
key: OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP,
|
key: OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP,
|
||||||
});
|
});
|
||||||
const isSyncEmailSkipped = syncEmailValue === OnboardingStepValues.SKIPPED;
|
const isSyncEmailSkipped = syncEmailValue === OnboardingStepValues.SKIPPED;
|
||||||
const connectedAccounts =
|
const connectedAccounts =
|
||||||
await this.connectedAccountRepository.getAllByUserId(
|
await this.connectedAccountRepository.getAllByUserId(
|
||||||
user.id,
|
user.id,
|
||||||
workspace.id,
|
user.defaultWorkspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
return !isSyncEmailSkipped && !connectedAccounts?.length;
|
return !isSyncEmailSkipped && !connectedAccounts?.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async isInviteTeamOnboardingStep(workspace: Workspace) {
|
private async isInviteTeamOnboardingStatus(workspace: Workspace) {
|
||||||
const inviteTeamValue = await this.keyValuePairService.get({
|
const inviteTeamValue = await this.keyValuePairService.get({
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
key: OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP,
|
key: OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP,
|
||||||
@@ -64,19 +113,28 @@ export class OnboardingService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOnboardingStep(
|
async getOnboardingStatus(user: User) {
|
||||||
user: User,
|
if (await this.isSubscriptionIncompleteOnboardingStatus(user)) {
|
||||||
workspace: Workspace,
|
return OnboardingStatus.PLAN_REQUIRED;
|
||||||
): Promise<OnboardingStep | null> {
|
|
||||||
if (await this.isSyncEmailOnboardingStep(user, workspace)) {
|
|
||||||
return OnboardingStep.SYNC_EMAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await this.isInviteTeamOnboardingStep(workspace)) {
|
if (await this.isWorkspaceActivationOnboardingStatus(user)) {
|
||||||
return OnboardingStep.INVITE_TEAM;
|
return OnboardingStatus.WORKSPACE_ACTIVATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
if (await this.isProfileCreationOnboardingStatus(user)) {
|
||||||
|
return OnboardingStatus.PROFILE_CREATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await this.isSyncEmailOnboardingStatus(user)) {
|
||||||
|
return OnboardingStatus.SYNC_EMAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await this.isInviteTeamOnboardingStatus(user.defaultWorkspace)) {
|
||||||
|
return OnboardingStatus.INVITE_TEAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OnboardingStatus.COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
async skipInviteTeamOnboardingStep(workspaceId: string) {
|
async skipInviteTeamOnboardingStep(workspaceId: string) {
|
||||||
|
|||||||
@@ -107,9 +107,7 @@ export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspace> {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspaceMemberCount = await this.workspaceMemberRepository.count();
|
return await this.workspaceMemberRepository.count();
|
||||||
|
|
||||||
return workspaceMemberCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkUserWorkspaceExists(
|
async checkUserWorkspaceExists(
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-mem
|
|||||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||||
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
||||||
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum';
|
||||||
|
|
||||||
registerEnumType(OnboardingStep, {
|
registerEnumType(OnboardingStatus, {
|
||||||
name: 'OnboardingStep',
|
name: 'OnboardingStatus',
|
||||||
description: 'Onboarding step',
|
description: 'Onboarding status',
|
||||||
});
|
});
|
||||||
|
|
||||||
@Entity({ name: 'user', schema: 'core' })
|
@Entity({ name: 'user', schema: 'core' })
|
||||||
@@ -119,6 +119,6 @@ export class User {
|
|||||||
@OneToMany(() => UserWorkspace, (userWorkspace) => userWorkspace.user)
|
@OneToMany(() => UserWorkspace, (userWorkspace) => userWorkspace.user)
|
||||||
workspaces: Relation<UserWorkspace[]>;
|
workspaces: Relation<UserWorkspace[]>;
|
||||||
|
|
||||||
@Field(() => OnboardingStep, { nullable: true })
|
@Field(() => OnboardingStatus, { nullable: true })
|
||||||
onboardingStep: OnboardingStep;
|
onboardingStatus: OnboardingStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
|||||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||||
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum';
|
||||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context';
|
import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context';
|
||||||
|
|
||||||
@@ -118,17 +118,13 @@ export class UserResolver {
|
|||||||
return this.userService.deleteUser(userId);
|
return this.userService.deleteUser(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => OnboardingStep)
|
@ResolveField(() => OnboardingStatus)
|
||||||
async onboardingStep(@Parent() user: User): Promise<OnboardingStep | null> {
|
async onboardingStatus(@Parent() user: User): Promise<OnboardingStatus> {
|
||||||
if (!user) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextInstance = await this.loadServiceWithWorkspaceContext.load(
|
const contextInstance = await this.loadServiceWithWorkspaceContext.load(
|
||||||
this.onboardingService,
|
this.onboardingService,
|
||||||
user.defaultWorkspaceId,
|
user.defaultWorkspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
return contextInstance.getOnboardingStep(user, user.defaultWorkspace);
|
return contextInstance.getOnboardingStatus(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
Relation,
|
Relation,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import Stripe from 'stripe';
|
|
||||||
|
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
@@ -85,10 +84,6 @@ export class Workspace {
|
|||||||
@OneToMany(() => FeatureFlagEntity, (featureFlag) => featureFlag.workspace)
|
@OneToMany(() => FeatureFlagEntity, (featureFlag) => featureFlag.workspace)
|
||||||
featureFlags: Relation<FeatureFlagEntity[]>;
|
featureFlags: Relation<FeatureFlagEntity[]>;
|
||||||
|
|
||||||
@Field(() => String)
|
|
||||||
@Column({ type: 'text', default: 'incomplete' })
|
|
||||||
subscriptionStatus: Stripe.Subscription.Status;
|
|
||||||
|
|
||||||
@Field({ nullable: true })
|
@Field({ nullable: true })
|
||||||
currentBillingSubscription: BillingSubscription;
|
currentBillingSubscription: BillingSubscription;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { WorkspaceService } from 'src/engine/core-modules/workspace/services/wor
|
|||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { getDryRunLogHeader } from 'src/utils/get-dry-run-log-header';
|
import { getDryRunLogHeader } from 'src/utils/get-dry-run-log-header';
|
||||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||||
|
import { SubscriptionStatus } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
|
|
||||||
type DeleteIncompleteWorkspacesCommandOptions = {
|
type DeleteIncompleteWorkspacesCommandOptions = {
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
@@ -52,7 +53,7 @@ export class DeleteIncompleteWorkspacesCommand extends CommandRunner {
|
|||||||
options: DeleteIncompleteWorkspacesCommandOptions,
|
options: DeleteIncompleteWorkspacesCommandOptions,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const where: FindOptionsWhere<Workspace> = {
|
const where: FindOptionsWhere<Workspace> = {
|
||||||
subscriptionStatus: 'incomplete',
|
currentBillingSubscription: { status: SubscriptionStatus.Incomplete },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.workspaceIds) {
|
if (options.workspaceIds) {
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export class AddStandardIdCommand extends CommandRunner {
|
|||||||
IS_STRIPE_INTEGRATION_ENABLED: false,
|
IS_STRIPE_INTEGRATION_ENABLED: false,
|
||||||
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
|
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
|
||||||
IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true,
|
IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true,
|
||||||
|
IS_FREE_ACCESS_ENABLED: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const standardFieldMetadataCollection = this.standardFieldFactory.create(
|
const standardFieldMetadataCollection = this.standardFieldFactory.create(
|
||||||
@@ -76,6 +77,7 @@ export class AddStandardIdCommand extends CommandRunner {
|
|||||||
IS_STRIPE_INTEGRATION_ENABLED: false,
|
IS_STRIPE_INTEGRATION_ENABLED: false,
|
||||||
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
|
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
|
||||||
IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true,
|
IS_GOOGLE_CALENDAR_SYNC_V2_ENABLED: true,
|
||||||
|
IS_FREE_ACCESS_ENABLED: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,17 @@ import { Module } from '@nestjs/common';
|
|||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { GoogleCalendarSyncCronJob } from 'src/modules/calendar/crons/jobs/google-calendar-sync.cron.job';
|
import { GoogleCalendarSyncCronJob } from 'src/modules/calendar/crons/jobs/google-calendar-sync.cron.job';
|
||||||
import { WorkspaceGoogleCalendarSyncModule } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module';
|
import { WorkspaceGoogleCalendarSyncModule } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.module';
|
||||||
|
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([Workspace, FeatureFlagEntity], 'core'),
|
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
|
||||||
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
||||||
WorkspaceGoogleCalendarSyncModule,
|
WorkspaceGoogleCalendarSyncModule,
|
||||||
|
BillingModule,
|
||||||
],
|
],
|
||||||
providers: [GoogleCalendarSyncCronJob],
|
providers: [GoogleCalendarSyncCronJob],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import { Scope } from '@nestjs/common';
|
|||||||
|
|
||||||
import { Repository, In } from 'typeorm';
|
import { Repository, In } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { WorkspaceGoogleCalendarSyncService } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service';
|
import { WorkspaceGoogleCalendarSyncService } from 'src/modules/calendar/services/workspace-google-calendar-sync/workspace-google-calendar-sync.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||||
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
||||||
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Processor({
|
@Processor({
|
||||||
queueName: MessageQueue.cronQueue,
|
queueName: MessageQueue.cronQueue,
|
||||||
@@ -17,26 +16,16 @@ import { Process } from 'src/engine/integrations/message-queue/decorators/proces
|
|||||||
})
|
})
|
||||||
export class GoogleCalendarSyncCronJob {
|
export class GoogleCalendarSyncCronJob {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Workspace, 'core')
|
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
|
||||||
@InjectRepository(DataSourceEntity, 'metadata')
|
@InjectRepository(DataSourceEntity, 'metadata')
|
||||||
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
||||||
private readonly workspaceGoogleCalendarSyncService: WorkspaceGoogleCalendarSyncService,
|
private readonly workspaceGoogleCalendarSyncService: WorkspaceGoogleCalendarSyncService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly billingService: BillingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Process(GoogleCalendarSyncCronJob.name)
|
@Process(GoogleCalendarSyncCronJob.name)
|
||||||
async handle(): Promise<void> {
|
async handle(): Promise<void> {
|
||||||
const workspaceIds = (
|
const workspaceIds =
|
||||||
await this.workspaceRepository.find({
|
await this.billingService.getActiveSubscriptionWorkspaceIds();
|
||||||
where: this.environmentService.get('IS_BILLING_ENABLED')
|
|
||||||
? {
|
|
||||||
subscriptionStatus: In(['active', 'trialing', 'past_due']),
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
select: ['id'],
|
|
||||||
})
|
|
||||||
).map((workspace) => workspace.id);
|
|
||||||
|
|
||||||
const dataSources = await this.dataSourceRepository.find({
|
const dataSources = await this.dataSourceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Repository, In } from 'typeorm';
|
import { Repository, In } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||||
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||||
import {
|
import {
|
||||||
MessageChannelSyncStage,
|
MessageChannelSyncStage,
|
||||||
@@ -21,35 +19,26 @@ import {
|
|||||||
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
||||||
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
||||||
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Processor(MessageQueue.cronQueue)
|
@Processor(MessageQueue.cronQueue)
|
||||||
export class MessagingMessageListFetchCronJob {
|
export class MessagingMessageListFetchCronJob {
|
||||||
private readonly logger = new Logger(MessagingMessageListFetchCronJob.name);
|
private readonly logger = new Logger(MessagingMessageListFetchCronJob.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Workspace, 'core')
|
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
|
||||||
@InjectRepository(DataSourceEntity, 'metadata')
|
@InjectRepository(DataSourceEntity, 'metadata')
|
||||||
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
||||||
@InjectMessageQueue(MessageQueue.messagingQueue)
|
@InjectMessageQueue(MessageQueue.messagingQueue)
|
||||||
private readonly messageQueueService: MessageQueueService,
|
private readonly messageQueueService: MessageQueueService,
|
||||||
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
||||||
private readonly messageChannelRepository: MessageChannelRepository,
|
private readonly messageChannelRepository: MessageChannelRepository,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly billingService: BillingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Process(MessagingMessageListFetchCronJob.name)
|
@Process(MessagingMessageListFetchCronJob.name)
|
||||||
async handle(): Promise<void> {
|
async handle(): Promise<void> {
|
||||||
const workspaceIds = (
|
const workspaceIds =
|
||||||
await this.workspaceRepository.find({
|
await this.billingService.getActiveSubscriptionWorkspaceIds();
|
||||||
where: this.environmentService.get('IS_BILLING_ENABLED')
|
|
||||||
? {
|
|
||||||
subscriptionStatus: In(['active', 'trialing', 'past_due']),
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
select: ['id'],
|
|
||||||
})
|
|
||||||
).map((workspace) => workspace.id);
|
|
||||||
|
|
||||||
const dataSources = await this.dataSourceRepository.find({
|
const dataSources = await this.dataSourceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Repository, In } from 'typeorm';
|
import { Repository, In } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||||
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
||||||
import {
|
import {
|
||||||
@@ -21,35 +19,26 @@ import {
|
|||||||
MessageChannelSyncStage,
|
MessageChannelSyncStage,
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Processor(MessageQueue.cronQueue)
|
@Processor(MessageQueue.cronQueue)
|
||||||
export class MessagingMessagesImportCronJob {
|
export class MessagingMessagesImportCronJob {
|
||||||
private readonly logger = new Logger(MessagingMessagesImportCronJob.name);
|
private readonly logger = new Logger(MessagingMessagesImportCronJob.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Workspace, 'core')
|
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
|
||||||
@InjectRepository(DataSourceEntity, 'metadata')
|
@InjectRepository(DataSourceEntity, 'metadata')
|
||||||
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
||||||
private readonly environmentService: EnvironmentService,
|
|
||||||
@InjectMessageQueue(MessageQueue.messagingQueue)
|
@InjectMessageQueue(MessageQueue.messagingQueue)
|
||||||
private readonly messageQueueService: MessageQueueService,
|
private readonly messageQueueService: MessageQueueService,
|
||||||
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
||||||
private readonly messageChannelRepository: MessageChannelRepository,
|
private readonly messageChannelRepository: MessageChannelRepository,
|
||||||
|
private readonly billingService: BillingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Process(MessagingMessagesImportCronJob.name)
|
@Process(MessagingMessagesImportCronJob.name)
|
||||||
async handle(): Promise<void> {
|
async handle(): Promise<void> {
|
||||||
const workspaceIds = (
|
const workspaceIds =
|
||||||
await this.workspaceRepository.find({
|
await this.billingService.getActiveSubscriptionWorkspaceIds();
|
||||||
where: this.environmentService.get('IS_BILLING_ENABLED')
|
|
||||||
? {
|
|
||||||
subscriptionStatus: In(['active', 'trialing', 'past_due']),
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
select: ['id'],
|
|
||||||
})
|
|
||||||
).map((workspace) => workspace.id);
|
|
||||||
|
|
||||||
const dataSources = await this.dataSourceRepository.find({
|
const dataSources = await this.dataSourceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Repository, In } from 'typeorm';
|
import { Repository, In } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||||
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
||||||
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||||
@@ -14,31 +12,22 @@ import {
|
|||||||
MessagingOngoingStaleJobData,
|
MessagingOngoingStaleJobData,
|
||||||
MessagingOngoingStaleJob,
|
MessagingOngoingStaleJob,
|
||||||
} from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
} from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Processor(MessageQueue.cronQueue)
|
@Processor(MessageQueue.cronQueue)
|
||||||
export class MessagingOngoingStaleCronJob {
|
export class MessagingOngoingStaleCronJob {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Workspace, 'core')
|
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
|
||||||
@InjectRepository(DataSourceEntity, 'metadata')
|
@InjectRepository(DataSourceEntity, 'metadata')
|
||||||
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
||||||
private readonly environmentService: EnvironmentService,
|
|
||||||
@InjectMessageQueue(MessageQueue.messagingQueue)
|
@InjectMessageQueue(MessageQueue.messagingQueue)
|
||||||
private readonly messageQueueService: MessageQueueService,
|
private readonly messageQueueService: MessageQueueService,
|
||||||
|
private readonly billingService: BillingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Process(MessagingOngoingStaleCronJob.name)
|
@Process(MessagingOngoingStaleCronJob.name)
|
||||||
async handle(): Promise<void> {
|
async handle(): Promise<void> {
|
||||||
const workspaceIds = (
|
const workspaceIds =
|
||||||
await this.workspaceRepository.find({
|
await this.billingService.getActiveSubscriptionWorkspaceIds();
|
||||||
where: this.environmentService.get('IS_BILLING_ENABLED')
|
|
||||||
? {
|
|
||||||
subscriptionStatus: In(['active', 'trialing', 'past_due']),
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
select: ['id'],
|
|
||||||
})
|
|
||||||
).map((workspace) => workspace.id);
|
|
||||||
|
|
||||||
const dataSources = await this.dataSourceRepository.find({
|
const dataSources = await this.dataSourceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { MessagingMessageListFetchJob } from 'src/modules/messaging/message-impo
|
|||||||
import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job';
|
import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job';
|
||||||
import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
||||||
import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener';
|
import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener';
|
||||||
|
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -28,6 +29,7 @@ import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules
|
|||||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||||
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
||||||
TwentyORMModule.forFeature([MessageChannelWorkspaceEntity]),
|
TwentyORMModule.forFeature([MessageChannelWorkspaceEntity]),
|
||||||
|
BillingModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
MessagingMessageListFetchCronCommand,
|
MessagingMessageListFetchCronCommand,
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
|
||||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
||||||
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||||
|
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||||
|
|
||||||
@Processor(MessageQueue.cronQueue)
|
@Processor(MessageQueue.cronQueue)
|
||||||
export class MessagingMessageChannelSyncStatusMonitoringCronJob {
|
export class MessagingMessageChannelSyncStatusMonitoringCronJob {
|
||||||
@@ -28,7 +28,7 @@ export class MessagingMessageChannelSyncStatusMonitoringCronJob {
|
|||||||
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
private readonly dataSourceRepository: Repository<DataSourceEntity>,
|
||||||
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
||||||
private readonly messageChannelRepository: MessageChannelRepository,
|
private readonly messageChannelRepository: MessageChannelRepository,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly billingService: BillingService,
|
||||||
private readonly messagingTelemetryService: MessagingTelemetryService,
|
private readonly messagingTelemetryService: MessagingTelemetryService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -41,16 +41,8 @@ export class MessagingMessageChannelSyncStatusMonitoringCronJob {
|
|||||||
message: 'Starting message channel sync status monitoring',
|
message: 'Starting message channel sync status monitoring',
|
||||||
});
|
});
|
||||||
|
|
||||||
const workspaceIds = (
|
const workspaceIds =
|
||||||
await this.workspaceRepository.find({
|
await this.billingService.getActiveSubscriptionWorkspaceIds();
|
||||||
where: this.environmentService.get('IS_BILLING_ENABLED')
|
|
||||||
? {
|
|
||||||
subscriptionStatus: In(['active', 'trialing', 'past_due']),
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
select: ['id'],
|
|
||||||
})
|
|
||||||
).map((workspace) => workspace.id);
|
|
||||||
|
|
||||||
const dataSources = await this.dataSourceRepository.find({
|
const dataSources = await this.dataSourceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-s
|
|||||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||||
import { MessagingMessageChannelSyncStatusMonitoringCronCommand } from 'src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command';
|
import { MessagingMessageChannelSyncStatusMonitoringCronCommand } from 'src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command';
|
||||||
import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron';
|
import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron';
|
||||||
|
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
MessagingCommonModule,
|
MessagingCommonModule,
|
||||||
|
BillingModule,
|
||||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||||
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -11,22 +11,6 @@ export class WorkspaceMemberRepository {
|
|||||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async getByIds(
|
|
||||||
userIds: string[],
|
|
||||||
workspaceId: string,
|
|
||||||
): Promise<WorkspaceMemberWorkspaceEntity[]> {
|
|
||||||
const dataSourceSchema =
|
|
||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
|
||||||
|
|
||||||
const result = await this.workspaceDataSourceService.executeRawQuery(
|
|
||||||
`SELECT * FROM ${dataSourceSchema}."workspaceMember" WHERE "userId" = ANY($1)`,
|
|
||||||
[userIds],
|
|
||||||
workspaceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async find(workspaceMemberId: string, workspaceId: string) {
|
public async find(workspaceMemberId: string, workspaceId: string) {
|
||||||
const dataSourceSchema =
|
const dataSourceSchema =
|
||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|||||||
Reference in New Issue
Block a user