"use client"; import { useState } from "react"; import Link from "next/link"; import { ArrowLeft, Check, LoaderCircle, RotateCcw } from "lucide-react"; import { submitSupport, type SupportKind } from "@/lib/api/support"; import { isApiError } from "@/lib/api/client"; import { cn } from "@/lib/utils"; type SupportFormProps = { kind: SupportKind; eyebrow: string; title: string; intro: string; categories?: string[]; showRating?: boolean; showTitleField?: boolean; messageLabel: string; messagePlaceholder: string; }; type Phase = "idle" | "submitting" | "done" | "error"; const inputClass = "w-full rounded-xl border border-white/12 bg-white/[0.03] px-3.5 py-3 text-[15px] text-white placeholder:text-white/30 outline-none transition focus:border-white/40"; const labelClass = "block text-xs font-bold uppercase tracking-[0.14em] text-white/45"; export function SupportForm({ kind, eyebrow, title, intro, categories, showRating = false, showTitleField = false, messageLabel, messagePlaceholder, }: SupportFormProps) { const [category, setCategory] = useState(categories?.[0] ?? ""); const [titleValue, setTitleValue] = useState(""); const [message, setMessage] = useState(""); const [rating, setRating] = useState(null); const [phase, setPhase] = useState("idle"); const [error, setError] = useState(null); const canSubmit = message.trim().length > 0 && phase !== "submitting"; async function handleSubmit() { if (!canSubmit) return; setPhase("submitting"); setError(null); try { await submitSupport({ kind, message: message.trim(), category: category || null, title: showTitleField ? titleValue.trim() || null : null, rating: showRating ? rating : null, page_url: typeof window !== "undefined" ? window.location.href : null, }); setPhase("done"); } catch (err) { // Never expose an internal payload — a plain, retryable message only. const status = isApiError(err) ? err.status : null; if (status === 429) { setError("You've sent a few messages in a short time. Please wait a minute and try again — your text is still here."); } else if (status === 422) { setError("Please add a bit more detail to your message before sending."); } else { setError("We could not send that just now. Check your connection and try again — your text is still here."); } setPhase("error"); } } if (phase === "done") { return (

Thank you — we received it

{kind === "bug" ? "Your report is saved. The team reviews bug reports during the beta and will act on the clear ones first." : "Your feedback is saved. Real student feedback is what shapes what DocDoe builds next."}

Back to DocDoe
); } return (
DocDoe

{eyebrow}

{title}

{intro}

{ event.preventDefault(); void handleSubmit(); }} > {categories && categories.length > 0 ? (
Category
{categories.map((item) => ( ))}
) : null} {showTitleField ? ( ) : null} {showRating ? (
Rating (optional)
{[1, 2, 3, 4, 5].map((value) => ( ))}
) : null}