- initial selected step

- assignees id to name on table view
This commit is contained in:
Joao Correia
2025-01-24 17:09:37 +00:00
parent 41d09eaad8
commit 1f7639a30e
5 changed files with 97 additions and 49 deletions

View File

@@ -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<ApprovalWorkflow>();
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<ApprovalWorkflow[]>([]);
const [filteredWorkflows, setFilteredWorkflows] = useState<ApprovalWorkflow[]>([]);
const [statusFilter, setStatusFilter] = useState<CustomStatus>("all");
const [entityFilter, setEntityFilter] = useState<CustomEntity>("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 (
<div className="flex flex-wrap gap-2">
{approvers.map((approver: string | null | undefined, index: number) => (
{assignees?.map((assigneeName: string, index: number) => (
<span
key={index}
className="inline-block rounded-full px-3 py-1 text-sm font-medium bg-gray-100 border border-gray-300 text-gray-900"
>
{approver}
{assigneeName}
</span>
))}
</div>
@@ -236,10 +257,17 @@ export default function ApprovalWorkflows({ user, userEntitiesWithLabel }: Props
cell: ({ row }: { row: { original: ApprovalWorkflow } }) => {
return (
<div className="flex gap-4">
<Link data-tip="Edit" href={`/approval-workflows/${row.original.id}`} className="cursor-pointer tooltip">
<Link onClick={(e) => e.stopPropagation()} data-tip="Edit" href={`/approval-workflows/${row.original.id}/edit`} className="cursor-pointer tooltip">
<FaRegEdit className="hover:text-mti-purple-light transition ease-in-out duration-300" />
</Link>
<button data-tip="Delete" className="cursor-pointer tooltip" onClick={() => deleteApprovalWorkflow(row.original.id, row.original.name)}>
<button
data-tip="Delete"
className="cursor-pointer tooltip"
onClick={(e) => {
e.stopPropagation();
deleteApprovalWorkflow(row.original.id, row.original.name);
}}
>
<BsTrash className="hover:text-mti-purple-light transition ease-in-out duration-300" />
</button>
</div>
@@ -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) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id} className="px-2 py-3 text-left text-purple-900">
<th key={header.id} className="px-3 py-2 text-left text-purple-900">
{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";
}