import { FC, useEffect, useRef, useState } from "react"; import FullCalendar from "@fullcalendar/react"; import dayGridPlugin from "@fullcalendar/daygrid"; import { ChevronLeftIcon, ChevronRightIcon, RoundedButton, } from "./Datepicker/components/utils"; import { dayDate, formatDay, monthYearDate } from "@/lib/utils/date"; import { X } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "./dialog"; import { Calender } from "@/lib/svg/Calender"; interface PopupPos { x: number; y: number; } export const CalenderGoogle: FC<{ events: any[] }> = ({ events }) => { const [showDialog, setShowDialog] = useState(false as boolean); const [canClose, setCanClose] = useState(true as boolean); const [detailDialog, setDetailDialog] = useState({ title: "Judul", start: new Date(), end: new Date(), allDay: true, color: "#2196f3", backgroundColor: "#2196f3", extendedProps: { id: 1, pic: [ { id: 1, name: "Karyawan 1" }, { id: 2, name: "Karyawan 2" }, { id: 3, name: "Karyawan 3" }, ], }, } as any); const calendarRef = useRef(null); const [popupPos, setPopupPos] = useState({ x: 0, y: 0 }); const [showPopup, setShowPopup] = useState(false); const [listMore, setListMore] = useState([] as any[]); const [now, setNow] = useState(new Date()); const [detailDate, setDetailDate] = useState(new Date()); const handlePrev = () => { const calendarApi = calendarRef.current?.getApi(); calendarApi?.prev(); setNow(calendarApi?.getDate() || new Date()); }; const handleNext = () => { const calendarApi = calendarRef.current?.getApi(); calendarApi?.next(); setNow(calendarApi?.getDate() || new Date()); }; const handleToday = () => { const calendarApi = calendarRef.current?.getApi(); calendarApi?.today(); }; const joinDayString = (day1: any, day2: any, split?: string) => { const label = day1 || day2; if (day1 && day2) { return `${day1} ${split || "-"} ${day2}`; } return label; }; const joinString = (data: any[], split?: string) => { const label = data?.length ? data.map((e) => e?.name) : []; return label.join(`${split || " ,"}`); }; return (
{ setShowDialog(e); setTimeout(() => { setCanClose(true); }, 100); }} > { setShowDialog(false); setTimeout(() => { setCanClose(true); }, 100); }} > Event

{detailDialog.title || "No title"}

{formatDay(detailDialog?.start, "YYYY") === formatDay(detailDialog?.end, "YYYY") ? joinDayString( formatDay(detailDialog?.start, "DD MMMM"), formatDay(detailDialog?.end, "DD MMMM, YYYY") ) : joinDayString( formatDay(detailDialog?.start, "DD MMMM YYYY"), formatDay(detailDialog?.end, "DD MMMM YYYY") )}

{detailDialog?.extendedProps?.pic?.length ? (

{joinString(detailDialog?.extendedProps?.pic)}

) : ( <> )}
{monthYearDate(now)}
{ return formatDay(arg.date, "DD MMMM YYYY") === formatDay(new Date(), "DD MMMM YYYY") ? cx( "!bg-transparent ", css` .fc-daygrid-day-number { } ` ) : ""; }} dayCellContent={(arg) => { const isToday = formatDay(arg.date, "DD MMMM YYYY") === formatDay(new Date(), "DD MMMM YYYY"); return ( {arg.dayNumberText} ); }} moreLinkClick={(info: any) => { const clickedDate = info.date; setDetailDate(clickedDate); const allEvents = info.allSegs.map( (seg: any) => seg?.eventRange?.def?.extendedProps || seg?.eventRange?.def ); const linkRect = info.jsEvent.target.getBoundingClientRect(); setPopupPos({ x: linkRect.left + window.scrollX, y: linkRect.top + window.scrollY, }); const list = [] as any[]; info.allSegs.map((info: any) => { const event = info?.event; list.push(event); }); setListMore(list); setShowPopup(true); return "none"; // Mencegah FullCalendar pindah ke tampilan hari }} // Ketika klik event eventClick={(info: any) => { const event = info?.event; setDetailDialog(event); setShowDialog(true); setCanClose(true); // setSelectedEvent(info.event); // setShowEventPopup(true); }} /> {showPopup && ( { if (canClose) { setShowPopup(false); } }} popupPos={popupPos} >
{dayDate(detailDate)}
setShowPopup(false)} >
{listMore.map((evt, idx) => { console.log(evt); return (
{ setDetailDialog(evt); setShowDialog(true); setCanClose(false); }} > {evt?.title}
); })}
)}
); }; interface CenteredPopupProps { children: React.ReactNode; onClose: () => void; popupPos: PopupPos; } const CenteredPopup: React.FC = ({ children, onClose, popupPos, }) => { const popupRef = useRef(null); const [adjustedPos, setAdjustedPos] = useState({ top: popupPos.y, left: popupPos.x, }); const [classname, setClassname] = useState(null as any); useEffect(() => { setClassname(css` top: ${popupPos.y}px; left: ${popupPos.x}px; transform: translate(-50%, -50%); `); }, []); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( popupRef.current && !popupRef.current.contains(event.target as Node) ) { onClose(); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, [onClose]); useEffect(() => { if (popupRef.current) { const rect = popupRef.current.getBoundingClientRect(); let newY = popupPos.y; let newX = popupPos.x; // Jika bagian bawah popup melebihi tinggi viewport, geser ke atas if (newY + rect.height > window.innerHeight) { newY = window.innerHeight - rect.height - 10; // beri margin 10px setClassname(css` bottom: 0; left: ${popupPos.x}px; transform: translateX(-50%); `); } } }, [popupPos]); return (
{children}
); };