From 8085ed719f1d4ad69078eee38e29e91d67ee1adb Mon Sep 17 00:00:00 2001 From: Jonathan Date: Fri, 10 Jul 2026 16:53:07 +0200 Subject: [PATCH] feat: add request form and live queue UI --- web/src/app/page.tsx | 9 ++++++- web/src/app/queue.tsx | 60 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 web/src/app/queue.tsx diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 3b2094a..bf3af1b 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,3 +1,10 @@ +import { Queue } from "./queue"; + export default function Home() { - return
Lyra
; + return ( +
+

Lyra

+ +
+ ); } diff --git a/web/src/app/queue.tsx b/web/src/app/queue.tsx new file mode 100644 index 0000000..cc2b566 --- /dev/null +++ b/web/src/app/queue.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { useEffect, useState } from "react"; + +type Row = { + id: string; + artist: string; + album: string; + status: string; + job: { state: string; currentStage: string } | null; +}; + +export function Queue() { + const [rows, setRows] = useState([]); + const [artist, setArtist] = useState(""); + const [album, setAlbum] = useState(""); + + async function refresh() { + const res = await fetch("/api/requests"); + const body = await res.json(); + setRows(body.requests); + } + + useEffect(() => { + refresh(); + const id = setInterval(refresh, 2000); + return () => clearInterval(id); + }, []); + + async function submit(e: React.FormEvent) { + e.preventDefault(); + if (!artist.trim() || !album.trim()) return; + await fetch("/api/requests", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ artist, album }), + }); + setArtist(""); + setAlbum(""); + refresh(); + } + + return ( +
+
+ setArtist(e.target.value)} /> + setAlbum(e.target.value)} /> + +
+
    + {rows.map((r) => ( +
  • + {r.artist} — {r.album} · {r.job?.state ?? r.status} + {r.job ? ` (${r.job.currentStage})` : ""} +
  • + ))} +
+
+ ); +}