"use server"; import config from "@payload-config"; import { getPayload } from "payload"; import type { AssignmentTransfer } from "@/payload-types"; import { isPayloadUser } from "@/utils/access-control/isPayloadUser"; import { appealTransfer as appealTransferCore, cancelTransfer as cancelTransferCore, createTransferRequest, recordTransferDecision, resolveAppeal as resolveAppealCore, } from "@/lib/transfers"; export interface ActionResult { readonly success: boolean; readonly error?: string; readonly data?: T; } /** * Web action mapping: requestTransfer → createTransferRequest, approveTransfer and * rejectTransfer → recordTransferDecision, appealTransfer → appealTransfer, * resolveAppeal → resolveAppeal, and cancelTransfer → cancelTransfer. The authenticated * user supplies each core function's actorUserId/requesterId. */ async function authenticate() { const payloadConfig = await config; const payload = await getPayload({ config: payloadConfig }); const { headers } = await import("next/headers"); const hdrs = await headers(); const { user } = await payload.auth({ headers: hdrs, canSetHeaders: false }); if (!isPayloadUser(user)) { throw new Error("Unauthorized"); } return { payload, user }; } function actionFailure(caughtError: unknown): ActionResult { const message = caughtError instanceof Error ? caughtError.message : "Unknown error"; return { success: false, error: message === "Unauthorized" ? "You must be logged in." : message, }; } export async function requestTransfer(input: { readonly fromAssignmentId: number; readonly toAssignmentId: number; readonly note?: string; }): Promise> { try { const { payload, user } = await authenticate(); const transfer = await createTransferRequest(payload, { requesterId: user.id, fromAssignmentId: input.fromAssignmentId, toAssignmentId: input.toAssignmentId, ...(input.note !== undefined ? { note: input.note } : {}), }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } } export async function approveTransfer( requestId: number, side: "from" | "to", ): Promise> { try { const { payload, user } = await authenticate(); const transfer = await recordTransferDecision(payload, { requestId, side, decision: "approved", actorUserId: user.id, }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } } export async function rejectTransfer( requestId: number, side: "from" | "to", reason: string, ): Promise> { try { const { payload, user } = await authenticate(); const transfer = await recordTransferDecision(payload, { requestId, side, decision: "rejected", reason, actorUserId: user.id, }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } } export async function appealTransfer( requestId: number, note?: string, ): Promise> { try { const { payload, user } = await authenticate(); const transfer = await appealTransferCore(payload, { requestId, actorUserId: user.id, ...(note !== undefined ? { note } : {}), }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } } export async function resolveAppeal( requestId: number, approve: boolean, note?: string, ): Promise> { try { const { payload, user } = await authenticate(); const transfer = await resolveAppealCore(payload, { requestId, approve, actorUserId: user.id, ...(note !== undefined ? { note } : {}), }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } } export async function cancelTransfer( requestId: number, ): Promise> { try { const { payload, user } = await authenticate(); const transfer = await cancelTransferCore(payload, { requestId, actorUserId: user.id, }); return { success: true, data: transfer }; } catch (caughtError) { return actionFailure(caughtError); } }