Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 1m1s
93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
// src/hooks/useActiveDeals.tsx
|
|
import { useMemo } from 'react';
|
|
import { useFlyers } from './useFlyers';
|
|
import { useUserData } from '../hooks/useUserData';
|
|
import { useFlyerItemsForFlyersQuery } from './queries/useFlyerItemsForFlyersQuery';
|
|
import { useFlyerItemCountQuery } from './queries/useFlyerItemCountQuery';
|
|
import type { DealItem } from '../types';
|
|
import { logger } from '../services/logger.client';
|
|
|
|
/**
|
|
* A custom hook to calculate currently active deals and total active items
|
|
* based on flyer validity dates and a user's watched items.
|
|
*
|
|
* Refactored to use TanStack Query (ADR-0005 Phase 6).
|
|
*
|
|
* @returns An object containing active deals, total active items, loading state, and any errors.
|
|
*/
|
|
export const useActiveDeals = () => {
|
|
const { flyers } = useFlyers();
|
|
const { watchedItems } = useUserData();
|
|
|
|
// Memoize the calculation of valid flyers to avoid re-computing on every render.
|
|
const validFlyers = useMemo(() => {
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
return flyers.filter((flyer) => {
|
|
const from = new Date(`${flyer.valid_from}T00:00:00`);
|
|
const to = new Date(`${flyer.valid_to}T00:00:00`);
|
|
const isValid = from <= today && today <= to;
|
|
return isValid;
|
|
});
|
|
}, [flyers]);
|
|
|
|
// Memoize valid flyer IDs for stable query keys
|
|
const validFlyerIds = useMemo(() => validFlyers.map((f) => f.flyer_id), [validFlyers]);
|
|
|
|
// Use TanStack Query for data fetching
|
|
const {
|
|
data: itemsData,
|
|
isLoading: loadingItems,
|
|
error: itemsError,
|
|
} = useFlyerItemsForFlyersQuery(
|
|
validFlyerIds,
|
|
validFlyerIds.length > 0 && watchedItems.length > 0,
|
|
);
|
|
|
|
const {
|
|
data: countData,
|
|
isLoading: loadingCount,
|
|
error: countError,
|
|
} = useFlyerItemCountQuery(validFlyerIds, validFlyerIds.length > 0);
|
|
|
|
// Consolidate loading and error states from both queries.
|
|
const isLoading = loadingCount || loadingItems;
|
|
const error =
|
|
itemsError || countError
|
|
? `Could not fetch active deals or totals: ${itemsError?.message || countError?.message}`
|
|
: null;
|
|
|
|
// Process the data returned from the query hooks.
|
|
const activeDeals = useMemo(() => {
|
|
if (!itemsData || watchedItems.length === 0) return [];
|
|
|
|
const watchedItemIds = new Set(watchedItems.map((item) => item.master_grocery_item_id));
|
|
const dealItemsRaw = itemsData.filter(
|
|
(item) => item.master_item_id && watchedItemIds.has(item.master_item_id),
|
|
);
|
|
const flyerIdToStoreName = new Map(
|
|
validFlyers.map((f) => [f.flyer_id, f.store?.name || 'Unknown Store']),
|
|
);
|
|
|
|
return dealItemsRaw.map((item): DealItem => {
|
|
const deal: DealItem = {
|
|
item: item.item,
|
|
price_display: item.price_display,
|
|
price_in_cents: item.price_in_cents ?? null,
|
|
quantity: item.quantity ?? '',
|
|
storeName: flyerIdToStoreName.get(item.flyer_id!) || 'Unknown Store',
|
|
master_item_name: item.master_item_name,
|
|
unit_price: item.unit_price ?? null,
|
|
};
|
|
|
|
// Logging the mapped deal for debugging purposes to trace data integrity issues
|
|
logger.info('Mapped DealItem:', deal);
|
|
|
|
return deal;
|
|
});
|
|
}, [itemsData, watchedItems, validFlyers]);
|
|
|
|
const totalActiveItems = countData?.count ?? 0;
|
|
return { activeDeals, totalActiveItems, isLoading, error };
|
|
};
|