import { produce } from 'immer'; import React, { useMemo } from 'react'; import { AppContextDispatchValue, AppStateContextValue } from '../../../types/appContext.js'; const AppStateContext = React.createContext( {} as AppStateContextValue ); const AppContextDispatch = React.createContext( {} as AppContextDispatchValue ); interface AppProviderProps { value: AppStateContextValue; children: React.ReactNode; } export function AppProvider({ value, children }: AppProviderProps) { const [data, setData] = React.useState(value); const [fetching, setFetching] = React.useState(false); const fetchPageData = async (url: string | URL): Promise => { setFetching(true); try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); const dataResponse = await response.json(); // Update the entire context using immer setData( produce(data, (draft) => { Object.assign(draft, dataResponse.eContext); return draft; }) ); } catch (error) { } finally { setFetching(false); } }; React.useEffect(() => { window.onpopstate = async () => { // Get the current url const url = new URL(window.location.href, window.location.origin); url.searchParams.append('ajax', 'true'); await fetchPageData(url.toString()); }; }, []); const contextDispatchValue = useMemo( () => ({ setData, fetchPageData }), [setData, fetchPageData] ); const contextValue = useMemo( () => ({ ...data, fetching }), [data, fetching] ); return ( {children} ); } export const useAppState = (): AppStateContextValue => React.useContext(AppStateContext); export const useAppDispatch = (): AppContextDispatchValue => React.useContext(AppContextDispatch);