working calendar, code may be messy
This commit is contained in:
+12
-10
@@ -72,16 +72,17 @@ export async function PUT(req: NextRequest) {
|
|||||||
{ status: HttpStatusCode.NotFound }
|
{ status: HttpStatusCode.NotFound }
|
||||||
);
|
);
|
||||||
|
|
||||||
database.schedules.insertOne({
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
message: 'ok',
|
||||||
|
id: (
|
||||||
|
await database.schedules.insertOne({
|
||||||
account: session.user,
|
account: session.user,
|
||||||
scheduled,
|
scheduled,
|
||||||
content,
|
content,
|
||||||
platforms,
|
platforms,
|
||||||
});
|
})
|
||||||
|
).insertedId,
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
message: 'ok',
|
|
||||||
},
|
},
|
||||||
{ status: HttpStatusCode.Ok }
|
{ status: HttpStatusCode.Ok }
|
||||||
);
|
);
|
||||||
@@ -128,12 +129,13 @@ export async function GET(req: NextRequest) {
|
|||||||
export async function DELETE(req: NextRequest) {
|
export async function DELETE(req: NextRequest) {
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const sessionId = url.searchParams.get('id');
|
const sessionId = url.searchParams.get('id');
|
||||||
const date = url.searchParams.get('date');
|
const schedule = url.searchParams.get('schedule');
|
||||||
|
|
||||||
if (typeof sessionId !== 'string' || typeof date !== 'string')
|
if (typeof sessionId !== 'string' || typeof schedule !== 'string')
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
message: 'Invalid structure, required param `id=` and `date=`',
|
message:
|
||||||
|
'Invalid structure, required param `id=` and `schedule=`',
|
||||||
},
|
},
|
||||||
{ status: HttpStatusCode.BadRequest }
|
{ status: HttpStatusCode.BadRequest }
|
||||||
);
|
);
|
||||||
@@ -151,8 +153,8 @@ export async function DELETE(req: NextRequest) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const result = await database.schedules.deleteMany({
|
const result = await database.schedules.deleteMany({
|
||||||
|
_id: new ObjectId(schedule),
|
||||||
account: session.user,
|
account: session.user,
|
||||||
scheduled: date,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.deletedCount === 0)
|
if (result.deletedCount === 0)
|
||||||
|
|||||||
+142
-76
@@ -8,112 +8,178 @@ import { ScheduleRemoveRequest } from '@/utils';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
import { PlusCircle, Trash } from 'lucide-react';
|
import { PlusCircle, Trash2 } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
export interface CalendarSchedule {
|
export interface CalendarSchedule {
|
||||||
date: Date;
|
date: Date;
|
||||||
platforms: { user: string }[];
|
platforms: { user: string }[];
|
||||||
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const weekdays = [
|
const weekdays: [string, number, number, number][] = [
|
||||||
'Mon',
|
['Mon', 2025, 2, 24],
|
||||||
'Tue',
|
['Tue', 2025, 2, 25],
|
||||||
'Wed',
|
['Wed', 2025, 2, 26],
|
||||||
'Thu',
|
['Thu', 2025, 2, 27],
|
||||||
'Fri',
|
['Fri', 2025, 2, 28],
|
||||||
'Sat',
|
['Sat', 2025, 2, 29],
|
||||||
'Sun',
|
['Sun', 2025, 3, 1],
|
||||||
];
|
];
|
||||||
|
|
||||||
const times = ['12 PM', '1 PM', '2 PM', '3 PM', '4 PM', '5 PM', '6 PM', '7 PM', '8 PM', '9 PM', '10 PM', '11 PM'];
|
const times: [string, number][] = [
|
||||||
|
['12 PM', 12],
|
||||||
|
['1 PM', 13],
|
||||||
|
['2 PM', 14],
|
||||||
|
['3 PM', 15],
|
||||||
|
['4 PM', 16],
|
||||||
|
['5 PM', 17],
|
||||||
|
['6 PM', 18],
|
||||||
|
['7 PM', 19],
|
||||||
|
['8 PM', 20],
|
||||||
|
['9 PM', 21],
|
||||||
|
['10 PM', 22],
|
||||||
|
['11 PM', 23],
|
||||||
|
];
|
||||||
|
|
||||||
export default function Calendar({
|
export default function Calendar({
|
||||||
setDialog,
|
setDialog,
|
||||||
sessionId,
|
sessionId,
|
||||||
events,
|
events,
|
||||||
|
setDate,
|
||||||
|
date,
|
||||||
|
setEvents,
|
||||||
}: {
|
}: {
|
||||||
setDialog: (b: boolean) => void;
|
setDialog: (b: boolean) => void;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
events: CalendarSchedule[];
|
events: CalendarSchedule[];
|
||||||
|
date: Date;
|
||||||
|
setDate: (d: Date) => void;
|
||||||
|
setEvents: (events: CalendarSchedule[]) => void;
|
||||||
}) {
|
}) {
|
||||||
const [selected, setSelected] = useState(0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="grid grid-cols-1 w-full h-20 mb-2">
|
<div className="grid grid-cols-1 w-full h-20 mb-2">
|
||||||
<div className="grid grid-cols-7 ml-20">
|
<div className="flex gap-2">
|
||||||
{weekdays.map((w, i) => (
|
{/* Times column */}
|
||||||
<div key={i} className="border">
|
<div className="w-20 flex flex-col gap-2">
|
||||||
<p className="w-max mx-auto">{w}</p>
|
<div className="h-24"></div>{' '}
|
||||||
|
{/* Empty space for alignment */}
|
||||||
|
<div className="grid grid-rows-10 h-full gap-2">
|
||||||
|
{times.map((t, j) => (
|
||||||
|
<div
|
||||||
|
key={j}
|
||||||
|
className="flex pr-2 h-16 border rounded-xl"
|
||||||
|
>
|
||||||
|
<p className="size-max m-auto">{t[0]}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 gap-2 w-full">
|
|
||||||
{times.map((w, i) => (
|
{/* Calendar grid */}
|
||||||
<div key={i} className="flex">
|
<div className="grid grid-cols-7 gap-2 flex-1">
|
||||||
<p className="w-20 border py-4">
|
{weekdays.map((w, i) => (
|
||||||
<p className="w-max mx-auto">{w}</p>
|
<div key={i} className="flex flex-col h-full gap-2">
|
||||||
|
<div className="border rounded-md h-24 flex">
|
||||||
|
<p className="size-max mx-auto">{w[0]}</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-rows-10 h-full gap-2">
|
||||||
|
{times.map((t, j) => {
|
||||||
|
const event = events.find((e) => {
|
||||||
|
console.log(
|
||||||
|
e.date.getHours(),
|
||||||
|
t[1]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
e.date.getFullYear() === w[1] &&
|
||||||
|
e.date.getMonth() === w[2] &&
|
||||||
|
e.date.getDate() === w[3] &&
|
||||||
|
e.date.getHours() === t[1]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ContextMenu key={j}>
|
||||||
|
<ContextMenuTrigger>
|
||||||
|
<div
|
||||||
|
className={`border rounded-xl w-full h-16 ${
|
||||||
|
event
|
||||||
|
? 'bg-primary/20'
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{event && (
|
||||||
|
<div className="p-2 text-sm flex items-center justify-center">
|
||||||
|
{/* <LampIcon className="h-6 w-6" /> */}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent>
|
||||||
|
<ContextMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setDialog(true);
|
||||||
|
setDate(
|
||||||
|
new Date(
|
||||||
|
w[1],
|
||||||
|
w[2],
|
||||||
|
w[3],
|
||||||
|
t[1],
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlusCircle className="mr-2 h-4 w-4" />
|
||||||
|
<p>New post</p>
|
||||||
|
</ContextMenuItem>
|
||||||
|
|
||||||
|
{event && (
|
||||||
|
<ContextMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
axios
|
||||||
|
.delete(
|
||||||
|
`/api/posts`,
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
id: sessionId,
|
||||||
|
schedule:
|
||||||
|
event.id,
|
||||||
|
} satisfies ScheduleRemoveRequest,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
() => {
|
||||||
|
setEvents(
|
||||||
|
events.filter(
|
||||||
|
(
|
||||||
|
e
|
||||||
|
) =>
|
||||||
|
e.id !==
|
||||||
|
event.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 className="mr-2 h-4 w-4 text-red-500" />
|
||||||
|
<p className="text-red-500">
|
||||||
|
Delete post
|
||||||
</p>
|
</p>
|
||||||
<div className="grid grid-cols-7 w-full ml-1">
|
</ContextMenuItem>
|
||||||
{weekdays.map((w, i) => (
|
)}
|
||||||
<div key={i} className="border py-4"></div>
|
</ContextMenuContent>
|
||||||
))}
|
</ContextMenu>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
// <div className="grid grid-cols-1 w-full">
|
|
||||||
// <div className="grid grid-cols-7">
|
|
||||||
// {weekdays.map((w, i) => (
|
|
||||||
// <div key={i}>
|
|
||||||
// <p className="w-max mx-auto">{w}</p>
|
|
||||||
// </div>
|
|
||||||
// ))}
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <ContextMenu>
|
|
||||||
// <ContextMenuTrigger></ContextMenuTrigger>
|
|
||||||
// <ContextMenuContent>
|
|
||||||
// <ContextMenuItem
|
|
||||||
// onClick={() => {
|
|
||||||
// setDialog(true);
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <PlusCircle className="w-4 mt-0.5" />{' '}
|
|
||||||
// <p className="ml-1">New post</p>
|
|
||||||
// </ContextMenuItem>
|
|
||||||
|
|
||||||
// {selected ? (
|
|
||||||
// <ContextMenuItem
|
|
||||||
// onClick={() => {
|
|
||||||
// if (selected) {
|
|
||||||
// axios.delete(`/api/posts`, {
|
|
||||||
// params: {
|
|
||||||
// id: sessionId,
|
|
||||||
// date: format(
|
|
||||||
// events[selected].date,
|
|
||||||
// 'y-MM-dd hh:mm'
|
|
||||||
// ),
|
|
||||||
// } satisfies ScheduleRemoveRequest,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }}
|
|
||||||
// className=""
|
|
||||||
// >
|
|
||||||
// <Trash className="w-4 mt-0.5 text-red-500" />{' '}
|
|
||||||
// <p className="ml-1 text-red-500">Delete</p>
|
|
||||||
// </ContextMenuItem>
|
|
||||||
// ) : (
|
|
||||||
// ''
|
|
||||||
// )}
|
|
||||||
// </ContextMenuContent>
|
|
||||||
// </ContextMenu>
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-41
@@ -1,59 +1,27 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react';
|
import { useEffect, useState } from '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 App from '@/components/app';
|
||||||
|
|
||||||
import { format, parse } from 'date-fns';
|
import { format, parse } from 'date-fns';
|
||||||
import PostDialog, { today } from './postDialog';
|
import PostDialog, { today } from './postDialog';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { Schedule, ScheduleRemoveRequest, ScheduleRequest } from '@/utils';
|
|
||||||
import Calendar, { CalendarSchedule } from './calendar';
|
import Calendar, { CalendarSchedule } from './calendar';
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CalendarApp() {
|
export default function CalendarApp() {
|
||||||
const eventsService = useState(() => createEventsServicePlugin())[0];
|
|
||||||
const dragAndDrop = useState(() => createDragAndDropPlugin())[0];
|
|
||||||
const [eventCount, setEventCount] = useState(0);
|
const [eventCount, setEventCount] = useState(0);
|
||||||
const sessionId = Cookies.get('session_id') || '';
|
const sessionId = Cookies.get('session_id') || '';
|
||||||
|
|
||||||
const calendar = useCalendarApp({
|
|
||||||
views: [createViewWeek()],
|
|
||||||
events: [],
|
|
||||||
plugins: [eventsService, dragAndDrop],
|
|
||||||
isDark: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [events, setEvents] = useState<CalendarSchedule[]>([]);
|
const [events, setEvents] = useState<CalendarSchedule[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get(`/api/posts/?id=${sessionId}`).then((response) => {
|
axios.get(`/api/posts/?id=${sessionId}`).then((response) => {
|
||||||
setEvents(response.data.schedules as CalendarSchedule[]);
|
const v = response.data.schedules.map((e: any) => ({
|
||||||
|
date: parse(e.scheduled, 'yyyy-MM-dd HH:mm', new Date()),
|
||||||
|
platforms: e.platforms,
|
||||||
|
id: e._id,
|
||||||
|
}));
|
||||||
|
setEvents(v);
|
||||||
setEventCount(response.data.schedules.length);
|
setEventCount(response.data.schedules.length);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -63,14 +31,14 @@ export default function CalendarApp() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<App>
|
<App>
|
||||||
<div>
|
<div className="flex flex-1 flex-col p-6 px-5 md:px-7 h-max">
|
||||||
<PostDialog
|
<PostDialog
|
||||||
date={date}
|
date={date}
|
||||||
setDate={setDate}
|
setDate={setDate}
|
||||||
newPostDialogOpen={postDialog}
|
newPostDialogOpen={postDialog}
|
||||||
setNewPostDialogOpen={setDialog}
|
setNewPostDialogOpen={setDialog}
|
||||||
setEvents={(e) => {
|
setEvents={(e) => {
|
||||||
calendar.events.add(e);
|
setEvents([...events, e]);
|
||||||
setEventCount(eventCount + 1);
|
setEventCount(eventCount + 1);
|
||||||
}}
|
}}
|
||||||
eventId={eventCount}
|
eventId={eventCount}
|
||||||
@@ -81,6 +49,9 @@ export default function CalendarApp() {
|
|||||||
setDialog={setDialog}
|
setDialog={setDialog}
|
||||||
sessionId={sessionId}
|
sessionId={sessionId}
|
||||||
events={events}
|
events={events}
|
||||||
|
date={date}
|
||||||
|
setDate={setDate}
|
||||||
|
setEvents={setEvents}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</App>
|
</App>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { Label } from '@/components/ui/label';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { PostRequest, ScheduleRequest } from '@/utils';
|
import { PostRequest, ScheduleRequest } from '@/utils';
|
||||||
|
import { CalendarSchedule } from './calendar';
|
||||||
|
|
||||||
type PostDialogProps = {
|
type PostDialogProps = {
|
||||||
newPostDialogOpen: boolean;
|
newPostDialogOpen: boolean;
|
||||||
@@ -33,7 +34,7 @@ type PostDialogProps = {
|
|||||||
date: Date;
|
date: Date;
|
||||||
setDate: (d: Date) => void;
|
setDate: (d: Date) => void;
|
||||||
eventId: number;
|
eventId: number;
|
||||||
setEvents: (e: CalendarEventExternal) => void;
|
setEvents: (e: CalendarSchedule) => void;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,24 +138,20 @@ export default function PostDialog({
|
|||||||
Post now
|
Post now
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
const end = new Date(date);
|
const { data } = await axios.put('/api/posts', {
|
||||||
end.setHours(date.getHours() + 1);
|
|
||||||
|
|
||||||
addEvent({
|
|
||||||
title: 'Post',
|
|
||||||
id: eventId,
|
|
||||||
start: format(date, 'y-MM-dd hh:mm'),
|
|
||||||
end: format(end, 'y-MM-dd hh:mm'),
|
|
||||||
});
|
|
||||||
|
|
||||||
axios.put('/api/posts', {
|
|
||||||
scheduled: format(date, 'y-MM-dd hh:mm'),
|
scheduled: format(date, 'y-MM-dd hh:mm'),
|
||||||
sessionId,
|
sessionId,
|
||||||
platforms: ['andjksds'],
|
platforms: ['andjksds'],
|
||||||
content,
|
content,
|
||||||
} satisfies ScheduleRequest);
|
} satisfies ScheduleRequest);
|
||||||
|
|
||||||
|
addEvent({
|
||||||
|
id: data.id,
|
||||||
|
date,
|
||||||
|
platforms: [{ user: 'andjksds' }],
|
||||||
|
});
|
||||||
|
|
||||||
setNewPostDialogOpen(false);
|
setNewPostDialogOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ export interface ScheduleRequest extends PostRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ScheduleRemoveRequest {
|
export interface ScheduleRemoveRequest {
|
||||||
date: string;
|
schedule: string;
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user