mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 08:03:13 +00:00
fix(uplifts): show a dash for Approved on WO when nothing is granted (SH-394)
A work order with a zero granted total rendered $0.00 in the Pending table's Approved on WO column and in the detail modal's Total line. Both now share isGrantedAmount, so zero or unknown totals render a dash and the column always matches the modal Total.
This commit is contained in:
parent
8b58eb5f64
commit
ec3f97dcf6
4 changed files with 167 additions and 4 deletions
|
|
@ -4,3 +4,7 @@ export function formatUpliftMoney(value: number): string {
|
|||
maximumFractionDigits: 2,
|
||||
})}`;
|
||||
}
|
||||
|
||||
export function isGrantedAmount(value: number | null): value is number {
|
||||
return value != null && value > 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ import {
|
|||
TableRow,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { formatUpliftMoney } from "@/app/(protected)/uplifts/_components/format-uplift-money";
|
||||
import {
|
||||
formatUpliftMoney,
|
||||
isGrantedAmount,
|
||||
} from "@/app/(protected)/uplifts/_components/format-uplift-money";
|
||||
import { Text } from "@/components/ui/text";
|
||||
import { useUpliftsCanApprove } from "@/domain/uplifts/use-cases/use-uplifts-can-approve";
|
||||
import type { UpliftQueueItem } from "@/domain/uplifts/types/uplift";
|
||||
|
|
@ -215,7 +218,7 @@ function UpliftApprovalRow({
|
|||
</Text>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{row.approvedOnWoTotal != null ? (
|
||||
{isGrantedAmount(row.approvedOnWoTotal) ? (
|
||||
<Text variant="body">{formatUpliftMoney(row.approvedOnWoTotal)}</Text>
|
||||
) : (
|
||||
<Text variant="caption" tone="muted">
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ import {
|
|||
formatUpliftCalendarDate,
|
||||
formatUpliftDateTime,
|
||||
} from "@/app/(protected)/uplifts/_components/format-uplift-dates";
|
||||
import { formatUpliftMoney } from "@/app/(protected)/uplifts/_components/format-uplift-money";
|
||||
import {
|
||||
formatUpliftMoney,
|
||||
isGrantedAmount,
|
||||
} from "@/app/(protected)/uplifts/_components/format-uplift-money";
|
||||
import { Text } from "@/components/ui/text";
|
||||
import { useWorkOrderUplifts } from "@/domain/work-orders/use-cases/use-work-order-uplifts";
|
||||
import { useUpliftsCanApprove } from "@/domain/uplifts/use-cases/use-uplifts-can-approve";
|
||||
|
|
@ -142,6 +145,7 @@ function ApprovedOnWoBreakdown({
|
|||
breakdown: ExposureBreakdown;
|
||||
unavailable: boolean;
|
||||
}) {
|
||||
const grantedTotal = isGrantedAmount(breakdown.total) ? breakdown.total : null;
|
||||
return (
|
||||
<Box sx={BORDERED_BLOCK_SX}>
|
||||
<BreakdownRow
|
||||
|
|
@ -156,7 +160,12 @@ function ApprovedOnWoBreakdown({
|
|||
strong={false}
|
||||
unavailable={unavailable}
|
||||
/>
|
||||
<BreakdownRow label="Total" value={breakdown.total} strong unavailable={unavailable} />
|
||||
<BreakdownRow
|
||||
label="Total"
|
||||
value={grantedTotal}
|
||||
strong
|
||||
unavailable={unavailable && breakdown.total == null}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
import { fireEvent, screen, within } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { UpliftQueueItem, UpliftsQueueResult } from "@/domain/uplifts/types/uplift";
|
||||
import { renderWithProviders } from "@/test/test-utils";
|
||||
|
||||
const queueState = vi.hoisted(() => ({ data: null as UpliftsQueueResult | null }));
|
||||
const woUplifts = vi.hoisted(() => ({
|
||||
data: [] as Array<Record<string, unknown>> | null,
|
||||
isError: false,
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/uplifts/use-cases/use-uplifts-queue", () => ({
|
||||
useUpliftsQueue: () => ({
|
||||
data: queueState.data,
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
error: null,
|
||||
refetch: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/uplifts/use-cases/use-uplift-actions", () => ({
|
||||
useApproveUplift: () => ({ isPending: false, mutate: vi.fn() }),
|
||||
useRejectUplift: () => ({ isPending: false, mutate: vi.fn() }),
|
||||
useRevokeUplift: () => ({ isPending: false, mutate: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("@/providers/auth-context", async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
useAuthContext: () => ({ user: { userRoles: "Admin" } }),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/uplifts/use-cases/use-uplifts-can-approve", () => ({
|
||||
useUpliftsCanApprove: () => ({ data: true }),
|
||||
}));
|
||||
|
||||
vi.mock("@/domain/work-orders/use-cases/use-work-order-uplifts", () => ({
|
||||
useWorkOrderUplifts: () => ({
|
||||
data: woUplifts.data,
|
||||
isLoading: false,
|
||||
isError: woUplifts.isError,
|
||||
}),
|
||||
}));
|
||||
|
||||
const pendingItem: UpliftQueueItem = {
|
||||
id: 41,
|
||||
status: "Pending",
|
||||
currentNTE: 100,
|
||||
requestedNTE: 250,
|
||||
delta: 150,
|
||||
vendorReason: "Extra parts",
|
||||
requestedAt: "2026-01-15T10:00:00Z",
|
||||
requestedByVendorName: "Gateway",
|
||||
decidedAt: "",
|
||||
decidedByName: "",
|
||||
decisionNote: "",
|
||||
requiredTier: 1,
|
||||
canDecide: true,
|
||||
expiresAt: "",
|
||||
notificationStatus: "",
|
||||
notificationError: "",
|
||||
evidenceDocumentId: null,
|
||||
evidenceFileName: "",
|
||||
evidenceContentType: "",
|
||||
evidenceSizeBytes: null,
|
||||
dispatchNumber: "DSP-41",
|
||||
poNumber: "PO-41",
|
||||
vendorCompanyName: "Gateway Plumbing",
|
||||
workOrderId: 99,
|
||||
dispatchId: 7,
|
||||
woNumber: "WO-99",
|
||||
site: "Site A",
|
||||
serviceName: "Plumbing repair",
|
||||
technicianName: "",
|
||||
workOrderDispatcherName: "",
|
||||
workOrderScheduledDate: "",
|
||||
attachmentCount: null,
|
||||
approvedOnWoAuto: null,
|
||||
approvedOnWoAdmin: null,
|
||||
approvedOnWoTotal: null,
|
||||
workOrderClosed: false,
|
||||
};
|
||||
|
||||
function seedQueue(overrides: Partial<UpliftQueueItem>) {
|
||||
queueState.data = {
|
||||
items: [{ ...pendingItem, ...overrides }],
|
||||
totalCount: 1,
|
||||
page: 1,
|
||||
pageSize: 25,
|
||||
pendingExposureTotal: 250,
|
||||
};
|
||||
}
|
||||
|
||||
async function renderQueuePage() {
|
||||
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
|
||||
renderWithProviders(<UpliftQueuePage />);
|
||||
}
|
||||
|
||||
function approvedOnWoColumnText(): string {
|
||||
const table = screen.getByRole("table", { name: "pending uplift requests" });
|
||||
const headers = within(table).getAllByRole("columnheader");
|
||||
const columnIndex = headers.findIndex((header) => header.textContent === "Approved on WO");
|
||||
const row = within(table).getByRole("row", { name: /Open uplift details for WO-99/ });
|
||||
return within(row).getAllByRole("cell")[columnIndex]?.textContent ?? "";
|
||||
}
|
||||
|
||||
function modalTotalText(): string {
|
||||
fireEvent.click(screen.getByRole("row", { name: /Open uplift details for WO-99/ }));
|
||||
const dialog = screen.getByRole("dialog");
|
||||
const label = within(dialog).getByText("Total");
|
||||
return label.parentElement?.lastElementChild?.textContent ?? "";
|
||||
}
|
||||
|
||||
describe("Uplift Approvals: Approved on WO (SH-394)", () => {
|
||||
beforeEach(() => {
|
||||
woUplifts.data = [];
|
||||
woUplifts.isError = false;
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ total: 0, expected: "—" },
|
||||
{ total: null, expected: "—" },
|
||||
{ total: 125, expected: "$125.00" },
|
||||
])(
|
||||
"renders $expected in the column and the modal Total for total $total",
|
||||
async ({ total, expected }) => {
|
||||
seedQueue({ approvedOnWoTotal: total });
|
||||
await renderQueuePage();
|
||||
|
||||
const column = approvedOnWoColumnText();
|
||||
const modalTotal = modalTotalText();
|
||||
|
||||
expect(column).toBe(expected);
|
||||
expect(modalTotal).toBe(column);
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps the modal Total as a dash when the WO uplift lookup fails but the row reports zero", async () => {
|
||||
woUplifts.data = null;
|
||||
woUplifts.isError = true;
|
||||
seedQueue({ approvedOnWoAuto: 0, approvedOnWoAdmin: 0, approvedOnWoTotal: 0 });
|
||||
await renderQueuePage();
|
||||
|
||||
expect(approvedOnWoColumnText()).toBe("—");
|
||||
expect(modalTotalText()).toBe("—");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue