"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { ArrowRight, Building2, CheckCircle2, Sparkles, Users, } from "lucide-react"; import { toast } from "sonner"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { api } from "~/trpc/react"; type Step = "welcome" | "business" | "client" | "done"; export function OnboardingWizard() { const router = useRouter(); const utils = api.useUtils(); const { data: status, isLoading } = api.settings.getOnboardingStatus.useQuery(); const [step, setStep] = useState("welcome"); const [businessName, setBusinessName] = useState(""); const [clientName, setClientName] = useState(""); const createBusiness = api.businesses.create.useMutation({ onSuccess: async () => { toast.success("Business added"); await utils.settings.getOnboardingStatus.invalidate(); setStep("client"); }, onError: (error) => toast.error(error.message), }); const createClient = api.clients.create.useMutation({ onSuccess: async () => { toast.success("Client added"); await utils.settings.getOnboardingStatus.invalidate(); setStep("done"); }, onError: (error) => toast.error(error.message), }); const completeOnboarding = api.settings.completeOnboarding.useMutation({ onSuccess: () => { router.push("/dashboard"); router.refresh(); }, onError: (error) => toast.error(error.message), }); useEffect(() => { if (status?.completed) { router.replace("/dashboard"); } }, [status?.completed, router]); useEffect(() => { if (!isLoading && status && !status.completed && step === "welcome") { if (status.businessCount > 0 && status.clientCount > 0) { setStep("done"); } else if (status.businessCount > 0) { setStep("client"); } } }, [isLoading, status, step]); function handleSkip() { completeOnboarding.mutate(); } function handleBusinessSubmit(e: React.FormEvent) { e.preventDefault(); if (!businessName.trim()) { toast.error("Business name is required"); return; } createBusiness.mutate({ name: businessName.trim(), isDefault: true, }); } function handleClientSubmit(e: React.FormEvent) { e.preventDefault(); if (!clientName.trim()) { toast.error("Client name is required"); return; } createClient.mutate({ name: clientName.trim() }); } function handleFinish() { completeOnboarding.mutate(); } function handleCreateInvoice() { completeOnboarding.mutate(undefined, { onSuccess: () => { router.push("/dashboard/invoices/new"); router.refresh(); }, }); } if (isLoading || status?.completed) { return (

Loading…

); } return (

{step === "welcome" && "Step 1 of 3"} {step === "business" && "Step 2 of 3"} {step === "client" && "Step 3 of 3"} {step === "done" && "All set"}

{step === "welcome" && ( Welcome to BeenVoice Let's set up the basics so you can send your first invoice. This only takes a minute.

Add the business you send invoices from

Add your first client to bill

)} {step === "business" && ( Your business This appears on invoices as the sender — name, logo, and contact details.
setBusinessName(e.target.value)} placeholder="Acme Studio LLC" autoFocus />
)} {step === "client" && ( Your first client Who are you billing? You can add more details later.
setClientName(e.target.value)} placeholder="Acme Corp" autoFocus />
)} {step === "done" && ( You're ready to go Your workspace is set up. Create an invoice or explore the dashboard. )} {step !== "welcome" && step !== "done" && ( )}
); }