diff --git a/packages/twenty-chrome-extension/src/generated/graphql.tsx b/packages/twenty-chrome-extension/src/generated/graphql.tsx index 33b20dd3498..2ced7aaa8fd 100644 --- a/packages/twenty-chrome-extension/src/generated/graphql.tsx +++ b/packages/twenty-chrome-extension/src/generated/graphql.tsx @@ -74,7 +74,7 @@ export type ActivityActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -86,7 +86,7 @@ export type ActivityAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -98,7 +98,7 @@ export type ActivityCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** An activity */ @@ -397,6 +397,10 @@ export type Analytics = { success: Scalars['Boolean']; }; +export type ApiConfig = { + mutationMaximumAffectedRecords: Scalars['Float']; +}; + /** An api key */ export type ApiKey = { /** Creation date */ @@ -853,8 +857,8 @@ export type Billing = { export type BillingSubscription = { id: Scalars['UUID']; - interval?: Maybe; - status: Scalars['String']; + interval?: Maybe; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -992,6 +996,12 @@ export type CalendarChannel = { isSyncEnabled?: Maybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: Maybe; + /** Sync stage */ + syncStage?: Maybe; + /** Sync stage started at */ + syncStageStartedAt?: Maybe; + /** Sync status */ + syncStatus?: Maybe; /** Throttle Failure Count */ throttleFailureCount?: Maybe; /** Update date */ @@ -1009,7 +1019,7 @@ export type CalendarChannelCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Calendar Channels */ @@ -1036,6 +1046,12 @@ export type CalendarChannelCreateInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1170,6 +1186,12 @@ export type CalendarChannelFilterInput = { or?: InputMaybe>>; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1194,6 +1216,12 @@ export type CalendarChannelOrderByInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1202,6 +1230,50 @@ export type CalendarChannelOrderByInput = { visibility?: InputMaybe; }; +/** Sync stage */ +export enum CalendarChannelSyncStageEnum { + /** Calendar events import ongoing */ + CalendarEventsImportOngoing = 'CALENDAR_EVENTS_IMPORT_ONGOING', + /** Calendar events import pending */ + CalendarEventsImportPending = 'CALENDAR_EVENTS_IMPORT_PENDING', + /** Calendar event list fetch ongoing */ + CalendarEventListFetchOngoing = 'CALENDAR_EVENT_LIST_FETCH_ONGOING', + /** Failed */ + Failed = 'FAILED', + /** Full calendar event list fetch pending */ + FullCalendarEventListFetchPending = 'FULL_CALENDAR_EVENT_LIST_FETCH_PENDING', + /** Partial calendar event list fetch pending */ + PartialCalendarEventListFetchPending = 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING' +} + +export type CalendarChannelSyncStageEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + +/** Sync status */ +export enum CalendarChannelSyncStatusEnum { + /** Active */ + Active = 'ACTIVE', + /** Failed Insufficient Permissions */ + FailedInsufficientPermissions = 'FAILED_INSUFFICIENT_PERMISSIONS', + /** Failed Unknown */ + FailedUnknown = 'FAILED_UNKNOWN', + /** Not Synced */ + NotSynced = 'NOT_SYNCED', + /** Ongoing */ + Ongoing = 'ONGOING' +} + +export type CalendarChannelSyncStatusEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Calendar Channels */ export type CalendarChannelUpdateInput = { /** Connected Account id foreign key */ @@ -1218,6 +1290,12 @@ export type CalendarChannelUpdateInput = { isSyncEnabled?: InputMaybe; /** Sync Cursor. Used for syncing events from the calendar provider */ syncCursor?: InputMaybe; + /** Sync stage */ + syncStage?: InputMaybe; + /** Sync stage started at */ + syncStageStartedAt?: InputMaybe; + /** Sync status */ + syncStatus?: InputMaybe; /** Throttle Failure Count */ throttleFailureCount?: InputMaybe; /** Update date */ @@ -1296,7 +1374,7 @@ export type CalendarEventCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1308,7 +1386,7 @@ export type CalendarEventCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Calendar events */ @@ -1645,6 +1723,7 @@ export enum CaptchaDriverType { } export type ClientConfig = { + api: ApiConfig; authProviders: AuthProviders; billing: Billing; captcha: Captcha; @@ -1811,7 +1890,7 @@ export type CompanyActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1823,7 +1902,7 @@ export type CompanyAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1835,7 +1914,7 @@ export type CompanyFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1847,7 +1926,7 @@ export type CompanyOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1859,7 +1938,7 @@ export type CompanyPeopleArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -1871,7 +1950,7 @@ export type CompanyTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A company */ @@ -2050,7 +2129,7 @@ export type ConnectedAccountCalendarChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -2062,7 +2141,7 @@ export type ConnectedAccountMessageChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A connected account */ @@ -2597,7 +2676,7 @@ export type MessageMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -2609,7 +2688,7 @@ export type MessageMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Channels */ @@ -2659,7 +2738,7 @@ export type MessageChannelMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Channels */ @@ -3300,7 +3379,7 @@ export type MessageThreadMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -3312,7 +3391,7 @@ export type MessageThreadMessagesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** Message Thread */ @@ -3517,7 +3596,9 @@ export type Mutation = { deleteWebhooks?: Maybe>; deleteWorkspaceMember?: Maybe; deleteWorkspaceMembers?: Maybe>; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; executeQuickActionOnActivity?: Maybe; executeQuickActionOnActivityTarget?: Maybe; @@ -3649,288 +3730,344 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe; }; export type MutationCreateActivitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateActivityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateActivityTargetArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateActivityTargetsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateApiKeyArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateApiKeysArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateAttachmentArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateAttachmentsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateAuditLogArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateAuditLogsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateBlocklistArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateBlocklistsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelEventAssociationArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelEventAssociationsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarChannelsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventParticipantArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventParticipantsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCalendarEventsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCommentArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateCommentsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCompaniesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateCompanyArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateConnectedAccountArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateConnectedAccountsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateFavoriteArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateFavoritesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelMessageAssociationArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelMessageAssociationsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageChannelsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageParticipantArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageParticipantsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessageThreadArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateMessageThreadsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateMessagesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateOpportunitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateOpportunityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreatePeopleArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreatePersonArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateTimelineActivitiesArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateTimelineActivityArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFieldArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFieldsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewFilterArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewFiltersArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewSortArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateViewSortsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateViewsArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateWebhookArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateWebhooksArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; export type MutationCreateWorkspaceMemberArgs = { data?: InputMaybe; + upsert?: InputMaybe; }; export type MutationCreateWorkspaceMembersArgs = { data?: InputMaybe>; + upsert?: InputMaybe; }; @@ -4803,10 +4940,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -4861,7 +5002,7 @@ export type OpportunityActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4873,7 +5014,7 @@ export type OpportunityAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4885,7 +5026,7 @@ export type OpportunityFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -4897,7 +5038,7 @@ export type OpportunityTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** An opportunity */ @@ -5120,7 +5261,7 @@ export type PersonActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5132,7 +5273,7 @@ export type PersonAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5144,7 +5285,7 @@ export type PersonCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5156,7 +5297,7 @@ export type PersonFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5168,7 +5309,7 @@ export type PersonMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5180,7 +5321,7 @@ export type PersonPointOfContactForOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5192,7 +5333,7 @@ export type PersonTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A person */ @@ -5332,9 +5473,16 @@ export type PersonUpdateInput = { xLink?: InputMaybe; }; +export type PostgresCredentials = { + id: Scalars['UUID']; + password: Scalars['String']; + user: Scalars['String']; + workspaceId: Scalars['String']; +}; + export type ProductPriceEntity = { created: Scalars['Float']; - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']; unitAmount: Scalars['Float']; }; @@ -5347,53 +5495,54 @@ export type ProductPricesEntity = { export type Query = { activities?: Maybe; activity?: Maybe; - activityDuplicates?: Maybe; + activityDuplicates?: Maybe>; activityTarget?: Maybe; - activityTargetDuplicates?: Maybe; + activityTargetDuplicates?: Maybe>; activityTargets?: Maybe; apiKey?: Maybe; - apiKeyDuplicates?: Maybe; + apiKeyDuplicates?: Maybe>; apiKeys?: Maybe; attachment?: Maybe; - attachmentDuplicates?: Maybe; + attachmentDuplicates?: Maybe>; attachments?: Maybe; auditLog?: Maybe; - auditLogDuplicates?: Maybe; + auditLogDuplicates?: Maybe>; auditLogs?: Maybe; billingPortalSession: SessionEntity; blocklist?: Maybe; - blocklistDuplicates?: Maybe; + blocklistDuplicates?: Maybe>; blocklists?: Maybe; calendarChannel?: Maybe; - calendarChannelDuplicates?: Maybe; + calendarChannelDuplicates?: Maybe>; calendarChannelEventAssociation?: Maybe; - calendarChannelEventAssociationDuplicates?: Maybe; + calendarChannelEventAssociationDuplicates?: Maybe>; calendarChannelEventAssociations?: Maybe; calendarChannels?: Maybe; calendarEvent?: Maybe; - calendarEventDuplicates?: Maybe; + calendarEventDuplicates?: Maybe>; calendarEventParticipant?: Maybe; - calendarEventParticipantDuplicates?: Maybe; + calendarEventParticipantDuplicates?: Maybe>; calendarEventParticipants?: Maybe; calendarEvents?: Maybe; checkUserExists: UserExists; checkWorkspaceInviteHashIsValid: WorkspaceInviteHashValid; clientConfig: ClientConfig; comment?: Maybe; - commentDuplicates?: Maybe; + commentDuplicates?: Maybe>; comments?: Maybe; companies?: Maybe; company?: Maybe; - companyDuplicates?: Maybe; + companyDuplicates?: Maybe>; connectedAccount?: Maybe; - connectedAccountDuplicates?: Maybe; + connectedAccountDuplicates?: Maybe>; connectedAccounts?: Maybe; currentUser: User; currentWorkspace: Workspace; favorite?: Maybe; - favoriteDuplicates?: Maybe; + favoriteDuplicates?: Maybe>; favorites?: Maybe; findWorkspaceFromInviteHash: Workspace; + getPostgresCredentials?: Maybe; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -5401,48 +5550,48 @@ export type Query = { getTimelineThreadsFromPersonId: TimelineThreadsWithTotal; message?: Maybe; messageChannel?: Maybe; - messageChannelDuplicates?: Maybe; + messageChannelDuplicates?: Maybe>; messageChannelMessageAssociation?: Maybe; - messageChannelMessageAssociationDuplicates?: Maybe; + messageChannelMessageAssociationDuplicates?: Maybe>; messageChannelMessageAssociations?: Maybe; messageChannels?: Maybe; - messageDuplicates?: Maybe; + messageDuplicates?: Maybe>; messageParticipant?: Maybe; - messageParticipantDuplicates?: Maybe; + messageParticipantDuplicates?: Maybe>; messageParticipants?: Maybe; messageThread?: Maybe; - messageThreadDuplicates?: Maybe; + messageThreadDuplicates?: Maybe>; messageThreads?: Maybe; messages?: Maybe; object: Object; objects: ObjectConnection; opportunities?: Maybe; opportunity?: Maybe; - opportunityDuplicates?: Maybe; + opportunityDuplicates?: Maybe>; people?: Maybe; person?: Maybe; - personDuplicates?: Maybe; + personDuplicates?: Maybe>; timelineActivities?: Maybe; timelineActivity?: Maybe; - timelineActivityDuplicates?: Maybe; + timelineActivityDuplicates?: Maybe>; validatePasswordResetToken: ValidatePasswordResetToken; view?: Maybe; - viewDuplicates?: Maybe; + viewDuplicates?: Maybe>; viewField?: Maybe; - viewFieldDuplicates?: Maybe; + viewFieldDuplicates?: Maybe>; viewFields?: Maybe; viewFilter?: Maybe; - viewFilterDuplicates?: Maybe; + viewFilterDuplicates?: Maybe>; viewFilters?: Maybe; viewSort?: Maybe; - viewSortDuplicates?: Maybe; + viewSortDuplicates?: Maybe>; viewSorts?: Maybe; views?: Maybe; webhook?: Maybe; - webhookDuplicates?: Maybe; + webhookDuplicates?: Maybe>; webhooks?: Maybe; workspaceMember?: Maybe; - workspaceMemberDuplicates?: Maybe; + workspaceMemberDuplicates?: Maybe>; workspaceMembers?: Maybe; }; @@ -5454,7 +5603,7 @@ export type QueryActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5464,8 +5613,8 @@ export type QueryActivityArgs = { export type QueryActivityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5475,8 +5624,8 @@ export type QueryActivityTargetArgs = { export type QueryActivityTargetDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5487,7 +5636,7 @@ export type QueryActivityTargetsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5497,8 +5646,8 @@ export type QueryApiKeyArgs = { export type QueryApiKeyDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5509,7 +5658,7 @@ export type QueryApiKeysArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5519,8 +5668,8 @@ export type QueryAttachmentArgs = { export type QueryAttachmentDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5531,7 +5680,7 @@ export type QueryAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5541,8 +5690,8 @@ export type QueryAuditLogArgs = { export type QueryAuditLogDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5553,7 +5702,7 @@ export type QueryAuditLogsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5568,8 +5717,8 @@ export type QueryBlocklistArgs = { export type QueryBlocklistDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5580,7 +5729,7 @@ export type QueryBlocklistsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5590,8 +5739,8 @@ export type QueryCalendarChannelArgs = { export type QueryCalendarChannelDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5601,8 +5750,8 @@ export type QueryCalendarChannelEventAssociationArgs = { export type QueryCalendarChannelEventAssociationDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5613,7 +5762,7 @@ export type QueryCalendarChannelEventAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5624,7 +5773,7 @@ export type QueryCalendarChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5634,8 +5783,8 @@ export type QueryCalendarEventArgs = { export type QueryCalendarEventDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5645,8 +5794,8 @@ export type QueryCalendarEventParticipantArgs = { export type QueryCalendarEventParticipantDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5657,7 +5806,7 @@ export type QueryCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5668,7 +5817,7 @@ export type QueryCalendarEventsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5689,8 +5838,8 @@ export type QueryCommentArgs = { export type QueryCommentDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5701,7 +5850,7 @@ export type QueryCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5712,7 +5861,7 @@ export type QueryCompaniesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5722,8 +5871,8 @@ export type QueryCompanyArgs = { export type QueryCompanyDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5733,8 +5882,8 @@ export type QueryConnectedAccountArgs = { export type QueryConnectedAccountDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5745,7 +5894,7 @@ export type QueryConnectedAccountsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5755,8 +5904,8 @@ export type QueryFavoriteArgs = { export type QueryFavoriteDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5767,7 +5916,7 @@ export type QueryFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5820,8 +5969,8 @@ export type QueryMessageChannelArgs = { export type QueryMessageChannelDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5831,8 +5980,8 @@ export type QueryMessageChannelMessageAssociationArgs = { export type QueryMessageChannelMessageAssociationDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5843,7 +5992,7 @@ export type QueryMessageChannelMessageAssociationsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5854,13 +6003,13 @@ export type QueryMessageChannelsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; export type QueryMessageDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5870,8 +6019,8 @@ export type QueryMessageParticipantArgs = { export type QueryMessageParticipantDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5882,7 +6031,7 @@ export type QueryMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5892,8 +6041,8 @@ export type QueryMessageThreadArgs = { export type QueryMessageThreadDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5904,7 +6053,7 @@ export type QueryMessageThreadsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5915,7 +6064,7 @@ export type QueryMessagesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5926,7 +6075,7 @@ export type QueryOpportunitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5936,8 +6085,8 @@ export type QueryOpportunityArgs = { export type QueryOpportunityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5948,7 +6097,7 @@ export type QueryPeopleArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5958,8 +6107,8 @@ export type QueryPersonArgs = { export type QueryPersonDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5970,7 +6119,7 @@ export type QueryTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -5980,8 +6129,8 @@ export type QueryTimelineActivityArgs = { export type QueryTimelineActivityDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -5996,8 +6145,8 @@ export type QueryViewArgs = { export type QueryViewDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6007,8 +6156,8 @@ export type QueryViewFieldArgs = { export type QueryViewFieldDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6019,7 +6168,7 @@ export type QueryViewFieldsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6029,8 +6178,8 @@ export type QueryViewFilterArgs = { export type QueryViewFilterDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6041,7 +6190,7 @@ export type QueryViewFiltersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6051,8 +6200,8 @@ export type QueryViewSortArgs = { export type QueryViewSortDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6063,7 +6212,7 @@ export type QueryViewSortsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6074,7 +6223,7 @@ export type QueryViewsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6084,8 +6233,8 @@ export type QueryWebhookArgs = { export type QueryWebhookDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6096,7 +6245,7 @@ export type QueryWebhooksArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6106,8 +6255,8 @@ export type QueryWorkspaceMemberArgs = { export type QueryWorkspaceMemberDuplicatesArgs = { - data?: InputMaybe; - id?: InputMaybe; + data?: InputMaybe>>; + ids?: InputMaybe>>; }; @@ -6118,7 +6267,7 @@ export type QueryWorkspaceMembersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; export type RawJsonFilter = { @@ -6226,13 +6375,30 @@ export type StringFilter = { startsWith?: InputMaybe; }; +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 = { supportDriver: Scalars['String']; supportFrontChatId?: Maybe; }; export type Telemetry = { - anonymizationEnabled: Scalars['Boolean']; enabled: Scalars['Boolean']; }; @@ -6534,7 +6700,7 @@ export type User = { firstName: Scalars['String']; id: Scalars['UUID']; lastName: Scalars['String']; - onboardingStep?: Maybe; + onboardingStatus?: Maybe; passwordHash?: Maybe; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe; @@ -6623,7 +6789,7 @@ export type ViewViewFieldsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6635,7 +6801,7 @@ export type ViewViewFiltersArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -6647,7 +6813,7 @@ export type ViewViewSortsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** (System) Views */ @@ -7222,7 +7388,6 @@ export type Workspace = { id: Scalars['UUID']; inviteHash?: Maybe; logo?: Maybe; - subscriptionStatus: Scalars['String']; updatedAt: Scalars['DateTime']; }; @@ -7304,7 +7469,7 @@ export type WorkspaceMemberAccountOwnerForCompaniesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7316,7 +7481,7 @@ export type WorkspaceMemberAssignedActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7328,7 +7493,7 @@ export type WorkspaceMemberAuditLogsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7340,7 +7505,7 @@ export type WorkspaceMemberAuthoredActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7352,7 +7517,7 @@ export type WorkspaceMemberAuthoredAttachmentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7364,7 +7529,7 @@ export type WorkspaceMemberAuthoredCommentsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7376,7 +7541,7 @@ export type WorkspaceMemberBlocklistArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7388,7 +7553,7 @@ export type WorkspaceMemberCalendarEventParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7400,7 +7565,7 @@ export type WorkspaceMemberConnectedAccountsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7412,7 +7577,7 @@ export type WorkspaceMemberFavoritesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7424,7 +7589,7 @@ export type WorkspaceMemberMessageParticipantsArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; @@ -7436,7 +7601,7 @@ export type WorkspaceMemberTimelineActivitiesArgs = { first?: InputMaybe; last?: InputMaybe; limit?: InputMaybe; - orderBy?: InputMaybe; + orderBy?: InputMaybe>>; }; /** A workspace member */ diff --git a/packages/twenty-front/src/__stories__/App.stories.tsx b/packages/twenty-front/src/__stories__/App.stories.tsx index 761c64f3bb8..c5314b5652a 100644 --- a/packages/twenty-front/src/__stories__/App.stories.tsx +++ b/packages/twenty-front/src/__stories__/App.stories.tsx @@ -13,7 +13,7 @@ import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/Sn import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { App } from '~/App'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const meta: Meta = { title: 'App/App', @@ -67,9 +67,9 @@ export const DarkMode: Story = { return HttpResponse.json({ data: { currentUser: { - ...mockedUsersData[0], + ...mockedUserData, workspaceMember: { - ...mockedUsersData[0].workspaceMember, + ...mockedUserData.workspaceMember, colorScheme: 'Dark', }, }, diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 7f5c5c4dded..8098afa1420 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -36,6 +36,11 @@ export type Analytics = { success: Scalars['Boolean']['output']; }; +export type ApiConfig = { + __typename?: 'ApiConfig'; + mutationMaximumAffectedRecords: Scalars['Float']['output']; +}; + export type ApiKeyToken = { __typename?: 'ApiKeyToken'; token: Scalars['String']['output']; @@ -98,8 +103,8 @@ export type Billing = { export type BillingSubscription = { __typename?: 'BillingSubscription'; id: Scalars['UUID']['output']; - interval?: Maybe; - status: Scalars['String']['output']; + interval?: Maybe; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -142,6 +147,7 @@ export enum CaptchaDriverType { export type ClientConfig = { __typename?: 'ClientConfig'; + api: ApiConfig; authProviders: AuthProviders; billing: Billing; captcha: Captcha; @@ -398,7 +404,9 @@ export type Mutation = { deleteOneRelation: Relation; deleteOneRemoteServer: RemoteServer; deleteUser: User; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; generateApiKeyToken: ApiKeyToken; generateJWT: AuthTokens; @@ -451,7 +459,7 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']['input']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe; }; @@ -636,10 +644,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -660,10 +672,18 @@ export type PageInfo = { startCursor?: Maybe; }; +export type PostgresCredentials = { + __typename?: 'PostgresCredentials'; + id: Scalars['UUID']['output']; + password: Scalars['String']['output']; + user: Scalars['String']['output']; + workspaceId: Scalars['String']['output']; +}; + export type ProductPriceEntity = { __typename?: 'ProductPriceEntity'; created: Scalars['Float']['output']; - recurringInterval: Scalars['String']['output']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']['output']; unitAmount: Scalars['Float']['output']; }; @@ -688,6 +708,7 @@ export type Query = { findManyRemoteServersByType: Array; findOneRemoteServerById: RemoteServer; findWorkspaceFromInviteHash: Workspace; + getPostgresCredentials?: Maybe; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -912,6 +933,24 @@ export enum SortNulls { 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 = { __typename?: 'Support'; supportDriver: Scalars['String']['output']; @@ -1084,7 +1123,7 @@ export type User = { firstName: Scalars['String']['output']; id: Scalars['UUID']['output']; lastName: Scalars['String']['output']; - onboardingStep?: Maybe; + onboardingStatus?: Maybe; passwordHash?: Maybe; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe; @@ -1163,7 +1202,6 @@ export type Workspace = { id: Scalars['UUID']['output']; inviteHash?: Maybe; logo?: Maybe; - subscriptionStatus: Scalars['String']['output']; updatedAt: Scalars['DateTime']['output']; }; diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 6b9b154ce7a..124daad290d 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -97,8 +97,8 @@ export type Billing = { export type BillingSubscription = { __typename?: 'BillingSubscription'; id: Scalars['UUID']; - interval?: Maybe; - status: Scalars['String']; + interval?: Maybe; + status: SubscriptionStatus; }; export type BillingSubscriptionFilter = { @@ -347,7 +347,7 @@ export type MutationChallengeArgs = { export type MutationCheckoutSessionArgs = { - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe; }; @@ -467,10 +467,14 @@ export type ObjectFieldsConnection = { pageInfo: PageInfo; }; -/** Onboarding step */ -export enum OnboardingStep { +/** Onboarding status */ +export enum OnboardingStatus { + Completed = 'COMPLETED', InviteTeam = 'INVITE_TEAM', - SyncEmail = 'SYNC_EMAIL' + PlanRequired = 'PLAN_REQUIRED', + ProfileCreation = 'PROFILE_CREATION', + SyncEmail = 'SYNC_EMAIL', + WorkspaceActivation = 'WORKSPACE_ACTIVATION' } export type OnboardingStepSuccess = { @@ -502,7 +506,7 @@ export type PostgresCredentials = { export type ProductPriceEntity = { __typename?: 'ProductPriceEntity'; created: Scalars['Float']; - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; stripePriceId: Scalars['String']; unitAmount: Scalars['Float']; }; @@ -684,6 +688,24 @@ export enum SortNulls { 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 = { __typename?: 'Support'; supportDriver: Scalars['String']; @@ -827,7 +849,7 @@ export type User = { firstName: Scalars['String']; id: Scalars['UUID']; lastName: Scalars['String']; - onboardingStep?: Maybe; + onboardingStatus?: Maybe; passwordHash?: Maybe; /** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */ passwordResetToken?: Maybe; @@ -896,7 +918,6 @@ export type Workspace = { id: Scalars['UUID']; inviteHash?: Maybe; logo?: Maybe; - subscriptionStatus: Scalars['String']; 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<{ 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<{ email: Scalars['String']; @@ -1213,7 +1234,7 @@ export type BillingPortalSessionQueryVariables = Exact<{ export type BillingPortalSessionQuery = { __typename?: 'Query', billingPortalSession: { __typename?: 'SessionEntity', url?: string | null } }; export type CheckoutSessionMutationVariables = Exact<{ - recurringInterval: Scalars['String']; + recurringInterval: SubscriptionInterval; successUrlPath?: InputMaybe; }>; @@ -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; }>; @@ -1242,7 +1263,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] 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; }>; @@ -1259,7 +1280,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf 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<{ 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<{ file: Scalars['Upload']; @@ -1403,7 +1424,7 @@ export const UserQueryFragmentFragmentDoc = gql` email canImpersonate supportUserHash - onboardingStep + onboardingStatus workspaceMember { id name { @@ -1421,7 +1442,6 @@ export const UserQueryFragmentFragmentDoc = gql` domainName inviteHash allowImpersonation - subscriptionStatus activationStatus featureFlags { id @@ -2221,7 +2241,7 @@ export type BillingPortalSessionQueryHookResult = ReturnType; export type BillingPortalSessionQueryResult = Apollo.QueryResult; export const CheckoutSessionDocument = gql` - mutation CheckoutSession($recurringInterval: String!, $successUrlPath: String) { + mutation CheckoutSession($recurringInterval: SubscriptionInterval!, $successUrlPath: String) { checkoutSession( recurringInterval: $recurringInterval successUrlPath: $successUrlPath @@ -2663,7 +2683,6 @@ export const UpdateWorkspaceDocument = gql` displayName logo allowImpersonation - subscriptionStatus } } `; diff --git a/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts b/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts index 1d2834937e3..709c071cce7 100644 --- a/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/useDefaultHomePagePath.test.ts @@ -7,7 +7,7 @@ import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMet import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { AppPath } from '@/types/AppPath'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const objectMetadataItem = getObjectMetadataItemsMock()[0]; jest.mock('@/object-metadata/hooks/useObjectMetadataItem'); @@ -36,7 +36,7 @@ const renderHooks = (withCurrentUser: boolean) => { () => { const setCurrentUser = useSetRecoilState(currentUserState); if (withCurrentUser) { - setCurrentUser(mockedUsersData[0]); + setCurrentUser(mockedUserData); } return useDefaultHomePagePath(); }, diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts index cf9a7730cd9..327e940ac3a 100644 --- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts @@ -1,15 +1,26 @@ -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation'; -jest.mock('@/auth/hooks/useOnboardingStatus'); -const setupMockOnboardingStatus = (onboardingStatus: OnboardingStatus) => { +jest.mock('@/onboarding/hooks/useOnboardingStatus'); +const setupMockOnboardingStatus = ( + onboardingStatus: OnboardingStatus | undefined, +) => { jest.mocked(useOnboardingStatus).mockReturnValueOnce(onboardingStatus); }; +jest.mock('@/workspace/hooks/useSubscriptionStatus'); +const setupMockSubscriptionStatus = ( + subscriptionStatus: SubscriptionStatus | undefined, +) => { + jest.mocked(useSubscriptionStatus).mockReturnValueOnce(subscriptionStatus); +}; + jest.mock('~/hooks/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'; jest.mock('~/hooks/useDefaultHomePagePath'); jest.mocked(useDefaultHomePagePath).mockReturnValue({ - defaultHomePagePath: '/objects/companies', + defaultHomePagePath, }); // prettier-ignore const testCases = [ - { loc: AppPath.Verify, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Verify, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Verify, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Verify, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Verify, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.Verify, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Verify, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.SignInUp, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.SignInUp, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SignInUp, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Invite, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.Invite, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingUserCreation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.ResetPassword, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.CreateWorkspace, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: undefined }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.CreateProfile, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: undefined }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.CreateProfile, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: undefined }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.SyncEmails, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: undefined }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SyncEmails, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: undefined }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.InviteTeam, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: undefined }, + { loc: AppPath.InviteTeam, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.PlanRequired, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequired, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: undefined }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Index, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Index, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Index, status: OnboardingStatus.PastDue, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Index, status: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, + { loc: AppPath.Index, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Index, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: defaultHomePagePath }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.TasksPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.TasksPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.TasksPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.RecordIndexPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.RecordShowPage, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Canceled, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Unpaid, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Impersonate, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Impersonate, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Impersonate, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.Authorize, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.Authorize, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.Authorize, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.Authorize, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.Authorize, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.Incomplete, res: AppPath.PlanRequired }, - { loc: AppPath.NotFound, status: OnboardingStatus.Canceled, res: '/settings/billing' }, - { loc: AppPath.NotFound, status: OnboardingStatus.Unpaid, res: '/settings/billing' }, - { loc: AppPath.NotFound, status: OnboardingStatus.PastDue, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingUserCreation, res: AppPath.SignInUp }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails }, - { loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam }, - { loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: undefined }, - { loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PlanRequired, res: AppPath.PlanRequired }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.Completed, res: '/settings/billing' }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.Completed, res: undefined }, + { loc: AppPath.NotFound, isLoggedIn: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WorkspaceActivation, res: AppPath.CreateWorkspace }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.ProfileCreation, res: AppPath.CreateProfile }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SyncEmail, res: AppPath.SyncEmails }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.InviteTeam, res: AppPath.InviteTeam }, + { loc: AppPath.NotFound, isLoggedIn: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.Completed, res: undefined }, ]; describe('usePageChangeEffectNavigateLocation', () => { 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); - setupMockOnboardingStatus(testCase.status); + setupMockOnboardingStatus(testCase.onboardingStatus); + setupMockSubscriptionStatus(testCase.subscriptionStatus); + setupMockIsLogged(testCase.isLoggedIn); expect(usePageChangeEffectNavigateLocation()).toEqual(testCase.res); }); }); describe('tests should be exhaustive', () => { it('all location and onboarding status should be tested', () => { + const untestedSubscriptionStatus = [ + SubscriptionStatus.Incomplete, + SubscriptionStatus.IncompleteExpired, + SubscriptionStatus.Paused, + SubscriptionStatus.Trialing, + ]; 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)), ); }); }); diff --git a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts index 5b34f0771ed..5492b7b988a 100644 --- a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts +++ b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts @@ -1,14 +1,18 @@ -import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; -import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; +import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; import { SettingsPath } from '@/types/SettingsPath'; +import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; +import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { isDefined } from '~/utils/isDefined'; export const usePageChangeEffectNavigateLocation = () => { const isMatchingLocation = useIsMatchingLocation(); + const isLoggedIn = useIsLogged(); const onboardingStatus = useOnboardingStatus(); + const subscriptionStatus = useSubscriptionStatus(); const { defaultHomePagePath } = useDefaultHomePagePath(); const isMatchingOpenRoute = @@ -33,25 +37,28 @@ export const usePageChangeEffectNavigateLocation = () => { return; } - if ( - onboardingStatus === OnboardingStatus.OngoingUserCreation && - !isMatchingOngoingUserCreationRoute - ) { + if (!isLoggedIn && !isMatchingOngoingUserCreationRoute) { return AppPath.SignInUp; } if ( - onboardingStatus === OnboardingStatus.Incomplete && + onboardingStatus === OnboardingStatus.PlanRequired && !isMatchingLocation(AppPath.PlanRequired) ) { return AppPath.PlanRequired; } if ( - isDefined(onboardingStatus) && - [OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes( - onboardingStatus, - ) && + subscriptionStatus === SubscriptionStatus.Unpaid && + !isMatchingLocation(AppPath.SettingsCatchAll) + ) { + return `${AppPath.SettingsCatchAll.replace('/*', '')}/${ + SettingsPath.Billing + }`; + } + + if ( + subscriptionStatus === SubscriptionStatus.Canceled && !( isMatchingLocation(AppPath.SettingsCatchAll) || isMatchingLocation(AppPath.PlanRequired) @@ -63,7 +70,7 @@ export const usePageChangeEffectNavigateLocation = () => { } if ( - onboardingStatus === OnboardingStatus.OngoingWorkspaceActivation && + onboardingStatus === OnboardingStatus.WorkspaceActivation && !isMatchingLocation(AppPath.CreateWorkspace) && !isMatchingLocation(AppPath.PlanRequiredSuccess) ) { @@ -71,21 +78,21 @@ export const usePageChangeEffectNavigateLocation = () => { } if ( - onboardingStatus === OnboardingStatus.OngoingProfileCreation && + onboardingStatus === OnboardingStatus.ProfileCreation && !isMatchingLocation(AppPath.CreateProfile) ) { return AppPath.CreateProfile; } if ( - onboardingStatus === OnboardingStatus.OngoingSyncEmail && + onboardingStatus === OnboardingStatus.SyncEmail && !isMatchingLocation(AppPath.SyncEmails) ) { return AppPath.SyncEmails; } if ( - onboardingStatus === OnboardingStatus.OngoingInviteTeam && + onboardingStatus === OnboardingStatus.InviteTeam && !isMatchingLocation(AppPath.InviteTeam) ) { return AppPath.InviteTeam; @@ -93,15 +100,9 @@ export const usePageChangeEffectNavigateLocation = () => { if ( onboardingStatus === OnboardingStatus.Completed && - isMatchingOnboardingRoute - ) { - return defaultHomePagePath; - } - - if ( - onboardingStatus === OnboardingStatus.CompletedWithoutSubscription && isMatchingOnboardingRoute && - !isMatchingLocation(AppPath.PlanRequired) + subscriptionStatus !== SubscriptionStatus.Canceled && + (isDefined(subscriptionStatus) || !isMatchingLocation(AppPath.PlanRequired)) ) { return defaultHomePagePath; } diff --git a/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx b/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx index 15c18390f69..ac5a371869b 100644 --- a/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx +++ b/packages/twenty-front/src/loading/components/__stories__/UserOrMetadataLoader.stories.tsx @@ -14,7 +14,7 @@ import { } from '~/testing/decorators/PageDecorator'; import { graphqlMocks, metadataGraphql } from '~/testing/graphqlMocks'; import { mockedClientConfig } from '~/testing/mock-data/config'; -import { mockedUsersData } from '~/testing/mock-data/users'; +import { mockedUserData } from '~/testing/mock-data/users'; const userMetadataLoaderMocks = { msw: { @@ -22,7 +22,7 @@ const userMetadataLoaderMocks = { graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => { return HttpResponse.json({ data: { - currentUser: mockedUsersData[0], + currentUser: mockedUserData, }, }); }), diff --git a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts deleted file mode 100644 index 13d8e23fdaf..00000000000 --- a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts +++ /dev/null @@ -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', - ); - }); -}); diff --git a/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts b/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts deleted file mode 100644 index b638b19da85..00000000000 --- a/packages/twenty-front/src/modules/auth/hooks/useOnboardingStatus.ts +++ /dev/null @@ -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, - }); -}; diff --git a/packages/twenty-front/src/modules/auth/states/currentUserState.ts b/packages/twenty-front/src/modules/auth/states/currentUserState.ts index 07efc7dfb1e..2aab02507ff 100644 --- a/packages/twenty-front/src/modules/auth/states/currentUserState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentUserState.ts @@ -4,7 +4,7 @@ import { User } from '~/generated/graphql'; export type CurrentUser = Pick< User, - 'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStep' + 'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStatus' >; export const currentUserState = createState({ diff --git a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts index c9187c3ea69..239dfc79304 100644 --- a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts @@ -10,7 +10,6 @@ export type CurrentWorkspace = Pick< | 'displayName' | 'allowImpersonation' | 'featureFlags' - | 'subscriptionStatus' | 'activationStatus' | 'currentBillingSubscription' | 'currentCacheVersion' diff --git a/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts deleted file mode 100644 index 813e9b38299..00000000000 --- a/packages/twenty-front/src/modules/auth/utils/__test__/getOnboardingStatus.test.ts +++ /dev/null @@ -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'); - }); -}); diff --git a/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts b/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts deleted file mode 100644 index 0dc25470522..00000000000 --- a/packages/twenty-front/src/modules/auth/utils/getOnboardingStatus.ts +++ /dev/null @@ -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; -}; diff --git a/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts b/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts index bff619a82f8..53821543cef 100644 --- a/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts +++ b/packages/twenty-front/src/modules/billing/graphql/checkoutSession.ts @@ -2,7 +2,7 @@ import { gql } from '@apollo/client'; export const CHECKOUT_SESSION = gql` mutation CheckoutSession( - $recurringInterval: String! + $recurringInterval: SubscriptionInterval! $successUrlPath: String ) { checkoutSession( diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts new file mode 100644 index 00000000000..3aaf6449502 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useOnboardingStatus.test.ts @@ -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); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts new file mode 100644 index 00000000000..223370bce72 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts @@ -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); + }); +}); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts new file mode 100644 index 00000000000..28bef7fd4a5 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/useOnboardingStatus.ts @@ -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; +}; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts new file mode 100644 index 00000000000..30a5f2fae8d --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts @@ -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({ + 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], + ); +}; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts deleted file mode 100644 index 42acf8feb0a..00000000000 --- a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStep.ts +++ /dev/null @@ -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({ - objectNameSingular: CoreObjectNameSingular.WorkspaceMember, - }); - return useRecoilCallback( - () => (currentOnboardingStep: OnboardingStep) => { - setCurrentUser( - (current) => - ({ - ...current, - onboardingStep: getNextOnboardingStep( - currentOnboardingStep, - workspaceMembers, - ), - }) as any, - ); - }, - [setCurrentUser, workspaceMembers], - ); -}; diff --git a/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx b/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx index 7da02230650..da0c12334d1 100644 --- a/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx +++ b/packages/twenty-front/src/modules/support/components/__stories__/SupportChat.stories.tsx @@ -10,7 +10,7 @@ import { supportChatState } from '@/client-config/states/supportChatState'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { mockDefaultWorkspace, - mockedUsersData, + mockedUserData, mockedWorkspaceMemberData, } from '~/testing/mock-data/users'; @@ -30,7 +30,7 @@ const meta: Meta = { setCurrentWorkspace(mockDefaultWorkspace); setCurrentWorkspaceMember(mockedWorkspaceMemberData); - setCurrentUser(mockedUsersData[0]); + setCurrentUser(mockedUserData); setSupportChat({ supportDriver: 'front', supportFrontChatId: '1234' }); return ; diff --git a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx b/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx index 822c193e8d1..e97dbbb4388 100644 --- a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx +++ b/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { Link } from 'react-router-dom'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconInfoCircle } from 'twenty-ui'; +import { AppPath } from '@/types/AppPath'; import { Button } from '@/ui/input/button/components/Button'; export type InfoAccent = 'blue' | 'danger'; @@ -11,6 +13,7 @@ export type InfoProps = { text: string; buttonTitle?: string; onClick?: (event: React.MouseEvent) => void; + to?: AppPath; }; const StyledTextContainer = styled.div` @@ -30,6 +33,7 @@ const StyledInfo = styled.div>` font-weight: ${({ theme }) => theme.font.weight.medium}; justify-content: space-between; max-width: 512px; + gap: ${({ theme }) => theme.spacing(2)}; padding: ${({ theme }) => theme.spacing(2)}; ${({ theme, accent }) => { switch (accent) { @@ -46,11 +50,17 @@ const StyledInfo = styled.div>` } }} `; + +const StyledLink = styled(Link)` + text-decoration: none; +`; + export const Info = ({ accent = 'blue', text, buttonTitle, onClick, + to, }: InfoProps) => { const theme = useTheme(); return ( @@ -59,12 +69,23 @@ export const Info = ({ {text} - {buttonTitle && onClick && ( + {buttonTitle && to && ( + +