"use client"; import React, { createContext, useContext, useEffect, useState, ReactNode, } from "react"; import { getManagerMemberships } from "@/app/utils/api/user-dashboard-platform/mappingFunction"; import { getAllUsers } from "@/app/utils/api/user-dashboard-platform"; import type { RoleMembership, User, } from "@/app/utils/api/user-dashboard-platform/type"; import { getAllFXRate } from "@/app/utils/api/fxRate"; import type { FxRateResponse } from "@/app/utils/api/fxRate/type"; /** year -> currency (upper-cased) -> rate */ export type FxRateMap = Map>; type SelectOption = { value: string; label: string }; interface AppCacheState { /** userId -> userName */ userNameMap: Map; /** userId -> designation */ userDesignationMap: Map; /** all active (non-deleted) platform users */ activeUsers: User[]; /** year -> currency -> rate, derived from the raw FX response */ fxRateMap: FxRateMap; /** the raw FX rate response (paginated) */ fxRateResponse: FxRateResponse | null; /** userId/userName options for users holding the Project Manager role */ projectManagerOptions: SelectOption[]; /** userId/userName options for users holding the Account Manager role */ accountManagerOptions: SelectOption[]; isLoading: boolean; refresh: () => void; } const AppCacheContext = createContext({ userNameMap: new Map(), userDesignationMap: new Map(), activeUsers: [], fxRateMap: new Map(), fxRateResponse: null, projectManagerOptions: [], accountManagerOptions: [], isLoading: true, refresh: () => {}, }); export function AppCacheProvider({ children }: { children: ReactNode }) { const [userNameMap, setUserNameMap] = useState>(new Map()); const [userDesignationMap, setUserDesignationMap] = useState< Map >(new Map()); const [activeUsers, setActiveUsers] = useState([]); const [fxRateMap, setFxRateMap] = useState(new Map()); const [fxRateResponse, setFxRateResponse] = useState( null, ); const [projectManagerOptions, setProjectManagerOptions] = useState< SelectOption[] >([]); const [accountManagerOptions, setAccountManagerOptions] = useState< SelectOption[] >([]); const [isLoading, setIsLoading] = useState(true); const [refreshKey, setRefreshKey] = useState(0); useEffect(() => { let cancelled = false; const load = async () => { setIsLoading(true); try { const allUsers = await getAllUsers(); const usersList: User[] = Array.isArray(allUsers) ? allUsers : []; // Build name + designation maps and the active-user list from one fetch const nameMap = new Map(); const designationMap = new Map(); usersList.forEach((u) => { if (u?.userId) { nameMap.set(u.userId, u.userName); designationMap.set(u.userId, u.userDesignation); } }); const activeUserList = usersList.filter( (u) => u.active && !u.userDeleted, ); const [memberships, rawFxResponse] = await Promise.all([ getManagerMemberships(), getAllFXRate(), ]); // Build FxRateMap (year -> currency -> rate) from the raw response const builtFxRateMap: FxRateMap = new Map(); rawFxResponse.content?.forEach((item) => { Object.entries(item.fxRateDetails || {}).forEach( ([year, currencyData]) => { if (!currencyData) return; Object.entries(currencyData).forEach(([, rateData]) => { const currency = rateData?.currency?.toUpperCase(); const rateValue = rateData?.fxRate; if ( !year || !currency || rateValue === null || rateValue === undefined || isNaN(rateValue) ) { return; } if (!builtFxRateMap.has(year)) { builtFxRateMap.set(year, new Map()); } builtFxRateMap.get(year)!.set(currency, rateValue); }); }, ); }); // Build manager option lists, deduped by userId const toOptions = (members: RoleMembership[]): SelectOption[] => { const options: SelectOption[] = []; members.forEach((member) => { const name = nameMap.get(member.userId); if (name) options.push({ value: member.userId, label: name }); }); return Array.from( new Map(options.map((opt) => [opt.value, opt])).values(), ); }; if (!cancelled) { setUserNameMap(nameMap); setUserDesignationMap(designationMap); setActiveUsers(activeUserList); setFxRateMap(builtFxRateMap); setFxRateResponse(rawFxResponse); setProjectManagerOptions(toOptions(memberships.projectManagerMembers)); setAccountManagerOptions(toOptions(memberships.accountManagerMembers)); } } catch (err) { console.error("AppCacheProvider: Failed to load maps", err); } finally { if (!cancelled) setIsLoading(false); } }; load(); return () => { cancelled = true; }; }, [refreshKey]); const refresh = () => setRefreshKey((k) => k + 1); return ( {children} ); } export function useAppCache(): AppCacheState { return useContext(AppCacheContext); }