Created a new page for ticket handling as well as submission

This commit is contained in:
Tiago Ribeiro
2024-01-28 21:05:17 +00:00
parent cf1cb6f270
commit 8b7e550a70
11 changed files with 1546 additions and 365 deletions

View File

@@ -0,0 +1,253 @@
import useUsers from "@/hooks/useUsers";
import {
Ticket,
TicketStatus,
TicketStatusLabel,
TicketType,
TicketTypeLabel,
} from "@/interfaces/ticket";
import { User } from "@/interfaces/user";
import { USER_TYPE_LABELS } from "@/resources/user";
import axios from "axios";
import moment from "moment";
import { useState } from "react";
import { toast } from "react-toastify";
import ShortUniqueId from "short-unique-id";
import Button from "../Low/Button";
import Input from "../Low/Input";
import Select from "../Low/Select";
interface Props {
user: User;
ticket: Ticket;
onClose: () => void;
}
export default function TicketDisplay({ user, ticket, onClose }: Props) {
const [subject] = useState(ticket.subject);
const [type, setType] = useState<TicketType>(ticket.type);
const [description] = useState(ticket.description);
const [reporter] = useState(ticket.reporter);
const [reportedFrom] = useState(ticket.reportedFrom);
const [status, setStatus] = useState(ticket.status);
const [assignedTo, setAssignedTo] = useState<string | null>(
ticket.assignedTo || null,
);
const [isLoading, setIsLoading] = useState(false);
const { users } = useUsers();
const submit = () => {
if (!type)
return toast.error("Please choose a type!", { toastId: "missing-type" });
setIsLoading(true);
axios
.patch(`/api/tickets/${ticket.id}`, {
subject,
type,
description,
reporter,
reportedFrom,
status,
assignedTo,
})
.then(() => {
toast.success(`The ticket has been updated!`, { toastId: "submitted" });
onClose();
})
.catch((e) => {
console.error(e);
toast.error("Something went wrong, please try again later!", {
toastId: "error",
});
})
.finally(() => setIsLoading(false));
};
const del = () => {
if (!confirm("Are you sure you want to delete this ticket?")) return;
setIsLoading(true);
axios
.delete(`/api/tickets/${ticket.id}`)
.then(() => {
toast.success(`The ticket has been deleted!`, { toastId: "submitted" });
onClose();
})
.catch((e) => {
console.error(e);
toast.error("Something went wrong, please try again later!", {
toastId: "error",
});
})
.finally(() => setIsLoading(false));
};
return (
<form className="flex flex-col gap-4 pt-8">
<Input
label="Subject"
type="text"
name="subject"
placeholder="Subject..."
value={subject}
onChange={(e) => null}
disabled
/>
<div className="-md:flex-col flex w-full items-center gap-4">
<div className="flex w-full flex-col gap-3">
<label className="text-mti-gray-dim text-base font-normal">
Status
</label>
<Select
options={Object.keys(TicketStatusLabel).map((x) => ({
value: x,
label: TicketStatusLabel[x as keyof typeof TicketStatusLabel],
}))}
value={{ value: status, label: TicketStatusLabel[status] }}
onChange={(value) =>
setStatus((value?.value as TicketStatus) ?? undefined)
}
placeholder="Status..."
/>
</div>
<div className="flex w-full flex-col gap-3">
<label className="text-mti-gray-dim text-base font-normal">
Type
</label>
<Select
options={Object.keys(TicketTypeLabel).map((x) => ({
value: x,
label: TicketTypeLabel[x as keyof typeof TicketTypeLabel],
}))}
value={{ value: type, label: TicketTypeLabel[type] }}
onChange={(value) => setType(value!.value as TicketType)}
placeholder="Type..."
/>
</div>
</div>
<div className="flex w-full flex-col gap-3">
<label className="text-mti-gray-dim text-base font-normal">
Assignee
</label>
<Select
options={[
{ value: "me", label: "Assign to me" },
...users
.filter((x) => ["admin", "developer"].includes(x.type))
.map((u) => ({
value: u.id,
label: `${u.name} - ${u.email}`,
})),
]}
value={
assignedTo
? {
value: assignedTo,
label: `${users.find((u) => u.id === assignedTo)?.name} - ${users.find((u) => u.id === assignedTo)?.email}`,
}
: null
}
onChange={(value) =>
value
? setAssignedTo(value.value === "me" ? user.id : value.value)
: setAssignedTo(null)
}
placeholder="Assignee..."
isClearable
/>
</div>
<div className="-md:flex-col flex w-full items-center gap-4">
<Input
label="Reported From"
type="text"
name="reportedFrom"
onChange={() => null}
value={reportedFrom}
disabled
/>
<Input
label="Date"
type="text"
name="date"
onChange={() => null}
value={moment(ticket.date).format("DD/MM/YYYY - HH:mm")}
disabled
/>
</div>
<div className="-md:flex-col flex w-full items-center gap-4">
<Input
label="Reporter's Name"
type="text"
name="reporter"
onChange={() => null}
value={reporter.name}
disabled
/>
<Input
label="Reporter's E-mail"
type="text"
name="reporter"
onChange={() => null}
value={reporter.email}
disabled
/>
<Input
label="Reporter's Type"
type="text"
name="reporterType"
onChange={() => null}
value={USER_TYPE_LABELS[reporter.type]}
disabled
/>
</div>
<textarea
className="input border-mti-gray-platinum h-full min-h-[300px] w-full cursor-text rounded-3xl border bg-white px-7 py-8"
placeholder="Write your ticket's description here..."
contentEditable={false}
value={description}
spellCheck
/>
<div className="-md:flex-col-reverse mt-2 flex w-full items-center justify-between gap-4">
<Button
type="button"
color="red"
className="w-full md:max-w-[200px]"
variant="outline"
onClick={del}
isLoading={isLoading}
>
Delete
</Button>
<div className="-md:flex-col-reverse flex w-full items-center justify-end gap-4">
<Button
type="button"
color="red"
className="w-full md:max-w-[200px]"
variant="outline"
onClick={onClose}
isLoading={isLoading}
>
Cancel
</Button>
<Button
type="button"
className="w-full md:max-w-[200px]"
isLoading={isLoading}
onClick={submit}
>
Update
</Button>
</div>
</div>
</form>
);
}