Work on workflows table

This commit is contained in:
Joao Correia
2025-01-22 00:30:14 +00:00
parent 73e2e95449
commit 8f8d5e5640
5 changed files with 211 additions and 58 deletions

View File

@@ -1,13 +1,12 @@
[
{
"id": "kajhfakscbka-asacaca-acawesae",
"name": "name-1",
"name": "English Exam 1st Quarter 2025",
"modules": [
"reading",
"writing"
],
"status": "pending",
"approvers": "prof-1",
"steps": [
{
"stepType": "form-intake",
@@ -67,5 +66,79 @@
"assigneesType": "corporate"
}
]
},
{
"id": "aaaaaakscbka-asacaca-acawesae",
"name": "English Exam 2nd Quarter 2025",
"modules": [
"reading",
"writing",
"level",
"speaking",
"listening"
],
"status": "approved",
"steps": [
{
"stepType": "form-intake",
"stepNumber": 1,
"completed": true,
"completedBy": "Prof. X",
"assignees": [
"Prof. X",
"Prof. Y",
"Prof. Z"
],
"assigneesType": "teacher"
},
{
"stepType": "approval-by",
"stepNumber": 2,
"completed": true,
"completedBy": "Prof. Y",
"assignees": [
"Prof. X",
"Prof. Y",
"Prof. Z"
],
"assigneesType": "teacher"
},
{
"stepType": "approval-by",
"stepNumber": 3,
"completed": true,
"completedBy": "Prof. Y",
"assignees": [
"Prof. X",
"Prof. Y",
"Prof. Z"
],
"assigneesType": "teacher"
},
{
"stepType": "approval-by",
"stepNumber": 4,
"completed": true,
"completedBy": "Prof. Y",
"assignees": [
"Prof. X",
"Prof. Y",
"Prof. Z"
],
"assigneesType": "teacher"
},
{
"stepType": "approval-by",
"stepNumber": 5,
"completed": true,
"completedBy": "Prof. Y",
"assignees": [
"Dir. X",
"Dir. Y",
"Dir. Z"
],
"assigneesType": "corporate"
}
]
}
]

View File

@@ -10,6 +10,10 @@ export interface ApprovalWorkflow {
}
export type StepType = "form-intake" | "approval-by";
export const StepTypeLabel: Record<StepType, string> = {
"form-intake": "Form Intake",
"approval-by": "Approval",
};
type AssigneesType = TeacherUser["type"] | CorporateUser["type"] | MasterCorporateUser["type"];
@@ -38,8 +42,8 @@ export function getUserTypeLabel(type: AssigneesType | undefined): string {
}
export type ApprovalWorkflowStatus = "approved" | "pending" | "rejected";
export const ApprovalWorkflowStatusLabel: {[key in ApprovalWorkflowStatus]: string} = {
approved: "Approved",
export const ApprovalWorkflowStatusLabel: Record<ApprovalWorkflowStatus, string> = {
approved: "Approved",
pending: "Pending",
rejected: "Rejected",
};

View File

@@ -1,4 +1,11 @@
export type Module = "reading" | "listening" | "writing" | "speaking" | "level";
export const ModuleTypeLabels: Record<Module, string> = {
reading: "Reading",
listening: "Listening",
writing: "Writing",
speaking: "Speaking",
level: "Level",
};
export interface Step {
min: number;

View File

@@ -1,6 +1,6 @@
import Layout from "@/components/High/Layout";
import useUser from "@/hooks/useUser";
import { ApprovalWorkflow, WorkflowStep } from "@/interfaces/approval.workflow";
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
import { sessionOptions } from "@/lib/session";
import { redirect } from "@/utils";
import { requestUser } from "@/utils/api";
@@ -17,10 +17,8 @@ import approvalWorkflowsData from '../../demo/approval_workflows.json'; // to te
import RequestedBy from "@/components/ApprovalWorkflows/RequestedBy";
import StartedOn from "@/components/ApprovalWorkflows/StartedOn";
import Status from "@/components/ApprovalWorkflows/Status";
import { useState } from "react";
import Button from "@/components/Low/Button";
import WorkflowEditableStepComponent from "@/components/ApprovalWorkflows/WorkflowEditableStepComponent";
import WorkflowStepComponent from "@/components/ApprovalWorkflows/WorkflowStepComponent";
import { useState } from "react";
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
const user = await requestUser(req, res);
@@ -102,8 +100,8 @@ export default function Home({ workflow }: { workflow: ApprovalWorkflow }) {
assigneesType={step.assigneesType}
finalStep={index === steps.length - 1}
currentStep={steps.findIndex(step => !step.completed) === index}
selected={index === selectedIndex} // Determine selected state
onClick={() => handleStepClick(index)} // Add click handler
selected={index === selectedIndex}
onClick={() => handleStepClick(index)}
/>
))}
</section>

