@@ -4,35 +4,92 @@ import { collection, getDocs, limit, orderBy, query } from "firebase/firestore";
44import { CurrencyMapContext } from "../context/CurrencyMapContext" ;
55import { DatabaseContext } from "../context/DatabaseContext" ;
66import { setCache } from "./storage" ;
7+ import { Gears } from "@/components/Gears" ;
8+ import { Alert , AlertDescription , AlertTitle } from "@/components/shadcn/Alert" ;
9+ import { AlertCircle , LoaderCircle , RefreshCw } from "lucide-react" ;
10+ import { CenterChild } from "@/components/CenterChild" ;
11+ import { Button } from "@/components/shadcn/Button" ;
712
813export function CurrencyMapProvider ( props : PropsWithChildren ) {
914 const db = useContext ( DatabaseContext ) ;
1015 const [ currencyMap , setCurrencyMap ] = useState < RateDefinitions | null > ( null ) ;
16+ const [ error , setError ] = useState < string | null > ( null ) ;
17+ const [ isLoadingDelayed , setIsLoadingDelayed ] = useState ( false ) ;
1118
1219 useEffect ( ( ) => {
20+ const loadingDelayTimeout = setTimeout ( ( ) => {
21+ setIsLoadingDelayed ( true ) ;
22+ } , 3000 ) ;
23+
1324 const fetchLatestDocument = async ( ) => {
14- const collectionRef = collection ( db , "rates" ) ;
25+ try {
26+ const collectionRef = collection ( db , "rates" ) ;
27+ const q = query ( collectionRef , orderBy ( "meta.createdAt" , "desc" ) , limit ( 1 ) ) ;
28+ const querySnapshot = await getDocs ( q ) ;
1529
16- const q = query ( collectionRef , orderBy ( "meta.createdAt" , "desc" ) , limit ( 1 ) ) ; // Query to fetch the latest document
30+ if ( ! querySnapshot . empty ) {
31+ querySnapshot . forEach ( ( doc ) => {
32+ const data = doc . data ( ) as RateDefinitions ;
33+ setCurrencyMap ( data ) ;
34+ setCache ( data ) ;
35+ } ) ;
36+ } else {
37+ setError ( "No exchange rate data found in the database." ) ;
38+ }
39+ } catch ( err ) {
40+ setError ( "Could not fetch latest exchange rate data. Please try again after a few minutes." ) ;
41+ } finally {
42+ clearTimeout ( loadingDelayTimeout ) ;
43+ }
44+ } ;
1745
18- const querySnapshot = await getDocs ( q ) ;
46+ fetchLatestDocument ( ) ;
1947
20- // FIXME: do I have to loop a .limit(1) data?
21- querySnapshot . forEach ( ( doc ) => {
22- const data = doc . data ( ) as RateDefinitions ;
23- setCurrencyMap ( data ) ;
24- setCache ( data ) ;
25- } ) ;
26- } ;
48+ return ( ) => clearTimeout ( loadingDelayTimeout ) ;
49+ } , [ db ] ) ;
50+
51+ if ( error ) {
52+ return (
53+ < CenterChild >
54+ < Alert variant = 'destructive' className = 'w-full max-w-[450px]' >
55+ < AlertCircle className = 'h-4 w-4' />
56+ < AlertTitle > Error</ AlertTitle >
57+ < AlertDescription > { error } </ AlertDescription >
58+ </ Alert >
59+ </ CenterChild >
60+ ) ;
61+ }
62+
63+ if ( isLoadingDelayed && ! currencyMap ) {
64+ return (
65+ < CenterChild >
66+ < div className = 'flex flex-col gap-6 items-center' >
67+ < Alert variant = 'default' className = 'w-full max-w-[450px]' >
68+ < LoaderCircle className = 'w-4 h-4 animate-spin' />
69+ < AlertTitle > Warning!</ AlertTitle >
70+ < AlertDescription >
71+ < p >
72+ The data is still trying to load, but it is taking longer than expected.{ " " }
73+ < span className = 'font-semibold' > It may keep loading indefinitely.</ span >
74+ </ p >
75+ < p >
76+ If the app does not launch within a few seconds, you can{ " " }
77+ < span className = 'underline' > reload the page</ span > or try again later.
78+ </ p >
79+ </ AlertDescription >
80+ </ Alert >
81+
82+ < Button onClick = { ( ) => window . location . reload ( ) } >
83+ < RefreshCw className = 'h-4 w-4' /> Reload Page
84+ </ Button >
85+ </ div >
86+ </ CenterChild >
87+ ) ;
88+ }
2789
28- fetchLatestDocument ( )
29- . then ( ( ) => {
30- // TODO: on fetch success?
31- } )
32- . catch ( ( error ) => {
33- console . error ( "Error fetching latest document:" , error ) ;
34- } ) ;
35- } , [ ] ) ;
90+ if ( ! currencyMap ) {
91+ return < Gears isLoading /> ;
92+ }
3693
3794 return < CurrencyMapContext . Provider value = { currencyMap } > { props . children } </ CurrencyMapContext . Provider > ;
3895}
0 commit comments