import RequestedBy from "@/components/ApprovalWorkflows/RequestedBy"; import StartedOn from "@/components/ApprovalWorkflows/StartedOn"; import Status from "@/components/ApprovalWorkflows/Status"; import Tip from "@/components/ApprovalWorkflows/Tip"; import UserWithProfilePic from "@/components/ApprovalWorkflows/UserWithProfilePic"; import WorkflowStepComponent from "@/components/ApprovalWorkflows/WorkflowStepComponent"; import Layout from "@/components/High/Layout"; import Button from "@/components/Low/Button"; import { ApprovalWorkflow, getUserTypeLabelShort, WorkflowStep } from "@/interfaces/approval.workflow"; import { User } from "@/interfaces/user"; import { sessionOptions } from "@/lib/session"; import { redirect, serialize } from "@/utils"; import { requestUser } from "@/utils/api"; import { getApprovalWorkflow } from "@/utils/approval.workflows.be"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; import { getSpecificUsers, getUser } from "@/utils/users.be"; import axios from "axios"; import { AnimatePresence, LayoutGroup, motion } from "framer-motion"; import { withIronSessionSsr } from "iron-session/next"; import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; import { BsChevronLeft } from "react-icons/bs"; import { FaSpinner, FaWpforms } from "react-icons/fa6"; import { FiSave } from "react-icons/fi"; import { IoMdCheckmarkCircleOutline } from "react-icons/io"; import { IoDocumentTextOutline } from "react-icons/io5"; import { MdOutlineDoubleArrow } from "react-icons/md"; import { RiThumbUpLine } from "react-icons/ri"; import { RxCrossCircled } from "react-icons/rx"; import { TiEdit } from "react-icons/ti"; import { toast, ToastContainer } from "react-toastify"; export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => { const user = await requestUser(req, res); if (!user) return redirect("/login") if (shouldRedirectHome(user) || !["admin", "developer", "teacher", "corporate", "mastercorporate"].includes(user.type)) return redirect("/") const { id } = params as { id: string }; const workflow: ApprovalWorkflow | null = await getApprovalWorkflow("configured-workflows", id); if (!workflow) return redirect("/approval-workflows") const allAssigneeIds: string[] = [ ...new Set( workflow.steps .map(step => step.assignees) .flat() ) ]; return { props: serialize({ user, workflow, workflowAssignees: await getSpecificUsers(allAssigneeIds), workflowRequester: await getUser(workflow.requester), }), }; }, sessionOptions); interface Props { user: User, workflow: ApprovalWorkflow, workflowAssignees: User[], workflowRequester: User, } export default function Home({ user, workflow, workflowAssignees, workflowRequester }: Props) { const steps = workflow.steps; let currentStep = steps.findIndex(step => !step.completed || step.rejected); if (currentStep === -1) currentStep = steps.length - 1; const [selectedStepIndex, setSelectedStepIndex] = useState(currentStep); 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); setSelectedStepIndex(index); setComments(stepInfo.comments || ""); setIsPanelOpen(true); }; 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); router.reload(); }) .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 = () => { setIsLoading(true); const updatedWorkflow: ApprovalWorkflow = { ...workflow, status: selectedStepIndex === workflow.steps.length - 1 ? "approved" : "pending", 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); router.reload(); }) .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 handleRejectStep = () => { if (!confirm(`Are you sure you want to reject this step?`)) return; setIsLoading(true); const updatedWorkflow: ApprovalWorkflow = { ...workflow, status: "rejected", steps: workflow.steps.map((step, index) => index === selectedStepIndex ? { ...step, completed: true, completedBy: user.id, completedDate: Date.now(), rejected: true, } : step ) }; axios .put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow) .then(() => { toast.success("Step rejected successfully."); setIsRedirecting(true); router.reload(); }) .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 handleViewExam = () => { } const handleEditExam = () => { } return ( <> {workflow.name} | EnCoach {user && (

{workflow.name}

{steps.find((step) => !step.completed) === undefined && }
{steps.map((step, index) => ( handleStepClick(index, step)} /> ))}
{/* Side panel */}
{isPanelOpen && selectedStep && (

Step {selectedStepIndex + 1}


{selectedStep.stepType === "approval-by" ? ( <> Approval Step ) : ( <> Form Intake Step ) }
{selectedStep.completed ? (
{selectedStep.rejected ? "Rejected" : "Approved"} on {new Date(selectedStep.completedDate!).toLocaleString("en-CA", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }).replace(", ", " at ")}

{selectedStep.rejected ? "Rejected" : "Approved"} by:

{(() => { const assignee = workflowAssignees.find( (assignee) => assignee.id === selectedStep.completedBy ); return assignee ? ( ) : ( "Unknown" ); })()}

No additional actions are required.

) : (
One assignee is required to sign off to complete this step:
{workflowAssignees.filter(user => selectedStep.assignees.includes(user.id)).map(user => ( ))}
)} {selectedStepIndex === currentStep && !selectedStep.completed && !selectedStep.rejected &&
}