"use client"; import React, { useState, useEffect } from "react"; import FullCalendar from "@fullcalendar/react"; import dayGridPlugin from "@fullcalendar/daygrid"; import timeGridPlugin from "@fullcalendar/timegrid"; import interactionPlugin, { Draggable } from "@fullcalendar/interaction"; import listPlugin from "@fullcalendar/list"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Calendar } from "@/components/ui/calendar"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Book, CheckCheck, Plus, Timer } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { EventContentArg } from "@fullcalendar/core"; import EventModal from "./event-modal"; import { useTranslations } from "next-intl"; import dayjs from "dayjs"; import { getCookiesDecrypt } from "@/lib/utils"; import { CalendarCategory } from "./data"; import { error } from "@/config/swal"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { getAgendaSettingsList } from "@/service/agenda-settings/agenda-setting"; const wait = () => new Promise((resolve) => setTimeout(resolve, 1000)); interface CalendarViewProps { categories: CalendarCategory[]; } export type CalendarEvent = { id: string; title: string; start: Date; end: Date; createBy: string; createdByName: string; isPublish: boolean | null; allDay: boolean; extendedProps: { calendar: string; description: string; isPublish?: boolean; createdByName?: string; }; }; export interface AgendaSettingsAPIResponse { id: number; title: string; createdByName: string; description: string; agendaType: string; startDate: string; endDate: string; isActive: boolean; isPublish: boolean; createdAt: string; updatedAt: string; createdById: number | null; } interface YearlyData { january?: AgendaSettingsAPIResponse[]; february?: AgendaSettingsAPIResponse[]; march?: AgendaSettingsAPIResponse[]; april?: AgendaSettingsAPIResponse[]; may?: AgendaSettingsAPIResponse[]; june?: AgendaSettingsAPIResponse[]; july?: AgendaSettingsAPIResponse[]; august?: AgendaSettingsAPIResponse[]; september?: AgendaSettingsAPIResponse[]; october?: AgendaSettingsAPIResponse[]; november?: AgendaSettingsAPIResponse[]; december?: AgendaSettingsAPIResponse[]; } interface MonthCardProps { monthId: keyof YearlyData; label: string; } interface ListItemProps { item: AgendaSettingsAPIResponse; text: string; createdBy: string; isPublish: boolean | null; bgColor: string; colorList: string[] | null; } interface APIResponse { success: boolean; message: string; data: YearlyData | null; errorCode: string | null; } type EventType = "0" | "1" | "2" | "3" | "4" | "5"; const INITIAL_YEAR = dayjs().format("YYYY"); const INITIAL_MONTH = dayjs().format("M"); const CalendarView = ({ categories }: CalendarViewProps) => { const [selectedCategory, setSelectedCategory] = useState([]); const [selectedEventDate, setSelectedEventDate] = useState(null); const roleId = Number(getCookiesDecrypt("urie")) || 0; const levelNumber = Number(getCookiesDecrypt("ulne")) || 0; const userLevelId = Number(getCookiesDecrypt("ulie")) || 0; const [calendarEvents, setCalendarEvents] = useState([]); const [isLoading, setIsLoading] = useState(false); const t = useTranslations("CalendarApp"); const [sheetOpen, setSheetOpen] = useState(false); const [date, setDate] = useState(new Date()); const [activeView, setActiveView] = useState("listYear"); const [yearlyData, setYearlyData] = useState({}); const [open, setOpen] = useState(false); const [selectedEventData, setSelectedEventData] = useState(null); const [selectedMonth, setSelectedMonth] = useState( dayjs(new Date(Number(INITIAL_YEAR), Number(INITIAL_MONTH) - 1, 1)) ); useEffect(() => { if (activeView === "listYear") { getYearlyEvents(); } else { getCalendarEvents(); } }, [activeView, selectedMonth]); useEffect(() => { if (categories?.length > 0) { setSelectedCategory(categories.map((c) => c.value)); } }, [categories]); const getCalendarEvents = async () => { setIsLoading(true); try { const res = await getAgendaSettingsList( selectedMonth?.format("YYYY") || INITIAL_YEAR, selectedMonth.format("M") || INITIAL_MONTH, "" ); if (res?.error) { error(res?.message || "Failed to fetch events"); return; } const monthData = res?.data?.data; if (monthData) { const allEvents: CalendarEvent[] = []; const events = monthData?.map((event: any) => ({ id: event.id.toString(), title: event.title, createBy: event.createdById, createdByName: event.createdByName, start: new Date(event.startDate), end: new Date(event.endDate), allDay: true, extendedProps: { isPublish: event.isPublish, calendar: event.agendaType, description: event.description, createdByName: event.createdByName, }, })); console.log("Event Data : ", events); setCalendarEvents(events); } } catch (err) { console.error("Failed to fetch calendar events:", err); error("Failed to fetch calendar events"); } finally { setIsLoading(false); } }; const getYearlyEvents = async () => { setIsLoading(true); try { const res = await getAgendaSettingsList( selectedMonth?.format("YYYY") || INITIAL_YEAR, "", "" ); if (res?.error) { error(res?.message || "Failed to fetch yearly events"); return; } const yearlyData = res?.data?.data; if (yearlyData) { setYearlyData(yearlyData); } } catch (err) { console.error("Failed to fetch yearly events:", err); error("Failed to fetch yearly events"); } finally { setIsLoading(false); } }; const filteredEvents = calendarEvents.filter((event) => { if (!selectedCategory.length) return false; console.log("Event category : ", selectedCategory); const eventCategories = event.extendedProps.calendar ?.split(",") .map((val: string) => val.trim()); const allCategoryId = ["1", "2", "3", "4", "5"]; const hasAllCategories = allCategoryId.every((categoryId) => selectedCategory.includes(categoryId) ); return eventCategories?.some( (cat: string) => selectedCategory.includes(cat) || (hasAllCategories && cat == "0") ); }); const handleEventClick = (arg: any) => { setSelectedEventDate(null); setSelectedEventData(arg); setSheetOpen(true); wait().then(() => (document.body.style.pointerEvents = "auto")); }; const handleCloseModal = () => { setSheetOpen(false); setSelectedEventData(null); setSelectedEventDate(null); }; const handleDateClick = (arg: any) => { setSheetOpen(true); setSelectedEventDate(arg); setSelectedEventData(null); wait().then(() => (document.body.style.pointerEvents = "auto")); }; const handleCategorySelection = (category: string) => { setSelectedCategory((prev) => { if (prev.includes(category)) { return prev.filter((c) => c !== category); } else { return [...prev, category]; } }); }; const handleDateChange = (startDate: string, endDate: string) => { const startDateOfDate = new Date(startDate); setSelectedMonth(dayjs(startDateOfDate)); }; const handleViewChange = (viewType: string) => { setActiveView(viewType); }; const handleClickListItem = (item: AgendaSettingsAPIResponse) => { const formattedEvent: CalendarEvent = { id: item.id.toString(), title: item.title, start: new Date(item.startDate), end: new Date(item.endDate), createBy: item.createdById?.toString() || "", createdByName: item.createdByName, isPublish: item.isPublish, allDay: true, extendedProps: { calendar: item.agendaType, description: item.description, isPublish: item.isPublish, createdByName: item.createdByName, }, }; const eventArg = { event: formattedEvent }; setSelectedEventDate(null); setSelectedEventData(eventArg); setSheetOpen(true); wait().then(() => (document.body.style.pointerEvents = "auto")); }; const getEventColor = (type: EventType): string => { const typeSplit = type.split(","); const firstType = typeSplit[0] as EventType; const colors: Record = { "0": "bg-gray-500", "1": "bg-yellow-500", "2": "bg-blue-400", "3": "bg-slate-400", "4": "bg-orange-500", "5": "bg-green-400", }; return colors[firstType] || "bg-gray-400"; }; const getEventColorList = (type: EventType): string[] | null => { const typeSplit = type.split(","); const typeList = typeSplit.slice(1); if (typeList.length === 0) return null; const colors: Record = { "0": "bg-black", "1": "bg-yellow-500", "2": "bg-blue-400", "3": "bg-slate-400", "4": "bg-orange-500", "5": "bg-green-400", }; return typeList.map((item) => colors[item as EventType] || "bg-gray-200"); }; const renderEventContent = (eventInfo: any) => { const { title } = eventInfo.event; const { createdByName, isPublish, calendar } = eventInfo.event.extendedProps; const bgColor = getEventColor(calendar); const colorList = getEventColorList(calendar); return (
{isPublish === true ? ( ) : ( )}

{title}

Created By: {createdByName}

{colorList && colorList.length > 0 && (
{colorList.map((color: string, index: number) => (
))}
)}
); }; const handleClassName = (arg: EventContentArg) => { const eventColor = getEventColor(arg.event.extendedProps.calendar); return eventColor || "primary"; }; // Components const ListItem: React.FC = ({ item, text, createdBy, isPublish, bgColor, colorList, }) => (
handleClickListItem(item)} >
{isPublish ? : }

