255 lines
7.2 KiB
TypeScript
255 lines
7.2 KiB
TypeScript
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}`,
|
|
})),
|
|
]}
|
|
disabled={user.type === "agent"}
|
|
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>
|
|
);
|
|
}
|