From 2c0cd3c42d717a357b108bf52bc519389bcd9a86 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Tue, 18 Feb 2025 09:26:00 +0100 Subject: [PATCH] calendar delete and bug fixes --- src/app/calendar/page.tsx | 120 ++++++++++++++++++++++------------ src/components/app.tsx | 59 ++++++++++------- src/components/postDialog.tsx | 30 ++++++++- src/components/timeSelect.tsx | 9 ++- 4 files changed, 143 insertions(+), 75 deletions(-) diff --git a/src/app/calendar/page.tsx b/src/app/calendar/page.tsx index 88f3339..b8783bf 100644 --- a/src/app/calendar/page.tsx +++ b/src/app/calendar/page.tsx @@ -1,6 +1,6 @@ 'use client'; import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react'; -import { createViewWeek } from '@schedule-x/calendar'; +import { CalendarEventExternal, createViewWeek } from '@schedule-x/calendar'; import { createEventsServicePlugin } from '@schedule-x/events-service'; import { createDragAndDropPlugin } from '@schedule-x/drag-and-drop'; @@ -15,74 +15,85 @@ import { ContextMenuTrigger, } from '@/components/ui/context-menu'; -import { PlusCircle } from 'lucide-react'; +import { PlusCircle, Trash } from 'lucide-react'; -import { parse } from 'date-fns'; +import { format, parse } from 'date-fns'; import PostDialog, { today } from '@/components/postDialog'; +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 calendar = useCalendarApp({ views: [createViewWeek()], - events: [ - { - id: '1', - title: 'Linus tech tips drama', - start: '2025-02-16 01:00', - end: '2025-02-16 02:00', - }, - ], + events: [], plugins: [eventsService, dragAndDrop], isDark: true, }); - useEffect(() => {}, [eventsService]); - const [newPostDialogOpen, setNewPostDialogOpen] = useState(false); const [date, setDate] = useState(today); + const [selected, setSelected] = useState(null); const handleDialog: MouseEventHandler = (event) => { const target = event.target as HTMLElement; - let hourElement = null; - let closestDistance = Infinity; - const children = target.parentElement?.children[0].children || []; - - for (let child of children) { - const childRect = child.getBoundingClientRect(); - const dx = Math.abs( - event.clientX - (childRect.left + childRect.width / 2) + if (target.className === 'sx__time-grid-event-time') { + setSelected( + target.parentElement?.parentElement?.getAttribute( + 'data-event-id' + ) ); - const dy = Math.abs( - event.clientY - (childRect.top + childRect.height / 2) - ); - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance < closestDistance) { - closestDistance = distance; - hourElement = child; - } + return; + } else { + setSelected(null); } - const dayElement = target.closest('.sx__time-grid-day'); + try { + const dayElement = target.closest('.sx__time-grid-day'); - const dayText = dayElement - ? dayElement.getAttribute('aria-label') - : null; + const dayText = dayElement + ? dayElement.getAttribute('aria-label') + : null; - if (!dayText || !hourElement) { - event.preventDefault(); - } else { - setDate( - parse( + 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 ( @@ -93,6 +104,11 @@ function CalendarApp() { setDate={setDate} newPostDialogOpen={newPostDialogOpen} setNewPostDialogOpen={setNewPostDialogOpen} + setEvents={(e) => { + calendar.events.add(e); + setEventCount(eventCount + 1); + }} + eventId={eventCount} /> @@ -108,8 +124,26 @@ function CalendarApp() { }} > {' '} -

New post

x +

New post

+ + {selected ? ( + { + if (selected) { + calendar.events.remove( + parseInt(selected) + ); + } + }} + className="" + > + {' '} +

Delete

+
+ ) : ( + '' + )}
diff --git a/src/components/app.tsx b/src/components/app.tsx index b835cb8..7a0302f 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -1,8 +1,9 @@ 'use client'; import * as React from 'react'; -import { Menu, ChevronDown, ChevronRight } from 'lucide-react'; +import { Menu } from 'lucide-react'; import { Button } from '@/components/ui/button'; +import { usePathname } from 'next/navigation'; import { Sheet, SheetContent, @@ -10,12 +11,6 @@ import { SheetTitle, SheetTrigger, } from '@/components/ui/sheet'; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from '@/components/ui/collapsible'; -import { cn } from '@/lib/utils'; import { SidebarContent, @@ -57,6 +52,7 @@ const footer = [ export function HamburgerMenu() { const [open, setOpen] = React.useState(false); + const pathname = usePathname(); return ( @@ -71,7 +67,11 @@ export function HamburgerMenu() { {items.map((item, i) => (
- + {pathname === item.url ? ( + + ) : ( + + )}
))} @@ -81,7 +81,11 @@ export function HamburgerMenu() { {footer.map((item, i) => ( - + {pathname === item.url ? ( + + ) : ( + + )} ))} @@ -92,6 +96,7 @@ export function HamburgerMenu() { export default function App({ children }: { children?: any }) { const isSmall = useSmallScreen(); + const pathname = usePathname(); return isSmall ? (
@@ -100,7 +105,11 @@ export default function App({ children }: { children?: any }) { {items.map((item, i) => (
- + {pathname === item.url ? ( + + ) : ( + + )}
))} @@ -110,28 +119,22 @@ export default function App({ children }: { children?: any }) { {footer.map((item, i) => (
- + {pathname === item.url ? ( + + ) : ( + + )}
))}
- {/* {items.map((item, i) => ( -
- - - -
- ))} */} {children} ) : (
- + @@ -146,7 +149,11 @@ export default function App({ children }: { children?: any }) { className="w-16 mx-auto" > - + {pathname === item.url ? ( + + ) : ( + + )} ))} @@ -162,7 +169,11 @@ export default function App({ children }: { children?: any }) { className="w-16 mx-auto" > - + {pathname === item.url ? ( + + ) : ( + + )} ))} diff --git a/src/components/postDialog.tsx b/src/components/postDialog.tsx index c781cb5..03e1682 100644 --- a/src/components/postDialog.tsx +++ b/src/components/postDialog.tsx @@ -1,6 +1,7 @@ import { Dialog, DialogContent, + DialogDescription, DialogFooter, DialogHeader, DialogTitle, @@ -17,12 +18,15 @@ import { format } from 'date-fns'; import { CalendarIcon } from 'lucide-react'; import { Calendar } from './ui/calendar'; import TimeSelect from './timeSelect'; +import { CalendarEventExternal } from '@schedule-x/calendar'; type PostDialogProps = { newPostDialogOpen: boolean; setNewPostDialogOpen: (b: boolean) => void; date: Date; setDate: (d: Date) => void; + eventId: number; + setEvents: (e: CalendarEventExternal) => void; }; export const today = new Date(); @@ -33,12 +37,15 @@ export default function PostDialog({ setNewPostDialogOpen, date, setDate, + setEvents, + eventId, }: PostDialogProps) { return ( - Feature not available + New post + Schedule posts on multiple accounts
@@ -63,7 +70,7 @@ export default function PostDialog({ selected={date} onSelect={(d: Date | undefined) => { if (d) { - const newDate = new Date(d); // Clone d + const newDate = new Date(d); newDate.setHours( date.getHours(), date.getMinutes(), @@ -93,7 +100,24 @@ export default function PostDialog({ > Cancel - +
diff --git a/src/components/timeSelect.tsx b/src/components/timeSelect.tsx index 837519c..991f2a1 100644 --- a/src/components/timeSelect.tsx +++ b/src/components/timeSelect.tsx @@ -23,19 +23,18 @@ const TimeSelect: React.FC = ({ setDate, className, }) => { - // Generate time options for all hours (00-23) with minutes (15, 30, 45) const times = Array.from({ length: 24 }, (_, h) => - [15, 30, 45].map((m) => `${h.toString().padStart(2, '0')}:${m}`) + [0, 15, 30, 45].map((m) => `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`) ).flat(); const currentHour = date.getHours().toString().padStart(2, '0'); const currentMinute = date.getMinutes(); - const nearestMinute = [15, 30, 45].reduce((prev, curr) => + const nearestMinute = [0, 15, 30, 45].reduce((prev, curr) => Math.abs(curr - currentMinute) < Math.abs(prev - currentMinute) ? curr : prev ); - const selectedTime = `${currentHour}:${nearestMinute}`; + const selectedTime = `${currentHour}:${nearestMinute.toString().padStart(2, '0')}`; const handleTimeChange = (newTime: string) => { const [hour, minute] = newTime.split(':').map(Number); @@ -65,4 +64,4 @@ const TimeSelect: React.FC = ({ ); }; -export default TimeSelect; +export default TimeSelect; \ No newline at end of file