diff --git a/apps/api/src/controllers/ticket.ts b/apps/api/src/controllers/ticket.ts index c6289b020..31fba5626 100644 --- a/apps/api/src/controllers/ticket.ts +++ b/apps/api/src/controllers/ticket.ts @@ -9,10 +9,11 @@ import { sendAssignedEmail } from "../lib/nodemailer/ticket/assigned"; import { sendComment } from "../lib/nodemailer/ticket/comment"; import { sendTicketCreate } from "../lib/nodemailer/ticket/create"; import { sendTicketStatus } from "../lib/nodemailer/ticket/status"; -import { checkSession } from "../lib/session"; -import { prisma } from "../prisma"; import { assignedNotification } from "../lib/notifications/issue/assigned"; import { commentNotification } from "../lib/notifications/issue/comment"; +import { sendWebhookNotification } from "../lib/notifications/webhook"; +import { checkSession } from "../lib/session"; +import { prisma } from "../prisma"; const validateEmail = (email: string) => { return String(email) @@ -97,33 +98,20 @@ export function ticketRoutes(fastify: FastifyInstance) { for (let i = 0; i < webhook.length; i++) { if (webhook[i].active === true) { - const url = webhook[i].url; - if (url.includes("discord.com")) { - const message = { - content: `Ticket ${ticket.id} created by ${ticket.name} -> ${ticket.email}. Priority -> ${ticket.priority}`, - avatar_url: - "https://avatars.githubusercontent.com/u/76014454?s=200&v=4", - username: "Peppermint.sh", - }; - axios - .post(url, message) - .then((response) => { - console.log("Message sent successfully!"); - console.log("Discord API response:", response.data); - }) - .catch((error) => { - console.error("Error sending message:", error); - }); - } else { - await axios.post(`${webhook[i].url}`, { - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - data: `Ticket ${ticket.id} created by ${ticket.name} -> ${ticket.email}. Priority -> ${ticket.priority}`, - }), - }); - } + const message = { + event: "ticket_created", + id: ticket.id, + title: ticket.title, + priority: ticket.priority, + email: ticket.email, + name: ticket.name, + type: ticket.type, + createdBy: ticket.createdBy, + assignedTo: ticket.assignedTo, + client: ticket.client, + }; + + await sendWebhookNotification(webhook[i], message); } } diff --git a/apps/api/src/lib/notifications/webhook.ts b/apps/api/src/lib/notifications/webhook.ts new file mode 100644 index 000000000..5a43ca298 --- /dev/null +++ b/apps/api/src/lib/notifications/webhook.ts @@ -0,0 +1,103 @@ +import axios from "axios"; + +function getPriorityColor(priority: string): number { + switch (priority.toLowerCase()) { + case "high": + return 16711680; // Red + case "medium": + return 16753920; // Orange + case "low": + return 65280; // Green + default: + return 8421504; // Grey + } +} + +export async function sendWebhookNotification(webhook: any, message: any) { + if (!webhook.active) return; + + const url = webhook.url; + + if (url.includes("discord.com")) { + const discordMessage = { + embeds: [ + { + title: "Issue Created", + description: "A new issue has been created", + color: getPriorityColor(message.priority), // Use the priority color function + footer: { + text: "Issue ID: " + message.id, + }, + author: { + name: "peppermint.sh", + icon_url: + "https://avatars.githubusercontent.com/u/76014454?s=200&v=4", + url: "https://peppermint.sh/", + }, + fields: [ + { + name: "Title", + value: message.title, + inline: false, + }, + { + name: "Priority Level", + value: message.priority, + inline: false, + }, + { + name: "Contact Email", + value: message.email ? message.email : "No email provided", + inline: false, + }, + { + name: "Created By", + value: message.createdBy.name, + inline: false, + }, + { + name: "Assigned To", + value: message.assignedTo + ? message.assignedTo.name + : "Unassigned", + inline: false, + }, + { + name: "Client", + value: message.client + ? message.client.name + : "No client assigned", + inline: false, + }, + { + name: "Type", + value: message.type, + inline: false, + }, + ], + }, + ], + content: "", + }; + + try { + await axios.post(url, discordMessage); + console.log("Discord webhook message sent successfully!"); + } catch (error: any) { + if (error.response) { + console.error("Discord API response error:", error.response.data); + } else { + console.error("Error sending Discord webhook:", error.message); + } + throw error; + } + } else { + try { + await axios.post(url, { + data: message, + }); + } catch (error) { + console.error("Error sending webhook:", error); + } + } +} diff --git a/apps/client/pages/issues/index.tsx b/apps/client/pages/issues/index.tsx index 177bc0751..713478529 100644 --- a/apps/client/pages/issues/index.tsx +++ b/apps/client/pages/issues/index.tsx @@ -1,37 +1,37 @@ import useTranslation from "next-translate/useTranslation"; import { useRouter } from "next/router"; +import { useEffect, useMemo, useState } from "react"; import Loader from "react-spinners/ClipLoader"; -import { useState, useMemo, useEffect } from "react"; +import { toast } from "@/shadcn/hooks/use-toast"; +import { cn } from "@/shadcn/lib/utils"; +import { Button } from "@/shadcn/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "@/shadcn/ui/command"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, - ContextMenuTrigger, ContextMenuSub, - ContextMenuSubTrigger, ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, } from "@/shadcn/ui/context-menu"; +import { Popover, PopoverContent, PopoverTrigger } from "@/shadcn/ui/popover"; import { getCookie } from "cookies-next"; +import { CheckIcon, Filter, X } from "lucide-react"; import moment from "moment"; import Link from "next/link"; import { useQuery } from "react-query"; import { useUser } from "../../store/session"; -import { Popover, PopoverContent, PopoverTrigger } from "@/shadcn/ui/popover"; -import { CheckIcon, Filter, X } from "lucide-react"; -import { Button } from "@/shadcn/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, -} from "@/shadcn/ui/command"; -import { cn } from "@/shadcn/lib/utils"; -import { toast } from "@/shadcn/hooks/use-toast"; async function getUserTickets(token: any) { const res = await fetch(`/api/v1/tickets/all`, { @@ -712,6 +712,8 @@ export default function Tickets() { "Content-Type": "application/json", }, body: JSON.stringify({ id: ticket.id }), + }).then(() => { + refetch(); }); } }} @@ -728,7 +730,7 @@ export default function Tickets() { type="button" className="relative block w-[400px] rounded-lg border-2 border-dashed border-gray-300 p-12 text-center hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" onClick={() => { - const event = new KeyboardEvent('keydown', { key: 'c' }); + const event = new KeyboardEvent("keydown", { key: "c" }); document.dispatchEvent(event); }} >