diff --git a/app/[locale]/(protected)/supervisor/knowledge-base/page.tsx b/app/[locale]/(protected)/supervisor/knowledge-base/page.tsx index 35ca2fca..c2117352 100644 --- a/app/[locale]/(protected)/supervisor/knowledge-base/page.tsx +++ b/app/[locale]/(protected)/supervisor/knowledge-base/page.tsx @@ -1,4 +1,4 @@ -'use client' +"use client"; import { Accordion, @@ -6,16 +6,25 @@ import { AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; -import {Card, CardContent} from "@/components/ui/card"; -import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs"; +import { Card, CardContent } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import SiteBreadcrumb from "@/components/site-breadcrumb"; -import {getKnowledgeBaseCategoryList, getKnowledgeBaseList} from "@/service/master/knowledge-base"; +import { + deleteKnowledgeBase, + getKnowledgeBaseCategoryList, + getKnowledgeBaseList, +} from "@/service/master/knowledge-base"; import React from "react"; -import {Plus, Trash2} from "lucide-react"; -import {Button} from "@/components/ui/button"; +import { Plus, Trash, Trash2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; import CreateCategory from "./create-category"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; +import { deleteMedia } from "@/service/content/content"; +import { error } from "@/lib/swal"; const KnowledgeBase = () => { + const MySwal = withReactContent(Swal); const [categories, setCategories] = React.useState([]); const [questions, setQuestions] = React.useState([]); @@ -28,7 +37,7 @@ const KnowledgeBase = () => { const data = response?.data?.data; if (data) { setCategories(data); - fetchQuestions(data[0]?.id) + fetchQuestions(data[0]?.id); } } @@ -38,84 +47,135 @@ const KnowledgeBase = () => { if (data) { setQuestions(data); } + }; + + async function doDelete(id: any) { + // loading(); + const data = { + id, + }; + + const response = await deleteKnowledgeBase(id); + + if (response?.error) { + error(response.message); + return false; + } + success(); } + function success() { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + window.location.reload(); + } + }); + } + + const handleDeleteKnowlagde = (id: any) => { + MySwal.fire({ + title: "Hapus Data", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(id); + } + }); + }; + return ( -
- - -
- - - - - {categories?.map((category: any, index: number) => ( - { - fetchQuestions(category?.id); - }} - className="data-[state=active]:bg-secondary data-[state=active]:text-default rounded-md px-6 py-3 w-full justify-start" - > - {category?.name} -
deleteCategory(category?.id)} - > - +
+ + +
+ + + + + {categories?.map((category: any, index: number) => ( + { + fetchQuestions(category?.id); + }} + className="group data-[state=active]:bg-secondary data-[state=active]:text-default rounded-md px-6 py-3 w-full justify-between flex items-center" + > + {category?.name} +
deleteCategory(category?.id)} + > + +
+
+ ))} +
+
+
+
+ {categories?.map((cateogry: any, index: number) => ( + + + {questions?.map((question: any) => ( + + +
+ + handleDeleteKnowlagde(question.id)} + />
- +
+ + {question.answer} + +
))} - - - -
- {categories?.map((cateogry: any, index: number) => ( - - - {questions?.map((question: any) => ( - - - {question.question} - - - {question.answer} - - - )) - } - - {questions?.length > 0 && -
- - -
- } -
- ))} -
+
+ {questions?.length > 0 && ( +
+ + +
+ )} +
+ ))}
- -
+
+ +
); }; diff --git a/app/[locale]/(protected)/supervisor/ticketing/components/columns.tsx b/app/[locale]/(protected)/supervisor/ticketing/components/columns.tsx index bf2f21a7..da18fbeb 100644 --- a/app/[locale]/(protected)/supervisor/ticketing/components/columns.tsx +++ b/app/[locale]/(protected)/supervisor/ticketing/components/columns.tsx @@ -12,6 +12,11 @@ import { import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { formatDateToIndonesian } from "@/utils/globals"; +import { Link } from "@/i18n/routing"; +import { deleteTicket } from "@/service/communication/communication"; +import withReactContent from "sweetalert2-react-content"; +import { error } from "@/lib/swal"; +import Swal from "sweetalert2"; const columns: ColumnDef[] = [ { @@ -90,6 +95,46 @@ const columns: ColumnDef[] = [ header: "Actions", enableHiding: false, cell: ({ row }) => { + const MySwal = withReactContent(Swal); + + async function doDelete(id: any) { + const response = await deleteTicket(id); + + if (response?.error) { + error(response.message); + return false; + } + success(); + } + + function success() { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + window.location.reload(); + } + }); + } + + const handleDelete = (id: any) => { + MySwal.fire({ + title: "Hapus Data", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(id); + } + }); + }; return ( @@ -102,15 +147,22 @@ const columns: ColumnDef[] = [ - - - View - - - - Edit - - + + + + View + + + + + + Edit + + + handleDelete(row.original.id)} + className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none" + > Delete diff --git a/app/[locale]/(protected)/supervisor/ticketing/detail/[id]/page.tsx b/app/[locale]/(protected)/supervisor/ticketing/detail/[id]/page.tsx new file mode 100644 index 00000000..8564ff60 --- /dev/null +++ b/app/[locale]/(protected)/supervisor/ticketing/detail/[id]/page.tsx @@ -0,0 +1,19 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormTaskDetail from "@/components/form/task/task-detail-form"; +import FormDetailInternal from "@/components/form/communication/internal-detail-form"; +import FormDetailTicketing from "@/components/form/ticketing/ticketing-detail-form"; + +const TicketingDetailPage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default TicketingDetailPage; diff --git a/app/[locale]/(protected)/supervisor/ticketing/update/[id]/page.tsx b/app/[locale]/(protected)/supervisor/ticketing/update/[id]/page.tsx new file mode 100644 index 00000000..9a78c7f1 --- /dev/null +++ b/app/[locale]/(protected)/supervisor/ticketing/update/[id]/page.tsx @@ -0,0 +1,20 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormTaskDetail from "@/components/form/task/task-detail-form"; +import FormDetailInternal from "@/components/form/communication/internal-detail-form"; +import FormDetailTicketing from "@/components/form/ticketing/ticketing-detail-form"; +import FormUpdateTicketing from "@/components/form/ticketing/ticketing-update-form"; + +const TicketingUpdatePage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default TicketingUpdatePage; diff --git a/components/form/ticketing/ticketing-detail-form.tsx b/components/form/ticketing/ticketing-detail-form.tsx new file mode 100644 index 00000000..0b05730e --- /dev/null +++ b/components/form/ticketing/ticketing-detail-form.tsx @@ -0,0 +1,411 @@ +"use client"; +"use client"; +import React, { useEffect, useState } from "react"; +import { useForm, Controller } from "react-hook-form"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Card } from "@/components/ui/card"; +import { zodResolver } from "@hookform/resolvers/zod"; +import * as z from "zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { useParams } from "next/navigation"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; +import { + deleteTicket, + getTicketingDetail, + getTicketingInternalDetail, + getTicketingInternalDiscussion, + getTicketingReply, + saveTicketing, + saveTicketInternalReply, + saveTicketReply, +} from "@/service/communication/communication"; +import { Icon } from "@iconify/react/dist/iconify.js"; +import { list } from "postcss"; +import { htmlToString } from "@/utils/globals"; +import { Textarea } from "@/components/ui/textarea"; +import { error } from "@/lib/swal"; +import { useRouter } from "next/navigation"; + +const taskSchema = z.object({ + title: z.string().min(1, { message: "Judul diperlukan" }), + naration: z.string().min(2, { + message: "Narasi Penugasan harus lebih dari 2 karakter.", + }), +}); + +export type taskDetail = { + id: number; + title: string; + createdAt: string; + referenceNumber: string | number; + createdBy: { + id: number; + fullname: string; + }; + sendTo: { + id: number; + fullname: string; + }; + status: { + id: number; + name: string; + }; + priority: { + id: number; + name: string; + }; + broadcastType: string; + narration: string; + is_active: string; +}; + +export type replyDetail = { + id: number; + comments: string; + createdAt: string; + user: { + id: number; + fullname: string; + }; + messageTo: { + id: number; + fullname: string; + }; +}; +export type internalDetail = { + id: number; + message: string; + createdAt: string; + createdBy: { + id: number; + fullname: string; + }; + sendTo: { + id: number; + fullname: string; + }; +}; + +export default function FormDetailTicketing() { + const MySwal = withReactContent(Swal); + const { id } = useParams() as { id: string }; + const router = useRouter(); + + const [detail, setDetail] = useState(); + const [ticketReply, setTicketReply] = useState([]); + const [ticketInternal, setTicketInternal] = useState( + null + ); + const [replyVisible, setReplyVisible] = useState(false); + const [replyMessage, setReplyMessage] = useState(""); + const [selectedPriority, setSelectedPriority] = useState(""); + const [selectedStatus, setSelectedStatus] = useState(""); + + const { + control, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + useEffect(() => { + async function initState() { + if (id) { + const response = await getTicketingDetail(id); + setTicketInternal(response?.data?.data || null); + setDetail(response?.data?.data); + } + } + initState(); + getTicketReply(); + }, [id]); + + async function getTicketReply() { + const res = await getTicketingReply(id); + if (res?.data !== null) { + setTicketReply(res?.data?.data); + } + } + + const handleReply = () => { + setReplyVisible((prev) => !prev); // Toggle visibility + }; + + const handleSendReply = async () => { + if (replyMessage.trim() === "") { + MySwal.fire({ + title: "Error", + text: "Pesan tidak boleh kosong!", + icon: "error", + }); + return; + } + + const data = { + ticketId: id, + message: replyMessage, + }; + + try { + const response = await saveTicketReply(data); + + // Tambahkan balasan baru ke daftar balasan + const newReply: replyDetail = { + id: response?.data?.id, + comments: replyMessage, + createdAt: response?.data?.createdAt, + user: response?.data?.messageFrom, + messageTo: response?.data?.messageTo, + }; + + setTicketReply((prevReplies) => [newReply, ...prevReplies]); + + MySwal.fire({ + title: "Sukses", + text: "Pesan berhasil dikirim.", + icon: "success", + }); + + // Reset input dan sembunyikan form balasan + setReplyMessage(""); + setReplyVisible(false); + } catch (error) { + MySwal.fire({ + title: "Error", + text: "Gagal mengirim balasan.", + icon: "error", + }); + console.error("Error sending reply:", error); + } + }; + + async function doDelete(id: any) { + const response = await deleteTicket(id); + + if (response?.error) { + error(response.message); + return false; + } + success("/in/supervisor/ticketing"); + } + + function success(redirect: string) { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push(redirect); + }); + } + + const handleDelete = (id: any) => { + MySwal.fire({ + title: "Hapus Data", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(id); + } + }); + }; + + return ( +
+
+ + + {/* */} +
+ +
+
+ {replyVisible && ( +
+