|
1 | 1 | import { useState, useEffect, useCallback } from "react"; |
2 | | -import { getProvidersList, getStructures } from "../../api"; |
| 2 | +import { getProvidersList, getProviderLinks, getStructures } from "../../api"; |
3 | 3 | import OptimadeHeader from "./OptimadeHeader"; |
4 | 4 | import OptimadeFilters from "./OptimadeFilters"; |
5 | 5 | import OptimadeFAQs from "./OptimadeFAQs"; |
@@ -53,51 +53,84 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) { |
53 | 53 |
|
54 | 54 | const providers = providersData?.data ?? []; |
55 | 55 |
|
56 | | - // --- URL → state (registry mode only) --- |
| 56 | + // --- Children from providers list --- |
| 57 | + const { data: childData, isLoading: loadingChildren } = useQuery({ |
| 58 | + queryKey: ["provider-links", selectedProvider?.attributes?.base_url], |
| 59 | + queryFn: () => getProviderLinks(selectedProvider.attributes.base_url), |
| 60 | + enabled: !!selectedProvider?.attributes?.base_url, |
| 61 | + staleTime: Infinity, |
| 62 | + }); |
| 63 | + |
| 64 | + const childEntries = |
| 65 | + childData?.children?.map((c) => ({ |
| 66 | + id: c.id, |
| 67 | + ...(c.attributes ?? {}), |
| 68 | + })) ?? []; |
| 69 | + |
| 70 | + // --- 1. URL → Provider State --- |
57 | 71 | useEffect(() => { |
58 | | - if (isCustom) return; |
59 | | - if (!providers.length || !providerParam) return; |
| 72 | + if (isCustom || !providers.length || !providerParam) return; |
60 | 73 |
|
61 | 74 | const provider = providers.find((p) => p.id === providerParam); |
62 | | - if (provider) setSelectedProvider(provider); |
| 75 | + if (provider && selectedProvider?.id !== provider.id) { |
| 76 | + setSelectedProvider(provider); |
| 77 | + } |
63 | 78 | }, [providers, providerParam, isCustom]); |
64 | 79 |
|
| 80 | + // --- 2. URL → Child State --- |
65 | 81 | useEffect(() => { |
66 | | - if (isCustom) return; |
67 | | - if (!selectedProvider || !dbParam) return; |
| 82 | + if (isCustom || !dbParam || !childEntries.length) return; |
68 | 83 |
|
69 | | - const child = selectedProvider.children?.find((c) => c.id === dbParam); |
70 | | - if (child) setSelectedChild(child); |
71 | | - }, [selectedProvider, dbParam, isCustom]); |
| 84 | + if (selectedChild?.id !== dbParam) { |
| 85 | + const child = childEntries.find((c) => c.id === dbParam); |
| 86 | + if (child) { |
| 87 | + setSelectedChild(child); |
| 88 | + } |
| 89 | + } |
| 90 | + }, [childEntries, dbParam, isCustom]); |
72 | 91 |
|
73 | 92 | // --- state → URL --- |
74 | 93 | useEffect(() => { |
75 | | - // --- CUSTOM MODE --- |
76 | | - if (selectedChild?.id === "__custom__" && selectedChild.base_url) { |
77 | | - setSearchParams({ base_url: selectedChild.base_url }, { replace: true }); |
78 | | - return; |
79 | | - } |
| 94 | + // 1. Determine if we are in Custom Mode |
| 95 | + const isCurrentlyCustom = selectedChild?.id === "__custom__"; |
80 | 96 |
|
81 | | - // --- REGISTRY MODE --- |
82 | | - if (selectedProvider?.id && selectedChild?.id) { |
83 | | - setSearchParams( |
84 | | - { |
85 | | - provider: selectedProvider.id, |
86 | | - db: selectedChild.id, |
87 | | - }, |
88 | | - { replace: true }, |
89 | | - ); |
90 | | - return; |
91 | | - } |
| 97 | + const params = new URLSearchParams(); |
92 | 98 |
|
93 | | - // --- PARTIAL / RESET --- |
94 | | - if (selectedProvider?.id) { |
95 | | - setSearchParams({ provider: selectedProvider.id }, { replace: true }); |
96 | | - return; |
| 99 | + if (isCurrentlyCustom) { |
| 100 | + // Only set base_url, ignore provider/db |
| 101 | + if (selectedChild?.base_url) { |
| 102 | + params.set("base_url", selectedChild.base_url); |
| 103 | + } else if (customUrl) { |
| 104 | + // Keep existing URL param if state hasn't updated yet |
| 105 | + params.set("base_url", customUrl); |
| 106 | + } |
| 107 | + } else { |
| 108 | + // --- REGISTRY MODE --- |
| 109 | + if (selectedProvider?.id) { |
| 110 | + params.set("provider", selectedProvider.id); |
| 111 | + } |
| 112 | + |
| 113 | + if (selectedChild?.id && selectedChild.id !== "__custom__") { |
| 114 | + params.set("db", selectedChild.id); |
| 115 | + } else if (dbParam && !selectedChild && selectedProvider) { |
| 116 | + // PERSIST the db param from URL while the provider's children are loading |
| 117 | + params.set("db", dbParam); |
| 118 | + } |
97 | 119 | } |
98 | 120 |
|
99 | | - setSearchParams({}, { replace: true }); |
100 | | - }, [selectedProvider, selectedChild]); |
| 121 | + // prevent loops by comparing old to new |
| 122 | + const newString = params.toString(); |
| 123 | + if (newString !== searchParams.toString() && newString !== "") { |
| 124 | + setSearchParams(params, { replace: true }); |
| 125 | + } |
| 126 | + }, [ |
| 127 | + selectedProvider, |
| 128 | + selectedChild, |
| 129 | + isCustom, |
| 130 | + customUrl, |
| 131 | + dbParam, |
| 132 | + setSearchParams, |
| 133 | + ]); |
101 | 134 |
|
102 | 135 | // --- Structures / results via TanStack Query --- |
103 | 136 | const { data: resultsData, isLoading: isLoading } = useQuery({ |
@@ -159,6 +192,8 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) { |
159 | 192 | selectedProvider={selectedProvider} |
160 | 193 | selectedChild={selectedChild} |
161 | 194 | onSelectChild={setSelectedChild} |
| 195 | + childEntries={childEntries} |
| 196 | + loadingChildren={loadingChildren} |
162 | 197 | /> |
163 | 198 | </div> |
164 | 199 |
|
|
0 commit comments