import Tip from "@/components/ApprovalWorkflows/Tip"; import WorkflowForm from "@/components/ApprovalWorkflows/WorkflowForm"; import Layout from "@/components/High/Layout"; import Button from "@/components/Low/Button"; import Input from "@/components/Low/Input"; import Select from "@/components/Low/Select"; import { ApprovalWorkflow, EditableApprovalWorkflow, EditableWorkflowStep } from "@/interfaces/approval.workflow"; import { Entity } from "@/interfaces/entity"; import { CorporateUser, DeveloperUser, MasterCorporateUser, TeacherUser, User } from "@/interfaces/user"; import { sessionOptions } from "@/lib/session"; import { redirect, serialize } from "@/utils"; import { requestUser } from "@/utils/api"; import { getEntities } from "@/utils/entities.be"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; import { getEntitiesUsers } from "@/utils/users.be"; import { uuidv4 } from "@firebase/util"; import { AnimatePresence, LayoutGroup, motion } from "framer-motion"; import { withIronSessionSsr } from "iron-session/next"; import Head from "next/head"; import Link from "next/link"; import { useEffect, useState } from "react"; import { BsChevronLeft } from "react-icons/bs"; import { GrClearOption } from "react-icons/gr"; import { toast, ToastContainer } from "react-toastify"; import { useRouter } from "next/router"; import axios from "axios"; import { getApprovalWorkflow } from "@/utils/approval.workflows.be"; 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 userEntitiesWithLabel = await getEntities(user.entities.map(entity => entity.id)); return { props: serialize({ user, workflow, userEntitiesWithLabel, userEntitiesApprovers: await getEntitiesUsers(userEntitiesWithLabel.map(entity => entity.id), { type: { $in: ["teacher", "corporate", "mastercorporate", "developer"] } }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[], }), }; }, sessionOptions); interface Props { user: User, workflow: ApprovalWorkflow, userEntitiesWithLabel: Entity[], userEntitiesApprovers: (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[], } export default function Home({ user, workflow, userEntitiesWithLabel, userEntitiesApprovers }: Props) { const [cloneWorkflow, setCloneWorkflow] = useState(null); const [entityId, setEntityId] = useState(workflow.entityId); const [entityApprovers, setEntityApprovers] = useState<(TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[]>([]); const [isLoading, setIsLoading] = useState(false); const [isRedirecting, setIsRedirecting] = useState(false); const router = useRouter(); useEffect(() => { if (entityId) { setEntityApprovers( userEntitiesApprovers.filter(approver => approver.entities.some(entity => entity.id === entityId) ) ); } else { setEntityApprovers([]); } }, [entityId, userEntitiesApprovers]); const ENTITY_OPTIONS = userEntitiesWithLabel.map(entity => ({ label: entity.label, value: entity.id, filter: (x: EditableApprovalWorkflow) => x.entityId === entity.id, })); useEffect(() => { const editableSteps: EditableWorkflowStep[] = workflow.steps.map(step => ({ key: step.stepNumber + 999, // just making sure they are unique because new steps that users add will have key=3 key=4 etc stepType: step.stepType, stepNumber: step.stepNumber, completed: false, assignees: step.assignees.map(id => id), firstStep: step.firstStep || false, finalStep: step.finalStep || false, onDelete: undefined, })); const editableWorkflow: EditableApprovalWorkflow = { id: uuidv4(), // this id is only used in UI. it is ommited on submission to DB and lets mongo handle unique id. name: workflow.name, entityId: workflow.entityId, requester: user.id, startDate: Date.now(), modules: workflow.modules, status: "pending", steps: editableSteps, }; setCloneWorkflow(editableWorkflow); }, []); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); if (!cloneWorkflow) { setIsLoading(false); return; } const filteredWorkflow: ApprovalWorkflow = { ...cloneWorkflow, steps: cloneWorkflow.steps.map(step => ({ ...step, completed: false, assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined) })) }; axios .post(`/api/approval-workflows/${workflow._id}/clone`, filteredWorkflow) .then(() => { toast.success("Approval Workflow cloned successfully."); setIsRedirecting(true); router.push("/approval-workflows"); }) .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 clone Approval Workflows!"); } else { toast.error("Something went wrong, please try again later."); } setIsLoading(false); console.log("Submitted Values:", filteredWorkflow); return; }) }; const onWorkflowChange = (wf: EditableApprovalWorkflow) => { setCloneWorkflow(wf); } const handleEntityChange = (wf: EditableApprovalWorkflow, entityId: string) => { const updatedWorkflow = { ...wf, entityId: entityId, steps: wf.steps.map(step => ({ ...step, assignees: step.assignees.map(() => null) })) } onWorkflowChange(updatedWorkflow); } const handleResetWorkflow = () => { if (!confirm("This action will reset all the fields in this workflow. Are you sure you want to proceed?")) return; const newId = uuidv4(); const newWorkflow: EditableApprovalWorkflow = { id: newId, name: "", entityId: "", modules: [], requester: user.id, startDate: Date.now(), status: "pending", steps: [ { key: 9998, stepType: "form-intake", stepNumber: 1, completed: false, firstStep: true, finalStep: false, assignees: [null] }, { key: 9999, stepType: "approval-by", stepNumber: 2, completed: false, firstStep: false, finalStep: true, assignees: [null] }, ], }; setCloneWorkflow(newWorkflow); } return ( <> Clone Workflow | EnCoach {user && (

Clone Workflow

{cloneWorkflow && ( <>
{ const updatedWorkflow = { ...cloneWorkflow, name: updatedName, }; onWorkflowChange(updatedWorkflow); }} />