diff --git a/apps/api/src/controllers/ticket.ts b/apps/api/src/controllers/ticket.ts index 066ff7ed2..5494d3b57 100644 --- a/apps/api/src/controllers/ticket.ts +++ b/apps/api/src/controllers/ticket.ts @@ -14,6 +14,8 @@ export function ticketRoutes(fastify: FastifyInstance) { const { name, company, detail, title, priority, email, engineer }: any = request.body; + console.log(request.body); + const ticket: any = await prisma.ticket.create({ data: { name, @@ -24,7 +26,7 @@ export function ticketRoutes(fastify: FastifyInstance) { client: company !== undefined ? { - connect: { id: company.id }, + connect: { id: company.id || company }, } : undefined, fromImap: false, @@ -62,6 +64,7 @@ export function ticketRoutes(fastify: FastifyInstance) { reply.status(200).send({ message: "Ticket created correctly", success: true, + id: ticket.id, }); } ); diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 68fc431b6..4510242af 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -122,7 +122,7 @@ const start = async () => { client.capture({ event: "server_started", - distinctId: "api_server", + distinctId: "uuid", }); await client.shutdownAsync(); diff --git a/apps/client/pages/_app.tsx b/apps/client/pages/_app.tsx index b5451473c..cf6e3a1d5 100644 --- a/apps/client/pages/_app.tsx +++ b/apps/client/pages/_app.tsx @@ -26,6 +26,8 @@ const queryClient = new QueryClient(); function Auth({ children }: any) { const { loading, user } = useUser(); + const router = useRouter(); + React.useEffect(() => { if (loading) return; // Do nothing while loading }, [user, loading]); @@ -34,9 +36,6 @@ function Auth({ children }: any) { return children; } - // Session is being fetched, or no user. - // If no user, useEffect() will redirect. - return (
{/* */} @@ -148,6 +147,15 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: any) { ); } + if (router.pathname.includes("/portal")) { + return ( + <> + + + + ); + } + return ( diff --git a/apps/client/pages/admin/clients/index.tsx b/apps/client/pages/admin/clients/index.tsx index e2acfef51..b560f971f 100644 --- a/apps/client/pages/admin/clients/index.tsx +++ b/apps/client/pages/admin/clients/index.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { useRouter } from "next/router"; import React from "react"; import { useQuery } from "react-query"; import { @@ -207,6 +208,8 @@ export default function Clients() { fetchAllClients ); + const router = useRouter(); + async function deleteClient(id: any) { await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/v1/clients/${id}/delete-client`, @@ -247,11 +250,18 @@ export default function Clients() { */} + + Portal Url +
); }, diff --git a/apps/client/pages/new.tsx b/apps/client/pages/new.tsx index 81cba2753..54c3244ed 100644 --- a/apps/client/pages/new.tsx +++ b/apps/client/pages/new.tsx @@ -25,7 +25,6 @@ export default function CreateTicket() { const token = getCookie("session"); - const [open, setOpen] = useState(false); const [name, setName] = useState(""); const [company, setCompany] = useState(); const [engineer, setEngineer] = useState(); diff --git a/apps/client/pages/portal/[id]/ticket/[id].tsx b/apps/client/pages/portal/[id]/ticket/[id].tsx new file mode 100644 index 000000000..e69de29bb diff --git a/apps/client/pages/portal/[id]/ticket/new.tsx b/apps/client/pages/portal/[id]/ticket/new.tsx new file mode 100644 index 000000000..5bbe6033d --- /dev/null +++ b/apps/client/pages/portal/[id]/ticket/new.tsx @@ -0,0 +1,374 @@ +// Check if the ID matches the id of the company +// If true then show ticket creation htmlForm else show access denied htmlForm +// API post request to creating a ticket with relevant client info +// Default to unassigned engineer +// Send Email to customer with ticket creation +// Send Email to Engineers with ticket creation if email notifications are turned on + +import { Listbox, Transition } from "@headlessui/react"; +import { + CheckCircleIcon, + CheckIcon, + ChevronUpDownIcon, +} from "@heroicons/react/20/solid"; +import { notifications } from "@mantine/notifications"; +import { useRouter } from "next/router"; +import { Fragment, useState } from "react"; + +const type = [ + { id: 1, name: "Bug" }, + { id: 2, name: "Feature Request" }, + { id: 3, name: "Support" }, + { id: 4, name: "Billing" }, + { id: 5, name: "Hardware" }, + { id: 6, name: "Software" }, +]; + +const pri = [ + { id: 7, name: "Low" }, + { id: 8, name: "Medium" }, + { id: 9, name: "High" }, +]; + +export default function ClientTicketNew() { + function classNames(...classes) { + return classes.filter(Boolean).join(" "); + } + + const router = useRouter(); + const [isLoading, setIsLoading] = useState(false); + const [view, setView] = useState("success"); + const [ticketID, setTicketID] = useState(""); + + const [selected, setSelected] = useState(type[2]); + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [subject, setSubject] = useState(""); + const [description, setDescription] = useState(""); + const [priority, setPriority] = useState(pri[0]); + + async function submitTicket() { + setIsLoading(true); + await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/v1/ticket/create`, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + name, + title: subject, + company: router.query.id, + email, + detail: description, + priority: priority.name, + }), + }) + .then((res) => res.json()) + .then((res) => { + if (res.success === true) { + notifications.show({ + title: "Ticket Created", + message: "Ticket created succesfully", + color: "green", + autoClose: 5000, + }); + setView("success"); + setTicketID(res.id); + } else { + notifications.show({ + title: "Error", + message: `Please fill out all information and try again`, + color: "red", + autoClose: 5000, + }); + } + }); + setIsLoading(false); + } + + return ( +
+ {view === "new" ? ( +
+

Submit a Ticket

+ + Need help? Submit a ticket and our support team will get back to you + as soon as possible. + + +
+
+ +
+ setName(e.target.value)} + value={name} + autoComplete="off" + /> +
+
+
+ +
+ setEmail(e.target.value)} + value={email} + autoComplete="off" + /> +
+
+
+ +
+ setSubject(e.target.value)} + value={subject} + /> +
+
+ + + {({ open }) => ( + <> + + Issue Type + +
+ + {selected.name} + + + + + + + {type.map((person) => ( + + classNames( + active + ? "bg-gray-400 text-white" + : "text-gray-900", + "relative cursor-default select-none py-2 pl-3 pr-9" + ) + } + value={person} + > + {({ selected, active }) => ( + <> + + {person.name} + + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+ + )} +
+ + + {({ open }) => ( + <> + + Priority + +
+ + {priority.name} + + + + + + + {pri.map((person) => ( + + classNames( + active + ? "bg-gray-400 text-white" + : "text-gray-900", + "relative cursor-default select-none py-2 pl-3 pr-9" + ) + } + value={person} + > + {({ selected, active }) => ( + <> + + {person.name} + + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+ + )} +
+ +
+ +
+