@@ -128,24 +128,47 @@ export function OptimadeQuerier({
128128 } ;
129129
130130 // --- Structures / results via TanStack Query ---
131- const { data : resultsData , isLoading : isLoading } = useQuery ( {
131+ const TIMEOUT_MS = 25_000 ; // 25 seconds
132+ const {
133+ data : resultsData ,
134+ isLoading,
135+ isError,
136+ error,
137+ } = useQuery ( {
132138 queryKey : [
133139 "structures" ,
134140 selectedChild ?. base_url ,
135141 currentFilter ,
136142 currentPage ,
137143 ] ,
138- queryFn : ( ) =>
139- getStructures ( {
140- providerUrl : selectedChild ?. base_url ,
141- filter : currentFilter ,
142- page : currentPage ,
143- } ) ,
144+ queryFn : async ( ) => {
145+ if ( ! selectedChild ?. base_url ) return null ;
146+ // Wrap the fetch in a timeout promise
147+ const fetchWithTimeout = new Promise ( async ( resolve , reject ) => {
148+ const timer = setTimeout ( ( ) => {
149+ reject ( new Error ( "Request timed out after 25 seconds" ) ) ;
150+ } , TIMEOUT_MS ) ;
151+
152+ try {
153+ const data = await getStructures ( {
154+ providerUrl : selectedChild . base_url ,
155+ filter : currentFilter ,
156+ page : currentPage ,
157+ } ) ;
158+ clearTimeout ( timer ) ;
159+ resolve ( data ) ;
160+ } catch ( err ) {
161+ clearTimeout ( timer ) ;
162+ reject ( new Error ( err ?. message ) ) ;
163+ }
164+ } ) ;
165+
166+ return fetchWithTimeout ;
167+ } ,
144168 enabled : ! ! selectedChild ?. base_url ,
145169 staleTime : 2 * 60 * 1000 ,
146- keepPreviousData : true , // keeps previous page visible while fetching new page
170+ keepPreviousData : true ,
147171 } ) ;
148-
149172 const results = resultsData ?. data ?? [ ] ;
150173 const metaData = resultsData ?. meta ?? { data_returned : 0 , data_available : 0 } ;
151174 const totalPages =
@@ -194,6 +217,37 @@ export function OptimadeQuerier({
194217 </ div >
195218 </ div >
196219
220+ { isError && (
221+ < div className = "flex items-start p-4 text-red-800 bg-red-50 border border-red-300 rounded-lg shadow-sm" >
222+ < svg
223+ className = "w-5 h-5 shrink-0"
224+ fill = "none"
225+ stroke = "currentColor"
226+ strokeWidth = { 1.5 }
227+ viewBox = "0 0 24 24"
228+ xmlns = "http://www.w3.org/2000/svg"
229+ >
230+ < path
231+ strokeLinecap = "round"
232+ strokeLinejoin = "round"
233+ d = "M12 8v4m0 4h.01M21 12c0 4.9706-4.0294 9-9 9s-9-4.0294-9-9 4.0294-9 9-9 9 4.0294 9 9z"
234+ />
235+ </ svg >
236+ < div className = "text-sm leading-relaxed" >
237+ Could not fetch data — the provider subdataset{ " " }
238+ < a
239+ href = { selectedChild . base_url }
240+ target = "_blank"
241+ rel = "noopener noreferrer"
242+ className = "text-blue-600 underline hover:text-blue-800"
243+ >
244+ { selectedChild . base_url }
245+ </ a > { " " }
246+ may be unreachable. Please try again later.
247+ </ div >
248+ </ div >
249+ ) }
250+
197251 { /* Filters */ }
198252 < div className = "p-2 w-full" >
199253 < motion . div
0 commit comments