From 47d24e8a29a857ff01a212cc6006a698b7eaadfe Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Thu, 12 Dec 2024 20:04:27 +0700 Subject: [PATCH 01/18] feat:create schedule,create agenda setting, curated-content,communication --- .../agenda-setting/calender-view.tsx | 6 +- .../agenda-setting/event-modal.tsx | 95 +++-- .../(protected)/agenda-setting/page.tsx | 4 +- .../contest/components/columns.tsx | 130 +++++++ .../contest/components/contest-table.tsx | 208 +++++++++++ app/[locale]/(protected)/contest/page.tsx | 28 +- .../contest/table-contest/contest-table.tsx | 347 ------------------ .../(protected)/contest/table-contest/data.ts | 74 ---- .../giat-penugasan/audio-visual.tsx | 78 ++++ .../curated-content/giat-penugasan/audio.tsx | 89 +++++ .../curated-content/giat-penugasan/image.tsx | 79 ++++ .../curated-content/giat-penugasan/teks.tsx | 103 ++++++ .../giat-routine/audio-visual.tsx | 78 ++++ .../curated-content/giat-routine/audio.tsx | 89 +++++ .../curated-content/giat-routine/image.tsx | 79 ++++ .../curated-content/giat-routine/teks.tsx | 103 ++++++ .../(protected)/curated-content/page.tsx | 86 +++-- .../press-conference/components/columns.tsx | 21 +- .../press-conference/detail/[id]/page.tsx | 23 ++ components/form/schedule/event-form.tsx | 64 ++-- .../form/schedule/pers-release-form.tsx | 64 ++-- .../schedule/press-conference-detail-form.tsx | 341 +++++++++++++++++ .../form/schedule/press-conference-form.tsx | 62 ++-- components/ui/carousel.tsx | 148 ++++---- service/agenda-setting/agenda-setting.ts | 16 + service/contest/contest.ts | 8 +- service/schedule/schedule.ts | 11 + 27 files changed, 1789 insertions(+), 645 deletions(-) create mode 100644 app/[locale]/(protected)/contest/components/columns.tsx create mode 100644 app/[locale]/(protected)/contest/components/contest-table.tsx delete mode 100644 app/[locale]/(protected)/contest/table-contest/contest-table.tsx delete mode 100644 app/[locale]/(protected)/contest/table-contest/data.ts create mode 100644 app/[locale]/(protected)/curated-content/giat-penugasan/audio-visual.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-penugasan/audio.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-penugasan/image.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-penugasan/teks.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-routine/audio-visual.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-routine/audio.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-routine/image.tsx create mode 100644 app/[locale]/(protected)/curated-content/giat-routine/teks.tsx create mode 100644 app/[locale]/(protected)/schedule/press-conference/detail/[id]/page.tsx create mode 100644 components/form/schedule/press-conference-detail-form.tsx create mode 100644 service/agenda-setting/agenda-setting.ts diff --git a/app/[locale]/(protected)/agenda-setting/calender-view.tsx b/app/[locale]/(protected)/agenda-setting/calender-view.tsx index 6eba2619..2f078cd3 100644 --- a/app/[locale]/(protected)/agenda-setting/calender-view.tsx +++ b/app/[locale]/(protected)/agenda-setting/calender-view.tsx @@ -110,11 +110,11 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => { const handleClassName = (arg: EventContentArg) => { if (arg.event.extendedProps.calendar === "national") { - return "destructive"; - } else if (arg.event.extendedProps.calendar === "polda") { return "primary"; - } else if (arg.event.extendedProps.calendar === "polres") { + } else if (arg.event.extendedProps.calendar === "polda") { return "success"; + } else if (arg.event.extendedProps.calendar === "polres") { + return "destructive"; } else if (arg.event.extendedProps.calendar === "international") { return "info"; } else { diff --git a/app/[locale]/(protected)/agenda-setting/event-modal.tsx b/app/[locale]/(protected)/agenda-setting/event-modal.tsx index 87ebc61f..c84fdc07 100644 --- a/app/[locale]/(protected)/agenda-setting/event-modal.tsx +++ b/app/[locale]/(protected)/agenda-setting/event-modal.tsx @@ -1,4 +1,4 @@ -"use client"; +// "use client"; import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -30,9 +30,18 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Textarea } from "@/components/ui/textarea"; +import { error, loading } from "@/lib/swal"; +import Cookies from "js-cookie"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { useRouter } from "next/navigation"; +import { postSchedule } from "@/service/schedule/schedule"; +import { saveAgendaSettings } from "@/service/agenda-setting/agenda-setting"; const schema = z.object({ title: z.string().min(3, { message: "Required" }), + description: z.string().min(3, { message: "Required" }), }); const EventModal = ({ @@ -57,6 +66,8 @@ const EventModal = ({ // delete modal state const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [eventIdToDelete, setEventIdToDelete] = useState(null); + const MySwal = withReactContent(Swal); + const router = useRouter(); const { register, @@ -70,20 +81,45 @@ const EventModal = ({ mode: "all", }); - const onSubmit = (data: any) => { - startTransition(() => { - if (!event) { - data.start = startDate; - data.end = endDate; - data.allDay = false; - data.extendedProps = { - calendar: calendarProps, - }; - } - if (event) { - } + const save = async (data: any) => { + // loading(); + + const reqData = { + title: data.title, + description: data.description || "", + agendaType: calendarProps, + startDate: format(startDate, "yyyy-MM-dd"), + endDate: format(endDate, "yyyy-MM-dd"), + }; + + console.log("Submitted Data:", reqData); + + const response = await saveAgendaSettings(reqData); + if (response.error) { + error(response.message); + return false; + } + + Cookies.set("AgendaSetting", response.data.data.id, { + expires: 1, + }); + + // Optional: Use Swal for success feedback + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/agenda-setting"); }); }; + + const onSubmit = (data: any) => { + save(data); + }; + useEffect(() => { if (selectedDate) { setStartDate(selectedDate.date); @@ -93,13 +129,10 @@ const EventModal = ({ setStartDate(event?.event?.start); setEndDate(event?.event?.end); const eventCalendar = event?.event?.extendedProps?.calendar; - if (eventCalendar) { - setCalendarProps(eventCalendar); - } else { - setCalendarProps(categories[0].value); - } + setCalendarProps(eventCalendar || categories[0].value); } setValue("title", event?.event?.title || ""); + setValue("description", event?.event?.description || ""); }, [event, selectedDate, open, categories, setValue]); const onDeleteEventAction = async () => { @@ -125,14 +158,15 @@ const EventModal = ({ - {event ? "Edit Event" : "Create Event"} {event?.title} + {event ? "Edit Agenda Setting" : "Create Agenda Setting"}{" "} + {event?.title}
- +
- +
+
+ + +
+
+ + + +
+
+ +
+ + {commentsData.map((comment) => ( +
+ + + +
+ + {comment.username} + + + {comment.date} + +

{comment.text}

+
handleReply(comment.id)} + > + + Balas +
+ {comment.replies.length > 0 && ( +
+ {comment.replies.map((reply: any, index: any) => ( +
+ + + +
+ + {reply.username} + + + {reply.date} + +

+ {reply.text} +

+
+
+ ))} +
+ )} +
+
+ ))} + {replyingTo !== null && ( +
+ + +
+ )} +
+
+ +
+ + ) : ( + "" + )} + + ); +} diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/document/detail/[id]/page.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/document/detail/[id]/page.tsx new file mode 100644 index 00000000..afa89b2b --- /dev/null +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/document/detail/[id]/page.tsx @@ -0,0 +1,518 @@ +"use client"; +import React, { ChangeEvent, useEffect, useRef, 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, CardContent } 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, useRouter } from "next/navigation"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import Cookies from "js-cookie"; +import { postBlog } from "@/service/blog/blog"; +import { Textarea } from "@/components/ui/textarea"; +import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react"; +import { detailMedia } from "@/service/curated-content/curated-content"; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/free-mode"; +import "swiper/css/navigation"; +import "swiper/css/pagination"; +import "swiper/css/thumbs"; +import "swiper/css"; +import "swiper/css/navigation"; +import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; +import JoditEditor from "jodit-react"; + +const detailSchema = z.object({ + title: z.string().min(1, { message: "Judul diperlukan" }), + categoryName: z.string().min(1, { message: "Judul diperlukan" }), + meta: z.string().min(1, { message: "Judul diperlukan" }), + description: z + .string() + .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), + // tags: z.string().min(1, { message: "Judul diperlukan" }), +}); + +type Category = { + id: string; + categoryName: string; +}; + +export type curationDetail = { + id: number; + title: string; + categoryName: string; + description: string; + uploadedBy: { + id: number; + fullname: string; + username: string | null; + email: string; + isActive: boolean; + isDefault: boolean; + isInternational: boolean; + userLevel: { + id: number; + name: string; + aliasName: string; + userGroupId: number; + }; + }; + tags: string; + provinceId: string; + is_active: string; +}; + +const initialComments = [ + { + id: 1, + username: "Esther Howard", + date: "07-04-2023 20:00 WIB", + text: "Tolong untuk narasinya mengikuti 5W + 1H!", + avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, + { + id: 2, + username: "Brooklyn Simmons", + date: "07-04-2023 20:00 WIB", + text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏", + avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, + { + id: 3, + username: "Leslie Alexander", + date: "07-04-2023 20:00 WIB", + text: "Sangat berguna. Terima Kasih!", + avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, +]; + +export default function DetailDocument() { + const MySwal = withReactContent(Swal); + const { id } = useParams() as { id: string }; + console.log(id); + const editor = useRef(null); + type DetailSchema = z.infer; + + const [selectedFiles, setSelectedFiles] = useState([]); + const taskId = Cookies.get("taskId"); + const scheduleId = Cookies.get("scheduleId"); + const scheduleType = Cookies.get("scheduleType"); + const [selectedTarget, setSelectedTarget] = useState(""); + // const [detail, setDetail] = useState({ + // title: null, + // tags: null, + // files: [], + // fileType: null, + // }); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + const [detailThumb, setDetailThumb] = useState([]); + const [thumbsSwiper, setThumbsSwiper] = useState(null); + + const { + control, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: zodResolver(detailSchema), + }); + + const [commentsData, setCommentsData] = useState(initialComments); + const [replyText, setReplyText] = useState(""); + const [replyingTo, setReplyingTo] = useState(null); + + const handleReply = (commentId: number) => { + setReplyingTo(commentId); + }; + + const addReply = (commentId: number) => { + if (replyText.trim()) { + const newCommentData = commentsData.map((comment: any) => { + if (comment.id === commentId) { + return { + ...comment, + replies: [ + ...comment.replies, + { + text: replyText, + username: "You", + date: new Date().toLocaleString(), + }, + ], + }; + } + return comment; + }); + + setCommentsData(newCommentData); + setReplyText(""); + setReplyingTo(null); + } + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await detailMedia(id); + const details = response.data?.data; + + setDetail(details); + const filesData = details.files || []; + const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => + file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" + ); + setDetailThumb(fileUrls); + } + } + initState(); + }, [id, refresh]); + + return ( +
+ {detail !== undefined ? ( + +
+

Kurasi Detail

+ +
+
+
+
+ + ( + + )} + /> + {errors.title?.message && ( +

+ {errors.title.message} +

+ )} +
+
+
+ + ( + + )} + /> +
+
+
+
+ + ( + +
+
+ + + +
+
+ +
+ + {commentsData.map((comment) => ( +
+ + + +
+ + {comment.username} + + + {comment.date} + +

{comment.text}

+
handleReply(comment.id)} + > + + Balas +
+ {comment.replies.length > 0 && ( +
+ {comment.replies.map((reply: any, index: any) => ( +
+ + + +
+ + {reply.username} + + + {reply.date} + +

+ {reply.text} +

+
+
+ ))} +
+ )} +
+
+ ))} + {replyingTo !== null && ( +
+ + +
+ )} +
+
+ +
+ + ) : ( + "" + )} +
+ ); +} diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/document/teks.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/document/teks.tsx index 8c3a988c..20e89711 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/document/teks.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/document/teks.tsx @@ -61,8 +61,8 @@ const TeksSliderPage = () => { - + ))}
diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx index de23584b..05ad3fff 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; -import { useRouter } from "next/navigation"; +import { useParams, useRouter } from "next/navigation"; import { Select, SelectContent, @@ -17,25 +17,26 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import JoditEditor from "jodit-react"; -import { register } from "module"; -import { Switch } from "@/components/ui/switch"; import Cookies from "js-cookie"; -import { createTask } from "@/config/api"; -import { - createMedia, - getTagsBySubCategoryId, - listEnableCategory, -} from "@/service/content/content"; import { postBlog } from "@/service/blog/blog"; import { Textarea } from "@/components/ui/textarea"; -import { InboxIcon } from "lucide-react"; +import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react"; +import { detailMedia } from "@/service/curated-content/curated-content"; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/free-mode"; +import "swiper/css/navigation"; +import "swiper/css/pagination"; +import "swiper/css/thumbs"; +import "swiper/css"; +import "swiper/css/navigation"; +import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; -const taskSchema = z.object({ +const detailSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), - slug: z.string().min(1, { message: "Judul diperlukan" }), + categoryName: z.string().min(1, { message: "Judul diperlukan" }), meta: z.string().min(1, { message: "Judul diperlukan" }), description: z .string() @@ -45,130 +46,151 @@ const taskSchema = z.object({ type Category = { id: string; - name: string; + categoryName: string; }; -const initialCategories: Category[] = [ +export type curationDetail = { + id: number; + title: string; + categoryName: string; + description: string; + uploadedBy: { + id: number; + fullname: string; + username: string | null; + email: string; + isActive: boolean; + isDefault: boolean; + isInternational: boolean; + userLevel: { + id: number; + name: string; + aliasName: string; + userGroupId: number; + }; + }; + tags: string; + provinceId: string; + is_active: string; +}; + +const initialComments = [ { - id: "1", - name: "Giat Polri", + id: 1, + username: "Esther Howard", + date: "07-04-2023 20:00 WIB", + text: "Tolong untuk narasinya mengikuti 5W + 1H!", + avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan }, { - id: "2", - name: "Giat Pimpinan", + id: 2, + username: "Brooklyn Simmons", + date: "07-04-2023 20:00 WIB", + text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏", + avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan }, { - id: "3", - name: "Liputan Kegiatan", - }, - { - id: "4", - name: "Seputar Prestasi", + id: 3, + username: "Leslie Alexander", + date: "07-04-2023 20:00 WIB", + text: "Sangat berguna. Terima Kasih!", + avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan }, ]; export default function DetailImage() { const MySwal = withReactContent(Swal); - const router = useRouter(); + const { id } = useParams() as { id: string }; + console.log(id); const editor = useRef(null); - type TaskSchema = z.infer; + type DetailSchema = z.infer; const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); const scheduleId = Cookies.get("scheduleId"); const scheduleType = Cookies.get("scheduleType"); - - const [categories] = useState(initialCategories); // State untuk kategori const [selectedTarget, setSelectedTarget] = useState(""); - const [selectedCategory, setSelectedCategory] = useState(); - const [tags, setTags] = useState([]); - const [isDraft, setIsDraft] = useState(false); - - const [unitSelection, setUnitSelection] = useState({ - allUnit: false, - mabes: false, - polda: false, - polres: false, - }); - - let fileTypeId = "1"; + // const [detail, setDetail] = useState({ + // title: null, + // tags: null, + // files: [], + // fileType: null, + // }); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + const [detailThumb, setDetailThumb] = useState([]); + const [thumbsSwiper, setThumbsSwiper] = useState(null); const { control, handleSubmit, setValue, formState: { errors }, - } = useForm({ - resolver: zodResolver(taskSchema), + } = useForm({ + resolver: zodResolver(detailSchema), }); - const handleRemoveTag = (index: any) => { - setTags((prevTags) => prevTags.filter((_, i) => i !== index)); + const [commentsData, setCommentsData] = useState(initialComments); + const [replyText, setReplyText] = useState(""); + const [replyingTo, setReplyingTo] = useState(null); + + const handleReply = (commentId: number) => { + setReplyingTo(commentId); }; - const handleImageChange = (event: ChangeEvent) => { - if (event.target.files) { - const files = Array.from(event.target.files); - setSelectedFiles((prevImages: any) => [...prevImages, ...files]); - console.log("DATAFILE::", selectedFiles); + const addReply = (commentId: number) => { + if (replyText.trim()) { + const newCommentData = commentsData.map((comment: any) => { + if (comment.id === commentId) { + return { + ...comment, + replies: [ + ...comment.replies, + { + text: replyText, + username: "You", + date: new Date().toLocaleString(), + }, + ], + }; + } + return comment; + }); + + setCommentsData(newCommentData); + setReplyText(""); + setReplyingTo(null); } }; - const handleRemoveImage = (index: number) => { - setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index)); - }; + useEffect(() => { + async function initState() { + if (id) { + const response = await detailMedia(id); + const details = response.data?.data; - const save = async (data: TaskSchema) => { - const requestData = { - ...data, - title: data.title, - description: data.description, - categoryId: selectedTarget, - slug: data.slug, - metadata: data.meta, - // tags: data.tags, - isDraft, - }; - - const response = await postBlog(requestData); - console.log("Form Data Submitted:", requestData); - console.log("response", response); - - MySwal.fire({ - title: "Sukses", - text: "Data berhasil disimpan.", - icon: "success", - confirmButtonColor: "#3085d6", - confirmButtonText: "OK", - }).then(() => { - router.push("/en/contributor/blog"); - }); - }; - - const onSubmit = (data: TaskSchema) => { - 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); + setDetail(details); + const filesData = details.files || []; + const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => + file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" + ); + setDetailThumb(fileUrls); } - }); - }; + } + initState(); + }, [id, refresh]); return ( - -
+
+ {detail !== undefined ? (

Kurasi Detail

-
+
@@ -183,6 +205,7 @@ export default function DetailImage() { value={field.value} onChange={field.onChange} placeholder="Enter Title" + defaultValue={detail.title} /> )} /> @@ -195,27 +218,20 @@ export default function DetailImage() {
- + ( + + )} + />
@@ -223,18 +239,19 @@ export default function DetailImage() { ( +
+
+ + + +
+
+ +
+ + {commentsData.map((comment) => ( +
+ + + +
+ + {comment.username} + + + {comment.date} + +

{comment.text}

+
handleReply(comment.id)} + > + + Balas +
+ {comment.replies.length > 0 && ( +
+ {comment.replies.map((reply: any, index: any) => ( +
+ + + +
+ + {reply.username} + + + {reply.date} + +

+ {reply.text} +

+
+
+ ))} +
+ )} +
+
+ ))} + {replyingTo !== null && ( +
+ + +
+ )} +
+
+
-
- + ) : ( + "" + )} +
); } diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx index 5d4b4804..523f860e 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx @@ -1,8 +1,10 @@ "use client"; +import { Link } from "@/components/navigation"; import { Card, CardContent } from "@/components/ui/card"; import { getListContent } from "@/service/landing/landing"; import { formatDateToIndonesian } from "@/utils/globals"; import { Icon } from "@iconify/react/dist/iconify.js"; +import image from "next/image"; import React, { useEffect, useState } from "react"; const VideoSliderPage = () => { @@ -53,32 +55,36 @@ const VideoSliderPage = () => { key={video?.id} className="hover:scale-110 transition-transform duration-300" > - - -
- {formatDateToIndonesian(new Date(video?.createdAt))}{" "} - {video?.timezone || "WIB"} | - - {video?.clickCount} - - - -
-
- {video?.title} -
-
+ + + +
+ {formatDateToIndonesian(new Date(video?.createdAt))}{" "} + {video?.timezone || "WIB"} | + + {video?.clickCount} + + + +
+
+ {video?.title} +
+
+ ))}
diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/video/detail/[id]/page.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/detail/[id]/page.tsx new file mode 100644 index 00000000..ce86d7b7 --- /dev/null +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/detail/[id]/page.tsx @@ -0,0 +1,551 @@ +"use client"; +import React, { ChangeEvent, useEffect, useRef, 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, CardContent } 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, useRouter } from "next/navigation"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import Cookies from "js-cookie"; +import { postBlog } from "@/service/blog/blog"; +import { Textarea } from "@/components/ui/textarea"; +import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react"; +import { detailMedia } from "@/service/curated-content/curated-content"; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/free-mode"; +import "swiper/css/navigation"; +import "swiper/css/pagination"; +import "swiper/css/thumbs"; +import "swiper/css"; +import "swiper/css/navigation"; +import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; + +const detailSchema = z.object({ + title: z.string().min(1, { message: "Judul diperlukan" }), + categoryName: z.string().min(1, { message: "Judul diperlukan" }), + meta: z.string().min(1, { message: "Judul diperlukan" }), + description: z + .string() + .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), + // tags: z.string().min(1, { message: "Judul diperlukan" }), +}); + +type Category = { + id: string; + categoryName: string; +}; + +export type curationDetail = { + id: number; + title: string; + categoryName: string; + description: string; + uploadedBy: { + id: number; + fullname: string; + username: string | null; + email: string; + isActive: boolean; + isDefault: boolean; + isInternational: boolean; + userLevel: { + id: number; + name: string; + aliasName: string; + userGroupId: number; + }; + }; + tags: string; + provinceId: string; + is_active: string; +}; + +const initialComments = [ + { + id: 1, + username: "Esther Howard", + date: "07-04-2023 20:00 WIB", + text: "Tolong untuk narasinya mengikuti 5W + 1H!", + avatar: "/images/avatar/avatar-3.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, + { + id: 2, + username: "Brooklyn Simmons", + date: "07-04-2023 20:00 WIB", + text: "Ok Baik, Saya segera melakukan perbaikan. Terima kasih atas masukannya. 🙏", + avatar: "/images/avatar/avatar-5.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, + { + id: 3, + username: "Leslie Alexander", + date: "07-04-2023 20:00 WIB", + text: "Sangat berguna. Terima Kasih!", + avatar: "/images/avatar/avatar-7.png", // URL avatar atau path gambar pengguna + replies: [], // Komentar balasan + }, +]; + +export default function DetailImage() { + const MySwal = withReactContent(Swal); + const { id } = useParams() as { id: string }; + console.log(id); + const editor = useRef(null); + type DetailSchema = z.infer; + + const [selectedFiles, setSelectedFiles] = useState([]); + const taskId = Cookies.get("taskId"); + const scheduleId = Cookies.get("scheduleId"); + const scheduleType = Cookies.get("scheduleType"); + const [selectedTarget, setSelectedTarget] = useState(""); + // const [detail, setDetail] = useState({ + // title: null, + // tags: null, + // files: [], + // fileType: null, + // }); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + const [detailVideo, setDetailVideo] = useState([]); + const [detailThumb, setDetailThumb] = useState([]); + const [thumbsSwiper, setThumbsSwiper] = useState(null); + + const { + control, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: zodResolver(detailSchema), + }); + + const [commentsData, setCommentsData] = useState(initialComments); + const [replyText, setReplyText] = useState(""); + const [replyingTo, setReplyingTo] = useState(null); + + const handleReply = (commentId: number) => { + setReplyingTo(commentId); + }; + + const addReply = (commentId: number) => { + if (replyText.trim()) { + const newCommentData = commentsData.map((comment: any) => { + if (comment.id === commentId) { + return { + ...comment, + replies: [ + ...comment.replies, + { + text: replyText, + username: "You", + date: new Date().toLocaleString(), + }, + ], + }; + } + return comment; + }); + + setCommentsData(newCommentData); + setReplyText(""); + setReplyingTo(null); + } + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await detailMedia(id); + const details = response.data?.data; + + setDetail(details); + const filesData = details.files || []; + const fileUrls = filesData.map((file: { url: string }) => + file.url ? file.url : "default-image.jpg" + ); + setDetailVideo(fileUrls); + const filesDataThumbnail = details.files || []; + const fileUrlsThumbnail = filesDataThumbnail.map( + (file: { thumbnailFileUrl: string }) => + file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" + ); + setDetailThumb(fileUrlsThumbnail); + } + } + initState(); + }, [id, refresh]); + + return ( +
+ {detail !== undefined ? ( + +
+

Kurasi Detail

+ +
+
+
+
+ + ( + + )} + /> + {errors.title?.message && ( +

+ {errors.title.message} +

+ )} +
+
+
+ + ( + + )} + /> +
+
+
+
+ + ( + +
+
+ + + +
+
+ +
+ + {commentsData.map((comment) => ( +
+ + + +
+ + {comment.username} + + + {comment.date} + +

{comment.text}

+
handleReply(comment.id)} + > + + Balas +
+ {comment.replies.length > 0 && ( +
+ {comment.replies.map((reply: any, index: any) => ( +
+ + + +
+ + {reply.username} + + + {reply.date} + +

+ {reply.text} +

+
+
+ ))} +
+ )} +
+
+ ))} + {replyingTo !== null && ( +
+ + +
+ )} +
+
+ +
+ + ) : ( + "" + )} +
+ ); +} diff --git a/components/form/planning/mediahub-publish.tsx b/components/form/planning/mediahub-publish.tsx new file mode 100644 index 00000000..49060fa6 --- /dev/null +++ b/components/form/planning/mediahub-publish.tsx @@ -0,0 +1,352 @@ +"use client"; +import React, { useEffect, useRef, 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, useRouter } from "next/navigation"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Checkbox } from "@/components/ui/checkbox"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import JoditEditor from "jodit-react"; +import { createTask } from "@/service/task"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon } from "lucide-react"; +import { id } from "date-fns/locale"; +import { getPlanningById } from "@/service/planning/planning"; + +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 mediahubDetail = { + id: number; + title: string; + fileTypeOutput: string; + assignedToTopLevel: string; + assignmentType: { + id: number; + name: string; + }; + date: string; + description: string; + is_active: string; +}; + +export default function PublishMediahub() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const editor = useRef(null); + type TaskSchema = z.infer; + const { id } = useParams() as { id: string }; + console.log(id); + const [taskOutput, setTaskOutput] = useState({ + all: false, + video: false, + audio: false, + image: false, + text: false, + }); + const [mainType, setMainType] = useState(1); + const [taskType, setTaskType] = useState("atensi-khusus"); + const [broadcastType, setBroadcastType] = useState("all"); // untuk Tipe Penugasan + const [type, setType] = useState("1"); + const [selectedTarget, setSelectedTarget] = useState("all"); + const [startDate, setStartDate] = useState(new Date()); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + + const [platformTypeVisible, setPlatformTypeVisible] = useState(false); + const [unitSelection, setUnitSelection] = useState({ + allUnit: false, + mabes: false, + polda: false, + polres: false, + }); + + const { + control, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + const handleRadioChange = (event: React.ChangeEvent) => { + const selectedValue = Number(event.target.value); + setMainType(selectedValue); + + setPlatformTypeVisible(selectedValue === 2); + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await getPlanningById(id); + const details = response.data?.data; + + setDetail(details); + if (details?.date) { + setStartDate(new Date(details.date)); // Konversi string tanggal ke objek Date + } + } + } + initState(); + }, [id, refresh]); + + useEffect(() => { + if (detail?.fileTypeOutput) { + const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor + setTaskOutput({ + all: outputSet.has(0), + video: outputSet.has(2), + audio: outputSet.has(4), + image: outputSet.has(1), + text: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); // Membagi string ke dalam array dan mengonversi ke nomor + setUnitSelection({ + allUnit: outputSet.has(0), + mabes: outputSet.has(1), + polda: outputSet.has(2), + polres: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + const save = async (data: TaskSchema) => { + const fileTypeMapping = { + all: "1", + video: "2", + audio: "3", + image: "4", + text: "5", + }; + + const selectedOutputs = Object.keys(taskOutput) + .filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true` + .map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string + .join(","); + + const requestData = { + ...data, + // assignmentType, + // assignmentCategory, + target: selectedTarget, + unitSelection, + assignedToRole: "3", + taskType: taskType, + broadcastType: broadcastType, + assignmentMainTypeId: mainType, + assignmentPurpose: "1", + assignmentTypeId: type, + fileTypeOutput: selectedOutputs, + id: null, + narration: data.naration, + platformType: "", + title: data.title, + }; + + const response = await createTask(requestData); + + console.log("Form Data Submitted:", requestData); + console.log("response", response); + + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/contributor/task"); + }); + }; + + const onSubmit = (data: TaskSchema) => { + 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 ( + +
+

