diff --git a/src/pages/api/approval-workflows/[id]/edit.ts b/src/pages/api/approval-workflows/[id]/edit.ts index 2d517f0e..c61e200a 100644 --- a/src/pages/api/approval-workflows/[id]/edit.ts +++ b/src/pages/api/approval-workflows/[id]/edit.ts @@ -2,7 +2,7 @@ import { ApprovalWorkflow } from "@/interfaces/approval.workflow"; import { sessionOptions } from "@/lib/session"; import { requestUser } from "@/utils/api"; -import { createApprovalWorkflows, updateApprovalWorkflow } from "@/utils/approval.workflows.be"; +import { updateApprovalWorkflow } from "@/utils/approval.workflows.be"; import { withIronSessionApiRoute } from "iron-session/next"; import type { NextApiRequest, NextApiResponse } from "next"; @@ -23,6 +23,8 @@ async function put(req: NextApiRequest, res: NextApiResponse) { const { id } = req.query as { id?: string }; const approvalWorkflow: ApprovalWorkflow = req.body; - if (id && approvalWorkflow) - return res.status(204).json(await updateApprovalWorkflow(id, approvalWorkflow)); + if (id && approvalWorkflow) { + await updateApprovalWorkflow(id, approvalWorkflow); + return res.status(204).end(); + } } diff --git a/src/pages/api/approval-workflows/[id]/index.ts b/src/pages/api/approval-workflows/[id]/index.ts index 16efab91..e8de49a8 100644 --- a/src/pages/api/approval-workflows/[id]/index.ts +++ b/src/pages/api/approval-workflows/[id]/index.ts @@ -2,7 +2,7 @@ import { ApprovalWorkflow } from "@/interfaces/approval.workflow"; import { sessionOptions } from "@/lib/session"; import { requestUser } from "@/utils/api"; -import { createApprovalWorkflows, deleteApprovalWorkflow, updateApprovalWorkflow } from "@/utils/approval.workflows.be"; +import { deleteApprovalWorkflow, updateApprovalWorkflow } from "@/utils/approval.workflows.be"; import { withIronSessionApiRoute } from "iron-session/next"; import type { NextApiRequest, NextApiResponse } from "next"; @@ -10,6 +10,7 @@ export default withIronSessionApiRoute(handler, sessionOptions); async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "DELETE") return await del(req, res); + if (req.method === "PUT") return await put(req, res); } async function del(req: NextApiRequest, res: NextApiResponse) { @@ -22,6 +23,22 @@ async function del(req: NextApiRequest, res: NextApiResponse) { const { id } = req.query as { id?: string }; - if (id) - return res.status(200).json(await deleteApprovalWorkflow(id)); + if (id) return res.status(200).json(await deleteApprovalWorkflow(id)); +} + +async function put(req: NextApiRequest, res: NextApiResponse) { + const user = await requestUser(req, res); + if (!user) return res.status(401).json({ ok: false }); + + if (!["admin", "developer", "corporate", "mastercorporate"].includes(user.type)) { + return res.status(403).json({ ok: false }); + } + + const { id } = req.query as { id?: string }; + const workflow = req.body; + + if (id && workflow) { + await updateApprovalWorkflow(id, workflow); + return res.status(204).end(); + } } diff --git a/src/pages/approval-workflows/[id]/clone.tsx b/src/pages/approval-workflows/[id]/clone.tsx index 7246b695..f91a83da 100644 --- a/src/pages/approval-workflows/[id]/clone.tsx +++ b/src/pages/approval-workflows/[id]/clone.tsx @@ -124,7 +124,6 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti ...cloneWorkflow, steps: cloneWorkflow.steps.map(step => ({ ...step, - currentStep: step.stepNumber === 1 ? true : false, completed: false, assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined) })) @@ -137,23 +136,21 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti setIsRedirecting(true); setTimeout(() => { router.push("/approval-workflows"); - }, 2000); + }, 1000); }) .catch((reason) => { if (reason.response.status === 401) { toast.error("Not logged in!"); - return router.push("/login"); - } - if (reason.response.status === 403) { + } else if (reason.response.status === 403) { toast.error("You do not have permission to clone Approval Workflows!"); - return router.push("/approval-workflows"); + } else { + toast.error("Something went wrong, please try again later."); } - toast.error("Something went wrong, please try again later."); setIsLoading(false); + console.log("Submitted Values:", filteredWorkflow); return; }) - console.log("Form submitted! Filtered Values:", filteredWorkflow); }; const onWorkflowChange = (wf: EditableApprovalWorkflow) => { diff --git a/src/pages/approval-workflows/[id]/edit.tsx b/src/pages/approval-workflows/[id]/edit.tsx index 8bad8e91..7c9a1d83 100644 --- a/src/pages/approval-workflows/[id]/edit.tsx +++ b/src/pages/approval-workflows/[id]/edit.tsx @@ -95,12 +95,11 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props) ...updatedWorkflow, steps: updatedWorkflow.steps.map(step => ({ ...step, - currentStep: step.stepNumber === 1 ? true : false, completed: false, assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined) })) }; - + axios .put(`/api/approval-workflows/${updatedWorkflow.id}/edit`, filteredWorkflow) .then(() => { @@ -108,23 +107,20 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props) setIsRedirecting(true); setTimeout(() => { router.push("/approval-workflows"); - }, 2000); + }, 1000); }) .catch((reason) => { if (reason.response.status === 401) { toast.error("Not logged in!"); - return router.push("/login"); - } - if (reason.response.status === 403) { + } else if (reason.response.status === 403) { toast.error("You do not have permission to edit Approval Workflows!"); - return router.push("/approval-workflows"); + } else { + toast.error("Something went wrong, please try again later."); } - toast.error("Something went wrong, please try again later."); setIsLoading(false); + console.log("Submitted Values:", filteredWorkflow); return; }) - - console.log("Form submitted! Filtered Values:", filteredWorkflow); }; const onWorkflowChange = (updatedWorkflow: EditableApprovalWorkflow) => { @@ -159,7 +155,7 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props) { const user = await requestUser(req, res); @@ -75,6 +79,9 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques const [selectedStep, setSelectedStep] = useState(steps[selectedStepIndex]); const [isPanelOpen, setIsPanelOpen] = useState(true); const [comments, setComments] = useState(selectedStep.comments || ""); + const [isLoading, setIsLoading] = useState(false); + const [isRedirecting, setIsRedirecting] = useState(false); + const router = useRouter(); const handleStepClick = (index: number, stepInfo: WorkflowStep) => { setSelectedStep(stepInfo); @@ -84,11 +91,82 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques }; const handleSaveComments = () => { + setIsLoading(true); + const updatedWorkflow: ApprovalWorkflow = { + ...workflow, + steps: workflow.steps.map((step, index) => + index === selectedStepIndex ? + { + ...step, + comments: comments, + } + : step + ) + }; + + axios + .put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow) + .then(() => { + toast.success("Comments saved successfully."); + setIsRedirecting(true); + setTimeout(() => { + router.reload(); + }, 1000); + }) + .catch((reason) => { + if (reason.response.status === 401) { + toast.error("Not logged in!"); + } else if (reason.response.status === 403) { + toast.error("You do not have permission to approve this step!"); + } else { + toast.error("Something went wrong, please try again later."); + } + setIsLoading(false); + console.log("Submitted Values:", updatedWorkflow); + return; + }) }; const handleApproveStep = () => { - + if (!confirm(`Are you sure you want to approve this step?`)) return; + setIsLoading(true); + + const updatedWorkflow: ApprovalWorkflow = { + ...workflow, + steps: workflow.steps.map((step, index) => + index === selectedStepIndex ? + { + ...step, + completed: true, + completedBy: user.id, + completedDate: Date.now(), + } + : step + ) + }; + + axios + .put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow) + .then(() => { + toast.success("Step approved successfully."); + setIsRedirecting(true); + setTimeout(() => { + router.reload(); + }, 1000); + }) + .catch((reason) => { + if (reason.response.status === 401) { + toast.error("Not logged in!"); + } else if (reason.response.status === 403) { + toast.error("You do not have permission to approve this step!"); + } else { + toast.error("Something went wrong, please try again later."); + } + setIsLoading(false); + console.log("Submitted Values:", updatedWorkflow); + return; + }) }; return ( @@ -120,7 +198,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques )} - - {selectedStepIndex === currentStep && + + {selectedStepIndex === currentStep && !selectedStep.completed && } @@ -267,14 +361,32 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques placeholder="Input comments here" className="w-full h-64 p-2 border-2 rounded-xl shadow-lg focus:border-mti-purple focus:outline-none mt-3 resize-none" /> +
diff --git a/src/pages/approval-workflows/create.tsx b/src/pages/approval-workflows/create.tsx index d2299c4a..73d5a4c0 100644 --- a/src/pages/approval-workflows/create.tsx +++ b/src/pages/approval-workflows/create.tsx @@ -86,13 +86,13 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesApprover if (workflows.length === 0) { setIsLoading(false); + return; } const filteredWorkflows: ApprovalWorkflow[] = workflows.map(workflow => ({ ...workflow, steps: workflow.steps.map(step => ({ ...step, - currentStep: step.stepNumber === 1 ? true : false, completed: false, assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined) })) @@ -105,23 +105,22 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesApprover setIsRedirecting(true); setTimeout(() => { router.push("/approval-workflows"); - }, 2000); + }, 1000); }) .catch((reason) => { if (reason.response.status === 401) { toast.error("Not logged in!"); - return router.push("/login"); } - if (reason.response.status === 403) { + else if (reason.response.status === 403) { toast.error("You do not have permission to create Approval Workflows!"); - return router.push("/approval-workflows"); } - toast.error("Something went wrong, please try again later."); + else { + toast.error("Something went wrong, please try again later."); + } setIsLoading(false); + console.log("Submitted Values:", filteredWorkflows); return; }) - - console.log("Form submitted! Filtered Values:", filteredWorkflows); }; const handleAddNewWorkflow = () => { diff --git a/src/pages/approval-workflows/index.tsx b/src/pages/approval-workflows/index.tsx index c7c71731..a8b59b26 100644 --- a/src/pages/approval-workflows/index.tsx +++ b/src/pages/approval-workflows/index.tsx @@ -27,6 +27,7 @@ import Input from "@/components/Low/Input"; import { FaRegClone } from "react-icons/fa6"; import useApprovalWorkflows from "@/hooks/useApprovalWorkflows"; import { getApprovalWorkflows } from "@/utils/approval.workflows.be"; +import { useRouter } from "next/router"; const columnHelper = createColumnHelper(); @@ -110,6 +111,7 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees, const [statusFilter, setStatusFilter] = useState(undefined); const [entityFilter, setEntityFilter] = useState(undefined); const [nameFilter, setNameFilter] = useState(""); + const router = useRouter(); useEffect(() => { const filters: Array<(workflow: ApprovalWorkflow) => boolean> = []; @@ -154,21 +156,18 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees, .then(() => { toast.success(`Successfully deleted ${name} Approval Workflow.`); setTimeout(() => { - window.location.reload(); - }, 2000); + router.reload(); + }, 1000); }) .catch((reason) => { if (reason.response.status === 404) { toast.error("Approval Workflow not found!"); - return; - } - - if (reason.response.status === 403) { + } else if (reason.response.status === 403) { toast.error("You do not have permission to delete an Approval Workflow!"); - return; + } else { + toast.error("Something went wrong, please try again later."); } - - toast.error("Something went wrong, please try again later."); + return; }) }; diff --git a/src/utils/approval.workflows.be.ts b/src/utils/approval.workflows.be.ts index e876a279..f82056dd 100644 --- a/src/utils/approval.workflows.be.ts +++ b/src/utils/approval.workflows.be.ts @@ -15,17 +15,20 @@ export const getApprovalWorkflow = async (id: string) => { return await db.collection("approval-workflows").findOne({ _id: new ObjectId(id) }); }; -export const createApprovalWorkflow = async (workflow: Omit) => { - return await db.collection("approval-workflows").insertOne(workflow); +export const createApprovalWorkflow = async (workflow: ApprovalWorkflow) => { + const { _id, ...workflowWithoutId } = workflow as ApprovalWorkflow; + return await db.collection("approval-workflows").insertOne(workflowWithoutId); }; -export const createApprovalWorkflows = async (workflows: Omit[]) => { +export const createApprovalWorkflows = async (workflows: ApprovalWorkflow[]) => { if (workflows.length === 0) return; - return await db.collection("approval-workflows").insertMany(workflows); + const workflowsWithoutIds: ApprovalWorkflow[] = workflows.map(({_id, ...wfs}) => wfs) + return await db.collection("approval-workflows").insertMany(workflowsWithoutIds); }; -export const updateApprovalWorkflow = async (id: string, workflow: Omit) => { - return await db.collection("approval-workflows").replaceOne({ _id: new ObjectId(id) }, workflow); +export const updateApprovalWorkflow = async (id: string, workflow: ApprovalWorkflow) => { + const { _id, ...workflowWithoutId } = workflow as ApprovalWorkflow; + return await db.collection("approval-workflows").replaceOne({ _id: new ObjectId(id) }, workflowWithoutId); }; export const deleteApprovalWorkflow = async (id: string) => {