diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 44d6631..49a959c 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -20,6 +20,8 @@ import eventsData from '@/data/events'; import { Event, EventsByDate } from '@/types'; import CalendarHeader from '@/components/CalendarHeader'; import DraggableEvent from './DraggableEvent'; +import WeekHeader from '@/components/WeekHeader'; +import DayColumn from '@/components/DayColumn'; const Calendar = () => { const { width } = useWindowSize(); @@ -296,149 +298,4 @@ const Calendar = () => { ); }; -interface DayColumnProps { - date: Date; - events: Event[]; - isMobile: boolean; - index: number; - onEventClick: (eventData: { event: Event; date: string }) => void; - onDragStart: () => void; - onDragEnd: () => void; - handleEventMove: (eventId: string, newDate: Date) => void; - onDayChange: (direction: 'left' | 'right') => void; - isClient: boolean; -} - -const DayColumn = ({ - date, - events, - onDragStart, - onDragEnd, - onEventClick, - handleEventMove, - onDayChange, - isClient -}: DayColumnProps) => { - const columnRef = useRef(null); - const { width } = useWindowSize(); - const [isMobile, setIsMobile] = useState(false); - - const parseTimeToMinutes = (time: string) => { - const [timePart, modifier] = time.split(' '); - let [hours, minutes] = timePart.split(':').map(Number); - - if (modifier === 'PM' && hours !== 12) { - hours += 12; // Convert PM times to 24-hour format - } - if (modifier === 'AM' && hours === 12) { - hours = 0; // Handle midnight (12:00 AM) - } - - return hours * 60 + minutes; - }; - - const sortedEvents = useMemo(() => { - const seenIds = new Set(); - return [...events] - .sort((a, b) => parseTimeToMinutes(a.time) - parseTimeToMinutes(b.time)) - .filter(event => { - if (seenIds.has(event.id)) { - //console.warn(`Duplicate event ID detected: ${event.id}`); - return false; - } - seenIds.add(event.id); - return true; - }); - }, [events]); - - useEffect(() => { - setIsMobile(width < 768); // Update isMobile after hydration - }, [width]); - - const dayOffset = differenceInDays(date, startOfWeek(date)); - const isActive = isMobile ? true : true; - - useEffect(() => { - const element = columnRef.current; - if (!element) return; - - const cleanup = dropTargetForElements({ - element, - getData: () => ({ date: format(date, 'yyyy-MM-dd') }), - }); - - return cleanup; - }, [date]); - - console.log('Date value:', date); - console.log('Is valid date:', date instanceof Date && !isNaN(date.getTime())); - - return ( - -
- {format(date, 'EEE, MMM d')} -
- -
- {sortedEvents - .filter(event => event && event.id) // Filter out invalid events - .map((event, index) => ( - { - onDayChange(dir); - const newDate = addDays(date, dir === 'left' ? -1 : 1); - handleEventMove(event.id, newDate); - }} - isClient={isClient} - /> - ))} -
-
- ); -}; - -const WeekHeader = ({ currentDate }: { currentDate: Date }) => { - const weekDays = useMemo(() => { - const start = startOfWeek(currentDate, { weekStartsOn: 0 }); // Start week on Sunday - return Array.from({ length: 7 }, (_, i) => addDays(start, i)); - }, [currentDate]); - - return ( -
- {weekDays.map((day, index) => ( - -
-
- {format(day, 'EEE')} -
-
- {format(day, 'd')} -
-
-
- ))} -
- ); -}; - export default Calendar; diff --git a/src/components/DayColumn.tsx b/src/components/DayColumn.tsx index b868f29..979aa05 100644 --- a/src/components/DayColumn.tsx +++ b/src/components/DayColumn.tsx @@ -1,53 +1,88 @@ -import React, { useRef } from 'react'; +import { useRef, useEffect, useMemo, useState } from 'react'; import { motion } from 'framer-motion'; -import { format, addDays } from 'date-fns'; +import { format, differenceInDays, startOfWeek, addDays } from 'date-fns'; +import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; import DraggableEvent from './DraggableEvent'; -import { Event } from '../types'; +import { useWindowSize } from '@/hooks/useWindowSize'; +import { Event } from '@/types'; interface DayColumnProps { date: Date; events: Event[]; - isMobile: boolean; - index: number; onEventClick: (eventData: { event: Event; date: string }) => void; onDragStart: () => void; onDragEnd: () => void; handleEventMove: (eventId: string, newDate: Date) => void; - onDayChange: (dir: 'left' | 'right') => void; + onDayChange: (direction: 'left' | 'right') => void; isClient: boolean; } -const DayColumn: React.FC = ({ - date, - events, - isMobile, - index, - onEventClick, - onDragStart, +const DayColumn = ({ + date, + events, + onDragStart, onDragEnd, + onEventClick, handleEventMove, onDayChange, isClient -}) => { +}: DayColumnProps) => { const columnRef = useRef(null); + const { width } = useWindowSize(); + const [isMobile, setIsMobile] = useState(false); + + const parseTimeToMinutes = (time: string) => { + const [timePart, modifier] = time.split(' '); + let [hours, minutes] = timePart.split(':').map(Number); - const sortedEvents = [...events].sort((a, b) => { - const timeA = new Date(a.time).getTime(); - const timeB = new Date(b.time).getTime(); - return timeA - timeB; - }); + if (modifier === 'PM' && hours !== 12) { + hours += 12; + } + if (modifier === 'AM' && hours === 12) { + hours = 0; + } - const handleMove = (dir: 'up' | 'down') => { - // ... existing code ... + return hours * 60 + minutes; }; + const sortedEvents = useMemo(() => { + const seenIds = new Set(); + return [...events] + .sort((a, b) => parseTimeToMinutes(a.time) - parseTimeToMinutes(b.time)) + .filter(event => { + if (seenIds.has(event.id)) { + return false; + } + seenIds.add(event.id); + return true; + }); + }, [events]); + + useEffect(() => { + setIsMobile(width < 768); + }, [width]); + + const dayOffset = differenceInDays(date, startOfWeek(date)); + + useEffect(() => { + const element = columnRef.current; + if (!element) return; + + const cleanup = dropTargetForElements({ + element, + getData: () => ({ date: format(date, 'yyyy-MM-dd') }), + }); + + return cleanup; + }, [date]); + return ( -
+
{format(date, 'EEE, MMM d')}
@@ -59,9 +94,9 @@ const DayColumn: React.FC = ({ key={event.id} event={event} date={format(date, 'yyyy-MM-dd')} - onEventClick={(eventData) => onEventClick({ event: eventData.event, date: eventData.date })} - onDragStart={() => onDragStart()} - onDragEnd={() => onDragEnd()} + onEventClick={onEventClick} + onDragStart={onDragStart} + onDragEnd={onDragEnd} onDayChange={(dir) => { onDayChange(dir); const newDate = addDays(date, dir === 'left' ? -1 : 1); diff --git a/src/components/WeekHeader.tsx b/src/components/WeekHeader.tsx new file mode 100644 index 0000000..323e06c --- /dev/null +++ b/src/components/WeekHeader.tsx @@ -0,0 +1,43 @@ +import { useMemo } from 'react'; +import { motion } from 'framer-motion'; +import { format, addDays, startOfWeek, isSameDay } from 'date-fns'; + +interface WeekHeaderProps { + currentDate: Date; +} + +const WeekHeader = ({ currentDate }: WeekHeaderProps) => { + const weekDays = useMemo(() => { + const start = startOfWeek(currentDate, { weekStartsOn: 0 }); + return Array.from({ length: 7 }, (_, i) => addDays(start, i)); + }, [currentDate]); + + return ( +
+ {weekDays.map((day, index) => ( + +
+
+ {format(day, 'EEE')} +
+
+ {format(day, 'd')} +
+
+
+ ))} +
+ ); +}; + +export default WeekHeader; \ No newline at end of file