{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "full-calendar",
  "type": "registry:block",
  "title": "Full Calendar",
  "description": "A full calendar component for scheduling events.",
  "dependencies": [
    "motion",
    "date-fns",
    "re-resizable",
    "zod",
    "react-hook-form",
    "@hookform/resolvers",
    "class-variance-authority",
    "clsx",
    "cmdk",
    "framer-motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "alert-dialog",
    "avatar",
    "badge",
    "button",
    "calendar",
    "command",
    "dialog",
    "dropdown-menu",
    "form",
    "input",
    "label",
    "popover",
    "scroll-area",
    "select",
    "skeleton",
    "sonner",
    "switch",
    "textarea",
    "toggle",
    "tooltip",
    "tabs",
    "https://calendar.jeraidi.dev/r/avatar-group.json",
    "https://calendar.jeraidi.dev/r/day-picker.json",
    "https://calendar.jeraidi.dev/r/date-time-picker.json",
    "https://calendar.jeraidi.dev/r/responsive-modal.json",
    "https://calendar.jeraidi.dev/r/button-group.json"
  ],
  "files": [
    {
      "path": "src/features/calendar/contexts/calendar-context.tsx",
      "content": "\"use client\";\n\nimport type React from \"react\";\nimport { createContext, useContext, useState } from \"react\";\nimport { useLocalStorage } from \"@/features/calendar/hooks\";\nimport type { IEvent, IUser } from \"@/features/calendar/interfaces\";\nimport type { TCalendarView, TEventColor } from \"@/features/calendar/types\";\n\ninterface ICalendarContext {\n  selectedDate: Date;\n  view: TCalendarView;\n  setView: (view: TCalendarView) => void;\n  agendaModeGroupBy: \"date\" | \"color\";\n  setAgendaModeGroupBy: (groupBy: \"date\" | \"color\") => void;\n  use24HourFormat: boolean;\n  toggleTimeFormat: () => void;\n  setSelectedDate: (date: Date | undefined) => void;\n  selectedUserId: IUser[\"id\"] | \"all\";\n  setSelectedUserId: (userId: IUser[\"id\"] | \"all\") => void;\n  badgeVariant: \"dot\" | \"colored\";\n  setBadgeVariant: (variant: \"dot\" | \"colored\") => void;\n  selectedColors: TEventColor[];\n  filterEventsBySelectedColors: (colors: TEventColor) => void;\n  filterEventsBySelectedUser: (userId: IUser[\"id\"] | \"all\") => void;\n  users: IUser[];\n  events: IEvent[];\n  addEvent: (event: IEvent) => void;\n  updateEvent: (event: IEvent) => void;\n  removeEvent: (eventId: number) => void;\n  clearFilter: () => void;\n}\n\ninterface CalendarSettings {\n  badgeVariant: \"dot\" | \"colored\";\n  view: TCalendarView;\n  use24HourFormat: boolean;\n  agendaModeGroupBy: \"date\" | \"color\";\n}\n\nconst DEFAULT_SETTINGS: CalendarSettings = {\n  badgeVariant: \"colored\",\n  view: \"day\",\n  use24HourFormat: true,\n  agendaModeGroupBy: \"date\",\n};\n\nconst CalendarContext = createContext({} as ICalendarContext);\n\nexport function CalendarProvider({\n  children,\n  users,\n  events,\n  badge = \"colored\",\n  view = \"day\",\n}: {\n  children: React.ReactNode;\n  users: IUser[];\n  events: IEvent[];\n  view?: TCalendarView;\n  badge?: \"dot\" | \"colored\";\n}) {\n  const [settings, setSettings] = useLocalStorage<CalendarSettings>(\n    \"calendar-settings\",\n    {\n      ...DEFAULT_SETTINGS,\n      badgeVariant: badge,\n      view: view,\n    },\n  );\n\n  const [badgeVariant, setBadgeVariantState] = useState<\"dot\" | \"colored\">(\n    settings.badgeVariant,\n  );\n  const [currentView, setCurrentViewState] = useState<TCalendarView>(\n    settings.view,\n  );\n  const [use24HourFormat, setUse24HourFormatState] = useState<boolean>(\n    settings.use24HourFormat,\n  );\n  const [agendaModeGroupBy, setAgendaModeGroupByState] = useState<\n    \"date\" | \"color\"\n  >(settings.agendaModeGroupBy);\n\n  const [selectedDate, setSelectedDate] = useState(new Date());\n  const [selectedUserId, setSelectedUserId] = useState<IUser[\"id\"] | \"all\">(\n    \"all\",\n  );\n  const [selectedColors, setSelectedColors] = useState<TEventColor[]>([]);\n\n  const [allEvents, setAllEvents] = useState<IEvent[]>(events || []);\n  const [filteredEvents, setFilteredEvents] = useState<IEvent[]>(events || []);\n\n  const updateSettings = (newPartialSettings: Partial<CalendarSettings>) => {\n    setSettings({\n      ...settings,\n      ...newPartialSettings,\n    });\n  };\n\n  const setBadgeVariant = (variant: \"dot\" | \"colored\") => {\n    setBadgeVariantState(variant);\n    updateSettings({ badgeVariant: variant });\n  };\n\n  const setView = (newView: TCalendarView) => {\n    setCurrentViewState(newView);\n    updateSettings({ view: newView });\n  };\n\n  const toggleTimeFormat = () => {\n    const newValue = !use24HourFormat;\n    setUse24HourFormatState(newValue);\n    updateSettings({ use24HourFormat: newValue });\n  };\n\n  const setAgendaModeGroupBy = (groupBy: \"date\" | \"color\") => {\n    setAgendaModeGroupByState(groupBy);\n    updateSettings({ agendaModeGroupBy: groupBy });\n  };\n\n  const filterEventsBySelectedColors = (color: TEventColor) => {\n    const isColorSelected = selectedColors.includes(color);\n    const newColors = isColorSelected\n      ? selectedColors.filter((c) => c !== color)\n      : [...selectedColors, color];\n\n    if (newColors.length > 0) {\n      const filtered = allEvents.filter((event) => {\n        const eventColor = event.color || \"blue\";\n        return newColors.includes(eventColor);\n      });\n      setFilteredEvents(filtered);\n    } else {\n      setFilteredEvents(allEvents);\n    }\n\n    setSelectedColors(newColors);\n  };\n\n  const filterEventsBySelectedUser = (userId: IUser[\"id\"] | \"all\") => {\n    setSelectedUserId(userId);\n    if (userId === \"all\") {\n      setFilteredEvents(allEvents);\n    } else {\n      const filtered = allEvents.filter((event) => event.user.id === userId);\n      setFilteredEvents(filtered);\n    }\n  };\n\n  const handleSelectDate = (date: Date | undefined) => {\n    if (!date) return;\n    setSelectedDate(date);\n  };\n\n  const addEvent = (event: IEvent) => {\n    setAllEvents((prev) => [...prev, event]);\n    setFilteredEvents((prev) => [...prev, event]);\n  };\n\n  const updateEvent = (event: IEvent) => {\n    const updated = {\n      ...event,\n      startDate: new Date(event.startDate).toISOString(),\n      endDate: new Date(event.endDate).toISOString(),\n    };\n\n    setAllEvents((prev) => prev.map((e) => (e.id === event.id ? updated : e)));\n    setFilteredEvents((prev) =>\n      prev.map((e) => (e.id === event.id ? updated : e)),\n    );\n  };\n\n  const removeEvent = (eventId: number) => {\n    setAllEvents((prev) => prev.filter((e) => e.id !== eventId));\n    setFilteredEvents((prev) => prev.filter((e) => e.id !== eventId));\n  };\n\n  const clearFilter = () => {\n    setFilteredEvents(allEvents);\n    setSelectedColors([]);\n    setSelectedUserId(\"all\");\n  };\n\n  const value = {\n    selectedDate,\n    setSelectedDate: handleSelectDate,\n    selectedUserId,\n    setSelectedUserId,\n    badgeVariant,\n    setBadgeVariant,\n    users,\n    selectedColors,\n    filterEventsBySelectedColors,\n    filterEventsBySelectedUser,\n    events: filteredEvents,\n    view: currentView,\n    use24HourFormat,\n    toggleTimeFormat,\n    setView,\n    agendaModeGroupBy,\n    setAgendaModeGroupBy,\n    addEvent,\n    updateEvent,\n    removeEvent,\n    clearFilter,\n  };\n\n  return (\n    <CalendarContext.Provider value={value}>\n      {children}\n    </CalendarContext.Provider>\n  );\n}\n\nexport function useCalendar(): ICalendarContext {\n  const context = useContext(CalendarContext);\n  if (!context)\n    throw new Error(\"useCalendar must be used within a CalendarProvider.\");\n  return context;\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/contexts/dnd-context.tsx",
      "content": "\"use client\";\n\nimport React, {\n  createContext,\n  type ReactNode,\n  useCallback,\n  useContext,\n  useRef,\n  useState,\n  useMemo,\n} from \"react\";\nimport { toast } from \"sonner\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\n\ninterface DragDropContextType {\n  draggedEvent: IEvent | null;\n  isDragging: boolean;\n  startDrag: (event: IEvent) => void;\n  endDrag: () => void;\n  handleEventDrop: (date: Date, hour?: number, minute?: number) => void;\n}\n\ninterface DndProviderProps {\n  children: ReactNode;\n}\n\nconst DragDropContext = createContext<DragDropContextType | undefined>(\n  undefined,\n);\n\nexport function DndProvider({ children }: DndProviderProps) {\n  const { updateEvent } = useCalendar();\n  const [dragState, setDragState] = useState<{\n    draggedEvent: IEvent | null;\n    isDragging: boolean;\n  }>({ draggedEvent: null, isDragging: false });\n\n  const onEventDroppedRef = useRef<\n    ((event: IEvent, newStartDate: Date, newEndDate: Date) => void) | null\n  >(null);\n\n  const startDrag = useCallback((event: IEvent) => {\n    setDragState({ draggedEvent: event, isDragging: true });\n  }, []);\n\n  const endDrag = useCallback(() => {\n    setDragState({ draggedEvent: null, isDragging: false });\n  }, []);\n\n  const calculateNewDates = useCallback(\n    (event: IEvent, targetDate: Date, hour?: number, minute?: number) => {\n      const originalStart = new Date(event.startDate);\n      const originalEnd = new Date(event.endDate);\n      const duration = originalEnd.getTime() - originalStart.getTime();\n\n      const newStart = new Date(targetDate);\n      if (hour !== undefined) {\n        newStart.setHours(hour, minute || 0, 0, 0);\n      } else {\n        newStart.setHours(\n          originalStart.getHours(),\n          originalStart.getMinutes(),\n          0,\n          0,\n        );\n      }\n\n      return {\n        newStart,\n        newEnd: new Date(newStart.getTime() + duration),\n      };\n    },\n    [],\n  );\n\n  const isSamePosition = useCallback((date1: Date, date2: Date) => {\n    return date1.getTime() === date2.getTime();\n  }, []);\n\n  const handleEventDrop = useCallback(\n    (targetDate: Date, hour?: number, minute?: number) => {\n      const { draggedEvent } = dragState;\n      if (!draggedEvent) return;\n\n      const { newStart, newEnd } = calculateNewDates(\n        draggedEvent,\n        targetDate,\n        hour,\n        minute,\n      );\n      const originalStart = new Date(draggedEvent.startDate);\n\n      // Check if dropped in same position\n      if (isSamePosition(originalStart, newStart)) {\n        endDrag();\n        return;\n      }\n\n      // Instantly update event\n      const callback = onEventDroppedRef.current;\n      if (callback) {\n        callback(draggedEvent, newStart, newEnd);\n      }\n      endDrag();\n    },\n    [dragState, calculateNewDates, isSamePosition, endDrag],\n  );\n\n  // Default event update handler\n  const handleEventUpdate = useCallback(\n    (event: IEvent, newStartDate: Date, newEndDate: Date) => {\n      try {\n        const updatedEvent = {\n          ...event,\n          startDate: newStartDate.toISOString(),\n          endDate: newEndDate.toISOString(),\n        };\n        updateEvent(updatedEvent);\n        toast.success(\"Event updated successfully\");\n      } catch {\n        toast.error(\"Failed to update event\");\n      }\n    },\n    [updateEvent],\n  );\n\n  // Set default callback\n  React.useEffect(() => {\n    onEventDroppedRef.current = handleEventUpdate;\n  }, [handleEventUpdate]);\n\n  const contextValue = useMemo(\n    () => ({\n      draggedEvent: dragState.draggedEvent,\n      isDragging: dragState.isDragging,\n      startDrag,\n      endDrag,\n      handleEventDrop,\n    }),\n    [dragState, startDrag, endDrag, handleEventDrop],\n  );\n\n  return (\n    <DragDropContext.Provider value={contextValue}>\n      {children}\n    </DragDropContext.Provider>\n  );\n}\n\nexport function useDragDrop() {\n  const context = useContext(DragDropContext);\n  if (!context) {\n    throw new Error(\"useDragDrop must be used within a DragDropProvider\");\n  }\n  return context;\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dialogs/add-edit-event-dialog.tsx",
      "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { addMinutes, format, set } from \"date-fns\";\nimport { type ReactNode, useEffect, useMemo } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { Button } from \"@/components/ui/button\";\nimport { DateTimePicker } from \"@/components/ui/date-time-picker\";\nimport {\n  Form,\n  FormControl,\n  FormField,\n  FormItem,\n  FormLabel,\n  FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n  Modal,\n  ModalClose,\n  ModalContent,\n  ModalDescription,\n  ModalFooter,\n  ModalHeader,\n  ModalTitle,\n  ModalTrigger,\n} from \"@/components/ui/responsive-modal\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { COLORS } from \"@/features/calendar/constants\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { useDisclosure } from \"@/features/calendar/hooks\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { eventSchema, type TEventFormData } from \"@/features/calendar/schemas\";\n\ninterface IProps {\n  children: ReactNode;\n  startDate?: Date;\n  startTime?: { hour: number; minute: number };\n  event?: IEvent;\n}\n\nexport function AddEditEventDialog({\n  children,\n  startDate,\n  startTime,\n  event,\n}: IProps) {\n  const { isOpen, onClose, onToggle } = useDisclosure();\n  const { addEvent, updateEvent } = useCalendar();\n  const isEditing = !!event;\n\n  const initialDates = useMemo(() => {\n    if (!isEditing && !event) {\n      if (!startDate) {\n        const now = new Date();\n        return { startDate: now, endDate: addMinutes(now, 30) };\n      }\n      const start = startTime\n        ? set(new Date(startDate), {\n            hours: startTime.hour,\n            minutes: startTime.minute,\n            seconds: 0,\n          })\n        : new Date(startDate);\n      const end = addMinutes(start, 30);\n      return { startDate: start, endDate: end };\n    }\n\n    return {\n      startDate: new Date(event.startDate),\n      endDate: new Date(event.endDate),\n    };\n  }, [startDate, startTime, event, isEditing]);\n\n  const form = useForm<TEventFormData>({\n    resolver: zodResolver(eventSchema),\n    defaultValues: {\n      title: event?.title ?? \"\",\n      description: event?.description ?? \"\",\n      startDate: initialDates.startDate,\n      endDate: initialDates.endDate,\n      color: event?.color ?? \"blue\",\n    },\n  });\n\n  useEffect(() => {\n    form.reset({\n      title: event?.title ?? \"\",\n      description: event?.description ?? \"\",\n      startDate: initialDates.startDate,\n      endDate: initialDates.endDate,\n      color: event?.color ?? \"blue\",\n    });\n  }, [event, initialDates, form]);\n\n  const onSubmit = (values: TEventFormData) => {\n    try {\n      const formattedEvent: IEvent = {\n        ...values,\n        startDate: format(values.startDate, \"yyyy-MM-dd'T'HH:mm:ss\"),\n        endDate: format(values.endDate, \"yyyy-MM-dd'T'HH:mm:ss\"),\n        id: isEditing ? event.id : Math.floor(Math.random() * 1000000),\n        user: isEditing\n          ? event.user\n          : {\n              id: Math.floor(Math.random() * 1000000).toString(),\n              name: \"Jeraidi Yassir\",\n              picturePath: null,\n            },\n        color: values.color,\n      };\n\n      if (isEditing) {\n        updateEvent(formattedEvent);\n        toast.success(\"Event updated successfully\");\n      } else {\n        addEvent(formattedEvent);\n        toast.success(\"Event created successfully\");\n      }\n\n      onClose();\n      form.reset();\n    } catch (error) {\n      console.error(`Error ${isEditing ? \"editing\" : \"adding\"} event:`, error);\n      toast.error(`Failed to ${isEditing ? \"edit\" : \"add\"} event`);\n    }\n  };\n\n  return (\n    <Modal open={isOpen} onOpenChange={onToggle} modal={false}>\n      <ModalTrigger asChild>{children}</ModalTrigger>\n      <ModalContent>\n        <ModalHeader>\n          <ModalTitle>{isEditing ? \"Edit Event\" : \"Add New Event\"}</ModalTitle>\n          <ModalDescription>\n            {isEditing\n              ? \"Modify your existing event.\"\n              : \"Create a new event for your calendar.\"}\n          </ModalDescription>\n        </ModalHeader>\n\n        <Form {...form}>\n          <form\n            id=\"event-form\"\n            onSubmit={form.handleSubmit(onSubmit)}\n            className=\"grid gap-4 py-4\"\n          >\n            <FormField\n              control={form.control}\n              name=\"title\"\n              render={({ field, fieldState }) => (\n                <FormItem>\n                  <FormLabel htmlFor=\"title\" className=\"required\">\n                    Title\n                  </FormLabel>\n                  <FormControl>\n                    <Input\n                      id=\"title\"\n                      placeholder=\"Enter a title\"\n                      {...field}\n                      className={fieldState.invalid ? \"border-red-500\" : \"\"}\n                    />\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n            <FormField\n              control={form.control}\n              name=\"startDate\"\n              render={({ field }) => (\n                <DateTimePicker form={form} field={field} />\n              )}\n            />\n            <FormField\n              control={form.control}\n              name=\"endDate\"\n              render={({ field }) => (\n                <DateTimePicker form={form} field={field} />\n              )}\n            />\n            <FormField\n              control={form.control}\n              name=\"color\"\n              render={({ field, fieldState }) => (\n                <FormItem>\n                  <FormLabel className=\"required\">Variant</FormLabel>\n                  <FormControl>\n                    <Select value={field.value} onValueChange={field.onChange}>\n                      <SelectTrigger\n                        className={`w-full ${\n                          fieldState.invalid ? \"border-red-500\" : \"\"\n                        }`}\n                      >\n                        <SelectValue placeholder=\"Select a variant\" />\n                      </SelectTrigger>\n                      <SelectContent>\n                        {COLORS.map((color) => (\n                          <SelectItem value={color} key={color}>\n                            <div className=\"flex items-center gap-2\">\n                              <div\n                                className={`size-3.5 rounded-full bg-${color}-600 dark:bg-${color}-700`}\n                              />\n                              {color}\n                            </div>\n                          </SelectItem>\n                        ))}\n                      </SelectContent>\n                    </Select>\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n            <FormField\n              control={form.control}\n              name=\"description\"\n              render={({ field, fieldState }) => (\n                <FormItem>\n                  <FormLabel className=\"required\">Description</FormLabel>\n                  <FormControl>\n                    <Textarea\n                      {...field}\n                      placeholder=\"Enter a description\"\n                      className={fieldState.invalid ? \"border-red-500\" : \"\"}\n                    />\n                  </FormControl>\n                  <FormMessage />\n                </FormItem>\n              )}\n            />\n          </form>\n        </Form>\n        <ModalFooter className=\"flex justify-end gap-2\">\n          <ModalClose asChild>\n            <Button type=\"button\" variant=\"outline\">\n              Cancel\n            </Button>\n          </ModalClose>\n          <Button form=\"event-form\" type=\"submit\">\n            {isEditing ? \"Save Changes\" : \"Create Event\"}\n          </Button>\n        </ModalFooter>\n      </ModalContent>\n    </Modal>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dialogs/delete-event-dialog.tsx",
      "content": "import { TrashIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogTitle,\n  AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport { Button } from \"@/components/ui/button\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\ninterface DeleteEventDialogProps {\n  eventId: number;\n}\n\nexport default function DeleteEventDialog({ eventId }: DeleteEventDialogProps) {\n  const { removeEvent } = useCalendar();\n\n  const deleteEvent = () => {\n    try {\n      removeEvent(eventId);\n      toast.success(\"Event deleted successfully.\");\n    } catch {\n      toast.error(\"Error deleting event.\");\n    }\n  };\n\n  if (!eventId) {\n    return null;\n  }\n\n  return (\n    <AlertDialog>\n      <AlertDialogTrigger asChild>\n        <Button variant=\"destructive\">\n          <TrashIcon />\n          Delete\n        </Button>\n      </AlertDialogTrigger>\n      <AlertDialogContent>\n        <AlertDialogHeader>\n          <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n          <AlertDialogDescription>\n            This action cannot be undone. This will permanently delete your\n            event and remove event data from our servers.\n          </AlertDialogDescription>\n        </AlertDialogHeader>\n        <AlertDialogFooter>\n          <AlertDialogCancel>Cancel</AlertDialogCancel>\n          <AlertDialogAction onClick={deleteEvent}>Continue</AlertDialogAction>\n        </AlertDialogFooter>\n      </AlertDialogContent>\n    </AlertDialog>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dialogs/event-details-dialog.tsx",
      "content": "\"use client\";\n\nimport { format, parseISO } from \"date-fns\";\nimport { Calendar, Clock, Text, User } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { toast } from \"sonner\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { AddEditEventDialog } from \"@/features/calendar/dialogs/add-edit-event-dialog\";\nimport { formatTime } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\n\ninterface IProps {\n  event: IEvent;\n  children: ReactNode;\n}\n\nexport function EventDetailsDialog({ event, children }: IProps) {\n  const startDate = parseISO(event.startDate);\n  const endDate = parseISO(event.endDate);\n  const { use24HourFormat, removeEvent } = useCalendar();\n\n  const deleteEvent = (eventId: number) => {\n    try {\n      removeEvent(eventId);\n      toast.success(\"Event deleted successfully.\");\n    } catch {\n      toast.error(\"Error deleting event.\");\n    }\n  };\n\n  return (\n    <Dialog>\n      <DialogTrigger asChild>{children}</DialogTrigger>\n      <DialogContent>\n        <DialogHeader>\n          <DialogTitle>{event.title}</DialogTitle>\n        </DialogHeader>\n\n        <ScrollArea className=\"max-h-[80vh]\">\n          <div className=\"space-y-4 p-4\">\n            <div className=\"flex items-start gap-2\">\n              <User className=\"mt-1 size-4 shrink-0 text-muted-foreground\" />\n              <div>\n                <p className=\"text-sm font-medium\">Responsible</p>\n                <p className=\"text-sm text-muted-foreground\">\n                  {event.user.name}\n                </p>\n              </div>\n            </div>\n\n            <div className=\"flex items-start gap-2\">\n              <Calendar className=\"mt-1 size-4 shrink-0 text-muted-foreground\" />\n              <div>\n                <p className=\"text-sm font-medium\">Start Date</p>\n                <p className=\"text-sm text-muted-foreground\">\n                  {format(startDate, \"EEEE dd MMMM\")}\n                  <span className=\"mx-1\">at</span>\n                  {formatTime(parseISO(event.startDate), use24HourFormat)}\n                </p>\n              </div>\n            </div>\n\n            <div className=\"flex items-start gap-2\">\n              <Clock className=\"mt-1 size-4 shrink-0 text-muted-foreground\" />\n              <div>\n                <p className=\"text-sm font-medium\">End Date</p>\n                <p className=\"text-sm text-muted-foreground\">\n                  {format(endDate, \"EEEE dd MMMM\")}\n                  <span className=\"mx-1\">at</span>\n                  {formatTime(parseISO(event.endDate), use24HourFormat)}\n                </p>\n              </div>\n            </div>\n\n            <div className=\"flex items-start gap-2\">\n              <Text className=\"mt-1 size-4 shrink-0 text-muted-foreground\" />\n              <div>\n                <p className=\"text-sm font-medium\">Description</p>\n                <p className=\"text-sm text-muted-foreground\">\n                  {event.description}\n                </p>\n              </div>\n            </div>\n          </div>\n        </ScrollArea>\n        <div className=\"flex justify-end gap-2\">\n          <AddEditEventDialog event={event}>\n            <Button variant=\"outline\">Edit</Button>\n          </AddEditEventDialog>\n          <Button\n            variant=\"destructive\"\n            onClick={() => {\n              deleteEvent(event.id);\n            }}\n          >\n            Delete\n          </Button>\n        </div>\n        <DialogClose />\n      </DialogContent>\n    </Dialog>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dialogs/events-list-dialog.tsx",
      "content": "import { format } from \"date-fns\";\nimport type { ReactNode } from \"react\";\nimport {\n  Modal,\n  ModalContent,\n  ModalHeader,\n  ModalTitle,\n  ModalTrigger,\n} from \"@/components/ui/responsive-modal\";\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { formatTime } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { dayCellVariants } from \"@/features/calendar/views/month-view/day-cell\";\nimport { EventBullet } from \"@/features/calendar/views/month-view/event-bullet\";\nimport { EventDetailsDialog } from \"@/features/calendar/dialogs/event-details-dialog\";\n\ninterface EventListDialogProps {\n  date: Date;\n  events: IEvent[];\n  maxVisibleEvents?: number;\n  children?: ReactNode;\n}\n\nexport function EventListDialog({\n  date,\n  events,\n  maxVisibleEvents = 3,\n  children,\n}: EventListDialogProps) {\n  const cellEvents = events;\n  const hiddenEventsCount = Math.max(cellEvents.length - maxVisibleEvents, 0);\n  const { badgeVariant, use24HourFormat } = useCalendar();\n\n  const defaultTrigger = (\n    <span className=\"cursor-pointer\">\n      <span className=\"sm:hidden\">+{hiddenEventsCount}</span>\n      <span className=\"hidden sm:inline py-0.5 px-2 my-1 rounded-xl border\">\n        {hiddenEventsCount}\n        <span className=\"mx-1\">more...</span>\n      </span>\n    </span>\n  );\n\n  return (\n    <Modal>\n      <ModalTrigger asChild>{children || defaultTrigger}</ModalTrigger>\n      <ModalContent className=\"sm:max-w-[425px]\">\n        <ModalHeader>\n          <ModalTitle className=\"my-2\">\n            <div className=\"flex items-center gap-2\">\n              <EventBullet color={cellEvents[0]?.color} className=\"\" />\n              <p className=\"text-sm font-medium\">\n                Events on {format(date, \"EEEE, MMMM d, yyyy\")}\n              </p>\n            </div>\n          </ModalTitle>\n        </ModalHeader>\n        <div className=\"max-h-[60vh] overflow-y-auto space-y-2\">\n          {cellEvents.length > 0 ? (\n            cellEvents.map((event) => (\n              <EventDetailsDialog event={event} key={event.id}>\n                <div\n                  className={cn(\n                    \"flex items-center gap-2 p-2 border rounded-md hover:bg-muted cursor-pointer\",\n                    {\n                      [dayCellVariants({ color: event.color })]:\n                        badgeVariant === \"colored\",\n                    },\n                  )}\n                >\n                  <EventBullet color={event.color} />\n                  <div className=\"flex justify-between items-center w-full\">\n                    <p className=\"text-sm font-medium\">{event.title}</p>\n                    <p className=\"text-xs\">\n                      {formatTime(event.startDate, use24HourFormat)}\n                    </p>\n                  </div>\n                </div>\n              </EventDetailsDialog>\n            ))\n          ) : (\n            <p className=\"text-sm text-muted-foreground\">\n              No events for this date.\n            </p>\n          )}\n        </div>\n      </ModalContent>\n    </Modal>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dnd/draggable-event.tsx",
      "content": "import { motion } from \"framer-motion\";\nimport type React from \"react\";\nimport type { ReactNode } from \"react\";\nimport { useDragDrop } from \"@/features/calendar/contexts/dnd-context\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\n\ninterface DraggableEventProps {\n  event: IEvent;\n  children: ReactNode;\n  className?: string;\n}\n\nexport function DraggableEvent({\n  event,\n  children,\n  className,\n}: DraggableEventProps) {\n  const { startDrag, endDrag, isDragging, draggedEvent } = useDragDrop();\n\n  const isCurrentlyDragged = isDragging && draggedEvent?.id === event.id;\n\n  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n    e.stopPropagation();\n  };\n\n  return (\n    <motion.div\n      className={`${className || \"\"} ${isCurrentlyDragged ? \"opacity-50 cursor-grabbing\" : \"cursor-grab\"}`}\n      draggable\n      onClick={(e: React.MouseEvent<HTMLDivElement>) => handleClick(e)}\n      onDragStart={(e) => {\n        (e as DragEvent).dataTransfer!.setData(\n          \"text/plain\",\n          event.id.toString(),\n        );\n        startDrag(event);\n      }}\n      onDragEnd={() => {\n        endDrag();\n      }}\n    >\n      {children}\n    </motion.div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dnd/droppable-area.tsx",
      "content": "import React, { type ReactNode } from \"react\";\nimport { useDragDrop } from \"@/features/calendar/contexts/dnd-context\";\n\ninterface DroppableAreaProps {\n  date: Date;\n  hour?: number;\n  minute?: number;\n  children: ReactNode;\n  className?: string;\n}\n\nexport function DroppableArea({\n  date,\n  hour,\n  minute,\n  children,\n  className,\n}: DroppableAreaProps) {\n  const { handleEventDrop, isDragging } = useDragDrop();\n\n  return (\n    <div\n      // biome-ignore lint/a11y/useSemanticElements: Using gridcell role for CSS grid layout where td is not applicable\n      role=\"gridcell\"\n      aria-label=\"Droppable area\"\n      tabIndex={-1}\n      className={`${className || \"\"} ${isDragging ? \"drop-target\" : \"\"}`}\n      onDragOver={(e) => {\n        // Prevent default to allow drop\n        e.preventDefault();\n        e.currentTarget.classList.add(\"bg-primary/10\");\n      }}\n      onDragLeave={(e) => {\n        e.currentTarget.classList.remove(\"bg-primary/10\");\n      }}\n      onDrop={(e) => {\n        e.preventDefault();\n        e.currentTarget.classList.remove(\"bg-primary/10\");\n        handleEventDrop(date, hour, minute);\n      }}\n    >\n      {children}\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/dnd/resizable-event.tsx",
      "content": "\"use client\";\n\nimport {\n  addMinutes,\n  differenceInMinutes,\n  format,\n  isAfter,\n  isBefore,\n  parseISO,\n} from \"date-fns\";\nimport { motion } from \"framer-motion\";\nimport { Resizable, type ResizeCallback } from \"re-resizable\";\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nimport type { IEvent } from \"@/features/calendar/interfaces\";\n\ninterface ResizableEventBlockProps {\n  event: IEvent;\n  children: React.ReactNode;\n  className?: string;\n}\n\nconst PIXELS_PER_HOUR = 96;\nconst MINUTES_PER_PIXEL = 60 / PIXELS_PER_HOUR;\nconst MIN_DURATION = 15; // in minutes\n\nexport function ResizableEvent({\n  event,\n  children,\n  className,\n}: ResizableEventBlockProps) {\n  const { updateEvent, use24HourFormat } = useCalendar();\n\n  const [isResizing, setIsResizing] = useState(false);\n  const [resizePreview, setResizePreview] = useState<{\n    start: string;\n    end: string;\n  } | null>(null);\n\n  const start = useMemo(() => parseISO(event.startDate), [event.startDate]);\n  const end = useMemo(() => parseISO(event.endDate), [event.endDate]);\n  const durationInMinutes = useMemo(\n    () => differenceInMinutes(end, start),\n    [start, end],\n  );\n\n  const resizeBoundaries = useMemo(() => {\n    const dayStart = new Date(start);\n    dayStart.setHours(0, 0, 0, 0);\n\n    const dayEnd = new Date(start);\n    dayEnd.setHours(23, 59, 59, 999);\n\n    return { dayStart, dayEnd };\n  }, [start]);\n\n  const handleResizeStart = useCallback(() => {\n    setIsResizing(true);\n  }, []);\n\n  const handleResize: ResizeCallback = useCallback(\n    (_, direction, ref) => {\n      const newHeight = parseInt(ref.style.height, 10);\n      const newDuration = Math.max(\n        MIN_DURATION,\n        Math.round((newHeight + 8) * MINUTES_PER_PIXEL),\n      );\n      const delta = newDuration - durationInMinutes;\n\n      let newStart = start;\n      let newEnd = end;\n\n      if (direction.includes(\"top\")) {\n        newStart = addMinutes(start, -delta);\n      } else if (direction.includes(\"bottom\")) {\n        newEnd = addMinutes(end, delta);\n      }\n\n      if (isBefore(newStart, resizeBoundaries.dayStart)) {\n        newStart = resizeBoundaries.dayStart;\n      }\n      if (isAfter(newEnd, resizeBoundaries.dayEnd)) {\n        newEnd = resizeBoundaries.dayEnd;\n      }\n\n      setResizePreview({\n        start: format(newStart, use24HourFormat ? \"HH:mm\" : \"h:mm a\"),\n        end: format(newEnd, use24HourFormat ? \"HH:mm\" : \"h:mm a\"),\n      });\n\n      updateEvent({\n        ...event,\n        startDate: newStart.toISOString(),\n        endDate: newEnd.toISOString(),\n      });\n    },\n    [\n      start,\n      end,\n      durationInMinutes,\n      resizeBoundaries,\n      use24HourFormat,\n      updateEvent,\n      event,\n    ],\n  );\n\n  const handleResizeStop = useCallback(() => {\n    setIsResizing(false);\n    setResizePreview(null);\n  }, []);\n\n  const resizeConfig = useMemo(\n    () => ({\n      minHeight: 15,\n      maxHeight: 1440,\n      enable: {\n        top: true,\n        bottom: true,\n        topRight: false,\n        bottomRight: false,\n        bottomLeft: false,\n        topLeft: false,\n      },\n      handleStyles: {\n        top: {\n          cursor: \"ns-resize\",\n          height: \"8px\",\n          top: \"-4px\",\n          backgroundColor: \"transparent\",\n        },\n        bottom: {\n          cursor: \"ns-resize\",\n          height: \"8px\",\n          bottom: \"-4px\",\n          backgroundColor: \"transparent\",\n        },\n      },\n      handleClasses: {\n        top: \"transition-colors rounded-sm\",\n        bottom: \"transition-colors rounded-sm\",\n      },\n      onResizeStart: handleResizeStart,\n      onResize: handleResize,\n      onResizeStop: handleResizeStop,\n      className: cn(\n        \"transition-all duration-200\",\n        isResizing && \"z-50 shadow-lg\",\n      ),\n    }),\n    [handleResizeStart, handleResize, handleResizeStop, isResizing],\n  );\n\n  return (\n    <motion.div\n      initial={{ opacity: 0, scale: 0.95 }}\n      animate={{ opacity: 1, scale: 1 }}\n      exit={{ opacity: 0, scale: 0.95 }}\n      transition={{ duration: 0.2 }}\n      className={cn(\"relative group\", className)}\n    >\n      <Resizable {...resizeConfig}>{children}</Resizable>\n\n      {isResizing && resizePreview && (\n        <motion.div\n          initial={{ opacity: 0, y: -10 }}\n          animate={{ opacity: 1, y: 0 }}\n          exit={{ opacity: 0, y: -10 }}\n          className=\"absolute -top-8 left-1/2 transform -translate-x-1/2 bg-gray-900 text-white text-xs px-2 py-1 rounded shadow-lg z-50 whitespace-nowrap\"\n        >\n          {resizePreview.start} - {resizePreview.end}\n        </motion.div>\n      )}\n    </motion.div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/calendar-header.tsx",
      "content": "\"use client\";\n\nimport { motion } from \"framer-motion\";\nimport {\n  CalendarRange,\n  Columns,\n  Grid2X2,\n  Grid3X3,\n  LayoutList,\n  List,\n  Plus,\n} from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { ButtonGroup } from \"@/components/ui/button-group\";\nimport {\n  slideFromLeft,\n  slideFromRight,\n  transition,\n} from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { AddEditEventDialog } from \"@/features/calendar/dialogs/add-edit-event-dialog\";\nimport { DateNavigator } from \"@/features/calendar/header/date-navigator\";\nimport FilterEvents from \"@/features/calendar/header/filter\";\nimport { TodayButton } from \"@/features/calendar/header/today-button\";\nimport { UserSelect } from \"@/features/calendar/header/user-select\";\nimport { Settings } from \"@/features/calendar/settings/settings\";\nimport Views from \"./view-tabs\";\n\nexport function CalendarHeader() {\n  const { view, events } = useCalendar();\n\n  return (\n    <div className=\"flex flex-col gap-4 border-b p-4 lg:flex-row lg:items-center lg:justify-between\">\n      <motion.div\n        className=\"flex items-center gap-3\"\n        variants={slideFromLeft}\n        initial=\"initial\"\n        animate=\"animate\"\n        transition={transition}\n      >\n        <TodayButton />\n        <DateNavigator view={view} events={events} />\n      </motion.div>\n\n      <motion.div\n        className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:gap-1.5\"\n        variants={slideFromRight}\n        initial=\"initial\"\n        animate=\"animate\"\n        transition={transition}\n      >\n        <div className=\"options flex-wrap flex items-center gap-4 md:gap-2\">\n          <FilterEvents />\n          <Views />\n        </div>\n\n        <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:gap-1.5\">\n          <UserSelect />\n\n          <AddEditEventDialog>\n            <Button>\n              <Plus className=\"h-4 w-4\" />\n              Add Event\n            </Button>\n          </AddEditEventDialog>\n        </div>\n        <Settings />\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/view-tabs.tsx",
      "content": "import { motion, AnimatePresence } from \"motion/react\";\n\nimport { Tabs, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\n\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"../contexts/calendar-context\";\nimport {\n  CalendarRange,\n  List,\n  Columns,\n  Grid3X3,\n  Grid2X2,\n} from \"lucide-react\";\nimport { TCalendarView } from \"../types\";\nimport { memo } from \"react\";\n\nconst tabs = [\n  {\n    name: \"Agenda\",\n    value: \"agenda\",\n    icon: () => <CalendarRange className=\"h-4 w-4\" />,\n  },\n  {\n    name: \"Day\",\n    value: \"day\",\n    icon: () => <List className=\"h-4 w-4\" />,\n  },\n  {\n    name: \"Week\",\n    value: \"week\",\n    icon: () => <Columns className=\"h-4 w-4\" />,\n  },\n  {\n    name: \"Month\",\n    value: \"month\",\n    icon: () => <Grid3X3 className=\"h-4 w-4\" />,\n  },\n  {\n    name: \"Year\",\n    value: \"year\",\n    icon: () => <Grid2X2 className=\"h-4 w-4\" />,\n  },\n];\n\nfunction Views() {\n  const { view, setView } = useCalendar();\n\n  return (\n    <Tabs\n      value={view}\n      onValueChange={(value) => setView(value as TCalendarView)}\n      className=\"gap-4 sm:w-auto w-full\"\n    >\n      <TabsList className=\"h-auto gap-2 rounded-xl p-1 w-full\">\n        {tabs.map(({ icon: Icon, name, value }) => {\n          const isActive = view === value;\n\n          return (\n            <motion.div\n              key={value}\n              layout\n              className={cn(\n                \"flex h-8 items-center justify-center overflow-hidden rounded-md\",\n                isActive ? \"flex-1\" : \"flex-none\"\n              )}\n              onClick={() => setView(value as TCalendarView)}\n              initial={false}\n              animate={{\n                width: isActive ? 120 : 32,\n              }}\n              transition={{\n                type: \"tween\",\n                stiffness: 400,\n                damping: 25,\n              }}\n            >\n              <TabsTrigger value={value} asChild>\n                <motion.div\n                  className=\"flex h-8 w-full items-center justify-center cursor-pointer\"\n                  animate={{ filter: \"blur(0px)\" }}\n                  exit={{ filter: \"blur(2px)\" }}\n                  transition={{ duration: 0.25, ease: \"easeOut\" }}\n                >\n                  <Icon />\n                  <AnimatePresence initial={false}>\n                    {isActive && (\n                      <motion.span\n                        className=\"font-medium\"\n                        initial={{ opacity: 0, scaleX: 0.8 }}\n                        animate={{ opacity: 1, scaleX: 1 }}\n                        transition={{ duration: 0.25, ease: \"easeOut\" }}\n                        style={{ originX: 0 }}\n                      >\n                        {name}\n                      </motion.span>\n                    )}\n                  </AnimatePresence>\n                </motion.div>\n              </TabsTrigger>\n            </motion.div>\n          );\n        })}\n      </TabsList>\n    </Tabs>\n  );\n}\n\nexport default memo(Views);",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/date-navigator.tsx",
      "content": "import { formatDate } from \"date-fns\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { useMemo } from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { buttonHover, transition } from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nimport {\n  getEventsCount,\n  navigateDate,\n  rangeText,\n} from \"@/features/calendar/helpers\";\n\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport type { TCalendarView } from \"@/features/calendar/types\";\n\ninterface IProps {\n  view: TCalendarView;\n  events: IEvent[];\n}\n\nconst MotionButton = motion.create(Button);\nconst MotionBadge = motion.create(Badge);\n\nexport function DateNavigator({ view, events }: IProps) {\n  const { selectedDate, setSelectedDate } = useCalendar();\n\n  const month = formatDate(selectedDate, \"MMMM\");\n  const year = selectedDate.getFullYear();\n\n  const eventCount = useMemo(\n    () => getEventsCount(events, selectedDate, view),\n    [events, selectedDate, view],\n  );\n\n  const handlePrevious = () =>\n    setSelectedDate(navigateDate(selectedDate, view, \"previous\"));\n  const handleNext = () =>\n    setSelectedDate(navigateDate(selectedDate, view, \"next\"));\n\n  return (\n    <div className=\"space-y-0.5\">\n      <div className=\"flex items-center gap-2\">\n        <motion.span\n          className=\"text-lg font-semibold\"\n          initial={{ x: -20, opacity: 0 }}\n          animate={{ x: 0, opacity: 1 }}\n          transition={transition}\n        >\n          {month} {year}\n        </motion.span>\n        <AnimatePresence mode=\"wait\">\n          <MotionBadge\n            key={eventCount}\n            variant=\"secondary\"\n            initial={{ scale: 0.8, opacity: 0 }}\n            animate={{ scale: 1, opacity: 1 }}\n            exit={{ scale: 0.8, opacity: 0 }}\n            transition={transition}\n          >\n            {eventCount} events\n          </MotionBadge>\n        </AnimatePresence>\n      </div>\n\n      <div className=\"flex items-center gap-2\">\n        <MotionButton\n          variant=\"outline\"\n          size=\"icon\"\n          className=\"h-6 w-6\"\n          onClick={handlePrevious}\n          variants={buttonHover}\n          whileHover=\"hover\"\n          whileTap=\"tap\"\n        >\n          <ChevronLeft className=\"h-4 w-4\" />\n        </MotionButton>\n\n        <motion.p\n          className=\"text-sm text-muted-foreground\"\n          initial={{ opacity: 0 }}\n          animate={{ opacity: 1 }}\n          transition={transition}\n        >\n          {rangeText(view, selectedDate)}\n        </motion.p>\n\n        <MotionButton\n          variant=\"outline\"\n          size=\"icon\"\n          className=\"h-6 w-6\"\n          onClick={handleNext}\n          variants={buttonHover}\n          whileHover=\"hover\"\n          whileTap=\"tap\"\n        >\n          <ChevronRight className=\"h-4 w-4\" />\n        </MotionButton>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/filter.tsx",
      "content": "import { CheckIcon, Filter, RefreshCcw } from \"lucide-react\";\nimport {\n\tDropdownMenu,\n\tDropdownMenuContent,\n\tDropdownMenuItem,\n\tDropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { Toggle } from \"@/components/ui/toggle\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport type { TEventColor } from \"@/features/calendar/types\";\n\nexport default function FilterEvents() {\n\tconst { selectedColors, filterEventsBySelectedColors, clearFilter } =\n\t\tuseCalendar();\n\n\tconst colors: TEventColor[] = [\n\t\t\"blue\",\n\t\t\"green\",\n\t\t\"red\",\n\t\t\"yellow\",\n\t\t\"purple\",\n\t\t\"orange\",\n\t];\n\n\treturn (\n\t\t<DropdownMenu>\n\t\t\t<DropdownMenuTrigger asChild>\n\t\t\t\t<Toggle variant=\"outline\" className=\"cursor-pointer w-fit\">\n\t\t\t\t\t<Filter className=\"h-4 w-4\" />\n\t\t\t\t</Toggle>\n\t\t\t</DropdownMenuTrigger>\n\t\t\t<DropdownMenuContent align=\"end\" className=\"w-[150px]\">\n\t\t\t\t{colors.map((color) => (\n\t\t\t\t\t<DropdownMenuItem\n\t\t\t\t\t\tkey={color}\n\t\t\t\t\t\tclassName=\"flex items-center gap-2 cursor-pointer\"\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tfilterEventsBySelectedColors(color);\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={`size-3.5 rounded-full bg-${color}-600 dark:bg-${color}-700`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<span className=\"capitalize flex justify-center items-center gap-2\">\n\t\t\t\t\t\t\t{color}\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{selectedColors.includes(color) && (\n\t\t\t\t\t\t\t\t\t<span className=\"text-blue-500\">\n\t\t\t\t\t\t\t\t\t\t<CheckIcon className=\"size-4\" />\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</DropdownMenuItem>\n\t\t\t\t))}\n\t\t\t\t<Separator className=\"my-2\" />\n\t\t\t\t<DropdownMenuItem\n\t\t\t\t\tdisabled={selectedColors.length === 0}\n\t\t\t\t\tclassName=\"flex gap-2 cursor-pointer\"\n\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tclearFilter();\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<RefreshCcw className=\"size-3.5\" />\n\t\t\t\t\tClear Filter\n\t\t\t\t</DropdownMenuItem>\n\t\t\t</DropdownMenuContent>\n\t\t</DropdownMenu>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/today-button.tsx",
      "content": "import { formatDate } from \"date-fns\";\nimport { motion } from \"framer-motion\";\nimport { Button } from \"@/components/ui/button\";\nimport { buttonHover, transition } from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nconst MotionButton = motion.create(Button);\n\nexport function TodayButton() {\n  const { setSelectedDate } = useCalendar();\n\n  const today = new Date();\n  const handleClick = () => setSelectedDate(today);\n\n  return (\n    <MotionButton\n      variant=\"outline\"\n      className=\"flex h-14 w-14 flex-col items-center justify-center p-0 text-center\"\n      onClick={handleClick}\n      variants={buttonHover}\n      whileHover=\"hover\"\n      whileTap=\"tap\"\n      transition={transition}\n    >\n      <motion.span\n        className=\"w-full bg-primary py-1 text-xs font-semibold text-primary-foreground\"\n        initial={{ y: -10, opacity: 0 }}\n        animate={{ y: 0, opacity: 1 }}\n        transition={{ delay: 0.1, ...transition }}\n      >\n        {formatDate(today, \"MMM\").toUpperCase()}\n      </motion.span>\n      <motion.span\n        className=\"text-lg font-bold\"\n        initial={{ y: 10, opacity: 0 }}\n        animate={{ y: 0, opacity: 1 }}\n        transition={{ delay: 0.2, ...transition }}\n      >\n        {today.getDate()}\n      </motion.span>\n    </MotionButton>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/header/user-select.tsx",
      "content": "import { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport { AvatarGroup } from \"@/components/ui/avatar-group\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nexport function UserSelect() {\n  const { users, selectedUserId, filterEventsBySelectedUser } = useCalendar();\n\n  return (\n    <Select value={selectedUserId!} onValueChange={filterEventsBySelectedUser}>\n      <SelectTrigger className=\"w-full\">\n        <SelectValue placeholder=\"Select a user\" />\n      </SelectTrigger>\n      <SelectContent align=\"end\">\n        <SelectItem value=\"all\">\n          <AvatarGroup className=\"mx-2 flex items-center\" max={3}>\n            {users.map((user) => (\n              <Avatar key={user.id} className=\"size-6 text-xxs\">\n                <AvatarImage\n                  src={user.picturePath ?? undefined}\n                  alt={user.name}\n                />\n                <AvatarFallback className=\"text-xxs\">\n                  {user.name[0]}\n                </AvatarFallback>\n              </Avatar>\n            ))}\n          </AvatarGroup>\n          All\n        </SelectItem>\n\n        {users.map((user) => (\n          <SelectItem\n            key={user.id}\n            value={user.id}\n            className=\"flex-1 cursor-pointer\"\n          >\n            <div className=\"flex items-center gap-2\">\n              <Avatar key={user.id} className=\"size-6\">\n                <AvatarImage\n                  src={user.picturePath ?? undefined}\n                  alt={user.name}\n                />\n                <AvatarFallback className=\"text-xxs\">\n                  {user.name[0]}\n                </AvatarFallback>\n              </Avatar>\n\n              <p className=\"truncate\">{user.name}</p>\n            </div>\n          </SelectItem>\n        ))}\n      </SelectContent>\n    </Select>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/settings/settings.tsx",
      "content": "import {\n  DotIcon,\n  MoonIcon,\n  PaletteIcon,\n  SettingsIcon,\n  SunMediumIcon,\n} from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nexport function Settings() {\n  const {\n    badgeVariant,\n    setBadgeVariant,\n    use24HourFormat,\n    toggleTimeFormat,\n    agendaModeGroupBy,\n    setAgendaModeGroupBy,\n  } = useCalendar();\n  const { theme, setTheme } = useTheme();\n\n  const isDarkMode = theme === \"dark\";\n  const isDotVariant = badgeVariant === \"dot\";\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"outline\" size=\"icon\">\n          <SettingsIcon />\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-56\">\n        <DropdownMenuLabel>Calendar settings</DropdownMenuLabel>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem>\n            Use dark mode\n            <DropdownMenuShortcut>\n              <Switch\n                icon={\n                  isDarkMode ? (\n                    <MoonIcon className=\"h-4 w-4\" />\n                  ) : (\n                    <SunMediumIcon className=\"h-4 w-4\" />\n                  )\n                }\n                checked={isDarkMode}\n                onCheckedChange={(checked) =>\n                  setTheme(checked ? \"dark\" : \"light\")\n                }\n              />\n            </DropdownMenuShortcut>\n          </DropdownMenuItem>\n\n          <DropdownMenuItem>\n            Use dot badge\n            <DropdownMenuShortcut>\n              <Switch\n                icon={\n                  isDotVariant ? (\n                    <DotIcon className=\"w-4 h-4\" />\n                  ) : (\n                    <PaletteIcon className=\"w-4 h-4\" />\n                  )\n                }\n                checked={isDotVariant}\n                onCheckedChange={(checked) =>\n                  setBadgeVariant(checked ? \"dot\" : \"colored\")\n                }\n              />\n            </DropdownMenuShortcut>\n          </DropdownMenuItem>\n          <DropdownMenuItem>\n            Use 24 hour format\n            <DropdownMenuShortcut>\n              <Switch\n                icon={\n                  use24HourFormat ? (\n                    <svg\n                      xmlns=\"http://www.w3.org/2000/svg\"\n                      width={24}\n                      height={24}\n                      viewBox=\"0 0 24 24\"\n                      fill=\"none\"\n                      stroke=\"currentColor\"\n                      strokeWidth={2}\n                      strokeLinecap=\"round\"\n                      strokeLinejoin=\"round\"\n                      className=\"icon icon-tabler icons-tabler-outline icon-tabler-clock-24\"\n                    >\n                      <title>24 Hour Format</title>\n                      <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n                      <path d=\"M3 12a9 9 0 0 0 5.998 8.485m12.002 -8.485a9 9 0 1 0 -18 0\" />\n                      <path d=\"M12 7v5\" />\n                      <path d=\"M12 15h2a1 1 0 0 1 1 1v1a1 1 0 0 1 -1 1h-1a1 1 0 0 0 -1 1v1a1 1 0 0 0 1 1h2\" />\n                      <path d=\"M18 15v2a1 1 0 0 0 1 1h1\" />\n                      <path d=\"M21 15v6\" />\n                    </svg>\n                  ) : (\n                    <svg\n                      xmlns=\"http://www.w3.org/2000/svg\"\n                      width={24}\n                      height={24}\n                      viewBox=\"0 0 24 24\"\n                      fill=\"none\"\n                      stroke=\"currentColor\"\n                      strokeWidth={2}\n                      strokeLinecap=\"round\"\n                      strokeLinejoin=\"round\"\n                      className=\"icon icon-tabler icons-tabler-outline icon-tabler-clock-12\"\n                    >\n                      <title>12 Hour Format</title>\n                      <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n                      <path d=\"M3 12a9 9 0 0 0 9 9m9 -9a9 9 0 1 0 -18 0\" />\n                      <path d=\"M12 7v5l.5 .5\" />\n                      <path d=\"M18 15h2a1 1 0 0 1 1 1v1a1 1 0 0 1 -1 1h-1a1 1 0 0 0 -1 1v1a1 1 0 0 0 1 1h2\" />\n                      <path d=\"M15 21v-6\" />\n                    </svg>\n                  )\n                }\n                checked={use24HourFormat}\n                onCheckedChange={toggleTimeFormat}\n              />\n            </DropdownMenuShortcut>\n          </DropdownMenuItem>\n        </DropdownMenuGroup>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuLabel>Agenda view group by</DropdownMenuLabel>\n          <DropdownMenuRadioGroup\n            value={agendaModeGroupBy}\n            onValueChange={(value) =>\n              setAgendaModeGroupBy(value as \"date\" | \"color\")\n            }\n          >\n            <DropdownMenuRadioItem value=\"date\">Date</DropdownMenuRadioItem>\n            <DropdownMenuRadioItem value=\"color\">Color</DropdownMenuRadioItem>\n          </DropdownMenuRadioGroup>\n        </DropdownMenuGroup>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/calendar-header-skeleton.tsx",
      "content": "import { Skeleton } from \"@/components/ui/skeleton\";\n\nexport function CalendarHeaderSkeleton() {\n\treturn (\n\t\t<div className=\"flex items-center justify-between border-b px-4 py-2\">\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t<Skeleton className=\"h-8 w-32\" />\n\t\t\t</div>\n\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Skeleton className=\"h-8 w-24\" />\n\t\t\t\t<div className=\"flex gap-1\">\n\t\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t</div>\n\t\t\t\t<Skeleton className=\"h-8 w-24\" />\n\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/calendar-skeleton.tsx",
      "content": "import { CalendarHeaderSkeleton } from \"@/features/calendar/skeletons/calendar-header-skeleton\";\nimport { MonthViewSkeleton } from \"@/features/calendar/skeletons/month-view-skeleton\";\n\nexport function CalendarSkeleton() {\n  return (\n    <div className=\"container mx-auto\">\n      <div className=\"flex h-screen flex-col\">\n        <CalendarHeaderSkeleton />\n        <div className=\"flex-1\">\n          <MonthViewSkeleton />\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/day-view-skeleton.tsx",
      "content": "import { Skeleton } from \"@/components/ui/skeleton\";\n\nexport function DayViewSkeleton() {\n\treturn (\n\t\t<div className=\"flex h-full flex-col\">\n\t\t\t<div className=\"grid grid-cols-2 border-b\">\n\t\t\t\t<div className=\"w-18\"></div>\n\t\t\t\t<div className=\"flex flex-col items-center justify-center py-2\">\n\t\t\t\t\t<Skeleton className=\"h-6 w-24 rounded-full\" />\n\t\t\t\t\t<Skeleton className=\"mt-1 h-4 w-16\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"flex flex-1 overflow-y-auto\">\n\t\t\t\t<div className=\"w-18 flex-shrink-0\">\n\t\t\t\t\t{Array.from({ length: 12 }).map((_, i) => (\n\t\t\t\t\t\t<div key={i} className=\"relative h-12 border-b pr-2 text-right\">\n\t\t\t\t\t\t\t<Skeleton className=\"absolute -top-3 right-2 h-4 w-10\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex-1\">\n\t\t\t\t\t<div className=\"relative\">\n\t\t\t\t\t\t{Array.from({ length: 12 }).map((_, hourIndex) => (\n\t\t\t\t\t\t\t<div key={hourIndex} className=\"h-12 border-b\"></div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/month-view-skeleton.tsx",
      "content": "import { Skeleton } from \"@/components/ui/skeleton\";\n\nexport function MonthViewSkeleton() {\n\treturn (\n\t\t<div className=\"flex h-full flex-col\">\n\t\t\t<div className=\"grid grid-cols-7 border-b py-2\">\n\t\t\t\t{Array.from({ length: 7 }).map((_, i) => (\n\t\t\t\t\t<div key={i} className=\"flex justify-center\">\n\t\t\t\t\t\t<Skeleton className=\"h-6 w-12\" />\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t<div className=\"grid flex-1 grid-cols-7 grid-rows-6\">\n\t\t\t\t{Array.from({ length: 42 }).map((_, i) => (\n\t\t\t\t\t<div key={i} className=\"border-b border-r p-1\">\n\t\t\t\t\t\t<Skeleton className=\"mb-1 h-6 w-6 rounded-full\" />\n\t\t\t\t\t\t<div className=\"mt-1 space-y-1\">\n\t\t\t\t\t\t\t{Array.from({ length: Math.floor(Math.random() * 3) }).map(\n\t\t\t\t\t\t\t\t(_, j) => (\n\t\t\t\t\t\t\t\t\t<Skeleton key={j} className=\"h-5 w-full\" />\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/week-view-skeleton.tsx",
      "content": "import { Skeleton } from \"@/components/ui/skeleton\";\n\nexport function WeekViewSkeleton() {\n\treturn (\n\t\t<div className=\"flex h-full flex-col\">\n\t\t\t<div className=\"grid grid-cols-8 border-b\">\n\t\t\t\t<div className=\"w-18\"></div>\n\t\t\t\t{Array.from({ length: 7 }).map((_, i) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\tclassName=\"flex flex-col items-center justify-center py-2\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Skeleton className=\"h-6 w-10 rounded-full\" />\n\t\t\t\t\t\t<Skeleton className=\"mt-1 h-4 w-6\" />\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t<div className=\"flex flex-1 overflow-y-auto\">\n\t\t\t\t<div className=\"w-18 flex-shrink-0\">\n\t\t\t\t\t{Array.from({ length: 12 }).map((_, i) => (\n\t\t\t\t\t\t<div key={i} className=\"relative h-12 border-b pr-2 text-right\">\n\t\t\t\t\t\t\t<Skeleton className=\"absolute -top-3 right-2 h-4 w-10\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"grid flex-1 grid-cols-7 divide-x\">\n\t\t\t\t\t{Array.from({ length: 7 }).map((_, dayIndex) => (\n\t\t\t\t\t\t<div key={dayIndex} className=\"relative\">\n\t\t\t\t\t\t\t{Array.from({ length: 12 }).map((_, hourIndex) => (\n\t\t\t\t\t\t\t\t<div key={hourIndex} className=\"h-12 border-b\"></div>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/skeletons/year-view-skeleton.tsx",
      "content": "import { Skeleton } from \"@/components/ui/skeleton\";\n\nconst MONTHS = Array.from({ length: 12 });\n\nexport function YearViewSkeleton() {\n\treturn (\n\t\t<div className=\"hidden sm:grid grid-cols-3 gap-4 flex-grow overflow-hidden auto-rows-fr lg:grid-cols-4\">\n\t\t\t{MONTHS.map((_, monthIndex) => (\n\t\t\t\t<div\n\t\t\t\t\tkey={monthIndex}\n\t\t\t\t\tclassName=\"flex flex-col border rounded-md overflow-hidden h-full animate-pulse\"\n\t\t\t\t>\n\t\t\t\t\t<div className=\"bg-primary/5 px-1 py-2 text-center\">\n\t\t\t\t\t\t<Skeleton className=\"h-4 w-24 mx-auto\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"grid grid-cols-7 text-center text-xs py-2 px-1\">\n\t\t\t\t\t\t{Array.from({ length: 7 }).map((_, i) => (\n\t\t\t\t\t\t\t<Skeleton key={i} className=\"h-3 w-3 mx-auto\" />\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"grid grid-cols-7 gap-0 p-1 flex-grow\">\n\t\t\t\t\t\t{Array.from({ length: 42 }).map((_, i) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col items-center justify-center p-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-4 w-4 rounded-full\" />\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-1.5 w-3 mt-1\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/agenda-view/agenda-events.tsx",
      "content": "import { format, parseISO } from \"date-fns\";\nimport type { FC } from \"react\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n} from \"@/components/ui/command\";\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { EventDetailsDialog } from \"@/features/calendar/dialogs/event-details-dialog\";\nimport {\n  formatTime,\n  getBgColor,\n  getColorClass,\n  getEventsForMonth,\n  getFirstLetters,\n  toCapitalize,\n} from \"@/features/calendar/helpers\";\nimport { EventBullet } from \"@/features/calendar/views/month-view/event-bullet\";\n\nexport const AgendaEvents: FC = () => {\n  const {\n    events,\n    use24HourFormat,\n    badgeVariant,\n    agendaModeGroupBy,\n    selectedDate,\n  } = useCalendar();\n\n  const monthEvents = getEventsForMonth(events, selectedDate);\n\n  const agendaEvents = Object.groupBy(monthEvents, (event) => {\n    return agendaModeGroupBy === \"date\"\n      ? format(parseISO(event.startDate), \"yyyy-MM-dd\")\n      : event.color;\n  });\n\n  const groupedAndSortedEvents = Object.entries(agendaEvents).sort(\n    (a, b) => new Date(a[0]).getTime() - new Date(b[0]).getTime(),\n  );\n\n  return (\n    <Command className=\"py-4 h-[80vh] bg-transparent\">\n      <div className=\"mb-4 mx-4\">\n        <CommandInput placeholder=\"Type a command or search...\" />\n      </div>\n      <CommandList className=\"max-h-max px-3 border-t\">\n        {groupedAndSortedEvents.map(([date, groupedEvents]) => (\n          <CommandGroup\n            key={date}\n            heading={\n              agendaModeGroupBy === \"date\"\n                ? format(parseISO(date), \"EEEE, MMMM d, yyyy\")\n                : toCapitalize(groupedEvents![0].color)\n            }\n          >\n            {groupedEvents!.map((event) => (\n              <CommandItem\n                key={event.id}\n                className={cn(\n                  \"mb-2 p-4 border rounded-md data-[selected=true]:bg-bg transition-all data-[selected=true]:text-none hover:cursor-pointer\",\n                  {\n                    [getColorClass(event.color)]: badgeVariant === \"colored\",\n                    \"hover:bg-zinc-200 dark:hover:bg-gray-900\":\n                      badgeVariant === \"dot\",\n                    \"hover:opacity-60\": badgeVariant === \"colored\",\n                  },\n                )}\n              >\n                <EventDetailsDialog event={event}>\n                  <div className=\"w-full flex items-center justify-between gap-4\">\n                    <div className=\"flex items-center gap-2\">\n                      {badgeVariant === \"dot\" ? (\n                        <EventBullet color={event.color} />\n                      ) : (\n                        <Avatar>\n                          <AvatarImage src=\"\" alt=\"@shadcn\" />\n                          <AvatarFallback className={getBgColor(event.color)}>\n                            {getFirstLetters(event.title)}\n                          </AvatarFallback>\n                        </Avatar>\n                      )}\n                      <div className=\"flex flex-col\">\n                        <p\n                          className={cn({\n                            \"font-medium\": badgeVariant === \"dot\",\n                            \"text-foreground\": badgeVariant === \"dot\",\n                          })}\n                        >\n                          {event.title}\n                        </p>\n                        <p className=\"text-muted-foreground text-sm line-clamp-1 text-ellipsis md:text-clip w-1/3\">\n                          {event.description}\n                        </p>\n                      </div>\n                    </div>\n                    <div className=\"w-40 flex justify-center items-center gap-1\">\n                      {agendaModeGroupBy === \"date\" ? (\n                        <>\n                          <p className=\"text-sm\">\n                            {formatTime(event.startDate, use24HourFormat)}\n                          </p>\n                          <span className=\"text-muted-foreground\">-</span>\n                          <p className=\"text-sm\">\n                            {formatTime(event.endDate, use24HourFormat)}\n                          </p>\n                        </>\n                      ) : (\n                        <>\n                          <p className=\"text-sm\">\n                            {format(event.startDate, \"MM/dd/yyyy\")}\n                          </p>\n                          <span className=\"text-sm\">at</span>\n                          <p className=\"text-sm\">\n                            {formatTime(event.startDate, use24HourFormat)}\n                          </p>\n                        </>\n                      )}\n                    </div>\n                  </div>\n                </EventDetailsDialog>\n              </CommandItem>\n            ))}\n          </CommandGroup>\n        ))}\n        <CommandEmpty>No results found.</CommandEmpty>\n      </CommandList>\n    </Command>\n  );\n};\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/month-view/calendar-month-view.tsx",
      "content": "import { motion } from \"framer-motion\";\nimport { useMemo } from \"react\";\nimport {\n\tstaggerContainer,\n\ttransition,\n} from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nimport {\n\tcalculateMonthEventPositions,\n\tgetCalendarCells,\n} from \"@/features/calendar/helpers\";\n\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { DayCell } from \"@/features/calendar/views/month-view/day-cell\";\n\ninterface IProps {\n\tsingleDayEvents: IEvent[];\n\tmultiDayEvents: IEvent[];\n}\n\nconst WEEK_DAYS = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\nexport function CalendarMonthView({ singleDayEvents, multiDayEvents }: IProps) {\n\tconst { selectedDate } = useCalendar();\n\n\tconst allEvents = [...multiDayEvents, ...singleDayEvents];\n\n\tconst cells = useMemo(() => getCalendarCells(selectedDate), [selectedDate]);\n\n\tconst eventPositions = useMemo(\n\t\t() =>\n\t\t\tcalculateMonthEventPositions(\n\t\t\t\tmultiDayEvents,\n\t\t\t\tsingleDayEvents,\n\t\t\t\tselectedDate,\n\t\t\t),\n\t\t[multiDayEvents, singleDayEvents, selectedDate],\n\t);\n\n\treturn (\n\t\t<motion.div initial=\"initial\" animate=\"animate\" variants={staggerContainer}>\n\t\t\t<div className=\"grid grid-cols-7\">\n\t\t\t\t{WEEK_DAYS.map((day, index) => (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tkey={day}\n\t\t\t\t\t\tclassName=\"flex items-center justify-center py-2\"\n\t\t\t\t\t\tinitial={{ opacity: 0, y: -10 }}\n\t\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\t\ttransition={{ delay: index * 0.05, ...transition }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span className=\"text-xs font-medium text-t-quaternary\">{day}</span>\n\t\t\t\t\t</motion.div>\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t<div className=\"grid grid-cols-7 overflow-hidden\">\n\t\t\t\t{cells.map((cell) => (\n\t\t\t\t\t<DayCell\n\t\t\t\t\t\tkey={cell.date.toISOString()}\n\t\t\t\t\t\tcell={cell}\n\t\t\t\t\t\tevents={allEvents}\n\t\t\t\t\t\teventPositions={eventPositions}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</motion.div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/month-view/day-cell.tsx",
      "content": "\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { isToday, startOfDay, isSunday, isSameMonth } from \"date-fns\";\nimport { motion } from \"framer-motion\";\nimport { useMemo, useCallback } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { transition } from \"@/features/calendar/animations\";\nimport { EventListDialog } from \"@/features/calendar/dialogs/events-list-dialog\";\nimport { DroppableArea } from \"@/features/calendar/dnd/droppable-area\";\nimport { getMonthCellEvents } from \"@/features/calendar/helpers\";\nimport { useMediaQuery } from \"@/features/calendar/hooks\";\nimport type { ICalendarCell, IEvent } from \"@/features/calendar/interfaces\";\nimport { EventBullet } from \"@/features/calendar/views/month-view/event-bullet\";\nimport { MonthEventBadge } from \"@/features/calendar/views/month-view/month-event-badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Plus } from \"lucide-react\";\nimport { AddEditEventDialog } from \"@/features/calendar/dialogs/add-edit-event-dialog\";\n\ninterface IProps {\n  cell: ICalendarCell;\n  events: IEvent[];\n  eventPositions: Record<string, number>;\n}\n\nexport const dayCellVariants = cva(\"text-white\", {\n  variants: {\n    color: {\n      blue: \"bg-blue-600 dark:bg-blue-500 hover:bg-blue-700 dark:hover:bg-blue-400 \",\n      green:\n        \"bg-green-600 dark:bg-green-500 hover:bg-green-700 dark:hover:bg-green-400\",\n      red: \"bg-red-600 dark:bg-red-500 hover:bg-red-700 dark:hover:bg-red-400\",\n      yellow:\n        \"bg-yellow-600 dark:bg-yellow-500 hover:bg-yellow-700 dark:hover:bg-yellow-400\",\n      purple:\n        \"bg-purple-600 dark:bg-purple-500 hover:bg-purple-700 dark:hover:bg-purple-400\",\n      orange:\n        \"bg-orange-600 dark:bg-orange-500 hover:bg-orange-700 dark:hover:bg-orange-400\",\n      gray: \"bg-gray-600 dark:bg-gray-500 hover:bg-gray-700 dark:hover:bg-gray-400\",\n    },\n  },\n  defaultVariants: {\n    color: \"blue\",\n  },\n});\n\nconst MAX_VISIBLE_EVENTS = 3;\n\nexport function DayCell({ cell, events, eventPositions }: IProps) {\n  const { day, currentMonth, date } = cell;\n  const isMobile = useMediaQuery(\"(max-width: 768px)\");\n\n  // Memoize cellEvents and currentCellMonth for performance\n  const { cellEvents, currentCellMonth } = useMemo(() => {\n    const cellEvents = getMonthCellEvents(date, events, eventPositions);\n    const currentCellMonth = startOfDay(\n      new Date(date.getFullYear(), date.getMonth(), 1),\n    );\n    return { cellEvents, currentCellMonth };\n  }, [date, events, eventPositions]);\n\n  // Memoize event rendering for each position with animation\n  const renderEventAtPosition = useCallback(\n    (position: number) => {\n      const event = cellEvents.find((e) => e.position === position);\n      if (!event) {\n        return (\n          <motion.div\n            key={`empty-${position}`}\n            className=\"lg:flex-1\"\n            initial={false}\n            animate={false}\n          />\n        );\n      }\n      const showBullet = isSameMonth(\n        new Date(event.startDate),\n        currentCellMonth,\n      );\n\n      return (\n        <motion.div\n          key={`event-${event.id}-${position}`}\n          className=\"lg:flex-1\"\n          initial={{ opacity: 0, x: -10 }}\n          animate={{ opacity: 1, x: 0 }}\n          transition={{ delay: position * 0.1, ...transition }}\n        >\n          {showBullet && (\n            <EventBullet className=\"lg:hidden\" color={event.color} />\n          )}\n          <MonthEventBadge\n            className=\"hidden lg:flex\"\n            event={event}\n            cellDate={startOfDay(date)}\n          />\n        </motion.div>\n      );\n    },\n    [cellEvents, currentCellMonth, date],\n  );\n\n  const showMoreCount = cellEvents.length - MAX_VISIBLE_EVENTS;\n\n  const showMobileMore = isMobile && currentMonth && showMoreCount > 0;\n  const showDesktopMore = !isMobile && currentMonth && showMoreCount > 0;\n\n  const cellContent = useMemo(\n    () => (\n      <motion.div\n        className={cn(\n          \"flex h-full lg:min-h-40 flex-col gap-1 border-l border-t\",\n          isSunday(date) && \"border-l-0\",\n        )}\n        initial={{ opacity: 0, y: 10 }}\n        animate={{ opacity: 1, y: 0 }}\n        transition={transition}\n      >\n        <DroppableArea date={date} className=\"w-full h-full py-2\">\n          <motion.span\n            className={cn(\n              \"h-6 px-1 text-xs font-semibold lg:px-2\",\n              !currentMonth && \"opacity-20\",\n              isToday(date) &&\n                \"flex w-6 translate-x-1 items-center justify-center rounded-full bg-primary px-0 font-bold text-primary-foreground\",\n            )}\n          >\n            {day}\n          </motion.span>\n\n          <motion.div\n            className={cn(\n              \"flex h-fit gap-1 px-2 mt-1 lg:h-[94px] lg:flex-col lg:gap-2 lg:px-0\",\n              !currentMonth && \"opacity-50\",\n            )}\n          >\n            {cellEvents.length === 0 && !isMobile ? (\n              <div className=\"w-full h-full flex justify-center items-center group\">\n                <AddEditEventDialog startDate={date}>\n                  <Button\n                    variant=\"ghost\"\n                    className=\"border opacity-0 group-hover:opacity-100 transition-opacity duration-200\"\n                  >\n                    <Plus className=\"h-4 w-4\" />\n                    <span className=\"max-sm:hidden\">Add Event</span>\n                  </Button>\n                </AddEditEventDialog>\n              </div>\n            ) : (\n              [0, 1, 2].map(renderEventAtPosition)\n            )}\n          </motion.div>\n\n          {showMobileMore && (\n            <div className=\"flex justify-end items-end mx-2\">\n              <span className=\"text-[0.6rem] font-semibold text-accent-foreground\">\n                +{showMoreCount}\n              </span>\n            </div>\n          )}\n\n          {showDesktopMore && (\n            <motion.div\n              className={cn(\n                \"h-4.5 px-1.5 my-2 text-end text-xs font-semibold text-muted-foreground\",\n                !currentMonth && \"opacity-50\",\n              )}\n              initial={{ opacity: 0, y: 5 }}\n              animate={{ opacity: 1, y: 0 }}\n              transition={{ delay: 0.3, ...transition }}\n            >\n              <EventListDialog date={date} events={cellEvents} />\n            </motion.div>\n          )}\n        </DroppableArea>\n      </motion.div>\n    ),\n    [\n      date,\n      day,\n      currentMonth,\n      cellEvents,\n      showMobileMore,\n      showDesktopMore,\n      showMoreCount,\n      renderEventAtPosition,\n      isMobile,\n    ],\n  );\n\n  if (isMobile && currentMonth) {\n    return (\n      <EventListDialog date={date} events={cellEvents}>\n        {cellContent}\n      </EventListDialog>\n    );\n  }\n\n  return cellContent;\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/month-view/event-bullet.tsx",
      "content": "import { cva } from \"class-variance-authority\";\nimport { motion } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\nimport { transition } from \"@/features/calendar/animations\";\nimport type { TEventColor } from \"@/features/calendar/types\";\n\nconst eventBulletVariants = cva(\"size-2 rounded-full\", {\n  variants: {\n    color: {\n      blue: \"bg-blue-600 dark:bg-blue-500\",\n      green: \"bg-green-600 dark:bg-green-500\",\n      red: \"bg-red-600 dark:bg-red-500\",\n      yellow: \"bg-yellow-600 dark:bg-yellow-500\",\n      purple: \"bg-purple-600 dark:bg-purple-500\",\n      orange: \"bg-orange-600 dark:bg-orange-500\",\n      gray: \"bg-gray-600 dark:bg-gray-500\",\n    },\n  },\n  defaultVariants: {\n    color: \"blue\",\n  },\n});\n\nexport function EventBullet({\n  color,\n  className,\n}: {\n  color: TEventColor;\n  className?: string;\n}) {\n  return (\n    <motion.div\n      className={cn(eventBulletVariants({ color, className }))}\n      initial={{ scale: 0, opacity: 0 }}\n      animate={{ scale: 1, opacity: 1 }}\n      whileHover={{ scale: 1.2 }}\n      transition={transition}\n    />\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/month-view/month-event-badge.tsx",
      "content": "import type { VariantProps } from \"class-variance-authority\";\nimport { cva } from \"class-variance-authority\";\nimport { endOfDay, isSameDay, parseISO, startOfDay } from \"date-fns\";\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { EventDetailsDialog } from \"@/features/calendar/dialogs/event-details-dialog\";\nimport { DraggableEvent } from \"@/features/calendar/dnd/draggable-event\";\nimport { formatTime } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { EventBullet } from \"@/features/calendar/views/month-view/event-bullet\";\n\nconst eventBadgeVariants = cva(\n  \"flex w-full h-6.5 select-none items-center justify-between gap-1.5 truncate whitespace-nowrap rounded-md border px-2 text-xs cursor-grab\",\n  {\n    variants: {\n      color: {\n        // Colored variants\n        blue: \"border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300\",\n        green:\n          \"border-green-200 bg-green-50 text-green-700 dark:border-green-800 dark:bg-green-950 dark:text-green-300\",\n        red: \"border-red-200 bg-red-50 text-red-700 dark:border-red-800 dark:bg-red-950 dark:text-red-300\",\n        yellow:\n          \"border-yellow-200 bg-yellow-50 text-yellow-700 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-300\",\n        purple:\n          \"border-purple-200 bg-purple-50 text-purple-700 dark:border-purple-800 dark:bg-purple-950 dark:text-purple-300\",\n        orange:\n          \"border-orange-200 bg-orange-50 text-orange-700 dark:border-orange-800 dark:bg-orange-950 dark:text-orange-300\",\n\n        // Dot variants\n        \"blue-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-blue-600\",\n        \"green-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-green-600\",\n        \"red-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-red-600\",\n        \"orange-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-orange-600\",\n        \"purple-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-purple-600\",\n        \"yellow-dot\": \"bg-bg-secondary text-t-primary [&_svg]:fill-yellow-600\",\n      },\n      multiDayPosition: {\n        first: \"relative z-10 mr-0 rounded-r-none border-r-0 [&>span]:mr-2.5\",\n        middle:\n          \"relative z-10 mx-0 w-[calc(100%_+_1px)] rounded-none border-x-0\",\n        last: \"ml-0 rounded-l-none border-l-0\",\n        none: \"\",\n      },\n    },\n    defaultVariants: {\n      color: \"blue-dot\",\n    },\n  },\n);\n\ninterface IProps extends Omit<\n  VariantProps<typeof eventBadgeVariants>,\n  \"color\" | \"multiDayPosition\"\n> {\n  event: IEvent;\n  cellDate: Date;\n  eventCurrentDay?: number;\n  eventTotalDays?: number;\n  className?: string;\n  position?: \"first\" | \"middle\" | \"last\" | \"none\";\n}\n\nexport function MonthEventBadge({\n  event,\n  cellDate,\n  eventCurrentDay,\n  eventTotalDays,\n  className,\n  position: propPosition,\n}: IProps) {\n  const { badgeVariant, use24HourFormat } = useCalendar();\n\n  const itemStart = startOfDay(parseISO(event.startDate));\n  const itemEnd = endOfDay(parseISO(event.endDate));\n\n  if (cellDate < itemStart || cellDate > itemEnd) return null;\n\n  let position: \"first\" | \"middle\" | \"last\" | \"none\" | undefined;\n\n  if (propPosition) {\n    position = propPosition;\n  } else if (eventCurrentDay && eventTotalDays) {\n    position = \"none\";\n  } else if (isSameDay(itemStart, itemEnd)) {\n    position = \"none\";\n  } else if (isSameDay(cellDate, itemStart)) {\n    position = \"first\";\n  } else if (isSameDay(cellDate, itemEnd)) {\n    position = \"last\";\n  } else {\n    position = \"middle\";\n  }\n\n  const renderBadgeText = [\"first\", \"none\"].includes(position);\n  const renderBadgeTime = [\"last\", \"none\"].includes(position);\n\n  const color = (\n    badgeVariant === \"dot\" ? `${event.color}-dot` : event.color\n  ) as VariantProps<typeof eventBadgeVariants>[\"color\"];\n\n  const eventBadgeClasses = cn(\n    eventBadgeVariants({ color, multiDayPosition: position, className }),\n  );\n\n  const marginClass = {\n    first: \"ml-1 mr-0\",\n    middle: \"mx-0\",\n    last: \"ml-0 mr-1\",\n    none: \"mx-1\",\n  }[position || \"none\"];\n\n  return (\n    <DraggableEvent event={event} className={marginClass}>\n      <EventDetailsDialog event={event}>\n        <button type=\"button\" className={eventBadgeClasses}>\n          <div className=\"flex items-center gap-1.5 truncate\">\n            {![\"middle\", \"last\"].includes(position) &&\n              badgeVariant === \"dot\" && <EventBullet color={event.color} />}\n\n            {renderBadgeText && (\n              <p className=\"flex-1 truncate font-semibold\">\n                {eventCurrentDay && (\n                  <span className=\"text-xs\">\n                    Day {eventCurrentDay} of {eventTotalDays} •{\" \"}\n                  </span>\n                )}\n                {event.title}\n              </p>\n            )}\n          </div>\n\n          <div className=\"hidden sm:block\">\n            {renderBadgeTime && (\n              <span>\n                {formatTime(new Date(event.startDate), use24HourFormat)}\n              </span>\n            )}\n          </div>\n        </button>\n      </EventDetailsDialog>\n    </DraggableEvent>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/calendar-day-view.tsx",
      "content": "import { format, isWithinInterval, parseISO } from \"date-fns\";\nimport { Calendar, Clock, User } from \"lucide-react\";\nimport { useEffect, useRef } from \"react\";\nimport { DayPicker } from \"@/components/ui/day-picker\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\n\nimport { AddEditEventDialog } from \"@/features/calendar/dialogs/add-edit-event-dialog\";\nimport { DroppableArea } from \"@/features/calendar/dnd/droppable-area\";\nimport { groupEvents } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { CalendarTimeline } from \"@/features/calendar/views/week-and-day-view/calendar-time-line\";\nimport { DayViewMultiDayEventsRow } from \"@/features/calendar/views/week-and-day-view/day-view-multi-day-events-row\";\nimport { RenderGroupedEvents } from \"@/features/calendar/views/week-and-day-view/render-grouped-events\";\n\ninterface IProps {\n  singleDayEvents: IEvent[];\n  multiDayEvents: IEvent[];\n}\n\nexport function CalendarDayView({ singleDayEvents, multiDayEvents }: IProps) {\n  const { selectedDate, setSelectedDate, users, use24HourFormat } =\n    useCalendar();\n  const scrollAreaRef = useRef<HTMLDivElement>(null);\n\n  const hours = Array.from({ length: 24 }, (_, i) => i);\n\n  useEffect(() => {\n    const handleDragOver = (e: DragEvent) => {\n      if (!scrollAreaRef.current) return;\n\n      const scrollArea = scrollAreaRef.current;\n      const rect = scrollArea.getBoundingClientRect();\n      const scrollSpeed = 15;\n\n      const scrollContainer =\n        scrollArea.querySelector(\"[data-radix-scroll-area-viewport]\") ||\n        scrollArea;\n\n      if (e.clientY < rect.top + 60) {\n        scrollContainer.scrollTop -= scrollSpeed;\n      }\n\n      if (e.clientY > rect.bottom - 60) {\n        scrollContainer.scrollTop += scrollSpeed;\n      }\n    };\n\n    document.addEventListener(\"dragover\", handleDragOver);\n    return () => {\n      document.removeEventListener(\"dragover\", handleDragOver);\n    };\n  }, []);\n\n  const getCurrentEvents = (events: IEvent[]) => {\n    const now = new Date();\n\n    return (\n      events.filter((event) =>\n        isWithinInterval(now, {\n          start: parseISO(event.startDate),\n          end: parseISO(event.endDate),\n        }),\n      ) || []\n    );\n  };\n\n  const currentEvents = getCurrentEvents(singleDayEvents);\n\n  const dayEvents = singleDayEvents.filter((event) => {\n    const eventDate = parseISO(event.startDate);\n    return (\n      eventDate.getDate() === selectedDate.getDate() &&\n      eventDate.getMonth() === selectedDate.getMonth() &&\n      eventDate.getFullYear() === selectedDate.getFullYear()\n    );\n  });\n\n  const groupedEvents = groupEvents(dayEvents);\n\n  return (\n    <div className=\"flex\">\n      <div className=\"flex flex-1 flex-col\">\n        <div>\n          <DayViewMultiDayEventsRow\n            selectedDate={selectedDate}\n            multiDayEvents={multiDayEvents}\n          />\n\n          {/* Day header */}\n          <div className=\"relative z-20 flex border-b\">\n            <div className=\"w-18\"></div>\n            <span className=\"flex-1 border-l py-2 text-center text-xs font-medium text-t-quaternary\">\n              {format(selectedDate, \"EE\")}{\" \"}\n              <span className=\"font-semibold text-t-secondary\">\n                {format(selectedDate, \"d\")}\n              </span>\n            </span>\n          </div>\n        </div>\n\n        <ScrollArea className=\"h-[800px]\" type=\"always\" ref={scrollAreaRef}>\n          <div className=\"flex\">\n            {/* Hours column */}\n            <div className=\"relative w-18\">\n              {hours.map((hour, index) => (\n                <div key={hour} className=\"relative\" style={{ height: \"96px\" }}>\n                  <div className=\"absolute -top-3 right-2 flex h-6 items-center\">\n                    {index !== 0 && (\n                      <span className=\"text-xs text-t-quaternary\">\n                        {format(\n                          new Date().setHours(hour, 0, 0, 0),\n                          use24HourFormat ? \"HH:00\" : \"h a\",\n                        )}\n                      </span>\n                    )}\n                  </div>\n                </div>\n              ))}\n            </div>\n\n            {/* Day grid */}\n            <div className=\"relative flex-1 border-l\">\n              <div className=\"relative\">\n                {hours.map((hour, index) => (\n                  <div\n                    key={hour}\n                    className=\"relative\"\n                    style={{ height: \"96px\" }}\n                  >\n                    {index !== 0 && (\n                      <div className=\"pointer-events-none absolute inset-x-0 top-0 border-b\"></div>\n                    )}\n\n                    <DroppableArea\n                      date={selectedDate}\n                      hour={hour}\n                      minute={0}\n                      className=\"absolute inset-x-0 top-0 h-[48px]\"\n                    >\n                      <AddEditEventDialog\n                        startDate={selectedDate}\n                        startTime={{ hour, minute: 0 }}\n                      >\n                        <div className=\"absolute inset-0 cursor-pointer transition-colors hover:bg-secondary\" />\n                      </AddEditEventDialog>\n                    </DroppableArea>\n\n                    <div className=\"pointer-events-none absolute inset-x-0 top-1/2 border-b border-dashed border-b-tertiary\"></div>\n\n                    <DroppableArea\n                      date={selectedDate}\n                      hour={hour}\n                      minute={30}\n                      className=\"absolute inset-x-0 bottom-0 h-[48px]\"\n                    >\n                      <AddEditEventDialog\n                        startDate={selectedDate}\n                        startTime={{ hour, minute: 30 }}\n                      >\n                        <div className=\"absolute inset-0 cursor-pointer transition-colors hover:bg-secondary\" />\n                      </AddEditEventDialog>\n                    </DroppableArea>\n                  </div>\n                ))}\n\n                <RenderGroupedEvents\n                  groupedEvents={groupedEvents}\n                  day={selectedDate}\n                />\n              </div>\n\n              <CalendarTimeline />\n            </div>\n          </div>\n        </ScrollArea>\n      </div>\n\n      <div className=\"hidden w-72 divide-y border-l md:block\">\n        <DayPicker\n          className=\"mx-auto w-fit\"\n          mode=\"single\"\n          selected={selectedDate}\n          onSelect={(date) => date && setSelectedDate(date)}\n          initialFocus\n        />\n\n        <div className=\"flex-1 space-y-3\">\n          {currentEvents.length > 0 ? (\n            <div className=\"flex items-start gap-2 px-4 pt-4\">\n              <span className=\"relative mt-[5px] flex size-2.5\">\n                <span className=\"absolute inline-flex size-full animate-ping rounded-full bg-green-400 opacity-75\"></span>\n                <span className=\"relative inline-flex size-2.5 rounded-full bg-green-600\"></span>\n              </span>\n\n              <p className=\"text-sm font-semibold text-t-secondary\">\n                Happening now\n              </p>\n            </div>\n          ) : (\n            <p className=\"p-4 text-center text-sm italic text-t-tertiary\">\n              No appointments or consultations at the moment\n            </p>\n          )}\n\n          {currentEvents.length > 0 && (\n            <ScrollArea className=\"h-[422px] px-4\" type=\"always\">\n              <div className=\"space-y-6 pb-4\">\n                {currentEvents.map((event) => {\n                  const user = users.find((user) => user.id === event.user.id);\n\n                  return (\n                    <div key={event.id} className=\"space-y-1.5\">\n                      <p className=\"line-clamp-2 text-sm font-semibold\">\n                        {event.title}\n                      </p>\n\n                      {user && (\n                        <div className=\"flex items-center gap-1.5\">\n                          <User className=\"size-4 text-t-quinary\" />\n                          <span className=\"text-sm text-t-tertiary\">\n                            {user.name}\n                          </span>\n                        </div>\n                      )}\n\n                      <div className=\"flex items-center gap-1.5\">\n                        <Calendar className=\"size-4 text-t-quinary\" />\n                        <span className=\"text-sm text-t-tertiary\">\n                          {format(new Date(event.startDate), \"MMM d, yyyy\")}\n                        </span>\n                      </div>\n\n                      <div className=\"flex items-center gap-1.5\">\n                        <Clock className=\"size-4 text-t-quinary\" />\n                        <span className=\"text-sm text-t-tertiary\">\n                          {format(\n                            parseISO(event.startDate),\n                            use24HourFormat ? \"HH:mm\" : \"hh:mm a\",\n                          )}{\" \"}\n                          -\n                          {format(\n                            parseISO(event.endDate),\n                            use24HourFormat ? \"HH:mm\" : \"hh:mm a\",\n                          )}\n                        </span>\n                      </div>\n                    </div>\n                  );\n                })}\n              </div>\n            </ScrollArea>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/calendar-time-line.tsx",
      "content": "import { useEffect, useState } from \"react\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { formatTime } from \"@/features/calendar/helpers\";\n\nexport function CalendarTimeline() {\n  const { use24HourFormat } = useCalendar();\n  const [currentTime, setCurrentTime] = useState(new Date());\n\n  useEffect(() => {\n    const timer = setInterval(() => setCurrentTime(new Date()), 60 * 1000);\n    return () => clearInterval(timer);\n  }, []);\n\n  const getCurrentTimePosition = () => {\n    const minutes = currentTime.getHours() * 60 + currentTime.getMinutes();\n    return (minutes / 1440) * 100;\n  };\n\n  const formatCurrentTime = () => {\n    return formatTime(currentTime, use24HourFormat);\n  };\n\n  return (\n    <div\n      className=\"pointer-events-none absolute inset-x-0 z-50 border-t border-primary\"\n      style={{ top: `${getCurrentTimePosition()}%` }}\n    >\n      <div className=\"absolute -left-1.5 -top-1.5 size-3 rounded-full bg-primary\"></div>\n\n      <div className=\"absolute -left-18 flex w-16 -translate-y-1/2 justify-end bg-background pr-1 text-xs font-medium text-primary\">\n        {formatCurrentTime()}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/calendar-week-view.tsx",
      "content": "import {addDays, format, isSameDay, parseISO, startOfWeek} from \"date-fns\";\nimport {motion} from \"framer-motion\";\nimport {ScrollArea} from \"@/components/ui/scroll-area\";\nimport {\n    fadeIn,\n    staggerContainer,\n    transition,\n} from \"@/features/calendar/animations\";\nimport {useCalendar} from \"@/features/calendar/contexts/calendar-context\";\nimport {AddEditEventDialog} from \"@/features/calendar/dialogs/add-edit-event-dialog\";\nimport {DroppableArea} from \"@/features/calendar/dnd/droppable-area\";\nimport {groupEvents} from \"@/features/calendar/helpers\";\nimport type {IEvent} from \"@/features/calendar/interfaces\";\nimport {CalendarTimeline} from \"@/features/calendar/views/week-and-day-view/calendar-time-line\";\nimport {RenderGroupedEvents} from \"@/features/calendar/views/week-and-day-view/render-grouped-events\";\nimport {\n    WeekViewMultiDayEventsRow\n} from \"@/features/calendar/views/week-and-day-view/week-view-multi-day-events-row\";\nimport {AlertCircleIcon} from 'lucide-react'\n\ninterface IProps {\n    singleDayEvents: IEvent[];\n    multiDayEvents: IEvent[];\n}\n\nexport function CalendarWeekView({singleDayEvents, multiDayEvents}: IProps) {\n    const {selectedDate, use24HourFormat} = useCalendar();\n\n    const weekStart = startOfWeek(selectedDate);\n    const weekDays = Array.from({length: 7}, (_, i) => addDays(weekStart, i));\n    const hours = Array.from({length: 24}, (_, i) => i);\n\n    return (\n        <motion.div\n            initial=\"initial\"\n            animate=\"animate\"\n            exit=\"exit\"\n            variants={fadeIn}\n            transition={transition}\n        >\n            <motion.div\n                className=\"flex flex-col items-center justify-center border-b p-4 text-sm sm:hidden\"\n                initial={{opacity: 0, y: -20}}\n                animate={{opacity: 1, y: 0}}\n                transition={transition}\n            >\n                <p>Weekly view is not recommended on smaller devices.</p>\n                <p>Please switch to a desktop device or use the daily view instead.</p>\n            </motion.div>\n\n            <motion.div\n                className=\"flex-col sm:flex\"\n                variants={staggerContainer}\n            >\n                <div>\n                    <WeekViewMultiDayEventsRow\n                        selectedDate={selectedDate}\n                        multiDayEvents={multiDayEvents}\n                    />\n\n                    {/* Week header */}\n                    <motion.div\n                        className=\"relative z-20 flex border-b\"\n                        initial={{opacity: 0, y: -20}}\n                        animate={{opacity: 1, y: 0}}\n                        transition={transition}\n                    >\n                        {/* Time column header - responsive width */}\n                        <div className=\"w-18\"></div>\n                        <div className=\"grid flex-1 grid-cols-7  border-l\">\n                            {weekDays.map((day, index) => (\n                                <motion.span\n                                    key={day.toISOString()}\n                                    className=\"py-1 sm:py-2 text-center text-xs font-medium text-t-quaternary\"\n                                    initial={{opacity: 0, y: -10}}\n                                    animate={{opacity: 1, y: 0}}\n                                    transition={{delay: index * 0.05, ...transition}}\n                                >\n                                    {/* Mobile: Show only day abbreviation and number */}\n                                    <span className=\"block sm:hidden\">\n\t\t\t\t\t\t\t\t\t{format(day, \"EEE\").charAt(0)}\n                                        <span className=\"block font-semibold text-t-secondary text-xs\">\n\t\t\t\t\t\t\t\t\t\t{format(day, \"d\")}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</span>\n                                    {/* Desktop: Show full format */}\n                                    <span className=\"hidden sm:inline\">\n\t\t\t\t\t\t\t\t\t{format(day, \"EE\")}{\" \"}\n                                        <span className=\"ml-1 font-semibold text-t-secondary\">\n\t\t\t\t\t\t\t\t\t\t{format(day, \"d\")}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</span>\n                                </motion.span>\n                            ))}\n                        </div>\n                    </motion.div>\n\n                </div>\n\n                <ScrollArea className=\"h-[736px]\" type=\"always\">\n                    <div className=\"flex\">\n                        {/* Hours column */}\n                        <motion.div className=\"relative w-18\" variants={staggerContainer}>\n                            {hours.map((hour, index) => (\n                                <motion.div\n                                    key={hour}\n                                    className=\"relative\"\n                                    style={{height: \"96px\"}}\n                                    initial={{opacity: 0, x: -20}}\n                                    animate={{opacity: 1, x: 0}}\n                                    transition={{delay: index * 0.02, ...transition}}\n                                >\n                                    <div className=\"absolute -top-3 right-2 flex h-6 items-center\">\n                                        {index !== 0 && (\n                                            <span className=\"text-xs text-t-quaternary\">\n\t\t\t\t\t\t\t\t\t\t\t\t{format(\n                                                    new Date().setHours(hour, 0, 0, 0),\n                                                    use24HourFormat ? \"HH:00\" : \"h a\",\n                                                )}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n                                        )}\n                                    </div>\n                                </motion.div>\n                            ))}\n                        </motion.div>\n\n                        {/* Week grid */}\n                        <motion.div\n                            className=\"relative flex-1 border-l\"\n                            variants={staggerContainer}\n                        >\n                            <div className=\"grid grid-cols-7 divide-x\">\n                                {weekDays.map((day, dayIndex) => {\n                                    const dayEvents = singleDayEvents.filter(\n                                        (event) =>\n                                            isSameDay(parseISO(event.startDate), day) ||\n                                            isSameDay(parseISO(event.endDate), day),\n                                    );\n                                    const groupedEvents = groupEvents(dayEvents);\n\n                                    return (\n                                        <motion.div\n                                            key={day.toISOString()}\n                                            className=\"relative\"\n                                            initial={{opacity: 0}}\n                                            animate={{opacity: 1}}\n                                            transition={{delay: dayIndex * 0.1, ...transition}}\n                                        >\n                                            {hours.map((hour, index) => (\n                                                <motion.div\n                                                    key={hour}\n                                                    className=\"relative\"\n                                                    style={{height: \"96px\"}}\n                                                    initial={{opacity: 0}}\n                                                    animate={{opacity: 1}}\n                                                    transition={{delay: index * 0.01, ...transition}}\n                                                >\n                                                    {index !== 0 && (\n                                                        <div\n                                                            className=\"pointer-events-none absolute inset-x-0 top-0 border-b\"></div>\n                                                    )}\n\n                                                    <DroppableArea\n                                                        date={day}\n                                                        hour={hour}\n                                                        minute={0}\n                                                        className=\"absolute inset-x-0 top-0  h-[48px]\"\n                                                    >\n                                                        <AddEditEventDialog\n                                                            startDate={day}\n                                                            startTime={{hour, minute: 0}}\n                                                        >\n                                                            <div\n                                                                className=\"absolute inset-0 cursor-pointer transition-colors hover:bg-secondary\"/>\n                                                        </AddEditEventDialog>\n                                                    </DroppableArea>\n\n                                                    <div\n                                                        className=\"pointer-events-none absolute inset-x-0 top-1/2 border-b border-dashed border-b-tertiary\"></div>\n\n                                                    <DroppableArea\n                                                        date={day}\n                                                        hour={hour}\n                                                        minute={30}\n                                                        className=\"absolute inset-x-0 bottom-0 h-[48px]\"\n                                                    >\n                                                        <AddEditEventDialog\n                                                            startDate={day}\n                                                            startTime={{hour, minute: 30}}\n                                                        >\n                                                            <div\n                                                                className=\"absolute inset-0 cursor-pointer transition-colors hover:bg-secondary\"/>\n                                                        </AddEditEventDialog>\n                                                    </DroppableArea>\n                                                </motion.div>\n                                            ))}\n\n                                            <RenderGroupedEvents\n                                                groupedEvents={groupedEvents}\n                                                day={day}\n                                            />\n                                        </motion.div>\n                                    );\n                                })}\n                            </div>\n\n                            <CalendarTimeline/>\n                        </motion.div>\n                    </div>\n                </ScrollArea>\n            </motion.div>\n        </motion.div>\n    );\n}\n\n\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/day-view-multi-day-events-row.tsx",
      "content": "import {\n  differenceInDays,\n  endOfDay,\n  isWithinInterval,\n  parseISO,\n  startOfDay,\n} from \"date-fns\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { MonthEventBadge } from \"@/features/calendar/views/month-view/month-event-badge\";\n\ninterface IProps {\n  selectedDate: Date;\n  multiDayEvents: IEvent[];\n}\n\nexport function DayViewMultiDayEventsRow({\n  selectedDate,\n  multiDayEvents,\n}: IProps) {\n  const dayStart = startOfDay(selectedDate);\n  const dayEnd = endOfDay(selectedDate);\n\n  const multiDayEventsInDay = multiDayEvents\n    .filter((event) => {\n      const eventStart = parseISO(event.startDate);\n      const eventEnd = parseISO(event.endDate);\n\n      return (\n        isWithinInterval(dayStart, { start: eventStart, end: eventEnd }) ||\n        isWithinInterval(dayEnd, { start: eventStart, end: eventEnd }) ||\n        (eventStart <= dayStart && eventEnd >= dayEnd)\n      );\n    })\n    .sort((a, b) => {\n      const durationA = differenceInDays(\n        parseISO(a.endDate),\n        parseISO(a.startDate),\n      );\n      const durationB = differenceInDays(\n        parseISO(b.endDate),\n        parseISO(b.startDate),\n      );\n      return durationB - durationA;\n    });\n\n  if (multiDayEventsInDay.length === 0) return null;\n\n  return (\n    <div className=\"flex border-b\">\n      <div className=\"w-18\"></div>\n      <div className=\"flex flex-1 flex-col gap-1 border-l py-1\">\n        {multiDayEventsInDay.map((event) => {\n          const eventStart = startOfDay(parseISO(event.startDate));\n          const eventEnd = startOfDay(parseISO(event.endDate));\n          const currentDate = startOfDay(selectedDate);\n\n          const eventTotalDays = differenceInDays(eventEnd, eventStart) + 1;\n          const eventCurrentDay = differenceInDays(currentDate, eventStart) + 1;\n\n          return (\n            <MonthEventBadge\n              key={event.id}\n              event={event}\n              cellDate={selectedDate}\n              eventCurrentDay={eventCurrentDay}\n              eventTotalDays={eventTotalDays}\n            />\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/event-block.tsx",
      "content": "import type { VariantProps } from \"class-variance-authority\";\nimport { cva } from \"class-variance-authority\";\nimport { differenceInMinutes, parseISO } from \"date-fns\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { EventDetailsDialog } from \"@/features/calendar/dialogs/event-details-dialog\";\nimport { DraggableEvent } from \"@/features/calendar/dnd/draggable-event\";\nimport { ResizableEvent } from \"@/features/calendar/dnd/resizable-event\";\nimport { formatTime } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\n\nconst calendarWeekEventCardVariants = cva(\n  \"flex select-none flex-col gap-0.5 truncate whitespace-nowrap rounded-md border px-2 py-1.5 text-xs focus-visible:outline-offset-2\",\n  {\n    variants: {\n      color: {\n        // Colored variants\n        blue: \"border-blue-200 bg-blue-100/50 text-blue-700 hover:bg-blue-100 dark:border-blue-800 dark:bg-blue-950/50 dark:text-blue-300 dark:hover:bg-blue-950\",\n        green:\n          \"border-green-200 bg-green-100/50 text-green-700 hover:bg-green-100 dark:border-green-800 dark:bg-green-950/50 dark:text-green-300 dark:hover:bg-green-950\",\n        red: \"border-red-200 bg-red-100/50 text-red-700 hover:bg-red-100 dark:border-red-800 dark:bg-red-950/50 dark:text-red-300 dark:hover:bg-red-950\",\n        yellow:\n          \"border-yellow-200 bg-yellow-100/50 text-yellow-700 hover:bg-yellow-100 dark:border-yellow-800 dark:bg-yellow-950/50 dark:text-yellow-300 dark:hover:bg-yellow-950\",\n        purple:\n          \"border-purple-200 bg-purple-100/50 text-purple-700 hover:bg-purple-100 dark:border-purple-800 dark:bg-purple-950/50 dark:text-purple-300 dark:hover:bg-purple-950\",\n        orange:\n          \"border-orange-200 bg-orange-100/50 text-orange-700 hover:bg-orange-100 dark:border-orange-800 dark:bg-orange-950/50 dark:text-orange-300 dark:hover:bg-orange-950\",\n\n        // Dot variants\n        \"blue-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-blue-600 dark:[&_svg]:fill-blue-500\",\n        \"green-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-green-600 dark:[&_svg]:fill-green-500\",\n        \"red-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-red-600 dark:[&_svg]:fill-red-500\",\n        \"orange-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-orange-600 dark:[&_svg]:fill-orange-500\",\n        \"purple-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-purple-600 dark:[&_svg]:fill-purple-500\",\n        \"yellow-dot\":\n          \"border-border bg-card text-foreground hover:bg-accent [&_svg]:fill-yellow-600 dark:[&_svg]:fill-yellow-500\",\n      },\n    },\n    defaultVariants: {\n      color: \"blue-dot\",\n    },\n  },\n);\n\ninterface IProps\n  extends\n    HTMLAttributes<HTMLDivElement>,\n    Omit<VariantProps<typeof calendarWeekEventCardVariants>, \"color\"> {\n  event: IEvent;\n}\n\nexport function EventBlock({ event, className }: IProps) {\n  const { badgeVariant, use24HourFormat } = useCalendar();\n\n  const start = parseISO(event.startDate);\n  const end = parseISO(event.endDate);\n  const durationInMinutes = differenceInMinutes(end, start);\n  const heightInPixels = (durationInMinutes / 60) * 96 - 8;\n\n  const color = (\n    badgeVariant === \"dot\" ? `${event.color}-dot` : event.color\n  ) as VariantProps<typeof calendarWeekEventCardVariants>[\"color\"];\n\n  const calendarWeekEventCardClasses = cn(\n    calendarWeekEventCardVariants({ color, className }),\n    durationInMinutes < 35 && \"py-0 justify-center\",\n  );\n\n  return (\n    <ResizableEvent event={event}>\n      <DraggableEvent event={event}>\n        <EventDetailsDialog event={event}>\n          <button\n            type=\"button\"\n            className={calendarWeekEventCardClasses}\n            style={{ height: `${heightInPixels}px` }}\n          >\n            <div className=\"flex items-center gap-1.5 truncate\">\n              {badgeVariant === \"dot\" && (\n                <svg\n                  width=\"8\"\n                  height=\"8\"\n                  viewBox=\"0 0 8 8\"\n                  xmlns=\"http://www.w3.org/2000/svg\"\n                  className=\"shrink-0\"\n                  aria-hidden=\"true\"\n                >\n                  <circle cx=\"4\" cy=\"4\" r=\"4\" />\n                </svg>\n              )}\n\n              <p className=\"truncate font-semibold\">{event.title}</p>\n            </div>\n\n            {durationInMinutes > 25 && (\n              <p>\n                {formatTime(start, use24HourFormat)} -{\" \"}\n                {formatTime(end, use24HourFormat)}\n              </p>\n            )}\n          </button>\n        </EventDetailsDialog>\n      </DraggableEvent>\n    </ResizableEvent>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/render-grouped-events.tsx",
      "content": "import { areIntervalsOverlapping, parseISO } from \"date-fns\";\nimport { getEventBlockStyle } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { EventBlock } from \"@/features/calendar/views/week-and-day-view/event-block\";\n\ninterface RenderGroupedEventsProps {\n  groupedEvents: IEvent[][];\n  day: Date;\n}\n\nexport function RenderGroupedEvents({\n  groupedEvents,\n  day,\n}: RenderGroupedEventsProps) {\n  return groupedEvents.map((group, groupIndex) =>\n    group.map((event) => {\n      let style = getEventBlockStyle(\n        event,\n        day,\n        groupIndex,\n        groupedEvents.length,\n      );\n      const hasOverlap = groupedEvents.some(\n        (otherGroup, otherIndex) =>\n          otherIndex !== groupIndex &&\n          otherGroup.some((otherEvent) =>\n            areIntervalsOverlapping(\n              {\n                start: parseISO(event.startDate),\n                end: parseISO(event.endDate),\n              },\n              {\n                start: parseISO(otherEvent.startDate),\n                end: parseISO(otherEvent.endDate),\n              },\n            ),\n          ),\n      );\n\n      if (!hasOverlap) style = { ...style, width: \"100%\", left: \"0%\" };\n\n      return (\n        <div key={event.id} className=\"absolute p-1\" style={style}>\n          <EventBlock event={event} />\n        </div>\n      );\n    }),\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/week-and-day-view/week-view-multi-day-events-row.tsx",
      "content": "import {\n\taddDays,\n\tdifferenceInDays,\n\tendOfWeek,\n\tisAfter,\n\tisBefore,\n\tparseISO,\n\tstartOfDay,\n\tstartOfWeek,\n} from \"date-fns\";\nimport { useMemo } from \"react\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { MonthEventBadge } from \"@/features/calendar/views/month-view/month-event-badge\";\n\ninterface IProps {\n\tselectedDate: Date;\n\tmultiDayEvents: IEvent[];\n}\n\nexport function WeekViewMultiDayEventsRow({\n\tselectedDate,\n\tmultiDayEvents,\n}: IProps) {\n\tconst weekStart = startOfWeek(selectedDate);\n\tconst weekEnd = endOfWeek(selectedDate);\n\tconst weekDays = Array.from({ length: 7 }, (_, i) => addDays(weekStart, i));\n\n\tconst processedEvents = useMemo(() => {\n\t\treturn multiDayEvents\n\t\t\t.map((event) => {\n\t\t\t\tconst start = parseISO(event.startDate);\n\t\t\t\tconst end = parseISO(event.endDate);\n\t\t\t\tconst adjustedStart = isBefore(start, weekStart) ? weekStart : start;\n\t\t\t\tconst adjustedEnd = isAfter(end, weekEnd) ? weekEnd : end;\n\t\t\t\tconst startIndex = differenceInDays(adjustedStart, weekStart);\n\t\t\t\tconst endIndex = differenceInDays(adjustedEnd, weekStart);\n\n\t\t\t\treturn {\n\t\t\t\t\t...event,\n\t\t\t\t\tadjustedStart,\n\t\t\t\t\tadjustedEnd,\n\t\t\t\t\tstartIndex,\n\t\t\t\t\tendIndex,\n\t\t\t\t};\n\t\t\t})\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst startDiff = a.adjustedStart.getTime() - b.adjustedStart.getTime();\n\t\t\t\tif (startDiff !== 0) return startDiff;\n\t\t\t\treturn b.endIndex - b.startIndex - (a.endIndex - a.startIndex);\n\t\t\t});\n\t}, [multiDayEvents, weekStart, weekEnd]);\n\n\tconst eventRows = useMemo(() => {\n\t\tconst rows: (typeof processedEvents)[] = [];\n\n\t\tprocessedEvents.forEach((event) => {\n\t\t\tlet rowIndex = rows.findIndex((row) =>\n\t\t\t\trow.every(\n\t\t\t\t\t(e) => e.endIndex < event.startIndex || e.startIndex > event.endIndex,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tif (rowIndex === -1) {\n\t\t\t\trowIndex = rows.length;\n\t\t\t\trows.push([]);\n\t\t\t}\n\n\t\t\trows[rowIndex].push(event);\n\t\t});\n\n\t\treturn rows;\n\t}, [processedEvents]);\n\n\tconst hasEventsInWeek = useMemo(() => {\n\t\treturn multiDayEvents.some((event) => {\n\t\t\tconst start = parseISO(event.startDate);\n\t\t\tconst end = parseISO(event.endDate);\n\n\t\t\treturn (\n\t\t\t\t// Event starts within the week\n\t\t\t\t(start >= weekStart && start <= weekEnd) ||\n\t\t\t\t// Event ends within the week\n\t\t\t\t(end >= weekStart && end <= weekEnd) ||\n\t\t\t\t// Event spans the entire week\n\t\t\t\t(start <= weekStart && end >= weekEnd)\n\t\t\t);\n\t\t});\n\t}, [multiDayEvents, weekStart, weekEnd]);\n\n\tif (!hasEventsInWeek) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<div className=\"overflow-hidden flex\">\n\t\t\t<div className=\"w-18 border-b\"></div>\n\t\t\t<div className=\"grid flex-1 grid-cols-7 divide-x border-b border-l\">\n\t\t\t\t{weekDays.map((day, dayIndex) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={day.toISOString()}\n\t\t\t\t\t\tclassName=\"flex h-full flex-col gap-1 py-1\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{eventRows.map((row, rowIndex) => {\n\t\t\t\t\t\t\tconst event = row.find(\n\t\t\t\t\t\t\t\t(e) => e.startIndex <= dayIndex && e.endIndex >= dayIndex,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (!event) {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<div key={`${rowIndex}-${dayIndex.toString()}`} className=\"h-6.5\" />\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet position: \"first\" | \"middle\" | \"last\" | \"none\" = \"none\";\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tdayIndex === event.startIndex &&\n\t\t\t\t\t\t\t\tdayIndex === event.endIndex\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tposition = \"none\";\n\t\t\t\t\t\t\t} else if (dayIndex === event.startIndex) {\n\t\t\t\t\t\t\t\tposition = \"first\";\n\t\t\t\t\t\t\t} else if (dayIndex === event.endIndex) {\n\t\t\t\t\t\t\t\tposition = \"last\";\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tposition = \"middle\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<MonthEventBadge\n\t\t\t\t\t\t\t\t\tkey={`${event.id}-${dayIndex}`}\n\t\t\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\t\t\tcellDate={startOfDay(day)}\n\t\t\t\t\t\t\t\t\tposition={position}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/views/year-view/calendar-year-view.tsx",
      "content": "import { getYear, isSameDay, isSameMonth } from \"date-fns\";\nimport { motion } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\nimport { staggerContainer, transition } from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { EventListDialog } from \"@/features/calendar/dialogs/events-list-dialog\";\nimport { getCalendarCells } from \"@/features/calendar/helpers\";\nimport type { IEvent } from \"@/features/calendar/interfaces\";\nimport { EventBullet } from \"@/features/calendar/views/month-view/event-bullet\";\n\ninterface IProps {\n  singleDayEvents: IEvent[];\n  multiDayEvents: IEvent[];\n}\n\nconst MONTHS = [\n  \"January\",\n  \"February\",\n  \"March\",\n  \"April\",\n  \"May\",\n  \"June\",\n  \"July\",\n  \"August\",\n  \"September\",\n  \"October\",\n  \"November\",\n  \"December\",\n];\n\nconst WEEKDAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\n\nexport function CalendarYearView({ singleDayEvents, multiDayEvents }: IProps) {\n  const { selectedDate, setSelectedDate } = useCalendar();\n  const currentYear = getYear(selectedDate);\n  const allEvents = [...multiDayEvents, ...singleDayEvents];\n\n  return (\n    <div className=\"flex flex-col h-full  overflow-y-auto p-4  sm:p-6\">\n      {/* Year grid */}\n      <motion.div\n        initial=\"initial\"\n        animate=\"animate\"\n        variants={staggerContainer}\n        className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 auto-rows-fr\"\n      >\n        {MONTHS.map((month, monthIndex) => {\n          const monthDate = new Date(currentYear, monthIndex, 1);\n          const cells = getCalendarCells(monthDate);\n\n          return (\n            <motion.div\n              key={month}\n              className=\"flex flex-col border border-border rounded-lg shadow-sm overflow-hidden\"\n              initial={{ opacity: 0, scale: 0.95 }}\n              animate={{ opacity: 1, scale: 1 }}\n              transition={{ delay: monthIndex * 0.05, ...transition }}\n              aria-label={`${month} ${currentYear} calendar`}\n            >\n              {/* Month header */}\n              <button\n                type=\"button\"\n                className=\"w-full px-3 py-2 text-center font-semibold text-sm sm:text-base cursor-pointer hover:bg-primary/20 transition-colors bg-transparent border-none appearance-none\"\n                onClick={() =>\n                  setSelectedDate(new Date(currentYear, monthIndex, 1))\n                }\n                aria-label={`Select ${month}`}\n              >\n                {month}\n              </button>\n\n              <div className=\"grid grid-cols-7 text-center text-xs font-medium text-muted-foreground py-2\">\n                {WEEKDAYS.map((day) => (\n                  <div key={day} className=\"p-1\">\n                    {day}\n                  </div>\n                ))}\n              </div>\n\n              <div className=\"grid grid-cols-7 gap-0.5 p-1.5 flex-grow text-xs\">\n                {cells.map((cell) => {\n                  const isCurrentMonth = isSameMonth(cell.date, monthDate);\n                  const isToday = isSameDay(cell.date, new Date());\n                  const dayEvents = allEvents.filter((event) =>\n                    isSameDay(new Date(event.startDate), cell.date),\n                  );\n                  const hasEvents = dayEvents.length > 0;\n\n                  return (\n                    <div\n                      key={cell.date.toISOString()}\n                      className={cn(\n                        \"flex flex-col items-center justify-start p-1 min-h-[2rem] relative\",\n                        !isCurrentMonth && \"text-muted-foreground/40\",\n                        hasEvents && isCurrentMonth\n                          ? \"cursor-pointer hover:bg-accent/20 hover:rounded-md\"\n                          : \"cursor-default\",\n                      )}\n                    >\n                      {isCurrentMonth && hasEvents ? (\n                        <EventListDialog date={cell.date} events={dayEvents}>\n                          <div className=\"w-full h-full flex flex-col items-center justify-start gap-0.5\">\n                            <span\n                              className={cn(\n                                \"size-5 flex items-center justify-center font-medium\",\n                                isToday &&\n                                  \"rounded-full bg-primary text-primary-foreground\",\n                              )}\n                            >\n                              {cell.day}\n                            </span>\n                            <div className=\"flex justify-center items-center gap-0.5\">\n                              {dayEvents.length <= 2 ? (\n                                dayEvents\n                                  .slice(0, 2)\n                                  .map((event) => (\n                                    <EventBullet\n                                      key={event.id}\n                                      color={event.color}\n                                      className=\"size-1.5\"\n                                    />\n                                  ))\n                              ) : (\n                                <div className=\"flex flex-col justify-center items-center\">\n                                  <EventBullet\n                                    color={dayEvents[0].color}\n                                    className=\"size-1.5\"\n                                  />\n                                  <span className=\"text-[0.6rem]\">\n                                    +{dayEvents.length - 1}\n                                  </span>\n                                </div>\n                              )}\n                            </div>\n                          </div>\n                        </EventListDialog>\n                      ) : (\n                        <div className=\"w-full h-full flex flex-col items-center justify-start\">\n                          <span\n                            className={cn(\n                              \"size-5 flex items-center justify-center font-medium\",\n                            )}\n                          >\n                            {cell.day}\n                          </span>\n                        </div>\n                      )}\n                    </div>\n                  );\n                })}\n              </div>\n            </motion.div>\n          );\n        })}\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/calendar.tsx",
      "content": "import React from \"react\";\nimport { CalendarBody } from \"@/features/calendar/calendar-body\";\nimport { CalendarProvider } from \"@/features/calendar/contexts/calendar-context\";\nimport { DndProvider } from \"@/features/calendar/contexts/dnd-context\";\nimport { CalendarHeader } from \"@/features/calendar/header/calendar-header\";\nimport { getEvents, getUsers } from \"@/features/calendar/requests\";\n\nasync function getCalendarData() {\n  return {\n    events: await getEvents(),\n    users: await getUsers(),\n  };\n}\n\nexport async function Calendar() {\n  const { events, users } = await getCalendarData();\n\n  return (\n    <CalendarProvider events={events} users={users} view=\"month\">\n      <DndProvider>\n        <div className=\"w-full border rounded-xl\">\n          <CalendarHeader />\n          <CalendarBody />\n        </div>\n      </DndProvider>\n    </CalendarProvider>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/calendar-body.tsx",
      "content": "\"use client\";\n\nimport { isSameDay, parseISO } from \"date-fns\";\nimport { motion } from \"framer-motion\";\nimport { fadeIn, transition } from \"@/features/calendar/animations\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport { AgendaEvents } from \"@/features/calendar/views/agenda-view/agenda-events\";\nimport { CalendarMonthView } from \"@/features/calendar/views/month-view/calendar-month-view\";\nimport { CalendarDayView } from \"@/features/calendar/views/week-and-day-view/calendar-day-view\";\nimport { CalendarWeekView } from \"@/features/calendar/views/week-and-day-view/calendar-week-view\";\nimport { CalendarYearView } from \"@/features/calendar/views/year-view/calendar-year-view\";\n\nexport function CalendarBody() {\n  const { view, events } = useCalendar();\n\n  const singleDayEvents = events.filter((event) => {\n    const startDate = parseISO(event.startDate);\n    const endDate = parseISO(event.endDate);\n    return isSameDay(startDate, endDate);\n  });\n\n  const multiDayEvents = events.filter((event) => {\n    const startDate = parseISO(event.startDate);\n    const endDate = parseISO(event.endDate);\n    return !isSameDay(startDate, endDate);\n  });\n\n  return (\n    <div className=\"w-full h-full overflow-scroll relative\">\n      <motion.div\n        key={view}\n        initial=\"initial\"\n        animate=\"animate\"\n        exit=\"exit\"\n        variants={fadeIn}\n        transition={transition}\n      >\n        {view === \"month\" && (\n          <CalendarMonthView\n            singleDayEvents={singleDayEvents}\n            multiDayEvents={multiDayEvents}\n          />\n        )}\n        {view === \"week\" && (\n          <CalendarWeekView\n            singleDayEvents={singleDayEvents}\n            multiDayEvents={multiDayEvents}\n          />\n        )}\n        {view === \"day\" && (\n          <CalendarDayView\n            singleDayEvents={singleDayEvents}\n            multiDayEvents={multiDayEvents}\n          />\n        )}\n        {view === \"year\" && (\n          <CalendarYearView\n            singleDayEvents={singleDayEvents}\n            multiDayEvents={multiDayEvents}\n          />\n        )}\n        {view === \"agenda\" && (\n          <motion.div\n            key=\"agenda\"\n            initial=\"initial\"\n            animate=\"animate\"\n            exit=\"exit\"\n            variants={fadeIn}\n            transition={transition}\n          >\n            <AgendaEvents />\n          </motion.div>\n        )}\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/constants.ts",
      "content": "import type { TEventColor } from \"@/features/calendar/types\";\n\nexport const COLORS: TEventColor[] = [\n\t\"blue\",\n\t\"green\",\n\t\"red\",\n\t\"yellow\",\n\t\"purple\",\n\t\"orange\",\n];\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/animations.ts",
      "content": "import type { Variants } from \"framer-motion\";\n\nexport const fadeIn: Variants = {\n\tinitial: { opacity: 0 },\n\tanimate: { opacity: 1 },\n\texit: { opacity: 0 },\n};\n\nexport const slideFromLeft: Variants = {\n\tinitial: { x: -20, opacity: 0 },\n\tanimate: { x: 0, opacity: 1 },\n\texit: { x: 20, opacity: 0 },\n};\n\nexport const slideFromRight: Variants = {\n\tinitial: { x: 20, opacity: 0 },\n\tanimate: { x: 0, opacity: 1 },\n\texit: { x: -20, opacity: 0 },\n};\n\nexport const transition = {\n\ttype: \"spring\",\n\tstiffness: 200,\n\tdamping: 20,\n} as const;\n\nexport const staggerContainer: Variants = {\n\tanimate: {\n\t\ttransition: {\n\t\t\tstaggerChildren: 0.1,\n\t\t},\n\t},\n};\n\nexport const buttonHover: Variants = {\n\thover: { scale: 1.05 },\n\ttap: { scale: 0.95 },\n};\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/helpers.ts",
      "content": "import {\n\taddDays,\n\taddMonths,\n\taddWeeks,\n\taddYears,\n\tdifferenceInDays,\n\tdifferenceInMinutes,\n\teachDayOfInterval,\n\tendOfMonth,\n\tendOfWeek,\n\tendOfYear,\n\tformat,\n\tisSameDay,\n\tisSameMonth,\n\tisSameWeek,\n\tisSameYear,\n\tisValid,\n\tparseISO,\n\tstartOfDay,\n\tstartOfMonth,\n\tstartOfWeek,\n\tstartOfYear,\n\tsubDays,\n\tsubMonths,\n\tsubWeeks,\n\tsubYears,\n} from \"date-fns\";\nimport { useCalendar } from \"@/features/calendar/contexts/calendar-context\";\nimport type {\n\tICalendarCell,\n\tIEvent,\n} from \"@/features/calendar/interfaces\";\nimport type {\n\tTCalendarView,\n\tTEventColor,\n} from \"@/features/calendar/types\";\n\nconst FORMAT_STRING = \"MMM d, yyyy\";\n\nexport function rangeText(view: TCalendarView, date: Date): string {\n\tlet start: Date;\n\tlet end: Date;\n\n\tswitch (view) {\n\t\tcase \"month\":\n\t\t\tstart = startOfMonth(date);\n\t\t\tend = endOfMonth(date);\n\t\t\tbreak;\n\t\tcase \"week\":\n\t\t\tstart = startOfWeek(date);\n\t\t\tend = endOfWeek(date);\n\t\t\tbreak;\n\t\tcase \"day\":\n\t\t\treturn format(date, FORMAT_STRING);\n\t\tcase \"year\":\n\t\t\tstart = startOfYear(date);\n\t\t\tend = endOfYear(date);\n\t\t\tbreak;\n\t\tcase \"agenda\":\n\t\t\tstart = startOfMonth(date);\n\t\t\tend = endOfMonth(date);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn \"Error while formatting\";\n\t}\n\n\treturn `${format(start, FORMAT_STRING)} - ${format(end, FORMAT_STRING)}`;\n}\n\nexport function navigateDate(\n\tdate: Date,\n\tview: TCalendarView,\n\tdirection: \"previous\" | \"next\",\n): Date {\n\tconst operations: Record<TCalendarView, (d: Date, n: number) => Date> = {\n\t\tmonth: direction === \"next\" ? addMonths : subMonths,\n\t\tweek: direction === \"next\" ? addWeeks : subWeeks,\n\t\tday: direction === \"next\" ? addDays : subDays,\n\t\tyear: direction === \"next\" ? addYears : subYears,\n\t\tagenda: direction === \"next\" ? addMonths : subMonths,\n\t};\n\n\treturn operations[view](date, 1);\n}\n\nexport function getEventsCount(\n\tevents: IEvent[],\n\tdate: Date,\n\tview: TCalendarView,\n): number {\n\tconst compareFns: Record<TCalendarView, (d1: Date, d2: Date) => boolean> = {\n\t\tday: isSameDay,\n\t\tweek: isSameWeek,\n\t\tmonth: isSameMonth,\n\t\tyear: isSameYear,\n\t\tagenda: isSameMonth,\n\t};\n\n\tconst compareFn = compareFns[view];\n\treturn events.filter((event) => compareFn(parseISO(event.startDate), date))\n\t\t.length;\n}\n\nexport function groupEvents(dayEvents: IEvent[]): IEvent[][] {\n\tconst sortedEvents = dayEvents.sort(\n\t\t(a, b) => parseISO(a.startDate).getTime() - parseISO(b.startDate).getTime(),\n\t);\n\tconst groups: IEvent[][] = [];\n\n\tfor (const event of sortedEvents) {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tlet placed = false;\n\n\t\tfor (const group of groups) {\n\t\t\tconst lastEventInGroup = group[group.length - 1];\n\t\t\tconst lastEventEnd = parseISO(lastEventInGroup.endDate);\n\n\t\t\tif (eventStart >= lastEventEnd) {\n\t\t\t\tgroup.push(event);\n\t\t\t\tplaced = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!placed) groups.push([event]);\n\t}\n\n\treturn groups;\n}\n\nexport function getEventBlockStyle(\n\tevent: IEvent,\n\tday: Date,\n\tgroupIndex: number,\n\tgroupSize: number,\n) {\n\tconst startDate = parseISO(event.startDate);\n\tconst dayStart = startOfDay(day); // Use startOfDay instead of manual reset\n\tconst eventStart = startDate < dayStart ? dayStart : startDate;\n\tconst startMinutes = differenceInMinutes(eventStart, dayStart);\n\n\tconst top = (startMinutes / 1440) * 100; // 1440 minutes in a day\n\tconst width = 100 / groupSize;\n\tconst left = groupIndex * width;\n\n\treturn { top: `${top}%`, width: `${width}%`, left: `${left}%` };\n}\n\nexport function getCalendarCells(selectedDate: Date): ICalendarCell[] {\n\tconst year = selectedDate.getFullYear();\n\tconst month = selectedDate.getMonth();\n\n\tconst daysInMonth = endOfMonth(selectedDate).getDate(); // Faster than new Date(year, month + 1, 0)\n\tconst firstDayOfMonth = startOfMonth(selectedDate).getDay();\n\tconst daysInPrevMonth = endOfMonth(new Date(year, month - 1)).getDate();\n\tconst totalDays = firstDayOfMonth + daysInMonth;\n\n\tconst prevMonthCells = Array.from({ length: firstDayOfMonth }, (_, i) => ({\n\t\tday: daysInPrevMonth - firstDayOfMonth + i + 1,\n\t\tcurrentMonth: false,\n\t\tdate: new Date(year, month - 1, daysInPrevMonth - firstDayOfMonth + i + 1),\n\t}));\n\n\tconst currentMonthCells = Array.from({ length: daysInMonth }, (_, i) => ({\n\t\tday: i + 1,\n\t\tcurrentMonth: true,\n\t\tdate: new Date(year, month, i + 1),\n\t}));\n\n\tconst nextMonthCells = Array.from(\n\t\t{ length: (7 - (totalDays % 7)) % 7 },\n\t\t(_, i) => ({\n\t\t\tday: i + 1,\n\t\t\tcurrentMonth: false,\n\t\t\tdate: new Date(year, month + 1, i + 1),\n\t\t}),\n\t);\n\n\treturn [...prevMonthCells, ...currentMonthCells, ...nextMonthCells];\n}\n\nexport function calculateMonthEventPositions(\n\tmultiDayEvents: IEvent[],\n\tsingleDayEvents: IEvent[],\n\tselectedDate: Date,\n): Record<string, number> {\n\tconst monthStart = startOfMonth(selectedDate);\n\tconst monthEnd = endOfMonth(selectedDate);\n\n\tconst eventPositions: Record<string, number> = {};\n\tconst occupiedPositions: Record<string, boolean[]> = {};\n\n\teachDayOfInterval({ start: monthStart, end: monthEnd }).forEach((day) => {\n\t\toccupiedPositions[day.toISOString()] = [false, false, false];\n\t});\n\n\tconst sortedEvents = [\n\t\t...multiDayEvents.sort((a, b) => {\n\t\t\tconst aDuration = differenceInDays(\n\t\t\t\tparseISO(a.endDate),\n\t\t\t\tparseISO(a.startDate),\n\t\t\t);\n\t\t\tconst bDuration = differenceInDays(\n\t\t\t\tparseISO(b.endDate),\n\t\t\t\tparseISO(b.startDate),\n\t\t\t);\n\t\t\treturn (\n\t\t\t\tbDuration - aDuration ||\n\t\t\t\tparseISO(a.startDate).getTime() - parseISO(b.startDate).getTime()\n\t\t\t);\n\t\t}),\n\t\t...singleDayEvents.sort(\n\t\t\t(a, b) =>\n\t\t\t\tparseISO(a.startDate).getTime() - parseISO(b.startDate).getTime(),\n\t\t),\n\t];\n\n\tsortedEvents.forEach((event) => {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tconst eventEnd = parseISO(event.endDate);\n\t\tconst eventDays = eachDayOfInterval({\n\t\t\tstart: eventStart < monthStart ? monthStart : eventStart,\n\t\t\tend: eventEnd > monthEnd ? monthEnd : eventEnd,\n\t\t});\n\n\t\tlet position = -1;\n\n\t\tfor (let i = 0; i < 3; i++) {\n\t\t\tif (\n\t\t\t\teventDays.every((day) => {\n\t\t\t\t\tconst dayPositions = occupiedPositions[startOfDay(day).toISOString()];\n\t\t\t\t\treturn dayPositions && !dayPositions[i];\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tposition = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (position !== -1) {\n\t\t\teventDays.forEach((day) => {\n\t\t\t\tconst dayKey = startOfDay(day).toISOString();\n\t\t\t\toccupiedPositions[dayKey][position] = true;\n\t\t\t});\n\t\t\teventPositions[event.id] = position;\n\t\t}\n\t});\n\n\treturn eventPositions;\n}\n\nexport function getMonthCellEvents(\n\tdate: Date,\n\tevents: IEvent[],\n\teventPositions: Record<string, number>,\n) {\n\tconst dayStart = startOfDay(date);\n\tconst eventsForDate = events.filter((event) => {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tconst eventEnd = parseISO(event.endDate);\n\t\treturn (\n\t\t\t(dayStart >= eventStart && dayStart <= eventEnd) ||\n\t\t\tisSameDay(dayStart, eventStart) ||\n\t\t\tisSameDay(dayStart, eventEnd)\n\t\t);\n\t});\n\n\treturn eventsForDate\n\t\t.map((event) => ({\n\t\t\t...event,\n\t\t\tposition: eventPositions[event.id] ?? -1,\n\t\t\tisMultiDay: event.startDate !== event.endDate,\n\t\t}))\n\t\t.sort((a, b) => {\n\t\t\tif (a.isMultiDay && !b.isMultiDay) return -1;\n\t\t\tif (!a.isMultiDay && b.isMultiDay) return 1;\n\t\t\treturn a.position - b.position;\n\t\t});\n}\n\nexport function formatTime(\n\tdate: Date | string,\n\tuse24HourFormat: boolean,\n): string {\n\tconst parsedDate = typeof date === \"string\" ? parseISO(date) : date;\n\tif (!isValid(parsedDate)) return \"\";\n\treturn format(parsedDate, use24HourFormat ? \"HH:mm\" : \"h:mm a\");\n}\n\nexport const getFirstLetters = (str: string): string => {\n\tif (!str) return \"\";\n\tconst words = str.split(\" \");\n\tif (words.length === 1) return words[0].charAt(0).toUpperCase();\n\treturn `${words[0].charAt(0).toUpperCase()}${words[1].charAt(0).toUpperCase()}`;\n};\n\nexport const getEventsForDay = (\n\tevents: IEvent[],\n\tdate: Date,\n\tisWeek = false,\n): IEvent[] => {\n\tconst targetDate = startOfDay(date);\n\treturn events\n\t\t.filter((event) => {\n\t\t\tconst startOfDayForEventStart = startOfDay(parseISO(event.startDate));\n\t\t\tconst startOfDayForEventEnd = startOfDay(parseISO(event.endDate));\n\t\t\tif (isWeek) {\n\t\t\t\treturn (\n\t\t\t\t\tevent.startDate !== event.endDate &&\n\t\t\t\t\tstartOfDayForEventStart <= targetDate &&\n\t\t\t\t\tstartOfDayForEventEnd >= targetDate\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn (\n\t\t\t\tstartOfDayForEventStart <= targetDate &&\n\t\t\t\tstartOfDayForEventEnd >= targetDate\n\t\t\t);\n\t\t})\n\t\t.map((event) => {\n\t\t\tconst eventStart = startOfDay(parseISO(event.startDate));\n\t\t\tconst eventEnd = startOfDay(parseISO(event.endDate));\n\t\t\tlet point: \"start\" | \"end\" | \"none\" | undefined;\n\n\t\t\tif (isSameDay(eventStart, eventEnd)) {\n\t\t\t\tpoint = \"none\";\n\t\t\t} else if (isSameDay(eventStart, targetDate)) {\n\t\t\t\tpoint = \"start\";\n\t\t\t} else if (isSameDay(eventEnd, targetDate)) {\n\t\t\t\tpoint = \"end\";\n\t\t\t}\n\n\t\t\treturn { ...event, point };\n\t\t});\n};\n\nexport const getWeekDates = (date: Date): Date[] => {\n\tconst startDate = startOfWeek(date, { weekStartsOn: 1 });\n\treturn Array.from({ length: 7 }, (_, i) => addDays(startDate, i));\n};\n\nexport const getEventsForWeek = (events: IEvent[], date: Date): IEvent[] => {\n\tconst weekDates = getWeekDates(date);\n\tconst startOfWeekDate = weekDates[0];\n\tconst endOfWeekDate = weekDates[6];\n\n\treturn events.filter((event) => {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tconst eventEnd = parseISO(event.endDate);\n\t\treturn (\n\t\t\tisValid(eventStart) &&\n\t\t\tisValid(eventEnd) &&\n\t\t\teventStart <= endOfWeekDate &&\n\t\t\teventEnd >= startOfWeekDate\n\t\t);\n\t});\n};\n\nexport const getEventsForMonth = (events: IEvent[], date: Date): IEvent[] => {\n\tconst startOfMonthDate = startOfMonth(date);\n\tconst endOfMonthDate = endOfMonth(date);\n\n\treturn events.filter((event) => {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tconst eventEnd = parseISO(event.endDate);\n\t\treturn (\n\t\t\tisValid(eventStart) &&\n\t\t\tisValid(eventEnd) &&\n\t\t\teventStart <= endOfMonthDate &&\n\t\t\teventEnd >= startOfMonthDate\n\t\t);\n\t});\n};\n\nexport const getEventsForYear = (events: IEvent[], date: Date): IEvent[] => {\n\tif (!events || !Array.isArray(events) || !isValid(date)) return [];\n\n\tconst startOfYearDate = startOfYear(date);\n\tconst endOfYearDate = endOfYear(date);\n\n\treturn events.filter((event) => {\n\t\tconst eventStart = parseISO(event.startDate);\n\t\tconst eventEnd = parseISO(event.endDate);\n\t\treturn (\n\t\t\tisValid(eventStart) &&\n\t\t\tisValid(eventEnd) &&\n\t\t\teventStart <= endOfYearDate &&\n\t\t\teventEnd >= startOfYearDate\n\t\t);\n\t});\n};\n\nexport const getColorClass = (color: string): string => {\n\tconst colorClasses: Record<TEventColor, string> = {\n\t\tred: \"border-red-200 bg-red-50 text-red-700 dark:border-red-800 dark:bg-red-950 dark:text-red-300\",\n\t\tyellow:\n\t\t\t\"border-yellow-200 bg-yellow-50 text-yellow-700 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-300\",\n\t\tgreen:\n\t\t\t\"border-green-200 bg-green-50 text-green-700 dark:border-green-800 dark:bg-green-950 dark:text-green-300\",\n\t\tblue: \"border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300\",\n\t\torange:\n\t\t\t\"border-orange-200 bg-orange-50 text-orange-700 dark:border-orange-800 dark:bg-orange-950 dark:text-orange-300\",\n\t\tpurple:\n\t\t\t\"border-purple-200 bg-purple-50 text-purple-700 dark:border-purple-800 dark:bg-purple-950 dark:text-purple-300\",\n\t};\n\treturn colorClasses[color as TEventColor] || \"\";\n};\n\nexport const getBgColor = (color: string): string => {\n\tconst colorClasses: Record<TEventColor, string> = {\n\t\tred: \"bg-red-400 dark:bg-red-600\",\n\t\tyellow: \"bg-yellow-400 dark:bg-yellow-600\",\n\t\tgreen: \"bg-green-400 dark:bg-green-600\",\n\t\tblue: \"bg-blue-400 dark:bg-blue-600\",\n\t\torange: \"bg-orange-400 dark:bg-orange-600\",\n\t\tpurple: \"bg-purple-400 dark:bg-purple-600\",\n\t};\n\treturn colorClasses[color as TEventColor] || \"\";\n};\n\nexport const useGetEventsByMode = (events: IEvent[]) => {\n\tconst { view, selectedDate } = useCalendar();\n\n\tswitch (view) {\n\t\tcase \"day\":\n\t\t\treturn getEventsForDay(events, selectedDate);\n\t\tcase \"week\":\n\t\t\treturn getEventsForWeek(events, selectedDate);\n\t\tcase \"agenda\":\n\t\tcase \"month\":\n\t\t\treturn getEventsForMonth(events, selectedDate);\n\t\tcase \"year\":\n\t\t\treturn getEventsForYear(events, selectedDate);\n\t\tdefault:\n\t\t\treturn [];\n\t}\n};\n\nexport const toCapitalize = (str: string): string => {\n\tif (!str) return \"\";\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n};\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/hooks.ts",
      "content": "import { useEffect, useState } from \"react\";\n\nexport function useDisclosure({\n\tdefaultIsOpen = false,\n}: {\n\tdefaultIsOpen?: boolean;\n} = {}) {\n\tconst [isOpen, setIsOpen] = useState(defaultIsOpen);\n\n\tconst onOpen = () => setIsOpen(true);\n\tconst onClose = () => setIsOpen(false);\n\tconst onToggle = () => setIsOpen((currentValue) => !currentValue);\n\n\treturn { onOpen, onClose, isOpen, onToggle };\n}\n\nexport const useLocalStorage = <T>(\n\tkey: string,\n\tinitialValue: T,\n): [T, (value: T) => void] => {\n\tconst readValue = (): T => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn initialValue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst item = window.localStorage.getItem(key);\n\t\t\treturn item ? (JSON.parse(item) as T) : initialValue;\n\t\t} catch (error) {\n\t\t\tconsole.warn(`Error reading localStorage key \"${key}\":`, error);\n\t\t\treturn initialValue;\n\t\t}\n\t};\n\n\tconst [storedValue, setStoredValue] = useState<T>(readValue);\n\n\tconst setValue = (value: T) => {\n\t\ttry {\n\t\t\tconst valueToStore =\n\t\t\t\tvalue instanceof Function ? value(storedValue) : value;\n\t\t\tsetStoredValue(valueToStore);\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\twindow.localStorage.setItem(key, JSON.stringify(valueToStore));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn(`Error setting localStorage key \"${key}\":`, error);\n\t\t}\n\t};\n\n\treturn [storedValue, setValue];\n};\n\nexport function useMediaQuery(query: string): boolean {\n\tconst [matches, setMatches] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst media = window.matchMedia(query);\n\t\tif (media.matches !== matches) {\n\t\t\tsetMatches(media.matches);\n\t\t}\n\n\t\tconst listener = () => setMatches(media.matches);\n\t\tmedia.addEventListener(\"change\", listener);\n\n\t\treturn () => media.removeEventListener(\"change\", listener);\n\t}, [matches, query]);\n\n\treturn matches;\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/interfaces.ts",
      "content": "import type { TEventColor } from \"@/features/calendar/types\";\n\nexport interface IUser {\n\tid: string;\n\tname: string;\n\tpicturePath: string | null;\n}\n\nexport interface IEvent {\n\tid: number;\n\tstartDate: string;\n\tendDate: string;\n\ttitle: string;\n\tcolor: TEventColor;\n\tdescription: string;\n\tuser: IUser;\n}\n\nexport interface ICalendarCell {\n\tday: number;\n\tcurrentMonth: boolean;\n\tdate: Date;\n}\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/mocks.ts",
      "content": "import { COLORS } from \"@/features/calendar/constants\";\nimport type { IEvent, IUser } from \"@/features/calendar/interfaces\";\n\nexport const USERS_MOCK: IUser[] = [\n\t{\n\t\tid: \"f3b035ac-49f7-4e92-a715-35680bf63175\",\n\t\tname: \"Michael Doe\",\n\t\tpicturePath: null,\n\t},\n\t{\n\t\tid: \"3e36ea6e-78f3-40dd-ab8c-a6c737c3c422\",\n\t\tname: \"Alice Johnson\",\n\t\tpicturePath: null,\n\t},\n\t{\n\t\tid: \"a7aff6bd-a50a-4d6a-ab57-76f76bb27cf5\",\n\t\tname: \"Robert Smith\",\n\t\tpicturePath: null,\n\t},\n\t{\n\t\tid: \"dd503cf9-6c38-43cf-94cc-0d4032e2f77a\",\n\t\tname: \"Emily Davis\",\n\t\tpicturePath: null,\n\t},\n];\n\n// ================================== //\n\nconst events = [\n\t\"Doctor's appointment\",\n\t\"Dental cleaning\",\n\t\"Eye exam\",\n\t\"Therapy session\",\n\t\"Business meeting\",\n\t\"Team stand-up\",\n\t\"Project deadline\",\n\t\"Weekly report submission\",\n\t\"Client presentation\",\n\t\"Marketing strategy review\",\n\t\"Networking event\",\n\t\"Sales call\",\n\t\"Investor pitch\",\n\t\"Board meeting\",\n\t\"Employee training\",\n\t\"Performance review\",\n\t\"One-on-one meeting\",\n\t\"Lunch with a colleague\",\n\t\"HR interview\",\n\t\"Conference call\",\n\t\"Web development sprint planning\",\n\t\"Software deployment\",\n\t\"Code review\",\n\t\"QA testing session\",\n\t\"Cybersecurity audit\",\n\t\"Server maintenance\",\n\t\"API integration update\",\n\t\"Data backup\",\n\t\"Cloud migration\",\n\t\"System upgrade\",\n\t\"Content planning session\",\n\t\"Product launch\",\n\t\"Customer support review\",\n\t\"Team building activity\",\n\t\"Legal consultation\",\n\t\"Budget review\",\n\t\"Financial planning session\",\n\t\"Tax filing deadline\",\n\t\"Investor relations update\",\n\t\"Partnership negotiation\",\n\t\"Medical check-up\",\n\t\"Vaccination appointment\",\n\t\"Blood donation\",\n\t\"Gym workout\",\n\t\"Yoga class\",\n\t\"Physical therapy session\",\n\t\"Nutrition consultation\",\n\t\"Personal trainer session\",\n\t\"Parent-teacher meeting\",\n\t\"School open house\",\n\t\"College application deadline\",\n\t\"Final exam\",\n\t\"Graduation ceremony\",\n\t\"Job interview\",\n\t\"Internship orientation\",\n\t\"Office relocation\",\n\t\"Business trip\",\n\t\"Flight departure\",\n\t\"Hotel check-in\",\n\t\"Vacation planning\",\n\t\"Birthday party\",\n\t\"Wedding anniversary\",\n\t\"Family reunion\",\n\t\"Housewarming party\",\n\t\"Community volunteer work\",\n\t\"Charity fundraiser\",\n\t\"Religious service\",\n\t\"Concert attendance\",\n\t\"Theater play\",\n\t\"Movie night\",\n\t\"Sporting event\",\n\t\"Football match\",\n\t\"Basketball game\",\n\t\"Tennis practice\",\n\t\"Marathon training\",\n\t\"Cycling event\",\n\t\"Fishing trip\",\n\t\"Camping weekend\",\n\t\"Hiking expedition\",\n\t\"Photography session\",\n\t\"Art workshop\",\n\t\"Cooking class\",\n\t\"Book club meeting\",\n\t\"Grocery shopping\",\n\t\"Car maintenance\",\n\t\"Home renovation meeting\",\n];\n\nconst mockGenerator = (numberOfEvents: number): IEvent[] => {\n\tconst result: IEvent[] = [];\n\tlet currentId = 1;\n\n\tconst randomUser = USERS_MOCK[Math.floor(Math.random() * USERS_MOCK.length)];\n\n\t// Date range: 30 days before and after now\n\tconst now = new Date();\n\tconst startRange = new Date(now);\n\tstartRange.setDate(now.getDate() - 30);\n\tconst endRange = new Date(now);\n\tendRange.setDate(now.getDate() + 30);\n\n\t// Create an event happening now\n\tconst currentEvent = {\n\t\tid: currentId++,\n\t\tstartDate: new Date(now.getTime() - 30 * 60000).toISOString(),\n\t\tendDate: new Date(now.getTime() + 30 * 60000).toISOString(),\n\t\ttitle: events[Math.floor(Math.random() * events.length)],\n\t\tcolor: COLORS[Math.floor(Math.random() * COLORS.length)],\n\t\tdescription:\n\t\t\t\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\",\n\t\tuser: randomUser,\n\t};\n\n\tresult.push(currentEvent);\n\n\t// Generate the remaining events\n\tfor (let i = 0; i < numberOfEvents - 1; i++) {\n\t\t// Determine if this is a multi-day event (10% chance)\n\t\tconst isMultiDay = Math.random() < 0.1;\n\n\t\tconst startDate = new Date(\n\t\t\tstartRange.getTime() +\n\t\t\tMath.random() * (endRange.getTime() - startRange.getTime()),\n\t\t);\n\n\t\t// Set time between 8 AM and 8 PM\n\t\tstartDate.setHours(\n\t\t\t8 + Math.floor(Math.random() * 12),\n\t\t\tMath.floor(Math.random() * 60),\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\n\t\tconst endDate = new Date(startDate);\n\n\t\tif (isMultiDay) {\n\t\t\t// Multi-day event: Add 1-4 days\n\t\t\tconst additionalDays = Math.floor(Math.random() * 4) + 1;\n\t\t\tendDate.setDate(startDate.getDate() + additionalDays);\n\t\t\tendDate.setHours(\n\t\t\t\t8 + Math.floor(Math.random() * 12),\n\t\t\t\tMath.floor(Math.random() * 60),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t} else {\n\t\t\t// Same-day event: Add 1-3 hours\n\t\t\tendDate.setHours(endDate.getHours() + Math.floor(Math.random() * 3) + 1);\n\t\t}\n\n\t\tresult.push({\n\t\t\tid: currentId++,\n\t\t\tstartDate: startDate.toISOString(),\n\t\t\tendDate: endDate.toISOString(),\n\t\t\ttitle: events[Math.floor(Math.random() * events.length)],\n\t\t\tcolor: COLORS[Math.floor(Math.random() * COLORS.length)],\n\t\t\tdescription:\n\t\t\t\t\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\",\n\t\t\tuser: USERS_MOCK[Math.floor(Math.random() * USERS_MOCK.length)],\n\t\t});\n\t}\n\n\treturn result;\n};\n\nexport const CALENDAR_ITEMS_MOCK: IEvent[] = mockGenerator(80);\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/requests.ts",
      "content": "import {\n\tCALENDAR_ITEMS_MOCK,\n\tUSERS_MOCK,\n} from \"@/features/calendar/mocks\";\n\nexport const getEvents = async () => {\n\treturn CALENDAR_ITEMS_MOCK;\n};\n\nexport const getUsers = async () => {\n\treturn USERS_MOCK;\n};\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/schemas.ts",
      "content": "import { z } from \"zod/v4\";\n\nexport const eventSchema = z.object({\n\ttitle: z.string().min(1, \"Title is required\"),\n\tdescription: z.string().min(1, \"Description is required\"),\n\tstartDate: z.date(\"Start date is required\"),\n\tendDate: z.date(\"End date is required\"),\n\tcolor: z.enum([\"blue\", \"green\", \"red\", \"yellow\", \"purple\", \"orange\"]),\n});\n\nexport type TEventFormData = z.infer<typeof eventSchema>;\n",
      "type": "registry:component"
    },
    {
      "path": "src/features/calendar/types.ts",
      "content": "export type TCalendarView = \"day\" | \"week\" | \"month\" | \"year\" | \"agenda\";\nexport type TEventColor =\n\t| \"blue\"\n\t| \"green\"\n\t| \"red\"\n\t| \"yellow\"\n\t| \"purple\"\n\t| \"orange\";\n",
      "type": "registry:component"
    }
  ]
}
