From ffb75f9b46ff24807f01ef45f1b6f76fff9ee39f Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Thu, 16 Jan 2025 03:02:28 +0800 Subject: [PATCH] feat:update agenda setting, task,content --- .../agenda-setting/calender-view.tsx | 186 ++++--- .../agenda-setting/event-modal.tsx | 443 +++++++++++----- .../agenda-setting/unit-mapping.tsx | 251 ++++----- .../content/audio/components/columns.tsx | 54 +- .../content/image/components/columns.tsx | 59 ++- .../content/image/components/table-image.tsx | 41 +- .../content/teks/components/columns.tsx | 54 +- .../content/video/components/columns.tsx | 54 +- .../contributor/task/components/columns.tsx | 55 +- components/form/content/audio-update-form.tsx | 261 ++++++--- components/form/content/image-update-form.tsx | 249 ++++++--- components/form/content/teks-update-form.tsx | 117 +++-- components/form/content/video-form.tsx | 8 +- components/form/content/video-update-form.tsx | 294 +++++++---- components/form/task/task-detail-form.tsx | 496 +++++++++++------- components/form/task/task-edit-form.tsx | 464 +++++++++++++--- components/form/task/task-form.tsx | 87 ++- public/assets/img/image-not.jpg | Bin 0 -> 63616 bytes service/agenda-setting/agenda-setting.ts | 12 +- service/content/content.ts | 11 + .../http-config/http-interceptor-service.ts | 10 +- 21 files changed, 2255 insertions(+), 951 deletions(-) create mode 100644 public/assets/img/image-not.jpg diff --git a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx index 4e6995e1..78719a93 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx @@ -46,7 +46,6 @@ export type CalendarEvent = { }; }; - const INITIAL_YEAR = dayjs().format("YYYY"); const INITIAL_MONTH = dayjs().format("M"); @@ -63,7 +62,7 @@ export interface AgendaSettingsAPIResponse { updatedAt: string; createdById: number | null; } - + interface YearlyData { january?: Event[]; february?: Event[]; @@ -86,7 +85,7 @@ interface MonthCardProps { interface ListItemProps { item: any; - text: string + text: string; createdBy: string; bgColor: string; } @@ -120,7 +119,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => { const [selectedYear, setSelectedYear] = useState(new Date()); const [selectedMonth, setSelectedMonth] = useState( - dayjs(new Date(Number(INITIAL_YEAR), Number(INITIAL_MONTH) - 1, 1)), + dayjs(new Date(Number(INITIAL_YEAR), Number(INITIAL_MONTH) - 1, 1)) ); const [dragEvents] = useState([ @@ -142,7 +141,11 @@ const CalendarView = ({ categories }: CalendarViewProps) => { const getCalendarEvents = async () => { console.log("View : ", activeView); - const res = await getAgendaSettingsList(selectedMonth?.format("YYYY") || INITIAL_YEAR, selectedMonth.format("M") || INITIAL_MONTH, ""); + const res = await getAgendaSettingsList( + selectedMonth?.format("YYYY") || INITIAL_YEAR, + selectedMonth.format("M") || INITIAL_MONTH, + "" + ); console.log("View : API Response:", res); if (res?.error) { @@ -175,13 +178,17 @@ const CalendarView = ({ categories }: CalendarViewProps) => { }; const getYearlyEvents = async () => { - const res = await getAgendaSettingsList(selectedMonth?.format("YYYY") || INITIAL_YEAR, '', ''); - if (res?.error) { - error(res.message); - return false; - } - setYearlyData(res?.data?.data); - } + const res = await getAgendaSettingsList( + selectedMonth?.format("YYYY") || INITIAL_YEAR, + "", + "" + ); + if (res?.error) { + error(res.message); + return false; + } + setYearlyData(res?.data?.data); + }; useEffect(() => { setSelectedCategory(categories?.map((c) => c.value)); @@ -218,21 +225,19 @@ const CalendarView = ({ categories }: CalendarViewProps) => { if (response?.data && Array.isArray(response?.data)) { // Transform API data to match CalendarEvent type - const eventsFromAPI: CalendarEvent[] = response?.data?.map( - (item) => ({ - id: item.id.toString(), - title: item.title, - createBy: "Mabes Polri - Approver", - createdByName: item.createdByName, - start: new Date(item.startDate), - end: new Date(item.endDate), - allDay: true, // Sesuaikan jika memang ada event sepanjang hari - extendedProps: { - calendar: item.agendaType, - description: item.description, - }, - }) - ); + const eventsFromAPI: CalendarEvent[] = response?.data?.map((item) => ({ + id: item.id.toString(), + title: item.title, + createBy: "Mabes Polri - Approver", + createdByName: item.createdByName, + start: new Date(item.startDate), + end: new Date(item.endDate), + allDay: true, // Sesuaikan jika memang ada event sepanjang hari + extendedProps: { + calendar: item.agendaType, + description: item.description, + }, + })); setApiEvents(eventsFromAPI); } else { @@ -321,7 +326,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => { const renderEventContent = (eventInfo: any) => { const { title } = eventInfo.event; - const { createdByName } = eventInfo.event.extendedProps; // Akses dari extendedProps + const { createdByName } = eventInfo.event.extendedProps; return ( <> @@ -340,6 +345,8 @@ const CalendarView = ({ categories }: CalendarViewProps) => { return "bg-blue-400 border-none"; } else if (arg.event.extendedProps.calendar === "polres") { return "bg-slate-400 border-none"; + } else if (arg.event.extendedProps.calendar === "satker") { + return "bg-orange-500 border-none"; } else if (arg.event.extendedProps.calendar === "international") { return "bg-green-400 border-none"; } else { @@ -359,29 +366,29 @@ const CalendarView = ({ categories }: CalendarViewProps) => { const handleViewChange = (viewType: string) => { console.log("Change view : ", viewType); setActiveView(viewType); - }; + }; const months: Array<{ id: keyof YearlyData; label: string }> = [ - { id: 'january', label: 'Januari' }, - { id: 'february', label: 'Februari' }, - { id: 'march', label: 'Maret' }, - { id: 'april', label: 'April' }, - { id: 'may', label: 'Mei' }, - { id: 'june', label: 'Juni' }, - { id: 'july', label: 'Juli' }, - { id: 'august', label: 'Agustus' }, - { id: 'september', label: 'September' }, - { id: 'october', label: 'Oktober' }, - { id: 'november', label: 'November' }, - { id: 'december', label: 'Desember' } + { id: "january", label: "Januari" }, + { id: "february", label: "Februari" }, + { id: "march", label: "Maret" }, + { id: "april", label: "April" }, + { id: "may", label: "Mei" }, + { id: "june", label: "Juni" }, + { id: "july", label: "Juli" }, + { id: "august", label: "Agustus" }, + { id: "september", label: "September" }, + { id: "october", label: "Oktober" }, + { id: "november", label: "November" }, + { id: "december", label: "Desember" }, ]; - const getEventColor = (type: Event['type']): string => { - const colors: Record = { - mabes: 'bg-yellow-500', - polda: 'bg-blue-400', - polres: 'bg-slate-400', - international: 'bg-green-400' + const getEventColor = (type: Event["type"]): string => { + const colors: Record = { + mabes: "bg-yellow-500", + polda: "bg-blue-400", + polres: "bg-slate-400", + international: "bg-green-400", }; return colors[type]; }; @@ -397,32 +404,38 @@ const CalendarView = ({ categories }: CalendarViewProps) => { allDay: true, extendedProps: { calendar: item.agendaType, - description: item.description - } + description: item.description, + }, }; const finalEvent: any = { - event: formattedEvent - } - + event: formattedEvent, + }; + console.log("Event click custom : ", finalEvent); setSelectedEventDate(null); setSheetOpen(true); setApiEvents(finalEvent); wait().then(() => (document.body.style.pointerEvents = "auto")); - } + }; - const ListItem: React.FC = ({ item, text, createdBy, bgColor }) => ( -
handleClickListItem(item)}> + const ListItem: React.FC = ({ + item, + text, + createdBy, + bgColor, + }) => ( +
handleClickListItem(item)} + >

{text}

-

- Created By: {createdBy} -

+

Created By: {createdBy}

); const MonthCard: React.FC = (props: any) => { - const { monthId, label } = props; + const { monthId, label } = props; const events: any = yearlyData?.[monthId]; const displayedEvents = events?.slice(0, 3); const hasMoreEvents = events?.length > 3; @@ -431,7 +444,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {

{label}

- +
{events?.length === 0 ? (
@@ -440,7 +453,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => { ) : ( <> {displayedEvents?.map((event: any, index: number) => ( - { bgColor={getEventColor(event.agendaType)} /> ))} - + {hasMoreEvents && ( @@ -462,12 +475,14 @@ const CalendarView = ({ categories }: CalendarViewProps) => { > - {label} + + {label} +
{events.map((event: any, index: number) => ( - { - {roleId == 11 || roleId == 12 ? + {roleId == 11 || roleId == 12 ? ( : + + ) : ( "" - } + )}
@@ -597,35 +613,53 @@ const CalendarView = ({ categories }: CalendarViewProps) => { handleDateChange(info.view.currentStart, info.view.currentEnd); handleViewChange(info.view.type); }} - viewClassNames={activeView === "listYear" ? "hide-calendar-grid" : ""} + viewClassNames={ + activeView === "listYear" ? "hide-calendar-grid" : "" + } /> {activeView === "listYear" && (
- {months.slice(0, 3).map(month => ( - + {months.slice(0, 3).map((month) => ( + ))}
{/* Second Row */}
- {months.slice(3, 6).map(month => ( - + {months.slice(3, 6).map((month) => ( + ))}
{/* Third Row */}
- {months.slice(6, 9).map(month => ( - + {months.slice(6, 9).map((month) => ( + ))}
{/* Fourth Row */}
- {months.slice(9, 12).map(month => ( - + {months.slice(9, 12).map((month) => ( + ))}
diff --git a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx index ce3d9210..67c3bb97 100644 --- a/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx +++ b/app/[locale]/(protected)/contributor/agenda-setting/event-modal.tsx @@ -36,9 +36,9 @@ import { error, loading, success } 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 { + deleteAgendaSettings, getAgendaSettingsById, saveAgendaSettings, } from "@/service/agenda-setting/agenda-setting"; @@ -52,6 +52,10 @@ import { Icon } from "@iconify/react"; import Image from "next/image"; import { UnitMapping } from "./unit-mapping"; import { useToast } from "@/components/ui/use-toast"; +import { usePathname, useRouter } from "next/navigation"; +import { Card } from "@/components/ui/card"; +import WavesurferPlayer from "@wavesurfer/react"; +import WaveSurfer from "wavesurfer.js"; const schema = z.object({ title: z.string().min(3, { message: "Required" }), @@ -80,15 +84,16 @@ const EventModal = ({ event: any; selectedDate: any; }) => { + const [detail, setDetail] = useState(); const [startDate, setStartDate] = useState(new Date()); const [endDate, setEndDate] = useState(new Date()); const [isPending, startTransition] = React.useTransition(); - const [agendaType, setAgendaType] = React.useState(categories[0].value); const [listDest, setListDest] = useState([]); const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [eventIdToDelete, setEventIdToDelete] = useState(null); const MySwal = withReactContent(Swal); const router = useRouter(); + const pathname = usePathname(); const [isLoading, setIsLoading] = useState(false); const [checkedLevels, setCheckedLevels] = useState(new Set()); const [expandedPolda, setExpandedPolda] = useState([{}]); @@ -129,11 +134,16 @@ const EventModal = ({ semua: false, nasional: false, polda: false, + polres: false, satker: false, - internasional: false, + international: false, }); - const [selectedPolda, setSelectedPolda] = React.useState([]); + const [agendaType, setAgendaType] = React.useState(""); // State untuk agendaType + const [selectedPolda, setSelectedPolda] = React.useState([]); // Untuk data Polda const [selectedSatker, setSelectedSatker] = React.useState([]); + const [selectedPolres, setSelectedPolres] = React.useState([]); + const [wavesurfer, setWavesurfer] = useState(); + const [isPlaying, setIsPlaying] = useState(false); const { register, @@ -153,6 +163,14 @@ const EventModal = ({ const detail = res?.data?.data; setDetailData(detail); + const description = detail?.description; + console.log("description", res?.data?.description); + + // Set nilai awal description ke form control + if (description) { + setValue("description", description); + } + const attachments = detail?.attachments; setImageUploadedFiles( attachments?.filter((file: any) => file.fileTypeId == 1) @@ -169,7 +187,7 @@ const EventModal = ({ } fetchDetailData(); - }, [event]); + }, [event, setValue]); // useEffect(() => { // async function fetchPoldaPolres() { @@ -226,22 +244,32 @@ const EventModal = ({ setWilayahPublish((prev: any) => { const newState = { ...prev, [key]: !prev[key] }; - // Handle "semua" logic to uncheck other options + // Handle "semua" logic to check all options if (key === "semua" && newState.semua) { + setAgendaType("all"); return { semua: true, - nasional: false, - polda: false, - satker: false, - internasional: false, + nasional: true, + polda: true, + polres: true, + satker: true, + international: true, }; } - // Uncheck "semua" if any other is selected + // Uncheck "semua" if any other option is selected if (key !== "semua") { newState.semua = false; } + // Set agendaType based on the selected checkbox + if (newState.nasional) setAgendaType("mabes"); + else if (newState.polda) setAgendaType("polda"); + else if (newState.polres) setAgendaType("polres"); + else if (newState.satker) setAgendaType("satker"); + else if (newState.international) setAgendaType("international"); + else setAgendaType(""); // Reset if no checkbox is selected + return newState; }); }; @@ -251,12 +279,15 @@ const EventModal = ({ if (wilayahPublish.semua) publishTo.push("all"); if (wilayahPublish.nasional) publishTo.push("mabes"); if (wilayahPublish.polda) publishTo.push(...selectedPolda); + if (wilayahPublish.polres) publishTo.push(...selectedPolres); if (wilayahPublish.satker) publishTo.push(...selectedSatker); - if (wilayahPublish.internasional) publishTo.push("internasional"); + if (wilayahPublish.international) publishTo.push("international"); const reqData = { + id: detailData?.id, title: data.title, description: data.description, + agendaType, // Include agendaType in request publishTo, startDate: format(startDate, "yyyy-MM-dd"), endDate: format(endDate, "yyyy-MM-dd"), @@ -273,50 +304,40 @@ const EventModal = ({ const id = response?.data?.data.id; loading(); - if (imageFiles?.length == 0) { + if (imageFiles?.length === 0) { setIsImageUploadFinish(true); } imageFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "1", "0"); }); - if (videoFiles?.length == 0) { + if (videoFiles?.length === 0) { setIsVideoUploadFinish(true); } videoFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "2", "0"); }); - if (textFiles?.length == 0) { + if (textFiles?.length === 0) { setIsTextUploadFinish(true); } textFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "3", "0"); }); - if (audioFiles?.length == 0) { + if (audioFiles?.length === 0) { setIsAudioUploadFinish(true); } audioFiles?.map(async (item: any, index: number) => { await uploadResumableFile(index, String(id), item, "4", "0"); }); - - // Optional: Use Swal for success feedback - // MySwal.fire({ - // title: "Sukses", - // text: "Data berhasil disimpan.", - // icon: "success", - // confirmButtonColor: "#3085d6", - // confirmButtonText: "OK", - // }).then(() => { - // router.push("en/contributor/agenda-setting"); - // }); }; const onSubmit = (data: any) => { if ( (wilayahPublish.polda && selectedPolda.length === 0) || - (wilayahPublish.satker && selectedSatker.length === 0) + (wilayahPublish.satker && selectedSatker.length === 0) || + (wilayahPublish.polres && selectedPolres.length === 0) ) { toast({ title: "Pilih ID untuk Polda/Satker", @@ -524,6 +545,60 @@ const EventModal = ({ const handleRemoveFile = (id: number) => {}; + async function doDelete(id: any) { + loading(); + const resDelete = await deleteAgendaSettings(id); + if (resDelete?.error) { + error(resDelete.message); + return false; + } + close(); + successSubmitDelete("/in/contributor/agenda-setting"); + window.location.reload(); + } + + const handleDelete = (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); + } + }); + }; + + function successSubmitDelete(redirect: string) { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + if (redirect === window.location.pathname) { + fetch(redirect, { method: "GET", cache: "reload" }).then(() => { + console.log("Data diperbarui."); + }); + } else { + window.location.href = redirect; + } + }); + } + + const onReady = (ws: any) => { + setWavesurfer(ws); + setIsPlaying(false); + }; + + const onPlayPause = () => { + wavesurfer && wavesurfer.playPause(); + }; + return ( <>
-
+
)}
+
+ toggleWilayah("polres")} + /> + + {wilayahPublish.polres && ( + + setSelectedPolres(data) + } + /> + )} +
toggleWilayah("internasional")} + id="international" + checked={wilayahPublish.international} + onCheckedChange={() => toggleWilayah("international")} /> -
@@ -743,33 +837,6 @@ const EventModal = ({
- {videoUploadedFiles?.map((file: any, index: number) => ( -
-
-
- {renderFilePreview(file.url)} -
-
-
- {file.fileName} -
-
-
- - -
- ))} setImageFiles(files)} + onDrop={(files) => setVideoFiles(files)} /> + {videoUploadedFiles?.map((file: any, index: number) => ( +
+
+ ))}
- {imageUploadedFiles?.map((file: any, index: number) => ( -
-
-
- {renderFilePreview(file.url)} -
-
-
- {file.fileName} -
-
-
- - -
- ))} setImageFiles(files)} /> + {imageUploadedFiles?.map((file: any, index: number) => ( +
+ + Thumbnail Gambar Utama + +
+
+
+ {renderFilePreview(file.url)} +
+
+
+ {file.fileName} +
+
+
+ + +
+
+ ))}
- {textUploadedFiles?.map((file: any, index: number) => ( -
-
-
- {renderFilePreview(file.url)} -
-
-
- {file.fileName} -
-
-
- -
- ))} setTextFiles(files)} /> + {textUploadedFiles?.map((file: any, index: number) => ( +
+