Perencanaan Mediahub

+ {detail !== undefined ? ( +
+
+ {/* Input Title */} +
+ + ( + + )} + /> + {errors.title?.message && ( +

{errors.title.message}

+ )} +
+
+ +
+ {Object.keys(taskOutput).map((key) => ( +
+ + setTaskOutput({ ...taskOutput, [key]: value }) + } + /> + +
+ ))} +
+
+
+
+ +
+ {Object.keys(unitSelection).map((key) => ( +
+ + setUnitSelection({ ...unitSelection, [key]: value }) + } + /> + +
+ ))} +
+
+
+
+ + setType(value)} // Mengubah nilai state ketika pilihan berubah + className="flex flex-wrap gap-3" + > +
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+ +
+
+
+
+ + ( + + )} + /> + {errors.naration?.message && ( +

+ {errors.naration.message} +

+ )} +
+
+ + {/* Submit Button */} +
+ +
+
+ ) : ( + "" + )} +
+
+ ); +} diff --git a/components/form/planning/medsos-publish.tsx b/components/form/planning/medsos-publish.tsx new file mode 100644 index 00000000..5124f4a4 --- /dev/null +++ b/components/form/planning/medsos-publish.tsx @@ -0,0 +1,352 @@ +"use client"; +import React, { useEffect, useRef, 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, useRouter } from "next/navigation"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Checkbox } from "@/components/ui/checkbox"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import JoditEditor from "jodit-react"; +import { createTask } from "@/service/task"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon } from "lucide-react"; +import { id } from "date-fns/locale"; +import { getPlanningById } from "@/service/planning/planning"; + +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 medsosDetail = { + id: number; + title: string; + fileTypeOutput: string; + assignedToTopLevel: string; + assignmentType: { + id: number; + name: string; + }; + date: string; + description: string; + is_active: string; +}; + +export default function PublishMedsos() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const editor = useRef(null); + type TaskSchema = z.infer; + const { id } = useParams() as { id: string }; + console.log(id); + const [taskOutput, setTaskOutput] = useState({ + all: false, + video: false, + audio: false, + image: false, + text: false, + }); + const [mainType, setMainType] = useState(1); + const [taskType, setTaskType] = useState("atensi-khusus"); + const [broadcastType, setBroadcastType] = useState("all"); // untuk Tipe Penugasan + const [type, setType] = useState("1"); + const [selectedTarget, setSelectedTarget] = useState("all"); + const [startDate, setStartDate] = useState(new Date()); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); + + const [platformTypeVisible, setPlatformTypeVisible] = useState(false); + const [unitSelection, setUnitSelection] = useState({ + allUnit: false, + mabes: false, + polda: false, + polres: false, + }); + + const { + control, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + const handleRadioChange = (event: React.ChangeEvent) => { + const selectedValue = Number(event.target.value); + setMainType(selectedValue); + + setPlatformTypeVisible(selectedValue === 2); + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await getPlanningById(id); + const details = response.data?.data; + + setDetail(details); + if (details?.date) { + setStartDate(new Date(details.date)); // Konversi string tanggal ke objek Date + } + } + } + initState(); + }, [id, refresh]); + + useEffect(() => { + if (detail?.fileTypeOutput) { + const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor + setTaskOutput({ + all: outputSet.has(0), + video: outputSet.has(2), + audio: outputSet.has(4), + image: outputSet.has(1), + text: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); // Membagi string ke dalam array dan mengonversi ke nomor + setUnitSelection({ + allUnit: outputSet.has(0), + mabes: outputSet.has(1), + polda: outputSet.has(2), + polres: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + const save = async (data: TaskSchema) => { + const fileTypeMapping = { + all: "1", + video: "2", + audio: "3", + image: "4", + text: "5", + }; + + const selectedOutputs = Object.keys(taskOutput) + .filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true` + .map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string + .join(","); + + const requestData = { + ...data, + // assignmentType, + // assignmentCategory, + target: selectedTarget, + unitSelection, + assignedToRole: "3", + taskType: taskType, + broadcastType: broadcastType, + assignmentMainTypeId: mainType, + assignmentPurpose: "1", + assignmentTypeId: type, + fileTypeOutput: selectedOutputs, + id: null, + narration: data.naration, + platformType: "", + title: data.title, + }; + + const response = await createTask(requestData); + + console.log("Form Data Submitted:", requestData); + console.log("response", response); + + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/contributor/task"); + }); + }; + + const onSubmit = (data: TaskSchema) => { + 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 ( + +
+

