mirror of
https://github.com/twentyhq/twenty.git
synced 2024-10-27 03:33:21 +03:00
5623 add an inviteteam onboarding step (#5769)
## Changes - add a new invite Team onboarding step - update currentUser.state to currentUser.onboardingStep ## Edge cases We will never display invite team onboarding step - if number of workspaceMember > 1 - if a workspaceMember as been deleted ## Important changes Update typeorm package version to 0.3.20 because we needed a fix on `indexPredicates` pushed in 0.3.20 version (https://github.com/typeorm/typeorm/issues/10191) ## Result <img width="844" alt="image" src="https://github.com/twentyhq/twenty/assets/29927851/0dab54cf-7c66-4c64-b0c9-b0973889a148"> https://github.com/twentyhq/twenty/assets/29927851/13268d0a-cfa7-42a4-84c6-9e1fbbe48912
This commit is contained in:
parent
2fdd2f4949
commit
3986824017
@ -185,7 +185,7 @@
|
|||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"tsup": "^8.0.1",
|
"tsup": "^8.0.1",
|
||||||
"type-fest": "4.10.1",
|
"type-fest": "4.10.1",
|
||||||
"typeorm": "^0.3.17",
|
"typeorm": "^0.3.20",
|
||||||
"use-context-selector": "^2.0.0",
|
"use-context-selector": "^2.0.0",
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
|
@ -994,8 +994,6 @@ export type CalendarChannel = {
|
|||||||
syncCursor?: Maybe<Scalars['String']>;
|
syncCursor?: Maybe<Scalars['String']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: Maybe<Scalars['Float']>;
|
throttleFailureCount?: Maybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: Maybe<Scalars['DateTime']>;
|
|
||||||
/** Update date */
|
/** Update date */
|
||||||
updatedAt?: Maybe<Scalars['DateTime']>;
|
updatedAt?: Maybe<Scalars['DateTime']>;
|
||||||
/** Visibility */
|
/** Visibility */
|
||||||
@ -1040,8 +1038,6 @@ export type CalendarChannelCreateInput = {
|
|||||||
syncCursor?: InputMaybe<Scalars['String']>;
|
syncCursor?: InputMaybe<Scalars['String']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Update date */
|
/** Update date */
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Visibility */
|
/** Visibility */
|
||||||
@ -1176,8 +1172,6 @@ export type CalendarChannelFilterInput = {
|
|||||||
syncCursor?: InputMaybe<StringFilter>;
|
syncCursor?: InputMaybe<StringFilter>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<FloatFilter>;
|
throttleFailureCount?: InputMaybe<FloatFilter>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<DateFilter>;
|
|
||||||
/** Update date */
|
/** Update date */
|
||||||
updatedAt?: InputMaybe<DateFilter>;
|
updatedAt?: InputMaybe<DateFilter>;
|
||||||
/** Visibility */
|
/** Visibility */
|
||||||
@ -1202,8 +1196,6 @@ export type CalendarChannelOrderByInput = {
|
|||||||
syncCursor?: InputMaybe<OrderByDirection>;
|
syncCursor?: InputMaybe<OrderByDirection>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<OrderByDirection>;
|
throttleFailureCount?: InputMaybe<OrderByDirection>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<OrderByDirection>;
|
|
||||||
/** Update date */
|
/** Update date */
|
||||||
updatedAt?: InputMaybe<OrderByDirection>;
|
updatedAt?: InputMaybe<OrderByDirection>;
|
||||||
/** Visibility */
|
/** Visibility */
|
||||||
@ -1228,8 +1220,6 @@ export type CalendarChannelUpdateInput = {
|
|||||||
syncCursor?: InputMaybe<Scalars['String']>;
|
syncCursor?: InputMaybe<Scalars['String']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Update date */
|
/** Update date */
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Visibility */
|
/** Visibility */
|
||||||
@ -2640,20 +2630,18 @@ export type MessageChannel = {
|
|||||||
isSyncEnabled?: Maybe<Scalars['Boolean']>;
|
isSyncEnabled?: Maybe<Scalars['Boolean']>;
|
||||||
/** Messages from the channel. */
|
/** Messages from the channel. */
|
||||||
messageChannelMessageAssociations?: Maybe<MessageChannelMessageAssociationConnection>;
|
messageChannelMessageAssociations?: Maybe<MessageChannelMessageAssociationConnection>;
|
||||||
/** Ongoing sync started at */
|
|
||||||
ongoingSyncStartedAt?: Maybe<Scalars['DateTime']>;
|
|
||||||
/** Last sync cursor */
|
/** Last sync cursor */
|
||||||
syncCursor?: Maybe<Scalars['String']>;
|
syncCursor?: Maybe<Scalars['String']>;
|
||||||
|
/** Sync stage */
|
||||||
|
syncStage?: Maybe<MessageChannelSyncStageEnum>;
|
||||||
|
/** Sync stage started at */
|
||||||
|
syncStageStartedAt?: Maybe<Scalars['DateTime']>;
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
syncStatus?: Maybe<MessageChannelSyncStatusEnum>;
|
syncStatus?: Maybe<MessageChannelSyncStatusEnum>;
|
||||||
/** Sync sub status */
|
|
||||||
syncSubStatus?: Maybe<MessageChannelSyncSubStatusEnum>;
|
|
||||||
/** Last sync date */
|
/** Last sync date */
|
||||||
syncedAt?: Maybe<Scalars['DateTime']>;
|
syncedAt?: Maybe<Scalars['DateTime']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: Maybe<Scalars['Float']>;
|
throttleFailureCount?: Maybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: Maybe<Scalars['DateTime']>;
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
type?: Maybe<MessageChannelTypeEnum>;
|
type?: Maybe<MessageChannelTypeEnum>;
|
||||||
/** Update date */
|
/** Update date */
|
||||||
@ -2696,20 +2684,18 @@ export type MessageChannelCreateInput = {
|
|||||||
isContactAutoCreationEnabled?: InputMaybe<Scalars['Boolean']>;
|
isContactAutoCreationEnabled?: InputMaybe<Scalars['Boolean']>;
|
||||||
/** Is Sync Enabled */
|
/** Is Sync Enabled */
|
||||||
isSyncEnabled?: InputMaybe<Scalars['Boolean']>;
|
isSyncEnabled?: InputMaybe<Scalars['Boolean']>;
|
||||||
/** Ongoing sync started at */
|
|
||||||
ongoingSyncStartedAt?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Last sync cursor */
|
/** Last sync cursor */
|
||||||
syncCursor?: InputMaybe<Scalars['String']>;
|
syncCursor?: InputMaybe<Scalars['String']>;
|
||||||
|
/** Sync stage */
|
||||||
|
syncStage?: InputMaybe<MessageChannelSyncStageEnum>;
|
||||||
|
/** Sync stage started at */
|
||||||
|
syncStageStartedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
syncStatus?: InputMaybe<MessageChannelSyncStatusEnum>;
|
syncStatus?: InputMaybe<MessageChannelSyncStatusEnum>;
|
||||||
/** Sync sub status */
|
|
||||||
syncSubStatus?: InputMaybe<MessageChannelSyncSubStatusEnum>;
|
|
||||||
/** Last sync date */
|
/** Last sync date */
|
||||||
syncedAt?: InputMaybe<Scalars['DateTime']>;
|
syncedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
type?: InputMaybe<MessageChannelTypeEnum>;
|
type?: InputMaybe<MessageChannelTypeEnum>;
|
||||||
/** Update date */
|
/** Update date */
|
||||||
@ -2740,21 +2726,19 @@ export type MessageChannelFilterInput = {
|
|||||||
/** Is Sync Enabled */
|
/** Is Sync Enabled */
|
||||||
isSyncEnabled?: InputMaybe<BooleanFilter>;
|
isSyncEnabled?: InputMaybe<BooleanFilter>;
|
||||||
not?: InputMaybe<MessageChannelFilterInput>;
|
not?: InputMaybe<MessageChannelFilterInput>;
|
||||||
/** Ongoing sync started at */
|
|
||||||
ongoingSyncStartedAt?: InputMaybe<DateFilter>;
|
|
||||||
or?: InputMaybe<Array<InputMaybe<MessageChannelFilterInput>>>;
|
or?: InputMaybe<Array<InputMaybe<MessageChannelFilterInput>>>;
|
||||||
/** Last sync cursor */
|
/** Last sync cursor */
|
||||||
syncCursor?: InputMaybe<StringFilter>;
|
syncCursor?: InputMaybe<StringFilter>;
|
||||||
|
/** Sync stage */
|
||||||
|
syncStage?: InputMaybe<MessageChannelSyncStageEnumFilter>;
|
||||||
|
/** Sync stage started at */
|
||||||
|
syncStageStartedAt?: InputMaybe<DateFilter>;
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
syncStatus?: InputMaybe<MessageChannelSyncStatusEnumFilter>;
|
syncStatus?: InputMaybe<MessageChannelSyncStatusEnumFilter>;
|
||||||
/** Sync sub status */
|
|
||||||
syncSubStatus?: InputMaybe<MessageChannelSyncSubStatusEnumFilter>;
|
|
||||||
/** Last sync date */
|
/** Last sync date */
|
||||||
syncedAt?: InputMaybe<DateFilter>;
|
syncedAt?: InputMaybe<DateFilter>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<FloatFilter>;
|
throttleFailureCount?: InputMaybe<FloatFilter>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<DateFilter>;
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
type?: InputMaybe<MessageChannelTypeEnumFilter>;
|
type?: InputMaybe<MessageChannelTypeEnumFilter>;
|
||||||
/** Update date */
|
/** Update date */
|
||||||
@ -2900,20 +2884,18 @@ export type MessageChannelOrderByInput = {
|
|||||||
isContactAutoCreationEnabled?: InputMaybe<OrderByDirection>;
|
isContactAutoCreationEnabled?: InputMaybe<OrderByDirection>;
|
||||||
/** Is Sync Enabled */
|
/** Is Sync Enabled */
|
||||||
isSyncEnabled?: InputMaybe<OrderByDirection>;
|
isSyncEnabled?: InputMaybe<OrderByDirection>;
|
||||||
/** Ongoing sync started at */
|
|
||||||
ongoingSyncStartedAt?: InputMaybe<OrderByDirection>;
|
|
||||||
/** Last sync cursor */
|
/** Last sync cursor */
|
||||||
syncCursor?: InputMaybe<OrderByDirection>;
|
syncCursor?: InputMaybe<OrderByDirection>;
|
||||||
|
/** Sync stage */
|
||||||
|
syncStage?: InputMaybe<OrderByDirection>;
|
||||||
|
/** Sync stage started at */
|
||||||
|
syncStageStartedAt?: InputMaybe<OrderByDirection>;
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
syncStatus?: InputMaybe<OrderByDirection>;
|
syncStatus?: InputMaybe<OrderByDirection>;
|
||||||
/** Sync sub status */
|
|
||||||
syncSubStatus?: InputMaybe<OrderByDirection>;
|
|
||||||
/** Last sync date */
|
/** Last sync date */
|
||||||
syncedAt?: InputMaybe<OrderByDirection>;
|
syncedAt?: InputMaybe<OrderByDirection>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<OrderByDirection>;
|
throttleFailureCount?: InputMaybe<OrderByDirection>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<OrderByDirection>;
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
type?: InputMaybe<OrderByDirection>;
|
type?: InputMaybe<OrderByDirection>;
|
||||||
/** Update date */
|
/** Update date */
|
||||||
@ -2922,6 +2904,29 @@ export type MessageChannelOrderByInput = {
|
|||||||
visibility?: InputMaybe<OrderByDirection>;
|
visibility?: InputMaybe<OrderByDirection>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Sync stage */
|
||||||
|
export enum MessageChannelSyncStageEnum {
|
||||||
|
/** Failed */
|
||||||
|
Failed = 'FAILED',
|
||||||
|
/** Full messages list fetch pending */
|
||||||
|
FullMessageListFetchPending = 'FULL_MESSAGE_LIST_FETCH_PENDING',
|
||||||
|
/** Messages import ongoing */
|
||||||
|
MessagesImportOngoing = 'MESSAGES_IMPORT_ONGOING',
|
||||||
|
/** Messages import pending */
|
||||||
|
MessagesImportPending = 'MESSAGES_IMPORT_PENDING',
|
||||||
|
/** Messages list fetch ongoing */
|
||||||
|
MessageListFetchOngoing = 'MESSAGE_LIST_FETCH_ONGOING',
|
||||||
|
/** Partial messages list fetch pending */
|
||||||
|
PartialMessageListFetchPending = 'PARTIAL_MESSAGE_LIST_FETCH_PENDING'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MessageChannelSyncStageEnumFilter = {
|
||||||
|
eq?: InputMaybe<MessageChannelSyncStageEnum>;
|
||||||
|
in?: InputMaybe<Array<InputMaybe<MessageChannelSyncStageEnum>>>;
|
||||||
|
is?: InputMaybe<FilterIs>;
|
||||||
|
neq?: InputMaybe<MessageChannelSyncStageEnum>;
|
||||||
|
};
|
||||||
|
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
export enum MessageChannelSyncStatusEnum {
|
export enum MessageChannelSyncStatusEnum {
|
||||||
/** Completed */
|
/** Completed */
|
||||||
@ -2949,29 +2954,6 @@ export type MessageChannelSyncStatusEnumFilter = {
|
|||||||
neq?: InputMaybe<MessageChannelSyncStatusEnum>;
|
neq?: InputMaybe<MessageChannelSyncStatusEnum>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Sync sub status */
|
|
||||||
export enum MessageChannelSyncSubStatusEnum {
|
|
||||||
/** Failed */
|
|
||||||
Failed = 'FAILED',
|
|
||||||
/** Full messages list fetch pending */
|
|
||||||
FullMessageListFetchPending = 'FULL_MESSAGE_LIST_FETCH_PENDING',
|
|
||||||
/** Messages import ongoing */
|
|
||||||
MessagesImportOngoing = 'MESSAGES_IMPORT_ONGOING',
|
|
||||||
/** Messages import pending */
|
|
||||||
MessagesImportPending = 'MESSAGES_IMPORT_PENDING',
|
|
||||||
/** Messages list fetch ongoing */
|
|
||||||
MessageListFetchOngoing = 'MESSAGE_LIST_FETCH_ONGOING',
|
|
||||||
/** Partial messages list fetch pending */
|
|
||||||
PartialMessageListFetchPending = 'PARTIAL_MESSAGE_LIST_FETCH_PENDING'
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MessageChannelSyncSubStatusEnumFilter = {
|
|
||||||
eq?: InputMaybe<MessageChannelSyncSubStatusEnum>;
|
|
||||||
in?: InputMaybe<Array<InputMaybe<MessageChannelSyncSubStatusEnum>>>;
|
|
||||||
is?: InputMaybe<FilterIs>;
|
|
||||||
neq?: InputMaybe<MessageChannelSyncSubStatusEnum>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
export enum MessageChannelTypeEnum {
|
export enum MessageChannelTypeEnum {
|
||||||
/** Email */
|
/** Email */
|
||||||
@ -3001,20 +2983,18 @@ export type MessageChannelUpdateInput = {
|
|||||||
isContactAutoCreationEnabled?: InputMaybe<Scalars['Boolean']>;
|
isContactAutoCreationEnabled?: InputMaybe<Scalars['Boolean']>;
|
||||||
/** Is Sync Enabled */
|
/** Is Sync Enabled */
|
||||||
isSyncEnabled?: InputMaybe<Scalars['Boolean']>;
|
isSyncEnabled?: InputMaybe<Scalars['Boolean']>;
|
||||||
/** Ongoing sync started at */
|
|
||||||
ongoingSyncStartedAt?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Last sync cursor */
|
/** Last sync cursor */
|
||||||
syncCursor?: InputMaybe<Scalars['String']>;
|
syncCursor?: InputMaybe<Scalars['String']>;
|
||||||
|
/** Sync stage */
|
||||||
|
syncStage?: InputMaybe<MessageChannelSyncStageEnum>;
|
||||||
|
/** Sync stage started at */
|
||||||
|
syncStageStartedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Sync status */
|
/** Sync status */
|
||||||
syncStatus?: InputMaybe<MessageChannelSyncStatusEnum>;
|
syncStatus?: InputMaybe<MessageChannelSyncStatusEnum>;
|
||||||
/** Sync sub status */
|
|
||||||
syncSubStatus?: InputMaybe<MessageChannelSyncSubStatusEnum>;
|
|
||||||
/** Last sync date */
|
/** Last sync date */
|
||||||
syncedAt?: InputMaybe<Scalars['DateTime']>;
|
syncedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
/** Throttle Failure Count */
|
/** Throttle Failure Count */
|
||||||
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
throttleFailureCount?: InputMaybe<Scalars['Float']>;
|
||||||
/** Throttle Pause Until */
|
|
||||||
throttlePauseUntil?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
/** Channel Type */
|
/** Channel Type */
|
||||||
type?: InputMaybe<MessageChannelTypeEnum>;
|
type?: InputMaybe<MessageChannelTypeEnum>;
|
||||||
/** Update date */
|
/** Update date */
|
||||||
@ -3572,8 +3552,9 @@ export type Mutation = {
|
|||||||
generateTransientToken: TransientToken;
|
generateTransientToken: TransientToken;
|
||||||
impersonate: Verify;
|
impersonate: Verify;
|
||||||
renewToken: AuthTokens;
|
renewToken: AuthTokens;
|
||||||
|
sendInviteLink: SendInviteLink;
|
||||||
signUp: LoginToken;
|
signUp: LoginToken;
|
||||||
skipSyncEmailOnboardingStep: SkipSyncEmailOnboardingStep;
|
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||||
track: Analytics;
|
track: Analytics;
|
||||||
updateActivities?: Maybe<Array<Activity>>;
|
updateActivities?: Maybe<Array<Activity>>;
|
||||||
updateActivity?: Maybe<Activity>;
|
updateActivity?: Maybe<Activity>;
|
||||||
@ -4411,6 +4392,11 @@ export type MutationRenewTokenArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationSendInviteLinkArgs = {
|
||||||
|
emails: Array<Scalars['String']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationSignUpArgs = {
|
export type MutationSignUpArgs = {
|
||||||
captchaToken?: InputMaybe<Scalars['String']>;
|
captchaToken?: InputMaybe<Scalars['String']>;
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@ -4817,6 +4803,17 @@ export type ObjectFieldsConnection = {
|
|||||||
pageInfo: PageInfo;
|
pageInfo: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Onboarding step */
|
||||||
|
export enum OnboardingStep {
|
||||||
|
InviteTeam = 'INVITE_TEAM',
|
||||||
|
SyncEmail = 'SYNC_EMAIL'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OnboardingStepSuccess = {
|
||||||
|
/** Boolean that confirms query was dispatched */
|
||||||
|
success: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
/** An opportunity */
|
/** An opportunity */
|
||||||
export type Opportunity = {
|
export type Opportunity = {
|
||||||
/** Activities tied to the opportunity */
|
/** Activities tied to the opportunity */
|
||||||
@ -6186,6 +6183,11 @@ export enum RemoteTableStatus {
|
|||||||
Synced = 'SYNCED'
|
Synced = 'SYNCED'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SendInviteLink = {
|
||||||
|
/** Boolean that confirms query was dispatched */
|
||||||
|
success: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type Sentry = {
|
export type Sentry = {
|
||||||
dsn?: Maybe<Scalars['String']>;
|
dsn?: Maybe<Scalars['String']>;
|
||||||
environment?: Maybe<Scalars['String']>;
|
environment?: Maybe<Scalars['String']>;
|
||||||
@ -6196,11 +6198,6 @@ export type SessionEntity = {
|
|||||||
url?: Maybe<Scalars['String']>;
|
url?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SkipSyncEmailOnboardingStep = {
|
|
||||||
/** Boolean that confirms query was dispatched */
|
|
||||||
success: Scalars['Boolean'];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Sort Directions */
|
/** Sort Directions */
|
||||||
export enum SortDirection {
|
export enum SortDirection {
|
||||||
Asc = 'ASC',
|
Asc = 'ASC',
|
||||||
@ -6537,12 +6534,12 @@ export type User = {
|
|||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
lastName: Scalars['String'];
|
lastName: Scalars['String'];
|
||||||
|
onboardingStep?: Maybe<OnboardingStep>;
|
||||||
passwordHash?: Maybe<Scalars['String']>;
|
passwordHash?: Maybe<Scalars['String']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetToken?: Maybe<Scalars['String']>;
|
passwordResetToken?: Maybe<Scalars['String']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
||||||
state: UserState;
|
|
||||||
supportUserHash?: Maybe<Scalars['String']>;
|
supportUserHash?: Maybe<Scalars['String']>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
workspaceMember?: Maybe<WorkspaceMember>;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
@ -6564,10 +6561,6 @@ export type UserMappingOptionsUser = {
|
|||||||
user?: Maybe<Scalars['String']>;
|
user?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserState = {
|
|
||||||
skipSyncEmailOnboardingStep?: Maybe<Scalars['Boolean']>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UserWorkspace = {
|
export type UserWorkspace = {
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
deletedAt?: Maybe<Scalars['DateTime']>;
|
deletedAt?: Maybe<Scalars['DateTime']>;
|
||||||
|
@ -48,6 +48,7 @@ import { RecordShowPage } from '~/pages/object-record/RecordShowPage';
|
|||||||
import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan';
|
import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan';
|
||||||
import { CreateProfile } from '~/pages/onboarding/CreateProfile';
|
import { CreateProfile } from '~/pages/onboarding/CreateProfile';
|
||||||
import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace';
|
import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace';
|
||||||
|
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
||||||
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess';
|
||||||
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
||||||
import { SettingsAccounts } from '~/pages/settings/accounts/SettingsAccounts';
|
import { SettingsAccounts } from '~/pages/settings/accounts/SettingsAccounts';
|
||||||
@ -143,6 +144,7 @@ const createRouter = (isBillingEnabled?: boolean) =>
|
|||||||
<Route path={AppPath.CreateWorkspace} element={<CreateWorkspace />} />
|
<Route path={AppPath.CreateWorkspace} element={<CreateWorkspace />} />
|
||||||
<Route path={AppPath.CreateProfile} element={<CreateProfile />} />
|
<Route path={AppPath.CreateProfile} element={<CreateProfile />} />
|
||||||
<Route path={AppPath.SyncEmails} element={<SyncEmails />} />
|
<Route path={AppPath.SyncEmails} element={<SyncEmails />} />
|
||||||
|
<Route path={AppPath.InviteTeam} element={<InviteTeam />} />
|
||||||
<Route path={AppPath.PlanRequired} element={<ChooseYourPlan />} />
|
<Route path={AppPath.PlanRequired} element={<ChooseYourPlan />} />
|
||||||
<Route
|
<Route
|
||||||
path={AppPath.PlanRequiredSuccess}
|
path={AppPath.PlanRequiredSuccess}
|
||||||
|
@ -101,6 +101,14 @@ export const PageChangeEffect = () => {
|
|||||||
setHotkeyScope(PageHotkeyScope.CreateWokspace);
|
setHotkeyScope(PageHotkeyScope.CreateWokspace);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case isMatchingLocation(AppPath.SyncEmails): {
|
||||||
|
setHotkeyScope(PageHotkeyScope.SyncEmail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case isMatchingLocation(AppPath.InviteTeam): {
|
||||||
|
setHotkeyScope(PageHotkeyScope.InviteTeam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case isMatchingLocation(AppPath.PlanRequired): {
|
case isMatchingLocation(AppPath.PlanRequired): {
|
||||||
setHotkeyScope(PageHotkeyScope.PlanRequired);
|
setHotkeyScope(PageHotkeyScope.PlanRequired);
|
||||||
break;
|
break;
|
||||||
|
@ -407,7 +407,7 @@ export type Mutation = {
|
|||||||
renewToken: AuthTokens;
|
renewToken: AuthTokens;
|
||||||
sendInviteLink: SendInviteLink;
|
sendInviteLink: SendInviteLink;
|
||||||
signUp: LoginToken;
|
signUp: LoginToken;
|
||||||
skipSyncEmailOnboardingStep: SkipSyncEmailOnboardingStep;
|
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||||
syncRemoteTable: RemoteTable;
|
syncRemoteTable: RemoteTable;
|
||||||
syncRemoteTableSchemaChanges: RemoteTable;
|
syncRemoteTableSchemaChanges: RemoteTable;
|
||||||
track: Analytics;
|
track: Analytics;
|
||||||
@ -636,6 +636,18 @@ export type ObjectFieldsConnection = {
|
|||||||
pageInfo: PageInfo;
|
pageInfo: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Onboarding step */
|
||||||
|
export enum OnboardingStep {
|
||||||
|
InviteTeam = 'INVITE_TEAM',
|
||||||
|
SyncEmail = 'SYNC_EMAIL'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OnboardingStepSuccess = {
|
||||||
|
__typename?: 'OnboardingStepSuccess';
|
||||||
|
/** Boolean that confirms query was dispatched */
|
||||||
|
success: Scalars['Boolean']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type PageInfo = {
|
export type PageInfo = {
|
||||||
__typename?: 'PageInfo';
|
__typename?: 'PageInfo';
|
||||||
/** The cursor of the last returned record. */
|
/** The cursor of the last returned record. */
|
||||||
@ -888,12 +900,6 @@ export type SessionEntity = {
|
|||||||
url?: Maybe<Scalars['String']['output']>;
|
url?: Maybe<Scalars['String']['output']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SkipSyncEmailOnboardingStep = {
|
|
||||||
__typename?: 'SkipSyncEmailOnboardingStep';
|
|
||||||
/** Boolean that confirms query was dispatched */
|
|
||||||
success: Scalars['Boolean']['output'];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Sort Directions */
|
/** Sort Directions */
|
||||||
export enum SortDirection {
|
export enum SortDirection {
|
||||||
Asc = 'ASC',
|
Asc = 'ASC',
|
||||||
@ -1078,12 +1084,12 @@ export type User = {
|
|||||||
firstName: Scalars['String']['output'];
|
firstName: Scalars['String']['output'];
|
||||||
id: Scalars['UUID']['output'];
|
id: Scalars['UUID']['output'];
|
||||||
lastName: Scalars['String']['output'];
|
lastName: Scalars['String']['output'];
|
||||||
|
onboardingStep?: Maybe<OnboardingStep>;
|
||||||
passwordHash?: Maybe<Scalars['String']['output']>;
|
passwordHash?: Maybe<Scalars['String']['output']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetToken?: Maybe<Scalars['String']['output']>;
|
passwordResetToken?: Maybe<Scalars['String']['output']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']['output']>;
|
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']['output']>;
|
||||||
state: UserState;
|
|
||||||
supportUserHash?: Maybe<Scalars['String']['output']>;
|
supportUserHash?: Maybe<Scalars['String']['output']>;
|
||||||
updatedAt: Scalars['DateTime']['output'];
|
updatedAt: Scalars['DateTime']['output'];
|
||||||
workspaceMember?: Maybe<WorkspaceMember>;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
@ -1118,11 +1124,6 @@ export type UserMappingOptionsUser = {
|
|||||||
user?: Maybe<Scalars['String']['output']>;
|
user?: Maybe<Scalars['String']['output']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserState = {
|
|
||||||
__typename?: 'UserState';
|
|
||||||
skipSyncEmailOnboardingStep?: Maybe<Scalars['Boolean']['output']>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UserWorkspace = {
|
export type UserWorkspace = {
|
||||||
__typename?: 'UserWorkspace';
|
__typename?: 'UserWorkspace';
|
||||||
createdAt: Scalars['DateTime']['output'];
|
createdAt: Scalars['DateTime']['output'];
|
||||||
|
@ -300,7 +300,7 @@ export type Mutation = {
|
|||||||
renewToken: AuthTokens;
|
renewToken: AuthTokens;
|
||||||
sendInviteLink: SendInviteLink;
|
sendInviteLink: SendInviteLink;
|
||||||
signUp: LoginToken;
|
signUp: LoginToken;
|
||||||
skipSyncEmailOnboardingStep: SkipSyncEmailOnboardingStep;
|
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||||
track: Analytics;
|
track: Analytics;
|
||||||
updateBillingSubscription: UpdateBillingEntity;
|
updateBillingSubscription: UpdateBillingEntity;
|
||||||
updateOneObject: Object;
|
updateOneObject: Object;
|
||||||
@ -459,6 +459,18 @@ export type ObjectFieldsConnection = {
|
|||||||
pageInfo: PageInfo;
|
pageInfo: PageInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Onboarding step */
|
||||||
|
export enum OnboardingStep {
|
||||||
|
InviteTeam = 'INVITE_TEAM',
|
||||||
|
SyncEmail = 'SYNC_EMAIL'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OnboardingStepSuccess = {
|
||||||
|
__typename?: 'OnboardingStepSuccess';
|
||||||
|
/** Boolean that confirms query was dispatched */
|
||||||
|
success: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type PageInfo = {
|
export type PageInfo = {
|
||||||
__typename?: 'PageInfo';
|
__typename?: 'PageInfo';
|
||||||
/** The cursor of the last returned record. */
|
/** The cursor of the last returned record. */
|
||||||
@ -643,12 +655,6 @@ export type SessionEntity = {
|
|||||||
url?: Maybe<Scalars['String']>;
|
url?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SkipSyncEmailOnboardingStep = {
|
|
||||||
__typename?: 'SkipSyncEmailOnboardingStep';
|
|
||||||
/** Boolean that confirms query was dispatched */
|
|
||||||
success: Scalars['Boolean'];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Sort Directions */
|
/** Sort Directions */
|
||||||
export enum SortDirection {
|
export enum SortDirection {
|
||||||
Asc = 'ASC',
|
Asc = 'ASC',
|
||||||
@ -804,12 +810,12 @@ export type User = {
|
|||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
lastName: Scalars['String'];
|
lastName: Scalars['String'];
|
||||||
|
onboardingStep?: Maybe<OnboardingStep>;
|
||||||
passwordHash?: Maybe<Scalars['String']>;
|
passwordHash?: Maybe<Scalars['String']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetToken?: Maybe<Scalars['String']>;
|
passwordResetToken?: Maybe<Scalars['String']>;
|
||||||
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
/** @deprecated field migrated into the AppTokens Table ref: https://github.com/twentyhq/twenty/issues/5021 */
|
||||||
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
passwordResetTokenExpiresAt?: Maybe<Scalars['DateTime']>;
|
||||||
state: UserState;
|
|
||||||
supportUserHash?: Maybe<Scalars['String']>;
|
supportUserHash?: Maybe<Scalars['String']>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
workspaceMember?: Maybe<WorkspaceMember>;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
@ -834,11 +840,6 @@ export type UserMappingOptionsUser = {
|
|||||||
user?: Maybe<Scalars['String']>;
|
user?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserState = {
|
|
||||||
__typename?: 'UserState';
|
|
||||||
skipSyncEmailOnboardingStep?: Maybe<Scalars['Boolean']>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UserWorkspace = {
|
export type UserWorkspace = {
|
||||||
__typename?: 'UserWorkspace';
|
__typename?: 'UserWorkspace';
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
@ -1140,7 +1141,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, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | 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, 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 RenewTokenMutationVariables = Exact<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
appToken: Scalars['String'];
|
appToken: Scalars['String'];
|
||||||
@ -1172,7 +1173,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, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | 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, 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 CheckUserExistsQueryVariables = Exact<{
|
export type CheckUserExistsQueryVariables = Exact<{
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@ -1224,9 +1225,9 @@ export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typ
|
|||||||
export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>;
|
export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'SkipSyncEmailOnboardingStep', success: boolean } };
|
export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } };
|
||||||
|
|
||||||
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | 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, 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 DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@ -1243,7 +1244,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
|
|||||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | 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, 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 AddUserToWorkspaceMutationVariables = Exact<{
|
export type AddUserToWorkspaceMutationVariables = Exact<{
|
||||||
inviteHash: Scalars['String'];
|
inviteHash: Scalars['String'];
|
||||||
@ -1394,9 +1395,7 @@ export const UserQueryFragmentFragmentDoc = gql`
|
|||||||
email
|
email
|
||||||
canImpersonate
|
canImpersonate
|
||||||
supportUserHash
|
supportUserHash
|
||||||
state {
|
onboardingStep
|
||||||
skipSyncEmailOnboardingStep
|
|
||||||
}
|
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
name {
|
name {
|
||||||
|
@ -36,6 +36,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
||||||
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -69,6 +72,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
||||||
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: AppPath.InviteTeam },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: undefined },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: undefined },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -80,6 +84,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -91,6 +96,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: undefined },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: undefined },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -102,9 +108,22 @@ const testCases = [
|
|||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: undefined },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, 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.PlanRequired, status: OnboardingStatus.Incomplete, res: undefined },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: undefined },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: undefined },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: undefined },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: undefined },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: undefined },
|
||||||
@ -113,6 +132,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -124,6 +144,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: undefined },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -135,6 +156,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: defaultHomePagePath },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: defaultHomePagePath },
|
||||||
|
|
||||||
@ -146,6 +168,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -157,6 +180,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -168,6 +192,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -179,6 +204,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -190,6 +216,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -201,6 +228,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -212,6 +240,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -223,6 +252,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -234,6 +264,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
|
|
||||||
@ -245,6 +276,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: AppPath.CreateWorkspace },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: AppPath.CreateProfile },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: AppPath.SyncEmails },
|
{ 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.Completed, res: undefined },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: undefined },
|
||||||
];
|
];
|
||||||
|
@ -25,6 +25,7 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
isMatchingLocation(AppPath.CreateWorkspace) ||
|
isMatchingLocation(AppPath.CreateWorkspace) ||
|
||||||
isMatchingLocation(AppPath.CreateProfile) ||
|
isMatchingLocation(AppPath.CreateProfile) ||
|
||||||
isMatchingLocation(AppPath.SyncEmails) ||
|
isMatchingLocation(AppPath.SyncEmails) ||
|
||||||
|
isMatchingLocation(AppPath.InviteTeam) ||
|
||||||
isMatchingLocation(AppPath.PlanRequired) ||
|
isMatchingLocation(AppPath.PlanRequired) ||
|
||||||
isMatchingLocation(AppPath.PlanRequiredSuccess);
|
isMatchingLocation(AppPath.PlanRequiredSuccess);
|
||||||
|
|
||||||
@ -79,6 +80,13 @@ export const usePageChangeEffectNavigateLocation = () => {
|
|||||||
return AppPath.SyncEmails;
|
return AppPath.SyncEmails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
onboardingStatus === OnboardingStatus.OngoingInviteTeam &&
|
||||||
|
!isMatchingLocation(AppPath.InviteTeam)
|
||||||
|
) {
|
||||||
|
return AppPath.InviteTeam;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
onboardingStatus === OnboardingStatus.Completed &&
|
onboardingStatus === OnboardingStatus.Completed &&
|
||||||
isMatchingOnboardingRoute &&
|
isMatchingOnboardingRoute &&
|
||||||
|
@ -5,30 +5,30 @@ import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEase
|
|||||||
|
|
||||||
type TitleProps = React.PropsWithChildren & {
|
type TitleProps = React.PropsWithChildren & {
|
||||||
animate?: boolean;
|
animate?: boolean;
|
||||||
withMarginTop?: boolean;
|
noMarginTop?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledTitle = styled.div<Pick<TitleProps, 'withMarginTop'>>`
|
const StyledTitle = styled.div<Pick<TitleProps, 'noMarginTop'>>`
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
font-size: ${({ theme }) => theme.font.size.xl};
|
font-size: ${({ theme }) => theme.font.size.xl};
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
||||||
margin-top: ${({ theme, withMarginTop }) =>
|
margin-top: ${({ theme, noMarginTop }) =>
|
||||||
withMarginTop ? theme.spacing(4) : 0};
|
!noMarginTop ? theme.spacing(4) : 0};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Title = ({
|
export const Title = ({
|
||||||
children,
|
children,
|
||||||
animate = false,
|
animate = false,
|
||||||
withMarginTop = true,
|
noMarginTop = false,
|
||||||
}: TitleProps) => {
|
}: TitleProps) => {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
return (
|
return (
|
||||||
<StyledTitle withMarginTop={withMarginTop}>
|
<StyledTitle noMarginTop={noMarginTop}>
|
||||||
<AnimatedEaseIn>{children}</AnimatedEaseIn>
|
<AnimatedEaseIn>{children}</AnimatedEaseIn>
|
||||||
</StyledTitle>
|
</StyledTitle>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <StyledTitle withMarginTop={withMarginTop}>{children}</StyledTitle>;
|
return <StyledTitle noMarginTop={noMarginTop}>{children}</StyledTitle>;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState';
|
import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState';
|
||||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
import { billingState } from '@/client-config/states/billingState';
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
|
|
||||||
const tokenPair = {
|
const tokenPair = {
|
||||||
accessToken: { token: 'accessToken', expiresAt: 'expiresAt' },
|
accessToken: { token: 'accessToken', expiresAt: 'expiresAt' },
|
||||||
@ -26,7 +27,7 @@ const currentUser = {
|
|||||||
email: 'test@test',
|
email: 'test@test',
|
||||||
supportUserHash: '1',
|
supportUserHash: '1',
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser;
|
} as CurrentUser;
|
||||||
const currentWorkspace = {
|
const currentWorkspace = {
|
||||||
activationStatus: 'active',
|
activationStatus: 'active',
|
||||||
@ -196,7 +197,7 @@ describe('useOnboardingStatus', () => {
|
|||||||
setBilling(billing);
|
setBilling(billing);
|
||||||
setCurrentUser({
|
setCurrentUser({
|
||||||
...currentUser,
|
...currentUser,
|
||||||
state: { skipSyncEmailOnboardingStep: false },
|
onboardingStep: OnboardingStep.SyncEmail,
|
||||||
});
|
});
|
||||||
setCurrentWorkspace({
|
setCurrentWorkspace({
|
||||||
...currentWorkspace,
|
...currentWorkspace,
|
||||||
@ -214,6 +215,39 @@ describe('useOnboardingStatus', () => {
|
|||||||
expect(result.current.onboardingStatus).toBe('ongoing_sync_email');
|
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 () => {
|
it('should return "completed"', async () => {
|
||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
const {
|
const {
|
||||||
|
@ -4,6 +4,7 @@ import { useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconGoogle, IconMicrosoft } from 'twenty-ui';
|
import { IconGoogle, IconMicrosoft } from 'twenty-ui';
|
||||||
|
|
||||||
import { FooterNote } from '@/auth/sign-in-up/components/FooterNote';
|
import { FooterNote } from '@/auth/sign-in-up/components/FooterNote';
|
||||||
@ -69,7 +70,7 @@ export const SignInUpForm = () => {
|
|||||||
const handleKeyDown = async (
|
const handleKeyDown = async (
|
||||||
event: React.KeyboardEvent<HTMLInputElement>,
|
event: React.KeyboardEvent<HTMLInputElement>,
|
||||||
) => {
|
) => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === Key.Enter) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (signInUpStep === SignInUpStep.Init) {
|
if (signInUpStep === SignInUpStep.Init) {
|
||||||
|
@ -4,7 +4,7 @@ import { User } from '~/generated/graphql';
|
|||||||
|
|
||||||
export type CurrentUser = Pick<
|
export type CurrentUser = Pick<
|
||||||
User,
|
User,
|
||||||
'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'state'
|
'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStep'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const currentUserState = createState<CurrentUser | null>({
|
export const currentUserState = createState<CurrentUser | null>({
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CurrentUser } from '@/auth/states/currentUserState';
|
import { CurrentUser } from '@/auth/states/currentUserState';
|
||||||
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
|
|
||||||
import { getOnboardingStatus } from '../getOnboardingStatus';
|
import { getOnboardingStatus } from '../getOnboardingStatus';
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
activationStatus: 'inactive',
|
activationStatus: 'inactive',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: false,
|
isBillingEnabled: false,
|
||||||
});
|
});
|
||||||
@ -38,7 +39,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
activationStatus: 'active',
|
activationStatus: 'active',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: false,
|
isBillingEnabled: false,
|
||||||
});
|
});
|
||||||
@ -57,7 +58,26 @@ describe('getOnboardingStatus', () => {
|
|||||||
activationStatus: 'active',
|
activationStatus: 'active',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: false },
|
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,
|
} as CurrentUser,
|
||||||
isBillingEnabled: false,
|
isBillingEnabled: false,
|
||||||
});
|
});
|
||||||
@ -76,7 +96,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
activationStatus: 'active',
|
activationStatus: 'active',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: false,
|
isBillingEnabled: false,
|
||||||
});
|
});
|
||||||
@ -96,7 +116,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
subscriptionStatus: 'incomplete',
|
subscriptionStatus: 'incomplete',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: true,
|
isBillingEnabled: true,
|
||||||
});
|
});
|
||||||
@ -116,7 +136,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
subscriptionStatus: 'incomplete',
|
subscriptionStatus: 'incomplete',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: false,
|
isBillingEnabled: false,
|
||||||
});
|
});
|
||||||
@ -136,7 +156,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
subscriptionStatus: 'canceled',
|
subscriptionStatus: 'canceled',
|
||||||
} as CurrentWorkspace,
|
} as CurrentWorkspace,
|
||||||
currentUser: {
|
currentUser: {
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
} as CurrentUser,
|
} as CurrentUser,
|
||||||
isBillingEnabled: true,
|
isBillingEnabled: true,
|
||||||
});
|
});
|
||||||
@ -145,6 +165,7 @@ describe('getOnboardingStatus', () => {
|
|||||||
expect(ongoingWorkspaceActivation).toBe('ongoing_workspace_activation');
|
expect(ongoingWorkspaceActivation).toBe('ongoing_workspace_activation');
|
||||||
expect(ongoingProfileCreation).toBe('ongoing_profile_creation');
|
expect(ongoingProfileCreation).toBe('ongoing_profile_creation');
|
||||||
expect(ongoingSyncEmail).toBe('ongoing_sync_email');
|
expect(ongoingSyncEmail).toBe('ongoing_sync_email');
|
||||||
|
expect(ongoingInviteTeam).toBe('ongoing_invite_team');
|
||||||
expect(completed).toBe('completed');
|
expect(completed).toBe('completed');
|
||||||
expect(incomplete).toBe('incomplete');
|
expect(incomplete).toBe('incomplete');
|
||||||
expect(canceled).toBe('canceled');
|
expect(canceled).toBe('canceled');
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CurrentUser } from '@/auth/states/currentUserState';
|
import { CurrentUser } from '@/auth/states/currentUserState';
|
||||||
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
|
|
||||||
export enum OnboardingStatus {
|
export enum OnboardingStatus {
|
||||||
Incomplete = 'incomplete',
|
Incomplete = 'incomplete',
|
||||||
@ -11,6 +12,7 @@ export enum OnboardingStatus {
|
|||||||
OngoingWorkspaceActivation = 'ongoing_workspace_activation',
|
OngoingWorkspaceActivation = 'ongoing_workspace_activation',
|
||||||
OngoingProfileCreation = 'ongoing_profile_creation',
|
OngoingProfileCreation = 'ongoing_profile_creation',
|
||||||
OngoingSyncEmail = 'ongoing_sync_email',
|
OngoingSyncEmail = 'ongoing_sync_email',
|
||||||
|
OngoingInviteTeam = 'ongoing_invite_team',
|
||||||
Completed = 'completed',
|
Completed = 'completed',
|
||||||
CompletedWithoutSubscription = 'completed_without_subscription',
|
CompletedWithoutSubscription = 'completed_without_subscription',
|
||||||
}
|
}
|
||||||
@ -59,10 +61,14 @@ export const getOnboardingStatus = ({
|
|||||||
return OnboardingStatus.OngoingProfileCreation;
|
return OnboardingStatus.OngoingProfileCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentUser.state.skipSyncEmailOnboardingStep) {
|
if (currentUser.onboardingStep === OnboardingStep.SyncEmail) {
|
||||||
return OnboardingStatus.OngoingSyncEmail;
|
return OnboardingStatus.OngoingSyncEmail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentUser.onboardingStep === OnboardingStep.InviteTeam) {
|
||||||
|
return OnboardingStatus.OngoingInviteTeam;
|
||||||
|
}
|
||||||
|
|
||||||
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'canceled') {
|
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'canceled') {
|
||||||
return OnboardingStatus.Canceled;
|
return OnboardingStatus.Canceled;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
|
|
||||||
|
const getNextOnboardingStep = (
|
||||||
|
currentOnboardingStep: OnboardingStep,
|
||||||
|
workspaceMembers: WorkspaceMember[],
|
||||||
|
) => {
|
||||||
|
if (currentOnboardingStep === OnboardingStep.SyncEmail) {
|
||||||
|
return workspaceMembers && workspaceMembers.length > 1
|
||||||
|
? null
|
||||||
|
: OnboardingStep.InviteTeam;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSetNextOnboardingStep = () => {
|
||||||
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
|
const { records: workspaceMembers } = useFindManyRecords<WorkspaceMember>({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||||
|
});
|
||||||
|
return useRecoilCallback(
|
||||||
|
() => (currentOnboardingStep: OnboardingStep) => {
|
||||||
|
setCurrentUser(
|
||||||
|
(current) =>
|
||||||
|
({
|
||||||
|
...current,
|
||||||
|
onboardingStep: getNextOnboardingStep(
|
||||||
|
currentOnboardingStep,
|
||||||
|
workspaceMembers,
|
||||||
|
),
|
||||||
|
}) as any,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[setCurrentUser, workspaceMembers],
|
||||||
|
);
|
||||||
|
};
|
@ -9,6 +9,7 @@ export enum AppPath {
|
|||||||
CreateWorkspace = '/create/workspace',
|
CreateWorkspace = '/create/workspace',
|
||||||
CreateProfile = '/create/profile',
|
CreateProfile = '/create/profile',
|
||||||
SyncEmails = '/sync/emails',
|
SyncEmails = '/sync/emails',
|
||||||
|
InviteTeam = '/invite-team',
|
||||||
PlanRequired = '/plan-required',
|
PlanRequired = '/plan-required',
|
||||||
PlanRequiredSuccess = '/plan-required/payment-success',
|
PlanRequiredSuccess = '/plan-required/payment-success',
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ export enum PageHotkeyScope {
|
|||||||
CreateWokspace = 'create-workspace',
|
CreateWokspace = 'create-workspace',
|
||||||
SignInUp = 'sign-in-up',
|
SignInUp = 'sign-in-up',
|
||||||
CreateProfile = 'create-profile',
|
CreateProfile = 'create-profile',
|
||||||
|
InviteTeam = 'invite-team',
|
||||||
|
SyncEmail = 'sync-email',
|
||||||
PlanRequired = 'plan-required',
|
PlanRequired = 'plan-required',
|
||||||
ShowPage = 'show-page',
|
ShowPage = 'show-page',
|
||||||
PersonShowPage = 'person-show-page',
|
PersonShowPage = 'person-show-page',
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
color: ${({ theme }) => theme.font.color.extraLight};
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
height: 1px;
|
||||||
|
flex-grow: 1;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
margin: 0 ${({ theme }) => theme.spacing(4)} 0 0;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
margin: 0 0 0 ${({ theme }) => theme.spacing(4)};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SeparatorLineText = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
return <StyledContainer>{children}</StyledContainer>;
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { ComponentDecorator } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { SeparatorLineText } from '../SeparatorLineText';
|
||||||
|
|
||||||
|
const meta: Meta<typeof SeparatorLineText> = {
|
||||||
|
title: 'UI/Display/Text/SeparatorLineText',
|
||||||
|
component: SeparatorLineText,
|
||||||
|
args: { children: 'Or' },
|
||||||
|
decorators: [ComponentDecorator],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof SeparatorLineText>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
@ -117,6 +117,7 @@ export type TextInputV2ComponentProps = Omit<
|
|||||||
onChange?: (text: string) => void;
|
onChange?: (text: string) => void;
|
||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
noErrorHelper?: boolean;
|
||||||
RightIcon?: IconComponent;
|
RightIcon?: IconComponent;
|
||||||
LeftIcon?: IconComponent;
|
LeftIcon?: IconComponent;
|
||||||
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||||
@ -134,6 +135,7 @@ const TextInputV2Component = (
|
|||||||
onKeyDown,
|
onKeyDown,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
error,
|
error,
|
||||||
|
noErrorHelper = false,
|
||||||
required,
|
required,
|
||||||
type,
|
type,
|
||||||
autoFocus,
|
autoFocus,
|
||||||
@ -207,7 +209,9 @@ const TextInputV2Component = (
|
|||||||
)}
|
)}
|
||||||
</StyledTrailingIconContainer>
|
</StyledTrailingIconContainer>
|
||||||
</StyledInputContainer>
|
</StyledInputContainer>
|
||||||
{error && <StyledErrorHelper>{error}</StyledErrorHelper>}
|
{error && !noErrorHelper && (
|
||||||
|
<StyledErrorHelper>{error}</StyledErrorHelper>
|
||||||
|
)}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -47,6 +47,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: false },
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingWorkspaceActivation, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: false },
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingProfileCreation, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: false },
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingSyncEmail, res: false },
|
||||||
|
{ loc: AppPath.Verify, status: OnboardingStatus.OngoingInviteTeam, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Verify, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.Verify, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.SignInUp, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -69,6 +71,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.Invite, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: true },
|
{ loc: AppPath.Invite, status: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
{ loc: AppPath.Invite, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
||||||
|
|
||||||
@ -80,6 +83,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: true },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.Completed, res: true },
|
||||||
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
{ loc: AppPath.ResetPassword, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
||||||
|
|
||||||
@ -91,6 +95,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.CreateWorkspace, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -102,6 +107,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.CreateProfile, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -113,9 +119,22 @@ const testCases = [
|
|||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.SyncEmails, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Incomplete, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Canceled, res: false },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Unpaid, res: false },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.PastDue, res: false },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingUserCreation, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.Completed, res: false },
|
||||||
|
{ loc: AppPath.InviteTeam, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Incomplete, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Canceled, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: false },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Unpaid, res: false },
|
||||||
@ -124,6 +143,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
{ loc: AppPath.PlanRequired, status: OnboardingStatus.CompletedWithoutSubscription, res: true },
|
||||||
|
|
||||||
@ -135,6 +155,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.PlanRequiredSuccess, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -146,6 +167,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.Index, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Index, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.Index, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -157,6 +179,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.TasksPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -168,6 +191,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.OpportunitiesPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -179,6 +203,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.RecordIndexPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -190,6 +215,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.RecordShowPage, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -201,6 +227,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.SettingsCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -212,6 +239,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.DevelopersCatchAll, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -223,6 +251,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.Impersonate, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -234,6 +263,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.Authorize, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.Authorize, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -245,6 +275,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.NotFoundWildcard, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
|
|
||||||
@ -256,6 +287,7 @@ const testCases = [
|
|||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingWorkspaceActivation, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingProfileCreation, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingSyncEmail, res: true },
|
||||||
|
{ loc: AppPath.NotFound, status: OnboardingStatus.OngoingInviteTeam, res: true },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: false },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.Completed, res: false },
|
||||||
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
{ loc: AppPath.NotFound, status: OnboardingStatus.CompletedWithoutSubscription, res: false },
|
||||||
];
|
];
|
||||||
|
@ -28,7 +28,8 @@ export const useShowAuthModal = () => {
|
|||||||
OnboardingStatus.OngoingUserCreation === onboardingStatus ||
|
OnboardingStatus.OngoingUserCreation === onboardingStatus ||
|
||||||
OnboardingStatus.OngoingProfileCreation === onboardingStatus ||
|
OnboardingStatus.OngoingProfileCreation === onboardingStatus ||
|
||||||
OnboardingStatus.OngoingWorkspaceActivation === onboardingStatus ||
|
OnboardingStatus.OngoingWorkspaceActivation === onboardingStatus ||
|
||||||
OnboardingStatus.OngoingSyncEmail === onboardingStatus
|
OnboardingStatus.OngoingSyncEmail === onboardingStatus ||
|
||||||
|
OnboardingStatus.OngoingInviteTeam === onboardingStatus
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
type AnimatedTranslationProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AnimatedTranslation = ({ children }: AnimatedTranslationProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial="hidden"
|
||||||
|
animate="visible"
|
||||||
|
variants={{
|
||||||
|
hidden: {
|
||||||
|
opacity: 0,
|
||||||
|
y: -20,
|
||||||
|
},
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
duration: theme.animation.duration.normal, // Replace this with your theme's duration
|
||||||
|
ease: 'easeInOut',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
@ -8,9 +8,7 @@ export const USER_QUERY_FRAGMENT = gql`
|
|||||||
email
|
email
|
||||||
canImpersonate
|
canImpersonate
|
||||||
supportUserHash
|
supportUserHash
|
||||||
state {
|
onboardingStep
|
||||||
skipSyncEmailOnboardingStep
|
|
||||||
}
|
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
name {
|
name {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { Controller, useForm } from 'react-hook-form';
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconCopy, IconMail, IconSend } from 'twenty-ui';
|
import { IconMail, IconSend } from 'twenty-ui';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { TextInput } from '@/ui/input/components/TextInput';
|
import { TextInput } from '@/ui/input/components/TextInput';
|
||||||
import { extractEmailsList } from '@/workspace/utils/extractEmailList';
|
import { sanitizeEmailList } from '@/workspace/utils/sanitizeEmailList';
|
||||||
import { useSendInviteLinkMutation } from '~/generated/graphql';
|
import { useSendInviteLinkMutation } from '~/generated/graphql';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ const validationSchema = () =>
|
|||||||
if (!value.length) {
|
if (!value.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const emails = extractEmailsList(value);
|
const emails = sanitizeEmailList(value.split(','));
|
||||||
if (emails.length === 0) {
|
if (emails.length === 0) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.invalid_string,
|
code: z.ZodIssueCode.invalid_string,
|
||||||
@ -69,7 +68,6 @@ type FormInput = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const WorkspaceInviteTeam = () => {
|
export const WorkspaceInviteTeam = () => {
|
||||||
const theme = useTheme();
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
const [sendInviteLink] = useSendInviteLinkMutation();
|
const [sendInviteLink] = useSendInviteLinkMutation();
|
||||||
|
|
||||||
@ -82,14 +80,13 @@ export const WorkspaceInviteTeam = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const submit = handleSubmit(async (data) => {
|
const submit = handleSubmit(async (data) => {
|
||||||
const emailsList = extractEmailsList(data.emails);
|
const emailsList = sanitizeEmailList(data.emails.split(','));
|
||||||
const result = await sendInviteLink({ variables: { emails: emailsList } });
|
const result = await sendInviteLink({ variables: { emails: emailsList } });
|
||||||
if (isDefined(result.errors)) {
|
if (isDefined(result.errors)) {
|
||||||
throw result.errors;
|
throw result.errors;
|
||||||
}
|
}
|
||||||
enqueueSnackBar('Invite link sent to email addresses', {
|
enqueueSnackBar('Invite link sent to email addresses', {
|
||||||
variant: SnackBarVariant.Success,
|
variant: SnackBarVariant.Success,
|
||||||
icon: <IconCopy size={theme.icon.size.md} />,
|
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import { extractEmailsList } from '@/workspace/utils/extractEmailList';
|
|
||||||
|
|
||||||
describe('extractEmailList', () => {
|
|
||||||
it('should extract email list', () => {
|
|
||||||
expect(extractEmailsList('toto@toto.com')).toEqual(['toto@toto.com']);
|
|
||||||
});
|
|
||||||
it('should extract email list with multiple emails', () => {
|
|
||||||
expect(extractEmailsList('toto@toto.com,toto2@toto.com')).toEqual([
|
|
||||||
'toto@toto.com',
|
|
||||||
'toto2@toto.com',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('should extract email list with multiple emails and wrong emails', () => {
|
|
||||||
expect(extractEmailsList('toto@toto.com,toto2@toto.com,toto')).toEqual([
|
|
||||||
'toto@toto.com',
|
|
||||||
'toto2@toto.com',
|
|
||||||
'toto',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('should remove duplicates', () => {
|
|
||||||
expect(extractEmailsList('toto@toto.com,toto@toto.com')).toEqual([
|
|
||||||
'toto@toto.com',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('should remove empty emails', () => {
|
|
||||||
expect(extractEmailsList('toto@toto.com,')).toEqual(['toto@toto.com']);
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,24 @@
|
|||||||
|
import { sanitizeEmailList } from '@/workspace/utils/sanitizeEmailList';
|
||||||
|
|
||||||
|
describe('sanitizeEmailList', () => {
|
||||||
|
it('should do nothing if sanitized email list', () => {
|
||||||
|
expect(sanitizeEmailList(['toto@toto.com', 'toto2@toto.com'])).toEqual([
|
||||||
|
'toto@toto.com',
|
||||||
|
'toto2@toto.com',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('should trim spaces', () => {
|
||||||
|
expect(sanitizeEmailList([' toto@toto.com ', ' toto2@toto.com'])).toEqual([
|
||||||
|
'toto@toto.com',
|
||||||
|
'toto2@toto.com',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('should filter empty emails', () => {
|
||||||
|
expect(sanitizeEmailList(['toto@toto.com', ''])).toEqual(['toto@toto.com']);
|
||||||
|
});
|
||||||
|
it('should remove duplicates', () => {
|
||||||
|
expect(sanitizeEmailList(['toto@toto.com', 'toto@toto.com'])).toEqual([
|
||||||
|
'toto@toto.com',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
@ -1,8 +1,7 @@
|
|||||||
export const extractEmailsList = (emails: string) => {
|
export const sanitizeEmailList = (emailList: string[]): string[] => {
|
||||||
return Array.from(
|
return Array.from(
|
||||||
new Set(
|
new Set(
|
||||||
emails
|
emailList
|
||||||
.split(',')
|
|
||||||
.map((email) => email.trim())
|
.map((email) => email.trim())
|
||||||
.filter((email) => email.length > 0),
|
.filter((email) => email.length > 0),
|
||||||
),
|
),
|
@ -143,7 +143,7 @@ export const ChooseYourPlan = () => {
|
|||||||
return (
|
return (
|
||||||
prices?.getProductPrices?.productPrices && (
|
prices?.getProductPrices?.productPrices && (
|
||||||
<>
|
<>
|
||||||
<Title withMarginTop={false}>Choose your Plan</Title>
|
<Title noMarginTop>Choose your Plan</Title>
|
||||||
<SubTitle>
|
<SubTitle>
|
||||||
Enjoy a {billing?.billingFreeTrialDurationInDays}-day free trial
|
Enjoy a {billing?.billingFreeTrialDurationInDays}-day free trial
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
|
@ -55,9 +55,7 @@ type Form = z.infer<typeof validationSchema>;
|
|||||||
|
|
||||||
export const CreateProfile = () => {
|
export const CreateProfile = () => {
|
||||||
const onboardingStatus = useOnboardingStatus();
|
const onboardingStatus = useOnboardingStatus();
|
||||||
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
|
||||||
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
||||||
currentWorkspaceMemberState,
|
currentWorkspaceMemberState,
|
||||||
);
|
);
|
||||||
@ -145,7 +143,7 @@ export const CreateProfile = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title withMarginTop={false}>Create profile</Title>
|
<Title noMarginTop>Create profile</Title>
|
||||||
<SubTitle>How you'll be identified on the app.</SubTitle>
|
<SubTitle>How you'll be identified on the app.</SubTitle>
|
||||||
<StyledContentContainer>
|
<StyledContentContainer>
|
||||||
<StyledSectionContainer>
|
<StyledSectionContainer>
|
||||||
|
@ -111,7 +111,7 @@ export const CreateWorkspace = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title withMarginTop={false}>Create your workspace</Title>
|
<Title noMarginTop>Create your workspace</Title>
|
||||||
<SubTitle>
|
<SubTitle>
|
||||||
A shared environment where you will be able to manage your customer
|
A shared environment where you will be able to manage your customer
|
||||||
relations with your team.
|
relations with your team.
|
||||||
|
220
packages/twenty-front/src/pages/onboarding/InviteTeam.tsx
Normal file
220
packages/twenty-front/src/pages/onboarding/InviteTeam.tsx
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
SubmitHandler,
|
||||||
|
useFieldArray,
|
||||||
|
useForm,
|
||||||
|
} from 'react-hook-form';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
import { IconCopy } from 'twenty-ui';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
|
import { Title } from '@/auth/components/Title';
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep';
|
||||||
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
|
import { SeparatorLineText } from '@/ui/display/text/components/SeparatorLineText';
|
||||||
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
|
import { LightButton } from '@/ui/input/button/components/LightButton';
|
||||||
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
|
import { AnimatedTranslation } from '@/ui/utilities/animation/components/AnimatedTranslation';
|
||||||
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
|
import { OnboardingStep, useSendInviteLinkMutation } from '~/generated/graphql';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
const StyledAnimatedContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: ${({ theme }) => theme.spacing(8)} 0;
|
||||||
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledActionLinkContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledButtonContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 200px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const validationSchema = z.object({
|
||||||
|
emails: z.array(
|
||||||
|
z.object({ email: z.union([z.literal(''), z.string().email()]) }),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
type FormInput = z.infer<typeof validationSchema>;
|
||||||
|
|
||||||
|
export const InviteTeam = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
const [sendInviteLink] = useSendInviteLinkMutation();
|
||||||
|
const setNextOnboardingStep = useSetNextOnboardingStep();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
formState: { isValid, isSubmitting },
|
||||||
|
} = useForm<FormInput>({
|
||||||
|
mode: 'onChange',
|
||||||
|
defaultValues: {
|
||||||
|
emails: [{ email: '' }, { email: '' }, { email: '' }],
|
||||||
|
},
|
||||||
|
resolver: zodResolver(validationSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name: 'emails',
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(({ emails }) => {
|
||||||
|
if (!emails) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const emailValues = emails.map((email) => email?.email);
|
||||||
|
if (emailValues[emailValues.length - 1] !== '') {
|
||||||
|
append({ email: '' });
|
||||||
|
}
|
||||||
|
if (emailValues.length > 3 && emailValues[emailValues.length - 2] === '') {
|
||||||
|
remove(emailValues.length - 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPlaceholder = (emailIndex: number) => {
|
||||||
|
if (emailIndex === 0) {
|
||||||
|
return 'tim@apple.dev';
|
||||||
|
}
|
||||||
|
if (emailIndex === 1) {
|
||||||
|
return 'craig@apple.dev';
|
||||||
|
}
|
||||||
|
if (emailIndex === 2) {
|
||||||
|
return 'mike@apple.dev';
|
||||||
|
}
|
||||||
|
return 'phil@apple.dev';
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyInviteLink = () => {
|
||||||
|
if (isDefined(currentWorkspace?.inviteHash)) {
|
||||||
|
const inviteLink = `${window.location.origin}/invite/${currentWorkspace?.inviteHash}`;
|
||||||
|
navigator.clipboard.writeText(inviteLink);
|
||||||
|
enqueueSnackBar('Link copied to clipboard', {
|
||||||
|
variant: SnackBarVariant.Success,
|
||||||
|
icon: <IconCopy size={theme.icon.size.md} />,
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<FormInput> = useCallback(
|
||||||
|
async (data) => {
|
||||||
|
const emails = Array.from(
|
||||||
|
new Set(
|
||||||
|
data.emails
|
||||||
|
.map((emailData) => emailData.email.trim())
|
||||||
|
.filter((email) => email.length > 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const result = await sendInviteLink({ variables: { emails } });
|
||||||
|
|
||||||
|
setNextOnboardingStep(OnboardingStep.InviteTeam);
|
||||||
|
|
||||||
|
if (isDefined(result.errors)) {
|
||||||
|
throw result.errors;
|
||||||
|
}
|
||||||
|
if (emails.length > 0) {
|
||||||
|
enqueueSnackBar('Invite link sent to email addresses', {
|
||||||
|
variant: SnackBarVariant.Success,
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[enqueueSnackBar, sendInviteLink, setNextOnboardingStep],
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Enter],
|
||||||
|
() => {
|
||||||
|
handleSubmit(onSubmit)();
|
||||||
|
},
|
||||||
|
PageHotkeyScope.InviteTeam,
|
||||||
|
[handleSubmit],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentUser?.onboardingStep !== OnboardingStep.InviteTeam) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Title noMarginTop>Invite your team</Title>
|
||||||
|
<SubTitle>
|
||||||
|
Get the most out of your workspace by inviting your team.
|
||||||
|
</SubTitle>
|
||||||
|
<StyledAnimatedContainer>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Controller
|
||||||
|
key={index}
|
||||||
|
name={`emails.${index}.email`}
|
||||||
|
control={control}
|
||||||
|
render={({
|
||||||
|
field: { onChange, onBlur, value },
|
||||||
|
fieldState: { error },
|
||||||
|
}) => (
|
||||||
|
<AnimatedTranslation>
|
||||||
|
<TextInputV2
|
||||||
|
autoFocus={index === 0}
|
||||||
|
type="email"
|
||||||
|
value={value}
|
||||||
|
placeholder={getPlaceholder(index)}
|
||||||
|
onBlur={onBlur}
|
||||||
|
error={error?.message}
|
||||||
|
onChange={onChange}
|
||||||
|
noErrorHelper
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</AnimatedTranslation>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{isDefined(currentWorkspace?.inviteHash) && (
|
||||||
|
<>
|
||||||
|
<SeparatorLineText>Or</SeparatorLineText>
|
||||||
|
<StyledActionLinkContainer>
|
||||||
|
<LightButton
|
||||||
|
title="Copy invitation link"
|
||||||
|
accent="tertiary"
|
||||||
|
onClick={copyInviteLink}
|
||||||
|
Icon={IconCopy}
|
||||||
|
/>
|
||||||
|
</StyledActionLinkContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</StyledAnimatedContainer>
|
||||||
|
<StyledButtonContainer>
|
||||||
|
<MainButton
|
||||||
|
title="Finish"
|
||||||
|
disabled={!isValid || isSubmitting}
|
||||||
|
onClick={handleSubmit(onSubmit)}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</StyledButtonContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,21 +1,25 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconGoogle } from 'twenty-ui';
|
import { IconGoogle } from 'twenty-ui';
|
||||||
|
|
||||||
import { SubTitle } from '@/auth/components/SubTitle';
|
import { SubTitle } from '@/auth/components/SubTitle';
|
||||||
import { Title } from '@/auth/components/Title';
|
import { Title } from '@/auth/components/Title';
|
||||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard';
|
import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard';
|
||||||
|
import { useSetNextOnboardingStep } from '@/onboarding/hooks/useSetNextOnboardingStep';
|
||||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||||
import { ActionLink } from '@/ui/navigation/link/components/ActionLink';
|
import { ActionLink } from '@/ui/navigation/link/components/ActionLink';
|
||||||
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import {
|
import {
|
||||||
CalendarChannelVisibility,
|
CalendarChannelVisibility,
|
||||||
MessageChannelVisibility,
|
MessageChannelVisibility,
|
||||||
|
OnboardingStep,
|
||||||
useSkipSyncEmailOnboardingStepMutation,
|
useSkipSyncEmailOnboardingStepMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
@ -35,9 +39,9 @@ const StyledActionLinkContainer = styled.div`
|
|||||||
|
|
||||||
export const SyncEmails = () => {
|
export const SyncEmails = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const navigate = useNavigate();
|
|
||||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||||
const setIsCurrentUserLoaded = useSetRecoilState(isCurrentUserLoadedState);
|
const setNextOnboardingStep = useSetNextOnboardingStep();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
const [visibility, setVisibility] = useState<MessageChannelVisibility>(
|
const [visibility, setVisibility] = useState<MessageChannelVisibility>(
|
||||||
MessageChannelVisibility.ShareEverything,
|
MessageChannelVisibility.ShareEverything,
|
||||||
);
|
);
|
||||||
@ -59,15 +63,25 @@ export const SyncEmails = () => {
|
|||||||
|
|
||||||
const continueWithoutSync = async () => {
|
const continueWithoutSync = async () => {
|
||||||
await skipSyncEmailOnboardingStepMutation();
|
await skipSyncEmailOnboardingStepMutation();
|
||||||
setIsCurrentUserLoaded(false);
|
setNextOnboardingStep(OnboardingStep.SyncEmail);
|
||||||
navigate(AppPath.Index);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSubmitting = false;
|
useScopedHotkeys(
|
||||||
|
[Key.Enter],
|
||||||
|
async () => {
|
||||||
|
await continueWithoutSync();
|
||||||
|
},
|
||||||
|
PageHotkeyScope.SyncEmail,
|
||||||
|
[continueWithoutSync],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentUser?.onboardingStep !== OnboardingStep.SyncEmail) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title withMarginTop={false}>Emails and Calendar</Title>
|
<Title noMarginTop>Emails and Calendar</Title>
|
||||||
<SubTitle>
|
<SubTitle>
|
||||||
Sync your Emails and Calendar with Twenty. Choose your privacy settings.
|
Sync your Emails and Calendar with Twenty. Choose your privacy settings.
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
@ -82,7 +96,6 @@ export const SyncEmails = () => {
|
|||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
width={200}
|
width={200}
|
||||||
Icon={() => <IconGoogle size={theme.icon.size.sm} />}
|
Icon={() => <IconGoogle size={theme.icon.size.sm} />}
|
||||||
disabled={isSubmitting}
|
|
||||||
/>
|
/>
|
||||||
<StyledActionLinkContainer>
|
<StyledActionLinkContainer>
|
||||||
<ActionLink onClick={continueWithoutSync}>
|
<ActionLink onClick={continueWithoutSync}>
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { within } from '@storybook/test';
|
||||||
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
|
import { AppPath } from '~/modules/types/AppPath';
|
||||||
|
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
||||||
|
import { InviteTeam } from '~/pages/onboarding/InviteTeam';
|
||||||
|
import {
|
||||||
|
PageDecorator,
|
||||||
|
PageDecoratorArgs,
|
||||||
|
} from '~/testing/decorators/PageDecorator';
|
||||||
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
|
const meta: Meta<PageDecoratorArgs> = {
|
||||||
|
title: 'Pages/Onboarding/InviteTeam',
|
||||||
|
component: InviteTeam,
|
||||||
|
decorators: [PageDecorator],
|
||||||
|
args: { routePath: AppPath.InviteTeam },
|
||||||
|
parameters: {
|
||||||
|
msw: {
|
||||||
|
handlers: [
|
||||||
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
currentUser: {
|
||||||
|
...mockedOnboardingUsersData[0],
|
||||||
|
onboardingStep: OnboardingStep.InviteTeam,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphqlMocks.handlers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export type Story = StoryObj<typeof InviteTeam>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
await canvas.findByText('Invite your team');
|
||||||
|
},
|
||||||
|
};
|
@ -3,6 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
import { graphql, HttpResponse } from 'msw';
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
|
||||||
|
import { OnboardingStep } from '~/generated/graphql';
|
||||||
import { AppPath } from '~/modules/types/AppPath';
|
import { AppPath } from '~/modules/types/AppPath';
|
||||||
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser';
|
||||||
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
import { SyncEmails } from '~/pages/onboarding/SyncEmails';
|
||||||
@ -24,7 +25,10 @@ const meta: Meta<PageDecoratorArgs> = {
|
|||||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||||
return HttpResponse.json({
|
return HttpResponse.json({
|
||||||
data: {
|
data: {
|
||||||
currentUser: mockedOnboardingUsersData[0],
|
currentUser: {
|
||||||
|
...mockedOnboardingUsersData[0],
|
||||||
|
onboardingStep: OnboardingStep.SyncEmail,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -10,7 +10,7 @@ type MockedUser = Pick<
|
|||||||
| 'canImpersonate'
|
| 'canImpersonate'
|
||||||
| '__typename'
|
| '__typename'
|
||||||
| 'supportUserHash'
|
| 'supportUserHash'
|
||||||
| 'state'
|
| 'onboardingStep'
|
||||||
> & {
|
> & {
|
||||||
workspaceMember: WorkspaceMember | null;
|
workspaceMember: WorkspaceMember | null;
|
||||||
locale: string;
|
locale: string;
|
||||||
@ -93,7 +93,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
defaultWorkspace: mockDefaultWorkspace,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
|
||||||
@ -116,7 +116,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
defaultWorkspace: mockDefaultWorkspace,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
defaultWorkspace: mockDefaultWorkspace,
|
defaultWorkspace: mockDefaultWorkspace,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
|
||||||
@ -159,6 +159,6 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
},
|
},
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
workspaces: [{ workspace: mockDefaultWorkspace }],
|
workspaces: [{ workspace: mockDefaultWorkspace }],
|
||||||
state: { skipSyncEmailOnboardingStep: true },
|
onboardingStep: null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddKeyValuePairTableUniqueContraints1717688588972
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = 'AddKeyValuePairTableUniqueContraints1717688588972';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE UNIQUE INDEX "IndexOnKeyUserIdAndNullWorkspaceIdUnique" ON "core"."keyValuePair" ("key", "userId") WHERE "workspaceId" is NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE UNIQUE INDEX "IndexOnKeyWorkspaceIdAndNullUserIdUnique" ON "core"."keyValuePair" ("key", "workspaceId") WHERE "userId" is NULL`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP INDEX "core"."IndexOnKeyWorkspaceIdAndNullUserIdUnique"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`DROP INDEX "core"."IndexOnKeyUserIdAndNullWorkspaceIdUnique"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repos
|
|||||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity';
|
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity';
|
||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { UserStateModule } from 'src/engine/core-modules/user-state/user-state.module';
|
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
||||||
|
|
||||||
import { AuthResolver } from './auth.resolver';
|
import { AuthResolver } from './auth.resolver';
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ const jwtModule = JwtModule.registerAsync({
|
|||||||
]),
|
]),
|
||||||
HttpModule,
|
HttpModule,
|
||||||
UserWorkspaceModule,
|
UserWorkspaceModule,
|
||||||
UserStateModule,
|
OnboardingModule,
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
GoogleAuthController,
|
GoogleAuthController,
|
||||||
|
@ -15,10 +15,10 @@ import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/strategies/googl
|
|||||||
import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-apis.service';
|
import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-apis.service';
|
||||||
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
|
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { UserStateService } from 'src/engine/core-modules/user-state/user-state.service';
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
|
||||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
|
||||||
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
|
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
|
||||||
|
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||||
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
|
|
||||||
@Controller('auth/google-apis')
|
@Controller('auth/google-apis')
|
||||||
export class GoogleAPIsAuthController {
|
export class GoogleAPIsAuthController {
|
||||||
@ -26,7 +26,7 @@ export class GoogleAPIsAuthController {
|
|||||||
private readonly googleAPIsService: GoogleAPIsService,
|
private readonly googleAPIsService: GoogleAPIsService,
|
||||||
private readonly tokenService: TokenService,
|
private readonly tokenService: TokenService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
private readonly userStateService: UserStateService,
|
private readonly onboardingService: OnboardingService,
|
||||||
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
|
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
|
||||||
private readonly workspaceMemberService: WorkspaceMemberRepository,
|
private readonly workspaceMemberService: WorkspaceMemberRepository,
|
||||||
) {}
|
) {}
|
||||||
@ -86,7 +86,7 @@ export class GoogleAPIsAuthController {
|
|||||||
)?.userId;
|
)?.userId;
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
await this.userStateService.skipSyncEmailOnboardingStep(
|
await this.onboardingService.skipSyncEmailOnboardingStep(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
Column,
|
Column,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
|
Index,
|
||||||
JoinColumn,
|
JoinColumn,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
@ -20,6 +21,14 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|||||||
@Entity({ name: 'keyValuePair', schema: 'core' })
|
@Entity({ name: 'keyValuePair', schema: 'core' })
|
||||||
@ObjectType('KeyValuePair')
|
@ObjectType('KeyValuePair')
|
||||||
@Unique('IndexOnKeyUserIdWorkspaceIdUnique', ['key', 'userId', 'workspaceId'])
|
@Unique('IndexOnKeyUserIdWorkspaceIdUnique', ['key', 'userId', 'workspaceId'])
|
||||||
|
@Index('IndexOnKeyWorkspaceIdAndNullUserIdUnique', ['key', 'workspaceId'], {
|
||||||
|
unique: true,
|
||||||
|
where: '"userId" is NULL',
|
||||||
|
})
|
||||||
|
@Index('IndexOnKeyUserIdAndNullWorkspaceIdUnique', ['key', 'userId'], {
|
||||||
|
unique: true,
|
||||||
|
where: '"workspaceId" is NULL',
|
||||||
|
})
|
||||||
export class KeyValuePair {
|
export class KeyValuePair {
|
||||||
@IDField(() => UUIDScalarType)
|
@IDField(() => UUIDScalarType)
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
@ -1,55 +1,70 @@
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { BadRequestException } from '@nestjs/common';
|
||||||
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
||||||
import { UserStates } from 'src/engine/core-modules/user-state/enums/user-states.enum';
|
|
||||||
import { UserStateEmailSyncValues } from 'src/engine/core-modules/user-state/enums/user-state-email-sync-values.enum';
|
|
||||||
|
|
||||||
export enum KeyValueTypes {
|
export class KeyValuePairService<TYPE> {
|
||||||
USER_STATE = 'USER_STATE',
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeyValuePairs = {
|
|
||||||
[KeyValueTypes.USER_STATE]: {
|
|
||||||
[UserStates.SYNC_EMAIL_ONBOARDING_STEP]: UserStateEmailSyncValues;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export class KeyValuePairService<TYPE extends keyof KeyValuePairs> {
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(KeyValuePair, 'core')
|
@InjectRepository(KeyValuePair, 'core')
|
||||||
private readonly keyValuePairRepository: Repository<KeyValuePair>,
|
private readonly keyValuePairRepository: Repository<KeyValuePair>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async get<K extends keyof KeyValuePairs[TYPE]>(
|
async get<K extends keyof TYPE>({
|
||||||
userId: string,
|
userId,
|
||||||
workspaceId: string,
|
workspaceId,
|
||||||
key: K,
|
key,
|
||||||
) {
|
}: {
|
||||||
return await this.keyValuePairRepository.findOne({
|
userId?: string;
|
||||||
where: {
|
workspaceId?: string;
|
||||||
userId,
|
key: K;
|
||||||
workspaceId,
|
}): Promise<TYPE[K] | undefined> {
|
||||||
key: key as string,
|
return (
|
||||||
},
|
await this.keyValuePairRepository.findOne({
|
||||||
});
|
where: {
|
||||||
|
userId,
|
||||||
|
workspaceId,
|
||||||
|
key: key as string,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)?.value as TYPE[K] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async set<K extends keyof KeyValuePairs[TYPE]>(
|
async set<K extends keyof TYPE>({
|
||||||
userId: string,
|
userId,
|
||||||
workspaceId: string,
|
workspaceId,
|
||||||
key: K,
|
key,
|
||||||
value: KeyValuePairs[TYPE][K],
|
value,
|
||||||
) {
|
}: {
|
||||||
await this.keyValuePairRepository.upsert(
|
userId?: string;
|
||||||
{
|
workspaceId?: string;
|
||||||
userId,
|
key: K;
|
||||||
workspaceId,
|
value: TYPE[K];
|
||||||
key: key as string,
|
}) {
|
||||||
value: value as string,
|
if (!userId && !workspaceId) {
|
||||||
},
|
throw new BadRequestException('userId and workspaceId are undefined');
|
||||||
{ conflictPaths: ['userId', 'workspaceId', 'key'] },
|
}
|
||||||
|
const upsertData = {
|
||||||
|
userId,
|
||||||
|
workspaceId,
|
||||||
|
key: key as string,
|
||||||
|
value: value as string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const conflictPaths = Object.keys(upsertData).filter(
|
||||||
|
(key) => key !== 'value' && upsertData[key] !== undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const indexPredicate = !userId
|
||||||
|
? '"userId" is NULL'
|
||||||
|
: !workspaceId
|
||||||
|
? '"workspaceId" is NULL'
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
await this.keyValuePairRepository.upsert(upsertData, {
|
||||||
|
conflictPaths,
|
||||||
|
indexPredicate,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
import { Field, ObjectType } from '@nestjs/graphql';
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class SkipSyncEmailOnboardingStep {
|
export class OnboardingStepSuccess {
|
||||||
@Field(() => Boolean, {
|
@Field(() => Boolean, {
|
||||||
description: 'Boolean that confirms query was dispatched',
|
description: 'Boolean that confirms query was dispatched',
|
||||||
})
|
})
|
@ -0,0 +1,4 @@
|
|||||||
|
export enum OnboardingStep {
|
||||||
|
SYNC_EMAIL = 'SYNC_EMAIL',
|
||||||
|
INVITE_TEAM = 'INVITE_TEAM',
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
|
import { OnboardingResolver } from 'src/engine/core-modules/onboarding/onboarding.resolver';
|
||||||
|
import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module';
|
||||||
|
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||||
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [DataSourceModule, UserWorkspaceModule, KeyValuePairModule],
|
||||||
|
exports: [OnboardingService],
|
||||||
|
providers: [OnboardingService, OnboardingResolver],
|
||||||
|
})
|
||||||
|
export class OnboardingModule {}
|
@ -2,27 +2,28 @@ import { UseGuards } from '@nestjs/common';
|
|||||||
import { Mutation, Resolver } from '@nestjs/graphql';
|
import { Mutation, Resolver } from '@nestjs/graphql';
|
||||||
|
|
||||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||||
import { UserState } from 'src/engine/core-modules/user-state/dtos/user-state.dto';
|
import { OnboardingStepSuccess } from 'src/engine/core-modules/onboarding/dtos/onboarding-step-success.dto';
|
||||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { UserStateService } from 'src/engine/core-modules/user-state/user-state.service';
|
|
||||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { SkipSyncEmailOnboardingStep } from 'src/engine/core-modules/user-state/dtos/skip-sync-email.entity-onboarding-step';
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Resolver(() => UserState)
|
@Resolver()
|
||||||
export class UserStateResolver {
|
export class OnboardingResolver {
|
||||||
constructor(private readonly userStateService: UserStateService) {}
|
constructor(private readonly onboardingService: OnboardingService) {}
|
||||||
|
|
||||||
@Mutation(() => SkipSyncEmailOnboardingStep)
|
@Mutation(() => OnboardingStepSuccess)
|
||||||
async skipSyncEmailOnboardingStep(
|
async skipSyncEmailOnboardingStep(
|
||||||
@AuthUser() user: User,
|
@AuthUser() user: User,
|
||||||
@AuthWorkspace() workspace: Workspace,
|
@AuthWorkspace() workspace: Workspace,
|
||||||
): Promise<SkipSyncEmailOnboardingStep> {
|
): Promise<OnboardingStepSuccess> {
|
||||||
return await this.userStateService.skipSyncEmailOnboardingStep(
|
await this.onboardingService.skipSyncEmailOnboardingStep(
|
||||||
user.id,
|
user.id,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service';
|
||||||
|
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
||||||
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
|
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
||||||
|
|
||||||
|
enum OnboardingStepValues {
|
||||||
|
SKIPPED = 'SKIPPED',
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OnboardingStepKeys {
|
||||||
|
SYNC_EMAIL_ONBOARDING_STEP = 'SYNC_EMAIL_ONBOARDING_STEP',
|
||||||
|
INVITE_TEAM_ONBOARDING_STEP = 'INVITE_TEAM_ONBOARDING_STEP',
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnboardingKeyValueType = {
|
||||||
|
[OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP]: OnboardingStepValues;
|
||||||
|
[OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP]: OnboardingStepValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OnboardingService {
|
||||||
|
constructor(
|
||||||
|
private readonly userWorkspaceService: UserWorkspaceService,
|
||||||
|
private readonly keyValuePairService: KeyValuePairService<OnboardingKeyValueType>,
|
||||||
|
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
||||||
|
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
private async isSyncEmailOnboardingStep(user: User, workspace: Workspace) {
|
||||||
|
const syncEmailValue = await this.keyValuePairService.get({
|
||||||
|
userId: user.id,
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
key: OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP,
|
||||||
|
});
|
||||||
|
const isSyncEmailSkipped = syncEmailValue === OnboardingStepValues.SKIPPED;
|
||||||
|
const connectedAccounts =
|
||||||
|
await this.connectedAccountRepository.getAllByUserId(
|
||||||
|
user.id,
|
||||||
|
workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
return !isSyncEmailSkipped && !connectedAccounts?.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async isInviteTeamOnboardingStep(workspace: Workspace) {
|
||||||
|
const inviteTeamValue = await this.keyValuePairService.get({
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
key: OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP,
|
||||||
|
});
|
||||||
|
const isInviteTeamSkipped =
|
||||||
|
inviteTeamValue === OnboardingStepValues.SKIPPED;
|
||||||
|
const workspaceMemberCount =
|
||||||
|
await this.userWorkspaceService.getWorkspaceMemberCount(workspace.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
!isInviteTeamSkipped &&
|
||||||
|
(!workspaceMemberCount || workspaceMemberCount <= 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOnboardingStep(
|
||||||
|
user: User,
|
||||||
|
workspace: Workspace,
|
||||||
|
): Promise<OnboardingStep | null> {
|
||||||
|
if (await this.isSyncEmailOnboardingStep(user, workspace)) {
|
||||||
|
return OnboardingStep.SYNC_EMAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await this.isInviteTeamOnboardingStep(workspace)) {
|
||||||
|
return OnboardingStep.INVITE_TEAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async skipInviteTeamOnboardingStep(workspaceId: string) {
|
||||||
|
await this.keyValuePairService.set({
|
||||||
|
workspaceId,
|
||||||
|
key: OnboardingStepKeys.INVITE_TEAM_ONBOARDING_STEP,
|
||||||
|
value: OnboardingStepValues.SKIPPED,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async skipSyncEmailOnboardingStep(userId: string, workspaceId: string) {
|
||||||
|
await this.keyValuePairService.set({
|
||||||
|
userId,
|
||||||
|
workspaceId,
|
||||||
|
key: OnboardingStepKeys.SYNC_EMAIL_ONBOARDING_STEP,
|
||||||
|
value: OnboardingStepValues.SKIPPED,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
import { UserState } from 'src/engine/core-modules/user-state/dtos/user-state.dto';
|
|
||||||
|
|
||||||
export const DEFAULT_USER_STATE: UserState = {
|
|
||||||
skipSyncEmailOnboardingStep: true,
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
|
||||||
|
|
||||||
@ObjectType('UserState')
|
|
||||||
export class UserState {
|
|
||||||
@Field(() => Boolean, { nullable: true })
|
|
||||||
skipSyncEmailOnboardingStep: boolean | null;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export enum UserStateEmailSyncValues {
|
|
||||||
SKIPPED = 'SKIPPED',
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export enum UserStates {
|
|
||||||
SYNC_EMAIL_ONBOARDING_STEP = 'SYNC_EMAIL_ONBOARDING_STEP',
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { UserStateService } from 'src/engine/core-modules/user-state/user-state.service';
|
|
||||||
import { UserStateResolver } from 'src/engine/core-modules/user-state/user-state.resolver';
|
|
||||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
|
||||||
import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [DataSourceModule, KeyValuePairModule],
|
|
||||||
exports: [UserStateService],
|
|
||||||
providers: [UserStateService, UserStateResolver],
|
|
||||||
})
|
|
||||||
export class UserStateModule {}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
|
||||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
|
||||||
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
||||||
import { UserState } from 'src/engine/core-modules/user-state/dtos/user-state.dto';
|
|
||||||
import {
|
|
||||||
KeyValuePairService,
|
|
||||||
KeyValueTypes,
|
|
||||||
} from 'src/engine/core-modules/key-value-pair/key-value-pair.service';
|
|
||||||
import { UserStates } from 'src/engine/core-modules/user-state/enums/user-states.enum';
|
|
||||||
import { UserStateEmailSyncValues } from 'src/engine/core-modules/user-state/enums/user-state-email-sync-values.enum';
|
|
||||||
import { SkipSyncEmailOnboardingStep } from 'src/engine/core-modules/user-state/dtos/skip-sync-email.entity-onboarding-step';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UserStateService {
|
|
||||||
constructor(
|
|
||||||
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
|
||||||
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
|
||||||
private readonly keyValuePairService: KeyValuePairService<KeyValueTypes.USER_STATE>,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async getUserState(user: User, workspace: Workspace): Promise<UserState> {
|
|
||||||
const connectedAccounts =
|
|
||||||
await this.connectedAccountRepository.getAllByUserId(
|
|
||||||
user.id,
|
|
||||||
workspace.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (connectedAccounts?.length) {
|
|
||||||
return {
|
|
||||||
skipSyncEmailOnboardingStep: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const skipSyncEmail = await this.keyValuePairService.get(
|
|
||||||
user.id,
|
|
||||||
workspace.id,
|
|
||||||
UserStates.SYNC_EMAIL_ONBOARDING_STEP,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
skipSyncEmailOnboardingStep:
|
|
||||||
!!skipSyncEmail &&
|
|
||||||
skipSyncEmail.value === UserStateEmailSyncValues.SKIPPED,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async skipSyncEmailOnboardingStep(
|
|
||||||
userId: string,
|
|
||||||
workspaceId: string,
|
|
||||||
): Promise<SkipSyncEmailOnboardingStep> {
|
|
||||||
await this.keyValuePairService.set(
|
|
||||||
userId,
|
|
||||||
workspaceId,
|
|
||||||
UserStates.SYNC_EMAIL_ONBOARDING_STEP,
|
|
||||||
UserStateEmailSyncValues.SKIPPED,
|
|
||||||
);
|
|
||||||
|
|
||||||
return { success: true };
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Entity,
|
Entity,
|
||||||
@ -18,7 +18,12 @@ import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-mem
|
|||||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||||
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
||||||
import { UserState } from 'src/engine/core-modules/user-state/dtos/user-state.dto';
|
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
||||||
|
|
||||||
|
registerEnumType(OnboardingStep, {
|
||||||
|
name: 'OnboardingStep',
|
||||||
|
description: 'Onboarding step',
|
||||||
|
});
|
||||||
|
|
||||||
@Entity({ name: 'user', schema: 'core' })
|
@Entity({ name: 'user', schema: 'core' })
|
||||||
@ObjectType('User')
|
@ObjectType('User')
|
||||||
@ -114,6 +119,6 @@ export class User {
|
|||||||
@OneToMany(() => UserWorkspace, (userWorkspace) => userWorkspace.user)
|
@OneToMany(() => UserWorkspace, (userWorkspace) => userWorkspace.user)
|
||||||
workspaces: Relation<UserWorkspace[]>;
|
workspaces: Relation<UserWorkspace[]>;
|
||||||
|
|
||||||
@Field(() => UserState, { nullable: false })
|
@Field(() => OnboardingStep, { nullable: true })
|
||||||
state: UserState;
|
onboardingStep: OnboardingStep;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s
|
|||||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||||
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
||||||
import { UserStateModule } from 'src/engine/core-modules/user-state/user-state.module';
|
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
||||||
|
|
||||||
import { userAutoResolverOpts } from './user.auto-resolver-opts';
|
import { userAutoResolverOpts } from './user.auto-resolver-opts';
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ import { UserService } from './services/user.service';
|
|||||||
}),
|
}),
|
||||||
DataSourceModule,
|
DataSourceModule,
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
UserStateModule,
|
|
||||||
WorkspaceModule,
|
WorkspaceModule,
|
||||||
|
OnboardingModule,
|
||||||
],
|
],
|
||||||
exports: [UserService],
|
exports: [UserService],
|
||||||
providers: [UserService, UserResolver, TypeORMService],
|
providers: [UserService, UserResolver, TypeORMService],
|
||||||
|
@ -27,11 +27,8 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
|||||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
import { OnboardingStep } from 'src/engine/core-modules/onboarding/enums/onboarding-step.enum';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
import { UserState } from 'src/engine/core-modules/user-state/dtos/user-state.dto';
|
|
||||||
import { UserStateService } from 'src/engine/core-modules/user-state/user-state.service';
|
|
||||||
import { DEFAULT_USER_STATE } from 'src/engine/core-modules/user-state/constants/default-user-state';
|
|
||||||
|
|
||||||
const getHMACKey = (email?: string, key?: string | null) => {
|
const getHMACKey = (email?: string, key?: string | null) => {
|
||||||
if (!email || !key) return null;
|
if (!email || !key) return null;
|
||||||
@ -47,10 +44,10 @@ export class UserResolver {
|
|||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(User, 'core')
|
@InjectRepository(User, 'core')
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
private readonly userStateService: UserStateService,
|
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
private readonly fileUploadService: FileUploadService,
|
private readonly fileUploadService: FileUploadService,
|
||||||
|
private readonly onboardingService: OnboardingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Query(() => User)
|
@Query(() => User)
|
||||||
@ -119,15 +116,15 @@ export class UserResolver {
|
|||||||
return this.userService.deleteUser(userId);
|
return this.userService.deleteUser(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => UserState)
|
@ResolveField(() => OnboardingStep)
|
||||||
async state(
|
async onboardingStep(@Parent() user: User): Promise<OnboardingStep | null> {
|
||||||
@Parent() user: User,
|
if (!user) {
|
||||||
@AuthWorkspace() workspace: Workspace,
|
return null;
|
||||||
): Promise<UserState> {
|
|
||||||
if (!user || !workspace) {
|
|
||||||
return DEFAULT_USER_STATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.userStateService.getUserState(user, workspace);
|
return this.onboardingService.getOnboardingStep(
|
||||||
|
user,
|
||||||
|
user.defaultWorkspace,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { ArgsType, Field } from '@nestjs/graphql';
|
import { ArgsType, Field } from '@nestjs/graphql';
|
||||||
|
|
||||||
import { ArrayNotEmpty, IsArray, IsEmail } from 'class-validator';
|
import { ArrayUnique, IsArray, IsEmail } from 'class-validator';
|
||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class SendInviteLinkInput {
|
export class SendInviteLinkInput {
|
||||||
@Field(() => [String])
|
@Field(() => [String])
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ArrayNotEmpty()
|
|
||||||
@IsEmail({}, { each: true })
|
@IsEmail({}, { each: true })
|
||||||
|
@ArrayUnique()
|
||||||
emails: string[];
|
emails: string[];
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/use
|
|||||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||||
import { EmailService } from 'src/engine/integrations/email/email.service';
|
import { EmailService } from 'src/engine/integrations/email/email.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
|
|
||||||
import { WorkspaceService } from './workspace.service';
|
import { WorkspaceService } from './workspace.service';
|
||||||
|
|
||||||
@ -48,12 +49,16 @@ describe('WorkspaceService', () => {
|
|||||||
provide: BillingService,
|
provide: BillingService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: EnvironmentService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: EmailService,
|
provide: EmailService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: EnvironmentService,
|
provide: OnboardingService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -18,6 +18,7 @@ import { BillingService } from 'src/engine/core-modules/billing/billing.service'
|
|||||||
import { SendInviteLink } from 'src/engine/core-modules/workspace/dtos/send-invite-link.entity';
|
import { SendInviteLink } from 'src/engine/core-modules/workspace/dtos/send-invite-link.entity';
|
||||||
import { EmailService } from 'src/engine/integrations/email/email.service';
|
import { EmailService } from 'src/engine/integrations/email/email.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
|
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||||
|
|
||||||
export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
||||||
constructor(
|
constructor(
|
||||||
@ -32,6 +33,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
private readonly billingService: BillingService,
|
private readonly billingService: BillingService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
private readonly emailService: EmailService,
|
private readonly emailService: EmailService,
|
||||||
|
private readonly onboardingService: OnboardingService,
|
||||||
) {
|
) {
|
||||||
super(workspaceRepository);
|
super(workspaceRepository);
|
||||||
}
|
}
|
||||||
@ -96,6 +98,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
});
|
});
|
||||||
|
await this.onboardingService.skipInviteTeamOnboardingStep(workspaceId);
|
||||||
await this.reassignOrRemoveUserDefaultWorkspace(workspaceId, userId);
|
await this.reassignOrRemoveUserDefaultWorkspace(workspaceId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +110,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
if (!workspace?.inviteHash) {
|
if (!workspace?.inviteHash) {
|
||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const frontBaseURL = this.environmentService.get('FRONT_BASE_URL');
|
const frontBaseURL = this.environmentService.get('FRONT_BASE_URL');
|
||||||
const inviteLink = `${frontBaseURL}/invite/${workspace.inviteHash}`;
|
const inviteLink = `${frontBaseURL}/invite/${workspace.inviteHash}`;
|
||||||
|
|
||||||
@ -136,6 +140,8 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.onboardingService.skipInviteTeamOnboardingStep(workspace.id);
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import { WorkspaceWorkspaceMemberListener } from 'src/engine/core-modules/worksp
|
|||||||
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { UserWorkspaceResolver } from 'src/engine/core-modules/user-workspace/user-workspace.resolver';
|
import { UserWorkspaceResolver } from 'src/engine/core-modules/user-workspace/user-workspace.resolver';
|
||||||
|
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
||||||
|
|
||||||
import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts';
|
import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts';
|
||||||
import { Workspace } from './workspace.entity';
|
import { Workspace } from './workspace.entity';
|
||||||
@ -37,6 +38,7 @@ import { WorkspaceService } from './services/workspace.service';
|
|||||||
UserWorkspaceModule,
|
UserWorkspaceModule,
|
||||||
WorkspaceManagerModule,
|
WorkspaceManagerModule,
|
||||||
DataSourceModule,
|
DataSourceModule,
|
||||||
|
OnboardingModule,
|
||||||
TypeORMModule,
|
TypeORMModule,
|
||||||
],
|
],
|
||||||
services: [WorkspaceService],
|
services: [WorkspaceService],
|
||||||
|
19
yarn.lock
19
yarn.lock
@ -42859,6 +42859,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"reflect-metadata@npm:^0.2.1":
|
||||||
|
version: 0.2.2
|
||||||
|
resolution: "reflect-metadata@npm:0.2.2"
|
||||||
|
checksum: 1cd93a15ea291e420204955544637c264c216e7aac527470e393d54b4bb075f10a17e60d8168ec96600c7e0b9fcc0cb0bb6e91c3fbf5b0d8c9056f04e6ac1ec2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"reflect.getprototypeof@npm:^1.0.4":
|
"reflect.getprototypeof@npm:^1.0.4":
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
resolution: "reflect.getprototypeof@npm:1.0.4"
|
resolution: "reflect.getprototypeof@npm:1.0.4"
|
||||||
@ -47538,7 +47545,7 @@ __metadata:
|
|||||||
tsup: "npm:^8.0.1"
|
tsup: "npm:^8.0.1"
|
||||||
tsx: "npm:^4.7.2"
|
tsx: "npm:^4.7.2"
|
||||||
type-fest: "npm:4.10.1"
|
type-fest: "npm:4.10.1"
|
||||||
typeorm: "npm:^0.3.17"
|
typeorm: "npm:^0.3.20"
|
||||||
typescript: "npm:5.3.3"
|
typescript: "npm:5.3.3"
|
||||||
use-context-selector: "npm:^2.0.0"
|
use-context-selector: "npm:^2.0.0"
|
||||||
use-debounce: "npm:^10.0.0"
|
use-debounce: "npm:^10.0.0"
|
||||||
@ -47664,9 +47671,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"typeorm@npm:^0.3.17":
|
"typeorm@npm:^0.3.20":
|
||||||
version: 0.3.19
|
version: 0.3.20
|
||||||
resolution: "typeorm@npm:0.3.19"
|
resolution: "typeorm@npm:0.3.20"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sqltools/formatter": "npm:^1.2.5"
|
"@sqltools/formatter": "npm:^1.2.5"
|
||||||
app-root-path: "npm:^3.1.0"
|
app-root-path: "npm:^3.1.0"
|
||||||
@ -47678,7 +47685,7 @@ __metadata:
|
|||||||
dotenv: "npm:^16.0.3"
|
dotenv: "npm:^16.0.3"
|
||||||
glob: "npm:^10.3.10"
|
glob: "npm:^10.3.10"
|
||||||
mkdirp: "npm:^2.1.3"
|
mkdirp: "npm:^2.1.3"
|
||||||
reflect-metadata: "npm:^0.1.13"
|
reflect-metadata: "npm:^0.2.1"
|
||||||
sha.js: "npm:^2.4.11"
|
sha.js: "npm:^2.4.11"
|
||||||
tslib: "npm:^2.5.0"
|
tslib: "npm:^2.5.0"
|
||||||
uuid: "npm:^9.0.0"
|
uuid: "npm:^9.0.0"
|
||||||
@ -47740,7 +47747,7 @@ __metadata:
|
|||||||
typeorm: cli.js
|
typeorm: cli.js
|
||||||
typeorm-ts-node-commonjs: cli-ts-node-commonjs.js
|
typeorm-ts-node-commonjs: cli-ts-node-commonjs.js
|
||||||
typeorm-ts-node-esm: cli-ts-node-esm.js
|
typeorm-ts-node-esm: cli-ts-node-esm.js
|
||||||
checksum: c03a226b6d78c65fa0e69f5d0f0c515f80d6d2f39ffdac50a84e41bcc59d3296c012e4f6033d8f7444c9f5fd277c6bb4c9fa72bac637547d8bf2ff29a38cb3c6
|
checksum: 7e4be724641beef86ae36289c87b6e66bfaf19a4313f089926d36d2d6f0d67f9314d942711c9d83ab8a174b8622148c2f7e83e6c1448d638ee3ab24469257814
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user