improved calendar design

This commit is contained in:
2025-03-04 16:51:59 +01:00
parent 0e663ce24e
commit 5735dc906d
3 changed files with 123 additions and 182 deletions
+83 -143
View File
@@ -1,191 +1,131 @@
export interface CalendarSchedule {
date: Date;
platforms: { user: string }[];
id: string;
}
import { import {
ContextMenu, ContextMenu,
ContextMenuContent, ContextMenuContent,
ContextMenuItem, ContextMenuItem,
ContextMenuTrigger, ContextMenuTrigger,
} from '@/components/ui/context-menu'; } from '@/components/ui/context-menu';
import { PlusCircle, Trash2 } from 'lucide-react';
import axios from 'axios'; import axios from 'axios';
import { Pencil, PlusCircle, Trash } from 'lucide-react';
import React from 'react';
export interface CalendarSchedule { const hours = Array.from({ length: 24 }, (_, i) => `${i}:00`);
date: Date; const days = [
platforms: { user: string }[]; 'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
];
export interface Event {
time: Date;
title: string;
id: string; id: string;
} }
// Function to get the current week's dates (Monday - Sunday) interface CalendarProps {
const getCurrentWeek = (): { label: string; date: Date }[] => { events: Event[];
const today = new Date(); setDate: (date: Date) => void;
const dayOfWeek = today.getDay(); // 0 (Sun) - 6 (Sat) setDialog: (dialog: boolean) => void;
const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // Adjust for Monday start setEvents: (events: Event[]) => void;
}
return Array.from({ length: 7 }, (_, i) => { const Calendar: React.FC<CalendarProps> = ({
const date = new Date(today);
date.setDate(today.getDate() + mondayOffset + i);
return {
label: date.toLocaleDateString('en-US', { weekday: 'short' }), // 'Mon', 'Tue', etc.
date,
};
});
};
// Time slots from 12 PM to 11 PM
const times: { label: string; hour: number }[] = Array.from(
{ length: 12 },
(_, i) => ({
label: `${(i + 12) % 12 || 12} PM`, // '12 PM', '1 PM', ..., '11 PM'
hour: i + 12,
})
);
export default function Calendar({
setDialog,
events, events,
setDate, setDate,
setDialog,
setEvents, setEvents,
}: { }) => {
setDialog: (b: boolean) => void;
events: CalendarSchedule[];
setDate: (d: Date) => void;
setEvents: (events: CalendarSchedule[]) => void;
}) {
const weekdays = getCurrentWeek();
return ( return (
<div className="flex flex-col"> <div className="grid grid-cols-[auto,repeat(7,1fr)] border text-center text-sm">
<div className="grid grid-cols-1 w-full h-20 mb-2"> <div className="border p-2 font-bold">Time</div>
<div className="flex gap-2"> {days.map((day) => (
{/* Time Labels */} <div key={day} className="border p-2 font-bold">
<div className="w-20 flex flex-col gap-2"> {day}
<div className="h-24"></div>{' '}
{/* Empty space for alignment */}
<div className="grid grid-rows-12 h-full gap-2">
{times.map((time) => (
<div
key={time.hour}
className="flex pr-2 h-16 border rounded-xl"
>
<p className="size-max m-auto">
{time.label}
</p>
</div> </div>
))} ))}
</div>
</div>
{/* Calendar Grid */} {hours.map((hour, rowIdx) => (
<div className="grid grid-cols-7 gap-2 flex-1"> <React.Fragment key={hour}>
{weekdays.map((weekday) => ( <div className="border p-2">{hour}</div>
<div
key={weekday.date.toDateString()}
className="flex flex-col h-full gap-2"
>
{/* Day Header */}
<div className="border rounded-md h-24 flex">
<p className="size-max mx-auto">
{weekday.label}
</p>
</div>
{/* Time Slots */} {days.map((_, colIdx) => {
<div className="grid grid-rows-12 h-full gap-2">
{times.map((time) => {
const event = events.find( const event = events.find(
(e) => (e: Event) =>
e.date.getFullYear() === e.time.getDay() === colIdx &&
weekday.date.getFullYear() && e.time.getHours() === rowIdx
e.date.getMonth() ===
weekday.date.getMonth() &&
e.date.getDate() ===
weekday.date.getDate() &&
e.date.getHours() === time.hour
); );
if (!event) {
return ( return (
<ContextMenu <ContextMenu key={`${colIdx}-${rowIdx}`}>
key={`${weekday.date.toDateString()}-${ <ContextMenuTrigger asChild>
time.hour <div className="relative border h-16"></div>
}`} </ContextMenuTrigger>
> <ContextMenuContent>
<ContextMenuTrigger> <ContextMenuItem
<div onClick={() => {
className={`border rounded-xl w-full h-16 ${ setDate(
event new Date(2024, 3, 4, rowIdx)
? 'bg-primary/20' );
: '' setDialog(true);
}`} }}
> >
<PlusCircle className="w-4 h-4 mr-1" />
New Post
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
);
}
return (
<ContextMenu key={`${colIdx}-${rowIdx}`}>
<ContextMenuTrigger asChild>
<div className="relative border h-16">
{event && ( {event && (
<div className="p-2 text-sm flex items-center justify-center"> <div className="absolute inset-0 bg-blue-500 text-white p-1 text-xs rounded">
{/* Event indicator */} {event.title}
</div> </div>
)} )}
</div> </div>
</ContextMenuTrigger> </ContextMenuTrigger>
<ContextMenuContent> <ContextMenuContent>
<ContextMenuItem <ContextMenuItem>
onClick={() => { <Pencil className="w-4 h-4 mr-1" />
setDialog(true); Edit
setDate(
new Date(
weekday.date.getFullYear(),
weekday.date.getMonth(),
weekday.date.getDate(),
time.hour,
0,
0
)
);
}}
>
<PlusCircle className="mr-2 h-4 w-4" />
<p>New post</p>
</ContextMenuItem> </ContextMenuItem>
{event && (
<ContextMenuItem <ContextMenuItem
className="text-red-600"
onClick={() => { onClick={() => {
axios axios.delete(
.delete( `/api/posts?schedule=${event.id}`
`/api/posts`, );
{
params: {
schedule:
event.id,
},
}
)
.then(
() => {
setEvents( setEvents(
events.filter( events.filter(
( (e) => e.id !== event.id
e
) =>
e.id !==
event.id
) )
); );
}
);
}} }}
> >
<Trash2 className="mr-2 h-4 w-4 text-red-500" /> <Trash className="w-4 h-4 mr-1" />
<p className="text-red-500"> Delete
Delete post
</p>
</ContextMenuItem> </ContextMenuItem>
)}
</ContextMenuContent> </ContextMenuContent>
</ContextMenu> </ContextMenu>
); );
})} })}
</div> </React.Fragment>
</div>
))} ))}
</div> </div>
</div>
</div>
</div>
); );
} };
export default Calendar;
+6 -5
View File
@@ -7,12 +7,12 @@ 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 Calendar, { CalendarSchedule } from './calendar'; import Calendar, { CalendarSchedule, Event } from './calendar';
import { DATE_FORMAT } from '@/lib/types'; import { DATE_FORMAT } from '@/lib/types';
export default function CalendarApp() { export default function CalendarApp() {
const sessionId = Cookies.get('session_id') || ''; const sessionId = Cookies.get('session_id') || '';
const [events, setEvents] = useState<CalendarSchedule[]>([]); const [events, setEvents] = useState<Event[]>([]);
useEffect(() => { useEffect(() => {
axios axios
@@ -20,10 +20,11 @@ export default function CalendarApp() {
withCredentials: true, withCredentials: true,
}) })
.then((response) => { .then((response) => {
const v = response.data.schedules.map((e: any) => ({ const v: Event[] = response.data.schedules.map((e: any) => ({
date: parse(e.scheduled, DATE_FORMAT, new Date()), time: parse(e.scheduled, DATE_FORMAT, new Date()),
platforms: e.platforms, platforms: e.platforms,
id: e._id, id: e._id,
title: 'Post',
})); }));
setEvents(v); setEvents(v);
}) })
@@ -43,7 +44,7 @@ export default function CalendarApp() {
setDate={setDate} setDate={setDate}
newPostDialogOpen={postDialog} newPostDialogOpen={postDialog}
setNewPostDialogOpen={setDialog} setNewPostDialogOpen={setDialog}
setEvents={(e) => { addEvents={(e) => {
setEvents([...events, e]); setEvents([...events, e]);
}} }}
/> />
+5 -5
View File
@@ -26,14 +26,14 @@ import { Label } from '@/components/ui/label';
import { useState } from 'react'; import { useState } from 'react';
import axios from 'axios'; import axios from 'axios';
import { DATE_FORMAT, PostRequest, ScheduleRequest } from '@/lib/types'; import { DATE_FORMAT, PostRequest, ScheduleRequest } from '@/lib/types';
import { CalendarSchedule } from './calendar'; import { CalendarSchedule, Event } from './calendar';
type PostDialogProps = { type PostDialogProps = {
newPostDialogOpen: boolean; newPostDialogOpen: boolean;
setNewPostDialogOpen: (b: boolean) => void; setNewPostDialogOpen: (b: boolean) => void;
date: Date; date: Date;
setDate: (d: Date) => void; setDate: (d: Date) => void;
setEvents: (e: CalendarSchedule) => void; addEvents: (e: Event) => void;
}; };
export const today = new Date(); export const today = new Date();
@@ -44,7 +44,7 @@ export default function PostDialog({
setNewPostDialogOpen, setNewPostDialogOpen,
date, date,
setDate, setDate,
setEvents: addEvent, addEvents: addEvent,
}: PostDialogProps) { }: PostDialogProps) {
const [content, setContent] = useState(''); const [content, setContent] = useState('');
@@ -154,8 +154,8 @@ export default function PostDialog({
addEvent({ addEvent({
id: data.id, id: data.id,
date, time: date,
platforms: [{ user: 'andjksds' }], title: 'New Post',
}); });
setNewPostDialogOpen(false); setNewPostDialogOpen(false);