Perencanaan Mediahub

+ {detail !== undefined ? ( +
+
+ {/* Input Title */} +
+ + ( + + )} + /> + {errors.title?.message && ( +

{errors.title.message}

+ )} +
+
+ +
+ {Object.keys(taskOutput).map((key) => ( +
+ + setTaskOutput({ ...taskOutput, [key]: value }) + } + /> + +
+ ))} +
+
+
+
+ +
+ {Object.keys(unitSelection).map((key) => ( +
+ + setUnitSelection({ ...unitSelection, [key]: value }) + } + /> + +
+ ))} +
+
+
+
+ + setType(value)} // Mengubah nilai state ketika pilihan berubah + className="flex flex-wrap gap-3" + > +
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+ +
+
+
+
+ + ( + + )} + /> + {errors.naration?.message && ( +

+ {errors.naration.message} +

+ )} +
+
+ + {/* Submit Button */} +
+ +
+
+ ) : ( + "" + )} +
+
+ ); +} diff --git a/components/form/task/task-form.tsx b/components/form/task/task-form.tsx index cee28706..37e5d9fa 100644 --- a/components/form/task/task-form.tsx +++ b/components/form/task/task-form.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { useForm, Controller } from "react-hook-form"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; -import { useRouter } from "next/navigation"; +import { useParams, useRouter } from "next/navigation"; import { Select, SelectContent, @@ -20,7 +20,7 @@ import { import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import JoditEditor from "jodit-react"; -import { createTask } from "@/service/task"; +import { createTask, getTask } from "@/service/task"; const taskSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -29,11 +29,32 @@ const taskSchema = z.object({ }), }); +export type taskDetail = { + id: number; + title: string; + fileTypeOutput: string; + assignedToTopLevel: string; + assignmentType: { + id: number; + name: string; + }; + assignmentMainType: { + id: number; + name: string; + }; + taskType: string; + broadcastType: string; + narration: string; + is_active: string; +}; + export default function FormTask() { const MySwal = withReactContent(Swal); const router = useRouter(); const editor = useRef(null); type TaskSchema = z.infer; + const { id } = useParams() as { id: string }; + console.log(id); // State for various form fields const [taskOutput, setTaskOutput] = useState({ @@ -46,11 +67,13 @@ export default function FormTask() { // const [assignmentType, setAssignmentType] = useState("mediahub"); // const [assignmentCategory, setAssignmentCategory] = useState("publication"); - const [mainType, setMainType] = useState(1); + const [mainType, setMainType] = useState("1"); const [taskType, setTaskType] = useState("atensi-khusus"); - const [broadcastType, setBroadcastType] = useState("all"); // untuk Tipe Penugasan + const [broadcastType, setBroadcastType] = useState(""); // untuk Tipe Penugasan const [type, setType] = useState("1"); const [selectedTarget, setSelectedTarget] = useState("all"); + const [detail, setDetail] = useState(); + const [refresh] = useState(false); const [platformTypeVisible, setPlatformTypeVisible] = useState(false); const [unitSelection, setUnitSelection] = useState({ @@ -68,12 +91,57 @@ export default function FormTask() { resolver: zodResolver(taskSchema), }); - const handleRadioChange = (event: React.ChangeEvent) => { - const selectedValue = Number(event.target.value); - setMainType(selectedValue); + // const handleRadioChange = (event: React.ChangeEvent) => { + // const selectedValue = Number(event.target.value); + // setMainType(selectedValue); - setPlatformTypeVisible(selectedValue === 2); - }; + // setPlatformTypeVisible(selectedValue === 2); + // }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await getTask(id); + const details = response.data?.data; + + setDetail(details); + } + } + initState(); + }, [id, refresh]); + + useEffect(() => { + if (detail?.broadcastType) { + setBroadcastType(detail.broadcastType); // Mengatur nilai broadcastType dari API + } + }, [detail?.broadcastType]); + + useEffect(() => { + if (detail?.fileTypeOutput) { + const outputSet = new Set(detail.fileTypeOutput.split(",").map(Number)); // Membagi string ke dalam array dan mengonversi ke nomor + setTaskOutput({ + all: outputSet.has(0), + video: outputSet.has(2), + audio: outputSet.has(4), + image: outputSet.has(1), + text: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); + + useEffect(() => { + if (detail?.assignedToTopLevel) { + const outputSet = new Set( + detail.assignedToTopLevel.split(",").map(Number) + ); + setUnitSelection({ + allUnit: outputSet.has(0), + mabes: outputSet.has(1), + polda: outputSet.has(2), + polres: outputSet.has(3), + }); + } + }, [detail?.fileTypeOutput]); const save = async (data: TaskSchema) => { const fileTypeMapping = { @@ -144,172 +212,184 @@ export default function FormTask() {

Form Penugasan

-
-
- {/* Input Title */} -
- - ( - + {detail !== undefined ? ( + +
+ {/* Input Title */} +
+ + ( + + )} + /> + {errors.title?.message && ( +

{errors.title.message}

)} - /> - {errors.title?.message && ( -

{errors.title.message}

- )} -
-
+
+
+
+ + +
+
+ {Object.keys(unitSelection).map((key) => ( +
+ + setUnitSelection({ ...unitSelection, [key]: value }) + } + /> + +
+ ))} +
+
- - + + setMainType(value)} + // value={String(mainType)} + // onValueChange={(value) => setMainType(Number(value))} + className="flex flex-wrap gap-3" + > + + + + +
-
- {Object.keys(unitSelection).map((key) => ( -
- - setUnitSelection({ ...unitSelection, [key]: value }) - } - /> - +
+ + setTaskType(String(value))} + className="flex flex-wrap gap-3" + > + + + + + +
+ {/* RadioGroup Assignment Category */} +
+ + setType(value)} // Mengubah nilai state ketika pilihan berubah + className="flex flex-wrap gap-3" + > +
+ +
- ))} -
-
- -
- - setMainType(Number(value))} - className="flex flex-wrap gap-3" - > - - - - - -
-
- - setTaskType(String(value))} - className="flex flex-wrap gap-3" - > - - - - - -
- {/* RadioGroup Assignment Category */} -
- - setType(value)} // Mengubah nilai state ketika pilihan berubah - className="flex flex-wrap gap-3" - > -
- - -
-
- - -
-
- - -
-
-
- -
- -
- {Object.keys(taskOutput).map((key) => ( -
- - setTaskOutput({ ...taskOutput, [key]: value }) - } - /> - +
+ +
- ))} +
+ + +
+
-
-
- - setBroadcastType(String(value))} - className="flex flex-wrap gap-3" - > - - - - - - - -
-
- - ( - +
+ +
+ {Object.keys(taskOutput).map((key) => ( +
+ + setTaskOutput({ ...taskOutput, [key]: value }) + } + /> + +
+ ))} +
+
+
+ + setBroadcastType(value)} // Mengatur nilai saat radio berubah + className="flex flex-wrap gap-3" + > +
+ + +
+
+ + +
+
+ + +
+
+
+
+ + ( + + )} + /> + {errors.naration?.message && ( +

+ {errors.naration.message} +

)} - /> - {errors.naration?.message && ( -

- {errors.naration.message} -

- )} +
-
- {/* Submit Button */} -
- -
- + {/* Submit Button */} +
+ +
+ + ) : ( + "" + )}
); diff --git a/service/curated-content/curated-content.ts b/service/curated-content/curated-content.ts new file mode 100644 index 00000000..af1628f4 --- /dev/null +++ b/service/curated-content/curated-content.ts @@ -0,0 +1,6 @@ +import { getAPIInterceptor } from "@/config/api"; + +export async function detailMedia(id: any) { + const url = `media?id=${id}`; + return getAPIInterceptor(url); +} diff --git a/service/planning/planning.ts b/service/planning/planning.ts index 09419b25..c0010852 100644 --- a/service/planning/planning.ts +++ b/service/planning/planning.ts @@ -1,3 +1,4 @@ +import { getAPIInterceptor } from "@/config/api"; import { httpGetInterceptor } from "../http-config/http-interceptor-service"; export async function getPlanningSentPagination( @@ -10,3 +11,8 @@ export async function getPlanningSentPagination( `planning/pagination/sent?enablePage=1&size=${size}&page=${page}&typeId=${typeId}&title=${title}` ); } + +export async function getPlanningById(id: any) { + const url = `planning?id=${id}`; + return getAPIInterceptor(url); +} diff --git a/service/task.ts b/service/task.ts index c2afd1c6..4aca8bcd 100644 --- a/service/task.ts +++ b/service/task.ts @@ -38,7 +38,7 @@ export async function createTask(data: any) { export async function getTask(id: any) { const url = `/assignment?id=${id}`; - return getAPIInterceptor({ url }); + return getAPIInterceptor(url); } export async function forwardTask(data: any) { From 542c8515a03ebc8153e615c6e10bed9d2f7bc39f Mon Sep 17 00:00:00 2001 From: sabdayagra Date: Tue, 17 Dec 2024 21:27:48 +0700 Subject: [PATCH 14/18] feat: add animation and adjust ui --- app/[locale]/(public)/audio/filter/page.tsx | 198 ++++++------ app/[locale]/(public)/contact/page.tsx | 84 ++--- .../(public)/document/filter/page.tsx | 72 +++-- app/[locale]/(public)/faqs/page.tsx | 35 ++- app/[locale]/(public)/feedback/page.tsx | 29 +- .../(public)/image/detail/[slug]/page.tsx | 170 +++++----- app/[locale]/(public)/image/filter/page.tsx | 63 ++-- app/[locale]/(public)/schedule/page.tsx | 137 +++++--- app/[locale]/(public)/video/filter/page.tsx | 153 ++++----- app/[locale]/page.tsx | 23 +- components/landing-page/Reveal.tsx | 58 ++++ components/landing-page/content-category.tsx | 53 ++-- components/landing-page/coverage.tsx | 79 ++--- components/landing-page/division.tsx | 77 ++--- components/landing-page/hero.tsx | 2 +- components/landing-page/navbar.tsx | 16 +- components/landing-page/new-content.tsx | 295 +++++++++--------- package-lock.json | 121 ++++++- package.json | 3 +- 19 files changed, 957 insertions(+), 711 deletions(-) create mode 100644 components/landing-page/Reveal.tsx diff --git a/app/[locale]/(public)/audio/filter/page.tsx b/app/[locale]/(public)/audio/filter/page.tsx index 803e4eab..cda4a2fa 100644 --- a/app/[locale]/(public)/audio/filter/page.tsx +++ b/app/[locale]/(public)/audio/filter/page.tsx @@ -1,6 +1,5 @@ "use client"; import React, { useEffect, useState } from "react"; -import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination"; import { Checkbox } from "@/components/ui/checkbox"; import { Icon } from "@iconify/react/dist/iconify.js"; import { getListContent } from "@/service/landing/landing"; @@ -8,6 +7,7 @@ import { formatDateToIndonesian } from "@/utils/globals"; import { useParams, usePathname, useRouter, useSearchParams } from "next/navigation"; import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table"; import LandingPagination from "@/components/landing-page/pagination"; +import { Reveal } from "@/components/landing-page/Reveal"; const columns: ColumnDef[] = [ { @@ -110,112 +110,116 @@ const FilterPage = () => {
{/* Left */}
- {/* Sidebar Kiri */} -
-

Filter

-
- {/* Pencarian */} -
- - -
+ + {/* Sidebar Kiri */} +
+

Filter

+
+ {/* Pencarian */} +
+ + +
- {/* Tahun & Bulan */} -
- - -
+ {/* Tahun & Bulan */} +
+ + +
- {/* Tanggal */} -
- - -
+ {/* Tanggal */} +
+ + +
- {/* Kategori */} -
-

Kategori

-
    - {categories.map((category) => ( -
  • - -
  • - ))} -
-
- {/* Garis */} -
- {/* Garis */} -
-

Format Foto

-
    - {formatAudio.map((format) => ( -
  • - -
  • - ))} -
+ {/* Kategori */} +
+

Kategori

+
    + {categories.map((category) => ( +
  • + +
  • + ))} +
+
+ {/* Garis */} +
+ {/* Garis */} +
+

Format Foto

+
    + {formatAudio.map((format) => ( +
  • + +
  • + ))} +
+
-
+
{/* Konten Kanan */} -
-
-

Urutkan berdasarkan

- -
- {/* Card */} -
- {audioData?.map((audio: any) => ( - -
- - - -
- -
-
- {formatDateToIndonesian(new Date(audio?.createdAt))} {audio?.timezone ? audio?.timezone : "WIB"} | 518 -
-
{audio?.title}
-
-
-
- -
-
- # -
{audio?.duration}
- - + +
+
+

Urutkan berdasarkan

+ +
+ {/* Card */} +
- - ))} + +
+
+ {formatDateToIndonesian(new Date(audio?.createdAt))} {audio?.timezone ? audio?.timezone : "WIB"} | 518 +
+
{audio?.title}
+
+
+
+ +
+
+ # +
{audio?.duration}
+ + + +
+
+ + ))} +
+
- -
+
); diff --git a/app/[locale]/(public)/contact/page.tsx b/app/[locale]/(public)/contact/page.tsx index ca09701b..02888d0c 100644 --- a/app/[locale]/(public)/contact/page.tsx +++ b/app/[locale]/(public)/contact/page.tsx @@ -1,54 +1,58 @@ +"use client"; +import { Reveal } from "@/components/landing-page/Reveal"; import React from "react"; const ContactForm = () => { return (
- {/* Header */} -
- contact -

Hubungi Kami

-
-

Tulis Pesan

-

Silahkan tinggalkan pesan Anda pada kolom yang tersedia

- - {/* Form */} -
-
- - + + {/* Header */} +
+ contact +

Hubungi Kami

+

Tulis Pesan

+

Silahkan tinggalkan pesan Anda pada kolom yang tersedia

-
- - -
+ {/* Form */} + +
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
- - +
+ + +
+ + + +
); }; diff --git a/app/[locale]/(public)/document/filter/page.tsx b/app/[locale]/(public)/document/filter/page.tsx index de4028f7..a7450a47 100644 --- a/app/[locale]/(public)/document/filter/page.tsx +++ b/app/[locale]/(public)/document/filter/page.tsx @@ -8,6 +8,7 @@ import { formatDateToIndonesian } from "@/utils/globals"; import { useParams, usePathname, useRouter, useSearchParams } from "next/navigation"; import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table"; import LandingPagination from "@/components/landing-page/pagination"; +import { Reveal } from "@/components/landing-page/Reveal"; const columns: ColumnDef[] = [ { @@ -175,44 +176,49 @@ const DocumentPage = () => {
{/* Konten Kanan */} +
-
-

Urutkan berdasarkan

- -
+ +
+

Urutkan berdasarkan

+ +
+
{/* Card */} -
- {documentData?.map((document: any) => ( - -
- - - -
- -
-
- {formatDateToIndonesian(new Date(document?.createdAt))} {document?.timezone ? document?.timezone : "WIB"} | 518 -
-
{document?.title}
-
- + +
+
+ {formatDateToIndonesian(new Date(document?.createdAt))} {document?.timezone ? document?.timezone : "WIB"} | 518 +
+
{document?.title}
+
+ + + + Download Dokumen +
+
+ + ))} +
+ +
diff --git a/app/[locale]/(public)/faqs/page.tsx b/app/[locale]/(public)/faqs/page.tsx index 6077a44c..1cc1b6c9 100644 --- a/app/[locale]/(public)/faqs/page.tsx +++ b/app/[locale]/(public)/faqs/page.tsx @@ -1,4 +1,5 @@ "use client"; +import { Reveal } from "@/components/landing-page/Reveal"; import React, { useState } from "react"; interface FAQItem { @@ -33,25 +34,27 @@ const FAQS: React.FC = () => { }; return ( -
+
{/* Header */} -
- Faqs -

Frequently Asked Questions

-
+ +
+ Faqs +

Frequently Asked Questions

+
- {/* FAQS Items */} -
- {faqs.map((faq, index) => ( -
-
toggleFAQ(index)}> -

{faq.question}

- {openIndex === index ? "−" : "+"} + {/* FAQS Items */} +
+ {faqs.map((faq, index) => ( +
+
toggleFAQ(index)}> +

{faq.question}

+ {openIndex === index ? "−" : "+"} +
+ {openIndex === index &&

{faq.answer}

}
- {openIndex === index &&

{faq.answer}

} -
- ))} -
+ ))} +
+
); }; diff --git a/app/[locale]/(public)/feedback/page.tsx b/app/[locale]/(public)/feedback/page.tsx index a9e2e0fa..09d85a3e 100644 --- a/app/[locale]/(public)/feedback/page.tsx +++ b/app/[locale]/(public)/feedback/page.tsx @@ -1,5 +1,6 @@ "use client"; +import { Reveal } from "@/components/landing-page/Reveal"; import React, { useState } from "react"; interface RatingProps { @@ -46,20 +47,22 @@ const FeedbackForm: React.FC = () => { }; return ( -
-
- Feedback -

Feedback Pengguna

+ +
+
+ Feedback +

Feedback Pengguna

+
+ handleRatingChange("accessibility", rating)} /> + handleRatingChange("appearance", rating)} /> + handleRatingChange("content", rating)} /> +
+ +
- handleRatingChange("accessibility", rating)} /> - handleRatingChange("appearance", rating)} /> - handleRatingChange("content", rating)} /> -
- -
-
+ ); }; diff --git a/app/[locale]/(public)/image/detail/[slug]/page.tsx b/app/[locale]/(public)/image/detail/[slug]/page.tsx index e3d2c830..8d549e4e 100644 --- a/app/[locale]/(public)/image/detail/[slug]/page.tsx +++ b/app/[locale]/(public)/image/detail/[slug]/page.tsx @@ -10,6 +10,7 @@ import { Icon } from "@iconify/react/dist/iconify.js"; import { textEllipsis } from "@/utils/globals"; import { getDetail } from "@/service/landing/landing"; import NewContent from "@/components/landing-page/new-content"; +import { Reveal } from "@/components/landing-page/Reveal"; const dummyImage = [ { id: 1, thumbnail: "/assets/banner-sample.png" }, @@ -81,110 +82,115 @@ const DetailInfo = () => { return (
- {/* Container Utama */}
{/* Bagian Kiri */} -
- {/* Gambar Utama */} -
- Main -
-
+ +
+ {/* Gambar Besar */} +
+ Main +
+
- {/* Gambar bawah Kecil */} -
- {detailDataImage?.files?.map((file: any, index: number) => ( - setSelectedImage(index)} key={file?.id}> - - - ))} + {/* Gambar bawah Kecil */} +
+ {detailDataImage?.files?.map((file: any, index: number) => ( + setSelectedImage(index)} key={file?.id}> + + + ))} +
-
+
{/* Bagian Kanan */} -
-
- - - -

Simpan

-
- {/* garis */} -
+ +
+
+ + + +

Simpan

+
+ {/* garis */} +
- - {detailDataImage?.category?.name} - + + {detailDataImage?.category?.name} + -
- {detailDataImage?.tags?.split(",").map((tag: string) => ( -

{tag}

- ))} -
+
+ {detailDataImage?.tags?.split(",").map((tag: string) => ( +

{tag}

+ ))} +
-
+
- {/* Opsi Ukuran Foto */} -

Opsi Ukuran Foto

+ {/* Opsi Ukuran Foto */} +

Opsi Ukuran Foto

-
+
-
- {sizes.map((size) => ( -
- {/* Download Semua */} -
- + {/* Tombol Download */} +
- - {/* Tombol Download */} - -
+
{/* Footer Informasi */} -
-
- oleh {detailDataImage?.uploadedBy?.userLevel?.name}  |  Diupdate pada {detailDataImage?.updatedAt} WIB  |  - -   {detailDataImage?.clickCount}   -

Kreator: {detailDataImage?.creatorName}

+ +
+
+ oleh {detailDataImage?.uploadedBy?.userLevel?.name}  |  Diupdate pada {detailDataImage?.updatedAt} WIB  |  + +   {detailDataImage?.clickCount}   +

Kreator: {detailDataImage?.creatorName}

+
-
- {/* Keterangan */} -
-

{detailDataImage?.title}

-
-
+ {/* Keterangan */} +
+

{detailDataImage?.title}

+
+
- {/* Comment */} -
-

Berikan Komentar

-