From 882c77b96fdb50a37a4de646e045b1b8bec19ef2 Mon Sep 17 00:00:00 2001
From: Anang Yusman
Date: Tue, 3 Jun 2025 13:46:06 +0800
Subject: [PATCH 1/4] feat:update content-rewrite
---
.../rewrite/create/[id]/page.tsx | 180 +++++++++++++-----
.../content-management/rewrite/page.tsx | 2 +-
service/detail/detail.ts | 10 +-
service/landing/landing.ts | 8 +-
4 files changed, 148 insertions(+), 52 deletions(-)
diff --git a/app/[locale]/(public)/content-management/rewrite/create/[id]/page.tsx b/app/[locale]/(public)/content-management/rewrite/create/[id]/page.tsx
index a982672d..9900b1ba 100644
--- a/app/[locale]/(public)/content-management/rewrite/create/[id]/page.tsx
+++ b/app/[locale]/(public)/content-management/rewrite/create/[id]/page.tsx
@@ -8,12 +8,24 @@ import { useParams, useSearchParams } from "next/navigation";
import React, { useEffect, useState } from "react";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
-import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
import { Controller, useForm } from "react-hook-form";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import CustomEditor from "@/components/editor/custom-editor";
-import { generateDataArticle, getDetailArticle } from "@/service/content/ai";
+import {
+ generateDataArticle,
+ generateDataRewrite,
+ getDetailArticle,
+} from "@/service/content/ai";
import { Button } from "@/components/ui/button";
import { close, error, loading } from "@/config/swal";
import { saveContentRewrite } from "@/service/content/content";
@@ -29,8 +41,13 @@ import { useTranslations } from "next-intl";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
mainKeyword: z.string().min(1, { message: "Keyword diperlukan" }),
- seo: z.string().min(1, { message: "Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter" }),
- description: z.string().min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
+ seo: z.string().min(1, {
+ message:
+ "Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter",
+ }),
+ description: z
+ .string()
+ .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
// tags: z.string().min(1, { message: "Judul diperlukan" }),
});
@@ -73,8 +90,12 @@ const page = (props: any) => {
const validationSchema = Yup.object().shape({
title: Yup.string().required("Judul tidak boleh kosong"),
mainKeyword: Yup.string().required("Keyword tidak boleh kosong"),
- seo: Yup.string().required("Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter"),
- description: Yup.string().required("Narasi Penugasan harus lebih dari 2 karakter."),
+ seo: Yup.string().required(
+ "Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter"
+ ),
+ description: Yup.string().required(
+ "Narasi Penugasan harus lebih dari 2 karakter."
+ ),
});
let componentMounted = true;
@@ -152,7 +173,10 @@ const page = (props: any) => {
useEffect(() => {
async function initState() {
setLoadingState(true);
- const response = await getDetail(id, states == "polda" ? "polda" : "mabes");
+ const response = await getDetail(
+ id,
+ states == "polda" ? "polda" : "mabes"
+ );
console.log("Detail dataaaa ::", response);
if (response?.data?.data?.isActive == false) {
window.location.replace("/");
@@ -174,7 +198,10 @@ const page = (props: any) => {
setMain({
id: response?.data?.data?.files[0]?.id,
type: response?.data?.data?.fileType.name,
- url: Number(response?.data?.data?.fileType?.id) == 4 ? response?.data?.data?.files[0]?.secondaryUrl : response?.data?.data?.files[0]?.url,
+ url:
+ Number(response?.data?.data?.fileType?.id) == 4
+ ? response?.data?.data?.files[0]?.secondaryUrl
+ : response?.data?.data?.files[0]?.url,
thumbnailFileUrl: response?.data?.data?.files[0]?.thumbnailFileUrl,
names: response?.data?.data?.files[0]?.fileName,
format: response?.data?.data?.files[0]?.format,
@@ -208,25 +235,17 @@ const page = (props: any) => {
const handleGenerateArtikel = async () => {
loading();
const request = {
- advConfig: "",
- style: selectedWritingStyle,
- website: "None",
- connectToWeb: true,
- lang: selectedLanguage,
- pointOfView: "None",
- title: getValues("title"),
- imageSource: "Web",
- mainKeyword: getValues("mainKeyword"),
- additionalKeywords: getValues("seo"),
- targetCountry: null,
- articleSize: selectedSize,
- projectId: 2,
+ style: "friendly",
+ lang: "id",
+ contextType: "text",
+ urlContext: null,
+ context: content?.description,
createdBy: roleId,
- // clientId: "ngDLPPiorplznw2jTqVe3YFCz5xqKfUJ",
- clientId: "mediahubClientId",
+ sentiment: "Humorous",
+ clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
};
console.log("Request", request);
- const res = await generateDataArticle(request);
+ const res = await generateDataRewrite(request);
close();
if (res.error) {
@@ -272,7 +291,10 @@ const page = (props: any) => {
throw new Error("Timeout: Artikel belum selesai diproses.");
};
const articleData = await waitForStatusUpdate();
- const cleanArticleBody = articleData?.articleBody?.replace(/
]*>/g, "");
+ const cleanArticleBody = articleData?.articleBody?.replace(
+ /
]*>/g,
+ ""
+ );
console.log("lalalala", cleanArticleBody);
const articleImagesData = articleData?.imagesUrl?.split(",");
setValue("description", cleanArticleBody || "");
@@ -302,7 +324,10 @@ const page = (props: any) => {
{t("language")}
-
{t("contextType")}
-
+
@@ -325,8 +353,12 @@ const page = (props: any) => {
{t("selectContext")}
{t("text")}
- {t("article")}
- {t("transcript")}
+
+ {t("article")}
+
+
+ {t("transcript")}
+
URL
@@ -334,7 +366,10 @@ const page = (props: any) => {
{t("writingStyle")}
-
+
@@ -342,8 +377,12 @@ const page = (props: any) => {
{t("selectWriting")}
Friendly
- Profesional
- Informational
+
+ Profesional
+
+
+ Informational
+
Neutral
Witty
@@ -352,16 +391,25 @@ const page = (props: any) => {
@@ -381,7 +440,16 @@ const page = (props: any) => {
control={control}
name="mainKeyword"
render={({ field: { onChange, value } }) => (
-
+
)}
/>
@@ -391,12 +459,22 @@ const page = (props: any) => {
control={control}
name="seo"
render={({ field: { onChange, value } }) => (
-
+
)}
/>
-
+
Generate Artikel
{isGeneratedArticle && (
@@ -426,14 +504,25 @@ const page = (props: any) => {
render={({ field: { onChange, value } }) =>
isLoadingData ? (
-
Loading Proses Data...
+
+ Loading Proses Data...
+
) : (
-
+
)
}
/>
- {articleBody === null || articleBody === "" ?
Deskripsi tidak boleh kosong*
: ""}
+ {articleBody === null || articleBody === "" ? (
+
+ Deskripsi tidak boleh kosong*
+
+ ) : (
+ ""
+ )}
-
diff --git a/app/[locale]/(public)/content-management/rewrite/page.tsx b/app/[locale]/(public)/content-management/rewrite/page.tsx
index 6a1b1d9d..660d10a1 100644
--- a/app/[locale]/(public)/content-management/rewrite/page.tsx
+++ b/app/[locale]/(public)/content-management/rewrite/page.tsx
@@ -283,7 +283,7 @@ const page = () => {
diff --git a/service/detail/detail.ts b/service/detail/detail.ts
index 7d3db8e3..d23b1014 100644
--- a/service/detail/detail.ts
+++ b/service/detail/detail.ts
@@ -1,6 +1,10 @@
-import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor } from "../http-config/http-interceptor-service";
+import {
+ httpDeleteInterceptor,
+ httpGetInterceptor,
+ httpPostInterceptor,
+} from "../http-config/http-interceptor-service";
-export async function getDetail(id: any, state: any) {
- const url = `media/public?slug=${id}&state=${state}`;
+export async function getDetail(slug: any, state: any) {
+ const url = `media/public?slug=${slug}&state=${state}`;
return httpGetInterceptor(url);
}
diff --git a/service/landing/landing.ts b/service/landing/landing.ts
index ffdcc2d4..51876f78 100644
--- a/service/landing/landing.ts
+++ b/service/landing/landing.ts
@@ -228,10 +228,10 @@ export async function saveWishlist(data: { mediaUploadId: string }) {
export async function getPublicSuggestionList(slug: any) {
const url = `media/public/suggestion?mediaId=${slug}`;
- const headers = {
- "content-Type": "application/json",
- };
- return httpGet(url, headers);
+ // const headers = {
+ // "content-Type": "application/json",
+ // };
+ return httpGetInterceptor(url);
}
export async function getUserNotifications(page = 0, typeId: any) {
From 88501ac84ff26094b613483944cf5cf382577378 Mon Sep 17 00:00:00 2001
From: Anang Yusman
Date: Tue, 3 Jun 2025 23:13:51 +0800
Subject: [PATCH 2/4] feat:update calendar-polri
---
.../admin/settings/iklan/component/column.tsx | 20 +-
.../admin/settings/iklan/component/table.tsx | 11 +-
.../(protected)/admin/settings/iklan/page.tsx | 10 +-
.../component/calendar-polri-table.tsx | 14 +-
.../calendar-polri/component/columns.tsx | 121 +++--
.../schedule/calendar-polri/create/page.tsx | 3 +-
.../calendar-polri/detail/[id]/page.tsx | 3 +-
.../calendar-polri/update/[id]/page.tsx | 3 +-
components/form/content/spit-convert-form.tsx | 26 +-
.../schedule/form-calendar-polri-detail.tsx | 482 +++++++++++++++++
.../schedule/form-calendar-polri-update.tsx | 453 ++++++++++++++++
.../form/schedule/form-calendar-polri.tsx | 495 +++++++++++++++---
messages/en.json | 3 +-
messages/in.json | 3 +-
service/broadcast/broadcast.ts | 12 +
service/schedule/schedule.ts | 30 ++
16 files changed, 1527 insertions(+), 162 deletions(-)
create mode 100644 components/form/schedule/form-calendar-polri-detail.tsx
create mode 100644 components/form/schedule/form-calendar-polri-update.tsx
diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx
index 6ffd551f..c137ec06 100644
--- a/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx
+++ b/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx
@@ -45,18 +45,20 @@ const columns: ColumnDef[] = [
{
accessorKey: "title",
header: "Judul",
- cell: ({ row }) => {row.getValue("title")},
+ cell: ({ row }) => {row.getValue("title")}
,
},
{
- accessorKey: "categoryName",
- header: "Kategori",
- cell: ({ row }) => {row.getValue("categoryName")},
- },
- {
- accessorKey: "createdAt",
- header: "Tanggal Unggah",
+ accessorKey: "contentFileName",
+ header: "Judul Gambar",
cell: ({ row }) => (
- {formatDateToIndonesian(row.getValue("createdAt"))}
+ {row.getValue("contentFileName")}
+ ),
+ },
+ {
+ accessorKey: "placements",
+ header: "Posisi",
+ cell: ({ row }) => (
+ {row.getValue("placements")}
),
},
diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx
index e9d72d23..4fc2216c 100644
--- a/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx
+++ b/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx
@@ -61,14 +61,17 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
-import { listDataMedia } from "@/service/broadcast/broadcast";
+import {
+ listDataAdvertisements,
+ listDataMedia,
+} 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 { TambahIklanModal } from "@/components/form/setting/form-add-iklan";
-const IklanList = () => {
+const AdvertisementsList = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [showData, setShowData] = React.useState("10");
@@ -146,7 +149,7 @@ const IklanList = () => {
async function fetchData() {
try {
loading();
- const res = await listDataMedia(
+ const res = await listDataAdvertisements(
page - 1,
showData,
"",
@@ -395,4 +398,4 @@ const IklanList = () => {
);
};
-export default IklanList;
+export default AdvertisementsList;
diff --git a/app/[locale]/(protected)/admin/settings/iklan/page.tsx b/app/[locale]/(protected)/admin/settings/iklan/page.tsx
index 3571c256..a207465b 100644
--- a/app/[locale]/(protected)/admin/settings/iklan/page.tsx
+++ b/app/[locale]/(protected)/admin/settings/iklan/page.tsx
@@ -1,20 +1,16 @@
"use client";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { useState } from "react";
-import { Button } from "@/components/ui/button";
-import PopUpList from "../popup/component/table";
-import PopUpListTable from "../popup/component/popup-table";
-import IklanList from "./component/table";
-import IklanListTable from "./component/popup-table";
+import AdvertisementsList from "./component/table";
-export default function AdminIklan() {
+export default function AdminAdvertisements() {
const [selectedTab, setSelectedTab] = useState("content");
return (
);
diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx
index 3dc28244..bc7254ce 100644
--- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx
+++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx
@@ -43,7 +43,10 @@ import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
-import { paginationSchedule } from "@/service/schedule/schedule";
+import {
+ paginationCalendar,
+ paginationSchedule,
+} from "@/service/schedule/schedule";
import { CardHeader, CardTitle } from "@/components/ui/card";
import { Link } from "@/i18n/routing";
import { useTranslations } from "next-intl";
@@ -117,7 +120,7 @@ const CalendarPolriTable = () => {
async function fetchData() {
try {
- const res = await paginationSchedule(
+ const res = await paginationCalendar(
showData,
page - 1,
1,
@@ -162,7 +165,12 @@ const CalendarPolriTable = () => {
{t("calendar-polri")} {t("schedule")}
-
+
+
+
+ Buat Kalender Polri
+
+
diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx
index 1a3a3ae3..33471915 100644
--- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx
+++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx
@@ -13,6 +13,10 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Link } from "@/components/navigation";
import { useTranslations } from "next-intl";
+import withReactContent from "sweetalert2-react-content";
+import Swal from "sweetalert2";
+import { error } from "@/lib/swal";
+import { deleteCalendar } from "@/service/schedule/schedule";
const useTableColumns = () => {
const t = useTranslations("Table"); // Panggil di dalam hook
@@ -58,76 +62,33 @@ const useTableColumns = () => {
{row.getValue("endDate")}
),
},
+
{
- accessorKey: "time",
- header: t("time"),
- cell: ({ row }: { row: { original: any } }) => {
- console.log("Row Original Data:", row.original);
- const { startTime, endTime } = row.original;
- return (
-
- {startTime || "N/A"} - {endTime || "N/A"}
-
- );
- },
- },
- {
- accessorKey: "address",
- header: t("address"),
- cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
- const address: string = row.getValue("address");
- return (
-
- {address.length > 50 ? `${address.slice(0, 40)}...` : address}
-
- );
- },
- },
- {
- accessorKey: "statusName",
+ accessorKey: "isActive",
header: "Status",
cell: ({ row }) => {
- const statusColors: Record = {
- diterima: "bg-green-100 text-green-600",
- "menunggu review": "bg-orange-100 text-orange-600",
- };
+ const isActive = row.getValue("isActive") as boolean;
- // Mengambil `statusName` dari data API
- const status = row.getValue("statusName") as string;
- const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
-
- // Gunakan `statusName` untuk pencocokan
- const statusStyles =
- statusColors[statusName] || "bg-gray-100 text-gray-600";
+ const status = isActive ? "Aktif" : "Tidak Aktif";
+ const statusStyles = isActive
+ ? "bg-green-100 text-green-600"
+ : "bg-gray-100 text-gray-600";
return (
- {status} {/* Tetap tampilkan nilai asli */}
+ {status}
);
},
},
{
- accessorKey: "speaker",
- header: t("speaker"),
- cell: ({ row }: { row: { original: any } }) => {
- console.log("Row Original Data:", row.original);
- const { speakerTitle, speakerName } = row.original;
- return (
-
- {speakerTitle || ""} {speakerName || ""}
-
- );
- },
- },
- {
- accessorKey: "uploaderName",
+ accessorKey: "createdByName",
header: t("source"),
cell: ({ row }) => (
- {row.getValue("uploaderName")}
+ {row.getValue("createdByName")}
),
},
@@ -138,6 +99,51 @@ const useTableColumns = () => {
header: t("action"),
enableHiding: false,
cell: ({ row }) => {
+ const MySwal = withReactContent(Swal);
+
+ async function doDelete(id: any) {
+ // loading();
+ const data = {
+ id,
+ };
+
+ const response = await deleteCalendar(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 handleDeleteCalendars = (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 (
@@ -151,7 +157,7 @@ const useTableColumns = () => {
@@ -159,14 +165,17 @@ const useTableColumns = () => {
Edit
-
+ handleDeleteCalendars(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)/contributor/schedule/calendar-polri/create/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx
index 250cc651..1ac121ed 100644
--- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx
+++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx
@@ -2,13 +2,14 @@ import { Card, CardContent } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import FormTask from "@/components/form/task/task-form";
import FormPressConference from "@/components/form/schedule/press-conference-form";
+import { CalendarPolriAdd } from "@/components/form/schedule/form-calendar-polri";
const CalendarPolriCreatePage = () => {
return (
);
diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx
index f3347ffb..f9a614f9 100644
--- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx
+++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx
@@ -6,13 +6,14 @@ import FormPressConference from "@/components/form/schedule/press-conference-for
import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form";
import { useParams } from "next/navigation";
import { id } from "date-fns/locale";
+import { CalendarPolriAddDetail } from "@/components/form/schedule/form-calendar-polri-detail";
const CalendarPolriDetailPage = () => {
return (
);
diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx
index ce527b9a..dad6f5b1 100644
--- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx
+++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx
@@ -7,13 +7,14 @@ import FormDetailPressConference from "@/components/form/schedule/press-conferen
import { useParams } from "next/navigation";
import { id } from "date-fns/locale";
import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form";
+import { CalendarPolriAddUpdate } from "@/components/form/schedule/form-calendar-polri-update";
const CalendarPolriUpdatePage = () => {
return (
);
diff --git a/components/form/content/spit-convert-form.tsx b/components/form/content/spit-convert-form.tsx
index 6e1e00c1..0222f302 100644
--- a/components/form/content/spit-convert-form.tsx
+++ b/components/form/content/spit-convert-form.tsx
@@ -169,6 +169,8 @@ export default function FormConvertSPIT() {
const [filePlacements, setFilePlacements] = useState([]);
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
const [files, setFiles] = useState([]);
+ const [selectedWritingStyle, setSelectedWritingStyle] =
+ useState("profesional");
const options: Option[] = [
{ id: "all", label: "SEMUA" },
@@ -494,7 +496,7 @@ export default function FormConvertSPIT() {
const handleRewriteClick = async () => {
const request = {
- style: "friendly",
+ style: selectedWritingStyle,
lang: "id",
contextType: "text",
urlContext: null,
@@ -702,6 +704,28 @@ export default function FormConvertSPIT() {
)}
+
+
+
+
+
+
+
+ Friendly
+
+ Profesional
+
+
+ Informational
+
+ Neutral
+ Witty
+
+
+
;
+ const [eventDate, setEventDate] = React.useState(new Date());
+ const [listDest, setListDest] = React.useState([]);
+ const [checkedLevels, setCheckedLevels] = React.useState(new Set());
+ const [expandedPolda, setExpandedPolda] = React.useState([{}]);
+ const [isLoading, setIsLoading] = React.useState(false);
+ const [detail, setDetail] = React.useState();
+ const [date, setDate] = React.useState({
+ from: new Date(2025, 0, 1),
+ });
+ const [refresh, setRefresh] = React.useState(false);
+
+ const [unitSelection, setUnitSelection] = React.useState({
+ semua: false,
+ mabes: false,
+ polda: false,
+ satker: false,
+ internasional: false,
+ });
+
+ const {
+ control,
+ handleSubmit,
+ setValue,
+ formState: { errors },
+ } = useForm({
+ resolver: zodResolver(calendarSchema),
+ defaultValues: {
+ description: "",
+ },
+ });
+
+ React.useEffect(() => {
+ async function initState() {
+ if (id) {
+ const response = await detailCalendar(id);
+ const details = response?.data?.data;
+
+ setDetail(details);
+ if (details) {
+ setDate({
+ from: parseISO(details.startDate),
+ to: parseISO(details.endDate),
+ });
+ }
+ }
+ }
+ initState();
+ }, [refresh, setValue]);
+
+ React.useEffect(() => {
+ async function fetchPoldaPolres() {
+ setIsLoading(true);
+ try {
+ const response = await getUserLevelForAssignments();
+ setListDest(response?.data?.data.list);
+ console.log("polda", response?.data?.data?.list);
+ const initialExpandedState = response?.data?.data.list.reduce(
+ (acc: any, polda: any) => {
+ acc[polda.id] = false;
+ return acc;
+ },
+ {}
+ );
+ setExpandedPolda(initialExpandedState);
+ console.log("polres", initialExpandedState);
+ } catch (error) {
+ console.error("Error fetching Polda/Polres data:", error);
+ } finally {
+ setIsLoading(false);
+ }
+ }
+ fetchPoldaPolres();
+ }, []);
+
+ const handleCheckboxChange = (levelId: number) => {
+ setCheckedLevels((prev) => {
+ const updatedLevels = new Set(prev);
+ if (updatedLevels.has(levelId)) {
+ updatedLevels.delete(levelId);
+ } else {
+ updatedLevels.add(levelId);
+ }
+ return updatedLevels;
+ });
+ };
+
+ const handlePoldaPolresChange = () => {
+ return Array.from(checkedLevels).join(","); // Mengonversi Set ke string
+ };
+
+ const handleUnitChange = (
+ key: keyof typeof unitSelection,
+ value: boolean
+ ) => {
+ if (key === "semua") {
+ const newState = {
+ semua: value,
+ mabes: value,
+ polda: value,
+ satker: value,
+ internasional: value,
+ };
+ setUnitSelection(newState);
+ } else {
+ const updatedSelection = {
+ ...unitSelection,
+ [key]: value,
+ };
+
+ const allChecked = ["mabes", "polda", "satker", "internasional"].every(
+ (k) => updatedSelection[k as keyof typeof unitSelection]
+ );
+
+ updatedSelection.semua = allChecked;
+
+ setUnitSelection(updatedSelection);
+ }
+ };
+
+ const toggleExpand = (poldaId: any) => {
+ setExpandedPolda((prev: any) => ({
+ ...prev,
+ [poldaId]: !prev[poldaId],
+ }));
+ };
+
+ const save = async (data: CalendarSchema) => {
+ const unitMapping = {
+ allUnit: "0",
+ mabes: "1",
+ polda: "2",
+ satker: "4",
+ internasional: "5",
+ };
+ const assignmentToString = Object.keys(unitSelection)
+ .filter((key) => unitSelection[key as keyof typeof unitSelection])
+ .map((key) => unitMapping[key as keyof typeof unitMapping])
+ .join(",");
+ const requestData = {
+ title: data.title,
+ startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
+ endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
+ description: data.description,
+ assignedTo: assignmentToString,
+ assignedToLevel: handlePoldaPolresChange(),
+ };
+
+ console.log("Form Data Submitted:", requestData);
+
+ const response = await postCalendar(requestData);
+ if (response?.error) {
+ error(response?.message);
+ return false;
+ }
+
+ Cookies.set("scheduleId", response?.data?.data.id, {
+ expires: 1,
+ });
+
+ MySwal.fire({
+ title: "Sukses",
+ text: "Data berhasil disimpan.",
+ icon: "success",
+ confirmButtonColor: "#3085d6",
+ confirmButtonText: "OK",
+ }).then(() => {
+ router.reload();
+ });
+ };
+
+ const onSubmit = (data: CalendarSchema) => {
+ 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);
+ }
+ });
+ };
+
+ return (
+
+
+ {detail !== undefined ? (
+
+
+
Tanggal Acara
+
+
+
+
+
+ {date?.from ? (
+ date.to ? (
+ <>
+ {format(date.from, "LLL dd, y")} -{" "}
+ {format(date.to, "LLL dd, y")}
+ >
+ ) : (
+ format(date.from, "LLL dd, y")
+ )
+ ) : (
+ Pick a date
+ )}
+
+
+
+
+
+
+
+
+
+
Publish Area
+
+
+ {Object.keys(unitSelection).map((key) => (
+
+
+ handleUnitChange(
+ key as keyof typeof unitSelection,
+ value as boolean
+ )
+ }
+ />
+
+
+ ))}
+
+
+
+
+
+
+
+
+
Nama Acara
+
(
+
+ )}
+ />
+ {errors.title?.message && (
+ {errors.title.message}
+ )}
+
+
+
+
+
+ Drag your file(s) or{" "}
+
+ browse
+
+
+
Max 10 MB files are allowed
+
+
+
+
Deskripsi
+
(
+
+ )}
+ />
+ {errors.description?.message && (
+
+ {errors.description?.message}
+
+ )}
+
+
+ ) : (
+ ""
+ )}
+
+
+
+ Kembali
+
+
+
+
+
+ );
+}
diff --git a/components/form/schedule/form-calendar-polri-update.tsx b/components/form/schedule/form-calendar-polri-update.tsx
new file mode 100644
index 00000000..4ab0f21a
--- /dev/null
+++ b/components/form/schedule/form-calendar-polri-update.tsx
@@ -0,0 +1,453 @@
+// components/TambahIklanModal.tsx
+"use client";
+
+import * as React from "react";
+import {
+ Dialog,
+ DialogTrigger,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Button } from "@/components/ui/button";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { CalendarIcon, ChevronDown, ChevronUp, Plus } from "lucide-react";
+import { useTranslations } from "next-intl";
+import DatePicker from "react-datepicker";
+import { id } from "date-fns/locale";
+import "react-datepicker/dist/react-datepicker.css";
+import { zodResolver } from "@hookform/resolvers/zod";
+import router from "next/router";
+import { Controller, useForm } from "react-hook-form";
+import { date, z } from "zod";
+import { error } from "@/lib/swal";
+import { postCalendar } from "@/service/schedule/schedule";
+import { DateRange } from "react-day-picker";
+import Cookies from "js-cookie";
+import withReactContent from "sweetalert2-react-content";
+import Swal from "sweetalert2";
+import { Label } from "@/components/ui/label";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { Calendar } from "@/components/ui/calendar";
+import { format } from "date-fns";
+import { cn } from "@/lib/utils";
+import { getUserLevelForAssignments } from "@/service/task";
+import { Card } from "@/components/ui/card";
+
+const calendarSchema = z.object({
+ title: z.string().min(1, { message: "Judul diperlukan" }),
+ description: z.string().min(1, { message: "Judul diperlukan" }),
+});
+
+export function CalendarPolriAddUpdate() {
+ const MySwal = withReactContent(Swal);
+ const [open, setOpen] = React.useState(false);
+ const t = useTranslations("Schedule");
+ type CalendarSchema = z.infer;
+ const [eventDate, setEventDate] = React.useState(new Date());
+ const [listDest, setListDest] = React.useState([]);
+ const [checkedLevels, setCheckedLevels] = React.useState(new Set());
+ const [expandedPolda, setExpandedPolda] = React.useState([{}]);
+ const [isLoading, setIsLoading] = React.useState(false);
+ const [date, setDate] = React.useState({
+ from: new Date(2025, 0, 1),
+ });
+
+ const [unitSelection, setUnitSelection] = React.useState({
+ semua: false,
+ mabes: false,
+ polda: false,
+ satker: false,
+ internasional: false,
+ });
+
+ const {
+ control,
+ handleSubmit,
+ setValue,
+ formState: { errors },
+ } = useForm({
+ resolver: zodResolver(calendarSchema),
+ defaultValues: {
+ description: "",
+ },
+ });
+
+ React.useEffect(() => {
+ async function fetchPoldaPolres() {
+ setIsLoading(true);
+ try {
+ const response = await getUserLevelForAssignments();
+ setListDest(response?.data?.data.list);
+ console.log("polda", response?.data?.data?.list);
+ const initialExpandedState = response?.data?.data.list.reduce(
+ (acc: any, polda: any) => {
+ acc[polda.id] = false;
+ return acc;
+ },
+ {}
+ );
+ setExpandedPolda(initialExpandedState);
+ console.log("polres", initialExpandedState);
+ } catch (error) {
+ console.error("Error fetching Polda/Polres data:", error);
+ } finally {
+ setIsLoading(false);
+ }
+ }
+ fetchPoldaPolres();
+ }, []);
+
+ const handleCheckboxChange = (levelId: number) => {
+ setCheckedLevels((prev) => {
+ const updatedLevels = new Set(prev);
+ if (updatedLevels.has(levelId)) {
+ updatedLevels.delete(levelId);
+ } else {
+ updatedLevels.add(levelId);
+ }
+ return updatedLevels;
+ });
+ };
+
+ const handlePoldaPolresChange = () => {
+ return Array.from(checkedLevels).join(","); // Mengonversi Set ke string
+ };
+
+ const handleUnitChange = (
+ key: keyof typeof unitSelection,
+ value: boolean
+ ) => {
+ if (key === "semua") {
+ const newState = {
+ semua: value,
+ mabes: value,
+ polda: value,
+ satker: value,
+ internasional: value,
+ };
+ setUnitSelection(newState);
+ } else {
+ const updatedSelection = {
+ ...unitSelection,
+ [key]: value,
+ };
+
+ const allChecked = ["mabes", "polda", "satker", "internasional"].every(
+ (k) => updatedSelection[k as keyof typeof unitSelection]
+ );
+
+ updatedSelection.semua = allChecked;
+
+ setUnitSelection(updatedSelection);
+ }
+ };
+
+ const toggleExpand = (poldaId: any) => {
+ setExpandedPolda((prev: any) => ({
+ ...prev,
+ [poldaId]: !prev[poldaId],
+ }));
+ };
+
+ const save = async (data: CalendarSchema) => {
+ const unitMapping = {
+ allUnit: "0",
+ mabes: "1",
+ polda: "2",
+ satker: "4",
+ internasional: "5",
+ };
+ const assignmentToString = Object.keys(unitSelection)
+ .filter((key) => unitSelection[key as keyof typeof unitSelection])
+ .map((key) => unitMapping[key as keyof typeof unitMapping])
+ .join(",");
+ const requestData = {
+ title: data.title,
+ startDate: date?.from ? format(date.from, "yyyy-MM-dd") : null,
+ endDate: date?.to ? format(date.to, "yyyy-MM-dd") : null,
+ description: data.description,
+ assignedTo: assignmentToString,
+ assignedToLevel: handlePoldaPolresChange(),
+ };
+
+ console.log("Form Data Submitted:", requestData);
+
+ const response = await postCalendar(requestData);
+ if (response?.error) {
+ error(response?.message);
+ return false;
+ }
+
+ Cookies.set("scheduleId", response?.data?.data.id, {
+ expires: 1,
+ });
+
+ MySwal.fire({
+ title: "Sukses",
+ text: "Data berhasil disimpan.",
+ icon: "success",
+ confirmButtonColor: "#3085d6",
+ confirmButtonText: "OK",
+ }).then(() => {
+ router.reload();
+ });
+ };
+
+ const onSubmit = (data: CalendarSchema) => {
+ 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);
+ }
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/components/form/schedule/form-calendar-polri.tsx b/components/form/schedule/form-calendar-polri.tsx
index d9358fb5..0af5fee4 100644
--- a/components/form/schedule/form-calendar-polri.tsx
+++ b/components/form/schedule/form-calendar-polri.tsx
@@ -13,100 +13,441 @@ import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
-import { CalendarIcon, Plus } from "lucide-react";
+import { CalendarIcon, ChevronDown, ChevronUp, Plus } from "lucide-react";
import { useTranslations } from "next-intl";
import DatePicker from "react-datepicker";
import { id } from "date-fns/locale";
import "react-datepicker/dist/react-datepicker.css";
+import { zodResolver } from "@hookform/resolvers/zod";
+import router from "next/router";
+import { Controller, useForm } from "react-hook-form";
+import { date, z } from "zod";
+import { error } from "@/lib/swal";
+import { postCalendar } from "@/service/schedule/schedule";
+import { DateRange } from "react-day-picker";
+import Cookies from "js-cookie";
+import withReactContent from "sweetalert2-react-content";
+import Swal from "sweetalert2";
+import { Label } from "@/components/ui/label";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { Calendar } from "@/components/ui/calendar";
+import { format } from "date-fns";
+import { cn } from "@/lib/utils";
+import { getUserLevelForAssignments } from "@/service/task";
+import { Card } from "@/components/ui/card";
+
+const calendarSchema = z.object({
+ title: z.string().min(1, { message: "Judul diperlukan" }),
+ description: z.string().min(1, { message: "Judul diperlukan" }),
+});
export function CalendarPolriAdd() {
+ const MySwal = withReactContent(Swal);
const [open, setOpen] = React.useState(false);
const t = useTranslations("Schedule");
+ type CalendarSchema = z.infer;
const [eventDate, setEventDate] = React.useState(new Date());
- return (
-