Files
flyer-crawler.projectium.com/src/hooks/useActiveDeals.tsx
Torben Sorensen 2913c7aa09
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 1m1s
tanstack
2026-01-10 03:20:40 -08:00

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 };
};