fix(operations): move page data helpers to surface modules
Satisfies the Next 16 rule that page files only export page fields: getSupplyBoxDetail/getSupplyBoxList and getReservationList/getReservationDetail move to reservations/surface.ts and pages import from it.
This commit is contained in:
parent
8c10719124
commit
5fb619a5cf
6 changed files with 207 additions and 117 deletions
|
|
@ -63,7 +63,7 @@ export interface SupplyBoxDetailData {
|
|||
* user, never overrideAccess). Returns null for an unknown id so the page can
|
||||
* render a not-found notice.
|
||||
*/
|
||||
export async function getSupplyBoxDetail(
|
||||
async function getSupplyBoxDetail(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
id: string,
|
||||
|
|
@ -114,17 +114,15 @@ function Section({ title, children }: { title: string; children: React.ReactNode
|
|||
function kvRow(label: string, value: React.ReactNode) {
|
||||
return (
|
||||
<div className="flex items-start justify-between gap-4 border border-white/10 px-2 py-1.5">
|
||||
<span className="shrink-0 font-mono text-[9px] uppercase tracking-widest text-white/50">{label}</span>
|
||||
<span className="shrink-0 font-mono text-[9px] uppercase tracking-widest text-white/50">
|
||||
{label}
|
||||
</span>
|
||||
<span className="min-w-0 truncate text-right font-mono text-xs text-white/80">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default async function SupplyBoxDetailPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
export default async function SupplyBoxDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const payload = await getPayload({ config });
|
||||
const { user: authUser } = await payload.auth({
|
||||
|
|
@ -257,7 +255,9 @@ export default async function SupplyBoxDetailPage({
|
|||
key={cmd.id}
|
||||
className="flex items-center justify-between gap-2 border border-white/10 px-2 py-1.5"
|
||||
>
|
||||
<span className="min-w-0 truncate font-mono text-xs text-white/80">{cmd.type}</span>
|
||||
<span className="min-w-0 truncate font-mono text-xs text-white/80">
|
||||
{cmd.type}
|
||||
</span>
|
||||
<span className="flex shrink-0 items-center gap-2">
|
||||
<span
|
||||
className={`border px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-widest ${STATUS_TONE_CLASSES[commandTone(cmd.status)]}`}
|
||||
|
|
@ -278,4 +278,4 @@ export default async function SupplyBoxDetailPage({
|
|||
</PageShell>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export interface SupplyBoxListData {
|
|||
* mints a fresh sessionId, so rows from older generations are stale snapshots;
|
||||
* only the newest sessionId per server is kept.
|
||||
*/
|
||||
export async function getSupplyBoxList(
|
||||
async function getSupplyBoxList(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
): Promise<SupplyBoxListData> {
|
||||
|
|
@ -151,8 +151,8 @@ export default async function SupplyBoxesPage() {
|
|||
<div className="mx-auto flex w-full max-w-7xl flex-col gap-6 px-4 py-6">
|
||||
<PageShell title="Supply Boxes" meta="LOGISTICS // CRATE SYNC">
|
||||
<p className="max-w-2xl text-sm text-white/70">
|
||||
Crate inventory synced from the game server through the Arma bridge.
|
||||
Rows show the newest generation per server; older sessions are filtered out.
|
||||
Crate inventory synced from the game server through the Arma bridge. Rows show the newest
|
||||
generation per server; older sessions are filtered out.
|
||||
</p>
|
||||
</PageShell>
|
||||
|
||||
|
|
@ -209,4 +209,4 @@ export default async function SupplyBoxesPage() {
|
|||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { LedgerRow, NoticeState, PageShell } from "@/components/frontend/operati
|
|||
import type { SurfaceUser } from "@/lib/operations/surface";
|
||||
import { CancelButton } from "@/components/frontend/operations/reservations/ReservationCancelButton";
|
||||
import type { OperationReservation } from "@/payload-types";
|
||||
import { getReservationDetail } from "../surface";
|
||||
|
||||
type PayloadType = Awaited<ReturnType<typeof import("payload").getPayload>>;
|
||||
|
||||
|
|
@ -21,14 +22,18 @@ function relationId(value: unknown): number | null {
|
|||
}
|
||||
|
||||
function relationLabel(value: unknown): string {
|
||||
if (typeof value === "object" && value !== null && "codeName" in (value as { codeName?: unknown })) {
|
||||
if (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
"codeName" in (value as { codeName?: unknown })
|
||||
) {
|
||||
const codeName = (value as { codeName?: unknown }).codeName;
|
||||
if (typeof codeName === "string" && codeName) return codeName;
|
||||
}
|
||||
return String(relationId(value) ?? "n/a");
|
||||
}
|
||||
|
||||
interface ReservationDetail {
|
||||
export interface ReservationDetail {
|
||||
reservation: OperationReservation | null;
|
||||
canCancel: boolean;
|
||||
}
|
||||
|
|
@ -40,31 +45,6 @@ interface ReservationDetail {
|
|||
* canCancel is true only when the row is still reserved AND the viewer holds
|
||||
* operation-reservations:update.
|
||||
*/
|
||||
export async function getReservationDetail(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
id: string,
|
||||
): Promise<ReservationDetail> {
|
||||
let reservation: OperationReservation | null = null;
|
||||
try {
|
||||
reservation = await payload.findByID({
|
||||
collection: "operation-reservations",
|
||||
id: Number(id),
|
||||
depth: 1,
|
||||
user: user ?? undefined,
|
||||
});
|
||||
} catch {
|
||||
reservation = null;
|
||||
}
|
||||
|
||||
const canCancel =
|
||||
reservation !== null &&
|
||||
reservation.status === "reserved" &&
|
||||
user !== null &&
|
||||
(await hasPermission(payload, user, "operation-reservations:update"));
|
||||
|
||||
return { reservation, canCancel };
|
||||
}
|
||||
|
||||
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
|
|
@ -78,7 +58,9 @@ function Section({ title, children }: { title: string; children: React.ReactNode
|
|||
function kvRow(label: string, value: React.ReactNode) {
|
||||
return (
|
||||
<div className="flex items-start justify-between gap-4 border border-white/10 px-2 py-1.5">
|
||||
<span className="shrink-0 font-mono text-[9px] uppercase tracking-widest text-white/50">{label}</span>
|
||||
<span className="shrink-0 font-mono text-[9px] uppercase tracking-widest text-white/50">
|
||||
{label}
|
||||
</span>
|
||||
<span className="min-w-0 truncate text-right font-mono text-xs text-white/80">{value}</span>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -156,7 +138,10 @@ export default async function ReservationDetailPage({
|
|||
) : (
|
||||
<ul className="flex flex-col gap-1">
|
||||
{personnel.map((member) => (
|
||||
<li key={member.id} className="flex items-center justify-between gap-2 border border-white/10 px-2 py-1.5">
|
||||
<li
|
||||
key={member.id}
|
||||
className="flex items-center justify-between gap-2 border border-white/10 px-2 py-1.5"
|
||||
>
|
||||
<span className="min-w-0 truncate font-mono text-xs text-white/80">
|
||||
{relationLabel(member.user)} · id {relationId(member.user)}
|
||||
</span>
|
||||
|
|
@ -201,7 +186,9 @@ export default async function ReservationDetailPage({
|
|||
<span className="min-w-0 truncate font-mono text-xs text-white/80">
|
||||
{relationLabel(line.resource)} · id {relationId(line.resource)}
|
||||
</span>
|
||||
<span className="font-mono text-xs tabular-nums text-white/70">{line.amount}</span>
|
||||
<span className="font-mono text-xs tabular-nums text-white/70">
|
||||
{line.amount}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
@ -211,7 +198,12 @@ export default async function ReservationDetailPage({
|
|||
<Section title="Budget">
|
||||
{budget?.amount != null || budget?.account != null ? (
|
||||
<div className="flex flex-col gap-1">
|
||||
{kvRow("Account", budget.account != null ? `${relationLabel(budget.account)} · id ${relationId(budget.account)}` : "n/a")}
|
||||
{kvRow(
|
||||
"Account",
|
||||
budget.account != null
|
||||
? `${relationLabel(budget.account)} · id ${relationId(budget.account)}`
|
||||
: "n/a",
|
||||
)}
|
||||
{kvRow("Amount", budget.amount ?? "n/a")}
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -221,14 +213,23 @@ export default async function ReservationDetailPage({
|
|||
|
||||
<Section title="Routing">
|
||||
<div className="flex flex-col gap-1">
|
||||
{kvRow("Origin", reservation.origin != null ? relationLabel(reservation.origin) : "n/a")}
|
||||
{kvRow("Destination", reservation.destination != null ? relationLabel(reservation.destination) : "n/a")}
|
||||
{kvRow(
|
||||
"Origin",
|
||||
reservation.origin != null ? relationLabel(reservation.origin) : "n/a",
|
||||
)}
|
||||
{kvRow(
|
||||
"Destination",
|
||||
reservation.destination != null ? relationLabel(reservation.destination) : "n/a",
|
||||
)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<Section title="Metadata">
|
||||
<div className="flex flex-col gap-1">
|
||||
{kvRow("Created by", reservation.createdBy != null ? relationLabel(reservation.createdBy) : "n/a")}
|
||||
{kvRow(
|
||||
"Created by",
|
||||
reservation.createdBy != null ? relationLabel(reservation.createdBy) : "n/a",
|
||||
)}
|
||||
{kvRow("Created at", reservation.createdAt)}
|
||||
{kvRow("Expires", reservation.expiresAt ?? "n/a")}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ import { listReservationOptions } from "@/lib/operations/reservationOptions";
|
|||
import { hasLogisticsQualification } from "@/utils/access-control/hasLogisticsQualification";
|
||||
import { CancelButton } from "@/components/frontend/operations/reservations/ReservationCancelButton";
|
||||
import { CreateReservationDialog } from "@/components/frontend/operations/reservations/CreateReservationDialog";
|
||||
import { getReservationList, type ReservationListData } from "./surface";
|
||||
|
||||
const RESERVATION_PAGE_SIZE = 20;
|
||||
export const RESERVATION_PAGE_SIZE = 20;
|
||||
|
||||
export interface ReservationRow {
|
||||
id: number;
|
||||
|
|
@ -34,16 +35,7 @@ export interface ReservationFilters {
|
|||
operationId?: string;
|
||||
}
|
||||
|
||||
export interface ReservationListData {
|
||||
rows: ReservationRow[];
|
||||
/** True when the viewer holds operation-reservations:read. False -> empty rows. */
|
||||
capability: boolean;
|
||||
page: number;
|
||||
totalDocs: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
type PayloadType = Awaited<ReturnType<typeof import("payload").getPayload>>;
|
||||
export type PayloadType = Awaited<ReturnType<typeof import("payload").getPayload>>;
|
||||
|
||||
/**
|
||||
* List of allocation reservations with status/operationId filters and
|
||||
|
|
@ -53,51 +45,6 @@ type PayloadType = Awaited<ReturnType<typeof import("payload").getPayload>>;
|
|||
* result (capability false) so the page can render the permission notice
|
||||
* instead of a list that looks like "no data".
|
||||
*/
|
||||
export async function getReservationList(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
filters: ReservationFilters,
|
||||
requestedPage = 1,
|
||||
): Promise<ReservationListData> {
|
||||
const canSee = await hasPermission(payload, user, "operation-reservations:read");
|
||||
if (!canSee) {
|
||||
return { rows: [], capability: false, page: 1, totalDocs: 0, totalPages: 0 };
|
||||
}
|
||||
|
||||
const conditions: Where[] = [];
|
||||
if (filters.status) conditions.push({ status: { equals: filters.status } });
|
||||
if (filters.operationId) conditions.push({ operationId: { equals: filters.operationId } });
|
||||
const where: Where | undefined = conditions.length > 0 ? { and: conditions } : undefined;
|
||||
|
||||
const found = await payload.find({
|
||||
collection: "operation-reservations",
|
||||
where,
|
||||
sort: "-createdAt",
|
||||
page: Math.max(1, requestedPage),
|
||||
limit: RESERVATION_PAGE_SIZE,
|
||||
depth: 0,
|
||||
user: user ?? undefined,
|
||||
});
|
||||
|
||||
const rows: ReservationRow[] = found.docs.map((doc) => {
|
||||
const r = doc as unknown as ReservationRow;
|
||||
return {
|
||||
id: r.id,
|
||||
reservationKey: r.reservationKey,
|
||||
operationId: r.operationId,
|
||||
status: r.status,
|
||||
expiresAt: r.expiresAt ?? null,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
rows,
|
||||
capability: true,
|
||||
page: found.page ?? Math.max(1, requestedPage),
|
||||
totalDocs: found.totalDocs ?? found.docs.length,
|
||||
totalPages: found.totalPages ?? 1,
|
||||
};
|
||||
}
|
||||
|
||||
function reservationHref(filters: ReservationFilters, page: number): string {
|
||||
const params = new URLSearchParams();
|
||||
|
|
@ -140,7 +87,12 @@ export default async function ReservationsPage({
|
|||
status: params.status || undefined,
|
||||
operationId: params.operationId || undefined,
|
||||
};
|
||||
const data = await getReservationList(payload, surfaceUser, filters, Number.isNaN(page) ? 1 : page);
|
||||
const data = await getReservationList(
|
||||
payload,
|
||||
surfaceUser,
|
||||
filters,
|
||||
Number.isNaN(page) ? 1 : page,
|
||||
);
|
||||
|
||||
// The cancel control is server-gated: only viewers holding
|
||||
// operation-reservations:update may render it, and only on reserved rows.
|
||||
|
|
@ -154,9 +106,7 @@ export default async function ReservationsPage({
|
|||
const canCreate = user
|
||||
? await hasPermission(payload, user, "operation-reservations:create")
|
||||
: false;
|
||||
const canManageLogistics = user
|
||||
? await hasLogisticsQualification(payload, user)
|
||||
: false;
|
||||
const canManageLogistics = user ? await hasLogisticsQualification(payload, user) : false;
|
||||
const options = canCreate && user ? await listReservationOptions(payload, user) : null;
|
||||
|
||||
return (
|
||||
|
|
@ -168,9 +118,16 @@ export default async function ReservationsPage({
|
|||
row captures what was consumed or returned.
|
||||
</p>
|
||||
|
||||
<form method="get" className="flex flex-wrap items-end gap-3" data-slot="reservations-filters">
|
||||
<form
|
||||
method="get"
|
||||
className="flex flex-wrap items-end gap-3"
|
||||
data-slot="reservations-filters"
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="font-mono text-[9px] uppercase tracking-widest text-white/50" htmlFor="reservation-status">
|
||||
<label
|
||||
className="font-mono text-[9px] uppercase tracking-widest text-white/50"
|
||||
htmlFor="reservation-status"
|
||||
>
|
||||
Status
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -187,7 +144,10 @@ export default async function ReservationsPage({
|
|||
</select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="font-mono text-[9px] uppercase tracking-widest text-white/50" htmlFor="reservation-operation">
|
||||
<label
|
||||
className="font-mono text-[9px] uppercase tracking-widest text-white/50"
|
||||
htmlFor="reservation-operation"
|
||||
>
|
||||
Operation
|
||||
</label>
|
||||
<input
|
||||
|
|
|
|||
109
src/app/(frontend)/operations/reservations/surface.ts
Normal file
109
src/app/(frontend)/operations/reservations/surface.ts
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import {
|
||||
RESERVATION_PAGE_SIZE,
|
||||
type PayloadType,
|
||||
type ReservationFilters,
|
||||
type ReservationRow,
|
||||
} from "./page";
|
||||
import type { OperationReservation } from "@/payload-types";
|
||||
import type { ReservationDetail } from "./[id]/page";
|
||||
import config from "@payload-config";
|
||||
import { getPayload } from "payload";
|
||||
import type { Where } from "payload";
|
||||
import { headers as nextHeaders } from "next/headers";
|
||||
import Link from "next/link";
|
||||
import { isPayloadUser } from "@/utils/access-control/isPayloadUser";
|
||||
import { hasPermission } from "@/utils/access-control/hasPermission";
|
||||
import {
|
||||
LedgerRow,
|
||||
NoticeState,
|
||||
PageShell,
|
||||
STATUS_TONE_CLASSES,
|
||||
statusToneFor,
|
||||
type ReadoutCell,
|
||||
} from "@/components/frontend/operations";
|
||||
import type { SurfaceUser } from "@/lib/operations/surface";
|
||||
import { listReservationOptions } from "@/lib/operations/reservationOptions";
|
||||
import { hasLogisticsQualification } from "@/utils/access-control/hasLogisticsQualification";
|
||||
import { CancelButton } from "@/components/frontend/operations/reservations/ReservationCancelButton";
|
||||
import { CreateReservationDialog } from "@/components/frontend/operations/reservations/CreateReservationDialog";
|
||||
|
||||
export interface ReservationListData {
|
||||
rows: ReservationRow[];
|
||||
/** True when the viewer holds operation-reservations:read. False -> empty rows. */
|
||||
capability: boolean;
|
||||
page: number;
|
||||
totalDocs: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export async function getReservationList(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
filters: ReservationFilters,
|
||||
requestedPage = 1,
|
||||
): Promise<ReservationListData> {
|
||||
const canSee = await hasPermission(payload, user, "operation-reservations:read");
|
||||
if (!canSee) {
|
||||
return { rows: [], capability: false, page: 1, totalDocs: 0, totalPages: 0 };
|
||||
}
|
||||
|
||||
const conditions: Where[] = [];
|
||||
if (filters.status) conditions.push({ status: { equals: filters.status } });
|
||||
if (filters.operationId) conditions.push({ operationId: { equals: filters.operationId } });
|
||||
const where: Where | undefined = conditions.length > 0 ? { and: conditions } : undefined;
|
||||
|
||||
const found = await payload.find({
|
||||
collection: "operation-reservations",
|
||||
where,
|
||||
sort: "-createdAt",
|
||||
page: Math.max(1, requestedPage),
|
||||
limit: RESERVATION_PAGE_SIZE,
|
||||
depth: 0,
|
||||
user: user ?? undefined,
|
||||
});
|
||||
|
||||
const rows: ReservationRow[] = found.docs.map((doc) => {
|
||||
const r = doc as unknown as ReservationRow;
|
||||
return {
|
||||
id: r.id,
|
||||
reservationKey: r.reservationKey,
|
||||
operationId: r.operationId,
|
||||
status: r.status,
|
||||
expiresAt: r.expiresAt ?? null,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
rows,
|
||||
capability: true,
|
||||
page: found.page ?? Math.max(1, requestedPage),
|
||||
totalDocs: found.totalDocs ?? found.docs.length,
|
||||
totalPages: found.totalPages ?? 1,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getReservationDetail(
|
||||
payload: PayloadType,
|
||||
user: SurfaceUser,
|
||||
id: string,
|
||||
): Promise<ReservationDetail> {
|
||||
let reservation: OperationReservation | null = null;
|
||||
try {
|
||||
reservation = await payload.findByID({
|
||||
collection: "operation-reservations",
|
||||
id: Number(id),
|
||||
depth: 1,
|
||||
user: user ?? undefined,
|
||||
});
|
||||
} catch {
|
||||
reservation = null;
|
||||
}
|
||||
|
||||
const canCancel =
|
||||
reservation !== null &&
|
||||
reservation.status === "reserved" &&
|
||||
user !== null &&
|
||||
(await hasPermission(payload, user, "operation-reservations:update"));
|
||||
|
||||
return { reservation, canCancel };
|
||||
}
|
||||
|
|
@ -2,9 +2,12 @@ import { getPayload, Payload } from "payload";
|
|||
import config from "@/payload.config";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi, type MockInstance } from "vitest";
|
||||
import type { OperationReservation, User } from "@/payload-types";
|
||||
import { getReservationList } from "@/app/(frontend)/operations/reservations/page";
|
||||
import { getReservationDetail } from "@/app/(frontend)/operations/reservations/[id]/page";
|
||||
import { createReservation, cancelReservation } from "@/app/(frontend)/operations/reservations/actions";
|
||||
import { getReservationList } from "@/app/(frontend)/operations/reservations/surface";
|
||||
import { getReservationDetail } from "@/app/(frontend)/operations/reservations/surface";
|
||||
import {
|
||||
createReservation,
|
||||
cancelReservation,
|
||||
} from "@/app/(frontend)/operations/reservations/actions";
|
||||
|
||||
// Mock next/headers so the action's authenticate() can run outside a request.
|
||||
vi.mock("next/headers", () => ({
|
||||
|
|
@ -85,7 +88,9 @@ beforeAll(async () => {
|
|||
afterAll(async () => {
|
||||
if (!payload) return;
|
||||
for (const id of reservationIds) {
|
||||
await payload.delete({ collection: "operation-reservations", id, overrideAccess: true }).catch(() => {});
|
||||
await payload
|
||||
.delete({ collection: "operation-reservations", id, overrideAccess: true })
|
||||
.catch(() => {});
|
||||
}
|
||||
for (const id of userIds) {
|
||||
await payload.delete({ collection: "users", id, overrideAccess: true }).catch(() => {});
|
||||
|
|
@ -122,12 +127,22 @@ describe("reservation surfaces: getReservationList", () => {
|
|||
const cancelledId = await createReservedReservation(`${RUN}-filter-c`, `${RUN}-op-filter-c`);
|
||||
await cancelReservation({ reservationId: cancelledId });
|
||||
|
||||
const reserved = await getReservationList(payload, { id: superUser.id }, { status: "reserved" }, 1);
|
||||
const reserved = await getReservationList(
|
||||
payload,
|
||||
{ id: superUser.id },
|
||||
{ status: "reserved" },
|
||||
1,
|
||||
);
|
||||
const reservedRows = reserved.rows.filter((r) => r.reservationKey === `${RUN}-filter-r`);
|
||||
expect(reservedRows).toHaveLength(1);
|
||||
expect(reservedRows[0].status).toBe("reserved");
|
||||
|
||||
const cancelled = await getReservationList(payload, { id: superUser.id }, { status: "cancelled" }, 1);
|
||||
const cancelled = await getReservationList(
|
||||
payload,
|
||||
{ id: superUser.id },
|
||||
{ status: "cancelled" },
|
||||
1,
|
||||
);
|
||||
const cancelledRows = cancelled.rows.filter((r) => r.reservationKey === `${RUN}-filter-c`);
|
||||
expect(cancelledRows).toHaveLength(1);
|
||||
expect(cancelledRows[0].status).toBe("cancelled");
|
||||
|
|
@ -136,7 +151,12 @@ describe("reservation surfaces: getReservationList", () => {
|
|||
it("narrows rows by operationId", async () => {
|
||||
authSpy.mockResolvedValue({ user: superUser });
|
||||
await createReservedReservation(`${RUN}-opid-1`, `${RUN}-op-specific`);
|
||||
const data = await getReservationList(payload, { id: superUser.id }, { operationId: `${RUN}-op-specific` }, 1);
|
||||
const data = await getReservationList(
|
||||
payload,
|
||||
{ id: superUser.id },
|
||||
{ operationId: `${RUN}-op-specific` },
|
||||
1,
|
||||
);
|
||||
expect(data.rows).toHaveLength(1);
|
||||
expect(data.rows[0].operationId).toBe(`${RUN}-op-specific`);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue