Files
klayrion/src/app/calendar/page.tsx
T
2025-02-19 20:23:34 +01:00

193 lines
6.5 KiB
TypeScript

'use client';
import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react';
import { createViewWeek } from '@schedule-x/calendar';
import { createEventsServicePlugin } from '@schedule-x/events-service';
import { createDragAndDropPlugin } from '@schedule-x/drag-and-drop';
import '@/calendar-theme.css';
import { MouseEventHandler, useEffect, useState } from 'react';
import App from '@/components/app';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { PlusCircle, Trash } from 'lucide-react';
import { format, parse } from 'date-fns';
import PostDialog, { today } from './postDialog';
import axios from 'axios';
import Cookies from 'js-cookie';
import { Schedule } from '@/utils';
function closestChild(children: any, clientX: number, clientY: number) {
let closestElement = null;
let closestDistance = Infinity;
for (let child of children) {
const childRect = child.getBoundingClientRect();
const dx = Math.abs(clientX - (childRect.left + childRect.width / 2));
const dy = Math.abs(clientY - (childRect.top + childRect.height / 2));
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestElement = child;
}
}
return closestElement;
}
function CalendarApp() {
const eventsService = useState(() => createEventsServicePlugin())[0];
const dragAndDrop = useState(() => createDragAndDropPlugin())[0];
const [eventCount, setEventCount] = useState(0);
const sessionId = Cookies.get('session_id') || '';
const calendar = useCalendarApp({
views: [createViewWeek()],
events: [],
plugins: [eventsService, dragAndDrop],
isDark: true,
});
useEffect(() => {
axios.get(`/api/posts/?id=${sessionId}`).then((response) => {
for (const [id, sched] of (
response.data.schedules as Schedule[]
).entries()) {
const date = parse(
sched.scheduled,
'y-MM-dd hh:mm',
new Date()
);
const end = new Date(date);
end.setHours(date.getHours() + 1);
calendar.events.add({
title: 'Post',
id,
start: format(date, 'y-MM-dd hh:mm'),
end: format(end, 'y-MM-dd hh:mm'),
});
setEventCount(eventCount + 1);
}
});
}, []);
const [newPostDialogOpen, setNewPostDialogOpen] = useState(false);
const [date, setDate] = useState<Date>(today);
const [selected, setSelected] = useState<string | null | undefined>(null);
const handleDialog: MouseEventHandler<HTMLSpanElement> = (event) => {
const target = event.target as HTMLElement;
if (target.className === 'sx__time-grid-event-time') {
const id =
target.parentElement?.parentElement?.getAttribute(
'data-event-id'
);
setSelected(id);
setDate(
parse(
calendar.events.get(parseInt(id || ''))?.start || '',
'y-MM-dd hh:mm',
new Date()
)
);
} else {
setSelected(null);
try {
const dayElement = target.closest('.sx__time-grid-day');
const dayText = dayElement
? dayElement.getAttribute('aria-label')
: null;
const hourElement = closestChild(
target.parentElement?.children[0].children || [],
event.clientX,
event.clientY
);
if (!dayText || !hourElement) {
event.preventDefault();
} else {
const toDate = parse(
(dayText || '') +
' ' +
(hourElement?.textContent || ''),
'MMMM dd, yyyy h a',
new Date()
);
if (toDate instanceof Date && !isNaN(toDate.getTime()))
setDate(toDate);
}
} catch {}
}
};
return (
<App>
<div>
<PostDialog
date={date}
setDate={setDate}
newPostDialogOpen={newPostDialogOpen}
setNewPostDialogOpen={setNewPostDialogOpen}
setEvents={(e) => {
calendar.events.add(e);
setEventCount(eventCount + 1);
}}
eventId={eventCount}
/>
<ContextMenu>
<ContextMenuTrigger onContextMenu={handleDialog}>
<ScheduleXCalendar
calendarApp={calendar}
customComponents={{}}
/>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
onClick={() => {
setNewPostDialogOpen(true);
}}
>
<PlusCircle className="w-4 mt-0.5" />{' '}
<p className="ml-1">New post</p>
</ContextMenuItem>
{selected ? (
<ContextMenuItem
onClick={() => {
if (selected) {
calendar.events.remove(
parseInt(selected)
);
}
}}
className=""
>
<Trash className="w-4 mt-0.5 text-red-500" />{' '}
<p className="ml-1 text-red-500">Delete</p>
</ContextMenuItem>
) : (
''
)}
</ContextMenuContent>
</ContextMenu>
</div>
</App>
);
}
export default CalendarApp;