@@ -426,7 +575,7 @@ export function CalendarPolriAdd() {
rows={3}
value={field.value}
onChange={field.onChange}
- placeholder="Masukan lokasi"
+ placeholder="Masukan Description"
/>
)}
/>
diff --git a/components/form/setting/form-add-iklan-detail.tsx b/components/form/setting/form-add-iklan-detail.tsx
new file mode 100644
index 00000000..8430568a
--- /dev/null
+++ b/components/form/setting/form-add-iklan-detail.tsx
@@ -0,0 +1,108 @@
+// 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 { Plus } from "lucide-react";
+
+export function TambahIklanModalDetail() {
+ const [open, setOpen] = React.useState(false);
+
+ return (
+
+ );
+}
diff --git a/components/form/setting/form-add-iklan-update.tsx b/components/form/setting/form-add-iklan-update.tsx
new file mode 100644
index 00000000..ae1c5012
--- /dev/null
+++ b/components/form/setting/form-add-iklan-update.tsx
@@ -0,0 +1,108 @@
+// 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 { Plus } from "lucide-react";
+
+export function TambahIklanModalUpdate() {
+ const [open, setOpen] = React.useState(false);
+
+ return (
+
+ );
+}
diff --git a/components/form/setting/form-add-iklan.tsx b/components/form/setting/form-add-iklan.tsx
index 2f702060..bcbb37ee 100644
--- a/components/form/setting/form-add-iklan.tsx
+++ b/components/form/setting/form-add-iklan.tsx
@@ -13,96 +13,558 @@ 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 { Plus } from "lucide-react";
+import { ChevronDown, ChevronUp, Plus } from "lucide-react";
+import { Card } from "@/components/ui/card";
+import Image from "next/image";
+import { Upload } from "tus-js-client";
+import { getCsrfToken } from "@/service/auth";
+import { error, loading } from "@/lib/swal";
+import { format } from "date-fns";
+import { getUserLevelForAssignments } from "@/service/task";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { Controller, useForm } from "react-hook-form";
+import withReactContent from "sweetalert2-react-content";
+import { useTranslations } from "next-intl";
+import Swal from "sweetalert2";
+import { z } from "zod";
+import { DateRange } from "react-day-picker";
+import { postCalendar } from "@/service/schedule/schedule";
+import { id } from "date-fns/locale";
+import router from "next/router";
+import { postAdvertisements } from "@/service/settings/settings";
+import Cookies from "js-cookie";
+import { Label } from "@/components/ui/label";
+import FileUploader from "../shared/file-uploader";
+import { Icon } from "@/components/ui/icon";
+
+const calendarSchema = z.object({
+ title: z.string().min(1, { message: "Judul diperlukan" }),
+ description: z.string().min(1, { message: "Judul diperlukan" }),
+});
+
+interface FileWithPreview extends File {
+ preview: string;
+}
+
+interface FileUploaded {
+ id: number;
+ url: string;
+}
export function TambahIklanModal() {
const [open, setOpen] = React.useState(false);
+ const MySwal = withReactContent(Swal);
+ 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 [isImageUploadFinish, setIsImageUploadFinish] = React.useState(false);
+ const [files, setFiles] = React.useState([]);
+ const [selectedPlacement, setSelectedPlacement] = React.useState("");
+ const [imageUploadedFiles, setImageUploadedFiles] = React.useState<
+ FileUploaded[]
+ >([]);
+ const [imageFiles, setImageFiles] = React.useState([]);
+ 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: "",
+ },
+ });
+
+ const handlePlacementSelect = (value: string) => {
+ setSelectedPlacement(value);
+ };
+
+ 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,
+ placements: selectedPlacement,
+ description: data.description,
+ redirectLink: "https://new.netidhub.com",
+ createdBy: assignmentToString,
+ assignedToLevel: handlePoldaPolresChange(),
+ };
+
+ console.log("Form Data Submitted:", requestData);
+
+ const response = await postAdvertisements(requestData);
+ if (response?.error) {
+ error(response?.message);
+ return false;
+ }
+
+ Cookies.set("scheduleId", response?.data?.data.id, {
+ expires: 1,
+ });
+
+ loading();
+ if (imageFiles?.length === 0) {
+ setIsImageUploadFinish(true);
+ }
+ imageFiles?.map(async (item: any, index: number) => {
+ await uploadResumableFile(index, String(id), item, "1", "0");
+ });
+ };
+
+ async function uploadResumableFile(
+ idx: number,
+ id: string,
+ file: any,
+ fileTypeId: string,
+ duration: string
+ ) {
+ console.log(idx, id, file, fileTypeId, duration);
+
+ const resCsrf = await getCsrfToken();
+ const csrfToken = resCsrf?.data?.token;
+ console.log("CSRF TOKEN : ", csrfToken);
+ const headers = {
+ "X-XSRF-TOKEN": csrfToken,
+ };
+
+ const upload = new Upload(file, {
+ endpoint: `${process.env.NEXT_PUBLIC_API}/advertisment/file/upload`,
+ headers: headers,
+ retryDelays: [0, 3000, 6000, 12_000, 24_000],
+ chunkSize: 20_000,
+ metadata: {
+ advertisementsId: id,
+ filename: file.name,
+ contentType: file.type,
+ fileTypeId: fileTypeId,
+ duration,
+ },
+ onBeforeRequest: function (req) {
+ var xhr = req.getUnderlyingObject();
+ xhr.withCredentials = true;
+ },
+ onError: async (e: any) => {
+ console.log("Error upload :", e);
+ error(e);
+ },
+ onChunkComplete: (
+ chunkSize: any,
+ bytesAccepted: any,
+ bytesTotal: any
+ ) => {
+ // const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100);
+ // progressInfo[idx].percentage = uploadPersen;
+ // counterUpdateProgress++;
+ // console.log(counterUpdateProgress);
+ // setProgressList(progressInfo);
+ // setCounterProgress(counterUpdateProgress);
+ },
+ onSuccess: async () => {
+ // uploadPersen = 100;
+ // progressInfo[idx].percentage = 100;
+ // counterUpdateProgress++;
+ // setCounterProgress(counterUpdateProgress);
+ successTodo();
+ if (fileTypeId == "1") {
+ setIsImageUploadFinish(true);
+ }
+ },
+ });
+
+ upload.start();
+ }
+
+ React.useEffect(() => {
+ successTodo();
+ }, [isImageUploadFinish]);
+
+ function successTodo() {
+ if (isImageUploadFinish) {
+ successSubmit("/in/admin/settings/iklan");
+ }
+ }
+
+ const successSubmit = (redirect: string) => {
+ MySwal.fire({
+ title: "Sukses",
+ text: "Data berhasil disimpan.",
+ icon: "success",
+ confirmButtonColor: "#3085d6",
+ confirmButtonText: "OK",
+ }).then(() => {
+ router.push(redirect);
+ });
+ };
+
+ 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);
+ }
+ });
+ };
+
+ const renderFilePreview = (url: string) => {
+ return (
+
+ );
+ };
+
+ const handleRemoveFile = (id: number) => {};
return (
-