diff --git a/apps/client/components/TicketDetails/index.tsx b/apps/client/components/TicketDetails/index.tsx
index 19406b717..b07f60d1c 100644
--- a/apps/client/components/TicketDetails/index.tsx
+++ b/apps/client/components/TicketDetails/index.tsx
@@ -1,26 +1,50 @@
-//@ts-nocheck
+// @ts-nocheck
+import {
+ Command,
+ CommandGroup,
+ CommandItem,
+ CommandList,
+} from "@/shadcn/ui/command";
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuSub,
+ ContextMenuSubContent,
+ ContextMenuSubTrigger,
+ ContextMenuTrigger,
+} from "@/shadcn/ui/context-menu";
+import { BlockNoteEditor, PartialBlock } from "@blocknote/core";
+import { BlockNoteView } from "@blocknote/mantine";
import { Switch } from "@headlessui/react";
import { CheckCircleIcon } from "@heroicons/react/20/solid";
-import moment from "moment";
-import { useRouter } from "next/router";
-import { useEffect, useRef, useState, useMemo } from "react";
-import { useQuery } from "react-query";
import { Text, Tooltip } from "@radix-ui/themes";
import { getCookie } from "cookies-next";
+import moment from "moment";
import useTranslation from "next-translate/useTranslation";
+import { useRouter } from "next/router";
+import { useEffect, useMemo, useRef, useState } from "react";
import Frame from "react-frame-component";
+import { useQuery } from "react-query";
import { useDebounce } from "use-debounce";
-import { BlockNoteEditor, PartialBlock } from "@blocknote/core";
-import { BlockNoteView } from "@blocknote/mantine";
-import { useUser } from "../../store/session";
-import { IconCombo, UserCombo } from "../Combo";
+import { toast } from "@/shadcn/hooks/use-toast";
+import { cn } from "@/shadcn/lib/utils";
import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/shadcn/ui/dropdown-menu";
+import {
+ CheckIcon,
CircleCheck,
CircleDotDashed,
Ellipsis,
Eye,
- EyeClosed,
EyeOff,
LifeBuoy,
Loader,
@@ -29,20 +53,11 @@ import {
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";
+import { useUser } from "../../store/session";
+import { IconCombo, UserCombo } from "../Combo";
const ticketStatusMap = [
{ id: 1, value: "needs_support", name: "Needs Support", icon: LifeBuoy },
@@ -396,6 +411,7 @@ export default function Ticket() {
// return undefined;
// }
try {
+ // @ts-ignore
return JSON.parse(storageString) as PartialBlock[];
} catch (e) {
return undefined;
@@ -441,6 +457,97 @@ export default function Ticket() {
setIssue(editor.document);
};
+ async function updateTicketStatus(e: any, ticket: any) {
+ await fetch(`/api/v1/ticket/status/update`, {
+ method: "PUT",
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ id: ticket.id, status: !ticket.isComplete }),
+ })
+ .then((res) => res.json())
+ .then(() => {
+ toast({
+ title: ticket.isComplete ? "Issue re-opened" : "Issue closed",
+ description: "The status of the issue has been updated.",
+ duration: 3000,
+ });
+ refetch();
+ });
+ }
+
+ // Add these new functions
+ async function updateTicketAssignee(ticketId: string, user: any) {
+ try {
+ const response = await fetch(`/api/v1/ticket/transfer`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ user: user ? user.id : undefined,
+ id: ticketId,
+ }),
+ });
+
+ if (!response.ok) throw new Error("Failed to update assignee");
+
+ toast({
+ title: "Assignee updated",
+ description: `Transferred issue successfully`,
+ duration: 3000,
+ });
+ refetch();
+ } catch (error) {
+ toast({
+ title: "Error",
+ description: "Failed to update assignee",
+ variant: "destructive",
+ duration: 3000,
+ });
+ }
+ }
+
+ async function updateTicketPriority(ticket: any, priority: string) {
+ try {
+ const response = await fetch(`/api/v1/ticket/update`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ id: ticket.id,
+ detail: ticket.detail,
+ note: ticket.note,
+ title: ticket.title,
+ priority: priority,
+ status: ticket.status,
+ }),
+ }).then((res) => res.json());
+
+ if (!response.success) throw new Error("Failed to update priority");
+
+ toast({
+ title: "Priority updated",
+ description: `Ticket priority set to ${priority}`,
+ duration: 3000,
+ });
+ refetch();
+ } catch (error) {
+ toast({
+ title: "Error",
+ description: "Failed to update priority",
+ variant: "destructive",
+ duration: 3000,
+ });
+ }
+ }
+
+ const priorities = ["low", "medium", "high"];
+
return (
{status === "loading" && (
@@ -457,482 +564,501 @@ export default function Ticket() {
)}
{status === "success" && (
-
-
-
-
-
-
-
-
- #{data.ticket.Number} -
-
- setTitle(e.target.value)}
- key={data.ticket.id}
- disabled={data.ticket.locked}
- />
-
-
-
- {data.ticket.client && (
-
-
- {data.ticket.client.name}
-
-
- )}
-
- {!data.ticket.isComplete ? (
-
-
- {t("open_issue")}
-
+
+
+
+
+
+
+
+
+
+
+ #{data.ticket.Number} -
+
+ setTitle(e.target.value)}
+ key={data.ticket.id}
+ disabled={data.ticket.locked}
+ />
+
+
+
+ {data.ticket.client && (
+
+
+ {data.ticket.client.name}
+
+
+ )}
+
+ {!data.ticket.isComplete ? (
+
+
+ {t("open_issue")}
+
+
+ ) : (
+
+
+ {t("closed_issue")}
+
+
+ )}
- ) : (
-
-
- {t("closed_issue")}
+
+
+ {data.ticket.type}
+ {data.ticket.hidden && (
+
+
+ Hidden
+
+
+ )}
+ {data.ticket.locked && (
+
+
+ Locked
+
+
+ )}
+
+ {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.type}
-
-
- {data.ticket.hidden && (
-
-
- Hidden
-
-
- )}
- {data.ticket.locked && (
-
-
- Locked
-
-
- )}
- {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
-
-
-
- )}
-
-
-