"use client"; import { useCallback, useEffect, useState } from "react"; import Header from "@/components/Header"; import GenerationCard from "@/components/GenerationCard"; import type { GenerationJob, GenerationsListResponse } from "@/lib/types/generation"; const PAGE_SIZE = 24; export default function LibraryPage() { const [jobs, setJobs] = useState([]); const [offset, setOffset] = useState(0); const [hasMore, setHasMore] = useState(true); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchJobs = useCallback(async (currentOffset: number, replace: boolean) => { setLoading(true); setError(null); try { const res = await fetch( `/api/generations?limit=${PAGE_SIZE}&offset=${currentOffset}`, { cache: "no-store" } ); if (!res.ok) throw new Error(`Server returned ${res.status}`); const data = (await res.json()) as GenerationsListResponse; setJobs((prev) => (replace ? data.items : [...prev, ...data.items])); setHasMore(data.items.length === PAGE_SIZE); } catch (err) { setError(err instanceof Error ? err.message : "Failed to load generations"); } finally { setLoading(false); } }, []); useEffect(() => { fetchJobs(0, true); }, [fetchJobs]); function handleDelete(id: string) { setJobs((prev) => prev.filter((j) => j.id !== id)); } function handleLoadMore() { const next = offset + PAGE_SIZE; setOffset(next); fetchJobs(next, false); } return (
{/* Page header */}

Generation Library

Every completed generation is saved here.

+ New Generation
{/* Error state */} {error && (
{error} —{" "}
)} {/* Empty state */} {!loading && jobs.length === 0 && !error && (

🎙

No generations yet

Generate some audio and it will appear here automatically.

Go generate something
)} {/* Grid */} {jobs.length > 0 && (
{jobs.map((job) => ( ))}
)} {/* Load more */} {hasMore && !loading && jobs.length > 0 && (
)} {/* Loading spinner */} {loading && (
Loading…
)}
); }