import{FormEvent,useMemo,useState}from "react"; import{ISSUE_OPTIONS,SYMPTOM_OPTIONS,URGENCY_OPTIONS}from "../../data/options"; import{formatSnakeCase}from "../../lib/format"; import{determineRecommendation,recommendationToStatus}from "../../lib/triage"; import{SupportCase}from "../../types/case"; import{Button}from "../ui/Button"; import{Card}from "../ui/Card"; import{Input,Label,Textarea}from "../ui/Field"; import{StatusPill}from "../ui/StatusPill"; import{Stepper}from "../ui/Stepper"; interface Props{onSubmitCase:(supportCase: SupportCase) => Promise<void>}export function DescribeProblemFlow({onSubmitCase}: Props){const [uploading,setUploading] = useState(false);const [step,setStep] = useState(0);const [draft,setDraft] = useState<Partial<SupportCase>>({mediaUrls: []});const [uploadMode,setUploadMode] = useState<"take_photo" | "record_video" | "upload_device" | null>(null);const recommendation = useMemo(() => determineRecommendation(draft),[draft]);const canContinue = (step === 0) || (step === 1 && !!draft.category) || (step === 2 && !!draft.symptom) || (step === 3 && !!draft.urgency) || (step >= 4 && step <= 7);const [submitting,setSubmitting] = useState(false);const [submitted,setSubmitted] = useState(false);const [submittedCaseId,setSubmittedCaseId] = useState<string | null>(null);const submit = async (event: FormEvent) =>{event.preventDefault();const now = new Date().toISOString();const caseId = crypto.randomUUID();const finalCase: SupportCase ={id:caseId,entryPath: "describe_problem",category: draft.category,symptom: draft.symptom,urgency: draft.urgency,mediaUrls: draft.mediaUrls ?? [],description: draft.description,contact: draft.contact,recommendation,status: recommendationToStatus(recommendation),createdAt: now,updatedAt: now,}setSubmitting(true);try{await onSubmitCase(finalCase);setSubmittedCaseId(caseId);setSubmitted(true)}finally{setSubmitting(false)}}const onMediaUpload = async (files: FileList | null) =>{if (!files?.length) return;setUploading(true);await new Promise((resolve) => setTimeout(resolve,800));const localUrls = Array.from(files).map((file) => URL.createObjectURL(file));setDraft((prev) => ({...prev,mediaUrls: [...(prev.mediaUrls ?? []),...localUrls]}));setUploading(false)}if (submitted){return (<Card> <h2>Written expert review</h2> <StatusPill>Payment received · Case submitted</StatusPill> <p className="muted">Thanks — your case is now in the expert review queue. We will send your written guidance to your phone and email.</p> <ul className="checklist"> <li>Your photos and details are attached to this case</li> <li>A plumbing expert will review and send clear next steps in writing</li> <li>You can return to support home anytime while you wait</li> </ul> {submittedCaseId ? <p className="muted">Case reference: {submittedCaseId}</p> : null} </Card>)}return (<Card> <h2>Written expert review</h2> <p className="muted">Written expert review for calmer,lower-cost first guidance.</p> <Stepper current={step + 1} total={8} /> <form onSubmit={submit} className="flow-form"> {step === 0 && (<div className="form-stack"> <StatusPill>Written expert review · 19 USD</StatusPill> <p className="muted">Send photos and details. A plumbing expert reviews your case and sends clear next steps in writing.</p> <ul className="checklist"> <li>Professional written review of your issue</li> <li>Priority and risk guidance for your home</li> <li>Practical next steps for your situation</li> </ul> </div>)} {step === 1 && (<div> <Label>1) What area needs review?</Label> <p className="muted">This helps us route your case to the right plumbing expert.</p> <div className="option-grid"> {ISSUE_OPTIONS.map((option) => (<button type="button" key={option.value} className={`option ${draft.category === option.value ? "option-selected" : ""}`} onClick={() => setDraft((prev) => ({...prev,category: option.value}))} > {option.label} </button>))} </div> </div> )} {step === 2 && (<div> <Label>2) What is happening?</Label> <p className="muted">Choose the closest symptom. You can add details in the next steps.</p> <div className="option-grid"> {SYMPTOM_OPTIONS.map((option) => (<button type="button" key={option.value} className={`option ${draft.symptom === option.value ? "option-selected" : ""}`} onClick={() => setDraft((prev) => ({...prev,symptom: option.value}))} > {option.label} </button>))} </div> </div> )} {step === 3 && (<div> <Label>3) How quickly do you need written guidance?</Label> <p className="muted">If water is actively flowing,shut off the water supply first if safe.</p> <div className="option-list"> {URGENCY_OPTIONS.map((option) => (<button type="button" key={option.value} className={`option option-row ${draft.urgency === option.value ? "option-selected" : ""}`} onClick={() => setDraft((prev) => ({...prev,urgency: option.value}))} > <strong>{option.label}</strong> <span className="muted">{option.helper}</span> </button>))} </div> </div> )} {step === 4 && (<div> <Label>4) Add visual evidence</Label> <p className="muted">Clear photos or a short video help the expert assess your issue faster.</p> <div className="option-list"> <button type="button" className={`option option-row ${uploadMode === "take_photo" ? "option-selected" : ""}`} onClick={() => setUploadMode("take_photo")}>Take photo</button> <button type="button" className={`option option-row ${uploadMode === "record_video" ? "option-selected" : ""}`} onClick={() => setUploadMode("record_video")}>Record short video</button> <button type="button" className={`option option-row ${uploadMode === "upload_device" ? "option-selected" : ""}`} onClick={() => setUploadMode("upload_device")}>Upload from device</button> </div> <Input type="file" multiple accept="image/*,video/*" onChange={(e) => onMediaUpload(e.target.files)} /> {uploading && <StatusPill>Upload in progress…</StatusPill>} {draft.mediaUrls?.length ? <p className="muted">Upload complete: {draft.mediaUrls.length} file(s) added.</p> : null} </div> )} {step === 5 && (<div> <Label>5) Describe what changed</Label> <Textarea rows={4} placeholder="When did it start, and what have you already tried?" value={draft.description ?? ""} onChange={(e) => setDraft((prev) => ({...prev,description: e.target.value}))} /> </div> )} {step === 6 && (<div className="form-stack"> <Label>6) Where should we send your written review?</Label> <p className="muted">We use these details for your expert response and updates.</p> <Input placeholder="Full name" value={draft.contact?.fullName ?? ""} onChange={(e) => setDraft((prev) => ({...prev,contact: {...prev.contact,fullName: e.target.value,phone: prev.contact?.phone ?? "",email: prev.contact?.email ?? ""}}))} /> <Input placeholder="Phone" value={draft.contact?.phone ?? ""} onChange={(e) => setDraft((prev) => ({...prev,contact: {...prev.contact,phone: e.target.value,fullName: prev.contact?.fullName ?? "",email: prev.contact?.email ?? ""}}))} /> <Input type="email" placeholder="Email" value={draft.contact?.email ?? ""} onChange={(e) => setDraft((prev) => ({...prev,contact: {...prev.contact,email: e.target.value,fullName: prev.contact?.fullName ?? "",phone: prev.contact?.phone ?? ""}}))} /> <StatusPill>Service guidance preview: {formatSnakeCase(recommendation)}</StatusPill> </div> )} {step === 7 && (<div className="form-stack"> <Label>7) Review and pay</Label> <ul className="checklist"> <li>Service: Written expert review</li> <li>Price: 19 USD</li> <li>Outcome: clear written next-step guidance</li> </ul> <StatusPill>Payment is required before expert review starts.</StatusPill> <Button type="submit" fullWidth disabled={submitting}>{submitting ? "Submitting…" : "Pay 19 USD and submit for review"}</Button> </div> )} {step < 7 && (<div className="flow-actions"> <Button type="button" variant="ghost" disabled={step === 0} onClick={() => setStep((s) => Math.max(0,s - 1))}> Previous </Button> <Button type="button" disabled={!canContinue} onClick={() => setStep((s) => Math.min(7,s + 1))}> Next step </Button> </div>)} </form> </Card>)}
