180 lines
5.9 KiB
TypeScript
180 lines
5.9 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";
|
|
import {checkAccess} from "@/utils/permissions";
|
|
|
|
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) => checkAccess(x, ["admin", "developer", "agent"]))
|
|
.map((u) => ({
|
|
value: u.id,
|
|
label: `${u.name} - ${u.email}`,
|
|
})),
|
|
]}
|
|
disabled={checkAccess(user, ["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>
|
|
);
|
|
}
|