diff --git a/server.ts b/server.ts index 7120897..f7623df 100644 --- a/server.ts +++ b/server.ts @@ -38,6 +38,7 @@ import receiptRouter from './src/routes/receipt.routes'; import dealsRouter from './src/routes/deals.routes'; import reactionsRouter from './src/routes/reactions.routes'; import storeRouter from './src/routes/store.routes'; +import categoryRouter from './src/routes/category.routes'; import { errorHandler } from './src/middleware/errorHandler'; import { backgroundJobService, startBackgroundJobs } from './src/services/backgroundJobService'; import { websocketService } from './src/services/websocketService.server'; @@ -288,6 +289,8 @@ app.use('/api/deals', dealsRouter); app.use('/api/reactions', reactionsRouter); // 16. Store management routes. app.use('/api/stores', storeRouter); +// 17. Category discovery routes (ADR-023: Database Normalization) +app.use('/api/categories', categoryRouter); // --- Error Handling and Server Startup --- diff --git a/src/features/flyer/ExtractedDataTable.test.tsx b/src/features/flyer/ExtractedDataTable.test.tsx index dab9809..d4328e4 100644 --- a/src/features/flyer/ExtractedDataTable.test.tsx +++ b/src/features/flyer/ExtractedDataTable.test.tsx @@ -58,6 +58,7 @@ const mockFlyerItems: FlyerItem[] = [ quantity: 'per lb', unit_price: { value: 1.99, unit: 'lb' }, master_item_id: 1, + category_id: 1, category_name: 'Produce', flyer_id: 1, }), @@ -69,6 +70,7 @@ const mockFlyerItems: FlyerItem[] = [ quantity: '4L', unit_price: { value: 1.125, unit: 'L' }, master_item_id: 2, + category_id: 2, category_name: 'Dairy', flyer_id: 1, }), @@ -80,6 +82,7 @@ const mockFlyerItems: FlyerItem[] = [ quantity: 'per kg', unit_price: { value: 8.0, unit: 'kg' }, master_item_id: 3, + category_id: 3, category_name: 'Meat', flyer_id: 1, }), @@ -241,7 +244,7 @@ describe('ExtractedDataTable', () => { expect(watchButton).toBeInTheDocument(); fireEvent.click(watchButton); - expect(mockAddWatchedItem).toHaveBeenCalledWith('Chicken Breast', 'Meat'); + expect(mockAddWatchedItem).toHaveBeenCalledWith('Chicken Breast', 3); }); it('should not show watch or add to list buttons for unmatched items', () => { @@ -589,7 +592,7 @@ describe('ExtractedDataTable', () => { const watchButton = within(itemRow).getByTitle("Add 'Canonical Mystery' to your watchlist"); fireEvent.click(watchButton); - expect(mockAddWatchedItem).toHaveBeenCalledWith('Canonical Mystery', 'Other/Miscellaneous'); + expect(mockAddWatchedItem).toHaveBeenCalledWith('Canonical Mystery', 19); }); it('should not call addItemToList when activeListId is null and button is clicked', () => { diff --git a/src/features/flyer/ExtractedDataTable.tsx b/src/features/flyer/ExtractedDataTable.tsx index 80c62c9..112997d 100644 --- a/src/features/flyer/ExtractedDataTable.tsx +++ b/src/features/flyer/ExtractedDataTable.tsx @@ -25,7 +25,7 @@ interface ExtractedDataTableRowProps { isAuthenticated: boolean; activeListId: number | null; onAddItemToList: (masterItemId: number) => void; - onAddWatchedItem: (itemName: string, category: string) => void; + onAddWatchedItem: (itemName: string, category_id: number) => void; } /** @@ -72,9 +72,7 @@ const ExtractedDataTableRow: React.FC = memo( )} {isAuthenticated && !isWatched && canonicalName && (