View File

@@ -3,7 +3,8 @@ import Button from "@/components/Low/Button";
import Select from "@/components/Low/Select";
import useApprovalWorkflows from "@/hooks/useApprovalWorkflows";
import useUser from "@/hooks/useUser";
import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel } from "@/interfaces/approval.workflow";
import { Module, ModuleTypeLabels } from "@/interfaces";
import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow";
import { sessionOptions } from "@/lib/session";
import { redirect } from "@/utils";
import { requestUser } from "@/utils/api";
@@ -117,31 +118,74 @@ export default function ApprovalWorkflows() {
cell: (info) => info.getValue(),
}), */
columnHelper.accessor("name", {
header: "Name",
cell: (info) => info.getValue(),
}),
/* columnHelper.accessor("module", {
header: "Module",
cell: (info) => info.getValue(),
}), */
columnHelper.accessor("status", {
header: "Status",
header: "NAME",
cell: (info) => (
<span className={clsx("rounded-full px-3 py-1 text-sm font-medium inline-block text-left w-[110px]", StatusClassNames[info.getValue()])}>
<span className="font-medium">
{info.getValue()}
</span>
),
}),
columnHelper.accessor("modules", {
header: "MODULES",
cell: (info) => (
<div className="flex flex-wrap gap-2">
{info.getValue().map((module: Module, index: number) => (
<span
key={index}
className="inline-block rounded-full px-3 py-1 text-sm font-medium bg-purple-100 border border-purple-300 text-purple-900"
>
{ModuleTypeLabels[module]}
</span>
))}
</div>
),
}),
columnHelper.accessor("status", {
header: "STATUS",
cell: (info) => (
<span className={clsx("inline-block rounded-full px-3 py-1 text-sm font-medium text-left w-[110px]", StatusClassNames[info.getValue()])}>
{ApprovalWorkflowStatusLabel[info.getValue()]}
</span>
),
}),
/* columnHelper.accessor("approvers", {
header: "Approvers",
cell: (info) => info.getValue(),
columnHelper.accessor("steps", {
header: "CURRENT APPROVERS",
cell: (info) => {
const steps = info.row.original.steps;
const currentStep = steps.find((step) => !step.completed);
const approvers = currentStep?.assignees || [];
return (
<div className="flex flex-wrap gap-2">
{approvers.map((approver: 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}
</span>
))}
</div>
);
},
}),
columnHelper.accessor("steps", {
header: "CURRENT STEP",
cell: (info) => {
const steps = info.row.original.steps;
const currentStep = steps.find((step) => !step.completed);
return (
<span className="font-medium">
{currentStep
? `Step ${currentStep.stepNumber}: ${StepTypeLabel[currentStep.stepType!]}`
: "Completed"}
</span>
);
},
}),
columnHelper.accessor("step", {
header: "Step",
cell: (info) => info.getValue(),
}), */
{
header: "Actions",
header: "ACTIONS",
id: "actions",
cell: ({ row }: { row: { original: ApprovalWorkflow } }) => {
return (
@@ -204,35 +248,62 @@ export default function ApprovalWorkflows() {
</div>
</div>
<table className="bg-mti-purple-ultralight/40 w-full rounded-xl">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th className="px-4 py-4 text-left" key={header.id}>
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
</th>
))}
</tr>
))}
</thead>
<tbody className="px-2">
{table.getRowModel().rows.map((row) => (
<tr
className={clsx(
"even:bg-mti-purple-ultralight/40 rounded-lg py-2 odd:bg-white"
)}
key={row.id}>
<div className="px-6 pb-4 bg-purple-100 rounded-2xl">
<table
className="w-full table-auto border-separate border-spacing-y-2"
style={{ tableLayout: "auto" }}
>
<thead>
{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">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{/*
Might be an overkill way to add rounded borders to the rows, but couldn't figure out another way...
border round and margin does not seem to work properly on tr
Another way to do it was with grid but that puts the same width in all rows, which is inconvenient
Regardless, it works and all calcs are pretty simple so shouldnt be too inefficient
*/}
{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";
if (cellIndex === 0) {
cellClasses += " border-l-2 rounded-l-2xl";
}
if (cellIndex === lastCellIndex) {
cellClasses += " border-r-2 rounded-r-2xl";
}
return (
<td key={cell.id} className={cellClasses}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
{row.getVisibleCells().map((cell) => (
<td className="w-fit items-center px-4 py-2" key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
</Layout>
)}
</>