From 2f71ec5d72ab7c1ece65dcbc0b2155e7c3e842c5 Mon Sep 17 00:00:00 2001 From: Kevin Mok Date: Fri, 28 Mar 2025 14:02:51 -0400 Subject: [PATCH] Prev/next week buttons in header on desktop --- package.json | 4 +- src/components/Calendar.tsx | 57 +++++++------------------ src/components/CalendarHeader.tsx | 39 +++++++++++++++++ src/components/DayColumn.tsx | 69 +++++++++++++++++++++++++++++++ src/types.ts | 2 +- 5 files changed, 127 insertions(+), 44 deletions(-) create mode 100644 src/components/CalendarHeader.tsx create mode 100644 src/components/DayColumn.tsx diff --git a/package.json b/package.json index 4f2de91..f280bd8 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "tailwindcss": "^4", - "postcss": "^8.0.0", "autoprefixer": "^10.0.0", + "postcss": "^8.0.0", + "tailwindcss": "^4", "typescript": "^5" } } diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 5941a2f..1ed0356 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -18,6 +18,7 @@ import { useWindowSize } from '@/hooks/useWindowSize'; import EventModal from '@/components/EventModal'; import eventsData from '@/data/events'; import { Event, EventsByDate } from '@/types'; +import CalendarHeader from '@/components/CalendarHeader'; const Calendar = () => { const { width } = useWindowSize(); @@ -28,10 +29,7 @@ const Calendar = () => { const [direction, setDirection] = useState<'left' | 'right'>('left'); const [isEventDragging, setIsEventDragging] = useState(false); - const [currentDate, setCurrentDate] = useState(() => { - const now = new Date(); - return new Date(now.getFullYear(), now.getMonth(), now.getDate()); - }); + const [currentDate, setCurrentDate] = useState(new Date()); const [selectedEvent, setSelectedEvent] = useState(null); const [events, setEvents] = useState(eventsData); @@ -98,13 +96,13 @@ const Calendar = () => { return Array.from({ length: 7 }, (_, i) => addDays(start, i)); }; - const handlePreviousWeek = useCallback(() => { + const handlePrevWeek = () => { setCurrentDate(prev => addDays(prev, -7)); - }, []); + }; - const handleNextWeek = useCallback(() => { + const handleNextWeek = () => { setCurrentDate(prev => addDays(prev, 7)); - }, []); + }; useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { @@ -112,7 +110,7 @@ const Calendar = () => { if (event.key === 'ArrowLeft') { event.preventDefault(); - handlePreviousWeek(); + handlePrevWeek(); } else if (event.key === 'ArrowRight') { event.preventDefault(); handleNextWeek(); @@ -121,12 +119,12 @@ const Calendar = () => { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [handlePreviousWeek, handleNextWeek, selectedEvent]); + }, [handlePrevWeek, handleNextWeek, selectedEvent]); const handleSwipe = (dir: 'left' | 'right') => { if (isMobile) { setDirection(dir); - setCurrentDate(prev => dir === 'left' ? addDays(prev, 1) : addDays(prev, -1)); + setCurrentDate(prev => addDays(prev, dir === 'left' ? 7 : -7)); } }; @@ -178,9 +176,7 @@ const Calendar = () => { const handleDayChange = useCallback((direction: 'left' | 'right') => { setCurrentDate(prev => { const newDate = addDays(prev, direction === 'left' ? -1 : 1); - // Reset dragging state to enable future swipes setIsEventDragging(false); - // Smooth transition setOffset(direction === 'left' ? -window.innerWidth : window.innerWidth); setTimeout(() => setOffset(0), 10); return newDate; @@ -229,9 +225,10 @@ const Calendar = () => { return (
-
{isMobile && } @@ -375,6 +372,9 @@ const DayColumn = ({ return cleanup; }, [date]); + console.log('Date value:', date); + console.log('Is valid date:', date instanceof Date && !isNaN(date)); + return ( { - const weekRange = useMemo(() => { - if (!isMobile) return ''; - const start = startOfWeek(currentDate, { weekStartsOn: 0 }); - const end = addDays(start, 6); - return `${format(start, 'MMM d')} - ${format(end, 'MMM d')}`; - }, [currentDate, isMobile]); - - return ( -
-
-

- {isMobile ? weekRange : format(currentDate, 'MMMM yyyy')} -

-
-
- ); -}; - const WeekHeader = ({ currentDate }: { currentDate: Date }) => { const weekDays = useMemo(() => { const start = startOfWeek(currentDate, { weekStartsOn: 0 }); // Start week on Sunday diff --git a/src/components/CalendarHeader.tsx b/src/components/CalendarHeader.tsx new file mode 100644 index 0000000..cab9c65 --- /dev/null +++ b/src/components/CalendarHeader.tsx @@ -0,0 +1,39 @@ +import { format } from 'date-fns'; + +interface CalendarHeaderProps { + currentDate: Date; + onPrevWeek: () => void; + onNextWeek: () => void; +} + +function CalendarHeader({ currentDate, onPrevWeek, onNextWeek }: CalendarHeaderProps) { + return ( +
+ + +

+ {format(currentDate, 'MMMM yyyy')} +

+ + +
+ ); +} + +export default CalendarHeader; \ No newline at end of file diff --git a/src/components/DayColumn.tsx b/src/components/DayColumn.tsx new file mode 100644 index 0000000..38bfe4e --- /dev/null +++ b/src/components/DayColumn.tsx @@ -0,0 +1,69 @@ +import React, { useRef } from 'react'; +import { motion } from 'framer-motion'; +import { format, addDays } from 'date-fns'; +import { DraggableEvent } from './DraggableEvent'; + +interface DayColumnProps { + date: Date; + events: Event[]; + isMobile: boolean; + index: number; + onEventClick: (event: Event) => void; + onDragStart: (event: React.MouseEvent) => void; + onDragEnd: (event: React.MouseEvent) => void; + handleEventMove: (eventId: string, newDate: Date) => void; + onDayChange: (dir: 'left' | 'right') => void; + isClient: boolean; +} + +const DayColumn: React.FC = ({ + date, + events, + isMobile, + index, + onEventClick, + onDragStart, + onDragEnd, + handleEventMove, + onDayChange, + isClient +}) => { + const columnRef = useRef(null); + + const sortedEvents = [...events].sort((a, b) => a.start.getTime() - b.start.getTime()); + + return ( + +
+ {format(date, 'EEE, MMM d')} +
+ +
+ {sortedEvents + .filter(event => event && event.id) + .map((event, index) => ( + { + onDayChange(dir); + const newDate = addDays(date, dir === 'left' ? -1 : 1); + handleEventMove(event.id, newDate); + }} + isClient={isClient} + /> + ))} +
+
+ ); +}; + +export default DayColumn; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 11ae375..d08f6f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,7 +2,7 @@ export interface Event { id: string; title: string; time: string; - date: string; + date: Date; description?: string; imageUrl?: string; // add other properties as needed