Add cancellation
This commit is contained in:
parent
9810126b09
commit
31cb674565
48
src/modules/resellerOffice365/actions/cancelRequest.ts
Normal file
48
src/modules/resellerOffice365/actions/cancelRequest.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import db from "@/core/db";
|
||||||
|
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
||||||
|
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||||
|
import notFound from "@/modules/dashboard/utils/notFound";
|
||||||
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
|
import ResellerOffice365Error from "../errors/ResellerOffice365Error";
|
||||||
|
import getCurrentUser from "@/modules/auth/utils/getCurrentUser";
|
||||||
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import "server-only"
|
||||||
|
|
||||||
|
export default async function cancelRequest(id: string): Promise<ServerResponseAction> {
|
||||||
|
try {
|
||||||
|
//TODO: Fix permission
|
||||||
|
if (!(await checkPermission("authenticated-only"))) return unauthorized();
|
||||||
|
|
||||||
|
const data = await db.office365LinkRequest.findFirst({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) return notFound({message: "The Provided ID does not match any"})
|
||||||
|
|
||||||
|
if (data.status !== "WAITING") throw new ResellerOffice365Error({
|
||||||
|
errorCode: "REQUEST_IS_NOT_IN_WAITING_STATE",
|
||||||
|
message: "This item is not in \"waiting\" state to perform cancellation. This might be due to the request has been accepted"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.createdBy !== (await getCurrentUser())?.id) return unauthorized();
|
||||||
|
|
||||||
|
await db.office365LinkRequest.update({
|
||||||
|
where: {id},
|
||||||
|
data: {
|
||||||
|
status: "CANCELLED",
|
||||||
|
cancelledAt: new Date()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
revalidatePath(".")
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return handleCatch(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,8 @@ import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
||||||
import getLinkRequestDataById from "../actions/getLinkRequestDataById";
|
import getLinkRequestDataById from "../actions/getLinkRequestDataById";
|
||||||
import { isPagesAPIRouteMatch } from "next/dist/server/future/route-matches/pages-api-route-match";
|
import { isPagesAPIRouteMatch } from "next/dist/server/future/route-matches/pages-api-route-match";
|
||||||
import inputLink from "../actions/inputLinks";
|
import inputLink from "../actions/inputLinks";
|
||||||
|
import { Office365LinkRequestStatus } from "@prisma/client";
|
||||||
|
import cancelRequest from "../actions/cancelRequest";
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -46,15 +48,27 @@ export interface ModalProps {
|
||||||
|
|
||||||
export default function RequestModal(props: ModalProps) {
|
export default function RequestModal(props: ModalProps) {
|
||||||
const [formState, setFormState] = useState<
|
const [formState, setFormState] = useState<
|
||||||
"idle" | "submitting" | "waiting" | "fetching" | "error"
|
| "idle"
|
||||||
|
| "submitting"
|
||||||
|
| "waiting"
|
||||||
|
| "fetching"
|
||||||
|
| "error"
|
||||||
|
| "confirming cancel"
|
||||||
|
| "cancelling"
|
||||||
>("idle");
|
>("idle");
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
|
const [requestStatus, setRequestStatus] = useState<
|
||||||
|
Office365LinkRequestStatus | "CREATING"
|
||||||
|
>("CREATING");
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = (force?: boolean) => {
|
||||||
if (formState === "submitting") return; //prevents closing
|
if (!force){
|
||||||
|
if (["submitting, cancelling"].includes(formState)) return; //prevents closing
|
||||||
|
}
|
||||||
//reset state
|
//reset state
|
||||||
setErrorMessage("");
|
setErrorMessage("");
|
||||||
|
setRequestStatus("CREATING");
|
||||||
setFormState("idle");
|
setFormState("idle");
|
||||||
form.reset();
|
form.reset();
|
||||||
props.onClose ? props.onClose() : "";
|
props.onClose ? props.onClose() : "";
|
||||||
|
|
@ -94,6 +108,15 @@ export default function RequestModal(props: ModalProps) {
|
||||||
link: item.link ?? "",
|
link: item.link ?? "",
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
setRequestStatus(data.status);
|
||||||
|
if (
|
||||||
|
data.status === "WAITING" &&
|
||||||
|
props.type === "detail"
|
||||||
|
) {
|
||||||
|
setFormState("waiting");
|
||||||
|
} else {
|
||||||
|
setFormState("idle");
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
|
|
@ -101,8 +124,6 @@ export default function RequestModal(props: ModalProps) {
|
||||||
} else {
|
} else {
|
||||||
setErrorMessage("Unkown error occured");
|
setErrorMessage("Unkown error occured");
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setFormState("idle");
|
setFormState("idle");
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
@ -227,12 +248,81 @@ export default function RequestModal(props: ModalProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
if (!props.detailId) return setErrorMessage("Cannot request cancellation. Cause: the ID is empty. Please contact your administrator")
|
||||||
|
setFormState("cancelling")
|
||||||
|
withServerAction(cancelRequest, props.detailId)
|
||||||
|
.then(() => {
|
||||||
|
notifications.show({
|
||||||
|
message: "The request has been cancelled",
|
||||||
|
color: "green"
|
||||||
|
})
|
||||||
|
setFormState("idle")
|
||||||
|
closeModal(true)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
if (e instanceof Error){
|
||||||
|
setErrorMessage(e.message)
|
||||||
|
}
|
||||||
|
setFormState("idle")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderActionButtons = () => (
|
||||||
|
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => closeModal()}
|
||||||
|
disabled={["submitting"].includes(formState)}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
{showCancelButton && (
|
||||||
|
<Button variant="outline" color="red" type="button" onClick={() => setFormState("confirming cancel")}>
|
||||||
|
Cancel Request
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{showSubmitButton && (
|
||||||
|
<Button
|
||||||
|
variant="filled"
|
||||||
|
leftSection={<TbDeviceFloppy size={20} />}
|
||||||
|
type="submit"
|
||||||
|
disabled={["submitting", "waiting"].includes(formState)}
|
||||||
|
loading={["submitting"].includes(formState)}
|
||||||
|
>
|
||||||
|
{props.type === "create" ? "Make Request" : "Save"}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderCancelConfirmation = () => (
|
||||||
|
<Stack mt="lg" gap={0}>
|
||||||
|
<Text>Are you sure to cancel this link request?</Text>
|
||||||
|
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
|
||||||
|
<Button type="button" variant="outline" onClick={() => setFormState("waiting")}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button type="button" variant="transparent" color="red" onClick={handleCancel}>
|
||||||
|
Yes, I am sure
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
const disableChange = formState !== "idle";
|
const disableChange = formState !== "idle";
|
||||||
const readonly = ["input link", "detail"].includes(props.type);
|
const readonly = ["input link", "detail"].includes(props.type);
|
||||||
const showSkeleton = formState === "fetching";
|
const showSkeleton = formState === "fetching";
|
||||||
const showActivationLink = ["input link", "detail"].includes(props.type);
|
const showActivationLink = ["input link", "detail"].includes(props.type);
|
||||||
const enableInputActivationLink = props.type === "input link";
|
const enableInputActivationLink = props.type === "input link";
|
||||||
const showSubmitButton = ["create", "input link"].includes(props.type);
|
const showSubmitButton = ["create", "input link"].includes(props.type);
|
||||||
|
const showCancelButton =
|
||||||
|
["detail"].includes(props.type) && formState === "waiting";
|
||||||
|
const showCancelRequestConfirmation = [
|
||||||
|
"confirming cancel",
|
||||||
|
"cancelling",
|
||||||
|
].includes(formState);
|
||||||
|
const showWaitingAlert = (["waiting", "confirming cancel"] as typeof formState[]).includes(formState)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|
@ -248,7 +338,7 @@ export default function RequestModal(props: ModalProps) {
|
||||||
>
|
>
|
||||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
{formState === "waiting" && (
|
{showWaitingAlert && (
|
||||||
<Alert color="orange">
|
<Alert color="orange">
|
||||||
Your request is being processed by administrator
|
Your request is being processed by administrator
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
@ -349,30 +439,9 @@ export default function RequestModal(props: ModalProps) {
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
{/* Buttons */}
|
{/* Buttons */}
|
||||||
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
|
{showCancelRequestConfirmation
|
||||||
<Button
|
? renderCancelConfirmation()
|
||||||
variant="outline"
|
: renderActionButtons()}
|
||||||
onClick={closeModal}
|
|
||||||
disabled={["submitting"].includes(formState)}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
{showSubmitButton && (
|
|
||||||
<Button
|
|
||||||
variant="filled"
|
|
||||||
leftSection={<TbDeviceFloppy size={20} />}
|
|
||||||
type="submit"
|
|
||||||
disabled={["submitting", "waiting"].includes(
|
|
||||||
formState
|
|
||||||
)}
|
|
||||||
loading={["submitting"].includes(formState)}
|
|
||||||
>
|
|
||||||
{props.type === "create"
|
|
||||||
? "Make Request"
|
|
||||||
: "Save"}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user