Files
MealQuest/web/src/onboarding/OnboardingStep.tsx
T
dev_agentandClaude Opus 5.5 b568558875
CI / ci (push) Successful in 2m20s
CI / ci (pull_request) Successful in 2m21s
Add onboarding steps 1 and 2 with the first-run redirect
While household_settings.onboarding_completed_at is null, OnboardingGate
sends every app route to /onboarding, a full screen outside the shell.
The household settings parser now reads onboarding_completed_at from the
existing GET /api/v1/settings/household.

Step 1 welcomes the household and explains Regulars, Side quests and the
Quest log. Step 2 follows mock 1h: progress pills, the add pill with its
grape "+" (Enter also adds), Regulars chips with remove, dashed Common
picks, and "Next: notifications" enabled at 3 Regulars. Adds and removes
go through new dinners API hooks (POST /api/v1/dinners, DELETE
/api/v1/dinners/{id}) optimistically, rolled back if the server refuses.
Step 3 is a placeholder until its task lands.

Maestro task 5a43f813-c940-4f79-a2be-027644ae9e6c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:48:42 -04:00

36 lines
1.1 KiB
TypeScript

import type { ReactNode } from 'react'
import styles from './Onboarding.module.css'
export const ONBOARDING_STEPS = 3
export type OnboardingStepProps = {
// 1-based; the progress pills fill up to it.
step: number
title: string
children: ReactNode
// The step's primary action, fixed to the bottom of the screen.
action?: ReactNode
}
// OnboardingStep is the frame every onboarding step shares: progress pills,
// the "Step N of 3" kicker and the Bagel title.
export function OnboardingStep({ step, title, children, action }: OnboardingStepProps) {
return (
<main className={styles.screen}>
<div className={styles.column}>
<div className={styles.progress} aria-hidden="true">
{Array.from({ length: ONBOARDING_STEPS }, (_, i) => (
<span key={i} className={[styles.pill, i < step && styles.filled].filter(Boolean).join(' ')} />
))}
</div>
<p className={styles.kicker}>
Step {step} of {ONBOARDING_STEPS}
</p>
<h1 className={styles.title}>{title}</h1>
{children}
</div>
{action && <div className={styles.footer}>{action}</div>}
</main>
)
}