"use client"; import { useMemo, useState } from "react"; import { ChevronDown, History, Loader2 } from "lucide-react"; import { ActivityDayGroups } from "@/components/ActivityRow"; import { tagesschluessel } from "@/lib/review"; import type { ReviewDay, ReviewEntry } from "@/types"; /** * Die fortlaufende Zeitleiste. * * Client-Komponente, weil hier nachgeladen wird – das ist der Unterschied * zum Wochenrueckblick, der komplett auf dem Server entsteht. * * Die Buendelung nach Tagen passiert hier im Browser. Das ist unbedenklich, * weil tagesschluessel eine feste Zeitzone benutzt: Server und Browser kommen * damit auf denselben Kalendertag, und die erste Seite hydriert ohne * Abweichung. */ export function Timeline({ erste, weitere: gabWeitere, }: { erste: ReviewEntry[]; weitere: boolean; }) { const [eintraege, setEintraege] = useState(erste); const [weitere, setWeitere] = useState(gabWeitere); const [laedt, setLaedt] = useState(false); const [fehler, setFehler] = useState(null); const tage: ReviewDay[] = useMemo(() => { // Map behaelt die Einfuegereihenfolge – die Eintraege kommen schon // absteigend, also stimmt die Reihenfolge der Tage von selbst. const nachTag = new Map(); for (const eintrag of eintraege) { const schluessel = tagesschluessel(new Date(eintrag.createdAt)); const liste = nachTag.get(schluessel) ?? []; liste.push(eintrag); nachTag.set(schluessel, liste); } return [...nachTag.entries()].map(([tag, liste]) => ({ tag, eintraege: liste })); }, [eintraege]); async function mehr() { const letzter = eintraege[eintraege.length - 1]; if (!letzter) return; setLaedt(true); setFehler(null); try { const antwort = await fetch( `/api/activity?vor=${encodeURIComponent(letzter.createdAt)}&id=${encodeURIComponent(letzter.id)}`, ); if (!antwort.ok) throw new Error("Verlauf konnte nicht geladen werden."); const nutzlast = (await antwort.json()) as { activities: ReviewEntry[]; weitere: boolean; }; /** * Gegen Dubletten absichern, auch wenn der Cursor sie ausschliesst: * ein zweimal gedrueckter Knopf oder ein wiederholter Aufruf soll * keine Zeile verdoppeln, und React braucht eindeutige Schluessel. */ setEintraege((bisher) => { const bekannt = new Set(bisher.map((eintrag) => eintrag.id)); return [...bisher, ...nutzlast.activities.filter((eintrag) => !bekannt.has(eintrag.id))]; }); setWeitere(nutzlast.weitere); } catch (gefangen) { setFehler(gefangen instanceof Error ? gefangen.message : String(gefangen)); } finally { setLaedt(false); } } if (eintraege.length === 0) { return (

Noch kein Verlauf

Sobald du ein Projekt anlegst, Aufgaben verschiebst oder Notizen schreibst, steht es hier.

); } return (
{/* Die Jahreszahl gehoert dazu: eine Zeitleiste reicht weit zurueck, und "3. Januar" allein sagt dann nicht genug. */} {fehler ? (

{fehler}

) : null}
{weitere ? ( ) : (

Das war alles.

)}

{eintraege.length} {eintraege.length === 1 ? "Vorgang" : "Vorgänge"} geladen

); }