fix: prevent two-pages-in-one layout bug on root and onboarding#24
Conversation
- Root page: add `mounted` guard so SSR and initial client render both show the loading spinner (same background gradient), eliminating the hydration-mismatch flash where the spinner and onboarding overlay briefly stack on returning users - GuestOnboardingFlow: wrap AnimatePresence in a persistent fixed inset-0 backdrop so step transitions never expose the body background through the opacity-0 initial animation state; steps switch to `absolute inset-0` inside the shared backdrop - ConversationalOnboarding: all phases now use `fixed inset-0 z-50` so the onboarding experience at /onboarding fully covers the (app) layout's TopBar and BottomNav, removing the visual of two stacked screens https://claude.ai/code/session_017cLXjZu6kkjXRf2BemMPpp
✅ Deploy Preview for bajet-buddy ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
bajet-buddy | a00bb04 | May 25 2026, 01:33 PM |
There was a problem hiding this comment.
Code Review
This pull request refactors the onboarding flow and root page to improve layout consistency and handle hydration. Key changes include the introduction of a shared LoadingSpinner and background constant, as well as updating onboarding containers to use fixed positioning. Feedback focuses on ensuring mobile responsiveness by adding overflow-y-auto to various containers and removing justify-center where it might cause content clipping at the top of the viewport when overflowing.
|
|
||
| return ( | ||
| <div className="flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground"> | ||
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
The main questions phase is missing overflow-y-auto. Since this phase contains dynamic text and multiple options, it is highly likely to overflow on mobile devices. Additionally, removing justify-center is recommended to prevent top-clipping during overflow.
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background p-6 text-foreground"> | |
| <div className="fixed inset-0 z-50 flex flex-col items-center overflow-y-auto bg-background p-6 text-foreground"> |
| <AnimatePresence mode="wait"> | ||
| {step === "questions" && ( | ||
| <motion.div key="questions" initial={{ x: 40, opacity: 0 }} animate={{ x: 0, opacity: 1 }} exit={{ x: -40, opacity: 0 }} | ||
| className="absolute inset-0"> |
There was a problem hiding this comment.
The absolute inset-0 container lacks overflow-y-auto. If the OnboardingChat content exceeds the viewport height, users will be unable to scroll to see the rest of the conversation, which is a critical issue on mobile devices.
| className="absolute inset-0"> | |
| className="absolute inset-0 overflow-y-auto"> |
| </AnimatePresence> | ||
| {step === "statement" && ( | ||
| <motion.div key="statement" initial={{ x: 40, opacity: 0 }} animate={{ x: 0, opacity: 1 }} exit={{ x: -40, opacity: 0 }} | ||
| className="absolute inset-0"> |
There was a problem hiding this comment.
|
|
||
| {step === "roast" && persona && ( | ||
| <motion.div key="roast" initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, y: 50 }} | ||
| className="absolute inset-0"> |
There was a problem hiding this comment.
| if (phase === "scan") { | ||
| return ( | ||
| <div className="flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground"> | ||
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
Using justify-center on a container with overflow-y-auto can cause the top of the content to be clipped and unreachable if the content height exceeds the viewport. It is safer to remove justify-center and rely on padding or a wrapper to ensure the content remains accessible on smaller screens, similar to the implementation in the result phase (line 357).
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> | |
| <div className="fixed inset-0 z-50 flex flex-col items-center overflow-y-auto bg-background p-6 text-foreground"> |
| const SPECIES_ORDER: PetSpecies[] = ["squirrel", "fox", "raccoon", "rabbit"]; | ||
| return ( | ||
| <div className="flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground"> | ||
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
Similar to the scan phase, combining justify-center with overflow-y-auto may lead to content clipping at the top on small devices. Removing justify-center ensures that all pet options are scrollable and visible.
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> | |
| <div className="fixed inset-0 z-50 flex flex-col items-center overflow-y-auto bg-background p-6 text-foreground"> |
| if (phase === "loading") { | ||
| return ( | ||
| <div className="min-h-screen flex flex-col items-center justify-center bg-background p-6 text-foreground"> | ||
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
This container is missing overflow-y-auto. While the loading state is currently minimal, adding it ensures the UI doesn't break on extremely small screens or in landscape orientation.
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background p-6 text-foreground"> | |
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/web/components/features/onboarding/ConversationalOnboarding.tsx">
<violation number="1" location="apps/web/components/features/onboarding/ConversationalOnboarding.tsx:172">
P2: `justify-center` combined with `overflow-y-auto` on a flex column causes top content to be clipped and unreachable when content exceeds viewport height. Remove `justify-center` and rely on padding or an inner wrapper to vertically center shorter content.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if (phase === "scan") { | ||
| return ( | ||
| <div className="flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground"> | ||
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> |
There was a problem hiding this comment.
P2: justify-center combined with overflow-y-auto on a flex column causes top content to be clipped and unreachable when content exceeds viewport height. Remove justify-center and rely on padding or an inner wrapper to vertically center shorter content.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/components/features/onboarding/ConversationalOnboarding.tsx, line 172:
<comment>`justify-center` combined with `overflow-y-auto` on a flex column causes top content to be clipped and unreachable when content exceeds viewport height. Remove `justify-center` and rely on padding or an inner wrapper to vertically center shorter content.</comment>
<file context>
@@ -169,7 +169,7 @@ export function ConversationalOnboarding() {
if (phase === "scan") {
return (
- <div className="flex min-h-screen flex-col items-center justify-center bg-background p-6 text-foreground">
+ <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground">
<div className="w-full max-w-md space-y-6">
<motion.div
</file context>
| <div className="fixed inset-0 z-50 flex flex-col items-center justify-center overflow-y-auto bg-background p-6 text-foreground"> | |
| <div className="fixed inset-0 z-50 flex flex-col items-center overflow-y-auto bg-background p-6 text-foreground"> |
Summary
mountedguard so SSR and the initial client render both show the same loading spinner (matching gradient background). This eliminates the flash/snap where a returning user would briefly see both the spinner and the onboarding overlay stacked.AnimatePresencein a persistentfixed inset-0 z-50div that always shows the gradient background. Step motion-divs now useabsolute inset-0inside this backdrop — during transitions the step content can animate withopacity: 0without punching a transparent hole that reveals the body background underneath.questions,scan,pet,loading,result) now usefixed inset-0 z-50instead ofmin-h-screenin normal flow. This covers theTopBarandBottomNavfrom the(app)layout on the/onboardingroute, so users no longer see the onboarding questionnaire and the app navigation chrome stacked on the same screen.Test plan
https://bajet-buddy.netlify.appas a first-time user — see only the loading spinner briefly, then a clean slide-in of the onboarding questions (no stacked pages)/onboardingdirectly — TopBar and BottomNav are covered; the questionnaire fills the full screenhttps://claude.ai/code/session_017cLXjZu6kkjXRf2BemMPpp
Generated by Claude Code
Summary by cubic
Fixes the “two pages stacked” bug on the root and
/onboardingroutes by making loading and onboarding screens full-screen and consistent across SSR and client render. Removes hydration flash and background bleed during step transitions.mountedguard so SSR and client both show the same spinner/gradient; no brief stack of spinner + onboarding for returning users.GuestOnboardingFlow: added a persistentfixed inset-0 z-50backdrop; steps render asabsolute inset-0to stop background peeking duringAnimatePresencetransitions.ConversationalOnboarding: all phases usefixed inset-0 z-50to fully coverTopBar/BottomNavon/onboarding.Written for commit a00bb04. Summary will update on new commits. Review in cubic