12 changed files with 4564 additions and 454 deletions
			
			
		- 
					3.eslintrc.json
 - 
					77mock-data.ts
 - 
					4668package-lock.json
 - 
					5package.json
 - 
					109src/components/Calendar.tsx
 - 
					25src/components/DayColumn.tsx
 - 
					97src/components/DraggableEvent.tsx
 - 
					14src/components/EventModal.tsx
 - 
					2src/data/events.ts
 - 
					2src/types.ts
 - 
					14src/types/index.ts
 - 
					2tsconfig.json
 
@ -0,0 +1,3 @@ | 
				
			|||
{ | 
				
			|||
  "extends": "next" | 
				
			|||
} | 
				
			|||
@ -1,77 +0,0 @@ | 
				
			|||
interface Event { | 
				
			|||
id: string; | 
				
			|||
title: string; | 
				
			|||
description: string; | 
				
			|||
imageUrl: string; | 
				
			|||
time: string; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
interface EventsByDate { | 
				
			|||
[date: string]: Event[]; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
const events: EventsByDate = { | 
				
			|||
"2024-03-11": [ | 
				
			|||
{ | 
				
			|||
id: "event-1", | 
				
			|||
title: "Coffee with Alex", | 
				
			|||
description: | 
				
			|||
"Meet with Alex to brainstorm ideas for the upcoming product | 
				
			|||
launch. We'll review market research and competitor analysis to identify | 
				
			|||
potential opportunities and challenges.", | 
				
			|||
imageUrl: | 
				
			|||
"https://fastly.picsum.photos/id/312/1920/1080.jpg?hmac=OD_fP9MUQN7uJ8NBR7t
 | 
				
			|||
lii78qwHPUROGgohG4w16Kjw", | 
				
			|||
time: "09:00 AM", | 
				
			|||
}, | 
				
			|||
{ | 
				
			|||
id: "event-2", | 
				
			|||
title: "Team Standup", | 
				
			|||
description: | 
				
			|||
"Weekly standup meeting with the dev team. Discuss progress, | 
				
			|||
blockers, and align on next week's priorities.", | 
				
			|||
imageUrl: | 
				
			|||
"http://fastly.picsum.photos/id/737/1920/1080.jpg?hmac=aFzER8Y4wcWTrXVx2wVK
 | 
				
			|||
Sj10IqnygaF33gESj0WGDwI", | 
				
			|||
time: "02:00 PM", | 
				
			|||
 | 
				
			|||
}, | 
				
			|||
], | 
				
			|||
"2024-03-12": [ | 
				
			|||
{ | 
				
			|||
id: "event-3", | 
				
			|||
title: "Yoga Session", | 
				
			|||
description: | 
				
			|||
"Join for a relaxing yoga session to reduce stress and improve | 
				
			|||
mindfulness. Suitable for all levels, focusing on gentle stretches.", | 
				
			|||
imageUrl: | 
				
			|||
"https://fastly.picsum.photos/id/392/1920/1080.jpg?hmac=Fvbf7C1Rcozg8EccwYP
 | 
				
			|||
qsGkk_o6Bld2GQRDPZKWpd7g", | 
				
			|||
time: "12:00 PM", | 
				
			|||
}, | 
				
			|||
{ | 
				
			|||
id: "event-4", | 
				
			|||
title: "Product Demo", | 
				
			|||
description: | 
				
			|||
"Demo of UI improvements and performance optimizations to gather | 
				
			|||
stakeholder feedback.", | 
				
			|||
imageUrl: | 
				
			|||
"https://fastly.picsum.photos/id/249/1920/1080.jpg?hmac=cPMNdgGXRh6T_KhRMua
 | 
				
			|||
QjRtAx5cWRraELjtL2MHTfYs", | 
				
			|||
time: "03:30 PM", | 
				
			|||
}, | 
				
			|||
], | 
				
			|||
"2024-03-13": [ | 
				
			|||
{ | 
				
			|||
id: "event-5", | 
				
			|||
title: "Client Meeting", | 
				
			|||
description: | 
				
			|||
"Review project progress, timeline adjustments, and outline roadmap | 
				
			|||
for next quarter with the client.", | 
				
			|||
imageUrl: | 
				
			|||
"https://fastly.picsum.photos/id/908/1920/1080.jpg?hmac=MeG_oA1s75hHAL_4JzC
 | 
				
			|||
ioh6--zyFTWSCTxOhe8ugvXo", | 
				
			|||
time: "11:30 AM", | 
				
			|||
}, | 
				
			|||
], | 
				
			|||
}; | 
				
			|||
						
							
						
						
							4668
	
						
						package-lock.json
						
							File diff suppressed because it is too large
							
							
								
									View File
								
							
						
					
				File diff suppressed because it is too large
							
							
								
									View File
								
							
						@ -0,0 +1,97 @@ | 
				
			|||
import { useRef, useState, useEffect } from 'react'; | 
				
			|||
import { motion } from 'framer-motion'; | 
				
