Applied the same fix for other pages
This commit is contained in:
@@ -22,16 +22,16 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
|||||||
redirect: {
|
redirect: {
|
||||||
destination: "/login",
|
destination: "/login",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRedirectHome(user) || user.type !== "developer") {
|
if (shouldRedirectHome(user) || !["developer", "admin", "corporate", "agent"].includes(user.type)) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/",
|
destination: "/",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,388 +5,308 @@ import Modal from "@/components/Modal";
|
|||||||
import useTickets from "@/hooks/useTickets";
|
import useTickets from "@/hooks/useTickets";
|
||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {
|
import {Ticket, TicketStatus, TicketStatusLabel, TicketType, TicketTypeLabel, TicketWithCorporate} from "@/interfaces/ticket";
|
||||||
Ticket,
|
import {sessionOptions} from "@/lib/session";
|
||||||
TicketStatus,
|
import {shouldRedirectHome} from "@/utils/navigation.disabled";
|
||||||
TicketStatusLabel,
|
import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table";
|
||||||
TicketType,
|
|
||||||
TicketTypeLabel,
|
|
||||||
TicketWithCorporate,
|
|
||||||
} from "@/interfaces/ticket";
|
|
||||||
import { sessionOptions } from "@/lib/session";
|
|
||||||
import { shouldRedirectHome } from "@/utils/navigation.disabled";
|
|
||||||
import {
|
|
||||||
createColumnHelper,
|
|
||||||
flexRender,
|
|
||||||
getCoreRowModel,
|
|
||||||
useReactTable,
|
|
||||||
} from "@tanstack/react-table";
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { withIronSessionSsr } from "iron-session/next";
|
import {withIronSessionSsr} from "iron-session/next";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useEffect, useState } from "react";
|
import {useEffect, useState} from "react";
|
||||||
import { BsArrowDown, BsArrowUp } from "react-icons/bs";
|
import {BsArrowDown, BsArrowUp} from "react-icons/bs";
|
||||||
import { ToastContainer } from "react-toastify";
|
import {ToastContainer} from "react-toastify";
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<TicketWithCorporate>();
|
const columnHelper = createColumnHelper<TicketWithCorporate>();
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({ req, res }) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
|
|
||||||
if (!user || !user.isVerified) {
|
if (!user || !user.isVerified) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/login",
|
destination: "/login",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (shouldRedirectHome(user) || !["admin", "developer", "agent"].includes(user.type)) {
|
||||||
shouldRedirectHome(user) ||
|
|
||||||
["admin", "developer", "agent"].includes(user.type)
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/",
|
destination: "/",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: { user: req.session.user },
|
props: {user: req.session.user},
|
||||||
};
|
};
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
const StatusClassNames: { [key in TicketStatus]: string } = {
|
const StatusClassNames: {[key in TicketStatus]: string} = {
|
||||||
submitted: "bg-mti-gray-dim",
|
submitted: "bg-mti-gray-dim",
|
||||||
"in-progress": "bg-mti-blue-dark",
|
"in-progress": "bg-mti-blue-dark",
|
||||||
completed: "bg-mti-green-dark",
|
completed: "bg-mti-green-dark",
|
||||||
};
|
};
|
||||||
|
|
||||||
const TypesClassNames: { [key in TicketType]: string } = {
|
const TypesClassNames: {[key in TicketType]: string} = {
|
||||||
feedback: "bg-mti-green-light",
|
feedback: "bg-mti-green-light",
|
||||||
bug: "bg-mti-red-dark",
|
bug: "bg-mti-red-dark",
|
||||||
help: "bg-mti-blue-light",
|
help: "bg-mti-blue-light",
|
||||||
};
|
};
|
||||||
|
|
||||||
const escapedURL = process.env.NEXT_PUBLIC_WEBSITE_URL || ''.replace(
|
const escapedURL = process.env.NEXT_PUBLIC_WEBSITE_URL || "".replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
/[.*+?^${}()|[\]\\]/g,
|
|
||||||
"\\$&"
|
|
||||||
);
|
|
||||||
const fromHomepage = [new RegExp(`^${escapedURL}`), /\/contact$/];
|
const fromHomepage = [new RegExp(`^${escapedURL}`), /\/contact$/];
|
||||||
|
|
||||||
type Source = "webpage" | "platform" | "";
|
type Source = "webpage" | "platform" | "";
|
||||||
|
|
||||||
const SOURCE_OPTIONS = [
|
const SOURCE_OPTIONS = [
|
||||||
{ value: "", label: "All" },
|
{value: "", label: "All"},
|
||||||
{ value: "webpage", label: "Webpage" },
|
{value: "webpage", label: "Webpage"},
|
||||||
{ value: "platform", label: "Platform" },
|
{value: "platform", label: "Platform"},
|
||||||
]
|
];
|
||||||
|
|
||||||
export default function Tickets() {
|
export default function Tickets() {
|
||||||
const [filteredTickets, setFilteredTickets] = useState<Ticket[]>([]);
|
const [filteredTickets, setFilteredTickets] = useState<Ticket[]>([]);
|
||||||
const [selectedTicket, setSelectedTicket] = useState<Ticket>();
|
const [selectedTicket, setSelectedTicket] = useState<Ticket>();
|
||||||
const [assigneeFilter, setAssigneeFilter] = useState<string>();
|
const [assigneeFilter, setAssigneeFilter] = useState<string>();
|
||||||
const [sourceFilter, setSourceFilter] = useState<Source>("");
|
const [sourceFilter, setSourceFilter] = useState<Source>("");
|
||||||
|
|
||||||
const [dateSorting, setDateSorting] = useState<"asc" | "desc">("desc");
|
const [dateSorting, setDateSorting] = useState<"asc" | "desc">("desc");
|
||||||
|
|
||||||
const [typeFilter, setTypeFilter] = useState<TicketType>();
|
const [typeFilter, setTypeFilter] = useState<TicketType>();
|
||||||
const [statusFilter, setStatusFilter] = useState<TicketStatus>();
|
const [statusFilter, setStatusFilter] = useState<TicketStatus>();
|
||||||
|
|
||||||
const { user } = useUser({ redirectTo: "/login" });
|
const {user} = useUser({redirectTo: "/login"});
|
||||||
const { users } = useUsers();
|
const {users} = useUsers();
|
||||||
const { tickets, reload } = useTickets();
|
const {tickets, reload} = useTickets();
|
||||||
|
|
||||||
const sortByDate = (a: Ticket, b: Ticket) => {
|
const sortByDate = (a: Ticket, b: Ticket) => {
|
||||||
return moment((dateSorting === "desc" ? b : a).date).diff(
|
return moment((dateSorting === "desc" ? b : a).date).diff(moment((dateSorting === "desc" ? a : b).date));
|
||||||
moment((dateSorting === "desc" ? a : b).date)
|
};
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filters = [];
|
const filters = [];
|
||||||
if (user?.type === "agent")
|
if (user?.type === "agent") filters.push((x: Ticket) => x.assignedTo === user.id);
|
||||||
filters.push((x: Ticket) => x.assignedTo === user.id);
|
if (typeFilter) filters.push((x: Ticket) => x.type === typeFilter);
|
||||||
if (typeFilter) filters.push((x: Ticket) => x.type === typeFilter);
|
if (statusFilter) filters.push((x: Ticket) => x.status === statusFilter);
|
||||||
if (statusFilter) filters.push((x: Ticket) => x.status === statusFilter);
|
if (assigneeFilter) filters.push((x: Ticket) => x.assignedTo === assigneeFilter);
|
||||||
if (assigneeFilter)
|
if (sourceFilter) {
|
||||||
filters.push((x: Ticket) => x.assignedTo === assigneeFilter);
|
if (sourceFilter === "webpage") filters.push((x: Ticket) => fromHomepage.some((r) => r.test(x.reportedFrom)));
|
||||||
if (sourceFilter) {
|
if (sourceFilter === "platform") filters.push((x: Ticket) => !fromHomepage.some((r) => r.test(x.reportedFrom)));
|
||||||
if (sourceFilter === "webpage")
|
}
|
||||||
filters.push((x: Ticket) => fromHomepage.some((r) => r.test(x.reportedFrom)));
|
setFilteredTickets([...filters.reduce((d, f) => d.filter(f), tickets)].sort(sortByDate));
|
||||||
if (sourceFilter === "platform")
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
filters.push((x: Ticket) => !fromHomepage.some((r) => r.test(x.reportedFrom)));
|
}, [tickets, typeFilter, statusFilter, assigneeFilter, dateSorting, user, sourceFilter]);
|
||||||
}
|
|
||||||
setFilteredTickets(
|
|
||||||
[...filters.reduce((d, f) => d.filter(f), tickets)].sort(sortByDate)
|
|
||||||
);
|
|
||||||
}, [tickets, typeFilter, statusFilter, assigneeFilter, dateSorting, user, sourceFilter]);
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
columnHelper.accessor("id", {
|
columnHelper.accessor("id", {
|
||||||
header: "ID",
|
header: "ID",
|
||||||
cell: (info) => info.getValue(),
|
cell: (info) => info.getValue(),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("type", {
|
columnHelper.accessor("type", {
|
||||||
header: "Type",
|
header: "Type",
|
||||||
cell: (info) => (
|
cell: (info) => (
|
||||||
<span
|
<span className={clsx("rounded-lg p-1 px-2 text-white", TypesClassNames[info.getValue()])}>{TicketTypeLabel[info.getValue()]}</span>
|
||||||
className={clsx(
|
),
|
||||||
"rounded-lg p-1 px-2 text-white",
|
}),
|
||||||
TypesClassNames[info.getValue()]
|
columnHelper.accessor("reporter", {
|
||||||
)}
|
header: "Reporter",
|
||||||
>
|
cell: (info) => info.getValue().email,
|
||||||
{TicketTypeLabel[info.getValue()]}
|
}),
|
||||||
</span>
|
columnHelper.accessor("reportedFrom", {
|
||||||
),
|
header: "Reported From",
|
||||||
}),
|
cell: (info) => info.getValue(),
|
||||||
columnHelper.accessor("reporter", {
|
}),
|
||||||
header: "Reporter",
|
columnHelper.accessor("date", {
|
||||||
cell: (info) => info.getValue().email,
|
id: "date",
|
||||||
}),
|
header: (
|
||||||
columnHelper.accessor("reportedFrom", {
|
<button className="flex items-center gap-2" onClick={() => setDateSorting((prev) => (prev === "asc" ? "desc" : "asc"))}>
|
||||||
header: "Reported From",
|
<span>Date</span>
|
||||||
cell: (info) => info.getValue(),
|
{dateSorting === "desc" && <BsArrowDown />}
|
||||||
}),
|
{dateSorting === "asc" && <BsArrowUp />}
|
||||||
columnHelper.accessor("date", {
|
</button>
|
||||||
id: "date",
|
) as any,
|
||||||
header: (
|
cell: (info) => <span className="whitespace-nowrap">{moment(info.getValue()).format("DD/MM/YYYY - HH:mm")}</span>,
|
||||||
<button
|
}),
|
||||||
className="flex items-center gap-2"
|
columnHelper.accessor("subject", {
|
||||||
onClick={() =>
|
header: "Subject",
|
||||||
setDateSorting((prev) => (prev === "asc" ? "desc" : "asc"))
|
cell: (info) => info.getValue().substring(0, 12) + (info.getValue().length > 12 ? "..." : ""),
|
||||||
}
|
}),
|
||||||
>
|
columnHelper.accessor("status", {
|
||||||
<span>Date</span>
|
header: "Status",
|
||||||
{dateSorting === "desc" && <BsArrowDown />}
|
cell: (info) => (
|
||||||
{dateSorting === "asc" && <BsArrowUp />}
|
<span className={clsx("rounded-lg p-1 px-2 text-white", StatusClassNames[info.getValue()])}>
|
||||||
</button>
|
{TicketStatusLabel[info.getValue()]}
|
||||||
) as any,
|
</span>
|
||||||
cell: (info) => (
|
),
|
||||||
<span className="whitespace-nowrap">{moment(info.getValue()).format("DD/MM/YYYY - HH:mm")}</span>
|
}),
|
||||||
),
|
columnHelper.accessor("assignedTo", {
|
||||||
}),
|
header: "Assignee",
|
||||||
columnHelper.accessor("subject", {
|
cell: (info) => users.find((x) => x.id === info.getValue())?.name || "",
|
||||||
header: "Subject",
|
}),
|
||||||
cell: (info) =>
|
columnHelper.accessor("corporate", {
|
||||||
info.getValue().substring(0, 12) +
|
header: "Corporate",
|
||||||
(info.getValue().length > 12 ? "..." : ""),
|
cell: (info) => info.getValue(),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("status", {
|
];
|
||||||
header: "Status",
|
|
||||||
cell: (info) => (
|
|
||||||
<span
|
|
||||||
className={clsx(
|
|
||||||
"rounded-lg p-1 px-2 text-white",
|
|
||||||
StatusClassNames[info.getValue()]
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{TicketStatusLabel[info.getValue()]}
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
columnHelper.accessor("assignedTo", {
|
|
||||||
header: "Assignee",
|
|
||||||
cell: (info) => users.find((x) => x.id === info.getValue())?.name || "",
|
|
||||||
}),
|
|
||||||
columnHelper.accessor("corporate", {
|
|
||||||
header: "Corporate",
|
|
||||||
cell: (info) => info.getValue(),
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
const getAssigneeValue = () => {
|
const getAssigneeValue = () => {
|
||||||
if (user && user.type === "agent")
|
if (user && user.type === "agent") return {value: user.id, label: `${user.name} - ${user.email}`};
|
||||||
return { value: user.id, label: `${user.name} - ${user.email}` };
|
|
||||||
|
|
||||||
if (assigneeFilter) {
|
if (assigneeFilter) {
|
||||||
const assigneeUser = users.find((x) => x.id === assigneeFilter);
|
const assigneeUser = users.find((x) => x.id === assigneeFilter);
|
||||||
return assigneeUser
|
return assigneeUser
|
||||||
? {
|
? {
|
||||||
value: assigneeFilter,
|
value: assigneeFilter,
|
||||||
label: `${assigneeUser.name} - ${assigneeUser.email}`,
|
label: `${assigneeUser.name} - ${assigneeUser.email}`,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: filteredTickets,
|
data: filteredTickets,
|
||||||
columns: columns,
|
columns: columns,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={!!selectedTicket}
|
isOpen={!!selectedTicket}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
reload();
|
reload();
|
||||||
setSelectedTicket(undefined);
|
setSelectedTicket(undefined);
|
||||||
}}
|
}}>
|
||||||
>
|
{selectedTicket && (
|
||||||
{selectedTicket && (
|
<TicketDisplay
|
||||||
<TicketDisplay
|
user={user!}
|
||||||
user={user!}
|
ticket={selectedTicket}
|
||||||
ticket={selectedTicket}
|
onClose={() => {
|
||||||
onClose={() => {
|
reload();
|
||||||
reload();
|
setSelectedTicket(undefined);
|
||||||
setSelectedTicket(undefined);
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
</Modal>
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>Tickets Panel | EnCoach</title>
|
<title>Tickets Panel | EnCoach</title>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
||||||
/>
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
{user && (
|
{user && (
|
||||||
<Layout user={user} className="gap-6">
|
<Layout user={user} className="gap-6">
|
||||||
<h1 className="text-2xl font-semibold">Tickets</h1>
|
<h1 className="text-2xl font-semibold">Tickets</h1>
|
||||||
|
|
||||||
<div className="flex w-full items-center gap-4">
|
<div className="flex w-full items-center gap-4">
|
||||||
<div className="flex w-full flex-col gap-3">
|
<div className="flex w-full flex-col gap-3">
|
||||||
<label className="text-mti-gray-dim text-base font-normal">
|
<label className="text-mti-gray-dim text-base font-normal">Status</label>
|
||||||
Status
|
<Select
|
||||||
</label>
|
options={Object.keys(TicketStatusLabel).map((x) => ({
|
||||||
<Select
|
value: x,
|
||||||
options={Object.keys(TicketStatusLabel).map((x) => ({
|
label: TicketStatusLabel[x as keyof typeof TicketStatusLabel],
|
||||||
value: x,
|
}))}
|
||||||
label: TicketStatusLabel[x as keyof typeof TicketStatusLabel],
|
value={
|
||||||
}))}
|
statusFilter
|
||||||
value={
|
? {
|
||||||
statusFilter
|
value: statusFilter,
|
||||||
? {
|
label: TicketStatusLabel[statusFilter],
|
||||||
value: statusFilter,
|
}
|
||||||
label: TicketStatusLabel[statusFilter],
|
: undefined
|
||||||
}
|
}
|
||||||
: undefined
|
onChange={(value) => setStatusFilter((value?.value as TicketStatus) ?? undefined)}
|
||||||
}
|
isClearable
|
||||||
onChange={(value) =>
|
placeholder="Status..."
|
||||||
setStatusFilter((value?.value as TicketStatus) ?? undefined)
|
/>
|
||||||
}
|
</div>
|
||||||
isClearable
|
<div className="flex w-full flex-col gap-3">
|
||||||
placeholder="Status..."
|
<label className="text-mti-gray-dim text-base font-normal">Type</label>
|
||||||
/>
|
<Select
|
||||||
</div>
|
options={Object.keys(TicketTypeLabel).map((x) => ({
|
||||||
<div className="flex w-full flex-col gap-3">
|
value: x,
|
||||||
<label className="text-mti-gray-dim text-base font-normal">
|
label: TicketTypeLabel[x as keyof typeof TicketTypeLabel],
|
||||||
Type
|
}))}
|
||||||
</label>
|
value={typeFilter ? {value: typeFilter, label: TicketTypeLabel[typeFilter]} : undefined}
|
||||||
<Select
|
onChange={(value) => setTypeFilter((value?.value as TicketType) ?? undefined)}
|
||||||
options={Object.keys(TicketTypeLabel).map((x) => ({
|
isClearable
|
||||||
value: x,
|
placeholder="Type..."
|
||||||
label: TicketTypeLabel[x as keyof typeof TicketTypeLabel],
|
/>
|
||||||
}))}
|
</div>
|
||||||
value={
|
<div className="flex w-full flex-col gap-3">
|
||||||
typeFilter
|
<label className="text-mti-gray-dim text-base font-normal">Assignee</label>
|
||||||
? { value: typeFilter, label: TicketTypeLabel[typeFilter] }
|
<Select
|
||||||
: undefined
|
options={[
|
||||||
}
|
{value: "me", label: "Assigned to me"},
|
||||||
onChange={(value) =>
|
...users
|
||||||
setTypeFilter((value?.value as TicketType) ?? undefined)
|
.filter((x) => ["admin", "developer", "agent"].includes(x.type))
|
||||||
}
|
.map((u) => ({
|
||||||
isClearable
|
value: u.id,
|
||||||
placeholder="Type..."
|
label: `${u.name} - ${u.email}`,
|
||||||
/>
|
})),
|
||||||
</div>
|
]}
|
||||||
<div className="flex w-full flex-col gap-3">
|
disabled={user.type === "agent"}
|
||||||
<label className="text-mti-gray-dim text-base font-normal">
|
value={getAssigneeValue()}
|
||||||
Assignee
|
onChange={(value) =>
|
||||||
</label>
|
value ? setAssigneeFilter(value.value === "me" ? user.id : value.value) : setAssigneeFilter(undefined)
|
||||||
<Select
|
}
|
||||||
options={[
|
placeholder="Assignee..."
|
||||||
{ value: "me", label: "Assigned to me" },
|
isClearable
|
||||||
...users
|
/>
|
||||||
.filter((x) =>
|
</div>
|
||||||
["admin", "developer", "agent"].includes(x.type)
|
<div className="flex w-full flex-col gap-3">
|
||||||
)
|
<label className="text-mti-gray-dim text-base font-normal">Source</label>
|
||||||
.map((u) => ({
|
<Select
|
||||||
value: u.id,
|
options={SOURCE_OPTIONS}
|
||||||
label: `${u.name} - ${u.email}`,
|
disabled={user.type === "agent"}
|
||||||
})),
|
value={SOURCE_OPTIONS.find((x) => x.value === sourceFilter)}
|
||||||
]}
|
onChange={(value) => setSourceFilter(value?.value as Source)}
|
||||||
disabled={user.type === "agent"}
|
/>
|
||||||
value={getAssigneeValue()}
|
</div>
|
||||||
onChange={(value) =>
|
</div>
|
||||||
value
|
|
||||||
? setAssigneeFilter(
|
|
||||||
value.value === "me" ? user.id : value.value
|
|
||||||
)
|
|
||||||
: setAssigneeFilter(undefined)
|
|
||||||
}
|
|
||||||
placeholder="Assignee..."
|
|
||||||
isClearable
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full flex-col gap-3">
|
|
||||||
<label className="text-mti-gray-dim text-base font-normal">
|
|
||||||
Source
|
|
||||||
</label>
|
|
||||||
<Select
|
|
||||||
options={SOURCE_OPTIONS}
|
|
||||||
disabled={user.type === "agent"}
|
|
||||||
value={SOURCE_OPTIONS.find((x) => x.value === sourceFilter)}
|
|
||||||
onChange={(value) => setSourceFilter(value?.value as Source)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table className="bg-mti-purple-ultralight/40 w-full rounded-xl">
|
<table className="bg-mti-purple-ultralight/40 w-full rounded-xl">
|
||||||
<thead>
|
<thead>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<tr key={headerGroup.id}>
|
<tr key={headerGroup.id}>
|
||||||
{headerGroup.headers.map((header) => (
|
{headerGroup.headers.map((header) => (
|
||||||
<th className="px-4 py-4 text-left" key={header.id}>
|
<th className="px-4 py-4 text-left" key={header.id}>
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
? null
|
</th>
|
||||||
: flexRender(
|
))}
|
||||||
header.column.columnDef.header,
|
</tr>
|
||||||
header.getContext()
|
))}
|
||||||
)}
|
</thead>
|
||||||
</th>
|
<tbody className="px-2">
|
||||||
))}
|
{table.getRowModel().rows.map((row) => (
|
||||||
</tr>
|
<tr
|
||||||
))}
|
className={clsx(
|
||||||
</thead>
|
"even:bg-mti-purple-ultralight/40 hover:bg-mti-purple-ultralight cursor-pointer rounded-lg py-2 odd:bg-white",
|
||||||
<tbody className="px-2">
|
"transition duration-300 ease-in-out",
|
||||||
{table.getRowModel().rows.map((row) => (
|
)}
|
||||||
<tr
|
onClick={() => setSelectedTicket(row.original)}
|
||||||
className={clsx(
|
key={row.id}>
|
||||||
"even:bg-mti-purple-ultralight/40 hover:bg-mti-purple-ultralight cursor-pointer rounded-lg py-2 odd:bg-white",
|
{row.getVisibleCells().map((cell) => (
|
||||||
"transition duration-300 ease-in-out"
|
<td className="w-fit items-center px-4 py-2" key={cell.id}>
|
||||||
)}
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
onClick={() => setSelectedTicket(row.original)}
|
</td>
|
||||||
key={row.id}
|
))}
|
||||||
>
|
</tr>
|
||||||
{row.getVisibleCells().map((cell) => (
|
))}
|
||||||
<td className="w-fit items-center px-4 py-2" key={cell.id}>
|
</tbody>
|
||||||
{flexRender(
|
</table>
|
||||||
cell.column.columnDef.cell,
|
</Layout>
|
||||||
cell.getContext()
|
)}
|
||||||
)}
|
</>
|
||||||
</td>
|
);
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</Layout>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user