Fix onboarding flow: workspace creation modal and invite team skip (#18577)

## Summary

- **Fix create-profile modal not showing after workspace creation**:
After activating a workspace, `CreateWorkspace.onSubmit` called
`refreshObjectMetadataItems()` which only updated the
`objectMetadataItemsState` atom but never marked the metadata store as
ready (`metadataStoreState` stayed at `'empty'`). Since `MetadataGater`
excludes `CreateWorkspace` but not `CreateProfile` from its loading
check, navigating to `/create/profile` triggered the skeleton loader
instead of the modal. The fix adds the full metadata pipeline after
refresh — `updateDraft('objectMetadataItems')` + `applyChanges()` for
objects, and `fetchAndLoadIndexViews()` for views — so
`isAppMetadataReady` is `true` before navigation.

- **Fix invite-team "Skip" not persisting to server**: Clicking "Skip"
on the invite-team page called `setNextOnboardingStatus()` which only
updated the local Jotai atom. The early return for empty emails bypassed
`sendInvitation`, so the server never cleared the
`ONBOARDING_INVITE_TEAM_PENDING` user var. On page refresh,
`GetCurrentUser` returned `INVITE_TEAM` and the user was stuck. The fix
removes the early return so `sendInvitation({ emails: [] })` always runs
— the server handles empty arrays fine and clears the pending flag.
This commit is contained in:
Charles Bochet
2026-03-12 13:15:05 +01:00
committed by GitHub
parent e8f8189167
commit 660536d6bb
2 changed files with 19 additions and 6 deletions
@@ -9,7 +9,10 @@ import { Logo } from '@/auth/components/Logo';
import { SubTitle } from '@/auth/components/SubTitle';
import { Title } from '@/auth/components/Title';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useFetchAndLoadIndexViews } from '@/metadata-store/hooks/useFetchAndLoadIndexViews';
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
@@ -19,6 +22,7 @@ import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser';
import { ApolloError } from '@apollo/client';
import { Trans, useLingui } from '@lingui/react/macro';
import { isNonEmptyString } from '@sniptt/guards';
import { useStore } from 'jotai';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { isDefined } from 'twenty-shared/utils';
import { H2Title } from 'twenty-ui/display';
@@ -68,6 +72,9 @@ export const CreateWorkspace = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const setNextOnboardingStatus = useSetNextOnboardingStatus();
const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems();
const { updateDraft, applyChanges } = useMetadataStore();
const { fetchAndLoadIndexViews } = useFetchAndLoadIndexViews();
const store = useStore();
const { loadCurrentUser } = useLoadCurrentUser();
const [activateWorkspace] = useActivateWorkspaceMutation();
@@ -117,12 +124,18 @@ export const CreateWorkspace = () => {
},
},
});
if (isDefined(result.errors)) {
throw result.errors ?? new Error(t`Unknown error`);
}
await refreshObjectMetadataItems();
const loadedObjects = store.get(objectMetadataItemsState.atom);
updateDraft('objectMetadataItems', loadedObjects);
applyChanges();
await fetchAndLoadIndexViews();
await loadCurrentUser();
setNextOnboardingStatus();
} catch (error: any) {
@@ -138,6 +151,10 @@ export const CreateWorkspace = () => {
enqueueErrorSnackBar,
loadCurrentUser,
refreshObjectMetadataItems,
updateDraft,
applyChanges,
store,
fetchAndLoadIndexViews,
setNextOnboardingStatus,
t,
],
@@ -131,16 +131,12 @@ export const InviteTeam = () => {
),
);
if (emails.length === 0) {
setNextOnboardingStatus();
return;
}
const result = await sendInvitation({ emails });
if (isDefined(result.errors)) {
throw result.errors;
}
if (emails.length > 0) {
enqueueSuccessSnackBar({
message: t`Invite link sent to email addresses`,