Files
twenty/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts
T
Raphaël Bosi db7d8172f7 Add v2 onboarding invite team page (#22229)
<img width="3024" height="1500" alt="CleanShot 2026-06-26 at 18 09
47@2x"
src="https://github.com/user-attachments/assets/e91f30a5-2763-42a0-9abf-d9fa8400870c"
/>


Adds the v2 onboarding **Invite team** page (`INVITE_TEAM`), shown right
after the create-profile step for the onboarding-v2 cohort. It renders
full-screen under `BlankLayout` via the shared `OnboardingV2Layout`,
matching the Figma (340px column, email inputs with inline remove, dark
Invite, Skip).

Reuses all v1 invite-team logic via a new `useInviteTeam` hook (v1
`InviteTeam` now consumes it too; its UI is unchanged). Routing mirrors
`SyncEmailsV2`/`CreateProfileV2`: new `AppPath.InviteTeamV2`, lazy
route, and an `isOnboardingV2`-gated branch in
`usePageChangeEffectNavigateLocation` (+ tests and a Storybook story).

No backend changes.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22229?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-29 13:53:07 +02:00

266 lines
10 KiB
TypeScript

import { aiModelsState } from '@/client-config/states/aiModelsState';
import { apiConfigState } from '@/client-config/states/apiConfigState';
import { onboardingConfigState } from '@/client-config/states/onboardingConfigState';
import { appVersionState } from '@/client-config/states/appVersionState';
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 { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState';
import { isConfigVariablesInDbEnabledState } from '@/client-config/states/isConfigVariablesInDbEnabledState';
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
import { isClickHouseConfiguredState } from '@/client-config/states/isClickHouseConfiguredState';
import { isCloudflareIntegrationEnabledState } from '@/client-config/states/isCloudflareIntegrationEnabledState';
import { isDDLLockedState } from '@/client-config/states/isDDLLockedState';
import { isEmailingDomainInDemoModeState } from '@/client-config/states/isEmailingDomainInDemoModeState';
import { isEmailVerificationRequiredState } from '@/client-config/states/isEmailVerificationRequiredState';
import { isGoogleCalendarEnabledState } from '@/client-config/states/isGoogleCalendarEnabledState';
import { isGoogleMessagingEnabledState } from '@/client-config/states/isGoogleMessagingEnabledState';
import { isImapSmtpCaldavEnabledState } from '@/client-config/states/isImapSmtpCaldavEnabledState';
import { maintenanceModeState } from '@/client-config/states/maintenanceModeState';
import { isMicrosoftCalendarEnabledState } from '@/client-config/states/isMicrosoftCalendarEnabledState';
import { isMicrosoftMessagingEnabledState } from '@/client-config/states/isMicrosoftMessagingEnabledState';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState';
import { sentryConfigState } from '@/client-config/states/sentryConfigState';
import { supportChatState } from '@/client-config/states/supportChatState';
import { type ClientConfig } from '@/client-config/types/ClientConfig';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { useCallback } from 'react';
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
import { getClientConfig } from '@/client-config/utils/getClientConfig';
import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
type UseClientConfigResult = {
data: { clientConfig: ClientConfig } | undefined;
loading: boolean;
error: Error | undefined;
fetchClientConfig: () => Promise<void>;
refetch: () => Promise<void>;
};
export const useClientConfig = (): UseClientConfigResult => {
const setIsAnalyticsEnabled = useSetAtomState(isAnalyticsEnabledState);
const setDomainConfiguration = useSetAtomState(domainConfigurationState);
const setAuthProviders = useSetAtomState(authProvidersState);
const setAiModels = useSetAtomState(aiModelsState);
const setIsDeveloperDefaultSignInPrefilled = useSetAtomState(
isDeveloperDefaultSignInPrefilledState,
);
const setIsMultiWorkspaceEnabled = useSetAtomState(
isMultiWorkspaceEnabledState,
);
const setIsEmailVerificationRequired = useSetAtomState(
isEmailVerificationRequiredState,
);
const setBilling = useSetAtomState(billingState);
const setSupportChat = useSetAtomState(supportChatState);
const setSentryConfig = useSetAtomState(sentryConfigState);
const [clientConfigApiStatus, setClientConfigApiStatus] = useAtomState(
clientConfigApiStatusState,
);
const setCaptcha = useSetAtomState(captchaState);
const setApiConfig = useSetAtomState(apiConfigState);
const setOnboardingConfig = useSetAtomState(onboardingConfigState);
const setCanManageFeatureFlags = useSetAtomState(canManageFeatureFlagsState);
const setLabPublicFeatureFlags = useSetAtomState(labPublicFeatureFlagsState);
const setIsMicrosoftMessagingEnabled = useSetAtomState(
isMicrosoftMessagingEnabledState,
);
const setIsMicrosoftCalendarEnabled = useSetAtomState(
isMicrosoftCalendarEnabledState,
);
const setIsGoogleMessagingEnabled = useSetAtomState(
isGoogleMessagingEnabledState,
);
const setIsGoogleCalendarEnabled = useSetAtomState(
isGoogleCalendarEnabledState,
);
const setIsAttachmentPreviewEnabled = useSetAtomState(
isAttachmentPreviewEnabledState,
);
const setIsConfigVariablesInDbEnabled = useSetAtomState(
isConfigVariablesInDbEnabledState,
);
const setCalendarBookingPageId = useSetAtomState(calendarBookingPageIdState);
const setIsEmailingDomainInDemoMode = useSetAtomState(
isEmailingDomainInDemoModeState,
);
const setIsImapSmtpCaldavEnabled = useSetAtomState(
isImapSmtpCaldavEnabledState,
);
const setAllowRequestsToTwentyIcons = useSetAtomState(
allowRequestsToTwentyIconsState,
);
const setIsCloudflareIntegrationEnabled = useSetAtomState(
isCloudflareIntegrationEnabledState,
);
const setIsClickHouseConfigured = useSetAtomState(
isClickHouseConfiguredState,
);
const setIsDDLLocked = useSetAtomState(isDDLLockedState);
const setMaintenanceMode = useSetAtomState(maintenanceModeState);
const setAppVersion = useSetAtomState(appVersionState);
const fetchClientConfig = useCallback(async () => {
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: true,
}));
try {
const clientConfig = await getClientConfig();
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: false,
isLoadedOnce: true,
isErrored: false,
error: undefined,
data: { clientConfig },
}));
setClientConfigApiStatus((currentStatus) => ({
...currentStatus,
isErrored: false,
error: undefined,
}));
setAppVersion(clientConfig.appVersion);
setAuthProviders({
google: clientConfig.authProviders.google,
microsoft: clientConfig.authProviders.microsoft,
password: clientConfig.authProviders.password,
magicLink: false,
sso: clientConfig.authProviders.sso,
});
setAiModels(clientConfig.aiModels ?? []);
setIsAnalyticsEnabled(clientConfig.analyticsEnabled);
setIsDeveloperDefaultSignInPrefilled(clientConfig.signInPrefilled);
setIsMultiWorkspaceEnabled(clientConfig.isMultiWorkspaceEnabled);
setIsEmailVerificationRequired(clientConfig.isEmailVerificationRequired);
setBilling(clientConfig.billing);
setSupportChat(clientConfig.support);
setSentryConfig({
dsn: clientConfig?.sentry?.dsn,
release: clientConfig?.sentry?.release,
environment: clientConfig?.sentry?.environment,
});
setCaptcha({
provider: clientConfig?.captcha?.provider,
siteKey: clientConfig?.captcha?.siteKey,
});
setApiConfig(clientConfig?.api);
setOnboardingConfig(clientConfig?.onboarding);
setDomainConfiguration({
defaultSubdomain: clientConfig?.defaultSubdomain,
frontDomain: clientConfig?.frontDomain,
publicFunctionDomain: clientConfig?.publicFunctionDomain,
});
setCanManageFeatureFlags(clientConfig?.canManageFeatureFlags);
setLabPublicFeatureFlags(clientConfig?.publicFeatureFlags);
setIsMicrosoftMessagingEnabled(clientConfig?.isMicrosoftMessagingEnabled);
setIsMicrosoftCalendarEnabled(clientConfig?.isMicrosoftCalendarEnabled);
setIsGoogleMessagingEnabled(clientConfig?.isGoogleMessagingEnabled);
setIsGoogleCalendarEnabled(clientConfig?.isGoogleCalendarEnabled);
setIsAttachmentPreviewEnabled(clientConfig?.isAttachmentPreviewEnabled);
setIsConfigVariablesInDbEnabled(
clientConfig?.isConfigVariablesInDbEnabled,
);
setClientConfigApiStatus((currentStatus) => ({
...currentStatus,
isSaved: true,
}));
setCalendarBookingPageId(clientConfig?.calendarBookingPageId ?? null);
setIsImapSmtpCaldavEnabled(clientConfig?.isImapSmtpCaldavEnabled);
setIsEmailingDomainInDemoMode(
clientConfig?.isEmailingDomainInDemoMode ?? false,
);
setAllowRequestsToTwentyIcons(clientConfig?.allowRequestsToTwentyIcons);
setIsCloudflareIntegrationEnabled(
clientConfig?.isCloudflareIntegrationEnabled,
);
setIsClickHouseConfigured(clientConfig?.isClickHouseConfigured ?? false);
setIsDDLLocked(clientConfig?.isWorkspaceSchemaDDLLocked ?? false);
setMaintenanceMode(clientConfig?.maintenance ?? null);
} catch (err) {
const error =
err instanceof Error ? err : new Error('Failed to fetch client config');
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: false,
isLoadedOnce: true,
isErrored: true,
error,
}));
}
}, [
setAiModels,
setApiConfig,
setOnboardingConfig,
setAppVersion,
setAuthProviders,
setBilling,
setCalendarBookingPageId,
setCanManageFeatureFlags,
setCaptcha,
setClientConfigApiStatus,
setDomainConfiguration,
setIsGoogleCalendarEnabled,
setIsGoogleMessagingEnabled,
setIsAnalyticsEnabled,
setIsAttachmentPreviewEnabled,
setIsConfigVariablesInDbEnabled,
setIsDeveloperDefaultSignInPrefilled,
setIsEmailVerificationRequired,
setIsImapSmtpCaldavEnabled,
setIsMultiWorkspaceEnabled,
setIsEmailingDomainInDemoMode,
setIsClickHouseConfigured,
setIsCloudflareIntegrationEnabled,
setIsDDLLocked,
setLabPublicFeatureFlags,
setMaintenanceMode,
setIsMicrosoftCalendarEnabled,
setIsMicrosoftMessagingEnabled,
setSentryConfig,
setSupportChat,
setAllowRequestsToTwentyIcons,
]);
return {
data: clientConfigApiStatus.data,
loading: clientConfigApiStatus.isLoading || false,
error: clientConfigApiStatus.error,
fetchClientConfig,
refetch: fetchClientConfig,
};
};