"use client"; import { Button } from "@azmr/ui/button"; import { Alert, AlertDescription, AlertTitle, Card, CardContent, CardFooter, } from "@azmr/ui/display"; import { Input } from "@azmr/ui/input"; import { Stepper } from "@azmr/ui/stepper"; import { ToggleGroup, ToggleGroupItem } from "@azmr/ui/toggle"; import { type FormEvent, useCallback, useId, useRef, useState } from "react"; const STEPS = [ { label: "Your team", description: "Name and size" }, { label: "Your plan", description: "Pick one" }, { label: "Confirm" }, ]; const PLANS = [ { value: "starter", label: "Starter · $49 a month" }, { value: "business", label: "Business · $240 a month" }, ]; // A wizard keeps every answer in one place, validates a step before moving on, and moves focus to // the new step's heading, so a keyboard or screen reader user is not left on a button that has // just disappeared. export default function OnboardingWizard() { const id = useId(); const [step, setStep] = useState(0); const [team, setTeam] = useState(""); const [size, setSize] = useState(""); const [plan, setPlan] = useState("starter"); const [error, setError] = useState(null); const [done, setDone] = useState(false); const moved = useRef(false); // A heading that appears after the person has moved on takes focus. Each step's heading has its // own `key`, so it is a new element and this runs once per step, never while they type. const focusHeading = useCallback((node: HTMLElement | null) => { if (node && moved.current) node.focus(); }, []); function go(to: number) { moved.current = true; setStep(to); } function next(event: FormEvent) { event.preventDefault(); if (step === 0) { if (team.trim().length < 2) return setError("Enter a team name."); if (!/^[1-9]\d{0,3}$/.test(size)) return setError("Enter how many people, as a whole number."); } setError(null); if (step === STEPS.length - 1) { moved.current = true; return setDone(true); } go(step + 1); } if (done) { return ( {team} is ready {size} people on the {plan} plan. We have sent a welcome email. ); } return (

{STEPS[step]?.label}

{error && ( {error} )} {step === 0 && ( <>
setTeam(event.target.value)} />
setSize(event.target.value)} />
)} {step === 1 && ( { // One plan is always chosen: ignore the click that would turn the last one off. const chosen = (value as string[])[0]; if (chosen) setPlan(chosen); }} className="flex-col items-stretch" > {PLANS.map((option) => ( {option.label} ))} )} {step === 2 && (
Team
{team}
People
{size}
Plan
{plan}
)}
); }