pelagia-portal/App/app/(portal)/approvals/[id]/approval-actions.tsx
2026-05-18 23:18:58 +05:30

121 lines
5.1 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { approvepo, rejectPo, requestEdits, requestVendorId } from "./actions";
import type { POStatus } from "@prisma/client";
export function ApprovalActions({
poId,
poStatus,
}: {
poId: string;
poStatus: POStatus;
}) {
const router = useRouter();
const [note, setNote] = useState("");
const [activeAction, setActiveAction] = useState<string | null>(null);
const [pending, setPending] = useState<string | null>(null);
const [error, setError] = useState("");
async function dispatch(action: string, requireNote = false) {
if (requireNote && !note.trim()) {
setError("A note is required for this action.");
return;
}
setPending(action);
setError("");
let result: { ok: true } | { error: string } | undefined;
if (action === "approve") result = await approvepo({ poId, note });
else if (action === "approve_note") result = await approvepo({ poId, note, withNote: true });
else if (action === "reject") result = await rejectPo({ poId, note });
else if (action === "request_edits") result = await requestEdits({ poId, note });
else if (action === "request_vendor_id") result = await requestVendorId({ poId });
if (result && "error" in result) {
setError(result.error);
setPending(null);
} else {
router.push("/approvals");
router.refresh();
}
}
return (
<div className="rounded-lg border border-neutral-200 bg-white p-4 md:p-6">
<h3 className="text-base font-semibold text-neutral-900 mb-4">Decision</h3>
{(activeAction === "reject" || activeAction === "request_edits" || activeAction === "approve_note") && (
<div className="mb-4">
<label className="block text-sm font-medium text-neutral-700 mb-1.5">
Note {activeAction !== "approve_note" ? "(required)" : "(optional)"}
</label>
<textarea
rows={3}
value={note}
onChange={(e) => setNote(e.target.value)}
className="w-full rounded-lg border border-neutral-300 px-3 py-2.5 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 resize-none"
placeholder={
activeAction === "reject"
? "Reason for rejection…"
: activeAction === "request_edits"
? "What needs to be changed…"
: "Optional note for the submitter…"
}
/>
</div>
)}
{error && (
<p className="mb-4 text-sm text-danger-700 bg-danger-50 rounded-lg px-3 py-2">{error}</p>
)}
<div className="flex flex-col sm:flex-row flex-wrap items-stretch sm:items-center gap-2 sm:gap-3">
<button
onClick={() => {
setActiveAction("reject");
if (activeAction === "reject") dispatch("reject", true);
}}
disabled={!!pending}
className="w-full sm:w-auto rounded-lg border border-danger bg-danger-50 px-4 py-2.5 text-sm font-medium text-danger-700 hover:bg-danger-100 disabled:opacity-60 transition-colors"
>
{pending === "reject" ? "Rejecting…" : activeAction === "reject" ? "Confirm Reject" : "Reject"}
</button>
<button
onClick={() => {
setActiveAction("request_edits");
if (activeAction === "request_edits") dispatch("request_edits", true);
}}
disabled={!!pending}
className="w-full sm:w-auto rounded-lg border border-warning bg-warning-50 px-4 py-2.5 text-sm font-medium text-warning-700 hover:bg-warning-100 disabled:opacity-60 transition-colors"
>
{pending === "request_edits" ? "Sending…" : activeAction === "request_edits" ? "Send Edit Request" : "Request Edits"}
</button>
<button
onClick={() => dispatch("request_vendor_id")}
disabled={!!pending}
className="w-full sm:w-auto rounded-lg border border-neutral-300 bg-white px-4 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:opacity-60 transition-colors"
>
{pending === "request_vendor_id" ? "Sending…" : "Request Vendor ID"}
</button>
<button
onClick={() => {
setActiveAction("approve_note");
if (activeAction === "approve_note") dispatch("approve_note");
}}
disabled={!!pending}
className="w-full sm:w-auto rounded-lg border border-neutral-300 bg-white px-4 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:opacity-60 transition-colors"
>
{pending === "approve_note" ? "Approving…" : activeAction === "approve_note" ? "Confirm Approve with Remarks" : "Approve with Remarks"}
</button>
<button
onClick={() => dispatch("approve")}
disabled={!!pending}
className="w-full sm:w-auto rounded-lg bg-success px-4 py-2.5 text-sm font-semibold text-white hover:opacity-90 disabled:opacity-60 transition-opacity"
>
{pending === "approve" ? "Approving…" : "Approve"}
</button>
</div>
</div>
);
}