SPB Git

Repository Public

ReportForm.tsx 2.2 KB 30 lines tsx

1"use client";23import { useState } from "react";45interface L { film: string; reason: string; detail: string; contact: string; send: string; thanks: string; reasons: Record<string, string>; error: string; limit: string }6export function ReportForm({ labels, film }: { labels: L; film: string }) {7  const [state, setState] = useState<"idle" | "sending" | "done" | "error" | "limit">("idle");8  async function submit(e: React.FormEvent<HTMLFormElement>) {9    e.preventDefault();10    const d = Object.fromEntries(new FormData(e.currentTarget));11    if (String(d.detail ?? "").trim().length < 8) { setState("error"); return; }12    setState("sending");13    const r = await fetch("/api/reports", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(d) }).catch(() => null);14    setState(r?.ok ? "done" : r?.status === 429 ? "limit" : "error");15  }16  if (state === "done") return <p className="card p-6" role="status">{labels.thanks}</p>;17  return (18    <form onSubmit={submit} className="space-y-4" noValidate>19      <div><label htmlFor="rf" className="label">{labels.film}</label><input id="rf" name="film" defaultValue={film} className="field mt-1" maxLength={200} /></div>20      <div><label htmlFor="rr" className="label">{labels.reason}</label>21        <select id="rr" name="reason" className="field mt-1">{Object.entries(labels.reasons).map(([k, v]) => <option key={k} value={k}>{v}</option>)}</select></div>22      <div><label htmlFor="rd" className="label">{labels.detail}</label><textarea id="rd" name="detail" rows={5} className="field mt-1" maxLength={2000} required aria-describedby="rerr" /></div>23      <div><label htmlFor="rc" className="label">{labels.contact}</label><input id="rc" name="contact" type="email" className="field mt-1" maxLength={200} autoComplete="email" /></div>24      <input type="text" name="website" tabIndex={-1} autoComplete="off" className="hidden" aria-hidden="true" />25      <p id="rerr" role="alert" className="min-h-5 text-sm text-[var(--color-bad)]">{state === "error" ? labels.error : state === "limit" ? labels.limit : ""}</p>26      <button type="submit" className="btn btn-primary" disabled={state === "sending"}>{labels.send}</button>27    </form>28  );29}30
Files main
Menu

Theme