From 5984f2f8147cbd8d5e2029ba689e07ca5c5467b2 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Fri, 10 Jul 2026 23:58:47 +0200 Subject: [PATCH] feat(collection-pool): render supplier-grouped sections --- src/app/(app)/collection-pool/page.tsx | 117 ++++++++++++++++--------- 1 file changed, 75 insertions(+), 42 deletions(-) diff --git a/src/app/(app)/collection-pool/page.tsx b/src/app/(app)/collection-pool/page.tsx index ec990a9..2e68089 100644 --- a/src/app/(app)/collection-pool/page.tsx +++ b/src/app/(app)/collection-pool/page.tsx @@ -118,6 +118,12 @@ export default function CollectionPoolPage() { const [readyDialogRow, setReadyDialogRow] = useState(null); const [readyDialogError, setReadyDialogError] = useState(null); const [selectedIds, setSelectedIds] = useState>(new Set()); + const [collapsedSuppliers, setCollapsedSuppliers] = useState>(new Set()); + const [bulkAssignDialog, setBulkAssignDialog] = useState<{ + supplierId: string; + supplierName: string; + rowIds: string[]; + } | null>(null); const toggleRowSelected = useCallback((rowId: string) => { setSelectedIds((prev) => { @@ -141,6 +147,25 @@ export default function CollectionPoolPage() { }); }, []); + const toggleCollapsed = useCallback((supplierId: string) => { + setCollapsedSuppliers((prev) => { + const next = new Set(prev); + if (next.has(supplierId)) next.delete(supplierId); + else next.add(supplierId); + return next; + }); + }, []); + + const openBulkAssign = useCallback( + (supplierId: string, supplierName: string, rowIds: string[]) => { + if (rowIds.length === 0) return; + setBulkAssignDialog({ supplierId, supplierName, rowIds }); + }, + [], + ); + + const closeBulkAssign = useCallback(() => setBulkAssignDialog(null), []); + const closeAssignDialog = useCallback(() => setAssignDialog(null), []); const openAssignForRow = useCallback((row: CollectionPoolVisibleRow) => { @@ -270,6 +295,21 @@ export default function CollectionPoolPage() { ) as CollectionPoolVisibleRow[]; }, [rows, todayYmd, filterText, readyFilter, sortMode, clusterSortKeyForSupplier]); + const groups = useMemo< + | (Omit & { rows: CollectionPoolVisibleRow[] })[] + | null + >(() => { + if (!visibleRows) return null; + // `buildSupplierGroups` types its rows as `CollectionPoolViewRow[]`, + // but every row in `visibleRows` is a `CollectionPoolVisibleRow` (a + // superset of `CollectionPoolViewRow` — see the cast above). The + // widening per-row is sound. + return buildSupplierGroups(visibleRows, supplierMarkerMap).map((g) => ({ + ...g, + rows: g.rows as CollectionPoolVisibleRow[], + })); + }, [visibleRows, supplierMarkerMap]); + const updateItemStatus = useCallback( async ( itemId: string, @@ -483,51 +523,44 @@ export default function CollectionPoolPage() { - {rows === null && ( -
- {Array.from({ length: 4 }).map((_, i) => ( -
- ))} +
+
+ Collection Item + Order Detail + Status + Actions
- )} - - {rows !== null && rows.length === 0 && ( - - )} - - {rows !== null && rows.length > 0 && visibleRows && visibleRows.length === 0 && ( - - )} - - {rows !== null && visibleRows && visibleRows.length > 0 && ( -
-
- Collection Item - Order Detail - Status - Actions -
-
    - {visibleRows.map((row) => ( - + {Array.from({ length: 4 }).map((_, i) => ( +
    ))} -
-
- )} +
+ ) : groups.length === 0 ? ( + + ) : ( + groups.map((group) => ( + + )) + )} +