export type PersonMini = { personId: number; name: string; birthDate: string | null; imageUrl?: string | null; }; export type PersonHistoryRecord = { seasonId: number; showId: number; startDate: string | null; endDate: string | null; seasonNumber: number; partner: PersonMini | null; seasonParticipants: (PersonMini & { partner?: PersonMini | null })[]; }; type RawSeasonNew = { seasonId: number; showId?: number; show?: number; seasonNumber: number; startDate: string | null; endDate: string | null; partner?: { personId: number; name: string; birthDate?: string | null; imageUrl?: string | null; } | null; seasonParticipants?: { personId: number; name: string; birthDate?: string | null; imageUrl?: string | null; }[]; }; type RawPersonOld = { personId: number; name: string; birthDate?: string | null; imageUrl?: string | null; }; type RawSeasonOld = { seasonId: number; show?: number; showId?: number; seasonNumber: number; startDate: string | null; endDate: string | null; seasonParticipants?: | { id?: { seasonId?: number; personId?: number }; person?: RawPersonOld | null; partner?: RawPersonOld | null; }[] | null; }; const PERSONS_BASE_URL = "https://fltr-app.de/api/persons"; function toMini(p: any | undefined | null): PersonMini | null { if (!p || !p.personId || !p.name) return null; return { personId: Number(p.personId), name: String(p.name), birthDate: p.birthDate ?? null, imageUrl: p.imageUrl ?? null, }; } function isFlatSeason(s: any): s is RawSeasonNew { const sp = s?.seasonParticipants; return Array.isArray(sp) && (sp.length === 0 || "personId" in (sp[0] ?? {})); } function mapSeason( s: RawSeasonNew | RawSeasonOld, requestedPersonId: number ): PersonHistoryRecord { const showId = Number((s as any).showId ?? (s as any).show ?? 0) || 0; const base = { seasonId: s.seasonId, showId, startDate: s.startDate ?? null, endDate: s.endDate ?? null, seasonNumber: s.seasonNumber, }; if (isFlatSeason(s)) { const seasonParticipants = Array.isArray(s.seasonParticipants) ? s.seasonParticipants .map((p) => toMini(p)) .filter((x): x is PersonMini => !!x) : []; const partner = toMini(s.partner ?? null); return { ...base, partner, seasonParticipants, }; } const spOld = (s as RawSeasonOld).seasonParticipants; const seasonParticipantsOld = Array.isArray(spOld) ? spOld .map((p) => { const pid = p.person?.personId ?? p.id?.personId; const name = p.person?.name ?? null; if (!pid || !name) return null; const me: PersonMini = { personId: Number(pid), name: String(name), birthDate: p.person?.birthDate ?? null, imageUrl: p.person?.imageUrl ?? null, }; const partnerMini = toMini(p.partner ?? null); return { ...me, partner: partnerMini, }; }) .filter((x): x is NonNullable => !!x) : []; const me = seasonParticipantsOld.find((pp) => pp.personId === requestedPersonId) || null; const partner = (me?.partner ?? null) as PersonMini | null; return { ...base, partner, seasonParticipants: seasonParticipantsOld, }; } export async function getPersonHistory( personId: number, signal?: AbortSignal ): Promise { const apiKey = process.env.EXPO_PUBLIC_API_KEY; const url = `${PERSONS_BASE_URL}/${personId}/history`; const res = await fetch(url, { signal, headers: { "Content-Type": "application/json", "X-API-Key": apiKey ?? "", }, }); if (!res.ok) throw new Error("GetPersonHistory failed " + res.status); const data: unknown = await res.json(); if (!Array.isArray(data)) return []; return (data as (RawSeasonNew | RawSeasonOld)[]).map((s) => mapSeason(s, personId) ); }