Created
December 11, 2025 06:23
-
-
Save jay-babu/855bcdbbd0e2e0256ab9aa2d3c9ee478 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/config/client.ts b/src/config/client.ts | |
| index 88e53b893..acb5e36fa 100644 | |
| --- a/src/config/client.ts | |
| +++ b/src/config/client.ts | |
| @@ -69,18 +69,64 @@ export const client = axios.create({ | |
| paramsSerializer: (params) => qs.stringify(params, { indices: false }), | |
| }); | |
| -client.interceptors.request.use(async (config) => { | |
| +// Cache Firebase token to avoid ~50ms getIdToken() call on every request | |
| +let cachedToken: string | null = null; | |
| +let cachedTokenUserId: string | undefined = undefined; | |
| + | |
| +export const getCachedToken = (): string | null | Promise<string | null> => { | |
| + const currentUser = firebaseAuth.currentUser; | |
| + | |
| + // Return synchronously if cached and same user | |
| + if (cachedToken && cachedTokenUserId === currentUser?.uid) { | |
| + return cachedToken; | |
| + } | |
| + | |
| + // Clear cache if user changed | |
| + if (!currentUser) { | |
| + cachedToken = null; | |
| + cachedTokenUserId = undefined; | |
| + return null; | |
| + } | |
| + | |
| + // Only go async when we need to fetch | |
| + return (async () => { | |
| + cachedToken = await currentUser.getIdToken(); | |
| + cachedTokenUserId = currentUser.uid; | |
| + return cachedToken; | |
| + })(); | |
| +}; | |
| + | |
| +// Export function to clear token cache (call on logout) | |
| +export const clearTokenCache = () => { | |
| + cachedToken = null; | |
| + cachedTokenUserId = undefined; | |
| +}; | |
| + | |
| +client.interceptors.request.use((config) => { | |
| config.headers["X-AVAILABILITY"] = REDIRECT_TO_CORE_SALE_API(); | |
| - // Get token using the centralized function that prefers Firebase when available | |
| - const token = await firebaseAuth.currentUser?.getIdToken(); | |
| - if (token) { | |
| - config.headers.Authorization = `Bearer ${token}`; | |
| - const currentUser = firebaseAuth.currentUser; | |
| - config.headers["X-User-ID"] = currentUser?.uid; | |
| + const tokenOrPromise = getCachedToken(); | |
| + | |
| + // If token is cached (synchronous), set headers and return config directly | |
| + if (typeof tokenOrPromise === "string") { | |
| + config.headers.Authorization = `Bearer ${tokenOrPromise}`; | |
| + config.headers["X-User-ID"] = firebaseAuth.currentUser?.uid; | |
| + return config; | |
| } | |
| - return config; | |
| + // If no user, return config directly | |
| + if (tokenOrPromise === null) { | |
| + return config; | |
| + } | |
| + | |
| + // Only go async when we need to fetch a new token | |
| + return tokenOrPromise.then((token) => { | |
| + if (token) { | |
| + config.headers.Authorization = `Bearer ${token}`; | |
| + config.headers["X-User-ID"] = firebaseAuth.currentUser?.uid; | |
| + } | |
| + return config; | |
| + }); | |
| }); | |
| // https://github.com/kubb-labs/kubb/commit/87370f5b09df4429e4ee8e3d40494e66f36c9484 | |
| diff --git a/src/context/Sales/factory/PreProcessWASMInputFactory.tsx b/src/context/Sales/factory/PreProcessWASMInputFactory.tsx | |
| index 2efdfd900..81b63b1ff 100644 | |
| --- a/src/context/Sales/factory/PreProcessWASMInputFactory.tsx | |
| +++ b/src/context/Sales/factory/PreProcessWASMInputFactory.tsx | |
| @@ -39,10 +39,9 @@ import type { | |
| WasmPricingCartInput, | |
| } from "src/lib/hades_price"; | |
| import type { Department as SpringDepartment } from "src/spring-generated"; | |
| -import { | |
| - EntitySalesChannelPaymentMethod, | |
| - usePreprocessPricingData, | |
| -} from "src/spring-generated"; | |
| +import { EntitySalesChannelPaymentMethod } from "src/spring-generated"; | |
| +import type { PreprocessPricingDataMutationResponse } from "src/spring-generated"; | |
| +import { getCachedToken } from "src/config/client"; | |
| import { useServiceState } from "src/store/serviceStatus/serviceStatusSlice"; | |
| import { | |
| convertDiscount, | |
| @@ -593,11 +592,7 @@ const createLocalPreProcessWASMInput = | |
| }; | |
| const createServerPreProcessWASMInput = | |
| - ( | |
| - preprocessPricingDataMutateAsync: ReturnType< | |
| - typeof usePreprocessPricingData | |
| - >["mutateAsync"], | |
| - ): UseMutateAsyncFunction< | |
| + (): UseMutateAsyncFunction< | |
| PreProcessWASMInputResult, | |
| Error, | |
| PreProcessWASMInputParams, | |
| @@ -632,24 +627,55 @@ const createServerPreProcessWASMInput = | |
| } | |
| } | |
| - const result = await timed("preprocessPricingData-server", async () => | |
| - preprocessPricingDataMutateAsync({ | |
| - data: { | |
| - dayOfWeek: params.dayOfWeek, | |
| - localDate: params.localDate, | |
| - localTime: params.localTime, | |
| - bulkItemPricesInput, | |
| - cohortId: params.entity.cohortId, | |
| - cohortItemIds, | |
| - cohortPriceLevelId: params.actualCohortPriceLevel, | |
| - departmentIds, | |
| - entityId: params.entity.id, | |
| - entityItemIds, | |
| - loyaltyCustomerId: params.requestedCustomer?.loyaltyCustomerId, | |
| - selectedSalesChannelId: params.selectedSalesChannel.id, | |
| + // Bypass axios/useMutation to avoid ~46ms overhead - use fetch directly | |
| + const requestData = { | |
| + dayOfWeek: params.dayOfWeek, | |
| + localDate: params.localDate, | |
| + localTime: params.localTime, | |
| + bulkItemPricesInput, | |
| + cohortId: params.entity.cohortId, | |
| + cohortItemIds, | |
| + cohortPriceLevelId: params.actualCohortPriceLevel, | |
| + departmentIds, | |
| + entityId: params.entity.id, | |
| + entityItemIds, | |
| + loyaltyCustomerId: params.requestedCustomer?.loyaltyCustomerId, | |
| + selectedSalesChannelId: params.selectedSalesChannel.id, | |
| + }; | |
| + | |
| + // Prepare all sync work before the timed block | |
| + const tokenOrPromise = timed("getCachedToken", () => getCachedToken()); | |
| + // Avoid async/await overhead when token is already cached | |
| + const resolvedToken = | |
| + typeof tokenOrPromise === "string" || tokenOrPromise === null | |
| + ? timed("tokenSync", () => tokenOrPromise) | |
| + : await timed("tokenAsync", () => tokenOrPromise); | |
| + const baseUrl = import.meta.env.VITE_APP_API_URL; | |
| + const body = JSON.stringify(requestData); | |
| + | |
| + const result = await timed("preprocessPricingData-server", async () => { | |
| + const response = await fetch(`${baseUrl}/api/v1/pricing_preprocess`, { | |
| + method: "POST", | |
| + headers: { | |
| + "Content-Type": "application/json", | |
| + ...(resolvedToken | |
| + ? { | |
| + Authorization: `Bearer ${resolvedToken}`, | |
| + } | |
| + : {}), | |
| + "X-Entity-ID": String(params.entity.id), | |
| + "X-Timezone": Intl.DateTimeFormat().resolvedOptions().timeZone, | |
| + "X-AVAILABILITY": "CRITICAL", | |
| }, | |
| - }), | |
| - ); | |
| + body, | |
| + }); | |
| + | |
| + if (!response.ok) { | |
| + throw new Error(`HTTP error! status: ${response.status}`); | |
| + } | |
| + | |
| + return response.json() as Promise<PreprocessPricingDataMutationResponse>; | |
| + }); | |
| // Direct mapping from server response to WASM input using shared utilities | |
| const entityItemPriceMap = buildEntityItemPriceMap( | |
| @@ -753,9 +779,6 @@ const createServerPreProcessWASMInput = | |
| }; | |
| export const usePreProcessWASMInputFactory = () => { | |
| - const { mutateAsync: preprocessPricingDataMutateAsync } = | |
| - usePreprocessPricingData(); | |
| - | |
| const isOffline = useServiceState("pricingContext").status === "offline"; | |
| return useMemo(() => { | |
| @@ -766,11 +789,9 @@ export const usePreProcessWASMInputFactory = () => { | |
| }; | |
| } else { | |
| return { | |
| - mutateAsync: createServerPreProcessWASMInput( | |
| - preprocessPricingDataMutateAsync, | |
| - ), | |
| + mutateAsync: createServerPreProcessWASMInput(), | |
| isPending: false, | |
| }; | |
| } | |
| - }, [preprocessPricingDataMutateAsync, isOffline]); | |
| + }, [isOffline]); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment