From 21376fd1b48389a05a8e6a0977c1afd7eae8eea3 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 29 Jun 2026 14:10:57 +0000 Subject: [PATCH] Add Create form with subject input and status polling --- src/app/create/CreateForm.tsx | 131 ++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/app/create/CreateForm.tsx diff --git a/src/app/create/CreateForm.tsx b/src/app/create/CreateForm.tsx new file mode 100644 index 0000000..e883039 --- /dev/null +++ b/src/app/create/CreateForm.tsx @@ -0,0 +1,131 @@ +"use client"; +import { useEffect, useRef, useState } from "react"; +import Link from "next/link"; + +type Phase = "idle" | "submitting" | "generating" | "review" | "ready" | "failed"; + +export default function CreateForm({ level: initialLevel, enabled }: { level: string; enabled: boolean }) { + const [level, setLevel] = useState(initialLevel); + const [subject, setSubject] = useState(""); + const [phase, setPhase] = useState("idle"); + const [msg, setMsg] = useState(""); + const [slug, setSlug] = useState(""); + const poll = useRef | undefined>(undefined); + + useEffect(() => () => clearInterval(poll.current), []); + + async function start(e: React.FormEvent) { + e.preventDefault(); + setMsg(""); + setSlug(""); + setPhase("submitting"); + try { + const res = await fetch("/api/create", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ level, subject }), + }); + const data = await res.json(); + if (!res.ok) { + setPhase("failed"); + setMsg(data.error || "Something went wrong."); + return; + } + if (data.status === "needs_review") { + setPhase("review"); + return; + } + setSlug(data.slug); + setPhase("generating"); + watch(data.id, data.slug); + } catch { + setPhase("failed"); + setMsg("Couldn't reach the server."); + } + } + + function watch(id: number, baseSlug: string) { + clearInterval(poll.current); + poll.current = setInterval(async () => { + try { + const r = await fetch(`/api/create/${id}`); + const d = await r.json(); + if (d.status === "ready") { + clearInterval(poll.current); + setSlug(baseSlug); + setPhase("ready"); + } else if (d.status === "failed" || d.status === "blocked") { + clearInterval(poll.current); + setPhase("failed"); + setMsg(d.error || "The drawing couldn't be made. Try a different subject."); + } + } catch { + /* keep polling */ + } + }, 2500); + } + + if (!enabled) { + return ( +
+

+ The Create feature isn't turned on for this DrawIt instance yet. Ask your administrator to configure a + drawing server (ComfyUI). +

+
+ ); + } + + const busy = phase === "submitting" || phase === "generating"; + + return ( +
+
+ + + +
+ + {phase === "generating" && ( +
+

🎨 Drawing your {subject || "picture"}… this can take a little while.

+

You can stay on this page.

+
+ )} + {phase === "review" && ( +
+

📨 Thanks! "{subject}" was sent to a grown-up to approve. Check back soon.

+
+ )} + {phase === "ready" && ( +
+

🎉 Your lesson is ready!

+ Start drawing +
+ )} + {phase === "failed" && ( +
+

{msg || "Something went wrong. Try a different subject."}

+
+ )} +
+ ); +}