diff --git a/src/app/(protected)/workorders/_hooks/use-work-orders-board-source.ts b/src/app/(protected)/workorders/_hooks/use-work-orders-board-source.ts
index 11771ca7..914bf835 100644
--- a/src/app/(protected)/workorders/_hooks/use-work-orders-board-source.ts
+++ b/src/app/(protected)/workorders/_hooks/use-work-orders-board-source.ts
@@ -23,6 +23,7 @@ export type WorkOrdersBoardSource = {
data: WorkOrderBoardListResult | undefined;
unassignedQueue: WorkOrderTableRow[];
unassignedError: Error | null;
+ unassignedLoading: boolean;
isLoading: boolean;
isFetching: boolean;
error: Error | null;
@@ -75,6 +76,7 @@ export function useWorkOrdersBoardSource(filters: FiltersReturn): WorkOrdersBoar
} = useWorkOrdersBoardSearch(resolvedSearchParams ?? { datePreset: "ThisWeek" }, advActive);
const {
data: queueData,
+ isLoading: queueLoading,
isFetching: queueFetching,
error: queueError,
refetch: refetchQueue,
@@ -94,6 +96,10 @@ export function useWorkOrdersBoardSource(filters: FiltersReturn): WorkOrdersBoar
data: advActive ? searchData : boardData,
unassignedQueue: advActive ? EMPTY_UNASSIGNED_QUEUE : (queueData ?? EMPTY_UNASSIGNED_QUEUE),
unassignedError: advActive ? null : (queueError ?? null),
+ // SH-165: the pinned queue has its own first-load state. Folding it into
+ // isFetching only made "still paging board/search" indistinguishable from
+ // "zero unassigned", so the pin announced an empty queue while loading.
+ unassignedLoading: advActive ? false : queueLoading,
isLoading: advActive ? searchLoading : boardLoading,
isFetching: advActive ? searchFetching : boardFetching || queueFetching,
error: advActive ? searchError : boardError,
diff --git a/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts b/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
index 469fd465..752272de 100644
--- a/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
+++ b/src/app/(protected)/workorders/_hooks/use-work-orders-table-data.ts
@@ -26,6 +26,7 @@ export function useWorkOrdersTableData(filters: FiltersReturn) {
data,
unassignedQueue,
unassignedError,
+ unassignedLoading,
isLoading,
isFetching,
error,
@@ -107,6 +108,7 @@ export function useWorkOrdersTableData(filters: FiltersReturn) {
advResults,
unassigned,
unassignedError,
+ unassignedLoading,
unscheduled,
displayGroups,
searchActive,
diff --git a/src/test/app/(protected)/workorders/wo-table-unassigned-queue.test.tsx b/src/test/app/(protected)/workorders/wo-table-unassigned-queue.test.tsx
index d010346d..66a61208 100644
--- a/src/test/app/(protected)/workorders/wo-table-unassigned-queue.test.tsx
+++ b/src/test/app/(protected)/workorders/wo-table-unassigned-queue.test.tsx
@@ -76,6 +76,7 @@ function baseTableData(
advResults: [],
unassigned: [],
unassignedError: null,
+ unassignedLoading: false,
unscheduled: [],
displayGroups: [],
searchActive: false,
@@ -308,6 +309,36 @@ describe("WoTableBody Unassigned queue (SH-165)", () => {
expect(screen.queryByText("WED · 07/15")).not.toBeInTheDocument();
});
+ it("distinguishes a still-loading queue from an empty one", () => {
+ render(
+
+ null}
+ renderInlineRow={() => null}
+ />
+ ,
+ );
+
+ expect(screen.getByText(/Loading unassigned work orders/)).toBeInTheDocument();
+ expect(screen.queryByText("No unassigned work orders.")).not.toBeInTheDocument();
+ });
+
+ it("announces an empty queue only once loading has settled", () => {
+ render(
+
+ null}
+ renderInlineRow={() => null}
+ />
+ ,
+ );
+
+ expect(screen.getByText("No unassigned work orders.")).toBeInTheDocument();
+ expect(screen.queryByText(/Loading unassigned work orders/)).not.toBeInTheDocument();
+ });
+
it("keeps the Unassigned pin visible when the queue query fails", () => {
render(
|