From 55d7368e72fd8eef4719d3b987c3415018733ee4 Mon Sep 17 00:00:00 2001 From: Jack Andrews Date: Wed, 6 Nov 2024 23:53:07 +0000 Subject: [PATCH] feat: issue actions --- apps/api/src/controllers/ticket.ts | 63 +++++-- .../20241106233134_lock/migration.sql | 2 + .../20241106234810_cascade/migration.sql | 5 + apps/api/src/prisma/schema.prisma | 3 +- .../client/components/TicketDetails/index.tsx | 167 ++++++++++++++++-- 5 files changed, 210 insertions(+), 30 deletions(-) create mode 100644 apps/api/src/prisma/migrations/20241106233134_lock/migration.sql create mode 100644 apps/api/src/prisma/migrations/20241106234810_cascade/migration.sql diff --git a/apps/api/src/controllers/ticket.ts b/apps/api/src/controllers/ticket.ts index 702b7f6b6..ebaa11ec7 100644 --- a/apps/api/src/controllers/ticket.ts +++ b/apps/api/src/controllers/ticket.ts @@ -638,16 +638,59 @@ export function ticketRoutes(fastify: FastifyInstance) { if (token) { const { hidden, id }: any = request.body; - await prisma.ticket - .update({ - where: { id: id }, - data: { - hidden: hidden, - }, - }) - .then(async (ticket) => { - // await sendTicketStatus(ticket); - }); + await prisma.ticket.update({ + where: { id: id }, + data: { + hidden: hidden, + }, + }); + + reply.send({ + success: true, + }); + } + } + ); + + // Lock a ticket + fastify.put( + "/api/v1/ticket/status/lock", + + async (request: FastifyRequest, reply: FastifyReply) => { + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { locked, id }: any = request.body; + + await prisma.ticket.update({ + where: { id: id }, + data: { + locked: locked, + }, + }); + + reply.send({ + success: true, + }); + } + } + ); + + // Delete a ticket + fastify.post( + "/api/v1/ticket/delete", + + async (request: FastifyRequest, reply: FastifyReply) => { + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { id }: any = request.body; + + await prisma.ticket.delete({ + where: { id: id }, + }); reply.send({ success: true, diff --git a/apps/api/src/prisma/migrations/20241106233134_lock/migration.sql b/apps/api/src/prisma/migrations/20241106233134_lock/migration.sql new file mode 100644 index 000000000..d9aaf2a9a --- /dev/null +++ b/apps/api/src/prisma/migrations/20241106233134_lock/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Ticket" ADD COLUMN "locked" BOOLEAN NOT NULL DEFAULT false; diff --git a/apps/api/src/prisma/migrations/20241106234810_cascade/migration.sql b/apps/api/src/prisma/migrations/20241106234810_cascade/migration.sql new file mode 100644 index 000000000..94b993642 --- /dev/null +++ b/apps/api/src/prisma/migrations/20241106234810_cascade/migration.sql @@ -0,0 +1,5 @@ +-- DropForeignKey +ALTER TABLE "Comment" DROP CONSTRAINT "Comment_ticketId_fkey"; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/api/src/prisma/schema.prisma b/apps/api/src/prisma/schema.prisma index 11aebb4b0..e0bf6757b 100644 --- a/apps/api/src/prisma/schema.prisma +++ b/apps/api/src/prisma/schema.prisma @@ -120,6 +120,7 @@ model Ticket { type TicketType @default(support) hidden Boolean @default(false) createdBy Json? + locked Boolean @default(false) TicketFile TicketFile[] Comment Comment[] @@ -164,7 +165,7 @@ model Comment { userId String? user User? @relation(fields: [userId], references: [id]) ticketId String - ticket Ticket @relation(fields: [ticketId], references: [id]) + ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade) } model Client { diff --git a/apps/client/components/TicketDetails/index.tsx b/apps/client/components/TicketDetails/index.tsx index 00470bdaf..2768d2679 100644 --- a/apps/client/components/TicketDetails/index.tsx +++ b/apps/client/components/TicketDetails/index.tsx @@ -18,14 +18,31 @@ import { IconCombo, UserCombo } from "../Combo"; import { CircleCheck, CircleDotDashed, + Ellipsis, + Eye, + EyeClosed, + EyeOff, LifeBuoy, Loader, LoaderCircle, + Lock, SignalHigh, SignalLow, SignalMedium, + Trash, + Trash2, + Unlock, } from "lucide-react"; import { toast } from "@/shadcn/hooks/use-toast"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/shadcn/ui/dropdown-menu"; +import { IconKeyboardHide } from "@tabler/icons-react"; const ticketStatusMap = [ { id: 1, value: "needs_support", name: "Needs Support", icon: LifeBuoy }, @@ -171,6 +188,46 @@ export default function Ticket() { .then(() => refetch()); } + async function lock(locked) { + await fetch(`/api/v1/ticket/status/lock`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + locked, + id, + }), + }) + .then((res) => res.json()) + .then(() => refetch()); + } + + async function deleteIssue(locked) { + await fetch(`/api/v1/ticket/delete`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + id, + }), + }) + .then((res) => res.json()) + .then((res) => { + if (res.success) { + toast({ + variant: "default", + title: "Issue Deleted", + description: "The issue has been deleted", + }); + router.push("/issues"); + } + }); + } + async function addComment() { await fetch(`/api/v1/ticket/comment`, { method: "POST", @@ -410,34 +467,106 @@ export default function Ticket() { key={data.ticket.id} /> -
-
- {!data.ticket.isComplete ? ( -
- - {t("open_issue")} +
+
+
+ {!data.ticket.isComplete ? ( +
+ + {t("open_issue")} + +
+ ) : ( +
+ + {t("closed_issue")} + +
+ )} +
+
+ + {data.ticket.type} + +
+ {data.ticket.hidden && ( +
+ + Hidden
- ) : ( -
- - {t("closed_issue")} + )} + {data.ticket.locked && ( +
+ + Locked
)}
-
- - {data.ticket.type} - -
- {data.ticket.client && ( -
+ {user.isAdmin && ( + + + + + + + Issue Actions + + + {data.ticket.hidden ? ( + hide(false)} + > + + Show Issue + + ) : ( + hide(true)} + > + + Hide Issue + + )} + {data.ticket.locked ? ( + lock(false)} + > + + Unlock Issue + + ) : ( + lock(true)} + > + + Lock Issue + + )} + + deleteIssue()} + > + + Delete Issue + + + + )} + {/*
{data.ticket.client.name} -
- )} +
*/}