{text}

Created By: {createdBy}

{colorList && colorList.length > 0 && (
{colorList.map((color: string, index: number) => (
))}
)}
); const MonthCard: React.FC = ({ monthId, label }) => { const events = yearlyData[monthId] || []; const displayedEvents = events.slice(0, 3); const hasMoreEvents = events.length > 3; return (

{label}

{events.length === 0 ? (

{t("no-data-yet", { defaultValue: "No Data Yet" })}

) : ( <> {displayedEvents.map((event, index) => ( ))} {hasMoreEvents && ( {label}
{events.map((event, index) => ( ))}
)} )}
); }; 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" }, ]; const getModalContent = () => (
{isLoading ? (

Loading...

) : (
No Ticket Number Date and Time Title Status
1 MIA - 001 23/01/2025 13:00 Daily Issue 25 Januari 2025 Completed
)}
); return ( <>
{/* {[3, 11, 2, 12].includes(roleId) && ( )} */} {/* {[3, 11, 2, 12].includes(roleId) && levelNumber !== 3 && ( */} {/* )} */} {/* {roleId === 3 && userLevelId === 216 && ( */} {t("monitoring-results", { defaultValue: "Monitoring Results", })} {getModalContent()} {/* )} */}
{ if (selectedDate) { setDate(selectedDate); handleDateClick(selectedDate); } }} className="rounded-md border w-full p-0 border-none border-black" />
{t("filter", { defaultValue: "Filter" })}
  • { if (selectedCategory.length === categories.length) { setSelectedCategory([]); } else { setSelectedCategory(categories.map((c) => c.value)); } }} />
  • {categories.map((category) => (
  • handleCategorySelection(category.value) } />
  • ))}
handleViewChange(info.view.type)} datesSet={(info: any) => { handleDateChange(info.view.currentStart, info.view.currentEnd); handleViewChange(info.view.type); }} viewClassNames={ activeView === "listYear" ? "hide-calendar-grid" : "" } /> {activeView === "listYear" && (
{[0, 3, 6, 9].map((startIndex) => (
{months.slice(startIndex, startIndex + 3).map((month) => ( ))}
))}
)}
); }; export default CalendarView;