44ed0d5498de78df737510bdcdd0e13483be0cb7
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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. --> |
||
|
|
dd57842187 |
Show the onboarding welcome animation on sign-up only (#23057)
The welcome overlay replayed for existing users signing in, because it had no signal for "this user just signed up" and inferred it from a coincidence: a COMPLETED user standing on an onboarding URL while being redirected away. This drops that inference and triggers explicitly at the only two places onboarding reaches COMPLETED: `useSetNextOnboardingStatus` and the Stripe return. |
||
|
|
6201d06141 |
Preload Stripe.js before the onboarding payment step (#22858)
## Context On the plan-required onboarding step, the card form was slow to appear because Stripe.js is loaded lazily (`@stripe/stripe-js/pure`): the script download only started once the payment page rendered, and the PaymentElement iframe could only boot after that. ## What this does - Adds `usePreloadStripeForPlanRequiredStep`, called once from `OnboardingStepLayout` (the shared layout for the authenticated onboarding step routes), so Stripe.js is already loaded by the time the user reaches the payment step. The hook only triggers when billing is enabled, the workspace has no subscription yet, and a publishable key is configured, so self-hosted instances still never contact Stripe. - Moves the memoized loader to `settings/billing/utils/getStripePromise.ts`, shared by `useStripePromise` and the preload hook. - Stops caching failed script loads: previously a rejected `loadStripe` promise stayed in the cache forever, which would have made a failed preload permanently break the payment form. Now a later call retries (stripe-js re-injects the script tag on retry). - Extracts the plan-required predicate into `onboarding/utils/getIsPlanRequired.ts`, now shared with `useSetNextOnboardingStatus`. The in-app add-credit-card modal is intentionally left untouched: it has no preceding step to preload from. ## Tests - `getStripePromise.test.ts`: dedup per publishable key, retry after a failed load. - `usePreloadStripeForPlanRequiredStep.test.ts`: preloads when billing is enabled and no subscription exists; skips when billing is disabled, a subscription exists, or the key is missing. --- _Generated by [Claude Code](https://claude.ai/code/session_01NtUN99tHPZ6bPWwpYKMbpE)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22858?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. --> |
||
|
|
e38d587602 |
Welcome animation when a workspace is set up (#22622)
## Desktop https://github.com/user-attachments/assets/87999ff5-9257-4fed-90e0-781322b1db98 ## Mobile https://github.com/user-attachments/assets/0d115cb6-7bca-4229-8fde-0f188e862b00 Greets the user the moment they finish onboarding: a halftone Twenty mark (brand purple) assembles from scattered particles, shimmers, then bursts outward to reveal the freshly loaded workspace behind it. Plays once, ~3s, with a reduced-motion fallback. `PageChangeEffect` sets a transient `isWelcomeAnimationVisibleState` atom at the onboarding to workspace redirect seam (gated by `shouldShowWelcomeAnimationOnNavigate`); `WelcomeOverlay`, mounted in `WorkspaceAppProviders`, plays it and clears it. Transient by design, so it never replays on reload. ## Why a canvas rendered on another thread The overlay plays at the exact moment the workspace mounts behind it, which is one of the heaviest main-thread stretches in the app (metadata, providers, first data fetch). Anything animating on the main thread competes with that work: - framer-motion and plain main-thread `requestAnimationFrame` visibly stuttered and froze during the mount, because long tasks starve rAF. - CSS keyframes stay smooth (they run on the compositor), but can't drive a ~2900-particle halftone with per-particle physics (staggered assemble, moving shimmer band, directional burst). So the halftone runs as a Canvas 2D particle system inside a Web Worker, drawing to an `OffscreenCanvas` transferred from the main thread. The whole render loop lives off the main thread, so app-mount jank can't reach it. A main-thread path is kept as a fallback for browsers without `OffscreenCanvas` / `transferControlToOffscreen`, and Safari workers (which lack rAF) fall back to a fixed-interval loop. The renderer is a pure, DOM-free module so it bundles cleanly into the worker; dot colors come from CSS vars read on the main thread and passed in. Also fires for every onboarding completion path and skips the billing `PlanRequired` detour. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22622?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. --> |