first commit
This commit is contained in:
186
frontend/app/utils/context/AppCacheContext.tsx
Normal file
186
frontend/app/utils/context/AppCacheContext.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
"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<string, Map<string, number>>;
|
||||
|
||||
type SelectOption = { value: string; label: string };
|
||||
|
||||
interface AppCacheState {
|
||||
/** userId -> userName */
|
||||
userNameMap: Map<string, string>;
|
||||
/** userId -> designation */
|
||||
userDesignationMap: Map<string, string | null>;
|
||||
/** 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<AppCacheState>({
|
||||
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<Map<string, string>>(new Map());
|
||||
const [userDesignationMap, setUserDesignationMap] = useState<
|
||||
Map<string, string | null>
|
||||
>(new Map());
|
||||
const [activeUsers, setActiveUsers] = useState<User[]>([]);
|
||||
const [fxRateMap, setFxRateMap] = useState<FxRateMap>(new Map());
|
||||
const [fxRateResponse, setFxRateResponse] = useState<FxRateResponse | null>(
|
||||
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<string, string>();
|
||||
const designationMap = new Map<string, string | null>();
|
||||
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 (
|
||||
<AppCacheContext.Provider
|
||||
value={{
|
||||
userNameMap,
|
||||
userDesignationMap,
|
||||
activeUsers,
|
||||
fxRateMap,
|
||||
fxRateResponse,
|
||||
projectManagerOptions,
|
||||
accountManagerOptions,
|
||||
isLoading,
|
||||
refresh,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppCacheContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useAppCache(): AppCacheState {
|
||||
return useContext(AppCacheContext);
|
||||
}
|
||||
Reference in New Issue
Block a user