CommentForm
uses localStorage
Comment on a contribution, or on one of its definitions (fixed); the maintainer signs with a name.
import { actOn, Chevron, toasts } from "#codebase/tcmts/share"; import { useEffect, useState } from "react"; import { Button, Form, Input, ListBox, ListBoxItem, Popover, Select, SelectValue, TextArea, TextField, } from "react-aria-components"; export function CommentForm({ id, about, fixed, named, as, }: { id: number; about: string[]; fixed?: string; named: boolean; as?: string; }) { const [body, setBody] = useState(""); const [on, setOn] = useState(fixed ?? ""); const [name, setName] = useState(""); const [busy, setBusy] = useState(false); useEffect(() => setName(localStorage.getItem("tcm.author") ?? ""), []); const whole = "(the whole change)"; return ( <Form className="say" id={fixed ? undefined : "comment"} onSubmit={async (e) => { e.preventDefault(); setBusy(true); try { if (named) localStorage.setItem("tcm.author", name); await actOn(id, "comment", { body, about: on || null, name }); setBody(""); toasts.add({ title: "Comment added", tone: "ok" }, { timeout: 3000 }); } catch (err) { toasts.add( { title: "Couldn't comment", description: (err as Error).message, tone: "bad" }, { timeout: 8000 }, ); } setBusy(false); }} > <TextField aria-label={fixed ? `Comment on ${fixed}` : "Comment"} value={body} onChange={setBody} isRequired > <TextArea placeholder={ fixed ? `Comment on ${fixed.slice(fixed.lastIndexOf(".") + 1)}` : "Leave a comment" } /> </TextField> <div className="row"> {!fixed && about.length > 0 && ( <Select aria-label="What it's about" className="select" value={on || whole} onChange={(k) => setOn(k === whole || k === null ? "" : String(k))} > <Button className="btn select-btn"> <SelectValue /> <Chevron /> </Button> <Popover className="menu-pop" placement="bottom start" offset={4}> <ListBox className="menu" items={[whole, ...about].map((n) => ({ id: n }))}> {(o) => ( <ListBoxItem id={o.id} className="opt"> {o.id === whole ? "about the whole change" : `about ${o.id}`} </ListBoxItem> )} </ListBox> </Popover> </Select> )} {named ? ( <TextField aria-label="Your name" value={name} onChange={setName} isRequired> <Input className="field" placeholder="Your name" /> </TextField> ) : ( <span className="muted">as {as}</span> )} <Button type="submit" className="btn primary" isPending={busy}> Comment </Button> </div> </Form> ); }