import { ArrowLeft, ArrowRight, Check } from "lucide-react"; import type { ReactNode } from "react"; import { Fragment } from "react"; import { CLIENT_WEBSITE_COUNT_OPTIONS, CLIENT_WORK_FOR, INTEREST_OPTIONS, ONBOARDING_LAST_STEP, type OnboardingAnswers, SOURCE_OPTIONS, WORK_FOR_OPTIONS, } from "@/client/features/onboarding/onboardingModel"; import { SearchConsoleOnboardingStep } from "@/client/features/onboarding/SearchConsoleOnboardingStep"; type PostSignupOnboardingProps = { firstName: string; title?: string; helperText?: string; step: number; answers: OnboardingAnswers; onAnswersChange: (answers: OnboardingAnswers) => void; onNext: () => void; onBack: () => void; onSkip: () => void; onFinish: (mcpSetupIntent: "yes" | "no") => void; isSaving: boolean; accountMenu: ReactNode; }; export function PostSignupOnboarding({ firstName, title, helperText, step, answers, onAnswersChange, onNext, onBack, onSkip, onFinish, isSaving, accountMenu, }: PostSignupOnboardingProps) { const canContinue = step === 0 ? answers.selectedInterests.length > 0 : step === 1 ? Boolean(answers.workFor) : step === 2 ? Boolean(answers.source) : true; const updateAnswers = (patch: Partial) => onAnswersChange({ ...answers, ...patch }); return (
{accountMenu}
OpenSEO

Step {step + 1} of {ONBOARDING_LAST_STEP + 1}

{title ?? (firstName ? `Welcome to OpenSEO, ${firstName}!` : "Welcome to OpenSEO!")}

{helperText ?? "A few quick answers to set things up."}

{step === 0 ? ( { updateAnswers({ selectedInterests: answers.selectedInterests.includes(value) ? answers.selectedInterests.filter((item) => item !== value) : [...answers.selectedInterests, value], }); }} otherValue={answers.interestOther} onOtherChange={(interestOther) => updateAnswers({ interestOther })} multiple /> ) : step === 1 ? ( updateAnswers({ workFor })} otherValue={answers.workForOther} onOtherChange={(workForOther) => updateAnswers({ workForOther })} followUp={{ showForValue: CLIENT_WORK_FOR, label: "About how many client sites do you work on?", options: [...CLIENT_WEBSITE_COUNT_OPTIONS], value: answers.clientWebsiteCount, onChange: (clientWebsiteCount) => updateAnswers({ clientWebsiteCount }), }} /> ) : step === 2 ? ( updateAnswers({ source })} otherValue={answers.sourceOther} onOtherChange={(sourceOther) => updateAnswers({ sourceOther })} /> ) : step === 3 ? ( ) : ( onFinish("yes")} onSkip={() => onFinish("no")} /> )} {step < ONBOARDING_LAST_STEP ? (
) : null}
); } function McpRecommendation({ isSaving, onBack, onSetup, onSkip, }: { isSaving: boolean; onBack: () => void; onSetup: () => void; onSkip: () => void; }) { const capabilities = [ "Keyword research", "Competitor research", "Link prospecting", ]; return (

Set up OpenSEO MCP?

The most powerful way to use OpenSEO — use AI to supercharge your SEO skills.

); } function OnboardingChoiceGroup({ title, description, options, selectedValues, onToggle, otherValue, onOtherChange, multiple = false, maxSelections, followUp, }: { title: string; description?: string; options: string[]; selectedValues: string[]; onToggle: (value: string) => void; otherValue: string; onOtherChange: (value: string) => void; multiple?: boolean; maxSelections?: number; followUp?: { showForValue: string; label: string; options: string[]; value: string; onChange: (value: string) => void; }; }) { const isOtherSelected = selectedValues.includes("Other"); const showFollowUp = followUp !== undefined && selectedValues.includes(followUp.showForValue); const atLimit = maxSelections !== undefined && selectedValues.length >= maxSelections; return (

{title}

{description ? (

{description}

) : null}
{options.map((option) => { const selected = selectedValues.includes(option); const disabled = atLimit && !selected; const showFollowUpHere = showFollowUp && followUp?.showForValue === option; return ( {showFollowUpHere && followUp ? (

{followUp.label}

{followUp.options.map((followUpOption) => { const followUpSelected = followUp.value === followUpOption; return ( ); })}
) : null}
); })}
{isOtherSelected ? ( onOtherChange(event.target.value)} /> ) : null}
); }