implement rejection of steps
This commit is contained in:
@@ -47,7 +47,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }
|
||||
user,
|
||||
workflow,
|
||||
userEntitiesWithLabel,
|
||||
userEntitiesApprovers: await getEntitiesUsers(userEntitiesWithLabel.map(entity => entity.id), { type: {$in: ["teacher", "corporate", "mastercorporate", "developer"]} }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
userEntitiesApprovers: await getEntitiesUsers(userEntitiesWithLabel.map(entity => entity.id), { type: { $in: ["teacher", "corporate", "mastercorporate", "developer"] } }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
}),
|
||||
};
|
||||
}, sessionOptions);
|
||||
@@ -134,9 +134,7 @@ export default function Home({ user, workflow, userEntitiesWithLabel, userEntiti
|
||||
.then(() => {
|
||||
toast.success("Approval Workflow cloned successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.push("/approval-workflows");
|
||||
}, 1000);
|
||||
router.push("/approval-workflows");
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
|
||||
@@ -39,7 +39,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }
|
||||
props: serialize({
|
||||
user,
|
||||
workflow,
|
||||
workflowEntityApprovers: await getEntityUsers(workflow.entityId, undefined, { type: {$in: ["teacher", "corporate", "mastercorporate", "developer"]} }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
workflowEntityApprovers: await getEntityUsers(workflow.entityId, undefined, { type: { $in: ["teacher", "corporate", "mastercorporate", "developer"] } }) as (TeacherUser | CorporateUser | MasterCorporateUser | DeveloperUser)[],
|
||||
}),
|
||||
};
|
||||
}, sessionOptions);
|
||||
@@ -54,7 +54,7 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
const [updatedWorkflow, setUpdatedWorkflow] = useState<EditableApprovalWorkflow | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState<boolean>(false);
|
||||
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -86,10 +86,10 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
|
||||
if (!updatedWorkflow){
|
||||
if (!updatedWorkflow) {
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const filteredWorkflow: ApprovalWorkflow = {
|
||||
...updatedWorkflow,
|
||||
@@ -99,15 +99,13 @@ export default function Home({ user, workflow, workflowEntityApprovers }: Props)
|
||||
assignees: step.assignees.filter((assignee): assignee is string => assignee !== null && assignee !== undefined)
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
axios
|
||||
.put(`/api/approval-workflows/${updatedWorkflow.id}/edit`, filteredWorkflow)
|
||||
.then(() => {
|
||||
toast.success("Approval Workflow edited successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.push("/approval-workflows");
|
||||
}, 1000);
|
||||
router.push("/approval-workflows");
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import { RiThumbUpLine } from "react-icons/ri";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||
import { FiSave } from "react-icons/fi";
|
||||
import { RxCrossCircled } from "react-icons/rx";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res, params }) => {
|
||||
const user = await requestUser(req, res);
|
||||
@@ -71,7 +72,7 @@ interface Props {
|
||||
export default function Home({ user, workflow, workflowAssignees, workflowRequester }: Props) {
|
||||
const steps = workflow.steps;
|
||||
|
||||
let currentStep = steps.findIndex(step => !step.completed);
|
||||
let currentStep = steps.findIndex(step => !step.completed || step.rejected);
|
||||
if (currentStep === -1)
|
||||
currentStep = steps.length - 1;
|
||||
|
||||
@@ -110,9 +111,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
.then(() => {
|
||||
toast.success("Comments saved successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
}, 1000);
|
||||
router.reload();
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
@@ -129,7 +128,6 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
};
|
||||
|
||||
const handleApproveStep = () => {
|
||||
if (!confirm(`Are you sure you want to approve this step?`)) return;
|
||||
setIsLoading(true);
|
||||
|
||||
const updatedWorkflow: ApprovalWorkflow = {
|
||||
@@ -151,9 +149,48 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
.then(() => {
|
||||
toast.success("Step approved successfully.");
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
router.reload();
|
||||
}, 1000);
|
||||
router.reload();
|
||||
})
|
||||
.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 handleRejectStep = () => {
|
||||
if (!confirm(`Are you sure you want to reject this step?`)) return;
|
||||
setIsLoading(true);
|
||||
|
||||
const updatedWorkflow: ApprovalWorkflow = {
|
||||
...workflow,
|
||||
status: "rejected",
|
||||
steps: workflow.steps.map((step, index) =>
|
||||
index === selectedStepIndex ?
|
||||
{
|
||||
...step,
|
||||
completed: true,
|
||||
completedBy: user.id,
|
||||
completedDate: Date.now(),
|
||||
rejected: true,
|
||||
}
|
||||
: step
|
||||
)
|
||||
};
|
||||
|
||||
axios
|
||||
.put(`/api/approval-workflows/${workflow._id}`, updatedWorkflow)
|
||||
.then(() => {
|
||||
toast.success("Step rejected successfully.");
|
||||
setIsRedirecting(true);
|
||||
router.reload();
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (reason.response.status === 401) {
|
||||
@@ -219,6 +256,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
key={index}
|
||||
completed={step.completed}
|
||||
completedBy={step.completedBy}
|
||||
rejected={step.rejected}
|
||||
stepNumber={step.stepNumber}
|
||||
stepType={step.stepType}
|
||||
assignees={step.assignees}
|
||||
@@ -276,7 +314,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
|
||||
{selectedStep.completed ? (
|
||||
<div className={"text-base font-medium text-gray-500 flex flex-col gap-6"}>
|
||||
Approved on {new Date(selectedStep.completedDate!).toLocaleString("en-CA", {
|
||||
{selectedStep.rejected ? "Rejected" : "Approved"} on {new Date(selectedStep.completedDate!).toLocaleString("en-CA", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
@@ -286,7 +324,7 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
hour12: false,
|
||||
}).replace(", ", " at ")}
|
||||
<div className="flex flex-row gap-1 text-sm">
|
||||
<p className="text-base">Approved by:</p>
|
||||
<p className="text-base">{selectedStep.rejected ? "Rejected" : "Approved"} by:</p>
|
||||
{(() => {
|
||||
const assignee = workflowAssignees.find(
|
||||
(assignee) => assignee.id === selectedStep.completedBy
|
||||
@@ -324,33 +362,61 @@ export default function Home({ user, workflow, workflowAssignees, workflowReques
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedStepIndex === currentStep && !selectedStep.completed &&
|
||||
<Button
|
||||
type="submit"
|
||||
color="purple"
|
||||
variant="solid"
|
||||
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
|
||||
onClick={handleApproveStep}
|
||||
padding="px-6 py-2"
|
||||
className="mb-3 w-full text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
{isRedirecting ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Reloading...
|
||||
</>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<IoMdCheckmarkCircleOutline size={20} />
|
||||
Approve Step
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
{selectedStepIndex === currentStep && !selectedStep.completed && !selectedStep.rejected &&
|
||||
<div className="flex flex-row gap-2 ">
|
||||
<Button
|
||||
type="submit"
|
||||
color="purple"
|
||||
variant="solid"
|
||||
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
|
||||
onClick={handleApproveStep}
|
||||
padding="px-6 py-2"
|
||||
className="mb-3 w-full text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
{isRedirecting ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Reloading...
|
||||
</>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<IoMdCheckmarkCircleOutline size={20} />
|
||||
Approve Step
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
color="red"
|
||||
variant="solid"
|
||||
disabled={!selectedStep.assignees.includes(user.id) || isLoading}
|
||||
onClick={handleRejectStep}
|
||||
padding="px-6 py-2"
|
||||
className="mb-3 w-1/2 text-lg flex items-center justify-center gap-2 text-left"
|
||||
>
|
||||
{isRedirecting ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Reloading...
|
||||
</>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<FaSpinner className="animate-spin size-5" />
|
||||
Loading...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RxCrossCircled size={20} />
|
||||
Reject Step
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<hr className="my-4 h-[4px] bg-mti-purple-ultralight rounded-full w-full" />
|
||||
@@ -361,7 +427,7 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user