import React, { createContext, useCallback, useContext, useState, ReactNode, } from "react"; import { getPersonHistory, PersonHistoryEntry } from "@/apis/personApi"; type PersonAppearances = { raw: PersonHistoryEntry[]; byShow: Record; showIds: number[]; }; type PersonContextType = { getPersonAppearances: (personId: number) => Promise; getShowIds: (personId: number) => Promise; getSeasonsForShow: (personId: number, showId: number) => Promise; isLoading: (personId: number) => boolean; getError: (personId: number) => string | null; invalidatePerson: (personId: number) => void; }; const PersonContext = createContext(null); export const PersonProvider = ({ children }: { children: ReactNode }) => { const [cache, setCache] = useState>({}); const [loading, setLoading] = useState>({}); const [errors, setErrors] = useState>({}); const buildAppearances = ( entries: PersonHistoryEntry[] ): PersonAppearances => { const byShow: Record> = {}; for (const e of entries) { if (!byShow[e.showId]) byShow[e.showId] = new Set(); byShow[e.showId].add(e.seasonNumber); } const byShowSorted: Record = Object.fromEntries( Object.entries(byShow).map(([showId, seasonsSet]) => [ Number(showId), Array.from(seasonsSet).sort((a, b) => a - b), ]) ); return { raw: entries, byShow: byShowSorted, showIds: Object.keys(byShowSorted) .map(Number) .sort((a, b) => a - b), }; }; const fetchAndCache = useCallback(async (personId: number) => { setLoading((l) => ({ ...l, [personId]: true })); setErrors((e) => ({ ...e, [personId]: null })); try { const data = await getPersonHistory(personId); const appearances = buildAppearances(data); setCache((c) => ({ ...c, [personId]: appearances })); return appearances; } catch (e: any) { setErrors((err) => ({ ...err, [personId]: e?.message || "Fehler beim Laden", })); return { raw: [], byShow: {}, showIds: [] }; } finally { setLoading((l) => ({ ...l, [personId]: false })); } }, []); const getPersonAppearances = useCallback( async (personId: number) => { if (cache[personId]) return cache[personId]; return await fetchAndCache(personId); }, [cache, fetchAndCache] ); const getShowIds = useCallback( async (personId: number) => { const app = await getPersonAppearances(personId); return app.showIds; }, [getPersonAppearances] ); const getSeasonsForShow = useCallback( async (personId: number, showId: number) => { const app = await getPersonAppearances(personId); return app.byShow[showId] || []; }, [getPersonAppearances] ); const isLoading = (personId: number) => !!loading[personId]; const getError = (personId: number) => errors[personId] || null; const invalidatePerson = (personId: number) => { setCache((c) => { const copy = { ...c }; delete copy[personId]; return copy; }); }; return ( {children} ); }; export const usePersonContext = () => { const ctx = useContext(PersonContext); if (!ctx) throw new Error("usePersonContext must be used within PersonProvider"); return ctx; };