Files
twenty/packages/twenty-front/src/modules/onboarding/components/WorkspaceSetupHeader.tsx
T
Raphaël Bosi f5a9adcb76 Add post-onboarding AI chat setup behind a feature flag (#23120)
https://github.com/user-attachments/assets/fec7076f-4e46-4c39-84d7-68e4340244ac



After finishing onboarding, users now land in a full-screen AI chat that
helps them set up their workspace, instead of going straight to their
default view. The welcome overlay's title flies into the chat's first
message so the handoff reads as one continuous motion: the slide plays
alone, the title swaps in place pixel-exactly (a regular-weight clone of
the target line is crossfaded in mid-flight to morph the font weight),
then the rest of the text fades in.

All of it sits behind `IS_ONBOARDING_AI_CHAT_ENABLED` (default off, not
registered as a public flag). With the flag off, onboarding behaves
exactly as it does today — the welcome overlay still plays and the user
lands on their home view.

Layout follows the Figma: the nav drawer stays visible and the chat
renders in a panel-styled container with an "Onboarding" header,
matching the expanded side panel.

Also fixes two pre-existing bugs the feature surfaced:
- On billing instances the completion redirect raced the lazy
`PaymentSuccess` page, which silently skipped the welcome animation on
the no-card trial path. The redirect now defers while a checkout is
pending, and `PaymentSuccess` always confirms through
`useLoadCurrentUser` so freshly served feature flags are respected.
- `useDefaultHomePagePath` could conclude its `/settings/profile`
empty-workspace fallback from a transiently empty metadata store and
strand the user there; it now waits for both object metadata and
navigation menu items before deciding.

Reviewer notes:
- `AgentChatRuntimeEffects` no longer keys off side-panel state, so
`modules/ai` stops importing `modules/side-panel`. The two
visibility-scoped effects moved into `AiChatTab`.
- `/workspace-setup` is deliberately URL-addressable rather than
onboarding-only: the collapse control in the header is a general
expand/collapse toggle (paired with a new expand button in the side
panel top bar), and gating the route would break refresh and
browser-back. It is still authenticated-only.
- The design's second, LLM-authored paragraph is not implemented —
starting an assistant turn with no user message needs server-side work.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23120?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-07-23 12:16:11 +02:00

48 lines
1.5 KiB
TypeScript

import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AiChatCloseButton } from '@/ai/components/AiChatCloseButton';
import { AiChatCollapseButton } from '@/ai/components/AiChatCollapseButton';
import { SIDE_PANEL_TOP_BAR_HEIGHT } from '@/side-panel/constants/SidePanelTopBarHeight';
const StyledHeader = styled.header`
align-items: center;
background-color: ${themeCssVariables.background.secondary};
border-bottom: 1px solid ${themeCssVariables.border.color.light};
box-sizing: border-box;
display: flex;
flex-shrink: 0;
gap: ${themeCssVariables.spacing['0.5']};
height: ${SIDE_PANEL_TOP_BAR_HEIGHT}px;
padding: 0 ${themeCssVariables.spacing[2]};
`;
const StyledHeaderTitle = styled.div`
align-items: center;
border-radius: ${themeCssVariables.border.radius.sm};
color: ${themeCssVariables.font.color.primary};
display: flex;
flex: 1;
font-size: ${themeCssVariables.font.size.md};
font-weight: ${themeCssVariables.font.weight.semiBold};
height: ${themeCssVariables.spacing[6]};
line-height: 1.4;
min-width: 0;
overflow: hidden;
padding: 0 ${themeCssVariables.spacing[1]};
text-overflow: ellipsis;
white-space: nowrap;
`;
type WorkspaceSetupHeaderProps = {
title: string;
};
export const WorkspaceSetupHeader = ({ title }: WorkspaceSetupHeaderProps) => (
<StyledHeader>
<StyledHeaderTitle>{title}</StyledHeaderTitle>
<AiChatCollapseButton />
<AiChatCloseButton />
</StyledHeader>
);