update: gemini fixes

This commit is contained in:
Yordan Simeonov
2025-10-29 20:50:21 +11:00
parent 04a44bad7b
commit 9725d8bff1
23 changed files with 473 additions and 647 deletions

13
hooks/useAutoComplete.ts Normal file
View File

@@ -0,0 +1,13 @@
import { useQuery } from "@tanstack/react-query";
import { getAutoComplete } from "@/apis/autoCompleteApi";
import { useDebounce } from "./useDebounce";
export const useAutoComplete = (query: string) => {
const debouncedQuery = useDebounce(query, 300);
return useQuery({
queryKey: ["autoComplete", debouncedQuery],
queryFn: () => getAutoComplete(debouncedQuery),
enabled: !!debouncedQuery,
});
};

17
hooks/useDebounce.ts Normal file
View File

@@ -0,0 +1,17 @@
import { useState, useEffect } from 'react';
export const useDebounce = <T>(value: T, delay: number): T => {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};

87
hooks/usePersonHistory.ts Normal file
View File

@@ -0,0 +1,87 @@
import { useQuery } from "@tanstack/react-query";
import { getPersonHistory, PersonHistoryRecord, PersonMini } from "@/apis/personHistoryApi";
import { getShowById, Show } from "@/apis/showApi";
type SeasonEntry = {
seasonNumber: number;
partner: PersonMini | null;
participants: PersonMini[];
startDate: string | null;
};
export type AppearanceGroup = {
show: Show;
seasons: SeasonEntry[];
};
export const usePersonHistory = (personId: number) => {
return useQuery({
queryKey: ["personHistory", personId],
queryFn: async () => {
const history = await getPersonHistory(personId);
const grouped = new Map<number, Map<number, SeasonEntry>>();
for (const h of history) {
if (!Number.isFinite(h.showId) || h.showId <= 0) continue;
const seasonsForShow =
grouped.get(h.showId) ?? new Map<number, SeasonEntry>();
const existing = seasonsForShow.get(h.seasonNumber);
if (existing) {
seasonsForShow.set(h.seasonNumber, {
seasonNumber: h.seasonNumber,
partner: existing.partner ?? h.partner ?? null,
participants: existing.participants.length
? existing.participants
: (h.seasonParticipants ?? []),
startDate: existing.startDate ?? h.startDate ?? null,
});
} else {
seasonsForShow.set(h.seasonNumber, {
seasonNumber: h.seasonNumber,
partner: h.partner ?? null,
participants: h.seasonParticipants ?? [],
startDate: h.startDate ?? null,
});
}
grouped.set(h.showId, seasonsForShow);
}
const showIds = Array.from(grouped.keys());
const shows = await Promise.all(
showIds.map(async (id) => {
try {
const s = await getShowById(id);
return s;
} catch {
return null;
}
})
);
const validShows = shows.filter((s): s is Show => !!s);
const result: AppearanceGroup[] = validShows.map((s) => {
const seasonsMap = grouped.get(s.id)!;
const seasonsSorted = Array.from(seasonsMap.values()).sort(
(a, b) => a.seasonNumber - b.seasonNumber
);
return {
show: s,
seasons: seasonsSorted,
};
});
result.sort((a, b) =>
a.show.title.localeCompare(b.show.title, "de", {
sensitivity: "base",
})
);
return result;
},
enabled: !!personId,
});
};

10
hooks/useSearch.ts Normal file
View File

@@ -0,0 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import { getSearchResults } from "@/apis/searchApi";
export const useSearch = (tags: string[]) => {
return useQuery({
queryKey: ["search", tags],
queryFn: () => getSearchResults(tags),
enabled: tags.length > 0,
});
};

50
hooks/useSeason.ts Normal file
View File

@@ -0,0 +1,50 @@
import { useQuery } from "@tanstack/react-query";
import { getSeason } from "@/apis/seasonApi";
export const useSeason = (showId: number, seasonNumber: number) => {
return useQuery({
queryKey: ["season", showId, seasonNumber],
queryFn: () => getSeason(showId, seasonNumber),
enabled: !!showId && !!seasonNumber,
});
};
export const useSeasonParticipants = (showId: number, seasonNumber: number) => {
const { data: season, ...rest } = useSeason(showId, seasonNumber);
return {
data: season?.participants ?? [],
...rest,
};
};
export const useSeasonDates = (showId: number, seasonNumber: number) => {
const { data: season, ...rest } = useSeason(showId, seasonNumber);
return {
data: season ? { startDate: season.startDate, endDate: season.endDate } : null,
...rest,
};
};
// This is a bit tricky, as we need to fetch seasons sequentially to know the count.
// React Query is not ideal for this kind of sequential fetching.
// However, we can still wrap the existing logic in a useQuery hook.
// This is not the most efficient way, but it's better than nothing.
export const useSeasonCount = (showId: number) => {
return useQuery({
queryKey: ["seasonCount", showId],
queryFn: async () => {
let n = 0;
for (let s = 1; s <= 50; s++) {
try {
const season = await getSeason(showId, s);
if (!season) break;
n = s;
} catch {
break;
}
}
return n;
},
enabled: !!showId,
});
};

10
hooks/useShow.ts Normal file
View File

@@ -0,0 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import { getShowById } from "@/apis/showApi";
export const useShow = (showId: number) => {
return useQuery({
queryKey: ["show", showId],
queryFn: () => getShowById(showId),
enabled: !!showId,
});
};

9
hooks/useShows.ts Normal file
View File

@@ -0,0 +1,9 @@
import { useQuery } from "@tanstack/react-query";
import { getShows } from "@/apis/showApi";
export const useShows = () => {
return useQuery({
queryKey: ["shows"],
queryFn: getShows,
});
};

View File

@@ -0,0 +1,13 @@
import { useQuery } from "@tanstack/react-query";
import { getStreamingImages, StreamingServiceRaw } from "@/apis/streamingServiceApi";
export const useStreamingServices = () => {
return useQuery({
queryKey: ["streamingServices"],
queryFn: async () => {
const data: StreamingServiceRaw[] = await getStreamingImages();
const mapped = Object.fromEntries(data.map((s) => [s.key, s.value]));
return mapped;
},
});
};