diff --git a/src/components/ApprovalWorkflows/WorkflowStep.tsx b/src/components/ApprovalWorkflows/WorkflowStep.tsx new file mode 100644 index 00000000..e451744d --- /dev/null +++ b/src/components/ApprovalWorkflows/WorkflowStep.tsx @@ -0,0 +1,98 @@ +import Option from "@/interfaces/option"; +import clsx from "clsx"; +import { useState } from "react"; +import { BsTrash } from "react-icons/bs"; +import WorkflowStepNumber from "./WorkflowStepNumber"; +import WorkflowStepSelects from "./WorkflowStepSelects"; + +export type StepType = "form-intake" | "approval-by"; + +const teacherOptions: Option[] = [ + // fetch from database? +] + +const directorOptions: Option[] = [ + // fetch from database? +] + +interface Props { + editView?: boolean, + finalStep?: boolean, + isSelected?: boolean, + stepNumber: number, + stepType: StepType, + requestedBy: string, + //requestedBy: TeacherUser | CorporateUser | MasterCorporateUser, + onDelete?: () => void; +} + +export default function WorkflowStep({ + editView = false, + finalStep = false, + isSelected = false, + stepNumber, + stepType, + requestedBy, + onDelete, +}: Props) { + // disable selectability of step if in editView + const effectiveIsSelected = editView ? false : isSelected; + + const [leftValue, setLeftValue] = useState(null); + const [rightValue, setRightValue] = useState(null); + + let showSelects = false; + let leftPlaceholder = ""; + let rightPlaceholder = ""; + + if (editView) { + if (stepType === "approval-by") { + // Show the selects only if it's an 'approval-by' step and in edit mode + showSelects = true; + leftPlaceholder = "Approval by"; + rightPlaceholder = finalStep ? "2nd Director" : "2nd Teacher"; + } + } + + return ( + + + + + + + {/* Only show selects if editView === true and stepType === 'approval-by' */} + {showSelects && ( + + + + )} + + {editView && stepNumber !== 1 && !finalStep && ( + + + + )} + + + ); +}; \ No newline at end of file diff --git a/src/components/ApprovalWorkflows/WorkflowStepNumber.tsx b/src/components/ApprovalWorkflows/WorkflowStepNumber.tsx new file mode 100644 index 00000000..93e75ca8 --- /dev/null +++ b/src/components/ApprovalWorkflows/WorkflowStepNumber.tsx @@ -0,0 +1,25 @@ +import { ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel } from "@/interfaces/approval.workflow"; +import clsx from "clsx"; +import React from "react"; +import { RiProgress5Line } from "react-icons/ri"; + +interface Props { + number: number; + isSelected?: boolean; +} + +export default function WorkflowStepNumber({ number, isSelected = false }: Props) { + return ( + + {number} + + ); +}; \ No newline at end of file diff --git a/src/components/ApprovalWorkflows/WorkflowStepSelects.tsx b/src/components/ApprovalWorkflows/WorkflowStepSelects.tsx new file mode 100644 index 00000000..63e30cfa --- /dev/null +++ b/src/components/ApprovalWorkflows/WorkflowStepSelects.tsx @@ -0,0 +1,53 @@ +import Option from "@/interfaces/option"; +import Select from "../Low/Select"; + +interface Props { + leftOptions: Option[]; + rightOptions: Option[]; + leftValue?: Option | null; + rightValue?: Option | null; + onLeftChange: (value: Option | null) => void; + onRightChange: (value: Option | null) => void; + leftPlaceholder?: string; + rightPlaceholder?: string; +} + +export default function WorkflowStepSelects({ + leftOptions, + rightOptions, + leftValue, + rightValue, + onLeftChange, + onRightChange, + leftPlaceholder = "Select", + rightPlaceholder = "Select", +}: Props) { + return ( + + {/* Left Select */} + + + + {/* Right Select */} + + + + + ); +} \ No newline at end of file diff --git a/src/pages/approval-workflows/[id].tsx b/src/pages/approval-workflows/[id].tsx index a9571269..1ba5f088 100644 --- a/src/pages/approval-workflows/[id].tsx +++ b/src/pages/approval-workflows/[id].tsx @@ -5,17 +5,31 @@ import { sessionOptions } from "@/lib/session"; import { redirect } from "@/utils"; import { requestUser } from "@/utils/api"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; +import { AnimatePresence, motion } from "framer-motion"; import { withIronSessionSsr } from "iron-session/next"; import Head from "next/head"; import Link from "next/link"; import { BsChevronLeft } from "react-icons/bs"; +import { FaRegCheckCircle } from "react-icons/fa"; +import { IoIosAddCircleOutline } from "react-icons/io"; import { ToastContainer } from "react-toastify"; + import approvalWorkflowsData from '../../demo/approval_workflows.json'; // to test locally import RequestedBy from "@/components/ApprovalWorkflows/RequestedBy"; import StartedOn from "@/components/ApprovalWorkflows/StartedOn"; import Status from "@/components/ApprovalWorkflows/Status"; +import WorkflowStep, { StepType } from "@/components/ApprovalWorkflows/WorkflowStep"; +import Button from "@/components/Low/Button"; +import { useState } from "react"; + +interface Step { + stepNumber: number; + stepType: StepType; + finalStep?: boolean; + key: number; +} export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => { const user = await requestUser(req, res) @@ -38,6 +52,47 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params } export default function Home({ approvalWorkflow }: { approvalWorkflow: ApprovalWorkflow }) { const { user } = useUser({ redirectTo: "/login" }); + const [selectedButton, setSelectedButton] = useState<"forms" | "progress">("forms"); + + const [steps, setSteps] = useState([ + { stepNumber: 1, stepType: "form-intake", key: 1 }, + { stepNumber: 2, stepType: "approval-by", finalStep: true, key: 2 }, + ]); + const [stepCounter, setStepCounter] = useState(3); // to guarantee unique keys used for animations + + const addStep = () => { + setSteps((prev) => { + const nonFinalSteps = prev.slice(0, -1); + const finalStep = prev[prev.length - 1]; + const newStep: Step = { stepNumber: finalStep.stepNumber, stepType: "approval-by", key: stepCounter }; + + const updatedFinalStep = { ...finalStep, stepNumber: finalStep.stepNumber + 1 }; + + setStepCounter((prev) => prev + 1); //update counter + + return [...nonFinalSteps, newStep, updatedFinalStep]; + }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // Handle form submission logic + console.log("Form submitted!", steps); + }; + + const handleDelete = (index: number) => { + setSteps((prev) => { + const updatedSteps = prev.filter((_, i) => i !== index); + + const recalculatedSteps = updatedSteps.map((step, idx) => ({ + ...step, + stepNumber: idx + 1, + })); + + return recalculatedSteps; + }); + }; + return ( <> @@ -62,17 +117,81 @@ export default function Home({ approvalWorkflow }: { approvalWorkflow: ApprovalW {approvalWorkflow.name} - - - - + + + + + + + + setSelectedButton("forms")} + className="transition-all duration-300 w-56 text-lg font-medium" + > + Forms + + setSelectedButton("progress")} + className="transition-all duration-300 w-56 text-lg font-medium" + > + Progress + + + + + + + + Add Step + + + {steps.map((step, index) => ( + + handleDelete(index)} // Pass index for deletion + /> + + ))} + + + + + Confirm Exam Workflow Pipeline + + + )} diff --git a/src/pages/approval-workflows/index.tsx b/src/pages/approval-workflows/index.tsx index e7688193..580e57c1 100644 --- a/src/pages/approval-workflows/index.tsx +++ b/src/pages/approval-workflows/index.tsx @@ -145,9 +145,9 @@ export default function ApprovalWorkflows() { cell: ({ row }: { row: { original: ApprovalWorkflow } }) => { return ( - deleteApprovalWorkflow(row.original.id, row.original.name)}> + deleteApprovalWorkflow(row.original.id, row.original.name)}> - +