Files
streamrip-ui/frontend/app/basket/page.tsx
T

89 lines
2.9 KiB
TypeScript

"use client";
import Link from "next/link";
import { clearBasket, loadBasket, removeFromBasket, type BasketItem } from "../lib/basket";
import { useEffect, useState } from "react";
export default function BasketPage() {
const [items, setItems] = useState<BasketItem[]>([]);
const [msg, setMsg] = useState("");
const [sending, setSending] = useState(false);
useEffect(() => {
setItems(loadBasket());
}, []);
function remove(item: BasketItem) {
removeFromBasket(item);
setItems(loadBasket());
}
async function checkout() {
if (items.length === 0) return;
setSending(true);
setMsg("");
try {
const r = await fetch("/api/downloads/batch", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
items: items.map((i) => ({ media_type: i.media_type, id: i.id })),
}),
});
if (!r.ok) throw new Error(`Fehler (${r.status})`);
const body = await r.json();
clearBasket();
setItems([]);
setMsg(
`${body.job_ids.length} angelegt — siehe Queue.` +
(body.rejected.length > 0 ? ` ${body.rejected.length} abgelehnt.` : "")
);
} catch (e: unknown) {
setMsg(e instanceof Error ? e.message : "Fehler.");
} finally {
setSending(false);
}
}
return (
<div>
<h1>Sammelkorb ({items.length})</h1>
{msg && <p>{msg}</p>}
{items.length === 0 && (
<p className="muted">
Leer — lege Treffer über „+ Korb“ auf Suche, Artist-, Album- oder Playlist-Seite hier ab.
</p>
)}
{items.length > 0 && (
<div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
<button onClick={checkout} disabled={sending} className="btn btn-primary">
{sending ? "…" : `Alle ${items.length} laden`}
</button>
<button
onClick={() => {
clearBasket();
setItems([]);
}}
className="btn"
>
Leeren
</button>
<Link href="/queue" style={{ alignSelf: "center" }}>Zur Queue →</Link>
</div>
)}
<ol style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 8 }}>
{items.map((i) => (
<li key={`${i.media_type}-${i.id}`} className="card" style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 14px" }}>
<span className="muted" style={{ fontSize: 13, width: 60, flexShrink: 0 }}>{i.media_type}</span>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontWeight: 600 }}>{i.title}</div>
<div className="muted" style={{ fontSize: 13 }}>{i.artist}</div>
</div>
<button onClick={() => remove(i)} className="btn">Entfernen</button>
</li>
))}
</ol>
</div>
);
}