From 6ebea4da2d0bc187bbee8dcfbcfa5e00edd7b1d5 Mon Sep 17 00:00:00 2001 From: Rama Priyanto Date: Mon, 30 Dec 2024 20:23:15 +0700 Subject: [PATCH 1/4] feat:detail list task plan, admin view --- .../table/task-plan/expand-list-view.tsx | 170 ++++++++++++ .../table/task-plan/list-view-column.tsx | 57 +--- .../list-view-social-media-column.tsx | 50 +--- lib/menus.ts | 260 ++++++++++++++++++ messages/en.json | 6 +- messages/in.json | 8 +- service/agenda-setting/agenda-setting.ts | 2 +- 7 files changed, 448 insertions(+), 105 deletions(-) create mode 100644 components/table/task-plan/expand-list-view.tsx diff --git a/components/table/task-plan/expand-list-view.tsx b/components/table/task-plan/expand-list-view.tsx new file mode 100644 index 00000000..0a7fd166 --- /dev/null +++ b/components/table/task-plan/expand-list-view.tsx @@ -0,0 +1,170 @@ +"use client"; +import { Button } from "@/components/ui/button"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { close, loading } from "@/config/swal"; +import { Link } from "@/i18n/routing"; +import { + getPlanningDailyByTypeId, + getPlanningPagination, +} from "@/service/agenda-setting/agenda-setting"; +import { htmlToString, textEllipsis } from "@/utils/globals"; +import { MoreVertical } from "lucide-react"; +import { useEffect, useState } from "react"; + +export default function ExpandedData(props: { datas: any }) { + const { datas } = props; + const [isOpen, setIsOpen] = useState(""); + const [getData, setGetData] = useState(); + + const handleIsOpen = (id: string) => { + setIsOpen(id); + }; + + useEffect(() => { + if (isOpen !== "") { + fetchData(); + } + }, [isOpen]); + + async function fetchData() { + loading(); + const response = await getPlanningPagination(0, "", 10, 1, 1, isOpen); + + close(); + setupData(response.data?.data); + } + + function setupData(rawData: any) { + if (rawData != undefined) { + const dataContent = rawData?.content; + const data = []; + + for (const [i, element] of dataContent.entries()) { + element.no = i + 1; + data.push(element); + } + + setGetData(data); + } + } + return ( + + + + + + + + {datas?.map((data: any) => ( + <> + + + + + + + handleIsOpen(data.id)} + > + + + + + + + + + + {getData?.map((row: any) => ( + + + + + + + + + ))} + + + + ))} +
Judul PerencanaanBatas WaktuStatusAksi
+ handleIsOpen(data.id)}>{data.title} + + `disinni igninn membuat state untuk mennyimpan data isOpen` + } + > + {data.date} + {data.status} + + + + + + + + Detail + + + + + Edit + + + + Delete + + + +
NoJudul PerencanaanNama PembuatBatas WaktuStatusAksi
{row.no}{row.title}{row.createdByName}{row.date}{row.status} + + + + + + + + Detail + + + + + Edit + + + + Delete + + + +
+ ); +} diff --git a/components/table/task-plan/list-view-column.tsx b/components/table/task-plan/list-view-column.tsx index a8ff693a..f492caaf 100644 --- a/components/table/task-plan/list-view-column.tsx +++ b/components/table/task-plan/list-view-column.tsx @@ -26,6 +26,8 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; +import ExpandedData from "./expand-list-view"; const columns: ColumnDef[] = [ { @@ -33,11 +35,7 @@ const columns: ColumnDef[] = [ header: "No", cell: ({ row }) => {row.getValue("no")}, }, - // { - // accessorKey: "title", - // header: "Judul Perencanaan", - // cell: ({ row }) => {row.getValue("title")}, - // }, + { accessorKey: "title", header: "Judul Perencanaan", @@ -52,54 +50,7 @@ const columns: ColumnDef[] = [ Rencanaan Mingguan - - - - - - - - {datas?.map((data: any) => ( - - - - - - - ))} -
Judul PerencanaanBatas WaktuStatusAksi
- {data.title} - {data.date}{data.status} - - - - - - - - Detail - - - - - Edit - - - - Delete - - - -
+ ); diff --git a/components/table/task-plan/list-view-social-media-column.tsx b/components/table/task-plan/list-view-social-media-column.tsx index 73bdc584..12cd60e3 100644 --- a/components/table/task-plan/list-view-social-media-column.tsx +++ b/components/table/task-plan/list-view-social-media-column.tsx @@ -26,6 +26,7 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import ExpandedData from "./expand-list-view"; const columns: ColumnDef[] = [ { @@ -52,54 +53,7 @@ const columns: ColumnDef[] = [ Rencanaan Mingguan - - - - - - - - {datas?.map((data: any) => ( - - - - - - - ))} -
Judul PerencanaanBatas WaktuStatusAksi
- {data.title} - {data.date}{data.status} - - - - - - - - Detail - - - - - Edit - - - - Hapus - - - -
+ ); diff --git a/lib/menus.ts b/lib/menus.ts index eef2b3bf..06f13a35 100644 --- a/lib/menus.ts +++ b/lib/menus.ts @@ -32,6 +32,7 @@ export type Group = { export function getMenuList(pathname: string, t: any): Group[] { const roleId = getCookiesDecrypt("urie"); + console.log("roleId"); const levelNumber = getCookiesDecrypt("ulne"); const userLevelId = getCookiesDecrypt("ulie"); @@ -1676,6 +1677,265 @@ export function getMenuList(pathname: string, t: any): Group[] { ], }, ]; + } else if (Number(roleId) === 2) { + menusSelected = [ + { + groupLabel: t("apps"), + id: "dashboard", + menus: [ + { + id: "dashboard", + href: "/dashboard", + label: t("dashboard"), + active: pathname.includes("/dashboard"), + icon: "material-symbols:dashboard", + submenus: [ + { + href: "/dashboard", + label: "Executive", + active: pathname === "/dashboard", + icon: "heroicons:arrow-trending-up", + children: [], + }, + { + href: "/dashboard/breakdown", + label: "Breakdown", + active: pathname === "/dashboard/breakdown", + icon: "heroicons:arrow-trending-up", + children: [], + }, + ], + }, + ], + }, + { + groupLabel: "", + id: "agenda-setting", + menus: [ + { + id: "agenda-setting", + href: "/contributor/agenda-setting", + label: t("agenda-setting"), + active: pathname.includes("/agenda-setting"), + icon: "iconoir:journal-page", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "management-user", + menus: [ + { + id: "management-user-menu", + href: "/adminn/management-user", + label: "Management User", + active: pathname.includes("/management-user"), + icon: "clarity:users-solid", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "content-production", + menus: [ + { + id: "content-production", + href: "/curator/content-production", + label: t("content-production"), + active: pathname.includes("/content-production"), + icon: "fluent:content-view-gallery-16-regular", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "pattern-relation", + menus: [ + { + id: "pattern-relation", + href: "/curator/pattern-relation", + label: t("pattern-relation"), + active: pathname.includes("/pattern-relation"), + icon: "oui:app-index-pattern", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "performance-polda", + menus: [ + { + id: "performance-polda", + href: "/admin/performance-polda", + label: t("performance-polda"), + active: pathname.includes("/admin/performance-polda"), + icon: "ant-design:signal-filled", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "analysis", + menus: [ + { + id: "analysis", + href: "/admin/analysis", + label: t("analysis"), + active: pathname.includes("/task-plan"), + icon: "mdi:chart-line", + submenus: [ + { + href: "/admin/analysis/magement-content", + label: t("management-content"), + active: pathname === "/admin/analysis/magement-content", + icon: "", + children: [], + }, + { + href: "/admin/analysis/schedule", + label: t("schedule"), + active: pathname === "/admin/analysis/schedule", + icon: "heroicons:shopping-cart", + children: [], + }, + { + href: "/admin/analysis/feedback-center", + label: "Feedback Center", + active: pathname === "/admin/analysis/feedback-center", + icon: "heroicons:shopping-cart", + children: [], + }, + { + href: "/admin/analysis/emergency-issue", + label: "Emergency Issue", + active: pathname === "/admin/analysis/emergency-issue", + icon: "heroicons:shopping-cart", + children: [], + }, + ], + }, + ], + }, + + { + groupLabel: "", + id: "media-tracking", + menus: [ + { + id: "media-tracking", + href: "/curator/media-tracking", + label: t("media-tracking"), + active: pathname.includes("/media-tracking"), + icon: "material-symbols:map-search-outline", + submenus: [ + { + href: "/admin/media-tracking/media-online", + label: "Media Onlinne", + active: pathname === "/media-tracking/media-online", + icon: "heroicons:arrow-trending-up", + children: [], + }, + { + href: "/admin/media-tracking/news", + label: "Tracking Beritra Hari Ini", + active: pathname === "/media-tracking/news", + icon: "heroicons:arrow-trending-up", + children: [], + }, + ], + }, + ], + }, + { + groupLabel: "", + id: "contest", + menus: [ + { + id: "contest", + href: "/shared/contest", + label: t("contest"), + active: pathname.includes("/contest"), + icon: "ic:outline-emoji-events", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "communication", + menus: [ + { + id: "communication", + href: "/shared/communication", + label: t("communication"), + active: pathname.includes("/communication"), + icon: "token:chat", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "feedback", + menus: [ + { + id: "feedback", + href: "/curator/feedback", + label: t("feedback"), + active: pathname.includes("/feedback"), + icon: "mdi:feedback-outline", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "broadcast", + menus: [ + { + id: "broadcast", + href: "/admin/broadcast", + label: "Broadcast", + active: pathname.includes("/broadcast"), + icon: "mdi:broadcast", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "experts", + menus: [ + { + id: "experts", + href: "/admin/add-experts", + label: t("add-experts"), + active: pathname.includes("/add-experts"), + icon: "majesticons:user", + submenus: [], + }, + ], + }, + { + groupLabel: "", + id: "settings", + menus: [ + { + id: "settings", + href: "/admin/settings", + label: t("settings"), + active: pathname.includes("/settinng"), + icon: "material-symbols:settings", + submenus: [], + }, + ], + }, + ]; } return menusSelected; diff --git a/messages/en.json b/messages/en.json index 7428b5bf..b88b12f9 100644 --- a/messages/en.json +++ b/messages/en.json @@ -294,7 +294,11 @@ "purchaseList": "Purchase List", "sellers": "Sellers", "typography": "Typography", - "colors": "Colors" + "colors": "Colors", + "performance-polda": "Performance Polda", + "analysis": "Analysis", + "management-content": "Management Content", + "add-experts": "Add Experts" }, "Changelog": { "version": "Version's", diff --git a/messages/in.json b/messages/in.json index 6faa946b..f057ae12 100644 --- a/messages/in.json +++ b/messages/in.json @@ -146,7 +146,7 @@ "forward": "Forward", "collaboration": "Collaboration", "account-report": "Account Report", - "settings": "Settings", + "settings": "Pengaturan", "feedback": "Feedback", "content-production": "Produksi Konten", "pattern-relation": "Pola & Relasi", @@ -294,7 +294,11 @@ "purchaseList": "Purchase List", "sellers": "Sellers", "typography": "Typography", - "colors": "Colors" + "colors": "Colors", + "performance-polda": "Performa Polda", + "analysis": "Analisa", + "management-content": "Manajemen Konten", + "add-experts": "Tambah Tenaga Ahli" }, "Changelog": { "version": "Version's", diff --git a/service/agenda-setting/agenda-setting.ts b/service/agenda-setting/agenda-setting.ts index 4057fe6e..d6c34d98 100644 --- a/service/agenda-setting/agenda-setting.ts +++ b/service/agenda-setting/agenda-setting.ts @@ -22,7 +22,7 @@ export async function getPlanningDailyByTypeId( date: string, typeId: number ) { - const url = `planning/pagination/daily?enablePage=1&size=${size}&page=${page}&date=${date}&typeId=${typeId}${ + const url = `planning/pagination/daily?enablePage=1&time=1&size=${size}&page=${page}&date=${date}&typeId=${typeId}${ parentId ? `&parentId=${parentId}` : "" }`; return getAPIInterceptor(url); From f3c9108614d191279c7b1a091e29896de047aa47 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Mon, 30 Dec 2024 21:43:39 +0800 Subject: [PATCH 2/4] feat:update agenda setting, form task --- .../agenda-setting/calender-view.tsx | 23 +- .../contributor/agenda-setting/data.ts | 12 + .../agenda-setting/event-modal.tsx | 267 ++++++++++++++++- .../shared/contest/create/page.tsx | 17 ++ .../(protected)/shared/contest/page.tsx | 9 +- components/form/content/image-ai-form.tsx | 13 +- .../form/contest/contest-detail-form.tsx | 283 +++++++++--------- components/form/task/task-form.tsx | 272 ++++++++++++----- package-lock.json | 222 +++++++++++++- package.json | 2 + 10 files changed, 853 insertions(+), 267 deletions(-) create mode 100644 app/[locale]/(protected)/shared/contest/create/page.tsx diff --git a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx index 73cf2e5a..1f21a324 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx @@ -18,6 +18,7 @@ import EventModal from "./event-modal"; import { useTranslations } from "next-intl"; import { getAgendaSettingsList } from "@/service/agenda-setting/agenda-setting"; import dayjs from "dayjs"; +import { getCookiesDecrypt } from "@/lib/utils"; const wait = () => new Promise((resolve) => setTimeout(resolve, 1000)); interface CalendarViewProps { events: CalendarEvent[]; @@ -66,7 +67,7 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => { // const [selectedEvent, setSelectedEvent] = useState( // null // ); - + const roleId = Number(getCookiesDecrypt("urie")) || 0; const [apiEvents, setApiEvents] = useState([]); const [loading, setLoading] = useState(false); const [draggableInitialized, setDraggableInitialized] = @@ -246,15 +247,17 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
- - - + {roleId === 11 && ( + + + + )}
( categories[0].value ); - // delete modal state + const [listDest, setListDest] = useState([]); const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [eventIdToDelete, setEventIdToDelete] = useState(null); const MySwal = withReactContent(Swal); const router = useRouter(); + const [isLoading, setIsLoading] = useState(false); + const [checkedLevels, setCheckedLevels] = useState(new Set()); + const [expandedPolda, setExpandedPolda] = useState([{}]); + const [audioFile, setAudioFile] = useState(null); + const [isRecording, setIsRecording] = useState(false); + const [timer, setTimer] = useState(120); const { register, @@ -81,8 +91,47 @@ const EventModal = ({ mode: "all", }); + useEffect(() => { + async function fetchPoldaPolres() { + setIsLoading(true); + try { + const response = await getUserLevelForAssignments(); + setListDest(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 save = async (data: any) => { - // loading(); + if (!audioFile) return; + + const formData = new FormData(); + formData.append("voiceNote", audioFile); const reqData = { title: data.title, @@ -90,6 +139,7 @@ const EventModal = ({ agendaType: calendarProps, startDate: format(startDate, "yyyy-MM-dd"), endDate: format(endDate, "yyyy-MM-dd"), + voiceNote: formData, }; console.log("Submitted Data:", reqData); @@ -146,6 +196,58 @@ const EventModal = ({ onClose(); }; + const toggleExpand = (poldaId: any) => { + setExpandedPolda((prev: any) => ({ + ...prev, + [poldaId]: !prev[poldaId], + })); + }; + + const onRecordingStart = () => { + setIsRecording(true); + + // Start a timer that stops the recording after 2 minutes (120 seconds) + const countdown = setInterval(() => { + setTimer((prevTimer) => { + if (prevTimer <= 1) { + clearInterval(countdown); // Stop the timer when it reaches 0 + return 0; + } + return prevTimer - 1; + }); + }, 1000); // Update every second + + // Automatically stop recording after 2 minutes + setTimeout(() => { + if (isRecording) { + handleStopRecording(); + } + }, 120000); // Stop after 2 minutes (120,000 ms) + }; + + const handleStopRecording = () => { + setIsRecording(false); + setTimer(120); // Reset the timer to 2 minutes for the next recording + }; + + const addAudioElement = (blob: Blob) => { + const url = URL.createObjectURL(blob); + const audio = document.createElement("audio"); + audio.src = url; + audio.controls = true; + document.body.appendChild(audio); + + // Convert Blob to File + const file = new File([blob], "voiceNote.webm", { type: "audio/webm" }); + setAudioFile(file); + }; + const handleDeleteAudio = () => { + // Remove the audio file by setting state to null + setAudioFile(null); + const audioElements = document.querySelectorAll("audio"); + audioElements.forEach((audio) => audio.remove()); + }; + return ( <> - + {event ? "Edit Agenda Setting" : "Create Agenda Setting"}{" "} {event?.title} -
+
@@ -181,7 +286,6 @@ const EventModal = ({
)}
-
@@ -254,7 +358,6 @@ const EventModal = ({
-
+ {calendarProps === "polda" && ( +
+ + + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest.map((polda: any) => ( +
+ + {expandedPolda[polda.id] && ( +
+ + {polda?.subDestination?.map((polres: any) => ( + + ))} +
+ )} +
+ ))} +
+
+
+
+ )}