import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import Layout from '../components/Layout'; import { fetchAll } from '../lib/api'; import { STATUS_COLORS } from '../lib/tables'; const TILES = [ { title: 'Content erstellen', icon: '✏️', description: 'Objekte markieren, Pairs & Sätze erstellen und prüfen.', path: '/content', color: 'border-amber-200 hover:border-amber-400 hover:bg-amber-50', }, { title: 'Audio / TTS', icon: '🔊', description: 'Sehen was noch kein Audio hat und Sprachausgabe generieren.', path: '/audio', color: 'border-purple-200 hover:border-purple-400 hover:bg-purple-50', }, { title: 'Wörter generieren', icon: '🪄', description: 'Neue Wörter zu einem Thema per KI erzeugen lassen.', path: '/content/words', color: 'border-emerald-200 hover:border-emerald-400 hover:bg-emerald-50', }, { title: 'Veröffentlichen', icon: '🚀', description: 'Fast fertige Inhalte sehen und mit einem Klick live schalten.', path: '/publish', color: 'border-violet-200 hover:border-violet-400 hover:bg-violet-50', }, { title: 'Datenbankverwaltung', icon: '🗄️', description: 'Alle Tabellen, Datensätze, Filter und verknüpfte Felder.', path: '/db', color: 'border-indigo-200 hover:border-indigo-400 hover:bg-indigo-50', }, { title: 'Einstellungen', icon: '⚙️', description: 'TTS-Stimmen pro Sprache und weitere Konfiguration.', path: '/settings', color: 'border-slate-200 hover:border-slate-400 hover:bg-slate-100', }, ]; // Pipeline-Stufen, die den Lebenszyklus eines Inhalts abbilden. const PIPELINES = [ { key: 'pictures', label: 'Bilder', endpoint: '/pictures', stages: ['uploaded', 'published', 'blocked'] }, { key: 'objects', label: 'Objekte', endpoint: '/objects', stages: ['draft', 'reviewed', 'published', 'blocked'] }, { key: 'pairs', label: 'Pairs', endpoint: '/pairs', stages: ['draft', 'reviewed', 'published', 'blocked'] }, { key: 'words', label: 'Wörter', endpoint: '/words', stages: ['requested', 'translated', 'generated', 'published', 'blocked'] }, { key: 'audios', label: 'Audios', endpoint: '/audios', stages: ['generated', 'published', 'blocked'] }, ]; function countByStatus(rows) { const out = {}; for (const r of rows || []) out[r.status] = (out[r.status] || 0) + 1; return out; } export default function Dashboard() { const navigate = useNavigate(); const [counts, setCounts] = useState(null); useEffect(() => { let active = true; (async () => { const entries = await Promise.all( PIPELINES.map(async p => { try { return [p.key, countByStatus(await fetchAll(p.endpoint))]; } catch { return [p.key, {}]; } }) ); if (active) setCounts(Object.fromEntries(entries)); })(); return () => { active = false; }; }, []); return (

Dashboard

Der Inhalts-Lebenszyklus: draft (erstellt) → reviewed (im Tool geprüft) →{' '} published (fertig inkl. Audio, in der App sichtbar). Nur veröffentlichte Inhalte mit Bild und Audio erscheinen für Lernende.

{/* Pipeline-Übersicht */}

Pipeline-Übersicht

{PIPELINES.map(p => (
{p.label}
{p.stages.map(stage => { const n = counts?.[p.key]?.[stage] ?? null; const cls = STATUS_COLORS[stage] || 'bg-gray-100 text-gray-600'; return ( {stage}: {counts ? (n ?? 0) : '…'} ); })}
))}

Zählung bis max. 500 pro Tabelle.

{/* Werkzeuge */}
{TILES.map(tile => (
navigate(tile.path)} className={`bg-white rounded-2xl border-2 p-6 transition-all cursor-pointer ${tile.color}`} >
{tile.icon}

{tile.title}

{tile.description}

))}
); }