ignore folder

This commit is contained in:
2026-04-21 06:30:48 +07:00
commit ca00b36f19
70 changed files with 3871 additions and 0 deletions

View File

@ -0,0 +1,62 @@
"use client";
import { FormEvent, useState } from "react";
import Modal from "../ui/Modal";
type ApprovalActionModalProps = {
isOpen: boolean;
mode: "approve" | "reject";
title: string;
onSubmit: (notes?: string, checkerRole?: string) => Promise<void>;
onClose: () => void;
};
export default function ApprovalActionModal({
isOpen,
mode,
title,
onSubmit,
onClose
}: ApprovalActionModalProps) {
const [notes, setNotes] = useState("");
const [checkerRole, setCheckerRole] = useState("");
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
setLoading(true);
try {
await onSubmit(notes, checkerRole || undefined);
} finally {
setLoading(false);
}
};
return (
<Modal isOpen={isOpen} title={title} onClose={onClose}>
<form className="vstack gap-3" onSubmit={handleSubmit}>
<textarea
className="form-control"
rows={4}
value={notes}
onChange={(e) => setNotes(e.target.value)}
placeholder="Notes"
/>
<input
className="form-control"
value={checkerRole}
onChange={(e) => setCheckerRole(e.target.value)}
placeholder="Optional checker role (defaults to CHECKER)"
/>
<div className="d-flex justify-content-end gap-2">
<button type="button" className="btn btn-outline-secondary" onClick={onClose}>
Cancel
</button>
<button className="btn btn-primary" disabled={loading} type="submit">
{loading ? "Saving..." : mode === "approve" ? "Approve" : "Reject"}
</button>
</div>
</form>
</Modal>
);
}

View File

@ -0,0 +1,36 @@
"use client";
import DataTable, { TableColumn } from "../ui/Table";
import { WorkflowRequestItem } from "@/types/api";
import StatusBadge from "./StatusBadge";
type ApprovalTableProps = {
data: WorkflowRequestItem[];
onApprove: (request: WorkflowRequestItem) => void;
onReject: (request: WorkflowRequestItem) => void;
};
export default function ApprovalTable({ data, onApprove, onReject }: ApprovalTableProps) {
const columns: TableColumn<WorkflowRequestItem>[] = [
{ key: "resourceType", header: "Resource Type" },
{ key: "resourceId", header: "Resource Id" },
{ key: "makerUsername", header: "Maker" },
{ key: "status", header: "Status", render: (row) => <StatusBadge status={row.status} /> },
{
key: "actions",
header: "Actions",
render: (row) => (
<div className="d-flex gap-2">
<button className="btn btn-success btn-sm" onClick={() => onApprove(row)}>
Approve
</button>
<button className="btn btn-danger btn-sm" onClick={() => onReject(row)}>
Reject
</button>
</div>
)
}
];
return <DataTable columns={columns} data={data} />;
}

View File

@ -0,0 +1,12 @@
import Badge from "../ui/Badge";
import { WorkflowStatus } from "@/types/api";
export default function StatusBadge({ status }: { status: WorkflowStatus }) {
const map = {
PENDING: "warning",
APPROVED: "success",
REJECTED: "danger",
DRAFT: "info"
} as const;
return <Badge variant={map[status]}>{status}</Badge>;
}