fix: SSR pour les providers cachés dans MetadataSearchModal

Les metadata providers sont récupérés côté serveur et les providers
sans API key sont passés en prop initialHiddenProviders, supprimant
le fetch client useEffect qui causait un layout shift.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 09:13:38 +01:00
parent e7295a371d
commit e078b0029f
2 changed files with 9 additions and 16 deletions

View File

@@ -41,7 +41,7 @@ export default async function SeriesDetailPage({
const seriesName = decodeURIComponent(name);
const [library, booksPage, seriesMeta, metadataLinks, readingStatusLink, prowlarrConfigured, qbConfigured] = await Promise.all([
const [library, booksPage, seriesMeta, metadataLinks, readingStatusLink, prowlarrConfigured, qbConfigured, metadataProviders] = await Promise.all([
fetchLibraries().then((libs) => libs.find((l) => l.id === id)),
fetchBooks(id, seriesName, page, limit).catch(() => ({
items: [] as BookDto[],
@@ -58,8 +58,12 @@ export default async function SeriesDetailPage({
apiFetch<{ url?: string; username?: string }>("/settings/qbittorrent")
.then(d => !!(d?.url?.trim() && d?.username?.trim()))
.catch(() => false),
apiFetch<{ comicvine?: { api_key?: string } }>("/settings/metadata_providers").catch(() => null),
]);
const hiddenProviders: string[] = [];
if (!metadataProviders?.comicvine?.api_key) hiddenProviders.push("comicvine");
const existingLink = metadataLinks.find((l) => l.status === "approved") ?? metadataLinks[0] ?? null;
let missingData: MissingBooksDto | null = null;
if (existingLink && existingLink.status === "approved") {
@@ -249,6 +253,7 @@ export default async function SeriesDetailPage({
seriesName={seriesName}
existingLink={existingLink}
initialMissing={missingData}
initialHiddenProviders={hiddenProviders}
/>
<ReadingStatusModal
libraryId={id}

View File

@@ -27,6 +27,7 @@ interface MetadataSearchModalProps {
seriesName: string;
existingLink: ExternalMetadataLinkDto | null;
initialMissing: MissingBooksDto | null;
initialHiddenProviders?: string[];
}
type ModalStep = "idle" | "searching" | "results" | "confirm" | "syncing" | "done" | "linked";
@@ -36,6 +37,7 @@ export function MetadataSearchModal({
seriesName,
existingLink,
initialMissing,
initialHiddenProviders,
}: MetadataSearchModalProps) {
const { t } = useTranslation();
const router = useRouter();
@@ -61,21 +63,7 @@ export function MetadataSearchModal({
// Provider selector: empty string = library default
const [searchProvider, setSearchProvider] = useState("");
const [activeProvider, setActiveProvider] = useState("");
const [hiddenProviders, setHiddenProviders] = useState<Set<string>>(new Set());
// Fetch metadata provider settings to hide providers without required API keys
useEffect(() => {
fetch("/api/settings/metadata_providers")
.then((r) => r.ok ? r.json() : null)
.then((data) => {
if (!data) return;
const hidden = new Set<string>();
// ComicVine requires an API key
if (!data.comicvine?.api_key) hidden.add("comicvine");
setHiddenProviders(hidden);
})
.catch(() => {});
}, []);
const [hiddenProviders] = useState<Set<string>>(new Set(initialHiddenProviders ?? []));
const visibleProviders = PROVIDERS.filter((p) => !hiddenProviders.has(p.value));