			|||
import { Event } from '../types'; | 
				
			|||
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; | 
				
			|||
 | 
				
			|||
interface DraggableEventProps { | 
				
			|||
  event: Event; | 
				
			|||
  date: string; | 
				
			|||
  onEventClick: (eventData: { event: Event; date: string }) => void; | 
				
			|||
  onDragStart: () => void; | 
				
			|||
  onDragEnd: () => void; | 
				
			|||
  onDayChange: (direction: 'left' | 'right') => void; | 
				
			|||
  isClient: boolean; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default function DraggableEvent({ | 
				
			|||
  event, | 
				
			|||
  date, | 
				
			|||
  onEventClick, | 
				
			|||
  onDragStart, | 
				
			|||
  onDragEnd, | 
				
			|||
  onDayChange, | 
				
			|||
  isClient | 
				
			|||
}: DraggableEventProps) { | 
				
			|||
  const ref = useRef<HTMLDivElement>(null); | 
				
			|||
  const [isDragging, setIsDragging] = useState(false); | 
				
			|||
  const screenWidth = useRef(isClient ? window.innerWidth : 0); | 
				
			|||
  const lastChangeTime = useRef(0); | 
				
			|||
 | 
				
			|||
  useEffect(() => { | 
				
			|||
    const element = ref.current; | 
				
			|||
    if (!element) return; | 
				
			|||
 | 
				
			|||
    const cleanup = draggable({ | 
				
			|||
      element, | 
				
			|||
      onDragStart: () => { | 
				
			|||
        screenWidth.current = window.innerWidth; | 
				
			|||
        setIsDragging(true); | 
				
			|||
        onDragStart(); | 
				
			|||
        lastChangeTime.current = Date.now(); | 
				
			|||
      }, | 
				
			|||
      onDrag: ({ location }) => { | 
				
			|||
        const currentX = location.current.input.clientX; | 
				
			|||
        const now = Date.now(); | 
				
			|||
         | 
				
			|||
        if (now - lastChangeTime.current > 500) { | 
				
			|||
          if (currentX < 50) { | 
				
			|||
            lastChangeTime.current = now; | 
				
			|||
            onDayChange('left'); | 
				
			|||
          } else if (currentX > screenWidth.current - 50) { | 
				
			|||
            lastChangeTime.current = now; | 
				
			|||
            onDayChange('right'); | 
				
			|||
          } | 
				
			|||
        } | 
				
			|||
      }, | 
				
			|||
      onDrop: () => { | 
				
			|||
        setIsDragging(false); | 
				
			|||
        onDragEnd(); | 
				
			|||
      }, | 
				
			|||
      getInitialData: () => ({ id: event.id, date }), | 
				
			|||
      dragHandle: element | 
				
			|||
    }); | 
				
			|||
 | 
				
			|||
    return cleanup; | 
				
			|||
  }, [date, event.id, onDragEnd, onDragStart, onDayChange]); | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <motion.div | 
				
			|||
      ref={ref} | 
				
			|||
      layoutId={event.id} | 
				
			|||
      onClick={() => !isDragging && onEventClick({ event, date })} | 
				
			|||
      className="bg-white p-4 rounded shadow mb-2 cursor-grab active:cursor-grabbing transition-all relative select-none" | 
				
			|||
      whileHover={{ scale: 1.01 }} | 
				
			|||
      style={{ | 
				
			|||
        opacity: isDragging ? 0.7 : 1, | 
				
			|||
        userSelect: 'none', | 
				
			|||
        WebkitUserSelect: 'none', | 
				
			|||
        touchAction: 'manipulation' | 
				
			|||
      }} | 
				
			|||
    > | 
				
			|||
      <div className="relative rounded overflow-hidden mb-2"> | 
				
			|||
        {event.imageUrl && ( | 
				
			|||
          <img  | 
				
			|||
            src={event.imageUrl}  | 
				
			|||
            alt={event.title} | 
				
			|||
            className="w-full h-16 md:h-12 object-cover pointer-events-none" | 
				
			|||
            draggable="false" | 
				
			|||
          /> | 
				
			|||
        )} | 
				
			|||
        <div className="absolute top-1 right-1 bg-black/50 text-white text-xs px-2 py-1 rounded"> | 
				
			|||
          {event.time} | 
				
			|||
        </div> | 
				
			|||
      </div> | 
				
			|||
      <h3 className="font-medium text-black">{event.title}</h3> | 
				
			|||
    </motion.div> | 
				
			|||
  ); | 
				
			|||
}  | 
				
			|||
@ -1,14 +0,0 @@ | 
				
			|||
console.log('Types module loaded'); | 
				
			|||
interface Event { | 
				
			|||
  id: string; | 
				
			|||
  title: string; | 
				
			|||
  description: string; | 
				
			|||
  imageUrl: string; | 
				
			|||
  time: string; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
interface EventsByDate { | 
				
			|||
  [date: string]: Event[]; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default { Event, EventsByDate }; | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue