- implement approval of steps
- remove currentStep field from step - implement save comments on step - fix _id issue when saving to mongo
This commit is contained in:
@@ -124,7 +124,6 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti
|
||||
...cloneWorkflow,
|
||||
steps: cloneWorkflow.steps.map(step => ({
|
||||
...step,
|
||||
currentStep: step.stepNumber === 1 ? true : false,
|
||||
completed: false,
|
||||
assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined)
|
||||
}))
|
||||
@@ -137,23 +136,21 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.push("/approval-workflows");
|
||||
}, 2000);
|
||||
}, 1000);
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
toast.error("Not logged in!");
|
||||
return router.push("/login");
|
||||
}
|
||||
if (reason.response.status === 403) {
|
||||
} else if (reason.response.status === 403) {
|
||||
toast.error("You do not have permission to clone Approval Workflows!");
|
||||
return router.push("/approval-workflows");
|
||||
} else {
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
}
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
setIsLoading(false);
|
||||
console.log("Submitted Values:", filteredWorkflow);
|
||||
return;
|
||||
})
|
||||
|
||||
console.log("Form submitted! Filtered Values:", filteredWorkflow);
|
||||
};
|
||||
|
||||
const onWorkflowChange = (wf: EditableApprovalWorkflow) => {
|
||||
|
||||
@@ -95,12 +95,11 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
...updatedWorkflow,
|
||||
steps: updatedWorkflow.steps.map(step => ({
|
||||
...step,
|
||||
currentStep: step.stepNumber === 1 ? true : false,
|
||||
completed: false,
|
||||
assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined)
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
axios
|
||||
.put(`/api/approval-workflows/${updatedWorkflow.id}/edit`, filteredWorkflow)
|
||||
.then(() => {
|
||||
@@ -108,23 +107,20 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.push("/approval-workflows");
|
||||
}, 2000);
|
||||
}, 1000);
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
toast.error("Not logged in!");
|
||||
return router.push("/login");
|
||||
}
|
||||
if (reason.response.status === 403) {
|
||||
} else if (reason.response.status === 403) {
|
||||
toast.error("You do not have permission to edit Approval Workflows!");
|
||||
return router.push("/approval-workflows");
|
||||
} else {
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
}
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
setIsLoading(false);
|
||||
console.log("Submitted Values:", filteredWorkflow);
|
||||
return;
|
||||
})
|
||||
|
||||
console.log("Form submitted! Filtered Values:", filteredWorkflow);
|
||||
};
|
||||
|
||||
const onWorkflowChange = (updatedWorkflow: EditableApprovalWorkflow) => {
|
||||
@@ -159,7 +155,7 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
<RequestedBy
|
||||
prefix={getUserTypeLabelShort(user.type)}
|
||||
name={user.name}
|
||||
profileImage="/blue-stock-photo.png" //{user.profilePicture}
|
||||
profileImage={user.profilePicture}
|
||||
/>
|
||||
<StartedOn
|
||||
date={workflow.startDate}
|
||||
|
||||
@@ -14,16 +14,20 @@ import { requestUser } from "@/utils/api";
|
||||
import { getApprovalWorkflow } from "@/utils/approval.workflows.be";
|
||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
||||
import { getSpecificUsers, getUser } from "@/utils/users.be";
|
||||
import axios from "axios";
|
||||
import { AnimatePresence, LayoutGroup, motion } from "framer-motion";
|
||||
import { withIronSessionSsr } from "iron-session/next";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { BsChevronLeft } from "react-icons/bs";
|
||||
import { FaWpforms } from "react-icons/fa6";
|
||||
import { FaSpinner, FaWpforms } from "react-icons/fa6";
|
||||
import { MdOutlineDoubleArrow } from "react-icons/md";
|
||||
import { RiThumbUpLine } from "react-icons/ri";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||
import { FiSave } from "react-icons/fi";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||
const user = await requestUser(req, res);
|
||||
@@ -75,6 +79,9 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
const [selectedStep, setSelectedStep] = useState<WorkflowStep>(steps[selectedStepIndex]);
|
||||
const [isPanelOpen, setIsPanelOpen] = useState(true);
|
||||
const [comments, setComments] = useState<string>(selectedStep.comments || "");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState<boolean>(false);
|
||||
const router = useRouter();
|
||||
|
||||
const handleStepClick = (index: number, stepInfo: WorkflowStep) => {
|
||||
setSelectedStep(stepInfo);
|
||||
@@ -84,11 +91,82 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
};
|
||||
|
||||
const handleSaveComments = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const updatedWorkflow: ApprovalWorkflow = {
|
||||
...workflow,
|
||||
steps: workflow.steps.map((step, index) =>
|
||||
index === selectedStepIndex ?
|
||||
{
|
||||
...step,
|
||||
comments: comments,
|
||||
}
|
||||
: step
|
||||
)
|
||||
};
|
||||
|
||||
axios
|
||||
.put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow)
|
||||
.then(() => {
|
||||
toast.success("Comments saved successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
}, 1000);
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
toast.error("Not logged in!");
|
||||
} else if (reason.response.status === 403) {
|
||||
toast.error("You do not have permission to approve this step!");
|
||||
} else {
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
}
|
||||
setIsLoading(false);
|
||||
console.log("Submitted Values:", updatedWorkflow);
|
||||
return;
|
||||
})
|
||||
};
|
||||
|
||||
const handleApproveStep = () => {
|
||||
|
||||
if (!confirm(`Are you sure you want to approve this step?`)) return;
|
||||
setIsLoading(true);
|
||||
|
||||
const updatedWorkflow: ApprovalWorkflow = {
|
||||
...workflow,
|
||||
steps: workflow.steps.map((step, index) =>
|
||||
index === selectedStepIndex ?
|
||||
{
|
||||
...step,
|
||||
completed: true,
|
||||
completedBy: user.id,
|
||||
completedDate: Date.now(),
|
||||
}
|
||||
: step
|
||||
)
|
||||
};
|
||||
|
||||
axios
|
||||
.put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow)
|
||||
.then(() => {
|
||||
toast.success("Step approved successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
}, 1000);
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
toast.error("Not logged in!");
|
||||
} else if (reason.response.status === 403) {
|
||||
toast.error("You do not have permission to approve this step!");
|
||||
} else {
|
||||
toast.error("Something went wrong, please try again later.");
|
||||
}
|
||||
setIsLoading(false);
|
||||
console.log("Submitted Values:", updatedWorkflow);
|
||||
return;
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -120,7 +198,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
<RequestedBy
|
||||
prefix={getUserTypeLabelShort(workflowRequester.type)}
|
||||
name={workflowRequester.name}
|
||||
profileImage="/blue-stock-photo.png" //{workflowRequester.profilePicture}
|
||||
profileImage={workflowRequester.profilePicture}
|
||||
/>
|
||||
<StartedOn
|
||||
date={workflow.startDate}
|
||||
@@ -245,17 +323,33 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedStepIndex === currentStep &&
|
||||
|
||||
{selectedStepIndex === currentStep && !selectedStep.completed &&
|
||||
<Button
|
||||
type="submit"
|
||||
color="purple"
|
||||
variant="solid"
|
||||
disabled={!selectedStep.assignees.includes(user.id)}
|
||||
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
|
||||
onClick={handleApproveStep}
|
||||
padding="px-6 py-2"
|
||||
className="mb-3 w-full text-lg"
|
||||
className="mb-3 w-full text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
Approve Step
|
||||
{isRedirecting ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Reloading...
|
||||
</>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<IoMdCheckmarkCircleOutline size={20} />
|
||||
Approve Step
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
}
|
||||
|
||||
@@ -267,14 +361,32 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
placeholder="Input comments here"
|
||||
className="w-full h-64 p-2 border-2 rounded-xl shadow-lg focus:border-mti-purple focus:outline-none mt-3 resize-none"
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
color="purple"
|
||||
variant="solid"
|
||||
onClick={handleSaveComments}
|
||||
disabled={isLoading}
|
||||
padding="px-6 py-2"
|
||||
className="mt-6 mb-3 w-full text-lg"
|
||||
className="mt-6 mb-3 w-full text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
Save Comments
|
||||
{isRedirecting ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Reloading...
|
||||
</>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<FiSave size={20} />
|
||||
Save Comments
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<hr className="my-4 h-[4px] bg-mti-purple-ultralight rounded-full w-full" />
|
||||
|
||||
Reference in New Issue
Block a user