From 7012e43ef9a7008156448f115a82c45c6a7114ef Mon Sep 17 00:00:00 2001 From: Sabda Yagra Date: Tue, 30 Sep 2025 12:49:54 +0700 Subject: [PATCH] fix: admin page section --- .../admin/add-experts/component/table.tsx | 4 +- .../admin/broadcast/email/component/table.tsx | 10 +- .../broadcast/whatsapp/component/table.tsx | 11 +- .../(admin)/admin/management-user/page.tsx | 2 +- .../results/component/table.tsx | 2 +- .../tracking-berita/component/table.tsx | 2 +- .../(admin)/admin/survey/component/table.tsx | 4 +- .../broadcast/content-blast--detail-form.tsx | 107 ++++++ .../form/broadcast/content-blast-form.tsx | 318 ++++++++++++++++++ .../visualization/content-production.tsx | 2 +- .../visualization/management-user-viz.tsx | 2 +- .../visualization/pattern-relation-viz.tsx | 2 +- 12 files changed, 437 insertions(+), 29 deletions(-) create mode 100644 components/form/broadcast/content-blast--detail-form.tsx create mode 100644 components/form/broadcast/content-blast-form.tsx diff --git a/app/[locale]/(admin)/admin/add-experts/component/table.tsx b/app/[locale]/(admin)/admin/add-experts/component/table.tsx index 62de2f1..463ab89 100644 --- a/app/[locale]/(admin)/admin/add-experts/component/table.tsx +++ b/app/[locale]/(admin)/admin/add-experts/component/table.tsx @@ -188,7 +188,7 @@ const AddExpertTable = () => { } return ( -
+

Tenaga Ahli

@@ -239,7 +239,7 @@ const AddExpertTable = () => { {table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => ( {header.isPlaceholder diff --git a/app/[locale]/(admin)/admin/broadcast/email/component/table.tsx b/app/[locale]/(admin)/admin/broadcast/email/component/table.tsx index 730cae1..330d388 100644 --- a/app/[locale]/(admin)/admin/broadcast/email/component/table.tsx +++ b/app/[locale]/(admin)/admin/broadcast/email/component/table.tsx @@ -47,27 +47,19 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; -import { InputGroup, InputGroupText } from "@/components/ui/input-group"; -import { paginationBlog } from "@/service/blog/blog"; -import { ticketingPagination } from "@/service/ticketing/ticketing"; -import { Badge } from "@/components/ui/badge"; import { useRouter, useSearchParams } from "next/navigation"; import TablePagination from "@/components/table/table-pagination"; import columns from "./column"; -import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import { - listDataMedia, - listDataMediaBroadCast, -} from "@/service/broadcast/broadcast"; import { listEnableCategory } from "@/service/content/content"; import { Checkbox } from "@/components/ui/checkbox"; import { close, loading } from "@/config/swal"; import { Link } from "@/i18n/routing"; +import { listDataMediaBroadCast } from "@/service/service/broadcast/broadcast"; const BroadcastEmailTable = () => { const router = useRouter(); diff --git a/app/[locale]/(admin)/admin/broadcast/whatsapp/component/table.tsx b/app/[locale]/(admin)/admin/broadcast/whatsapp/component/table.tsx index 0c6b79a..1949a5b 100644 --- a/app/[locale]/(admin)/admin/broadcast/whatsapp/component/table.tsx +++ b/app/[locale]/(admin)/admin/broadcast/whatsapp/component/table.tsx @@ -37,7 +37,6 @@ import { TrendingUp, UserIcon, } from "lucide-react"; -import { cn } from "@/lib/utils"; import { DropdownMenu, DropdownMenuContent, @@ -47,27 +46,19 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; -import { InputGroup, InputGroupText } from "@/components/ui/input-group"; -import { paginationBlog } from "@/service/blog/blog"; -import { ticketingPagination } from "@/service/ticketing/ticketing"; -import { Badge } from "@/components/ui/badge"; import { useRouter, useSearchParams } from "next/navigation"; import TablePagination from "@/components/table/table-pagination"; import columns from "./column"; -import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import { - listDataMedia, - listDataMediaBroadCast, -} from "@/service/broadcast/broadcast"; import { listEnableCategory } from "@/service/content/content"; import { Checkbox } from "@/components/ui/checkbox"; import { close, loading } from "@/config/swal"; import { Link } from "@/i18n/routing"; +import { listDataMediaBroadCast } from "@/service/service/broadcast/broadcast"; const BroadcastWhatsAppTable = () => { const router = useRouter(); diff --git a/app/[locale]/(admin)/admin/management-user/page.tsx b/app/[locale]/(admin)/admin/management-user/page.tsx index 1a09b26..a266d5d 100644 --- a/app/[locale]/(admin)/admin/management-user/page.tsx +++ b/app/[locale]/(admin)/admin/management-user/page.tsx @@ -36,7 +36,7 @@ export default function ManagementUser() { -
+

Data User {isInternal ? "Internal" : "Eksternal"} diff --git a/app/[locale]/(admin)/admin/media-tracking/results/component/table.tsx b/app/[locale]/(admin)/admin/media-tracking/results/component/table.tsx index 739cd27..54bc6d1 100644 --- a/app/[locale]/(admin)/admin/media-tracking/results/component/table.tsx +++ b/app/[locale]/(admin)/admin/media-tracking/results/component/table.tsx @@ -236,7 +236,7 @@ const ResultTable = () => { }; return ( -

+
diff --git a/app/[locale]/(admin)/admin/media-tracking/tracking-berita/component/table.tsx b/app/[locale]/(admin)/admin/media-tracking/tracking-berita/component/table.tsx index f64abe5..697db53 100644 --- a/app/[locale]/(admin)/admin/media-tracking/tracking-berita/component/table.tsx +++ b/app/[locale]/(admin)/admin/media-tracking/tracking-berita/component/table.tsx @@ -135,7 +135,7 @@ export default function TrackingBeritaCard() { }; return ( - +
{
-
+
{table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => ( {header.isPlaceholder diff --git a/components/form/broadcast/content-blast--detail-form.tsx b/components/form/broadcast/content-blast--detail-form.tsx new file mode 100644 index 0000000..14d8efc --- /dev/null +++ b/components/form/broadcast/content-blast--detail-form.tsx @@ -0,0 +1,107 @@ +"use client"; + +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { useParams } from "next/navigation"; +import { loading, close } from "@/config/swal"; +import { getMediaBlastBroadCast } from "@/service/service/broadcast/broadcast"; + +interface BroadcastDetail { + id: number; + body: string; + subject: string; + sendTime: string; + thumbnail: string; + contentUrl: string; +} + +export default function DetailContentBlast() { + const params = useParams(); + const { id } = params as { id: string }; + + const [detail, setDetail] = useState(null); + const [notFound, setNotFound] = useState(false); + + useEffect(() => { + fetchDetailData(); + }, [id]); + + async function fetchDetailData() { + loading(); + try { + const res = await getMediaBlastBroadCast(id); + close(); + + const detailData = res?.data?.data; + let updatedUrl = detailData.contentUrl; + + const domainsToUpdate = ["mediahub.polri.go.id", "netidhub.com"]; + + domainsToUpdate.forEach((domain) => { + if ( + updatedUrl.includes(domain) && + !updatedUrl.includes(`${domain}/in`) + ) { + updatedUrl = updatedUrl.replace(domain, `${domain}/in`); + } + }); + if (detailData && detailData.id === Number(id)) { + setDetail({ + id: detailData.id, + body: detailData.body, + subject: detailData.subject, + sendTime: detailData.sendTime, + thumbnail: detailData.thumbnail, + contentUrl: updatedUrl, + }); + } else { + setNotFound(true); + } + } catch (error) { + close(); + console.error("Failed to fetch broadcast detail:", error); + setNotFound(true); + } + } + + if (notFound) { + return
Data tidak ditemukan.
; + } + + if (!detail) { + return
Loading preview...
; + } + + return ( +
+

Preview

+
+
+ +
+ +
{detail.subject}
+

+ Selengkapnya silakan cek di sini:{" "} + + {detail.contentUrl} + +

+
+ {detail.sendTime} +
+
+
+ ); +} diff --git a/components/form/broadcast/content-blast-form.tsx b/components/form/broadcast/content-blast-form.tsx new file mode 100644 index 0000000..42d1ff4 --- /dev/null +++ b/components/form/broadcast/content-blast-form.tsx @@ -0,0 +1,318 @@ +"use client"; +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; + +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { + getLocaleTime, + getLocaleTimestamp, + textEllipsis, +} from "@/utils/globals"; +import { Link, useRouter } from "@/i18n/routing"; +import { useEffect, useRef, useState } from "react"; +import { useParams } from "next/navigation"; +import Select from "react-select"; +import makeAnimated from "react-select/animated"; +import { Textarea } from "@/components/ui/textarea"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import dynamic from "next/dynamic"; +import { detailMediaSummary, getMediaBlastCampaignList, saveMediaBlastBroadcast } from "@/service/service/broadcast/broadcast"; + +const CustomEditor = dynamic( + () => { + return import("@/components/editor/custom-editor"); + }, + { ssr: false } +); + +const animatedComponent = makeAnimated(); + +const FormSchema = z.object({ + title: z.string({ + required_error: "Required", + }), + url: z.string({ + required_error: "Required", + }), + thumbnail: z.string({ + required_error: "Required", + }), + detail: z.string({ + required_error: "Required", + }), + selected: z + .array( + z.object({ + id: z.number(), + label: z.string(), + value: z.string(), + }) + ) + .refine((value) => value.length > 0, { + message: "Required", + }), +}); + +interface Campaign { + id: string; + name: string; +} + +export default function ContentBlast(props: { type: string }) { + const editor = useRef(null); + const id = useParams()?.id; + const MySwal = withReactContent(Swal); + const router = useRouter(); + const { type } = props; + + const [dataSelectCampaign, setDataSelectCampaign] = useState([]); + const [openModal, setOpenModal] = useState(false); + + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { selected: [], detail: "" }, + }); + + const onSubmit = async (data: z.infer) => { + if (form.getValues("detail") == "") { + form.setError("detail", { + type: "manual", + message: "Required", + }); + } else { + MySwal.fire({ + title: "Simpan Data", + text: "Apakah Anda yakin ingin menyimpan data ini?", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Simpan", + }).then((result) => { + if (result.isConfirmed) { + save(data); + } + }); + } + }; + + const save = async (data: z.infer) => { + const selectedCampaign = form.getValues("selected"); + + for (let i = 0; i < selectedCampaign.length; i++) { + const reqData = { + mediaUploadId: id, + mediaBlastCampaignId: selectedCampaign[i].id, + subject: type == "wa" ? `*${data.title}*` : data.title, + body: data.detail?.replace(/\n/g, ""), + type: type, + isScheduled: false, + thumbnail: data?.thumbnail, + sendDate: getLocaleTimestamp(new Date()), + sendTime: getLocaleTime(new Date()), + contentUrl: data.url, + }; + + console.log("req =>", reqData); + const response = await saveMediaBlastBroadcast(reqData); + } + setOpenModal(true); + }; + + useEffect(() => { + async function initState() { + const response = await detailMediaSummary(String(id)); + const details = response?.data?.data; + let pageUrl = details?.pageUrl || ""; + if (pageUrl.includes("mediahub.polri.go.id")) { + pageUrl = pageUrl.replace( + /(\.id)(\/|$)/, + (match: any, p1: any, p2: any) => { + return p2.startsWith("/in") ? match : `${p1}/in${p2}`; + } + ); + } + if (details != undefined) { + form.setValue("thumbnail", details.smallThumbnailLink); + let body = `

Berita hari ini !!!

+
+
+ +
+ ${pageUrl} +

${details?.title}

+

+ ${textEllipsis(details?.description, 150)} +

+
+
`; + form.setValue("title", `${details?.title}`); + form.setValue( + "url", + details?.pageUrl || "https://mediahub.polri.go.id" + ); + if (type == "wa") { + body = `${textEllipsis(details?.description, 150)}`; + form.setValue("detail", body); + } else { + form.setValue("detail", body); + } + } + } + + async function getCampaign() { + const response = await getMediaBlastCampaignList(); + const campaign = response?.data?.data?.content; + handleLabelCampaign(campaign); + console.log(campaign); + } + + initState(); + getCampaign(); + }, [id]); + + function handleLabelCampaign(data: any) { + const optionArr: any = []; + + data.map((option: any) => { + optionArr.push({ + id: option.id, + label: option.title, + value: option.title, + }); + }); + console.log("option arr", optionArr); + setDataSelectCampaign(optionArr); + } + + return ( +
+ +

Broadcast

+ ( + + Subject + + + + + )} + /> + ( + + Detail Perencanaan + {type === "wa" ? ( +