From f33a2d868fce5e2d2faffa30fb4124f3ee57edf3 Mon Sep 17 00:00:00 2001 From: Tsahi Matsliah Date: Mon, 20 Apr 2026 17:18:49 +0300 Subject: [PATCH 1/6] feat(webapp): streamline onboarding v2 landing layout and hero Made-with: Cursor --- .../components/onboarding/OnboardingV2.tsx | 432 ++++-------------- 1 file changed, 89 insertions(+), 343 deletions(-) diff --git a/packages/webapp/components/onboarding/OnboardingV2.tsx b/packages/webapp/components/onboarding/OnboardingV2.tsx index 85ebd26435..22c2b64cb7 100644 --- a/packages/webapp/components/onboarding/OnboardingV2.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2.tsx @@ -52,11 +52,6 @@ import { import { ChromeIcon } from '@dailydotdev/shared/src/components/icons/Browser/Chrome'; import { MagicIcon } from '@dailydotdev/shared/src/components/icons/Magic'; -import { TerminalIcon } from '@dailydotdev/shared/src/components/icons/Terminal'; -import { HomeIcon } from '@dailydotdev/shared/src/components/icons/Home'; -import { HotIcon } from '@dailydotdev/shared/src/components/icons/Hot'; -import { EyeIcon } from '@dailydotdev/shared/src/components/icons/Eye'; -import { SquadIcon } from '@dailydotdev/shared/src/components/icons/Squad'; import { VIcon } from '@dailydotdev/shared/src/components/icons/V'; import { StarIcon } from '@dailydotdev/shared/src/components/icons/Star'; import { IconSize } from '@dailydotdev/shared/src/components/Icon'; @@ -87,74 +82,6 @@ import { OnboardingV2Styles } from './OnboardingV2Styles'; import { useOnboardingAnimations } from './useOnboardingAnimations'; import { OnboardingChooserGrid } from './OnboardingChooserGrid'; -type RisingTag = { - label: string; - left: string; - delay: string; - duration: string; - driftX: number; -}; - -const RISING_TAGS_DESKTOP: RisingTag[] = [ - { label: 'React', left: '8%', delay: '0s', duration: '14s', driftX: 12 }, - { label: 'AI & ML', left: '28%', delay: '1.2s', duration: '15s', driftX: -8 }, - { - label: 'System Design', - left: '52%', - delay: '0.6s', - duration: '14.5s', - driftX: 10, - }, - { label: 'Docker', left: '78%', delay: '2s', duration: '13.8s', driftX: -14 }, - { - label: 'TypeScript', - left: '18%', - delay: '3.4s', - duration: '15.2s', - driftX: 8, - }, - { - label: 'Next.js', - left: '88%', - delay: '2.8s', - duration: '14.4s', - driftX: -10, - }, - { - label: 'Python', - left: '42%', - delay: '4.2s', - duration: '14.8s', - driftX: -6, - }, - { - label: 'Kubernetes', - left: '66%', - delay: '5s', - duration: '14.2s', - driftX: 12, - }, -]; - -const RISING_TAGS_MOBILE: RisingTag[] = [ - { label: 'React', left: '10%', delay: '0s', duration: '13.5s', driftX: 8 }, - { - label: 'AI & ML', - left: '55%', - delay: '1.5s', - duration: '14s', - driftX: -10, - }, - { label: 'Docker', left: '30%', delay: '3s', duration: '13s', driftX: 6 }, - { - label: 'TypeScript', - left: '75%', - delay: '4.5s', - duration: '14.5s', - driftX: -8, - }, -]; - export type OnboardingStep = | 'hero' | 'prompt' @@ -253,7 +180,6 @@ export const OnboardingV2 = (): ReactElement => { const [showMobileAppPopup, setShowMobileAppPopup] = useState(false); const { mounted, - tagsReady, feedVisible, heroRef, confettiParticles, @@ -295,14 +221,6 @@ export const OnboardingV2 = (): ReactElement => { [], ); - const openSignup = useCallback( - (context: 'github' | 'ai') => { - setSignupContext(context); - setStep('prompt'); - }, - [setSignupContext], - ); - const clearImportTimers = useCallback(() => { importTimersRef.current.forEach(clearTimeout); importTimersRef.current = []; @@ -715,10 +633,25 @@ export const OnboardingV2 = (): ReactElement => { }; }, [importBodyPhase]); + useEffect(() => { + if (step !== 'hero') { + return undefined; + } + const { style } = document.body; + const prev = style.overflow; + style.overflow = 'hidden'; + return () => { + style.overflow = prev; + }; + }, [step]); + return (
@@ -752,46 +685,18 @@ export const OnboardingV2 = (): ReactElement => { )} - {/* ── Dummy Sidebar (laptop only) ── */} - - {/* ── Hero ── */}
-
+
{
- {tagsReady && - RISING_TAGS_DESKTOP.map((tag) => ( - - {tag.label} - - ))}
{/* Single radial hero glow */}
- {/* Centered text content */} -
+ {/* Title + chooser — on hero, flex fills space above footer (no page scroll) */} +
- {/* Mobile-only rising tags */} -
- {tagsReady && - RISING_TAGS_MOBILE.map((tag) => ( - - {tag.label} - - ))} -
- {/* Headline */} + {/* Headline — slightly smaller than typo-mega1 on tablet */}
{ )} style={{ transitionDelay: '200ms' }} > -

+

- Staying updated shouldn't be hard + Staying sharp shouldn't be hard
- Get your personalized dev feed + A dev feed built around your stack

- {/* Subtext */} -
-

- Millions of developers rely on daily.dev for tech news, tools, and - discussions that actually matter. Tailored to your stack from day - one. -

-
- - {/* Hero CTA group */} -
-
-
- - + />
-
- - {/* Mobile-only bottom rising tags */} -
- {tagsReady && - RISING_TAGS_MOBILE.map((tag) => ( - - {tag.label} - - ))} -
+ )}
@@ -1302,75 +1085,38 @@ export const OnboardingV2 = (): ReactElement => {
)} - {/* ── Feed ── */} -
- - - - - - - - {/* ── Inline chooser panel at feed end ── */} - {step === 'hero' && ( -
-
-
-
-

- You just explored the global feed. -

-

- Now build a feed that is truly yours -

-
- - { - if (isLoggedIn) { - startImportFlowGithub(); - } else { - initiateGithubAuth(); - } - }} - onAiSubmit={() => { - if (isLoggedIn) { - startAiProcessing(); - } else { - setSignupContext('ai'); - openSignupAuth(); - } - }} - /> -
-
- )} -
+ {/* ── Feed (hidden on hero — chooser lives in hero) ── */} + {step !== 'hero' && ( +
+ + + + + + + +
+ )} {step !== 'complete' && ( -
+
)} From 7c801353d250dff1c3fb1afe4a994dd80fa84952 Mon Sep 17 00:00:00 2001 From: capJavert Date: Wed, 22 Apr 2026 13:22:13 +0200 Subject: [PATCH 2/6] feat: style adjustments --- .../components/onboarding/OnboardingV2.tsx | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/packages/webapp/components/onboarding/OnboardingV2.tsx b/packages/webapp/components/onboarding/OnboardingV2.tsx index 7a12aa4175..1e047d862a 100644 --- a/packages/webapp/components/onboarding/OnboardingV2.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2.tsx @@ -636,24 +636,12 @@ export const OnboardingV2 = (): ReactElement => { }; }, [importBodyPhase]); - useEffect(() => { - if (step !== 'hero') { - return undefined; - } - const { style } = document.body; - const prev = style.overflow; - style.overflow = 'hidden'; - return () => { - style.overflow = prev; - }; - }, [step]); - return (
@@ -692,14 +680,13 @@ export const OnboardingV2 = (): ReactElement => {
-
+
{ {/* Single radial hero glow */}
- {/* Title + chooser — on hero, flex fills space above footer (no page scroll) */} + {/* Title + chooser */}
@@ -801,7 +786,7 @@ export const OnboardingV2 = (): ReactElement => { onAiPromptChange={setAiPrompt} canStartAiFlow={canStartAiFlow} isImporting={isImporting} - origin={Origin.OnboardingFeedEnd} + origin={Origin.Onboarding} onGithubClick={() => { if (isLoggedIn) { startImportFlowGithub(); @@ -1107,14 +1092,7 @@ export const OnboardingV2 = (): ReactElement => { )} {step !== 'complete' && ( -
+
)} From 0caf777562d7adb6fd163640a1578baaa41bc3e6 Mon Sep 17 00:00:00 2001 From: capJavert Date: Wed, 22 Apr 2026 13:29:34 +0200 Subject: [PATCH 3/6] feat: cleanup --- packages/shared/src/lib/log.ts | 1 - .../components/onboarding/OnboardingV2.tsx | 2 +- .../onboarding/OnboardingV2Styles.tsx | 135 +----------------- .../onboarding/useOnboardingAnimations.ts | 105 +------------- 4 files changed, 4 insertions(+), 239 deletions(-) diff --git a/packages/shared/src/lib/log.ts b/packages/shared/src/lib/log.ts index a8d5fe8a94..1414a8b9a6 100644 --- a/packages/shared/src/lib/log.ts +++ b/packages/shared/src/lib/log.ts @@ -474,7 +474,6 @@ export enum TargetType { HighlightsCard = 'highlights card', AdvertiseHereCta = 'advertise here cta', // Onboarding v2 - HeroCta = 'hero cta', SignupChooser = 'signup chooser', SignupPrompt = 'signup prompt', ProfileImport = 'profile import', diff --git a/packages/webapp/components/onboarding/OnboardingV2.tsx b/packages/webapp/components/onboarding/OnboardingV2.tsx index 1e047d862a..f3c1612695 100644 --- a/packages/webapp/components/onboarding/OnboardingV2.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2.tsx @@ -1075,7 +1075,7 @@ export const OnboardingV2 = (): ReactElement => { {/* ── Feed (only on complete step — chooser lives in hero) ── */} {step === 'complete' && ( -
+
diff --git a/packages/webapp/components/onboarding/OnboardingV2Styles.tsx b/packages/webapp/components/onboarding/OnboardingV2Styles.tsx index c47d49c61d..335d1a7492 100644 --- a/packages/webapp/components/onboarding/OnboardingV2Styles.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2Styles.tsx @@ -11,12 +11,6 @@ export const OnboardingV2Styles = (): ReactElement => ( display: none !important; } - .onb-feed-stage:not(.onb-feed-unlocked) article:nth-of-type(n + 19) { - display: none !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) article:nth-of-type(18) ~ div { - display: none !important; - } .onb-hero .onb-float-1, .onb-hero .onb-float-2, .onb-hero .onb-float-3 { @@ -26,8 +20,6 @@ export const OnboardingV2Styles = (): ReactElement => ( padding-top: 0 !important; } - /* fade-out handled by .onb-revealed nth-of-type rules below */ - /* ─── HERO PARALLAX ─── */ .onb-hero { --scroll-y: 0; @@ -64,41 +56,6 @@ export const OnboardingV2Styles = (): ReactElement => ( opacity: calc(1 - var(--scroll-y) * 0.001); } - /* ─── RISING TAG CLOUD ─── */ - @keyframes onb-tag-rise { - 0% { - opacity: 0; - transform: translate3d(0, 0, 0) scale(0.88); - } - 6% { - opacity: 0.6; - transform: translate3d(calc(var(--tag-drift-x, 0px) * 0.1), -6vh, 0) - scale(0.95); - } - 40% { - opacity: 0.45; - transform: translate3d(calc(var(--tag-drift-x, 0px) * 0.55), -28vh, 0) - scale(1); - } - 75% { - opacity: 0.15; - transform: translate3d(calc(var(--tag-drift-x, 0px) * 0.85), -52vh, 0) - scale(1.01); - } - 100% { - opacity: 0; - transform: translate3d(var(--tag-drift-x, 0px), -70vh, 0) scale(1.02); - } - } - .onb-rising-tag { - opacity: 0; - animation: onb-tag-rise var(--tag-duration, 14s) linear infinite; - animation-delay: var(--tag-delay, 0s); - contain: layout style; - will-change: transform, opacity; - transform: translateZ(0); - } - /* ─── SHIMMER ─── */ .onb-shimmer { position: relative; @@ -166,17 +123,6 @@ export const OnboardingV2Styles = (): ReactElement => ( opacity: 1; } } - .onb-feed-stage:not(.onb-feed-unlocked) article.onb-revealed { - opacity: 1 !important; - transform: translateY(0) scale(1) !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) article.onb-revealed:hover { - transform: translateY(0) scale(1) !important; - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25), - 0 0 0 1px rgba(255, 255, 255, 0.03) !important; - border-color: rgba(255, 255, 255, 0.06) !important; - } - /* ─── CHIP POP ─── */ @keyframes onb-chip-pop { 0% { @@ -531,12 +477,6 @@ export const OnboardingV2Styles = (): ReactElement => ( animation: onb-celebration-sparkle 1.2s ease-out forwards; } - .onb-feed-unlocked article { - opacity: 1 !important; - transform: none !important; - pointer-events: auto !important; - } - /* ─── AI PROCESSING ORB ─── */ @keyframes onb-ai-orb-breathe { 0%, @@ -899,72 +839,6 @@ export const OnboardingV2Styles = (): ReactElement => ( box-shadow: 0 28px 90px rgba(0, 0, 0, 0.62); } - /* ─── FEED ARTICLE SCROLL-REVEAL ─── */ - .onb-feed-stage:not(.onb-feed-unlocked) article { - opacity: 0; - transform: translateY(0.75rem) scale(0.995); - transition: opacity 0.38s cubic-bezier(0.16, 1, 0.3, 1), - transform 0.38s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.25s ease, - border-color 0.25s ease !important; - transition-delay: var(--reveal-delay, 0ms); - } - - /* ─── FEED FADE-OUT GRADIENT (bottom of visible articles) ─── */ - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(13).onb-revealed { - opacity: 0.88 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(14).onb-revealed { - opacity: 0.72 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(15).onb-revealed { - opacity: 0.52 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(16).onb-revealed { - opacity: 0.32 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(17).onb-revealed { - opacity: 0.15 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(18).onb-revealed { - opacity: 0.05 !important; - } - - @media (max-width: 63.9375rem) { - .onb-feed-stage:not(.onb-feed-unlocked) article:nth-of-type(n + 11) { - display: none !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) article:nth-of-type(10) ~ div { - display: none !important; - } - - .onb-feed-stage:not(.onb-feed-unlocked) article.onb-revealed:hover { - box-shadow: none !important; - } - - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(7).onb-revealed { - opacity: 0.88 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(8).onb-revealed { - opacity: 0.65 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(9).onb-revealed { - opacity: 0.38 !important; - } - .onb-feed-stage:not(.onb-feed-unlocked) - article:nth-of-type(10).onb-revealed { - opacity: 0.12 !important; - } - } - /* ─── TOPIC PILLS (no interaction) ─── */ .onb-marquee span { pointer-events: none; @@ -983,8 +857,6 @@ export const OnboardingV2Styles = (): ReactElement => ( } } - /* mobile rising tags already handled by .onb-rising-tag */ - /* ─── MOBILE MODAL SLIDE-UP ─── */ @keyframes onb-modal-slide-up { from { @@ -1019,7 +891,6 @@ export const OnboardingV2Styles = (): ReactElement => ( } /* ─── OFF-SCREEN ANIMATION PAUSING ─── */ - .onb-hero-offscreen .onb-rising-tag, .onb-hero-offscreen .onb-hero-radial, .onb-hero-offscreen .onb-float-1, .onb-hero-offscreen .onb-float-2, @@ -1028,8 +899,7 @@ export const OnboardingV2Styles = (): ReactElement => ( .onb-hero-offscreen .onb-btn-glow { animation-play-state: paused !important; } - .onb-hero-offscreen .onb-hero-radial, - .onb-hero-offscreen .onb-rising-tag { + .onb-hero-offscreen .onb-hero-radial { will-change: auto !important; } @@ -1091,8 +961,7 @@ export const OnboardingV2Styles = (): ReactElement => ( .onb-sparkle, .onb-confetti-star, .onb-eng-pulse, - .onb-eng-floater, - .onb-rising-tag { + .onb-eng-floater { animation: none !important; opacity: 1 !important; } diff --git a/packages/webapp/components/onboarding/useOnboardingAnimations.ts b/packages/webapp/components/onboarding/useOnboardingAnimations.ts index ba38d56ad7..018b3baefc 100644 --- a/packages/webapp/components/onboarding/useOnboardingAnimations.ts +++ b/packages/webapp/components/onboarding/useOnboardingAnimations.ts @@ -49,10 +49,8 @@ function buildConfettiParticles(): ConfettiParticle[] { } export function useOnboardingAnimations(step: OnboardingStep) { - // ── Mount + tag reveal + feed visible state ── + // ── Mount state ── const [mounted, setMounted] = useState(false); - const [tagsReady, setTagsReady] = useState(false); - const [feedVisible, setFeedVisible] = useState(false); // ── Refs ── const heroRef = useRef(null); @@ -65,34 +63,6 @@ export function useOnboardingAnimations(step: OnboardingStep) { return () => cancelAnimationFrame(raf); }, []); - // ── Tag reveal timing ── - useEffect(() => { - if (!mounted) { - return undefined; - } - let idleTimer: number | null = null; - let revealTimer: ReturnType | null = null; - - const revealTags = () => { - revealTimer = setTimeout(() => setTagsReady(true), 180); - }; - - if ('requestIdleCallback' in window) { - idleTimer = window.requestIdleCallback(revealTags, { timeout: 1400 }); - } else { - revealTimer = setTimeout(() => setTagsReady(true), 1200); - } - - return () => { - if (idleTimer !== null && 'cancelIdleCallback' in window) { - window.cancelIdleCallback(idleTimer); - } - if (revealTimer !== null) { - window.clearTimeout(revealTimer); - } - }; - }, [mounted]); - // ── Body overflow management ── useEffect(() => { const isModalOpen = step !== 'hero' && step !== 'complete'; @@ -110,77 +80,6 @@ export function useOnboardingAnimations(step: OnboardingStep) { }; }, [step]); - // ── Feed article reveal + intersection observer ── - useEffect(() => { - if (!mounted) { - return undefined; - } - - const timer = window.setTimeout(() => { - setFeedVisible(true); - }, 400); - - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - (entry.target as HTMLElement).classList.add('onb-revealed'); - observer.unobserve(entry.target); - } - }); - }, - { rootMargin: '0px 0px -40px 0px', threshold: 0.05 }, - ); - - const observeFeedArticles = () => { - document - .querySelectorAll('.onb-feed-stage article') - .forEach((article, i) => { - if (!article.dataset.onbRevealDelay) { - article.style.setProperty( - '--reveal-delay', - `${Math.min(i * 60, 400)}ms`, - ); - // eslint-disable-next-line no-param-reassign - article.dataset.onbRevealDelay = 'true'; - } - - if (article.classList.contains('onb-revealed')) { - return; - } - - observer.observe(article); - }); - }; - - observeFeedArticles(); - - const mutationObserver = new MutationObserver((mutations) => { - const hasNewArticles = mutations.some((mutation) => - Array.from(mutation.addedNodes).some( - (node) => - node instanceof HTMLElement && - (node.tagName === 'ARTICLE' || node.querySelector('article')), - ), - ); - if (hasNewArticles) { - observeFeedArticles(); - } - }); - const feedContainer = - document.querySelector('.onb-feed-stage') ?? document.body; - mutationObserver.observe(feedContainer, { - childList: true, - subtree: true, - }); - - return () => { - window.clearTimeout(timer); - mutationObserver.disconnect(); - observer.disconnect(); - }; - }, [mounted]); - // ── Parallax scroll ── useEffect(() => { const prefersReduced = window.matchMedia( @@ -246,8 +145,6 @@ export function useOnboardingAnimations(step: OnboardingStep) { return { mounted, - tagsReady, - feedVisible, heroRef, confettiParticles, isEdgeBrowser, From b961fbe8dca4495f1e115c1e6f946399cb204fad Mon Sep 17 00:00:00 2001 From: capJavert Date: Wed, 22 Apr 2026 13:34:59 +0200 Subject: [PATCH 4/6] fix: extension modal showing when dismissed --- .../components/onboarding/OnboardingV2.tsx | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/webapp/components/onboarding/OnboardingV2.tsx b/packages/webapp/components/onboarding/OnboardingV2.tsx index f3c1612695..50a551779b 100644 --- a/packages/webapp/components/onboarding/OnboardingV2.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2.tsx @@ -189,10 +189,9 @@ export const OnboardingV2 = (): ReactElement => { ONBOARDING_AI_PROMPT_KEY, '', ); - const [extensionSeen, setExtensionSeen] = usePersistentContext( - ONBOARDING_EXTENSION_SEEN_KEY, - false, - ); + const [extensionSeen, setExtensionSeen, isExtensionSeenFetched] = + usePersistentContext(ONBOARDING_EXTENSION_SEEN_KEY, false); + const shouldShowExtension = showExtensionCta && !extensionSeen; const [authDisplay, setAuthDisplay] = useState(AuthDisplay.OnboardingSignup); const [isLoginFlow, setIsLoginFlow] = useState(false); const [acceptedMarketing, setAcceptedMarketing] = useState(true); @@ -404,7 +403,7 @@ export const OnboardingV2 = (): ReactElement => { setImportExiting(true); trackTimer(() => { setImportExiting(false); - setStep(showExtensionCta ? 'extension' : 'complete'); + setStep(shouldShowExtension ? 'extension' : 'complete'); }, 350); }, 600); }, FINISHING_ANIMATION_MS); @@ -418,7 +417,7 @@ export const OnboardingV2 = (): ReactElement => { completeAction, router, trackTimer, - showExtensionCta, + shouldShowExtension, ], ); @@ -473,12 +472,12 @@ export const OnboardingV2 = (): ReactElement => { return; } - if (extensionSeen || !showExtensionCta) { - setStep('complete'); - } else { - setStep('extension'); + if (!isExtensionSeenFetched) { + return; } + setStep(shouldShowExtension ? 'extension' : 'complete'); + return; } @@ -527,7 +526,8 @@ export const OnboardingV2 = (): ReactElement => { isLoggedIn, isOnboardingActionsReady, isOnboardingComplete, - extensionSeen, + isExtensionSeenFetched, + shouldShowExtension, aiPrompt, signupContext, step, @@ -535,7 +535,6 @@ export const OnboardingV2 = (): ReactElement => { setSignupContext, startImportFlowGithub, startAiProcessing, - showExtensionCta, ]); useEffect(() => { @@ -1287,7 +1286,7 @@ export const OnboardingV2 = (): ReactElement => { pathname: `${webappUrl}onboarding`, query: { ...router.query, step: 'complete' }, }); - setStep(showExtensionCta ? 'extension' : 'complete'); + setStep(shouldShowExtension ? 'extension' : 'complete'); }} className="mx-auto mt-6 rounded-14 bg-white px-8 py-3 font-bold text-black transition-all duration-200 typo-callout hover:-translate-y-0.5 hover:shadow-[0_8px_28px_rgba(255,255,255,0.12)] disabled:cursor-not-allowed disabled:opacity-40" > From e6e641380846e1f642ecabff5d791d3eb478de2f Mon Sep 17 00:00:00 2001 From: capJavert Date: Wed, 22 Apr 2026 13:39:09 +0200 Subject: [PATCH 5/6] fix: context fetch guard --- .../components/onboarding/OnboardingV2.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/webapp/components/onboarding/OnboardingV2.tsx b/packages/webapp/components/onboarding/OnboardingV2.tsx index 50a551779b..b25351e869 100644 --- a/packages/webapp/components/onboarding/OnboardingV2.tsx +++ b/packages/webapp/components/onboarding/OnboardingV2.tsx @@ -185,10 +185,8 @@ export const OnboardingV2 = (): ReactElement => { isEdgeBrowser, extensionImages, } = useOnboardingAnimations(step); - const [aiPrompt, setAiPrompt] = usePersistentContext( - ONBOARDING_AI_PROMPT_KEY, - '', - ); + const [aiPrompt, setAiPrompt, isAiPromptFetched] = + usePersistentContext(ONBOARDING_AI_PROMPT_KEY, '', undefined, ''); const [extensionSeen, setExtensionSeen, isExtensionSeenFetched] = usePersistentContext(ONBOARDING_EXTENSION_SEEN_KEY, false); const shouldShowExtension = showExtensionCta && !extensionSeen; @@ -204,9 +202,12 @@ export const OnboardingV2 = (): ReactElement => { >(null); const [importBodyHeight, setImportBodyHeight] = useState(null); const [importExiting, setImportExiting] = useState(false); - const [signupContext, setSignupContext] = usePersistentContext< - 'github' | 'ai' | null - >(ONBOARDING_SIGNUP_CONTEXT_KEY, null, ['github', 'ai']); + const [signupContext, setSignupContext, isSignupContextFetched] = + usePersistentContext<'github' | 'ai' | null>( + ONBOARDING_SIGNUP_CONTEXT_KEY, + null, + ['github', 'ai'], + ); const pageRef = useRef(null); const importTimersRef = useRef[]>([]); const importBodyContentRef = useRef(null); @@ -432,6 +433,8 @@ export const OnboardingV2 = (): ReactElement => { if ( !isAuthReady || isAuthenticating || + !isAiPromptFetched || + !isSignupContextFetched || ( [ 'auth', @@ -527,6 +530,8 @@ export const OnboardingV2 = (): ReactElement => { isOnboardingActionsReady, isOnboardingComplete, isExtensionSeenFetched, + isAiPromptFetched, + isSignupContextFetched, shouldShowExtension, aiPrompt, signupContext, From 3a9c75bdc7340fb498737cebe61b46c57b0a1440 Mon Sep 17 00:00:00 2001 From: capJavert Date: Wed, 22 Apr 2026 13:42:39 +0200 Subject: [PATCH 6/6] chore: remove unused event --- packages/shared/src/lib/log.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/shared/src/lib/log.ts b/packages/shared/src/lib/log.ts index 1414a8b9a6..8d418c39ce 100644 --- a/packages/shared/src/lib/log.ts +++ b/packages/shared/src/lib/log.ts @@ -84,7 +84,6 @@ export enum Origin { Leaderboard = 'leaderboard', // Onboarding v2 OnboardingModal = 'onboarding modal', - OnboardingFeedEnd = 'onboarding feed end', // Auth BetterAuthEmailLogin = 'betterauth email login', BetterAuthEmailLoginBoot = 'betterauth email login boot',