mediahub-fe/app/[locale]/(protected)/contributor/agenda-setting/calender-view.tsx

352 lines
11 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import FullCalendar from "@fullcalendar/react"; // must go before plugins
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 ExternalDraggingevent from "./dragging-events";
import { Calendar } from "@/components/ui/calendar";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Plus } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { CalendarCategory } from "./data";
import { EventContentArg } from "@fullcalendar/core";
import EventModal from "./event-modal";
import { useTranslations } from "next-intl";
import { getAgendaSettingsList } from "@/service/agenda-setting/agenda-setting";
import dayjs from "dayjs";
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
interface CalendarViewProps {
events: CalendarEvent[];
categories: CalendarCategory[];
}
const INITIAL_YEAR = dayjs().format("YYYY");
const INITIAL_MONTH = dayjs().format("M");
export interface CalendarEvent {
id: string;
title: string;
start: Date;
end: Date;
allDay: boolean;
extendedProps: {
calendar: string;
description?: string;
};
}
export interface AgendaSettingsAPIResponse {
id: number;
title: string;
description: string;
agendaType: string;
startDate: string; // API mengembalikan tanggal dalam bentuk string
endDate: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
createdById: number | null;
createdByName: string | null;
}
interface APIResponse {
error: boolean;
message: any;
data: AgendaSettingsAPIResponse[] | null; // `data` bisa berupa array atau null
}
const CalendarView = ({ events, categories }: CalendarViewProps) => {
const [selectedCategory, setSelectedCategory] = useState<string[] | null>(
null
);
const [selectedEventDate, setSelectedEventDate] = useState<Date | null>(null);
// const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(
// null
// );
const [apiEvents, setApiEvents] = useState<CalendarEvent[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [draggableInitialized, setDraggableInitialized] =
useState<boolean>(false);
const t = useTranslations("CalendarApp");
// event canvas state
const [sheetOpen, setSheetOpen] = useState<boolean>(false);
const [date, setDate] = React.useState<Date>(new Date());
const [dragEvents] = useState([
{ title: "New Event Planning", id: "101", tag: "business" },
{ title: "Meeting", id: "102", tag: "meeting" },
{ title: "Generating Reports", id: "103", tag: "holiday" },
{ title: "Create New theme", id: "104", tag: "etc" },
]);
useEffect(() => {
getCalendarEvents();
});
const getCalendarEvents = async () => {
const res = await getAgendaSettingsList(INITIAL_YEAR, INITIAL_MONTH, "");
console.log("ress", res);
if (res.error) {
return false;
}
};
useEffect(() => {
setSelectedCategory(categories?.map((c) => c.value));
}, [events, categories]);
useEffect(() => {
console.log("Fetched events from API:", apiEvents);
}, [apiEvents]);
const filteredEvents = apiEvents?.filter((event) =>
selectedCategory?.includes(event.extendedProps.calendar)
);
const displayedEvents =
filteredEvents?.length > 0 ? filteredEvents : apiEvents;
useEffect(() => {
console.log("Filtered events based on category:", displayedEvents);
}, [filteredEvents, apiEvents]);
useEffect(() => {
setSelectedCategory(categories?.map((c) => c.value));
}, [categories]);
useEffect(() => {
console.log("Selected categories:", selectedCategory);
}, [selectedCategory]);
useEffect(() => {
const fetchAgendaEvents = async () => {
setLoading(true);
try {
const selectedMonth = new Date(); // Replace with your logic for selected month
const year = selectedMonth.getFullYear().toString();
const month = (selectedMonth.getMonth() + 1).toString();
const typeFilter = ""; // Replace with your type filter logic if needed
const response: APIResponse = await getAgendaSettingsList(
year,
month,
typeFilter
);
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,
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 {
console.warn("No events found in API response.");
setApiEvents([]);
}
} catch (error) {
console.error("Failed to fetch agenda settings:", error);
setApiEvents([]);
} finally {
setLoading(false);
}
};
fetchAgendaEvents();
}, []);
useEffect(() => {
const draggableEl = document.getElementById("external-events");
const initDraggable = () => {
if (draggableEl) {
new Draggable(draggableEl, {
itemSelector: ".fc-event",
eventData: function (eventEl) {
let title = eventEl.getAttribute("title");
let id = eventEl.getAttribute("data");
let event = dragEvents.find((e) => e.id === id);
let tag = event ? event.tag : "";
return {
title: title,
id: id,
extendedProps: {
calendar: tag,
},
};
},
});
}
};
if (dragEvents.length > 0) {
initDraggable();
}
return () => {
draggableEl?.removeEventListener("mousedown", initDraggable);
};
}, [dragEvents]);
// event click
const handleEventClick = (arg: any) => {
setSelectedEventDate(null);
setSheetOpen(true);
setApiEvents(arg);
wait().then(() => (document.body.style.pointerEvents = "auto"));
};
// handle close modal
const handleCloseModal = () => {
setSheetOpen(false);
setApiEvents([]);
setSelectedEventDate(null);
};
const handleDateClick = (arg: any) => {
setSheetOpen(true);
setSelectedEventDate(arg);
setApiEvents([]);
wait().then(() => (document.body.style.pointerEvents = "auto"));
};
const handleCategorySelection = (category: string) => {
if (selectedCategory && selectedCategory.includes(category)) {
setSelectedCategory(selectedCategory.filter((c) => c !== category));
} else {
setSelectedCategory([...(selectedCategory || []), category]);
}
};
const handleClassName = (arg: EventContentArg) => {
if (arg.event.extendedProps.calendar === "mabes") {
return "primary";
} 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 {
return "primary";
}
};
return (
<>
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
<Card className="col-span-12 lg:col-span-4 2xl:col-span-3 pb-5">
<CardContent className="p-0">
<CardHeader className="border-none mb-2 pt-5">
<Button
onClick={handleDateClick}
className="dark:bg-background dark:text-foreground"
>
<Plus className="w-4 h-4 me-1" />
{"Tambahkan Agenda baru"}
</Button>
</CardHeader>
<div className="px-3">
<Calendar
mode="single"
selected={date}
onSelect={(s) => {
handleDateClick(s);
}}
className="rounded-md border w-full p-0 border-none"
/>
</div>
{/* <div id="external-events" className=" space-y-1.5 mt-6 px-4">
<p className="text-sm font-medium text-default-700 mb-3">
{t("shortDesc")}
</p>
{dragEvents.map((event) => (
<ExternalDraggingevent key={event.id} event={event} />
))}
</div> */}
<div className="py-4 text-default-800 font-semibold text-xs uppercase mt-4 mb-2 px-4">
{t("filter")}
</div>
<ul className="space-y-3 px-4">
<li className=" flex gap-3">
<Checkbox
checked={selectedCategory?.length === categories?.length}
onClick={() => {
if (selectedCategory?.length === categories?.length) {
setSelectedCategory([]);
} else {
setSelectedCategory(categories.map((c) => c.value));
}
}}
/>
<Label>All</Label>
</li>
{categories?.map((category) => (
<li className="flex gap-3 " key={category.value}>
<Checkbox
className={category.className}
id={category.label}
checked={selectedCategory?.includes(category.value)}
onClick={() => handleCategorySelection(category.value)}
/>
<Label htmlFor={category.label}>{category.label}</Label>
</li>
))}
</ul>
</CardContent>
</Card>
<Card className="col-span-12 lg:col-span-8 2xl:col-span-9 pt-5">
<CardContent className="dashcode-app-calendar">
<FullCalendar
plugins={[
dayGridPlugin,
timeGridPlugin,
interactionPlugin,
listPlugin,
]}
headerToolbar={{
left: "prev,next today",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay,listWeek",
}}
events={displayedEvents}
editable={true}
rerenderDelay={10}
eventDurationEditable={false}
selectable={true}
selectMirror={true}
droppable={true}
dayMaxEvents={2}
weekends={true}
eventClassNames={handleClassName}
dateClick={handleDateClick}
eventClick={handleEventClick}
initialView="dayGridMonth"
/>
</CardContent>
</Card>
</div>
<EventModal
open={sheetOpen}
onClose={handleCloseModal}
categories={categories}
event={apiEvents}
selectedDate={selectedEventDate}
/>
</>
);
};
export default CalendarView;