diff --git a/packages/frontend/src/pages/Marketplace.tsx b/packages/frontend/src/pages/Marketplace.tsx new file mode 100644 index 0000000..d15fa53 --- /dev/null +++ b/packages/frontend/src/pages/Marketplace.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { motion } from 'framer-motion'; +import { marketplaceApi, type MarketplaceListResponse } from '../api/marketplace.js'; +import { lessonsApi } from '../api/lessons.js'; +import { ApiClientError } from '../api/client.js'; + +export function MarketplacePage() { + const [data, setData] = useState({ rows: [], total: 0 }); + const [q, setQ] = useState(''); + const [curatedOnly, setCuratedOnly] = useState(false); + const [busy, setBusy] = useState(false); + const [error, setError] = useState(null); + const navigate = useNavigate(); + + async function refresh() { + setBusy(true); setError(null); + try { + const r = await marketplaceApi.list({ q: q.trim() || undefined, curated: curatedOnly ? true : undefined }); + setData(r); + } catch (e) { + setError(e instanceof ApiClientError ? e.message : 'Kon marketplace niet laden.'); + } finally { setBusy(false); } + } + + useEffect(() => { refresh(); }, [curatedOnly]); + + async function subscribe(id: number) { + try { await lessonsApi.subscribe(id); await refresh(); } + catch (e) { alert(e instanceof ApiClientError ? e.message : 'Abonneren mislukt'); } + } + + async function fork(id: number) { + try { + const f = await lessonsApi.fork(id); + navigate(`/admin/lessons/${f.id}`); + } + catch (e) { alert(e instanceof ApiClientError ? e.message : 'Forken mislukt'); } + } + + return ( +
+
+

Marketplace 🛍️

+

Vind trainingen van andere gebruikers en officiële beheerderscontent.

+
+ +
+ setQ(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && refresh()} + /> + + +
+ + {error &&

{error}

} + + {data.rows.length === 0 && !busy ? ( +
Geen lessen gevonden.
+ ) : ( +
    + {data.rows.map((l, i) => ( + +
    + {l.isCurated && ⭐ Curated} + {l.isFork && 🍴 Fork} +
    +

    {l.name}

    +

    {l.description ?? geen beschrijving}

    +
    + door {l.ownerDisplayName} + {l.totalCards} kaarten · {l.subscribersCount} abonnees +
    +
    + + +
    +
    + ))} +
+ )} +
+ ); +}