71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
type Wanted = {
|
|
id: string;
|
|
artistName: string;
|
|
album: string;
|
|
state: string;
|
|
currentQualityClass: number | null;
|
|
lastSearchedAt: string | null;
|
|
};
|
|
|
|
export function WantedClient() {
|
|
const [rows, setRows] = useState<Wanted[]>([]);
|
|
const [artist, setArtist] = useState("");
|
|
const [album, setAlbum] = useState("");
|
|
const [error, setError] = useState("");
|
|
|
|
async function refresh() {
|
|
const res = await fetch("/api/wanted");
|
|
setRows((await res.json()).wanted);
|
|
}
|
|
useEffect(() => {
|
|
refresh();
|
|
}, []);
|
|
|
|
async function add(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
setError("");
|
|
if (!artist.trim() || !album.trim()) return;
|
|
const res = await fetch("/api/wanted", {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({ artist, album }),
|
|
});
|
|
if (!res.ok) {
|
|
setError((await res.json()).error ?? "failed to add");
|
|
return;
|
|
}
|
|
setArtist("");
|
|
setAlbum("");
|
|
refresh();
|
|
}
|
|
|
|
async function searchNow(w: Wanted) {
|
|
await fetch(`/api/releases/${w.id}/search`, { method: "POST" });
|
|
refresh();
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<form onSubmit={add}>
|
|
<input aria-label="wanted artist" placeholder="Artist" value={artist} onChange={(e) => setArtist(e.target.value)} />
|
|
<input aria-label="wanted album" placeholder="Album" value={album} onChange={(e) => setAlbum(e.target.value)} />
|
|
<button type="submit">Add to wanted</button>
|
|
{error ? <span> {error}</span> : null}
|
|
</form>
|
|
<ul>
|
|
{rows.map((w) => (
|
|
<li key={w.id}>
|
|
{w.artistName} — {w.album} · <em>{w.currentQualityClass !== null ? `have q${w.currentQualityClass}, upgrading` : w.state}</em>
|
|
{w.lastSearchedAt ? ` · last tried ${new Date(w.lastSearchedAt).toLocaleString()}` : " · never tried"}{" "}
|
|
<button onClick={() => searchNow(w)}>Search now</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|