From 7a7f7e157e40c75c2fbe09ea1de6a82221b00603 Mon Sep 17 00:00:00 2001
From: Khalim Conn-Kowlessar
Date: Wed, 8 Jul 2026 16:04:53 +0000
Subject: [PATCH] feat(live-reporting): select page vs all pages in bulk
download
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The header tick now selects the current page (its intuitive meaning). When
the whole page is ticked and more filtered rows exist, a Gmail-style banner
offers "Select all N across pages" (and "Clear selection" once everything
is selected) — so users can grab a page-sized chunk without selecting the
entire project.
Co-Authored-By: Claude Opus 4.8 (1M context)
---
.../live/DocumentBulkDownload.tsx | 3 +-
.../your-projects/live/DocumentTable.tsx | 73 +++++++++++++++++--
2 files changed, 69 insertions(+), 7 deletions(-)
diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentBulkDownload.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentBulkDownload.tsx
index d1961656..5b8bf746 100644
--- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentBulkDownload.tsx
+++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentBulkDownload.tsx
@@ -178,7 +178,8 @@ export default function DocumentBulkDownload({
{selectedIds.size} selected
- Tick the properties to include, or use the header box to select all.
+ Tick properties, or use the header box to select the page (then “select
+ all across pages”).
{overCap && (
diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentTable.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentTable.tsx
index 0c61f8ca..ec50d043 100644
--- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentTable.tsx
+++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/DocumentTable.tsx
@@ -119,21 +119,23 @@ export default function DocumentTable({ data, onOpenDrawer, docStatusMap, portfo
enableSorting: false,
enableGlobalFilter: false,
header: ({ table }) => {
- const ids = table
- .getFilteredRowModel()
+ // Header ticks the current page; the banner below offers all pages.
+ const pageIds = table
+ .getRowModel()
.rows.map((r) => r.original.landlordPropertyId)
.filter((id): id is string => !!id);
- const allSelected = ids.length > 0 && ids.every((id) => selection.selectedIds.has(id));
- const someSelected = ids.some((id) => selection.selectedIds.has(id));
+ const allSelected =
+ pageIds.length > 0 && pageIds.every((id) => selection.selectedIds.has(id));
+ const someSelected = pageIds.some((id) => selection.selectedIds.has(id));
return (
{
if (el) el.indeterminate = someSelected && !allSelected;
}}
- onChange={() => selection.onSetMany(ids, !allSelected)}
+ onChange={() => selection.onSetMany(pageIds, !allSelected)}
className="h-4 w-4 accent-brandblue align-middle"
/>
);
@@ -217,6 +219,31 @@ export default function DocumentTable({ data, onOpenDrawer, docStatusMap, portfo
const currentPage = table.getState().pagination.pageIndex + 1;
const totalFiltered = table.getFilteredRowModel().rows.length;
+ // "Select all across pages" banner: shown when the whole current page is
+ // ticked and there are more filtered rows than fit on it (Gmail-style).
+ const pageSelectableIds = selection
+ ? table
+ .getRowModel()
+ .rows.map((r) => r.original.landlordPropertyId)
+ .filter((id): id is string => !!id)
+ : [];
+ const filteredSelectableIds = selection
+ ? table
+ .getFilteredRowModel()
+ .rows.map((r) => r.original.landlordPropertyId)
+ .filter((id): id is string => !!id)
+ : [];
+ const pageFullySelected =
+ pageSelectableIds.length > 0 &&
+ pageSelectableIds.every((id) => selection!.selectedIds.has(id));
+ const allFilteredSelected =
+ filteredSelectableIds.length > 0 &&
+ filteredSelectableIds.every((id) => selection!.selectedIds.has(id));
+ const showSelectAllBanner =
+ !!selection &&
+ pageFullySelected &&
+ filteredSelectableIds.length > pageSelectableIds.length;
+
const retroAssessmentLabel: Record = {
all: "All retrofit statuses",
none: "No Retrofit Docs",
@@ -314,6 +341,40 @@ export default function DocumentTable({ data, onOpenDrawer, docStatusMap, portfo
propert{totalFiltered === 1 ? "y" : "ies"}
+ {/* Select-all-across-pages banner */}
+ {showSelectAllBanner && (
+
+ {allFilteredSelected ? (
+ <>
+
+ All {filteredSelectableIds.length}{" "}
+ matching propert{filteredSelectableIds.length === 1 ? "y is" : "ies are"}{" "}
+ selected.
+
+
+ >
+ ) : (
+ <>
+
+ All {pageSelectableIds.length} on this
+ page selected.
+
+
+ >
+ )}
+
+ )}
+
{/* Table */}