fix(uplifts): show an unavailable count pill while a queue is loading or failed

This commit is contained in:
Alexandre Brandizzi 2026-09-25 13:43:11 -03:00
parent 70e52937aa
commit 70501693c8
2 changed files with 49 additions and 13 deletions

View file

@ -18,6 +18,7 @@ import { useAuthContext } from "@/providers/auth-context";
import { useUpliftApprovalController } from "@/domain/uplifts/use-cases/use-uplift-approval-controller";
import { useUpliftsQueue } from "@/domain/uplifts/use-cases/use-uplifts-queue";
import { Text } from "@/components/ui/text";
import type { UpliftsQueueResult } from "@/domain/uplifts/types/uplift";
const PAGE_SIZE = 25;
@ -47,13 +48,33 @@ const TAB_LABELS: Record<UpliftApprovalTab, string> = {
rejected: "Rejected",
};
// A tab's total is only known once its queue has loaded without error; until then the
// pill must not claim a count (a loading or failed queue is not an empty one).
function knownTotal(query: {
data?: UpliftsQueueResult | undefined;
error: unknown;
}): number | null {
if (query.error || !query.data) return null;
return query.data.totalCount;
}
function TabCountPill({ tab, count }: { tab: UpliftApprovalTab; count: number | null }) {
return (
<Chip
size="small"
label={count ?? "—"}
aria-label={count == null ? `${tab} uplift count unavailable` : `${count} ${tab} uplifts`}
/>
);
}
function UpliftApprovalsTabs({
tab,
counts,
onChange,
}: {
tab: UpliftApprovalTab;
counts: Record<UpliftApprovalTab, number>;
counts: Record<UpliftApprovalTab, number | null>;
onChange: (_event: unknown, value: string) => void;
}) {
return (
@ -65,11 +86,7 @@ function UpliftApprovalsTabs({
label={
<Stack direction="row" spacing={1} sx={{ alignItems: "center" }}>
<span>{TAB_LABELS[value]}</span>
<Chip
size="small"
label={counts[value]}
aria-label={`${counts[value]} ${value} uplifts`}
/>
<TabCountPill tab={value} count={counts[value]} />
</Stack>
}
/>
@ -152,9 +169,9 @@ export default function UpliftQueuePage() {
const activeQuery = queries[tab];
const rows = activeQuery.data?.items ?? [];
const counts = {
pending: pendingQuery.data?.totalCount ?? 0,
approved: approvedQuery.data?.totalCount ?? 0,
rejected: rejectedQuery.data?.totalCount ?? 0,
pending: knownTotal(pendingQuery),
approved: knownTotal(approvedQuery),
rejected: knownTotal(rejectedQuery),
};
const pendingExposureTotal = pendingQuery.data?.pendingExposureTotal ?? null;

View file

@ -9,7 +9,8 @@ import { formatDateTime } from "@/lib/time-utils";
import { renderWithProviders } from "@/test/test-utils";
const queueState = vi.hoisted(() => ({
byStatus: {} as Record<string, UpliftsQueueResult>,
byStatus: {} as Record<string, UpliftsQueueResult | undefined>,
errorByStatus: {} as Record<string, Error | undefined>,
requestedStatuses: [] as Array<string | undefined>,
}));
@ -92,11 +93,13 @@ function page(items: UpliftQueueItem[], totalCount = items.length): UpliftsQueue
vi.mock("@/domain/uplifts/use-cases/use-uplifts-queue", () => ({
useUpliftsQueue: (params: UpliftsQueueParams) => {
queueState.requestedStatuses.push(params.status);
const data = queueState.byStatus[params.status ?? ""];
const error = queueState.errorByStatus[params.status ?? ""] ?? null;
return {
data: queueState.byStatus[params.status ?? ""] ?? null,
isLoading: false,
data,
isLoading: data === undefined && error === null,
isFetching: false,
error: null,
error,
refetch: vi.fn(),
};
},
@ -127,6 +130,7 @@ async function openRejectedTab() {
describe("Uplift Approvals rejected tab", () => {
beforeEach(() => {
queueState.requestedStatuses = [];
queueState.errorByStatus = {};
queueState.byStatus = {
Pending: page([pendingItem]),
Approved: page([approvedItem]),
@ -145,6 +149,21 @@ describe("Uplift Approvals rejected tab", () => {
expect(queueState.requestedStatuses).toContain("Rejected");
});
it("never claims a count for a queue that is still loading or failed to load", async () => {
queueState.byStatus.Rejected = undefined;
queueState.errorByStatus.Rejected = new Error("Forbidden");
queueState.byStatus.Approved = undefined;
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
const rejectedPill = screen.getByLabelText("rejected uplift count unavailable");
expect(rejectedPill).toHaveTextContent("—");
expect(screen.getByLabelText("approved uplift count unavailable")).toHaveTextContent("—");
expect(screen.queryByLabelText("0 rejected uplifts")).not.toBeInTheDocument();
expect(screen.queryByLabelText("0 approved uplifts")).not.toBeInTheDocument();
expect(screen.getByLabelText("1 pending uplifts")).toBeInTheDocument();
});
it("lists only rejected uplifts, in the server's most-recently-rejected order", async () => {
const table = await openRejectedTab();