diff --git a/src/components/ApprovalWorkflows/UserWithProfilePic.tsx b/src/components/ApprovalWorkflows/UserWithProfilePic.tsx index 63ff9434..4254bfd9 100644 --- a/src/components/ApprovalWorkflows/UserWithProfilePic.tsx +++ b/src/components/ApprovalWorkflows/UserWithProfilePic.tsx @@ -9,7 +9,7 @@ interface Props { export default function UserWithProfilePic({ prefix, name, profileImage }: Props) { return (
-

{prefix} {name}

+

{prefix} {name}

{name} assignee.id === completedBy); const assigneesUsers = workflowAssignees.filter(user => assignees!.includes(user.id)); @@ -59,31 +57,46 @@ export default function WorkflowStepComponent({ <>

Form: Intake

{completed && completedBy && ( -

- Completed by {getUserTypeLabelShort(completedByUser?.type)} {completedByUser?.name} -

+
+ +
)} {!completed && completedBy && ( - <> - {assigneesUsers.map(user => ( -

- {getUserTypeLabelShort(user.type)} {user.name} -

- ))} - +
+ In Progress... Assignees: +
+ {assigneesUsers.map(user => ( + + + + ))} +
+
)} ) : ( stepType === "approval-by" && ( <>

Approval: {getUserTypeLabel(assigneesType)}

- {completed ? ( -

- Approved by {workflowAssignees.find((assignee) => assignee.id === completedBy)?.name || "Unknown"} -

+ {completed && completedBy ? ( +
+ +
) : !completed && currentStep ? (
- In Progress... Assignees: + In Progress... Assignees:
{assigneesUsers.map(user => ( @@ -97,9 +110,9 @@ export default function WorkflowStepComponent({
) : ( -

+

Waiting for previous steps... -

+
)} ) diff --git a/src/pages/approval-workflows/[id].tsx b/src/pages/approval-workflows/[id].tsx index 0f197be2..32117735 100644 --- a/src/pages/approval-workflows/[id].tsx +++ b/src/pages/approval-workflows/[id].tsx @@ -1,5 +1,4 @@ import Layout from "@/components/High/Layout"; -import useUser from "@/hooks/useUser"; import { ApprovalWorkflow, getUserTypeLabelShort } from "@/interfaces/approval.workflow"; import { sessionOptions } from "@/lib/session"; import { redirect, serialize } from "@/utils"; @@ -17,10 +16,9 @@ import RequestedBy from "@/components/ApprovalWorkflows/RequestedBy"; import StartedOn from "@/components/ApprovalWorkflows/StartedOn"; import Status from "@/components/ApprovalWorkflows/Status"; import WorkflowStepComponent from "@/components/ApprovalWorkflows/WorkflowStepComponent"; -import { useState } from "react"; -import useApprovalWorkflows from "@/hooks/useApprovalWorkflows"; import { User } from "@/interfaces/user"; -import { getSpecificUsers, getUser, getUsers } from "@/utils/users.be"; +import { getSpecificUsers, getUser } from "@/utils/users.be"; +import { useState } from "react"; export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => { const user = await requestUser(req, res); @@ -32,7 +30,6 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params } const { id } = params as { id: string }; // replace later with await getApprovalWorkflow(id). Don't think a hook is needed here; - const approvalWorkflowsDataAsWorkflows = approvalWorkflowsData as ApprovalWorkflow[]; const workflow: ApprovalWorkflow | undefined = approvalWorkflowsDataAsWorkflows.find(workflow => workflow.id === id); @@ -67,7 +64,11 @@ interface Props { export default function Home({ user, workflow, workflowAssignees, workflowRequester }: Props) { const steps = workflow.steps; - const [selectedIndex, setSelectedIndex] = useState(steps.length - 1); + let currentStep = steps.findIndex(step => !step.completed); + if (currentStep === -1) + currentStep = steps.length - 1; + + const [selectedIndex, setSelectedIndex] = useState(currentStep); const handleStepClick = (index: number) => { setSelectedIndex(index); @@ -124,7 +125,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques assignees={step.assignees} assigneesType={step.assigneesType} finalStep={index === steps.length - 1} - currentStep={steps.findIndex(step => !step.completed) === index} + currentStep={currentStep === index} selected={index === selectedIndex} onClick={() => handleStepClick(index)} /> diff --git a/src/pages/approval-workflows/create.tsx b/src/pages/approval-workflows/create.tsx index a806186d..6c355b51 100644 --- a/src/pages/approval-workflows/create.tsx +++ b/src/pages/approval-workflows/create.tsx @@ -104,7 +104,7 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesTeachers ], }; setWorkflows((prev) => [...prev, newWorkflow]); - setSelectedWorkflowId(newId); + handleSelectWorkflow(newId); }; const onWorkflowChange = (updatedWorkflow: ApprovalWorkflow) => { @@ -113,8 +113,14 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesTeachers ); } - const handleSelectWorkflow = (id: string) => { + const handleSelectWorkflow = (id: string | undefined) => { setSelectedWorkflowId(id); + const selectedWorkflow = workflows.find(wf => wf.id === id); + if (selectedWorkflow) { + setEntityId(selectedWorkflow.entityId || null); + } else { + setEntityId(null); + } }; const handleDeleteWorkflow = (id: string) => { @@ -125,7 +131,7 @@ export default function Home({ user, userEntitiesWithLabel, userEntitiesTeachers setWorkflows(updatedWorkflows); if (selectedWorkflowId === id) { - setSelectedWorkflowId(updatedWorkflows.find(wf => wf.id)?.id); + handleSelectWorkflow(updatedWorkflows.find(wf => wf.id)?.id); } }; diff --git a/src/pages/approval-workflows/index.tsx b/src/pages/approval-workflows/index.tsx index a06a9b1b..ef09c959 100644 --- a/src/pages/approval-workflows/index.tsx +++ b/src/pages/approval-workflows/index.tsx @@ -1,17 +1,16 @@ import Layout from "@/components/High/Layout"; import Button from "@/components/Low/Button"; import Select from "@/components/Low/Select"; -import useApprovalWorkflows from "@/hooks/useApprovalWorkflows"; import { Module, ModuleTypeLabels } from "@/interfaces"; import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow"; import { Entity, EntityWithRoles } from "@/interfaces/entity"; -import { TeacherUser, User } from "@/interfaces/user"; +import { 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 { getUsers } from "@/utils/users.be"; +import { getSpecificUsers } from "@/utils/users.be"; import { createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"; import axios from "axios"; import clsx from "clsx"; @@ -24,6 +23,8 @@ import { FaRegEdit } from "react-icons/fa"; import { IoIosAddCircleOutline } from "react-icons/io"; import { toast, ToastContainer } from "react-toastify"; +import approvalWorkflowsData from '../../demo/approval_workflows.json'; // to test locally + const columnHelper = createColumnHelper(); export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => { @@ -37,9 +38,25 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => { const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS); const allowedEntities = findAllowedEntities(user, entities, "view_approval_workflows"); */ + + // replace later with await getApprovalWorkflow(id). Don't think a hook is needed here; + const workflows = approvalWorkflowsData as ApprovalWorkflow[]; + + const allAssigneeIds: string[] = [ + ...new Set( + workflows + .map(workflow => workflow.steps + .map(step => step.assignees) + .flat() as string[] // we are sure assignees coming from a db workflow are all valid strings. + ).flat() as string[] + ) + ]; + return { props: serialize({ user, + workflows, + workflowsAssignees: await getSpecificUsers(allAssigneeIds), userEntitiesWithLabel: await getEntities(user.entities.map(entity => entity.id)), }), }; @@ -79,10 +96,12 @@ const STATUS_OPTIONS = [ interface Props { user: User, + workflows: ApprovalWorkflow[], + workflowsAssignees: User[], userEntitiesWithLabel: Entity[], } -export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props) { +export default function ApprovalWorkflows({ user, workflows, workflowsAssignees, userEntitiesWithLabel }: Props) { const ENTITY_OPTIONS = [ { @@ -100,13 +119,11 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props .sort((a, b) => a.label.localeCompare(b.label)), ]; - const [filteredApprovalWorkflows, setFilteredApprovalWorkflows] = useState([]); + const [filteredWorkflows, setFilteredWorkflows] = useState([]); const [statusFilter, setStatusFilter] = useState("all"); const [entityFilter, setEntityFilter] = useState("all"); - const { approvalWorkflows/* , reload */ } = useApprovalWorkflows(); - useEffect(() => { const filters = []; if (statusFilter) { @@ -118,9 +135,9 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props if (filter) filters.push(filter); } - setFilteredApprovalWorkflows([...filters.reduce((d, f) => d.filter(f), approvalWorkflows)]); + setFilteredWorkflows([...filters.reduce((d, f) => d.filter(f), workflows)]); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [approvalWorkflows, statusFilter, entityFilter]); + }, [workflows, statusFilter, entityFilter]); const deleteApprovalWorkflow = (id: string, name: string) => { if (!confirm(`Are you sure you want to delete this Approval Workflow?`)) return; @@ -193,21 +210,25 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props ), }), columnHelper.accessor("steps", { - id: "currentApprovers", - header: "CURRENT APPROVERS", + id: "currentAssignees", + header: "CURRENT ASSIGNEES", cell: (info) => { const steps = info.row.original.steps; const currentStep = steps.find((step) => !step.completed); - const approvers = currentStep?.assignees || []; + + const assignees = currentStep?.assignees!.map((assigneeId) => { + const assignee = workflowsAssignees.find((user) => user.id === assigneeId); + return assignee?.name || "Unknown Assignee"; + }); return (
- {approvers.map((approver: string | null | undefined, index: number) => ( + {assignees?.map((assigneeName: string, index: number) => ( - {approver} + {assigneeName} ))}
@@ -236,10 +257,17 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props cell: ({ row }: { row: { original: ApprovalWorkflow } }) => { return (
- + e.stopPropagation()} data-tip="Edit" href={`/approval-workflows/${row.original.id}/edit`} className="cursor-pointer tooltip"> -
@@ -249,7 +277,7 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props ]; const table = useReactTable({ - data: filteredApprovalWorkflows, + data: filteredWorkflows, columns: columns, getCoreRowModel: getCoreRowModel(), }); @@ -315,7 +343,7 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( - + {header.isPlaceholder ? null : flexRender( @@ -338,7 +366,7 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props {row.getVisibleCells().map((cell, cellIndex) => { const lastCellIndex = row.getVisibleCells().length - 1; - let cellClasses = "px-4 py-2 bg-purple-50 border-y-2 border-purple-300"; + let cellClasses = "px-3 py-2 bg-purple-50 border-y-2 border-purple-300"; if (cellIndex === 0) { cellClasses += " border-l-2 rounded-l-2xl"; }