import { useState } from "react"; import { ArrowLeft, LifeBuoy } from "lucide-react"; import { usePatientSupportService } from "../../services/PatientSupportService.tsx"; import { relayServerFailure } from "../../utils/fetchFailureMessage"; import { Input } from "../ui/input.tsx"; /** * A patient reporting that the portal itself is broken, from the assistant's own panel. * * The practice's form is a separate component reaching separate routes, and they are not merged. * The server keys a patient's ticket on their account, outside every practice partition; one * component switching on the mount is the only way those two could meet in this client. * * A view, not a destination: the panel swaps what it shows and swaps back. Somebody reporting a * fault is already stuck, and taking their screen away at that moment is how a report turns into a * telephone call to the practice, which cannot fix it. */ export type PatientSupportTicketFormProps = { /** Back to the conversation. The panel stays open either way. */ onBack: () => void; /** The surface being helped with, in the reader's terms. */ workspace: string; /** The in-app route, so support can open the screen rather than ask which one. */ route: string; /** The last thing asked of the assistant, when there was one. */ lastQuestion?: string; }; export const PatientSupportTicketForm = ({ onBack, workspace, route, lastQuestion, }: PatientSupportTicketFormProps) => { const { submitPatientSupportTicket } = usePatientSupportService(); const [subject, setSubject] = useState(""); const [body, setBody] = useState(""); const [sending, setSending] = useState(false); const [error, setError] = useState(null); const [reference, setReference] = useState(null); const submit = async (event: React.FormEvent) => { event.preventDefault(); if (sending || !subject.trim() || !body.trim()) return; setSending(true); setError(null); try { const receipt = await submitPatientSupportTicket({ subject: subject.trim(), body: body.trim(), workspace, route, lastQuestion, }); setReference(receipt.reference); } catch (failure) { /* * The fields keep what they hold. Somebody has just written out a problem they could not * solve, and losing it to a failed request is worse than the thing that brought them here. */ setError( relayServerFailure(failure, "That could not be sent just now. Your message is still here — try again."), ); } finally { setSending(false); } }; if (reference) { return (

Your report is in.

Quote {reference} if you get in touch about it. The answer appears on your support screen.

{/* The only way back to this ticket until somebody answers it. A plain anchor rather than `useNavigate`: the widget mounts wherever it is embedded and cannot assume a router context of its own. */} See your support tickets
); } return (

This goes to Akashic support. For care, appointments, or bills, message your practice.

{/* `htmlFor` and an `id` rather than a label wrapped round the field: `Input` is a component, so a wrapping label associates with nothing a browser can see. The textarea below wraps because it is a real `