diff --git a/src/app/(protected)/uplifts/_components/uplift-approvals-table.tsx b/src/app/(protected)/uplifts/_components/uplift-approvals-table.tsx
index 8aa2ec8c..2ab99236 100644
--- a/src/app/(protected)/uplifts/_components/uplift-approvals-table.tsx
+++ b/src/app/(protected)/uplifts/_components/uplift-approvals-table.tsx
@@ -15,7 +15,7 @@ import {
import { formatUpliftMoney } from "@/app/(protected)/uplifts/_components/format-uplift-money";
import { Text } from "@/components/ui/text";
import type { UpliftQueueItem } from "@/domain/uplifts/types/uplift";
-import { getWaitTimeTextClass, timeSince, waitTimeColor } from "@/lib/time-utils";
+import { formatDateTime, getWaitTimeTextClass, timeSince, waitTimeColor } from "@/lib/time-utils";
export type UpliftApprovalTab = "pending" | "approved";
@@ -223,9 +223,16 @@ function UpliftApprovalRow({
{row.requestedByVendorName || "—"}
-
-
-
+ {tab === "pending" ? (
+
+
+
+ ) : (
+ <>
+ {row.decidedByName || "—"}
+ {row.decidedAt ? formatDateTime(row.decidedAt) : "—"}
+ >
+ )}
{tab === "pending" ? (
void;
isDecisionPending: boolean;
}) {
+ const headerCells = tab === "pending" ? PENDING_HEADER_CELLS : APPROVED_HEADER_CELLS;
return (
- {HEADER_CELLS.map((label) => (
+ {headerCells.map((label) => (
{label}
@@ -290,13 +311,13 @@ export function UpliftApprovalsTable({
{isLoading ? (
-
+
) : rows.length === 0 ? (
-
+
{tab === "pending" ? (
No uplifts waiting for approval.
diff --git a/src/app/(protected)/uplifts/_components/uplift-detail-modal.tsx b/src/app/(protected)/uplifts/_components/uplift-detail-modal.tsx
index 8fb24905..04ac0b56 100644
--- a/src/app/(protected)/uplifts/_components/uplift-detail-modal.tsx
+++ b/src/app/(protected)/uplifts/_components/uplift-detail-modal.tsx
@@ -25,6 +25,7 @@ type ModalCallbacks = {
onApprove: (row: UpliftQueueItem) => void;
onReject: (row: UpliftQueueItem) => void;
onRevoke: (row: UpliftQueueItem) => void;
+ onOpenAttachment: (row: UpliftQueueItem) => void;
};
function DetailField({ label, children }: { label: string; children: ReactNode }) {
@@ -49,7 +50,13 @@ function DetailSection({ title, children }: { title: string; children: ReactNode
);
}
-function UpliftAttachments({ item }: { item: UpliftQueueItem }) {
+function UpliftAttachments({
+ item,
+ onOpenAttachment,
+}: {
+ item: UpliftQueueItem;
+ onOpenAttachment: (row: UpliftQueueItem) => void;
+}) {
if (item.evidenceDocumentId == null && !item.evidenceFileName) {
return (
@@ -63,7 +70,12 @@ function UpliftAttachments({ item }: { item: UpliftQueueItem }) {
: 0;
return (
-
+ onOpenAttachment(item) : undefined}
+ clickable={item.evidenceDocumentId != null}
+ />
{extraCount > 0 && }
);
@@ -91,7 +103,13 @@ function WorkOrderSection({ item, info }: { item: UpliftQueueItem; info?: WorkOr
);
}
-function RequestSection({ item }: { item: UpliftQueueItem }) {
+function RequestSection({
+ item,
+ onOpenAttachment,
+}: {
+ item: UpliftQueueItem;
+ onOpenAttachment: (row: UpliftQueueItem) => void;
+}) {
const waitingClass = item.requestedAt
? getWaitTimeTextClass(waitTimeColor(item.requestedAt))
: undefined;
@@ -114,7 +132,7 @@ function RequestSection({ item }: { item: UpliftQueueItem }) {
{item.vendorReason || "No justification provided."}
-
+
);
@@ -269,6 +287,7 @@ export function UpliftDetailModal({
onApprove,
onReject,
onRevoke,
+ onOpenAttachment,
}: {
item: UpliftQueueItem | null;
approvePending: boolean;
@@ -326,7 +345,7 @@ export function UpliftDetailModal({
-
+
- a.requestedAt < b.requestedAt ? -1 : a.requestedAt > b.requestedAt ? 1 : 0,
- );
- } else {
- copy.sort((a, b) => (a.decidedAt > b.decidedAt ? -1 : a.decidedAt < b.decidedAt ? 1 : 0));
- }
- return copy;
-}
-
function UpliftApprovalsHeader({ pendingExposureTotal }: { pendingExposureTotal: number | null }) {
return (
@@ -151,7 +139,7 @@ export default function UpliftQueuePage() {
} = useUpliftApprovalController();
const activeQuery = tab === "pending" ? pendingQuery : approvedQuery;
- const rows = useMemo(() => sortRows(activeQuery.data?.items ?? [], tab), [activeQuery.data, tab]);
+ const rows = activeQuery.data?.items ?? [];
const pendingCount = pendingQuery.data?.totalCount ?? 0;
const pendingExposureTotal = pendingQuery.data?.pendingExposureTotal ?? null;
@@ -204,6 +192,7 @@ export default function UpliftQueuePage() {
onApprove={handleApprove}
onReject={handleRejectRequest}
onRevoke={handleRevokeRequest}
+ onOpenAttachment={handleOpenAttachment}
/>
)}
{
renderWithProviders();
fireEvent.click(screen.getByRole("tab", { name: "Approved" }));
+ expect(screen.getByRole("columnheader", { name: "Approved By" })).toBeInTheDocument();
+ expect(screen.getByRole("columnheader", { name: "Approved At" })).toBeInTheDocument();
+ expect(screen.queryByRole("columnheader", { name: "Waiting" })).not.toBeInTheDocument();
+ expect(screen.getByText("Admin User")).toBeInTheDocument();
const revoke = await screen.findByRole("button", { name: "Revoke" });
expect(revoke).toBeDisabled();
fireEvent.mouseOver(revoke);