diff --git a/package.json b/package.json index ea4ae684b..b0414a544 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@aws-sdk/client-s3": "^3.700.0", "@aws-sdk/client-sts": "^3.700.0", "@aws-sdk/credential-providers": "^3.700.0", + "@calcom/embed-react": "^1.5.3", "@codesandbox/sandpack-react": "^2.13.5", "@dagrejs/dagre": "^1.1.2", "@emotion/react": "^11.11.1", diff --git a/packages/twenty-front/public/images/placeholders/onboarding-covers/onboarding-book-call-decision-cover.png b/packages/twenty-front/public/images/placeholders/onboarding-covers/onboarding-book-call-decision-cover.png new file mode 100644 index 000000000..3e1e4c9b4 Binary files /dev/null and b/packages/twenty-front/public/images/placeholders/onboarding-covers/onboarding-book-call-decision-cover.png differ diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index b9f260309..2a51cd34a 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -318,6 +318,7 @@ export type ClientConfig = { api: ApiConfig; authProviders: AuthProviders; billing: Billing; + calendarBookingPageId?: Maybe; canManageFeatureFlags: Scalars['Boolean']; captcha: Captcha; chromeExtensionId?: Maybe; @@ -948,6 +949,7 @@ export type Mutation = { signUp: AvailableWorkspacesAndAccessTokensOutput; signUpInNewWorkspace: SignUpOutput; signUpInWorkspace: SignUpOutput; + skipBookOnboardingStep: OnboardingStepSuccess; skipSyncEmailOnboardingStep: OnboardingStepSuccess; submitFormStep: Scalars['Boolean']; switchToEnterprisePlan: BillingUpdateOutput; @@ -1477,6 +1479,7 @@ export type OnDbEventInput = { /** Onboarding status */ export enum OnboardingStatus { + BOOK_ONBOARDING = 'BOOK_ONBOARDING', COMPLETED = 'COMPLETED', INVITE_TEAM = 'INVITE_TEAM', PLAN_REQUIRED = 'PLAN_REQUIRED', @@ -2747,7 +2750,7 @@ export type GetMeteredProductsUsageQuery = { __typename?: 'Query', getMeteredPro export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; -export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, isMultiWorkspaceEnabled: boolean, isEmailVerificationRequired: boolean, defaultSubdomain?: string | null, frontDomain: string, debugMode: boolean, analyticsEnabled: boolean, isAttachmentPreviewEnabled: boolean, chromeExtensionId?: string | null, canManageFeatureFlags: boolean, isMicrosoftMessagingEnabled: boolean, isMicrosoftCalendarEnabled: boolean, isGoogleMessagingEnabled: boolean, isGoogleCalendarEnabled: boolean, isConfigVariablesInDbEnabled: boolean, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, trialPeriods: Array<{ __typename?: 'BillingTrialPeriodDTO', duration: number, isCreditCardRequired: boolean }> }, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean, sso: Array<{ __typename?: 'SSOIdentityProvider', id: string, name: string, type: IdentityProviderType, status: SsoIdentityProviderStatus, issuer: string }> }, support: { __typename?: 'Support', supportDriver: SupportDriver, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null }, api: { __typename?: 'ApiConfig', mutationMaximumAffectedRecords: number }, publicFeatureFlags: Array<{ __typename?: 'PublicFeatureFlag', key: FeatureFlagKey, metadata: { __typename?: 'PublicFeatureFlagMetadata', label: string, description: string, imagePath: string } }> } }; +export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, isMultiWorkspaceEnabled: boolean, isEmailVerificationRequired: boolean, defaultSubdomain?: string | null, frontDomain: string, debugMode: boolean, analyticsEnabled: boolean, isAttachmentPreviewEnabled: boolean, chromeExtensionId?: string | null, canManageFeatureFlags: boolean, isMicrosoftMessagingEnabled: boolean, isMicrosoftCalendarEnabled: boolean, isGoogleMessagingEnabled: boolean, isGoogleCalendarEnabled: boolean, isConfigVariablesInDbEnabled: boolean, calendarBookingPageId?: string | null, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, trialPeriods: Array<{ __typename?: 'BillingTrialPeriodDTO', duration: number, isCreditCardRequired: boolean }> }, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean, sso: Array<{ __typename?: 'SSOIdentityProvider', id: string, name: string, type: IdentityProviderType, status: SsoIdentityProviderStatus, issuer: string }> }, support: { __typename?: 'Support', supportDriver: SupportDriver, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null }, api: { __typename?: 'ApiConfig', mutationMaximumAffectedRecords: number }, publicFeatureFlags: Array<{ __typename?: 'PublicFeatureFlag', key: FeatureFlagKey, metadata: { __typename?: 'PublicFeatureFlagMetadata', label: string, description: string, imagePath: string } }> } }; export type SearchQueryVariables = Exact<{ searchInput: Scalars['String']; @@ -2761,6 +2764,11 @@ export type SearchQueryVariables = Exact<{ export type SearchQuery = { __typename?: 'Query', search: { __typename?: 'SearchResultConnection', edges: Array<{ __typename?: 'SearchResultEdge', cursor: string, node: { __typename?: 'SearchRecord', recordId: string, objectNameSingular: string, label: string, imageUrl?: string | null, tsRankCD: number, tsRank: number } }>, pageInfo: { __typename?: 'SearchResultPageInfo', hasNextPage: boolean, endCursor?: string | null } } }; +export type SkipBookOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>; + + +export type SkipBookOnboardingStepMutation = { __typename?: 'Mutation', skipBookOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } }; + export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>; @@ -4758,6 +4766,7 @@ export const GetClientConfigDocument = gql` isGoogleMessagingEnabled isGoogleCalendarEnabled isConfigVariablesInDbEnabled + calendarBookingPageId } } `; @@ -4849,6 +4858,38 @@ export function useSearchLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions; export type SearchLazyQueryHookResult = ReturnType; export type SearchQueryResult = Apollo.QueryResult; +export const SkipBookOnboardingStepDocument = gql` + mutation SkipBookOnboardingStep { + skipBookOnboardingStep { + success + } +} + `; +export type SkipBookOnboardingStepMutationFn = Apollo.MutationFunction; + +/** + * __useSkipBookOnboardingStepMutation__ + * + * To run a mutation, you first call `useSkipBookOnboardingStepMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useSkipBookOnboardingStepMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [skipBookOnboardingStepMutation, { data, loading, error }] = useSkipBookOnboardingStepMutation({ + * variables: { + * }, + * }); + */ +export function useSkipBookOnboardingStepMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(SkipBookOnboardingStepDocument, options); + } +export type SkipBookOnboardingStepMutationHookResult = ReturnType; +export type SkipBookOnboardingStepMutationResult = Apollo.MutationResult; +export type SkipBookOnboardingStepMutationOptions = Apollo.BaseMutationOptions; export const SkipSyncEmailOnboardingStepDocument = gql` mutation SkipSyncEmailOnboardingStep { skipSyncEmailOnboardingStep { diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts index cdbc48636..62258d26f 100644 --- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts @@ -9,10 +9,10 @@ import { useRecoilValue } from 'recoil'; import { OnboardingStatus } from '~/generated/graphql'; +import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace'; import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation'; import { UNTESTED_APP_PATHS } from '~/testing/constants/UntestedAppPaths'; import { isMatchingLocation } from '~/utils/isMatchingLocation'; -import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace'; jest.mock('@/onboarding/hooks/useOnboardingStatus'); const setupMockOnboardingStatus = ( @@ -92,6 +92,7 @@ const testCases: { { loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -101,6 +102,7 @@ const testCases: { { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' }, @@ -110,6 +112,7 @@ const testCases: { { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' }, { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' }, { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' }, + { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' }, @@ -119,6 +122,7 @@ const testCases: { { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' }, { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' }, { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' }, + { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -130,6 +134,7 @@ const testCases: { { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -139,6 +144,7 @@ const testCases: { { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -148,6 +154,7 @@ const testCases: { { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: undefined }, { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -157,6 +164,7 @@ const testCases: { { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: undefined }, { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -166,8 +174,29 @@ const testCases: { { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: undefined }, + { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' }, + { loc: AppPath.BookCallDecision, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined }, + { loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, + + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' }, + { loc: AppPath.BookCall, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined }, + { loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, + { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined }, { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' }, { loc: AppPath.PlanRequired, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp }, @@ -175,6 +204,7 @@ const testCases: { { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined }, @@ -184,6 +214,7 @@ const testCases: { { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -193,6 +224,7 @@ const testCases: { { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath }, { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -202,6 +234,7 @@ const testCases: { { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -211,6 +244,7 @@ const testCases: { { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -220,6 +254,7 @@ const testCases: { { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined, objectNamePluralFromParams: 'existing-object', objectNamePluralFromMetadata: 'existing-object' }, { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: AppPath.NotFound, objectNamePluralFromParams: 'non-existing-object', objectNamePluralFromMetadata: 'existing-object' }, @@ -231,6 +266,7 @@ const testCases: { { loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -240,6 +276,7 @@ const testCases: { { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -249,6 +286,7 @@ const testCases: { { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -258,6 +296,7 @@ const testCases: { { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -267,6 +306,7 @@ const testCases: { { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired }, @@ -276,6 +316,7 @@ const testCases: { { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile }, { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails }, { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam }, + { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision }, { loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined }, ]; diff --git a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts index 02c729c06..2ef0fa64e 100644 --- a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts +++ b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts @@ -39,6 +39,8 @@ export const usePageChangeEffectNavigateLocation = () => { AppPath.InviteTeam, AppPath.PlanRequired, AppPath.PlanRequiredSuccess, + AppPath.BookCallDecision, + AppPath.BookCall, ]; const objectNamePlural = useParams().objectNamePlural ?? ''; @@ -60,7 +62,12 @@ export const usePageChangeEffectNavigateLocation = () => { if ( onboardingStatus === OnboardingStatus.PLAN_REQUIRED && - !someMatchingLocationOf([AppPath.PlanRequired, AppPath.PlanRequiredSuccess]) + !someMatchingLocationOf([ + AppPath.PlanRequired, + AppPath.PlanRequiredSuccess, + AppPath.BookCall, + AppPath.BookCallDecision, + ]) ) { if ( isMatchingLocation(location, AppPath.VerifyEmail) && @@ -86,6 +93,8 @@ export const usePageChangeEffectNavigateLocation = () => { !someMatchingLocationOf([ AppPath.CreateWorkspace, AppPath.PlanRequiredSuccess, + AppPath.BookCallDecision, + AppPath.BookCall, ]) ) { return AppPath.CreateWorkspace; @@ -112,6 +121,13 @@ export const usePageChangeEffectNavigateLocation = () => { return AppPath.InviteTeam; } + if ( + onboardingStatus === OnboardingStatus.BOOK_ONBOARDING && + !someMatchingLocationOf([AppPath.BookCallDecision, AppPath.BookCall]) + ) { + return AppPath.BookCallDecision; + } + if ( onboardingStatus === OnboardingStatus.COMPLETED && someMatchingLocationOf([...onboardingPaths, ...onGoingUserCreationPaths]) && diff --git a/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx b/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx index bc4d62a6d..c4a92c2a7 100644 --- a/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx +++ b/packages/twenty-front/src/modules/app/hooks/useCreateAppRouter.tsx @@ -19,6 +19,8 @@ import { SignInUp } from '~/pages/auth/SignInUp'; import { NotFound } from '~/pages/not-found/NotFound'; import { RecordIndexPage } from '~/pages/object-record/RecordIndexPage'; import { RecordShowPage } from '~/pages/object-record/RecordShowPage'; +import { BookCall } from '~/pages/onboarding/BookCall'; +import { BookCallDecision } from '~/pages/onboarding/BookCallDecision'; import { ChooseYourPlan } from '~/pages/onboarding/ChooseYourPlan'; import { CreateProfile } from '~/pages/onboarding/CreateProfile'; import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace'; @@ -53,6 +55,11 @@ export const useCreateAppRouter = ( path={AppPath.PlanRequiredSuccess} element={} /> + } + /> + } /> } /> } /> } /> diff --git a/packages/twenty-front/src/modules/auth/components/AuthModal.tsx b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx index a406b0946..f6ea9dd5f 100644 --- a/packages/twenty-front/src/modules/auth/components/AuthModal.tsx +++ b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx @@ -1,9 +1,11 @@ import { AuthModalMountEffect } from '@/auth/components/AuthModalMountEffect'; import { AUTH_MODAL_ID } from '@/auth/constants/AuthModalId'; +import { getAuthModalConfig } from '@/auth/utils/getAuthModalConfig'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import styled from '@emotion/styled'; import React from 'react'; +import { useLocation } from 'react-router-dom'; const StyledContent = styled.div` align-items: center; @@ -14,13 +16,27 @@ type AuthModalProps = { children: React.ReactNode; }; -export const AuthModal = ({ children }: AuthModalProps) => ( - <> - - - - {children} - - - -); +export const AuthModal = ({ children }: AuthModalProps) => { + const location = useLocation(); + const config = getAuthModalConfig(location); + + return ( + <> + + + {config.showScrollWrapper ? ( + + {children} + + ) : ( + <>{children} + )} + + + ); +}; diff --git a/packages/twenty-front/src/modules/auth/constants/AuthModalConfig.ts b/packages/twenty-front/src/modules/auth/constants/AuthModalConfig.ts new file mode 100644 index 000000000..7b6f715c0 --- /dev/null +++ b/packages/twenty-front/src/modules/auth/constants/AuthModalConfig.ts @@ -0,0 +1,24 @@ +import { AppPath } from '@/types/AppPath'; +import { ModalSize, ModalVariants } from '@/ui/layout/modal/components/Modal'; + +type AuthModalConfigType = { + size: ModalSize; + variant: ModalVariants; + showScrollWrapper: boolean; +}; + +export const AUTH_MODAL_CONFIG: { + default: AuthModalConfigType; + [key: string]: AuthModalConfigType; +} = { + default: { + size: 'medium', + variant: 'primary', + showScrollWrapper: true, + }, + [AppPath.BookCall]: { + size: 'extraLarge', + variant: 'transparent', + showScrollWrapper: false, + }, +}; diff --git a/packages/twenty-front/src/modules/auth/utils/getAuthModalConfig.ts b/packages/twenty-front/src/modules/auth/utils/getAuthModalConfig.ts new file mode 100644 index 000000000..7d22404a5 --- /dev/null +++ b/packages/twenty-front/src/modules/auth/utils/getAuthModalConfig.ts @@ -0,0 +1,18 @@ +import { AUTH_MODAL_CONFIG } from '@/auth/constants/AuthModalConfig'; +import { AppPath } from '@/types/AppPath'; +import { Location } from 'react-router-dom'; +import { isDefined } from 'twenty-shared/utils'; +import { isMatchingLocation } from '~/utils/isMatchingLocation'; + +export const getAuthModalConfig = (location: Location) => { + for (const path of Object.values(AppPath)) { + if ( + isMatchingLocation(location, path) && + isDefined(AUTH_MODAL_CONFIG[path]) + ) { + return AUTH_MODAL_CONFIG[path]; + } + } + + return AUTH_MODAL_CONFIG.default; +}; diff --git a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx index 4fc28b4f7..3840df974 100644 --- a/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx +++ b/packages/twenty-front/src/modules/client-config/components/ClientConfigProviderEffect.tsx @@ -2,6 +2,7 @@ import { useClientConfig } from '@/client-config/hooks/useClientConfig'; import { apiConfigState } from '@/client-config/states/apiConfigState'; import { authProvidersState } from '@/client-config/states/authProvidersState'; import { billingState } from '@/client-config/states/billingState'; +import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; import { canManageFeatureFlagsState } from '@/client-config/states/canManageFeatureFlagsState'; import { captchaState } from '@/client-config/states/captchaState'; import { chromeExtensionIdState } from '@/client-config/states/chromeExtensionIdState'; @@ -85,6 +86,10 @@ export const ClientConfigProviderEffect = () => { isConfigVariablesInDbEnabledState, ); + const setCalendarBookingPageId = useSetRecoilState( + calendarBookingPageIdState, + ); + const { data, loading, error, fetchClientConfig } = useClientConfig(); useEffect(() => { @@ -173,6 +178,8 @@ export const ClientConfigProviderEffect = () => { ...currentStatus, isSaved: true, })); + + setCalendarBookingPageId(data?.clientConfig?.calendarBookingPageId ?? null); }, [ data, loading, @@ -198,6 +205,7 @@ export const ClientConfigProviderEffect = () => { setGoogleCalendarEnabled, setIsAttachmentPreviewEnabled, setIsConfigVariablesInDbEnabled, + setCalendarBookingPageId, ]); return <>; diff --git a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts index 215912cd6..bbdd889d6 100644 --- a/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts +++ b/packages/twenty-front/src/modules/client-config/graphql/queries/getClientConfig.ts @@ -62,6 +62,7 @@ export const GET_CLIENT_CONFIG = gql` isGoogleMessagingEnabled isGoogleCalendarEnabled isConfigVariablesInDbEnabled + calendarBookingPageId } } `; diff --git a/packages/twenty-front/src/modules/client-config/states/calendarBookingPageIdState.ts b/packages/twenty-front/src/modules/client-config/states/calendarBookingPageIdState.ts new file mode 100644 index 000000000..dd0370224 --- /dev/null +++ b/packages/twenty-front/src/modules/client-config/states/calendarBookingPageIdState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui/utilities'; + +export const calendarBookingPageIdState = createState({ + key: 'calendarBookingPageIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/onboarding/constants/BookCallModalId.ts b/packages/twenty-front/src/modules/onboarding/constants/BookCallModalId.ts new file mode 100644 index 000000000..89a10f6fc --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/constants/BookCallModalId.ts @@ -0,0 +1 @@ +export const BOOK_CALL_MODAL_ID = 'book-call-modal'; diff --git a/packages/twenty-front/src/modules/onboarding/graphql/mutations/skipBookOnboardingStep.ts b/packages/twenty-front/src/modules/onboarding/graphql/mutations/skipBookOnboardingStep.ts new file mode 100644 index 000000000..80977103a --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/graphql/mutations/skipBookOnboardingStep.ts @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client'; + +export const SKIP_BOOK_ONBOARDING_STEP = gql` + mutation SkipBookOnboardingStep { + skipBookOnboardingStep { + success + } + } +`; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts index f96ff94d1..218e4b57f 100644 --- a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts +++ b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts @@ -5,12 +5,14 @@ import { CurrentWorkspace, currentWorkspaceState, } from '@/auth/states/currentWorkspaceState'; +import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; import { isDefined } from 'twenty-shared/utils'; import { OnboardingStatus } from '~/generated/graphql'; const getNextOnboardingStatus = ( currentUser: CurrentUser | null, currentWorkspace: CurrentWorkspace | null, + calendarBookingPageId: string | null, ) => { if (currentUser?.onboardingStatus === OnboardingStatus.WORKSPACE_ACTIVATION) { return OnboardingStatus.PROFILE_CREATION; @@ -25,12 +27,21 @@ const getNextOnboardingStatus = ( ) { return OnboardingStatus.INVITE_TEAM; } + if (currentUser?.onboardingStatus === OnboardingStatus.INVITE_TEAM) { + return isDefined(calendarBookingPageId) + ? OnboardingStatus.BOOK_ONBOARDING + : OnboardingStatus.COMPLETED; + } + if (currentUser?.onboardingStatus === OnboardingStatus.BOOK_ONBOARDING) { + return OnboardingStatus.COMPLETED; + } return OnboardingStatus.COMPLETED; }; export const useSetNextOnboardingStatus = () => { const currentUser = useRecoilValue(currentUserState); const currentWorkspace = useRecoilValue(currentWorkspaceState); + const calendarBookingPageId = useRecoilValue(calendarBookingPageIdState); return useRecoilCallback( ({ set }) => @@ -38,6 +49,7 @@ export const useSetNextOnboardingStatus = () => { const nextOnboardingStatus = getNextOnboardingStatus( currentUser, currentWorkspace, + calendarBookingPageId, ); set(currentUserState, (current) => { if (isDefined(current)) { @@ -49,6 +61,6 @@ export const useSetNextOnboardingStatus = () => { return current; }); }, - [currentWorkspace, currentUser], + [currentWorkspace, currentUser, calendarBookingPageId], ); }; diff --git a/packages/twenty-front/src/modules/types/AppPath.ts b/packages/twenty-front/src/modules/types/AppPath.ts index 598d9a17b..09cad691b 100644 --- a/packages/twenty-front/src/modules/types/AppPath.ts +++ b/packages/twenty-front/src/modules/types/AppPath.ts @@ -13,6 +13,8 @@ export enum AppPath { InviteTeam = '/invite-team', PlanRequired = '/plan-required', PlanRequiredSuccess = '/plan-required/payment-success', + BookCallDecision = '/book-call-decision', + BookCall = '/book-call', // Onboarded Index = '/', diff --git a/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx b/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx index 4ca522994..70e7ec939 100644 --- a/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/hooks/__tests__/useShowAuthModal.test.tsx @@ -43,6 +43,8 @@ const testCases = [ { loc: AppPath.InviteTeam, res: true }, { loc: AppPath.PlanRequired, res: true }, { loc: AppPath.PlanRequiredSuccess, res: true }, + { loc: AppPath.BookCallDecision, res: true }, + { loc: AppPath.BookCall, res: true }, { loc: AppPath.Index, res: false }, { loc: AppPath.RecordIndexPage, res: false }, diff --git a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts index 6cc23bda6..3e4e498e1 100644 --- a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts +++ b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts @@ -19,7 +19,9 @@ export const useShowAuthModal = () => { isMatchingLocation(location, AppPath.SignInUp) || isMatchingLocation(location, AppPath.CreateWorkspace) || isMatchingLocation(location, AppPath.PlanRequired) || - isMatchingLocation(location, AppPath.PlanRequiredSuccess) + isMatchingLocation(location, AppPath.PlanRequiredSuccess) || + isMatchingLocation(location, AppPath.BookCallDecision) || + isMatchingLocation(location, AppPath.BookCall) ) { return true; } diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx index 4b4e604aa..ec6df0927 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx @@ -25,11 +25,14 @@ const StyledModalDiv = styled(motion.div)<{ box-shadow: ${({ theme, modalVariant }) => modalVariant === 'primary' ? theme.boxShadow.superHeavy - : theme.boxShadow.strong}; - background: ${({ theme }) => theme.background.primary}; + : modalVariant === 'transparent' + ? 'none' + : theme.boxShadow.strong}; + background: ${({ theme, modalVariant }) => + modalVariant === 'transparent' ? 'transparent' : theme.background.primary}; color: ${({ theme }) => theme.font.color.primary}; - border-radius: ${({ theme, isMobile }) => { - if (isMobile) return `0`; + border-radius: ${({ theme, isMobile, modalVariant }) => { + if (isMobile || modalVariant === 'transparent') return `0`; return theme.border.radius.md; }}; overflow-x: hidden; @@ -123,7 +126,7 @@ const StyledBackDrop = styled(motion.div)<{ }>` align-items: center; background: ${({ theme, modalVariant }) => - modalVariant === 'primary' + modalVariant === 'primary' || modalVariant === 'transparent' ? theme.background.overlayPrimary : modalVariant === 'secondary' ? theme.background.overlaySecondary @@ -177,7 +180,11 @@ const ModalFooter = ({ children, className }: ModalFooterProps) => ( export type ModalSize = 'small' | 'medium' | 'large' | 'extraLarge'; export type ModalPadding = 'none' | 'small' | 'medium' | 'large'; -export type ModalVariants = 'primary' | 'secondary' | 'tertiary'; +export type ModalVariants = + | 'primary' + | 'secondary' + | 'tertiary' + | 'transparent'; export type ModalProps = React.PropsWithChildren & { modalId: string; diff --git a/packages/twenty-front/src/pages/onboarding/BookCall.tsx b/packages/twenty-front/src/pages/onboarding/BookCall.tsx new file mode 100644 index 000000000..87c2172c0 --- /dev/null +++ b/packages/twenty-front/src/pages/onboarding/BookCall.tsx @@ -0,0 +1,86 @@ +import Cal from '@calcom/embed-react'; +import styled from '@emotion/styled'; +import { Link } from 'react-router-dom'; + +import { currentUserState } from '@/auth/states/currentUserState'; +import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; +import { AppPath } from '@/types/AppPath'; +import { Modal } from '@/ui/layout/modal/components/Modal'; +import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; +import { useTheme } from '@emotion/react'; +import { useLingui } from '@lingui/react/macro'; +import { useRecoilValue } from 'recoil'; +import { IconChevronLeft, IconChevronRightPipe } from 'twenty-ui/display'; +import { LightButton } from 'twenty-ui/input'; +import { useIsMobile } from 'twenty-ui/utilities'; +import { + OnboardingStatus, + useSkipBookOnboardingStepMutation, +} from '~/generated/graphql'; + +const StyledModalFooter = styled(Modal.Footer)` + height: auto; + justify-content: center; + padding: ${({ theme }) => theme.spacing(3)}; +`; + +const StyledModalContent = styled(Modal.Content)` + overflow: hidden; + padding: 0; +`; + +const StyledScrollWrapper = styled(ScrollWrapper)<{ isMobile: boolean }>` + ${({ isMobile }) => !isMobile && 'height: auto;'} +`; + +export const BookCall = () => { + const { t } = useLingui(); + const theme = useTheme(); + const calendarBookingPageId = useRecoilValue(calendarBookingPageIdState); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); + const currentUser = useRecoilValue(currentUserState); + const [skipBookOnboardingStepMutation] = useSkipBookOnboardingStepMutation(); + + const isMobile = useIsMobile(); + const isPlanRequired = + currentUser?.onboardingStatus === OnboardingStatus.PLAN_REQUIRED; + + const handleCompleteOnboarding = async () => { + await skipBookOnboardingStepMutation(); + setNextOnboardingStatus(); + }; + + return ( + <> + + + + + + + {isPlanRequired ? ( + + + + ) : ( + + )} + + + ); +}; diff --git a/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx b/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx new file mode 100644 index 000000000..792e9ac10 --- /dev/null +++ b/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx @@ -0,0 +1,74 @@ +import { SubTitle } from '@/auth/components/SubTitle'; +import { Title } from '@/auth/components/Title'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; +import { AppPath } from '@/types/AppPath'; +import { Modal } from '@/ui/layout/modal/components/Modal'; +import styled from '@emotion/styled'; +import { Trans, useLingui } from '@lingui/react/macro'; +import { Link } from 'react-router-dom'; +import { LightButton, MainButton } from 'twenty-ui/input'; +import { useSkipBookOnboardingStepMutation } from '~/generated/graphql'; + +const StyledCoverImage = styled.img` + border-radius: ${({ theme }) => theme.border.radius.sm}; + height: 204px; + object-fit: cover; + width: 320px; +`; + +const StyledModalContent = styled(Modal.Content)` + gap: ${({ theme }) => theme.spacing(8)}; +`; + +const StyledTitleContainer = styled.div` + align-items: center; + display: flex; + flex-direction: column; + justify-content: center; +`; + +const StyledButtonContainer = styled.div` + align-items: center; + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(4)}; + width: 100%; +`; + +const StyledLink = styled(Link)` + text-decoration: none; +`; + +export const BookCallDecision = () => { + const { t } = useLingui(); + const setNextOnboardingStatus = useSetNextOnboardingStatus(); + const [skipBookOnboardingStepMutation] = useSkipBookOnboardingStepMutation(); + + const handleFinish = async () => { + await skipBookOnboardingStepMutation(); + setNextOnboardingStatus(); + }; + + return ( + + + + <Trans>Book your onboarding</Trans> + + + + Our team can help you set up your workspace to match your specific + needs and workflows. + + + + + + + + + + + + ); +}; diff --git a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx index 3d825b54b..c231c85e4 100644 --- a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx +++ b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx @@ -9,6 +9,8 @@ import { TrialCard } from '@/billing/components/TrialCard'; import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession'; import { isBillingPriceLicensed } from '@/billing/utils/isBillingPriceLicensed'; import { billingState } from '@/client-config/states/billingState'; +import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; +import { AppPath } from '@/types/AppPath'; import { Modal } from '@/ui/layout/modal/components/Modal'; import styled from '@emotion/styled'; import { Trans, useLingui } from '@lingui/react/macro'; @@ -97,6 +99,8 @@ export const ChooseYourPlan = () => { billingCheckoutSessionState, ); + const calendarBookingPageId = useRecoilValue(calendarBookingPageIdState); + const [verifyEmailNextPath, setVerifyEmailNextPath] = useRecoilState( verifyEmailNextPathState, ); @@ -250,7 +254,11 @@ export const ChooseYourPlan = () => { Change Plan - + Book a Call diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index 392f9a35d..9bfdfe677 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -1,6 +1,7 @@ import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; @@ -66,9 +67,11 @@ export const InviteTeam = () => { const theme = useTheme(); const { enqueueSnackBar } = useSnackBar(); const { sendInvitation } = useCreateWorkspaceInvitation(); - const setNextOnboardingStatus = useSetNextOnboardingStatus(); const currentWorkspace = useRecoilValue(currentWorkspaceState); + const calendarBookingPageId = useRecoilValue(calendarBookingPageIdState); + const hasCalendarBooking = isDefined(calendarBookingPageId); + const { control, handleSubmit, @@ -136,8 +139,6 @@ export const InviteTeam = () => { ); const result = await sendInvitation({ emails }); - setNextOnboardingStatus(); - if (isDefined(result.errors)) { throw result.errors; } @@ -147,6 +148,8 @@ export const InviteTeam = () => { duration: 2000, }); } + + setNextOnboardingStatus(); }, [enqueueSnackBar, sendInvitation, setNextOnboardingStatus, t], ); @@ -214,7 +217,7 @@ export const InviteTeam = () => { { isGoogleMessagingEnabled: false, isGoogleCalendarEnabled: false, isConfigVariablesInDbEnabled: false, + calendarBookingPageId: undefined, }; jest diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts index 3ea904dc3..6a179fdca 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts @@ -147,4 +147,7 @@ export class ClientConfig { @Field(() => Boolean) isConfigVariablesInDbEnabled: boolean; + + @Field(() => String, { nullable: true }) + calendarBookingPageId?: string; } diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts index f764f94f2..9f3fa0b24 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts @@ -78,6 +78,7 @@ describe('ClientConfigService', () => { MESSAGING_PROVIDER_GMAIL_ENABLED: true, CALENDAR_PROVIDER_GOOGLE_ENABLED: true, IS_CONFIG_VARIABLES_IN_DB_ENABLED: false, + CALENDAR_BOOKING_PAGE_ID: 'team/twenty/talk-to-us', }; return mockValues[key]; @@ -145,6 +146,7 @@ describe('ClientConfigService', () => { isGoogleMessagingEnabled: true, isGoogleCalendarEnabled: true, isConfigVariablesInDbEnabled: false, + calendarBookingPageId: 'team/twenty/talk-to-us', }); }); diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts index 4af6aa7bb..88c883ebf 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts @@ -102,6 +102,9 @@ export class ClientConfigService { isConfigVariablesInDbEnabled: this.twentyConfigService.get( 'IS_CONFIG_VARIABLES_IN_DB_ENABLED', ), + calendarBookingPageId: this.twentyConfigService.get( + 'CALENDAR_BOOKING_PAGE_ID', + ), }; return clientConfig; diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts b/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts index 8370714f2..dd4370a52 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/enums/onboarding-status.enum.ts @@ -4,5 +4,6 @@ export enum OnboardingStatus { PROFILE_CREATION = 'PROFILE_CREATION', SYNC_EMAIL = 'SYNC_EMAIL', INVITE_TEAM = 'INVITE_TEAM', + BOOK_ONBOARDING = 'BOOK_ONBOARDING', COMPLETED = 'COMPLETED', } diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts index d61c41472..46c4856d5 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts @@ -28,4 +28,16 @@ export class OnboardingResolver { return { success: true }; } + + @Mutation(() => OnboardingStepSuccess) + async skipBookOnboardingStep( + @AuthWorkspace() workspace: Workspace, + ): Promise { + await this.onboardingService.setOnboardingBookOnboardingPending({ + workspaceId: workspace.id, + value: false, + }); + + return { success: true }; + } } diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts index 3e4ab92e9..8f1f54af7 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts @@ -12,12 +12,14 @@ export enum OnboardingStepKeys { ONBOARDING_CONNECT_ACCOUNT_PENDING = 'ONBOARDING_CONNECT_ACCOUNT_PENDING', ONBOARDING_INVITE_TEAM_PENDING = 'ONBOARDING_INVITE_TEAM_PENDING', ONBOARDING_CREATE_PROFILE_PENDING = 'ONBOARDING_CREATE_PROFILE_PENDING', + ONBOARDING_BOOK_ONBOARDING_PENDING = 'ONBOARDING_BOOK_ONBOARDING_PENDING', } export type OnboardingKeyValueTypeMap = { [OnboardingStepKeys.ONBOARDING_CONNECT_ACCOUNT_PENDING]: boolean; [OnboardingStepKeys.ONBOARDING_INVITE_TEAM_PENDING]: boolean; [OnboardingStepKeys.ONBOARDING_CREATE_PROFILE_PENDING]: boolean; + [OnboardingStepKeys.ONBOARDING_BOOK_ONBOARDING_PENDING]: boolean; }; @Injectable() @@ -62,6 +64,10 @@ export class OnboardingService { const isInviteTeamPending = userVars.get(OnboardingStepKeys.ONBOARDING_INVITE_TEAM_PENDING) === true; + const isBookOnboardingPending = + userVars.get(OnboardingStepKeys.ONBOARDING_BOOK_ONBOARDING_PENDING) === + true; + if (isProfileCreationPending) { return OnboardingStatus.PROFILE_CREATION; } @@ -74,6 +80,10 @@ export class OnboardingService { return OnboardingStatus.INVITE_TEAM; } + if (isBookOnboardingPending) { + return OnboardingStatus.BOOK_ONBOARDING; + } + return OnboardingStatus.COMPLETED; } @@ -153,4 +163,27 @@ export class OnboardingService { value: true, }); } + + async setOnboardingBookOnboardingPending({ + workspaceId, + value, + }: { + workspaceId: string; + value: boolean; + }) { + if (!value) { + await this.userVarsService.delete({ + workspaceId, + key: OnboardingStepKeys.ONBOARDING_BOOK_ONBOARDING_PENDING, + }); + + return; + } + + await this.userVarsService.set({ + workspaceId, + key: OnboardingStepKeys.ONBOARDING_BOOK_ONBOARDING_PENDING, + value: true, + }); + } } diff --git a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts index 7e46956d8..4c851638f 100644 --- a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts +++ b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts @@ -630,6 +630,14 @@ export class ConfigVariables { @IsOptional() CHROME_EXTENSION_ID: string; + @ConfigVariablesMetadata({ + group: ConfigVariablesGroup.Other, + description: 'Page ID for Cal.com booking integration', + type: ConfigVariableType.STRING, + }) + @IsOptional() + CALENDAR_BOOKING_PAGE_ID?: string; + @ConfigVariablesMetadata({ group: ConfigVariablesGroup.Logging, description: 'Enable or disable buffering for logs before sending', diff --git a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts index 78a4d17fd..0e9dbc968 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.spec.ts @@ -70,6 +70,7 @@ describe('WorkspaceInvitationService', () => { provide: OnboardingService, useValue: { setOnboardingInviteTeamPending: jest.fn(), + setOnboardingBookOnboardingPending: jest.fn(), }, }, { @@ -181,6 +182,12 @@ describe('WorkspaceInvitationService', () => { workspaceId: workspace.id, value: false, }); + expect( + onboardingService.setOnboardingBookOnboardingPending, + ).toHaveBeenCalledWith({ + workspaceId: workspace.id, + value: true, + }); }); }); }); diff --git a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts index d0c8f7c84..6292e09fb 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace-invitation/services/workspace-invitation.service.ts @@ -324,6 +324,11 @@ export class WorkspaceInvitationService { value: false, }); + await this.onboardingService.setOnboardingBookOnboardingPending({ + workspaceId: workspace.id, + value: true, + }); + const result = invitationsPr.reduce<{ errors: string[]; result: ReturnType< diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index 03fd5e31c..83870d2a1 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -4,18 +4,18 @@ export { IconAlertCircle, IconAlertTriangle, IconApi, - IconAppWindow, IconApps, + IconAppWindow, IconArchive, IconArchiveOff, IconArrowBackUp, IconArrowDown, IconArrowLeft, IconArrowRight, - IconArrowUp, - IconArrowUpRight, IconArrowsDiagonal, IconArrowsVertical, + IconArrowUp, + IconArrowUpRight, IconAt, IconBaselineDensitySmall, IconBell, @@ -47,8 +47,9 @@ export { IconChevronDown, IconChevronLeft, IconChevronRight, - IconChevronUp, + IconChevronRightPipe, IconChevronsRight, + IconChevronUp, IconCircleDot, IconCircleOff, IconCirclePlus, diff --git a/packages/twenty-ui/src/display/index.ts b/packages/twenty-ui/src/display/index.ts index c547b740e..fc5b9f2c9 100644 --- a/packages/twenty-ui/src/display/index.ts +++ b/packages/twenty-ui/src/display/index.ts @@ -66,18 +66,18 @@ export { IconAlertCircle, IconAlertTriangle, IconApi, - IconAppWindow, IconApps, + IconAppWindow, IconArchive, IconArchiveOff, IconArrowBackUp, IconArrowDown, IconArrowLeft, IconArrowRight, - IconArrowUp, - IconArrowUpRight, IconArrowsDiagonal, IconArrowsVertical, + IconArrowUp, + IconArrowUpRight, IconAt, IconBaselineDensitySmall, IconBell, @@ -109,8 +109,9 @@ export { IconChevronDown, IconChevronLeft, IconChevronRight, - IconChevronUp, + IconChevronRightPipe, IconChevronsRight, + IconChevronUp, IconCircleDot, IconCircleOff, IconCirclePlus, diff --git a/yarn.lock b/yarn.lock index 7ff26f2d6..06bdf67f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4814,6 +4814,35 @@ __metadata: languageName: node linkType: hard +"@calcom/embed-core@npm:1.5.3": + version: 1.5.3 + resolution: "@calcom/embed-core@npm:1.5.3" + checksum: 10c0/85d2a17800dc685c75670a24ddc650eabac571001067640f2715aa7e9ffdad5fb36fc4c5f33c6d00bf6937ae6997a3beb45cd0d3cc96754fc1b3171ea888d796 + languageName: node + linkType: hard + +"@calcom/embed-react@npm:^1.5.3": + version: 1.5.3 + resolution: "@calcom/embed-react@npm:1.5.3" + dependencies: + "@calcom/embed-core": "npm:1.5.3" + "@calcom/embed-snippet": "npm:1.3.3" + peerDependencies: + react: ^18.2.0 || ^19.0.0 + react-dom: ^18.2.0 || ^19.0.0 + checksum: 10c0/aa42bbd96b2d7b16dc2b582cdc6e13ea5015b91fa8e6f680f554e56d562f64e783df74eac50b028543827b3a8d62307fde37cad19f574b7ff7bc3bab8cf52dfe + languageName: node + linkType: hard + +"@calcom/embed-snippet@npm:1.3.3": + version: 1.3.3 + resolution: "@calcom/embed-snippet@npm:1.3.3" + dependencies: + "@calcom/embed-core": "npm:1.5.3" + checksum: 10c0/2488d33f23aa1495004803b6f8f3bba7f3aad2bd2b951aaffb9891c27250aed48fa7deb251cf4cf65e4e8c1f12c07c70eb5e6ab6706455fa71b8208fe53dfd53 + languageName: node + linkType: hard + "@clickhouse/client-common@npm:1.11.0": version: 1.11.0 resolution: "@clickhouse/client-common@npm:1.11.0" @@ -56654,6 +56683,7 @@ __metadata: "@babel/core": "npm:^7.14.5" "@babel/preset-react": "npm:^7.14.5" "@babel/preset-typescript": "npm:^7.24.6" + "@calcom/embed-react": "npm:^1.5.3" "@codesandbox/sandpack-react": "npm:^2.13.5" "@crxjs/vite-plugin": "npm:^1.0.14" "@dagrejs/dagre": "npm:^1.1.2"