use custom hook to render approval workflows list instead of reloading full page.

This commit is contained in:
Joao Correia
2025-02-03 12:52:03 +00:00
parent 19f2193414
commit d3385caaf8
3 changed files with 64 additions and 14 deletions

View File

@@ -0,0 +1,24 @@
import { ApprovalWorkflow } from "@/interfaces/approval.workflow";
import axios from "axios";
import { useCallback, useEffect, useState } from "react";
export default function useApprovalWorkflows() {
const [workflows, setWorkflows] = useState<ApprovalWorkflow[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const getData = useCallback(() => {
setIsLoading(true);
axios
.get<ApprovalWorkflow[]>(`/api/approval-workflows`)
.then((response) => setWorkflows(response.data))
.catch((error) => {
setIsError(true);
})
.finally(() => setIsLoading(false));
}, []);
useEffect(getData, [getData]);
return { workflows, isLoading, isError, reload: getData };
}

View File

@@ -0,0 +1,23 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { sessionOptions } from "@/lib/session";
import { requestUser } from "@/utils/api";
import { getApprovalWorkflows } from "@/utils/approval.workflows.be";
import { withIronSessionApiRoute } from "iron-session/next";
import type { NextApiRequest, NextApiResponse } from "next";
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") return await get(req, res);
}
async function get(req: NextApiRequest, res: NextApiResponse) {
const user = await requestUser(req, res);
if (!user) return res.status(401).json({ ok: false });
if (!["admin", "developer", "corporate", "mastercorporate"].includes(user.type)) {
return res.status(403).json({ ok: false });
}
return res.status(200).json(await getApprovalWorkflows("configured-workflows"));
}

View File

@@ -2,6 +2,7 @@ import Layout from "@/components/High/Layout";
import Button from "@/components/Low/Button"; import Button from "@/components/Low/Button";
import Input from "@/components/Low/Input"; import Input from "@/components/Low/Input";
import Select from "@/components/Low/Select"; import Select from "@/components/Low/Select";
import useApprovalWorkflows from "@/hooks/useApprovalWorkflows";
import { Module, ModuleTypeLabels } from "@/interfaces"; import { Module, ModuleTypeLabels } from "@/interfaces";
import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow"; import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow";
import { Entity, EntityWithRoles } from "@/interfaces/entity"; import { Entity, EntityWithRoles } from "@/interfaces/entity";
@@ -51,7 +52,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
return { return {
props: serialize({ props: serialize({
user, user,
workflows, initialWorkflows: workflows,
workflowsAssignees: await getSpecificUsers(allAssigneeIds), workflowsAssignees: await getSpecificUsers(allAssigneeIds),
userEntitiesWithLabel: await getEntities(user.entities.map(entity => entity.id)), userEntitiesWithLabel: await getEntities(user.entities.map(entity => entity.id)),
}), }),
@@ -87,12 +88,21 @@ const STATUS_OPTIONS = [
interface Props { interface Props {
user: User, user: User,
workflows: ApprovalWorkflow[], initialWorkflows: ApprovalWorkflow[],
workflowsAssignees: User[], workflowsAssignees: User[],
userEntitiesWithLabel: Entity[], userEntitiesWithLabel: Entity[],
} }
export default function ApprovalWorkflows({ user, workflows, workflowsAssignees, userEntitiesWithLabel }: Props) { export default function ApprovalWorkflows({ user, initialWorkflows, workflowsAssignees, userEntitiesWithLabel }: Props) {
const {workflows, reload} = useApprovalWorkflows();
const currentWorkflows = workflows || initialWorkflows;
const [filteredWorkflows, setFilteredWorkflows] = useState<ApprovalWorkflow[]>([]);
const [statusFilter, setStatusFilter] = useState<CustomStatus>(undefined);
const [entityFilter, setEntityFilter] = useState<CustomEntity>(undefined);
const [nameFilter, setNameFilter] = useState<string>("");
const ENTITY_OPTIONS = [ const ENTITY_OPTIONS = [
...userEntitiesWithLabel ...userEntitiesWithLabel
@@ -104,13 +114,6 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees,
.sort((a, b) => a.label.localeCompare(b.label)), .sort((a, b) => a.label.localeCompare(b.label)),
]; ];
const [filteredWorkflows, setFilteredWorkflows] = useState<ApprovalWorkflow[]>([]);
const [statusFilter, setStatusFilter] = useState<CustomStatus>(undefined);
const [entityFilter, setEntityFilter] = useState<CustomEntity>(undefined);
const [nameFilter, setNameFilter] = useState<string>("");
const router = useRouter();
useEffect(() => { useEffect(() => {
const filters: Array<(workflow: ApprovalWorkflow) => boolean> = []; const filters: Array<(workflow: ApprovalWorkflow) => boolean> = [];
@@ -135,10 +138,10 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees,
} }
// Apply all filters // Apply all filters
const filtered = workflows.filter(workflow => filters.every(filterFn => filterFn(workflow))); const filtered = currentWorkflows.filter(workflow => filters.every(filterFn => filterFn(workflow)));
setFilteredWorkflows(filtered); setFilteredWorkflows(filtered);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [workflows, statusFilter, entityFilter, nameFilter]); }, [currentWorkflows, statusFilter, entityFilter, nameFilter]);
const handleNameFilterChange = (name: ApprovalWorkflow["name"]) => { const handleNameFilterChange = (name: ApprovalWorkflow["name"]) => {
@@ -153,7 +156,7 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees,
.delete(`/api/approval-workflows/${id}`) .delete(`/api/approval-workflows/${id}`)
.then(() => { .then(() => {
toast.success(`Successfully deleted ${name} Approval Workflow.`); toast.success(`Successfully deleted ${name} Approval Workflow.`);
router.reload(); reload();
}) })
.catch((reason) => { .catch((reason) => {
if (reason.response.status === 404) { if (reason.response.status === 404) {
@@ -215,7 +218,7 @@ export default function ApprovalWorkflows({ user, workflows, workflowsAssignees,
const currentStep = steps.find((step) => !step.completed); const currentStep = steps.find((step) => !step.completed);
const rejected = steps.find((step) => step.rejected); const rejected = steps.find((step) => step.rejected);
if(rejected) return ""; if (rejected) return "";
const assignees = currentStep?.assignees.map((assigneeId) => { const assignees = currentStep?.assignees.map((assigneeId) => {
const assignee = workflowsAssignees.find((user) => user.id === assigneeId); const assignee = workflowsAssignees.find((user) => user.id === assigneeId);