@ilamy/calendar 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/index.cjs +3553 -0
- package/dist/index.d.cts +190 -0
- package/dist/index.d.ts +190 -0
- package/dist/index.js +3525 -0
- package/package.json +114 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3553 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var import_node_module = require("node:module");
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
10
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
11
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
12
|
+
for (let key of __getOwnPropNames(mod))
|
|
13
|
+
if (!__hasOwnProp.call(to, key))
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: () => mod[key],
|
|
16
|
+
enumerable: true
|
|
17
|
+
});
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
34
|
+
var __export = (target, all) => {
|
|
35
|
+
for (var name in all)
|
|
36
|
+
__defProp(target, name, {
|
|
37
|
+
get: all[name],
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
set: (newValue) => all[name] = () => newValue
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/index.ts
|
|
45
|
+
var exports_src = {};
|
|
46
|
+
__export(exports_src, {
|
|
47
|
+
useIlamyCalendarContext: () => usePublicCalendarContext,
|
|
48
|
+
IlamyCalendar: () => IlamyCalendar
|
|
49
|
+
});
|
|
50
|
+
module.exports = __toCommonJS(exports_src);
|
|
51
|
+
|
|
52
|
+
// src/features/month-view/components/month-view.tsx
|
|
53
|
+
var import_react9 = require("motion/react");
|
|
54
|
+
var import_react10 = __toESM(require("react"));
|
|
55
|
+
|
|
56
|
+
// src/contexts/calendar-context/context.ts
|
|
57
|
+
var import_react = require("react");
|
|
58
|
+
var CalendarContext = import_react.createContext(undefined);
|
|
59
|
+
var useCalendarContext = () => {
|
|
60
|
+
const context = import_react.useContext(CalendarContext);
|
|
61
|
+
if (context === undefined) {
|
|
62
|
+
throw new Error("useCalendarContext must be used within a CalendarProvider");
|
|
63
|
+
}
|
|
64
|
+
return context;
|
|
65
|
+
};
|
|
66
|
+
var usePublicCalendarContext = () => {
|
|
67
|
+
const context = import_react.useContext(CalendarContext);
|
|
68
|
+
if (context === undefined) {
|
|
69
|
+
throw new Error("useCalendarContext must be used within ilamy calendar");
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
currentDate: context.currentDate,
|
|
73
|
+
view: context.view,
|
|
74
|
+
events: context.events,
|
|
75
|
+
isEventFormOpen: context.isEventFormOpen,
|
|
76
|
+
selectedEvent: context.selectedEvent,
|
|
77
|
+
selectedDate: context.selectedDate,
|
|
78
|
+
firstDayOfWeek: context.firstDayOfWeek,
|
|
79
|
+
setCurrentDate: context.setCurrentDate,
|
|
80
|
+
selectDate: context.selectDate,
|
|
81
|
+
setView: context.setView,
|
|
82
|
+
nextPeriod: context.nextPeriod,
|
|
83
|
+
prevPeriod: context.prevPeriod,
|
|
84
|
+
today: context.today,
|
|
85
|
+
addEvent: context.addEvent,
|
|
86
|
+
updateEvent: context.updateEvent,
|
|
87
|
+
deleteEvent: context.deleteEvent,
|
|
88
|
+
openEventForm: context.openEventForm,
|
|
89
|
+
closeEventForm: context.closeEventForm
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/components/ui/accordion.tsx
|
|
94
|
+
var AccordionPrimitive = __toESM(require("@radix-ui/react-accordion"));
|
|
95
|
+
var import_lucide_react = require("lucide-react");
|
|
96
|
+
|
|
97
|
+
// src/lib/utils.ts
|
|
98
|
+
var import_clsx = require("clsx");
|
|
99
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
100
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
101
|
+
function cn(...inputs) {
|
|
102
|
+
return import_tailwind_merge.twMerge(import_clsx.clsx(inputs));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/components/ui/accordion.tsx
|
|
106
|
+
var jsx_dev_runtime = require("react/jsx-dev-runtime");
|
|
107
|
+
// src/components/ui/alert.tsx
|
|
108
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
109
|
+
var jsx_dev_runtime2 = require("react/jsx-dev-runtime");
|
|
110
|
+
var alertVariants = import_class_variance_authority.cva("relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
|
|
111
|
+
variants: {
|
|
112
|
+
variant: {
|
|
113
|
+
default: "bg-card text-card-foreground",
|
|
114
|
+
destructive: "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
|
|
115
|
+
primary: "bg-blue-50 dark:bg-blue-950/20 border-blue-200 dark:border-blue-800 text-blue-900 dark:text-blue-100 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-400 *:data-[slot=alert-description]:text-blue-800 dark:*:data-[slot=alert-description]:text-blue-200",
|
|
116
|
+
secondary: "bg-gray-50 dark:bg-gray-950/20 border-gray-200 dark:border-gray-800 text-gray-900 dark:text-gray-100 [&>svg]:text-gray-600 dark:[&>svg]:text-gray-400 *:data-[slot=alert-description]:text-gray-800 dark:*:data-[slot=alert-description]:text-gray-200",
|
|
117
|
+
success: "bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-800 text-green-900 dark:text-green-100 [&>svg]:text-green-600 dark:[&>svg]:text-green-400 *:data-[slot=alert-description]:text-green-800 dark:*:data-[slot=alert-description]:text-green-200",
|
|
118
|
+
warning: "bg-yellow-50 dark:bg-yellow-950/20 border-yellow-200 dark:border-yellow-800 text-yellow-900 dark:text-yellow-100 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-400 *:data-[slot=alert-description]:text-yellow-800 dark:*:data-[slot=alert-description]:text-yellow-200"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
defaultVariants: {
|
|
122
|
+
variant: "default"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// src/components/ui/badge.tsx
|
|
126
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
127
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
128
|
+
var jsx_dev_runtime3 = require("react/jsx-dev-runtime");
|
|
129
|
+
var badgeVariants = import_class_variance_authority2.cva("inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-clip", {
|
|
130
|
+
variants: {
|
|
131
|
+
variant: {
|
|
132
|
+
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
133
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
134
|
+
destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
135
|
+
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
defaultVariants: {
|
|
139
|
+
variant: "default"
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// src/components/ui/button.tsx
|
|
143
|
+
var import_react_slot2 = require("@radix-ui/react-slot");
|
|
144
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
145
|
+
var jsx_dev_runtime4 = require("react/jsx-dev-runtime");
|
|
146
|
+
var buttonVariants = import_class_variance_authority3.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", {
|
|
147
|
+
variants: {
|
|
148
|
+
variant: {
|
|
149
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
150
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
151
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
152
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
153
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
154
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
155
|
+
},
|
|
156
|
+
size: {
|
|
157
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
158
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
159
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
160
|
+
icon: "size-9"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
defaultVariants: {
|
|
164
|
+
variant: "default",
|
|
165
|
+
size: "default"
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
function Button({
|
|
169
|
+
className,
|
|
170
|
+
variant,
|
|
171
|
+
size,
|
|
172
|
+
asChild = false,
|
|
173
|
+
...props
|
|
174
|
+
}) {
|
|
175
|
+
const Comp = asChild ? import_react_slot2.Slot : "button";
|
|
176
|
+
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Comp, {
|
|
177
|
+
"data-slot": "button",
|
|
178
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
179
|
+
...props
|
|
180
|
+
}, undefined, false, undefined, this);
|
|
181
|
+
}
|
|
182
|
+
// src/components/ui/calendar.tsx
|
|
183
|
+
var import_lucide_react2 = require("lucide-react");
|
|
184
|
+
var import_react_day_picker = require("react-day-picker");
|
|
185
|
+
var jsx_dev_runtime5 = require("react/jsx-dev-runtime");
|
|
186
|
+
function Calendar({
|
|
187
|
+
className,
|
|
188
|
+
classNames,
|
|
189
|
+
showOutsideDays = true,
|
|
190
|
+
...props
|
|
191
|
+
}) {
|
|
192
|
+
return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(import_react_day_picker.DayPicker, {
|
|
193
|
+
showOutsideDays,
|
|
194
|
+
className: cn("p-3", className),
|
|
195
|
+
classNames: {
|
|
196
|
+
months: "flex flex-col sm:flex-row gap-2",
|
|
197
|
+
month: "flex flex-col gap-4",
|
|
198
|
+
caption: "flex justify-center pt-1 relative items-center w-full",
|
|
199
|
+
caption_label: "text-sm font-medium",
|
|
200
|
+
nav: "flex items-center gap-1",
|
|
201
|
+
nav_button: cn(buttonVariants({ variant: "outline" }), "size-7 bg-transparent p-0 opacity-50 hover:opacity-100"),
|
|
202
|
+
nav_button_previous: "absolute left-1",
|
|
203
|
+
nav_button_next: "absolute right-1",
|
|
204
|
+
table: "w-full border-collapse space-x-1",
|
|
205
|
+
head_row: "flex",
|
|
206
|
+
head_cell: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
|
207
|
+
row: "flex w-full mt-2",
|
|
208
|
+
cell: cn("relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md", props.mode === "range" ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" : "[&:has([aria-selected])]:rounded-md"),
|
|
209
|
+
day: cn(buttonVariants({ variant: "ghost" }), "size-8 p-0 font-normal aria-selected:opacity-100"),
|
|
210
|
+
day_range_start: "day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
|
|
211
|
+
day_range_end: "day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
|
|
212
|
+
day_selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
|
213
|
+
day_today: "bg-accent text-accent-foreground",
|
|
214
|
+
day_outside: "day-outside text-muted-foreground aria-selected:text-muted-foreground",
|
|
215
|
+
day_disabled: "text-muted-foreground opacity-50",
|
|
216
|
+
day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
|
|
217
|
+
day_hidden: "invisible",
|
|
218
|
+
...classNames
|
|
219
|
+
},
|
|
220
|
+
components: {
|
|
221
|
+
IconLeft: ({ className: className2, ...props2 }) => /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(import_lucide_react2.ChevronLeft, {
|
|
222
|
+
className: cn("size-4", className2),
|
|
223
|
+
...props2
|
|
224
|
+
}, undefined, false, undefined, this),
|
|
225
|
+
IconRight: ({ className: className2, ...props2 }) => /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(import_lucide_react2.ChevronRight, {
|
|
226
|
+
className: cn("size-4", className2),
|
|
227
|
+
...props2
|
|
228
|
+
}, undefined, false, undefined, this)
|
|
229
|
+
},
|
|
230
|
+
...props
|
|
231
|
+
}, undefined, false, undefined, this);
|
|
232
|
+
}
|
|
233
|
+
// src/components/ui/checkbox.tsx
|
|
234
|
+
var CheckboxPrimitive = __toESM(require("@radix-ui/react-checkbox"));
|
|
235
|
+
var import_lucide_react3 = require("lucide-react");
|
|
236
|
+
var jsx_dev_runtime6 = require("react/jsx-dev-runtime");
|
|
237
|
+
function Checkbox({
|
|
238
|
+
className,
|
|
239
|
+
...props
|
|
240
|
+
}) {
|
|
241
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(CheckboxPrimitive.Root, {
|
|
242
|
+
"data-slot": "checkbox",
|
|
243
|
+
className: cn("peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className),
|
|
244
|
+
...props,
|
|
245
|
+
children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(CheckboxPrimitive.Indicator, {
|
|
246
|
+
"data-slot": "checkbox-indicator",
|
|
247
|
+
className: "flex items-center justify-center text-current transition-none",
|
|
248
|
+
children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(import_lucide_react3.CheckIcon, {
|
|
249
|
+
className: "size-3.5"
|
|
250
|
+
}, undefined, false, undefined, this)
|
|
251
|
+
}, undefined, false, undefined, this)
|
|
252
|
+
}, undefined, false, undefined, this);
|
|
253
|
+
}
|
|
254
|
+
// src/components/ui/card.tsx
|
|
255
|
+
var jsx_dev_runtime7 = require("react/jsx-dev-runtime");
|
|
256
|
+
// src/components/ui/date-picker.tsx
|
|
257
|
+
var import_dayjs2 = __toESM(require("dayjs"));
|
|
258
|
+
var import_lucide_react4 = require("lucide-react");
|
|
259
|
+
|
|
260
|
+
// src/components/ui/popover.tsx
|
|
261
|
+
var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"));
|
|
262
|
+
var jsx_dev_runtime8 = require("react/jsx-dev-runtime");
|
|
263
|
+
function Popover({
|
|
264
|
+
...props
|
|
265
|
+
}) {
|
|
266
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(PopoverPrimitive.Root, {
|
|
267
|
+
"data-slot": "popover",
|
|
268
|
+
...props
|
|
269
|
+
}, undefined, false, undefined, this);
|
|
270
|
+
}
|
|
271
|
+
function PopoverTrigger({
|
|
272
|
+
...props
|
|
273
|
+
}) {
|
|
274
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(PopoverPrimitive.Trigger, {
|
|
275
|
+
"data-slot": "popover-trigger",
|
|
276
|
+
...props
|
|
277
|
+
}, undefined, false, undefined, this);
|
|
278
|
+
}
|
|
279
|
+
function PopoverContent({
|
|
280
|
+
className,
|
|
281
|
+
align = "center",
|
|
282
|
+
sideOffset = 4,
|
|
283
|
+
...props
|
|
284
|
+
}) {
|
|
285
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(PopoverPrimitive.Portal, {
|
|
286
|
+
children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(PopoverPrimitive.Content, {
|
|
287
|
+
"data-slot": "popover-content",
|
|
288
|
+
align,
|
|
289
|
+
sideOffset,
|
|
290
|
+
className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", className),
|
|
291
|
+
...props
|
|
292
|
+
}, undefined, false, undefined, this)
|
|
293
|
+
}, undefined, false, undefined, this);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/components/ui/date-picker.tsx
|
|
297
|
+
var import_react2 = require("react");
|
|
298
|
+
var import_react_popover = require("@radix-ui/react-popover");
|
|
299
|
+
var jsx_dev_runtime9 = require("react/jsx-dev-runtime");
|
|
300
|
+
function DatePicker({
|
|
301
|
+
date,
|
|
302
|
+
closeOnSelect,
|
|
303
|
+
setDate,
|
|
304
|
+
label = "Pick a date",
|
|
305
|
+
className
|
|
306
|
+
}) {
|
|
307
|
+
const popOverRef = import_react2.useRef(null);
|
|
308
|
+
const onSelect = (date2) => {
|
|
309
|
+
setDate(date2);
|
|
310
|
+
if (closeOnSelect) {
|
|
311
|
+
popOverRef.current?.click();
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV("div", {
|
|
315
|
+
className,
|
|
316
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Popover, {
|
|
317
|
+
children: [
|
|
318
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(PopoverTrigger, {
|
|
319
|
+
asChild: true,
|
|
320
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Button, {
|
|
321
|
+
variant: "outline",
|
|
322
|
+
className: cn("w-full justify-start text-left font-normal", !date && "text-muted-foreground"),
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(import_lucide_react4.Calendar, {
|
|
325
|
+
className: "mr-2 h-4 w-4"
|
|
326
|
+
}, undefined, false, undefined, this),
|
|
327
|
+
date ? import_dayjs2.default(date).format("MMM D, YYYY") : /* @__PURE__ */ jsx_dev_runtime9.jsxDEV("span", {
|
|
328
|
+
children: label
|
|
329
|
+
}, undefined, false, undefined, this)
|
|
330
|
+
]
|
|
331
|
+
}, undefined, true, undefined, this)
|
|
332
|
+
}, undefined, false, undefined, this),
|
|
333
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(PopoverContent, {
|
|
334
|
+
className: "w-auto p-0",
|
|
335
|
+
align: "start",
|
|
336
|
+
children: [
|
|
337
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(import_react_popover.PopoverClose, {
|
|
338
|
+
ref: popOverRef
|
|
339
|
+
}, undefined, false, undefined, this),
|
|
340
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Calendar, {
|
|
341
|
+
mode: "single",
|
|
342
|
+
selected: date,
|
|
343
|
+
onSelect,
|
|
344
|
+
initialFocus: true
|
|
345
|
+
}, undefined, false, undefined, this)
|
|
346
|
+
]
|
|
347
|
+
}, undefined, true, undefined, this)
|
|
348
|
+
]
|
|
349
|
+
}, undefined, true, undefined, this)
|
|
350
|
+
}, undefined, false, undefined, this);
|
|
351
|
+
}
|
|
352
|
+
// src/components/ui/dialog.tsx
|
|
353
|
+
var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"));
|
|
354
|
+
var import_lucide_react5 = require("lucide-react");
|
|
355
|
+
var jsx_dev_runtime10 = require("react/jsx-dev-runtime");
|
|
356
|
+
function Dialog({
|
|
357
|
+
...props
|
|
358
|
+
}) {
|
|
359
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Root, {
|
|
360
|
+
"data-slot": "dialog",
|
|
361
|
+
...props
|
|
362
|
+
}, undefined, false, undefined, this);
|
|
363
|
+
}
|
|
364
|
+
function DialogPortal({
|
|
365
|
+
...props
|
|
366
|
+
}) {
|
|
367
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Portal, {
|
|
368
|
+
"data-slot": "dialog-portal",
|
|
369
|
+
...props
|
|
370
|
+
}, undefined, false, undefined, this);
|
|
371
|
+
}
|
|
372
|
+
function DialogOverlay({
|
|
373
|
+
className,
|
|
374
|
+
...props
|
|
375
|
+
}) {
|
|
376
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Overlay, {
|
|
377
|
+
"data-slot": "dialog-overlay",
|
|
378
|
+
className: cn("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", className),
|
|
379
|
+
...props
|
|
380
|
+
}, undefined, false, undefined, this);
|
|
381
|
+
}
|
|
382
|
+
function DialogContent({
|
|
383
|
+
className,
|
|
384
|
+
children,
|
|
385
|
+
...props
|
|
386
|
+
}) {
|
|
387
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPortal, {
|
|
388
|
+
"data-slot": "dialog-portal",
|
|
389
|
+
children: [
|
|
390
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogOverlay, {}, undefined, false, undefined, this),
|
|
391
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Content, {
|
|
392
|
+
"data-slot": "dialog-content",
|
|
393
|
+
className: cn("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg", className),
|
|
394
|
+
...props,
|
|
395
|
+
children: [
|
|
396
|
+
children,
|
|
397
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Close, {
|
|
398
|
+
className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
399
|
+
children: [
|
|
400
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(import_lucide_react5.XIcon, {}, undefined, false, undefined, this),
|
|
401
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV("span", {
|
|
402
|
+
className: "sr-only",
|
|
403
|
+
children: "Close"
|
|
404
|
+
}, undefined, false, undefined, this)
|
|
405
|
+
]
|
|
406
|
+
}, undefined, true, undefined, this)
|
|
407
|
+
]
|
|
408
|
+
}, undefined, true, undefined, this)
|
|
409
|
+
]
|
|
410
|
+
}, undefined, true, undefined, this);
|
|
411
|
+
}
|
|
412
|
+
function DialogHeader({ className, ...props }) {
|
|
413
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV("div", {
|
|
414
|
+
"data-slot": "dialog-header",
|
|
415
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
416
|
+
...props
|
|
417
|
+
}, undefined, false, undefined, this);
|
|
418
|
+
}
|
|
419
|
+
function DialogFooter({ className, ...props }) {
|
|
420
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV("div", {
|
|
421
|
+
"data-slot": "dialog-footer",
|
|
422
|
+
className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
423
|
+
...props
|
|
424
|
+
}, undefined, false, undefined, this);
|
|
425
|
+
}
|
|
426
|
+
function DialogTitle({
|
|
427
|
+
className,
|
|
428
|
+
...props
|
|
429
|
+
}) {
|
|
430
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Title, {
|
|
431
|
+
"data-slot": "dialog-title",
|
|
432
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
433
|
+
...props
|
|
434
|
+
}, undefined, false, undefined, this);
|
|
435
|
+
}
|
|
436
|
+
function DialogDescription({
|
|
437
|
+
className,
|
|
438
|
+
...props
|
|
439
|
+
}) {
|
|
440
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DialogPrimitive.Description, {
|
|
441
|
+
"data-slot": "dialog-description",
|
|
442
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
443
|
+
...props
|
|
444
|
+
}, undefined, false, undefined, this);
|
|
445
|
+
}
|
|
446
|
+
// src/components/ui/dropdown-menu.tsx
|
|
447
|
+
var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"));
|
|
448
|
+
var import_lucide_react6 = require("lucide-react");
|
|
449
|
+
var jsx_dev_runtime11 = require("react/jsx-dev-runtime");
|
|
450
|
+
// src/components/ui/form.tsx
|
|
451
|
+
var React = __toESM(require("react"));
|
|
452
|
+
var import_react_slot3 = require("@radix-ui/react-slot");
|
|
453
|
+
var import_react_hook_form = require("react-hook-form");
|
|
454
|
+
|
|
455
|
+
// src/components/ui/label.tsx
|
|
456
|
+
var LabelPrimitive = __toESM(require("@radix-ui/react-label"));
|
|
457
|
+
var jsx_dev_runtime12 = require("react/jsx-dev-runtime");
|
|
458
|
+
|
|
459
|
+
function Label2({
|
|
460
|
+
className,
|
|
461
|
+
...props
|
|
462
|
+
}) {
|
|
463
|
+
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(LabelPrimitive.Root, {
|
|
464
|
+
"data-slot": "label",
|
|
465
|
+
className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
|
|
466
|
+
...props
|
|
467
|
+
}, undefined, false, undefined, this);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/components/ui/form.tsx
|
|
471
|
+
var jsx_dev_runtime13 = require("react/jsx-dev-runtime");
|
|
472
|
+
var FormFieldContext = React.createContext({});
|
|
473
|
+
var FormItemContext = React.createContext({});
|
|
474
|
+
// src/components/ui/input.tsx
|
|
475
|
+
var jsx_dev_runtime14 = require("react/jsx-dev-runtime");
|
|
476
|
+
function Input({ className, type, ...props }) {
|
|
477
|
+
return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV("input", {
|
|
478
|
+
type,
|
|
479
|
+
"data-slot": "input",
|
|
480
|
+
className: cn("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className),
|
|
481
|
+
...props
|
|
482
|
+
}, undefined, false, undefined, this);
|
|
483
|
+
}
|
|
484
|
+
// src/components/ui/link.tsx
|
|
485
|
+
var jsx_dev_runtime15 = require("react/jsx-dev-runtime");
|
|
486
|
+
// src/components/ui/scroll-area.tsx
|
|
487
|
+
var ScrollAreaPrimitive = __toESM(require("@radix-ui/react-scroll-area"));
|
|
488
|
+
var jsx_dev_runtime16 = require("react/jsx-dev-runtime");
|
|
489
|
+
function ScrollArea({
|
|
490
|
+
className,
|
|
491
|
+
children,
|
|
492
|
+
...props
|
|
493
|
+
}) {
|
|
494
|
+
return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollAreaPrimitive.Root, {
|
|
495
|
+
"data-slot": "scroll-area",
|
|
496
|
+
className: cn("relative", className),
|
|
497
|
+
...props,
|
|
498
|
+
children: [
|
|
499
|
+
/* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollAreaPrimitive.Viewport, {
|
|
500
|
+
"data-slot": "scroll-area-viewport",
|
|
501
|
+
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
502
|
+
children
|
|
503
|
+
}, undefined, false, undefined, this),
|
|
504
|
+
/* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollBar, {}, undefined, false, undefined, this),
|
|
505
|
+
/* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollAreaPrimitive.Corner, {}, undefined, false, undefined, this)
|
|
506
|
+
]
|
|
507
|
+
}, undefined, true, undefined, this);
|
|
508
|
+
}
|
|
509
|
+
function ScrollBar({
|
|
510
|
+
className,
|
|
511
|
+
orientation = "vertical",
|
|
512
|
+
...props
|
|
513
|
+
}) {
|
|
514
|
+
return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollAreaPrimitive.ScrollAreaScrollbar, {
|
|
515
|
+
"data-slot": "scroll-area-scrollbar",
|
|
516
|
+
orientation,
|
|
517
|
+
className: cn("flex touch-none p-px transition-colors select-none", orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent", orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent", className),
|
|
518
|
+
...props,
|
|
519
|
+
children: /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(ScrollAreaPrimitive.ScrollAreaThumb, {
|
|
520
|
+
"data-slot": "scroll-area-thumb",
|
|
521
|
+
className: "bg-border relative flex-1 rounded-full"
|
|
522
|
+
}, undefined, false, undefined, this)
|
|
523
|
+
}, undefined, false, undefined, this);
|
|
524
|
+
}
|
|
525
|
+
// src/components/ui/select.tsx
|
|
526
|
+
var SelectPrimitive = __toESM(require("@radix-ui/react-select"));
|
|
527
|
+
var import_lucide_react7 = require("lucide-react");
|
|
528
|
+
var jsx_dev_runtime17 = require("react/jsx-dev-runtime");
|
|
529
|
+
// src/components/ui/separator.tsx
|
|
530
|
+
var SeparatorPrimitive = __toESM(require("@radix-ui/react-separator"));
|
|
531
|
+
var jsx_dev_runtime18 = require("react/jsx-dev-runtime");
|
|
532
|
+
// src/components/ui/sheet.tsx
|
|
533
|
+
var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"));
|
|
534
|
+
var import_lucide_react8 = require("lucide-react");
|
|
535
|
+
var jsx_dev_runtime19 = require("react/jsx-dev-runtime");
|
|
536
|
+
// src/components/ui/table.tsx
|
|
537
|
+
var jsx_dev_runtime20 = require("react/jsx-dev-runtime");
|
|
538
|
+
// src/components/ui/tabs.tsx
|
|
539
|
+
var TabsPrimitive = __toESM(require("@radix-ui/react-tabs"));
|
|
540
|
+
var jsx_dev_runtime21 = require("react/jsx-dev-runtime");
|
|
541
|
+
// src/components/ui/textarea.tsx
|
|
542
|
+
var jsx_dev_runtime22 = require("react/jsx-dev-runtime");
|
|
543
|
+
// src/components/ui/tooltip.tsx
|
|
544
|
+
var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"));
|
|
545
|
+
var jsx_dev_runtime23 = require("react/jsx-dev-runtime");
|
|
546
|
+
function TooltipProvider({
|
|
547
|
+
delayDuration = 0,
|
|
548
|
+
...props
|
|
549
|
+
}) {
|
|
550
|
+
return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Provider, {
|
|
551
|
+
"data-slot": "tooltip-provider",
|
|
552
|
+
delayDuration,
|
|
553
|
+
...props
|
|
554
|
+
}, undefined, false, undefined, this);
|
|
555
|
+
}
|
|
556
|
+
function Tooltip({
|
|
557
|
+
...props
|
|
558
|
+
}) {
|
|
559
|
+
return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipProvider, {
|
|
560
|
+
children: /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Root, {
|
|
561
|
+
"data-slot": "tooltip",
|
|
562
|
+
...props
|
|
563
|
+
}, undefined, false, undefined, this)
|
|
564
|
+
}, undefined, false, undefined, this);
|
|
565
|
+
}
|
|
566
|
+
function TooltipTrigger({
|
|
567
|
+
...props
|
|
568
|
+
}) {
|
|
569
|
+
return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Trigger, {
|
|
570
|
+
"data-slot": "tooltip-trigger",
|
|
571
|
+
...props
|
|
572
|
+
}, undefined, false, undefined, this);
|
|
573
|
+
}
|
|
574
|
+
function TooltipContent({
|
|
575
|
+
className,
|
|
576
|
+
sideOffset = 0,
|
|
577
|
+
children,
|
|
578
|
+
...props
|
|
579
|
+
}) {
|
|
580
|
+
return /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Portal, {
|
|
581
|
+
children: /* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Content, {
|
|
582
|
+
"data-slot": "tooltip-content",
|
|
583
|
+
sideOffset,
|
|
584
|
+
className: cn("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", className),
|
|
585
|
+
...props,
|
|
586
|
+
children: [
|
|
587
|
+
children,
|
|
588
|
+
/* @__PURE__ */ jsx_dev_runtime23.jsxDEV(TooltipPrimitive.Arrow, {
|
|
589
|
+
className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"
|
|
590
|
+
}, undefined, false, undefined, this)
|
|
591
|
+
]
|
|
592
|
+
}, undefined, true, undefined, this)
|
|
593
|
+
}, undefined, false, undefined, this);
|
|
594
|
+
}
|
|
595
|
+
// src/features/month-view/components/all-events-dialog.tsx
|
|
596
|
+
var import_react5 = require("react");
|
|
597
|
+
|
|
598
|
+
// src/features/draggable-event/draggable-event.tsx
|
|
599
|
+
var import_core = require("@dnd-kit/core");
|
|
600
|
+
var import_react3 = require("motion/react");
|
|
601
|
+
var import_react4 = require("react");
|
|
602
|
+
var jsx_dev_runtime24 = require("react/jsx-dev-runtime");
|
|
603
|
+
function DraggableEventUnmemoized({
|
|
604
|
+
elementId,
|
|
605
|
+
event,
|
|
606
|
+
className,
|
|
607
|
+
style,
|
|
608
|
+
disableDrag = false
|
|
609
|
+
}) {
|
|
610
|
+
const { onEventClick, renderEvent, disableEventClick, disableDragAndDrop } = useCalendarContext();
|
|
611
|
+
const { attributes, listeners, setNodeRef, isDragging } = import_core.useDraggable({
|
|
612
|
+
id: elementId,
|
|
613
|
+
data: {
|
|
614
|
+
event,
|
|
615
|
+
type: "calendar-event"
|
|
616
|
+
},
|
|
617
|
+
disabled: disableDrag || disableDragAndDrop
|
|
618
|
+
});
|
|
619
|
+
const DefaultEventContent = () => /* @__PURE__ */ jsx_dev_runtime24.jsxDEV("div", {
|
|
620
|
+
className: cn(event.backgroundColor || "bg-blue-500", event.color || "text-white", "h-full w-full px-1 border-[1.5px] border-card rounded-md text-left overflow-clip"),
|
|
621
|
+
style: { backgroundColor: event.backgroundColor, color: event.color },
|
|
622
|
+
children: /* @__PURE__ */ jsx_dev_runtime24.jsxDEV("p", {
|
|
623
|
+
className: "text-[10px] font-semibold sm:text-xs mt-0.5",
|
|
624
|
+
children: event.title
|
|
625
|
+
}, undefined, false, undefined, this)
|
|
626
|
+
}, undefined, false, undefined, this);
|
|
627
|
+
return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(import_react3.AnimatePresence, {
|
|
628
|
+
mode: "wait",
|
|
629
|
+
children: /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(import_react3.motion.div, {
|
|
630
|
+
ref: setNodeRef,
|
|
631
|
+
...attributes,
|
|
632
|
+
...listeners,
|
|
633
|
+
initial: { opacity: 0, y: -50 },
|
|
634
|
+
animate: { opacity: 1, y: 0 },
|
|
635
|
+
exit: { opacity: 0, y: -50 },
|
|
636
|
+
layout: true,
|
|
637
|
+
layoutId: elementId,
|
|
638
|
+
transition: { duration: 0.4, ease: "easeInOut" },
|
|
639
|
+
className: cn("truncate h-full w-full", disableDrag || disableDragAndDrop ? disableEventClick ? "cursor-default" : "cursor-pointer" : "cursor-grab", isDragging && !(disableDrag || disableDragAndDrop) && "cursor-grabbing shadow-lg", className),
|
|
640
|
+
style,
|
|
641
|
+
onClick: (e) => {
|
|
642
|
+
e.stopPropagation();
|
|
643
|
+
onEventClick(event);
|
|
644
|
+
},
|
|
645
|
+
children: renderEvent ? renderEvent(event) : /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(DefaultEventContent, {}, undefined, false, undefined, this)
|
|
646
|
+
}, elementId, false, undefined, this)
|
|
647
|
+
}, undefined, false, undefined, this);
|
|
648
|
+
}
|
|
649
|
+
var DraggableEvent = import_react4.memo(DraggableEventUnmemoized, (prevProps, nextProps) => {
|
|
650
|
+
return prevProps.elementId === nextProps.elementId && prevProps.disableDrag === nextProps.disableDrag && prevProps.className === nextProps.className && prevProps.event.id === nextProps.event.id && prevProps.event.height === nextProps.event.height;
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// src/features/month-view/components/all-events-dialog.tsx
|
|
654
|
+
var jsx_dev_runtime25 = require("react/jsx-dev-runtime");
|
|
655
|
+
var AllEventDialog = ({ ref }) => {
|
|
656
|
+
const [dialogOpen, setDialogOpen] = import_react5.useState(false);
|
|
657
|
+
const [selectedDayEvents, setSelectedDayEvents] = import_react5.useState(null);
|
|
658
|
+
const { currentDate, firstDayOfWeek } = useCalendarContext();
|
|
659
|
+
import_react5.useImperativeHandle(ref, () => ({
|
|
660
|
+
open: () => setDialogOpen(true),
|
|
661
|
+
close: () => setDialogOpen(false),
|
|
662
|
+
setSelectedDayEvents: (dayEvents) => setSelectedDayEvents(dayEvents)
|
|
663
|
+
}));
|
|
664
|
+
const firstDayOfMonth = currentDate.startOf("month");
|
|
665
|
+
let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
|
|
666
|
+
while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
|
|
667
|
+
adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
|
|
668
|
+
}
|
|
669
|
+
return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(Dialog, {
|
|
670
|
+
open: dialogOpen,
|
|
671
|
+
onOpenChange: setDialogOpen,
|
|
672
|
+
children: /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(DialogContent, {
|
|
673
|
+
className: "max-h-[80vh] max-w-md overflow-y-auto",
|
|
674
|
+
children: [
|
|
675
|
+
/* @__PURE__ */ jsx_dev_runtime25.jsxDEV(DialogHeader, {
|
|
676
|
+
children: /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(DialogTitle, {
|
|
677
|
+
children: selectedDayEvents && selectedDayEvents.day.format("MMMM D, YYYY")
|
|
678
|
+
}, undefined, false, undefined, this)
|
|
679
|
+
}, undefined, false, undefined, this),
|
|
680
|
+
/* @__PURE__ */ jsx_dev_runtime25.jsxDEV("div", {
|
|
681
|
+
className: "mt-4 space-y-3",
|
|
682
|
+
children: selectedDayEvents && selectedDayEvents.events.map((event) => {
|
|
683
|
+
return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(DraggableEvent, {
|
|
684
|
+
elementId: event.id,
|
|
685
|
+
event,
|
|
686
|
+
className: "relative my-1 h-[30px]"
|
|
687
|
+
}, event.id, false, undefined, this);
|
|
688
|
+
})
|
|
689
|
+
}, undefined, false, undefined, this)
|
|
690
|
+
]
|
|
691
|
+
}, undefined, true, undefined, this)
|
|
692
|
+
}, undefined, false, undefined, this);
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
// src/lib/dayjs-config.ts
|
|
696
|
+
var import_dayjs3 = __toESM(require("dayjs"));
|
|
697
|
+
var import_weekday = __toESM(require("dayjs/plugin/weekday"));
|
|
698
|
+
var import_weekOfYear = __toESM(require("dayjs/plugin/weekOfYear"));
|
|
699
|
+
var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter"));
|
|
700
|
+
var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore"));
|
|
701
|
+
var import_isBetween = __toESM(require("dayjs/plugin/isBetween"));
|
|
702
|
+
var import_minMax = __toESM(require("dayjs/plugin/minMax"));
|
|
703
|
+
var import_timezone = __toESM(require("dayjs/plugin/timezone"));
|
|
704
|
+
var import_utc = __toESM(require("dayjs/plugin/utc"));
|
|
705
|
+
var import_localeData = __toESM(require("dayjs/plugin/localeData"));
|
|
706
|
+
var import_af = require("dayjs/locale/af");
|
|
707
|
+
var import_am = require("dayjs/locale/am");
|
|
708
|
+
var import_ar_dz = require("dayjs/locale/ar-dz");
|
|
709
|
+
var import_ar_iq = require("dayjs/locale/ar-iq");
|
|
710
|
+
var import_ar_kw = require("dayjs/locale/ar-kw");
|
|
711
|
+
var import_ar_ly = require("dayjs/locale/ar-ly");
|
|
712
|
+
var import_ar_ma = require("dayjs/locale/ar-ma");
|
|
713
|
+
var import_ar_sa = require("dayjs/locale/ar-sa");
|
|
714
|
+
var import_ar_tn = require("dayjs/locale/ar-tn");
|
|
715
|
+
var import_ar = require("dayjs/locale/ar");
|
|
716
|
+
var import_az = require("dayjs/locale/az");
|
|
717
|
+
var import_be = require("dayjs/locale/be");
|
|
718
|
+
var import_bg = require("dayjs/locale/bg");
|
|
719
|
+
var import_bi = require("dayjs/locale/bi");
|
|
720
|
+
var import_bm = require("dayjs/locale/bm");
|
|
721
|
+
var import_bn_bd = require("dayjs/locale/bn-bd");
|
|
722
|
+
var import_bn = require("dayjs/locale/bn");
|
|
723
|
+
var import_bo = require("dayjs/locale/bo");
|
|
724
|
+
var import_br = require("dayjs/locale/br");
|
|
725
|
+
var import_bs = require("dayjs/locale/bs");
|
|
726
|
+
var import_ca = require("dayjs/locale/ca");
|
|
727
|
+
var import_cs = require("dayjs/locale/cs");
|
|
728
|
+
var import_cv = require("dayjs/locale/cv");
|
|
729
|
+
var import_cy = require("dayjs/locale/cy");
|
|
730
|
+
var import_da = require("dayjs/locale/da");
|
|
731
|
+
var import_de_at = require("dayjs/locale/de-at");
|
|
732
|
+
var import_de_ch = require("dayjs/locale/de-ch");
|
|
733
|
+
var import_de = require("dayjs/locale/de");
|
|
734
|
+
var import_dv = require("dayjs/locale/dv");
|
|
735
|
+
var import_el = require("dayjs/locale/el");
|
|
736
|
+
var import_en_au = require("dayjs/locale/en-au");
|
|
737
|
+
var import_en_ca = require("dayjs/locale/en-ca");
|
|
738
|
+
var import_en_gb = require("dayjs/locale/en-gb");
|
|
739
|
+
var import_en_ie = require("dayjs/locale/en-ie");
|
|
740
|
+
var import_en_il = require("dayjs/locale/en-il");
|
|
741
|
+
var import_en_in = require("dayjs/locale/en-in");
|
|
742
|
+
var import_en_nz = require("dayjs/locale/en-nz");
|
|
743
|
+
var import_en_sg = require("dayjs/locale/en-sg");
|
|
744
|
+
var import_en_tt = require("dayjs/locale/en-tt");
|
|
745
|
+
var import_en = require("dayjs/locale/en");
|
|
746
|
+
var import_eo = require("dayjs/locale/eo");
|
|
747
|
+
var import_es_do = require("dayjs/locale/es-do");
|
|
748
|
+
var import_es_mx = require("dayjs/locale/es-mx");
|
|
749
|
+
var import_es_pr = require("dayjs/locale/es-pr");
|
|
750
|
+
var import_es_us = require("dayjs/locale/es-us");
|
|
751
|
+
var import_es = require("dayjs/locale/es");
|
|
752
|
+
var import_et = require("dayjs/locale/et");
|
|
753
|
+
var import_eu = require("dayjs/locale/eu");
|
|
754
|
+
var import_fa = require("dayjs/locale/fa");
|
|
755
|
+
var import_fi = require("dayjs/locale/fi");
|
|
756
|
+
var import_fo = require("dayjs/locale/fo");
|
|
757
|
+
var import_fr_ca = require("dayjs/locale/fr-ca");
|
|
758
|
+
var import_fr_ch = require("dayjs/locale/fr-ch");
|
|
759
|
+
var import_fr = require("dayjs/locale/fr");
|
|
760
|
+
var import_fy = require("dayjs/locale/fy");
|
|
761
|
+
var import_ga = require("dayjs/locale/ga");
|
|
762
|
+
var import_gd = require("dayjs/locale/gd");
|
|
763
|
+
var import_gl = require("dayjs/locale/gl");
|
|
764
|
+
var import_gom_latn = require("dayjs/locale/gom-latn");
|
|
765
|
+
var import_gu = require("dayjs/locale/gu");
|
|
766
|
+
var import_he = require("dayjs/locale/he");
|
|
767
|
+
var import_hi = require("dayjs/locale/hi");
|
|
768
|
+
var import_hr = require("dayjs/locale/hr");
|
|
769
|
+
var import_ht = require("dayjs/locale/ht");
|
|
770
|
+
var import_hu = require("dayjs/locale/hu");
|
|
771
|
+
var import_hy_am = require("dayjs/locale/hy-am");
|
|
772
|
+
var import_id = require("dayjs/locale/id");
|
|
773
|
+
var import_is = require("dayjs/locale/is");
|
|
774
|
+
var import_it_ch = require("dayjs/locale/it-ch");
|
|
775
|
+
var import_it = require("dayjs/locale/it");
|
|
776
|
+
var import_ja = require("dayjs/locale/ja");
|
|
777
|
+
var import_jv = require("dayjs/locale/jv");
|
|
778
|
+
var import_ka = require("dayjs/locale/ka");
|
|
779
|
+
var import_kk = require("dayjs/locale/kk");
|
|
780
|
+
var import_km = require("dayjs/locale/km");
|
|
781
|
+
var import_kn = require("dayjs/locale/kn");
|
|
782
|
+
var import_ko = require("dayjs/locale/ko");
|
|
783
|
+
var import_ku = require("dayjs/locale/ku");
|
|
784
|
+
var import_ky = require("dayjs/locale/ky");
|
|
785
|
+
var import_lb = require("dayjs/locale/lb");
|
|
786
|
+
var import_lo = require("dayjs/locale/lo");
|
|
787
|
+
var import_lt = require("dayjs/locale/lt");
|
|
788
|
+
var import_lv = require("dayjs/locale/lv");
|
|
789
|
+
var import_me = require("dayjs/locale/me");
|
|
790
|
+
var import_mi = require("dayjs/locale/mi");
|
|
791
|
+
var import_mk = require("dayjs/locale/mk");
|
|
792
|
+
var import_ml = require("dayjs/locale/ml");
|
|
793
|
+
var import_mn = require("dayjs/locale/mn");
|
|
794
|
+
var import_mr = require("dayjs/locale/mr");
|
|
795
|
+
var import_ms_my = require("dayjs/locale/ms-my");
|
|
796
|
+
var import_ms = require("dayjs/locale/ms");
|
|
797
|
+
var import_mt = require("dayjs/locale/mt");
|
|
798
|
+
var import_my = require("dayjs/locale/my");
|
|
799
|
+
var import_nb = require("dayjs/locale/nb");
|
|
800
|
+
var import_ne = require("dayjs/locale/ne");
|
|
801
|
+
var import_nl_be = require("dayjs/locale/nl-be");
|
|
802
|
+
var import_nl = require("dayjs/locale/nl");
|
|
803
|
+
var import_nn = require("dayjs/locale/nn");
|
|
804
|
+
var import_oc_lnc = require("dayjs/locale/oc-lnc");
|
|
805
|
+
var import_pa_in = require("dayjs/locale/pa-in");
|
|
806
|
+
var import_pl = require("dayjs/locale/pl");
|
|
807
|
+
var import_pt_br = require("dayjs/locale/pt-br");
|
|
808
|
+
var import_pt = require("dayjs/locale/pt");
|
|
809
|
+
var import_rn = require("dayjs/locale/rn");
|
|
810
|
+
var import_ro = require("dayjs/locale/ro");
|
|
811
|
+
var import_ru = require("dayjs/locale/ru");
|
|
812
|
+
var import_rw = require("dayjs/locale/rw");
|
|
813
|
+
var import_sd = require("dayjs/locale/sd");
|
|
814
|
+
var import_se = require("dayjs/locale/se");
|
|
815
|
+
var import_si = require("dayjs/locale/si");
|
|
816
|
+
var import_sk = require("dayjs/locale/sk");
|
|
817
|
+
var import_sl = require("dayjs/locale/sl");
|
|
818
|
+
var import_sq = require("dayjs/locale/sq");
|
|
819
|
+
var import_sr_cyrl = require("dayjs/locale/sr-cyrl");
|
|
820
|
+
var import_sr = require("dayjs/locale/sr");
|
|
821
|
+
var import_ss = require("dayjs/locale/ss");
|
|
822
|
+
var import_sv_fi = require("dayjs/locale/sv-fi");
|
|
823
|
+
var import_sv = require("dayjs/locale/sv");
|
|
824
|
+
var import_sw = require("dayjs/locale/sw");
|
|
825
|
+
var import_ta = require("dayjs/locale/ta");
|
|
826
|
+
var import_te = require("dayjs/locale/te");
|
|
827
|
+
var import_tet = require("dayjs/locale/tet");
|
|
828
|
+
var import_tg = require("dayjs/locale/tg");
|
|
829
|
+
var import_th = require("dayjs/locale/th");
|
|
830
|
+
var import_tk = require("dayjs/locale/tk");
|
|
831
|
+
var import_tl_ph = require("dayjs/locale/tl-ph");
|
|
832
|
+
var import_tlh = require("dayjs/locale/tlh");
|
|
833
|
+
var import_tr = require("dayjs/locale/tr");
|
|
834
|
+
var import_tzl = require("dayjs/locale/tzl");
|
|
835
|
+
var import_tzm_latn = require("dayjs/locale/tzm-latn");
|
|
836
|
+
var import_tzm = require("dayjs/locale/tzm");
|
|
837
|
+
var import_ug_cn = require("dayjs/locale/ug-cn");
|
|
838
|
+
var import_uk = require("dayjs/locale/uk");
|
|
839
|
+
var import_ur = require("dayjs/locale/ur");
|
|
840
|
+
var import_uz_latn = require("dayjs/locale/uz-latn");
|
|
841
|
+
var import_uz = require("dayjs/locale/uz");
|
|
842
|
+
var import_vi = require("dayjs/locale/vi");
|
|
843
|
+
var import_x_pseudo = require("dayjs/locale/x-pseudo");
|
|
844
|
+
var import_yo = require("dayjs/locale/yo");
|
|
845
|
+
var import_zh_cn = require("dayjs/locale/zh-cn");
|
|
846
|
+
var import_zh_hk = require("dayjs/locale/zh-hk");
|
|
847
|
+
var import_zh_tw = require("dayjs/locale/zh-tw");
|
|
848
|
+
var import_zh = require("dayjs/locale/zh");
|
|
849
|
+
import_dayjs3.default.extend(import_weekday.default);
|
|
850
|
+
import_dayjs3.default.extend(import_weekOfYear.default);
|
|
851
|
+
import_dayjs3.default.extend(import_isSameOrAfter.default);
|
|
852
|
+
import_dayjs3.default.extend(import_isSameOrBefore.default);
|
|
853
|
+
import_dayjs3.default.extend(import_isBetween.default);
|
|
854
|
+
import_dayjs3.default.extend(import_minMax.default);
|
|
855
|
+
import_dayjs3.default.extend(import_timezone.default);
|
|
856
|
+
import_dayjs3.default.extend(import_utc.default);
|
|
857
|
+
import_dayjs3.default.extend(import_localeData.default);
|
|
858
|
+
var dayjs_config_default = import_dayjs3.default;
|
|
859
|
+
|
|
860
|
+
// src/features/month-view/components/day-cell.tsx
|
|
861
|
+
var import_react6 = __toESM(require("react"));
|
|
862
|
+
|
|
863
|
+
// src/features/droppable-cell/droppable-cell.tsx
|
|
864
|
+
var import_core2 = require("@dnd-kit/core");
|
|
865
|
+
var jsx_dev_runtime26 = require("react/jsx-dev-runtime");
|
|
866
|
+
function DroppableCell({
|
|
867
|
+
id,
|
|
868
|
+
type,
|
|
869
|
+
date,
|
|
870
|
+
hour,
|
|
871
|
+
minute,
|
|
872
|
+
children,
|
|
873
|
+
className,
|
|
874
|
+
style,
|
|
875
|
+
"data-testid": dataTestId
|
|
876
|
+
}) {
|
|
877
|
+
const { onCellClick, disableDragAndDrop, disableCellClick } = useCalendarContext();
|
|
878
|
+
const { isOver, setNodeRef } = import_core2.useDroppable({
|
|
879
|
+
id,
|
|
880
|
+
data: {
|
|
881
|
+
type,
|
|
882
|
+
date,
|
|
883
|
+
hour,
|
|
884
|
+
minute
|
|
885
|
+
},
|
|
886
|
+
disabled: disableDragAndDrop
|
|
887
|
+
});
|
|
888
|
+
const handleCellClick = (e) => {
|
|
889
|
+
e.stopPropagation();
|
|
890
|
+
if (disableCellClick)
|
|
891
|
+
return;
|
|
892
|
+
const startDate = date.hour(hour ?? 0).minute(minute ?? 0);
|
|
893
|
+
let endDate = startDate.clone();
|
|
894
|
+
if (hour !== undefined && minute !== undefined) {
|
|
895
|
+
endDate = endDate.hour(hour).minute(minute + 15);
|
|
896
|
+
} else if (hour !== undefined) {
|
|
897
|
+
endDate = endDate.hour(hour + 1).minute(0);
|
|
898
|
+
} else {
|
|
899
|
+
endDate = endDate.hour(23).minute(59);
|
|
900
|
+
}
|
|
901
|
+
onCellClick(startDate, endDate);
|
|
902
|
+
};
|
|
903
|
+
return /* @__PURE__ */ jsx_dev_runtime26.jsxDEV("div", {
|
|
904
|
+
ref: setNodeRef,
|
|
905
|
+
"data-testid": dataTestId,
|
|
906
|
+
className: cn(className, isOver && !disableDragAndDrop && "bg-accent", disableCellClick ? "cursor-default" : "cursor-pointer"),
|
|
907
|
+
onClick: handleCellClick,
|
|
908
|
+
style,
|
|
909
|
+
children
|
|
910
|
+
}, undefined, false, undefined, this);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// src/features/month-view/components/day-cell.tsx
|
|
914
|
+
var jsx_dev_runtime27 = require("react/jsx-dev-runtime");
|
|
915
|
+
var DayCell = ({
|
|
916
|
+
index,
|
|
917
|
+
day,
|
|
918
|
+
className = ""
|
|
919
|
+
}) => {
|
|
920
|
+
const allEventsDialogRef = import_react6.default.useRef(null);
|
|
921
|
+
const {
|
|
922
|
+
events,
|
|
923
|
+
currentDate,
|
|
924
|
+
firstDayOfWeek,
|
|
925
|
+
dayMaxEvents = 0
|
|
926
|
+
} = useCalendarContext();
|
|
927
|
+
const todayEvents = events.filter((e) => {
|
|
928
|
+
const startsToday = e.start.isSame(day, "day");
|
|
929
|
+
const endsToday = e.end.isSame(day, "day");
|
|
930
|
+
const spansToday = e.start.isBefore(day, "day") && e.end.isAfter(day, "day");
|
|
931
|
+
return startsToday || endsToday || spansToday;
|
|
932
|
+
});
|
|
933
|
+
const firstDayOfMonth = currentDate.startOf("month");
|
|
934
|
+
let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
|
|
935
|
+
while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
|
|
936
|
+
adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
|
|
937
|
+
}
|
|
938
|
+
const showAllEvents = (day2, events2) => {
|
|
939
|
+
allEventsDialogRef.current?.setSelectedDayEvents({
|
|
940
|
+
day: day2,
|
|
941
|
+
events: events2
|
|
942
|
+
});
|
|
943
|
+
allEventsDialogRef.current?.open();
|
|
944
|
+
};
|
|
945
|
+
const isToday = day.isSame(dayjs_config_default(), "day");
|
|
946
|
+
const isCurrentMonth = day.month() === currentDate.month();
|
|
947
|
+
const isLastColumn = index === 6;
|
|
948
|
+
const hiddenEventsCount = todayEvents.length - dayMaxEvents;
|
|
949
|
+
const hasHiddenEvents = hiddenEventsCount > 0;
|
|
950
|
+
return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(jsx_dev_runtime27.Fragment, {
|
|
951
|
+
children: [
|
|
952
|
+
/* @__PURE__ */ jsx_dev_runtime27.jsxDEV(DroppableCell, {
|
|
953
|
+
id: `day-cell-${day.format("YYYY-MM-DD")}`,
|
|
954
|
+
type: "day-cell",
|
|
955
|
+
"data-testid": `day-cell-${day.format("YYYY-MM-DD")}`,
|
|
956
|
+
date: day,
|
|
957
|
+
className: cn("cursor-pointer overflow-clip p-1 hover:bg-accent", !isCurrentMonth && "bg-secondary text-muted-foreground", isLastColumn && "border-r-0", className),
|
|
958
|
+
children: /* @__PURE__ */ jsx_dev_runtime27.jsxDEV("div", {
|
|
959
|
+
className: "flex flex-col gap-1",
|
|
960
|
+
children: [
|
|
961
|
+
/* @__PURE__ */ jsx_dev_runtime27.jsxDEV("div", {
|
|
962
|
+
className: cn("flex h-5 w-5 items-center justify-center rounded-full text-xs sm:h-6 sm:w-6 sm:text-sm", isToday && "bg-primary text-primary-foreground font-medium"),
|
|
963
|
+
children: day.date()
|
|
964
|
+
}, undefined, false, undefined, this),
|
|
965
|
+
todayEvents.slice(0, dayMaxEvents).map((event, rowIndex) => /* @__PURE__ */ jsx_dev_runtime27.jsxDEV("div", {
|
|
966
|
+
className: "h-[20px] w-full",
|
|
967
|
+
"data-testid": event?.title
|
|
968
|
+
}, `empty-${rowIndex}`, false, undefined, this)),
|
|
969
|
+
hasHiddenEvents && /* @__PURE__ */ jsx_dev_runtime27.jsxDEV("div", {
|
|
970
|
+
className: "text-muted-foreground hover:text-foreground cursor-pointer text-[10px] whitespace-nowrap sm:text-xs mt-1",
|
|
971
|
+
onClick: (e) => {
|
|
972
|
+
e.stopPropagation();
|
|
973
|
+
showAllEvents(day, todayEvents);
|
|
974
|
+
},
|
|
975
|
+
children: [
|
|
976
|
+
"+",
|
|
977
|
+
hiddenEventsCount,
|
|
978
|
+
" more"
|
|
979
|
+
]
|
|
980
|
+
}, undefined, true, undefined, this)
|
|
981
|
+
]
|
|
982
|
+
}, undefined, true, undefined, this)
|
|
983
|
+
}, undefined, false, undefined, this),
|
|
984
|
+
/* @__PURE__ */ jsx_dev_runtime27.jsxDEV(AllEventDialog, {
|
|
985
|
+
ref: allEventsDialogRef
|
|
986
|
+
}, undefined, false, undefined, this)
|
|
987
|
+
]
|
|
988
|
+
}, undefined, true, undefined, this);
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
// src/features/month-view/components/month-header.tsx
|
|
992
|
+
var import_react7 = require("motion/react");
|
|
993
|
+
var import_react8 = require("react");
|
|
994
|
+
var import_dayjs4 = __toESM(require("dayjs"));
|
|
995
|
+
var jsx_dev_runtime28 = require("react/jsx-dev-runtime");
|
|
996
|
+
var MonthHeader = () => {
|
|
997
|
+
const { firstDayOfWeek, currentLocale, stickyHeader } = useCalendarContext();
|
|
998
|
+
const weekDays = import_react8.useMemo(() => {
|
|
999
|
+
const days = import_dayjs4.default.weekdays().map((day) => day.toLowerCase());
|
|
1000
|
+
const shortDays = import_dayjs4.default.weekdaysShort().map((day) => day.toLowerCase());
|
|
1001
|
+
for (let i = 0;i < firstDayOfWeek; i++) {
|
|
1002
|
+
const dayToMove = days.shift();
|
|
1003
|
+
const shortDayToMove = shortDays.shift();
|
|
1004
|
+
if (dayToMove)
|
|
1005
|
+
days.push(dayToMove);
|
|
1006
|
+
if (shortDayToMove)
|
|
1007
|
+
shortDays.push(shortDayToMove);
|
|
1008
|
+
}
|
|
1009
|
+
return { days, shortDays };
|
|
1010
|
+
}, [firstDayOfWeek, currentLocale]);
|
|
1011
|
+
return /* @__PURE__ */ jsx_dev_runtime28.jsxDEV("div", {
|
|
1012
|
+
className: cn("grid grid-cols-7 border-b bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
|
|
1013
|
+
"data-testid": "month-header",
|
|
1014
|
+
children: weekDays.days.map((weekDay, index) => /* @__PURE__ */ jsx_dev_runtime28.jsxDEV(import_react7.AnimatePresence, {
|
|
1015
|
+
mode: "wait",
|
|
1016
|
+
children: /* @__PURE__ */ jsx_dev_runtime28.jsxDEV(import_react7.motion.div, {
|
|
1017
|
+
initial: { opacity: 0, y: -10 },
|
|
1018
|
+
animate: { opacity: 1, y: 0 },
|
|
1019
|
+
exit: { opacity: 0, y: -10 },
|
|
1020
|
+
transition: {
|
|
1021
|
+
duration: 0.25,
|
|
1022
|
+
ease: "easeInOut",
|
|
1023
|
+
delay: index * 0.05
|
|
1024
|
+
},
|
|
1025
|
+
className: "py-2 text-center font-medium border-r first:border-l",
|
|
1026
|
+
"data-testid": `weekday-header-${weekDay}`,
|
|
1027
|
+
children: [
|
|
1028
|
+
/* @__PURE__ */ jsx_dev_runtime28.jsxDEV("span", {
|
|
1029
|
+
className: "hidden text-sm sm:inline",
|
|
1030
|
+
children: weekDay
|
|
1031
|
+
}, undefined, false, undefined, this),
|
|
1032
|
+
/* @__PURE__ */ jsx_dev_runtime28.jsxDEV("span", {
|
|
1033
|
+
className: "text-xs sm:hidden",
|
|
1034
|
+
children: weekDays.shortDays[index]
|
|
1035
|
+
}, undefined, false, undefined, this)
|
|
1036
|
+
]
|
|
1037
|
+
}, weekDay, true, undefined, this)
|
|
1038
|
+
}, weekDay, false, undefined, this))
|
|
1039
|
+
}, undefined, false, undefined, this);
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
// src/lib/constants.ts
|
|
1043
|
+
var GAP_BETWEEN_ELEMENTS = 1;
|
|
1044
|
+
var DAY_NUMBER_HEIGHT = 24;
|
|
1045
|
+
var EVENT_BAR_HEIGHT = 24;
|
|
1046
|
+
|
|
1047
|
+
// src/features/month-view/components/week-events-layer.tsx
|
|
1048
|
+
var jsx_dev_runtime29 = require("react/jsx-dev-runtime");
|
|
1049
|
+
var WeekEventsLayer = ({ days }) => {
|
|
1050
|
+
const { events, dayMaxEvents } = useCalendarContext();
|
|
1051
|
+
const weekStart = days[0];
|
|
1052
|
+
const weekEnd = days[6];
|
|
1053
|
+
const weekEvents = events.filter((e) => {
|
|
1054
|
+
const startsInWeek = e.start.isSameOrAfter(weekStart.startOf("day")) && e.start.isSameOrBefore(weekEnd.endOf("day"));
|
|
1055
|
+
const endsInWeek = e.end.isSameOrAfter(weekStart.startOf("day")) && e.end.isSameOrBefore(weekEnd.endOf("day"));
|
|
1056
|
+
const spansWeek = e.start.isBefore(weekStart.startOf("day")) && e.end.isAfter(weekEnd.endOf("day"));
|
|
1057
|
+
return startsInWeek || endsInWeek || spansWeek;
|
|
1058
|
+
});
|
|
1059
|
+
const multiDayEvents = weekEvents.filter((e) => e.end.diff(e.start, "day") > 0);
|
|
1060
|
+
const singleDayEvents = weekEvents.filter((e) => e.end.diff(e.start, "day") === 0);
|
|
1061
|
+
const sortedMultiDay = [...multiDayEvents].sort((a, b) => {
|
|
1062
|
+
const startDiff = a.start.diff(b.start);
|
|
1063
|
+
if (startDiff !== 0)
|
|
1064
|
+
return startDiff;
|
|
1065
|
+
return b.end.diff(b.start) - a.end.diff(a.start);
|
|
1066
|
+
});
|
|
1067
|
+
const sortedSingleDay = [...singleDayEvents].sort((a, b) => a.start.diff(b.start));
|
|
1068
|
+
const grid = [];
|
|
1069
|
+
for (let row = 0;row < dayMaxEvents; row++) {
|
|
1070
|
+
grid[row] = [];
|
|
1071
|
+
for (let col = 0;col < 7; col++) {
|
|
1072
|
+
grid[row][col] = { taken: false, event: null };
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
const eventPositions = [];
|
|
1076
|
+
for (const event of sortedMultiDay) {
|
|
1077
|
+
const eventStart = dayjs_config_default.max(event.start.startOf("day"), weekStart);
|
|
1078
|
+
const eventEnd = dayjs_config_default.min(event.end.startOf("day"), weekEnd);
|
|
1079
|
+
const startCol = Math.max(0, eventStart.diff(weekStart, "day"));
|
|
1080
|
+
const endCol = Math.min(6, eventEnd.diff(weekStart, "day"));
|
|
1081
|
+
let placedSuccessfully = false;
|
|
1082
|
+
let assignedRow = -1;
|
|
1083
|
+
for (let row = 0;row < dayMaxEvents; row++) {
|
|
1084
|
+
let canPlace = true;
|
|
1085
|
+
for (let col = startCol;col <= endCol; col++) {
|
|
1086
|
+
if (grid[row][col].taken) {
|
|
1087
|
+
canPlace = false;
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (canPlace) {
|
|
1092
|
+
assignedRow = row;
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (assignedRow !== -1) {
|
|
1097
|
+
for (let col = startCol;col <= endCol; col++) {
|
|
1098
|
+
grid[assignedRow][col] = { taken: true, event };
|
|
1099
|
+
}
|
|
1100
|
+
const spanDays = endCol - startCol + 1;
|
|
1101
|
+
eventPositions.push({
|
|
1102
|
+
left: startCol / 7 * 100,
|
|
1103
|
+
width: spanDays / 7 * 100,
|
|
1104
|
+
top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + assignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
|
|
1105
|
+
height: EVENT_BAR_HEIGHT,
|
|
1106
|
+
position: assignedRow,
|
|
1107
|
+
...event
|
|
1108
|
+
});
|
|
1109
|
+
placedSuccessfully = true;
|
|
1110
|
+
}
|
|
1111
|
+
if (!placedSuccessfully) {
|
|
1112
|
+
for (let tryStartCol = startCol + 1;tryStartCol <= endCol; tryStartCol++) {
|
|
1113
|
+
let truncatedAssignedRow = -1;
|
|
1114
|
+
for (let row = 0;row < dayMaxEvents; row++) {
|
|
1115
|
+
let canPlace = true;
|
|
1116
|
+
for (let col = tryStartCol;col <= endCol; col++) {
|
|
1117
|
+
if (grid[row][col].taken) {
|
|
1118
|
+
canPlace = false;
|
|
1119
|
+
break;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (canPlace) {
|
|
1123
|
+
truncatedAssignedRow = row;
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
if (truncatedAssignedRow !== -1) {
|
|
1128
|
+
for (let col = tryStartCol;col <= endCol; col++) {
|
|
1129
|
+
grid[truncatedAssignedRow][col] = { taken: true, event };
|
|
1130
|
+
}
|
|
1131
|
+
const truncatedSpanDays = endCol - tryStartCol + 1;
|
|
1132
|
+
eventPositions.push({
|
|
1133
|
+
left: tryStartCol / 7 * 100,
|
|
1134
|
+
width: truncatedSpanDays / 7 * 100,
|
|
1135
|
+
top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + truncatedAssignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
|
|
1136
|
+
height: EVENT_BAR_HEIGHT,
|
|
1137
|
+
position: truncatedAssignedRow,
|
|
1138
|
+
...event
|
|
1139
|
+
});
|
|
1140
|
+
placedSuccessfully = true;
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
for (const event of sortedSingleDay) {
|
|
1147
|
+
const eventStart = dayjs_config_default.max(event.start.startOf("day"), weekStart);
|
|
1148
|
+
const col = Math.max(0, eventStart.diff(weekStart, "day"));
|
|
1149
|
+
let assignedRow = -1;
|
|
1150
|
+
for (let row = 0;row < dayMaxEvents; row++) {
|
|
1151
|
+
if (!grid[row][col].taken) {
|
|
1152
|
+
assignedRow = row;
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
if (assignedRow !== -1) {
|
|
1157
|
+
grid[assignedRow][col] = { taken: true, event };
|
|
1158
|
+
eventPositions.push({
|
|
1159
|
+
left: col / 7 * 100,
|
|
1160
|
+
width: 1 / 7 * 100,
|
|
1161
|
+
top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + assignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
|
|
1162
|
+
height: EVENT_BAR_HEIGHT,
|
|
1163
|
+
position: assignedRow,
|
|
1164
|
+
...event
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return /* @__PURE__ */ jsx_dev_runtime29.jsxDEV("div", {
|
|
1169
|
+
className: "relative w-full h-full pointer-events-none z-20 overflow-clip",
|
|
1170
|
+
children: eventPositions.map((event) => {
|
|
1171
|
+
return /* @__PURE__ */ jsx_dev_runtime29.jsxDEV("div", {
|
|
1172
|
+
className: "absolute z-10 pointer-events-auto overflow-clip",
|
|
1173
|
+
style: {
|
|
1174
|
+
left: `calc(${event.left}% + var(--spacing) * 0.25)`,
|
|
1175
|
+
width: `calc(${event.width}% - var(--spacing) * 1)`,
|
|
1176
|
+
top: `${event.top}px`,
|
|
1177
|
+
height: `${EVENT_BAR_HEIGHT}px`
|
|
1178
|
+
},
|
|
1179
|
+
children: /* @__PURE__ */ jsx_dev_runtime29.jsxDEV(DraggableEvent, {
|
|
1180
|
+
elementId: `event-${event.id}-${event.position}-${weekStart.format("YYYY-MM-DD")}`,
|
|
1181
|
+
event,
|
|
1182
|
+
className: "h-full w-full shadow"
|
|
1183
|
+
}, undefined, false, undefined, this)
|
|
1184
|
+
}, `event-${event.id}-${event.position}-${weekStart.format("YYYY-MM-DD")}`, false, undefined, this);
|
|
1185
|
+
})
|
|
1186
|
+
}, undefined, false, undefined, this);
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
// src/features/month-view/components/month-view.tsx
|
|
1190
|
+
var jsx_dev_runtime30 = require("react/jsx-dev-runtime");
|
|
1191
|
+
var MonthView = ({ dayMaxEvents = 3 }) => {
|
|
1192
|
+
const allEventsDialogRef = import_react10.default.useRef(null);
|
|
1193
|
+
const { currentDate, firstDayOfWeek } = useCalendarContext();
|
|
1194
|
+
const firstDayOfMonth = currentDate.startOf("month");
|
|
1195
|
+
let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
|
|
1196
|
+
while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
|
|
1197
|
+
adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
|
|
1198
|
+
}
|
|
1199
|
+
const calendarDays = import_react10.useMemo(() => {
|
|
1200
|
+
const days = [[]];
|
|
1201
|
+
let day = adjustedFirstDayOfCalendar.clone();
|
|
1202
|
+
for (let i = 0;i < 42; i++) {
|
|
1203
|
+
if (days[days.length - 1].length === 7) {
|
|
1204
|
+
days.push([]);
|
|
1205
|
+
}
|
|
1206
|
+
days[days.length - 1].push(day);
|
|
1207
|
+
day = day.add(1, "day");
|
|
1208
|
+
}
|
|
1209
|
+
return days;
|
|
1210
|
+
}, [adjustedFirstDayOfCalendar]);
|
|
1211
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV("div", {
|
|
1212
|
+
className: "flex h-full flex-col",
|
|
1213
|
+
"data-testid": "month-view",
|
|
1214
|
+
children: [
|
|
1215
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(MonthHeader, {}, undefined, false, undefined, this),
|
|
1216
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(ScrollArea, {
|
|
1217
|
+
className: "flex-1 overflow-auto",
|
|
1218
|
+
"data-testid": "month-scroll-area",
|
|
1219
|
+
children: /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(import_react9.AnimatePresence, {
|
|
1220
|
+
mode: "wait",
|
|
1221
|
+
children: /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(import_react9.motion.div, {
|
|
1222
|
+
initial: { opacity: 0 },
|
|
1223
|
+
animate: { opacity: 1 },
|
|
1224
|
+
exit: { opacity: 0 },
|
|
1225
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
1226
|
+
className: "relative grid flex-1 grid-cols-7 grid-rows-6 overflow-auto",
|
|
1227
|
+
"data-testid": "month-calendar-grid",
|
|
1228
|
+
children: calendarDays.map((days, index) => {
|
|
1229
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV("div", {
|
|
1230
|
+
className: "relative col-span-7 grid grid-cols-7",
|
|
1231
|
+
"data-testid": `week-row-${index}`,
|
|
1232
|
+
children: [
|
|
1233
|
+
days.map((day, dayIndex) => {
|
|
1234
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(DayCell, {
|
|
1235
|
+
index: dayIndex,
|
|
1236
|
+
day,
|
|
1237
|
+
dayMaxEvents,
|
|
1238
|
+
className: "border-r border-b first:border-l"
|
|
1239
|
+
}, day.format("YYYY-MM-DD"), false, undefined, this);
|
|
1240
|
+
}),
|
|
1241
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV("div", {
|
|
1242
|
+
className: "absolute inset-0 z-10 pointer-events-none",
|
|
1243
|
+
children: /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(WeekEventsLayer, {
|
|
1244
|
+
days
|
|
1245
|
+
}, undefined, false, undefined, this)
|
|
1246
|
+
}, undefined, false, undefined, this)
|
|
1247
|
+
]
|
|
1248
|
+
}, `week-${index}`, true, undefined, this);
|
|
1249
|
+
})
|
|
1250
|
+
}, currentDate.format("YYYY-MM-DD"), false, undefined, this)
|
|
1251
|
+
}, undefined, false, undefined, this)
|
|
1252
|
+
}, undefined, false, undefined, this),
|
|
1253
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(AllEventDialog, {
|
|
1254
|
+
ref: allEventsDialogRef
|
|
1255
|
+
}, undefined, false, undefined, this)
|
|
1256
|
+
]
|
|
1257
|
+
}, undefined, true, undefined, this);
|
|
1258
|
+
};
|
|
1259
|
+
|
|
1260
|
+
// src/features/week-view/week-view.tsx
|
|
1261
|
+
var import_dayjs9 = __toESM(require("dayjs"));
|
|
1262
|
+
var import_weekOfYear2 = __toESM(require("dayjs/plugin/weekOfYear"));
|
|
1263
|
+
|
|
1264
|
+
// src/features/week-view/week-all-day-row.tsx
|
|
1265
|
+
var import_react11 = require("react");
|
|
1266
|
+
var jsx_dev_runtime31 = require("react/jsx-dev-runtime");
|
|
1267
|
+
var WeekAllDayRow = () => {
|
|
1268
|
+
const { currentDate, getEventsForDateRange, firstDayOfWeek } = useCalendarContext();
|
|
1269
|
+
const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
|
|
1270
|
+
const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
|
|
1271
|
+
const endOfWeek = adjustedStartOfWeek.add(6, "day");
|
|
1272
|
+
const weekDays = [];
|
|
1273
|
+
for (let i = 0;i < 7; i++) {
|
|
1274
|
+
weekDays.push(adjustedStartOfWeek.add(i, "day"));
|
|
1275
|
+
}
|
|
1276
|
+
const expandedStartDate = adjustedStartOfWeek.subtract(6, "day");
|
|
1277
|
+
const expandedEndDate = endOfWeek.add(6, "day");
|
|
1278
|
+
const allEvents = getEventsForDateRange(expandedStartDate, expandedEndDate);
|
|
1279
|
+
const weekEvents = allEvents.filter((event) => {
|
|
1280
|
+
return event.start.isSameOrAfter(adjustedStartOfWeek) && event.start.isSameOrBefore(endOfWeek) || event.end.isSameOrAfter(adjustedStartOfWeek) && event.end.isSameOrBefore(endOfWeek) || event.start.isBefore(adjustedStartOfWeek) && event.end.isAfter(endOfWeek);
|
|
1281
|
+
});
|
|
1282
|
+
const allDayEvents = weekEvents.filter((event) => event.all_day);
|
|
1283
|
+
const { processedAllDayEvents } = import_react11.useMemo(() => {
|
|
1284
|
+
const sortedEvents = [...allDayEvents].sort((a, b) => {
|
|
1285
|
+
const startDiff = a.start.diff(b.start);
|
|
1286
|
+
if (startDiff !== 0)
|
|
1287
|
+
return startDiff;
|
|
1288
|
+
const aDuration = a.end.diff(a.start);
|
|
1289
|
+
const bDuration = b.end.diff(b.start);
|
|
1290
|
+
return bDuration - aDuration;
|
|
1291
|
+
});
|
|
1292
|
+
const rows = [];
|
|
1293
|
+
const processedEvents = [];
|
|
1294
|
+
sortedEvents.forEach((event) => {
|
|
1295
|
+
const eventStart = event.start.isBefore(adjustedStartOfWeek) ? adjustedStartOfWeek : event.start;
|
|
1296
|
+
const eventEnd = event.end.isAfter(endOfWeek) ? endOfWeek : event.end;
|
|
1297
|
+
const startDayIndex = Math.max(0, eventStart.diff(adjustedStartOfWeek, "day"));
|
|
1298
|
+
const endDayIndex = Math.min(6, eventEnd.diff(adjustedStartOfWeek, "day"));
|
|
1299
|
+
const left = startDayIndex / 7 * 100;
|
|
1300
|
+
const width = (endDayIndex - startDayIndex + 1) / 7 * 100;
|
|
1301
|
+
let rowIndex = 0;
|
|
1302
|
+
let placed = false;
|
|
1303
|
+
while (!placed) {
|
|
1304
|
+
if (rowIndex >= rows.length) {
|
|
1305
|
+
rows.push([]);
|
|
1306
|
+
placed = true;
|
|
1307
|
+
} else {
|
|
1308
|
+
const row = rows[rowIndex];
|
|
1309
|
+
const canFit = row.every((item) => {
|
|
1310
|
+
return eventStart.isAfter(item.end) || eventEnd.isBefore(item.event.start);
|
|
1311
|
+
});
|
|
1312
|
+
if (canFit) {
|
|
1313
|
+
placed = true;
|
|
1314
|
+
} else {
|
|
1315
|
+
rowIndex++;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
rows[rowIndex].push({ end: eventEnd, event });
|
|
1320
|
+
processedEvents.push({
|
|
1321
|
+
...event,
|
|
1322
|
+
left,
|
|
1323
|
+
width,
|
|
1324
|
+
top: rowIndex * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
|
|
1325
|
+
height: EVENT_BAR_HEIGHT,
|
|
1326
|
+
all_day: true
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
return {
|
|
1330
|
+
processedAllDayEvents: processedEvents,
|
|
1331
|
+
allDayRowsCount: Math.max(1, rows.length)
|
|
1332
|
+
};
|
|
1333
|
+
}, [allDayEvents, adjustedStartOfWeek, endOfWeek]);
|
|
1334
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV("div", {
|
|
1335
|
+
className: "grid grid-cols-[auto_1fr_1fr_1fr_1fr_1fr_1fr_1fr] grid-rows-1 relative",
|
|
1336
|
+
"data-testid": "week-all-day-row",
|
|
1337
|
+
children: [
|
|
1338
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV("div", {
|
|
1339
|
+
className: "w-14 flex shrink-0 items-center justify-end border-x border-b pr-2 min-h-16",
|
|
1340
|
+
children: /* @__PURE__ */ jsx_dev_runtime31.jsxDEV("span", {
|
|
1341
|
+
className: "text-muted-foreground text-[10px] whitespace-nowrap sm:text-xs",
|
|
1342
|
+
children: "All-day"
|
|
1343
|
+
}, undefined, false, undefined, this)
|
|
1344
|
+
}, undefined, false, undefined, this),
|
|
1345
|
+
weekDays.map((day) => /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(DroppableCell, {
|
|
1346
|
+
id: `all-day-cell-${day.format("YYYY-MM-DD")}`,
|
|
1347
|
+
type: "day-cell",
|
|
1348
|
+
date: day,
|
|
1349
|
+
className: "hover:bg-accent h-full flex-1 cursor-pointer border-r border-b"
|
|
1350
|
+
}, `all-day-${day.format("YYYY-MM-DD")}`, false, undefined, this)),
|
|
1351
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV("div", {
|
|
1352
|
+
className: "absolute inset-0 z-10 p-1 col-span-7 col-start-2",
|
|
1353
|
+
children: processedAllDayEvents.map((event, index) => /* @__PURE__ */ jsx_dev_runtime31.jsxDEV("div", {
|
|
1354
|
+
className: "absolute",
|
|
1355
|
+
style: {
|
|
1356
|
+
left: `${event.left}%`,
|
|
1357
|
+
width: `calc(${event.width}% - var(--spacing) * 2)`,
|
|
1358
|
+
top: `${event.top}px`,
|
|
1359
|
+
height: `${event.height}px`
|
|
1360
|
+
},
|
|
1361
|
+
children: /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(DraggableEvent, {
|
|
1362
|
+
elementId: `all-day-${event.id}-${index}`,
|
|
1363
|
+
event,
|
|
1364
|
+
className: "h-full w-full overflow-clip text-xs absolute"
|
|
1365
|
+
}, `all-day-${event.id}-${index}`, false, undefined, this)
|
|
1366
|
+
}, `all-day-container-${event.id}`, false, undefined, this))
|
|
1367
|
+
}, undefined, false, undefined, this)
|
|
1368
|
+
]
|
|
1369
|
+
}, undefined, true, undefined, this);
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
// src/features/week-view/week-header.tsx
|
|
1373
|
+
var import_dayjs5 = __toESM(require("dayjs"));
|
|
1374
|
+
var import_react12 = require("motion/react");
|
|
1375
|
+
var jsx_dev_runtime32 = require("react/jsx-dev-runtime");
|
|
1376
|
+
var WeekHeader = () => {
|
|
1377
|
+
const {
|
|
1378
|
+
currentDate,
|
|
1379
|
+
selectDate,
|
|
1380
|
+
openEventForm,
|
|
1381
|
+
firstDayOfWeek,
|
|
1382
|
+
stickyHeader
|
|
1383
|
+
} = useCalendarContext();
|
|
1384
|
+
const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
|
|
1385
|
+
const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
|
|
1386
|
+
const weekDays = [];
|
|
1387
|
+
for (let i = 0;i < 7; i++) {
|
|
1388
|
+
weekDays.push(adjustedStartOfWeek.add(i, "day"));
|
|
1389
|
+
}
|
|
1390
|
+
return /* @__PURE__ */ jsx_dev_runtime32.jsxDEV("div", {
|
|
1391
|
+
className: cn("grid grid-cols-[auto_1fr_1fr_1fr_1fr_1fr_1fr_1fr] grid-rows-1 bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
|
|
1392
|
+
"data-testid": "week-header",
|
|
1393
|
+
children: [
|
|
1394
|
+
/* @__PURE__ */ jsx_dev_runtime32.jsxDEV("div", {
|
|
1395
|
+
className: "col-span-1 w-14 shrink-0 items-center justify-center border-x border-b p-2",
|
|
1396
|
+
children: /* @__PURE__ */ jsx_dev_runtime32.jsxDEV("div", {
|
|
1397
|
+
className: "flex flex-col items-center justify-center",
|
|
1398
|
+
children: [
|
|
1399
|
+
/* @__PURE__ */ jsx_dev_runtime32.jsxDEV("span", {
|
|
1400
|
+
className: "text-muted-foreground text-xs",
|
|
1401
|
+
children: "Week"
|
|
1402
|
+
}, undefined, false, undefined, this),
|
|
1403
|
+
/* @__PURE__ */ jsx_dev_runtime32.jsxDEV("span", {
|
|
1404
|
+
className: "font-medium",
|
|
1405
|
+
children: currentDate.week()
|
|
1406
|
+
}, undefined, false, undefined, this)
|
|
1407
|
+
]
|
|
1408
|
+
}, undefined, true, undefined, this)
|
|
1409
|
+
}, undefined, false, undefined, this),
|
|
1410
|
+
weekDays.map((day, index) => {
|
|
1411
|
+
const isToday = day.isSame(import_dayjs5.default(), "day");
|
|
1412
|
+
return /* @__PURE__ */ jsx_dev_runtime32.jsxDEV(import_react12.AnimatePresence, {
|
|
1413
|
+
mode: "wait",
|
|
1414
|
+
children: /* @__PURE__ */ jsx_dev_runtime32.jsxDEV(import_react12.motion.div, {
|
|
1415
|
+
initial: { opacity: 0, y: -10 },
|
|
1416
|
+
animate: { opacity: 1, y: 0 },
|
|
1417
|
+
exit: { opacity: 0, y: -10 },
|
|
1418
|
+
transition: {
|
|
1419
|
+
duration: 0.25,
|
|
1420
|
+
ease: "easeInOut",
|
|
1421
|
+
delay: index * 0.05
|
|
1422
|
+
},
|
|
1423
|
+
className: cn("hover:bg-accent flex-1 cursor-pointer p-1 text-center sm:p-2 border-r border-b", isToday && "bg-primary/10 font-bold"),
|
|
1424
|
+
onClick: () => {
|
|
1425
|
+
selectDate(day);
|
|
1426
|
+
openEventForm(day);
|
|
1427
|
+
},
|
|
1428
|
+
"data-testid": `week-day-header-${day.format("dddd").toLowerCase()}`,
|
|
1429
|
+
children: [
|
|
1430
|
+
/* @__PURE__ */ jsx_dev_runtime32.jsxDEV("div", {
|
|
1431
|
+
className: "text-xs sm:text-sm",
|
|
1432
|
+
children: day.format("ddd")
|
|
1433
|
+
}, undefined, false, undefined, this),
|
|
1434
|
+
/* @__PURE__ */ jsx_dev_runtime32.jsxDEV("div", {
|
|
1435
|
+
className: cn("mx-auto mt-1 flex h-5 w-5 items-center justify-center rounded-full text-xs sm:h-7 sm:w-7 sm:text-sm", isToday && "bg-primary text-primary-foreground"),
|
|
1436
|
+
children: day.date()
|
|
1437
|
+
}, undefined, false, undefined, this)
|
|
1438
|
+
]
|
|
1439
|
+
}, day.format("YYYY-MM-DD"), true, undefined, this)
|
|
1440
|
+
}, day.format("YYYY-MM-DD"), false, undefined, this);
|
|
1441
|
+
})
|
|
1442
|
+
]
|
|
1443
|
+
}, undefined, true, undefined, this);
|
|
1444
|
+
};
|
|
1445
|
+
|
|
1446
|
+
// src/features/week-view/week-time-grid.tsx
|
|
1447
|
+
var import_dayjs8 = __toESM(require("dayjs"));
|
|
1448
|
+
|
|
1449
|
+
// src/features/week-view/week-day-col.tsx
|
|
1450
|
+
var import_dayjs7 = __toESM(require("dayjs"));
|
|
1451
|
+
|
|
1452
|
+
// src/hooks/useProcessedDayEvents.ts
|
|
1453
|
+
var import_dayjs6 = __toESM(require("dayjs"));
|
|
1454
|
+
var import_react13 = require("react");
|
|
1455
|
+
var useProcessedDayEvents = ({ day }) => {
|
|
1456
|
+
const { getEventsForDateRange } = useCalendarContext();
|
|
1457
|
+
const todayEvents = import_react13.useMemo(() => {
|
|
1458
|
+
let eventsForDay = getEventsForDateRange(day.startOf("day"), day.endOf("day"));
|
|
1459
|
+
eventsForDay = eventsForDay.filter((e) => !e.all_day).toSorted((a, b) => a.start.diff(b.start));
|
|
1460
|
+
if (eventsForDay.length === 0) {
|
|
1461
|
+
return [];
|
|
1462
|
+
}
|
|
1463
|
+
const clusters = [];
|
|
1464
|
+
let currentCluster = [];
|
|
1465
|
+
let lastEventEnd = null;
|
|
1466
|
+
for (const event of eventsForDay) {
|
|
1467
|
+
if (lastEventEnd && event.start.isSameOrAfter(lastEventEnd)) {
|
|
1468
|
+
if (currentCluster.length > 0) {
|
|
1469
|
+
clusters.push(currentCluster);
|
|
1470
|
+
}
|
|
1471
|
+
currentCluster = [];
|
|
1472
|
+
}
|
|
1473
|
+
currentCluster.push(event);
|
|
1474
|
+
lastEventEnd = lastEventEnd ? import_dayjs6.default.max(lastEventEnd, event.end) : event.end;
|
|
1475
|
+
}
|
|
1476
|
+
if (currentCluster.length > 0) {
|
|
1477
|
+
clusters.push(currentCluster);
|
|
1478
|
+
}
|
|
1479
|
+
const processedEvents = [];
|
|
1480
|
+
for (const cluster of clusters) {
|
|
1481
|
+
if (cluster.length === 1) {
|
|
1482
|
+
const event = cluster[0];
|
|
1483
|
+
const startTime = event.start.hour() + event.start.minute() / 60;
|
|
1484
|
+
let endTime = event.end.hour() + event.end.minute() / 60;
|
|
1485
|
+
if (endTime < startTime) {
|
|
1486
|
+
endTime = 24;
|
|
1487
|
+
}
|
|
1488
|
+
const totalDuration = endTime - startTime;
|
|
1489
|
+
const top = startTime / 24 * 100;
|
|
1490
|
+
const height = totalDuration / 24 * 100;
|
|
1491
|
+
processedEvents.push({ ...event, left: 0, width: 100, top, height });
|
|
1492
|
+
continue;
|
|
1493
|
+
}
|
|
1494
|
+
const sortedEvents = [...cluster].sort((a, b) => {
|
|
1495
|
+
const aDuration = a.end.diff(a.start, "minute");
|
|
1496
|
+
const bDuration = b.end.diff(b.start, "minute");
|
|
1497
|
+
if (aDuration !== bDuration) {
|
|
1498
|
+
return bDuration - aDuration;
|
|
1499
|
+
}
|
|
1500
|
+
return a.start.diff(b.start);
|
|
1501
|
+
});
|
|
1502
|
+
const totalEvents = sortedEvents.length;
|
|
1503
|
+
let maxOffset;
|
|
1504
|
+
if (totalEvents === 2) {
|
|
1505
|
+
maxOffset = 25;
|
|
1506
|
+
} else if (totalEvents === 3) {
|
|
1507
|
+
maxOffset = 50;
|
|
1508
|
+
} else if (totalEvents === 4) {
|
|
1509
|
+
maxOffset = 60;
|
|
1510
|
+
} else {
|
|
1511
|
+
maxOffset = 70;
|
|
1512
|
+
}
|
|
1513
|
+
const offsetPerEvent = totalEvents > 1 ? maxOffset / (totalEvents - 1) : 0;
|
|
1514
|
+
for (let i = 0;i < sortedEvents.length; i++) {
|
|
1515
|
+
const event = sortedEvents[i];
|
|
1516
|
+
const startTime = event.start.hour() + event.start.minute() / 60;
|
|
1517
|
+
let endTime = event.end.hour() + event.end.minute() / 60;
|
|
1518
|
+
if (endTime < startTime) {
|
|
1519
|
+
endTime = 24;
|
|
1520
|
+
}
|
|
1521
|
+
const totalDuration = endTime - startTime;
|
|
1522
|
+
const top = startTime / 24 * 100;
|
|
1523
|
+
const height = totalDuration / 24 * 100;
|
|
1524
|
+
let left;
|
|
1525
|
+
let width;
|
|
1526
|
+
let zIndex;
|
|
1527
|
+
if (i === 0) {
|
|
1528
|
+
left = 0;
|
|
1529
|
+
width = 100;
|
|
1530
|
+
zIndex = 1;
|
|
1531
|
+
} else {
|
|
1532
|
+
left = offsetPerEvent * i;
|
|
1533
|
+
width = 100 - left;
|
|
1534
|
+
zIndex = i + 1;
|
|
1535
|
+
}
|
|
1536
|
+
processedEvents.push({
|
|
1537
|
+
...event,
|
|
1538
|
+
left,
|
|
1539
|
+
width,
|
|
1540
|
+
top,
|
|
1541
|
+
height,
|
|
1542
|
+
zIndex
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
return processedEvents;
|
|
1547
|
+
}, [day, getEventsForDateRange]);
|
|
1548
|
+
return todayEvents;
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// src/features/day-view/day-events-layer.tsx
|
|
1552
|
+
var jsx_dev_runtime33 = require("react/jsx-dev-runtime");
|
|
1553
|
+
var DayEventsLayer = ({
|
|
1554
|
+
day,
|
|
1555
|
+
"data-testid": dataTestId
|
|
1556
|
+
}) => {
|
|
1557
|
+
const todayEvents = useProcessedDayEvents({ day });
|
|
1558
|
+
return /* @__PURE__ */ jsx_dev_runtime33.jsxDEV("div", {
|
|
1559
|
+
"data-testid": dataTestId,
|
|
1560
|
+
className: "pointer-events-none absolute inset-0 z-30",
|
|
1561
|
+
children: todayEvents.map((event, index) => {
|
|
1562
|
+
const veryVeryUniqueKey = `event-${event.id}-${index}-${day.format("YYYY-MM-DD")}`;
|
|
1563
|
+
const isShortEvent = event.end.diff(event.start, "minute") <= 15;
|
|
1564
|
+
return /* @__PURE__ */ jsx_dev_runtime33.jsxDEV("div", {
|
|
1565
|
+
className: "absolute",
|
|
1566
|
+
style: {
|
|
1567
|
+
left: `${event.left}%`,
|
|
1568
|
+
width: `calc(${event.width}% - var(--spacing) * 2)`,
|
|
1569
|
+
top: `${event.top}%`,
|
|
1570
|
+
height: `${event.height}%`
|
|
1571
|
+
},
|
|
1572
|
+
children: /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(DraggableEvent, {
|
|
1573
|
+
elementId: `draggable-${veryVeryUniqueKey}`,
|
|
1574
|
+
event,
|
|
1575
|
+
className: cn("pointer-events-auto absolute", {
|
|
1576
|
+
"[&_p]:text-[10px] [&_p]:mt-0": isShortEvent
|
|
1577
|
+
})
|
|
1578
|
+
}, undefined, false, undefined, this)
|
|
1579
|
+
}, `container-${veryVeryUniqueKey}`, false, undefined, this);
|
|
1580
|
+
})
|
|
1581
|
+
}, undefined, false, undefined, this);
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
// src/features/week-view/week-day-col.tsx
|
|
1585
|
+
var jsx_dev_runtime34 = require("react/jsx-dev-runtime");
|
|
1586
|
+
var hours = Array.from({ length: 24 }, (_, i) => i).map((hour) => import_dayjs7.default().hour(hour).minute(0));
|
|
1587
|
+
var WeekDayCol = ({ day }) => {
|
|
1588
|
+
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV("div", {
|
|
1589
|
+
"data-testid": `week-day-col-${day.format("YYYY-MM-DD")}`,
|
|
1590
|
+
className: "col-span-1 relative grid grid-rows-24 border-r",
|
|
1591
|
+
children: [
|
|
1592
|
+
hours.map((time) => {
|
|
1593
|
+
const hour = time.hour();
|
|
1594
|
+
const cellDate = day.format("YYYY-MM-DD");
|
|
1595
|
+
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(DroppableCell, {
|
|
1596
|
+
id: `time-cell-${cellDate}-${time.format("HH")}`,
|
|
1597
|
+
type: "time-cell",
|
|
1598
|
+
date: day,
|
|
1599
|
+
hour,
|
|
1600
|
+
"data-testid": `week-time-cell-${cellDate}-${time.format("HH")}`,
|
|
1601
|
+
className: cn("hover:bg-accent relative z-20 h-[60px] cursor-pointer border-b")
|
|
1602
|
+
}, `${cellDate}-${time.format("HH")}`, false, undefined, this);
|
|
1603
|
+
}),
|
|
1604
|
+
/* @__PURE__ */ jsx_dev_runtime34.jsxDEV(DayEventsLayer, {
|
|
1605
|
+
"data-testid": `week-day-events-${day.format("YYYY-MM-DD")}`,
|
|
1606
|
+
day
|
|
1607
|
+
}, undefined, false, undefined, this)
|
|
1608
|
+
]
|
|
1609
|
+
}, undefined, true, undefined, this);
|
|
1610
|
+
};
|
|
1611
|
+
|
|
1612
|
+
// src/features/week-view/week-time-grid.tsx
|
|
1613
|
+
var jsx_dev_runtime35 = require("react/jsx-dev-runtime");
|
|
1614
|
+
var hours2 = Array.from({ length: 24 }, (_, i) => i).map((hour) => import_dayjs8.default().hour(hour).minute(0));
|
|
1615
|
+
var WeekTimeGrid = () => {
|
|
1616
|
+
const { currentDate, firstDayOfWeek } = useCalendarContext();
|
|
1617
|
+
const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
|
|
1618
|
+
const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
|
|
1619
|
+
const weekDays = [];
|
|
1620
|
+
for (let i = 0;i < 7; i++) {
|
|
1621
|
+
weekDays.push(adjustedStartOfWeek.add(i, "day"));
|
|
1622
|
+
}
|
|
1623
|
+
const todayIndex = weekDays.findIndex((day) => day.isSame(import_dayjs8.default(), "day"));
|
|
1624
|
+
const isCurrentWeek = todayIndex !== -1;
|
|
1625
|
+
return /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1626
|
+
"data-testid": "week-time-grid",
|
|
1627
|
+
className: "relative h-full grid grid-cols-[auto_repeat(7,1fr)] grid-rows-[repeat(24,minmax(60px, 1fr))]",
|
|
1628
|
+
children: [
|
|
1629
|
+
/* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1630
|
+
"data-testid": "week-time-labels",
|
|
1631
|
+
className: "z-10 col-span-1 w-14 grid grid-rows-24 border-x",
|
|
1632
|
+
children: hours2.map((time) => /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1633
|
+
"data-testid": `week-time-hour-${time.format("HH")}`,
|
|
1634
|
+
className: "h-[60px] border-b text-right",
|
|
1635
|
+
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("span", {
|
|
1636
|
+
className: "text-muted-foreground pr-2 text-right text-[10px] sm:text-xs",
|
|
1637
|
+
children: time.format("h A")
|
|
1638
|
+
}, undefined, false, undefined, this)
|
|
1639
|
+
}, time.format("HH:mm"), false, undefined, this))
|
|
1640
|
+
}, undefined, false, undefined, this),
|
|
1641
|
+
weekDays.map((day) => /* @__PURE__ */ jsx_dev_runtime35.jsxDEV(WeekDayCol, {
|
|
1642
|
+
day
|
|
1643
|
+
}, day.format("YYYY-MM-DD"), false, undefined, this)),
|
|
1644
|
+
isCurrentWeek && /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1645
|
+
"data-testid": "week-current-time-indicator",
|
|
1646
|
+
className: "pointer-events-none absolute z-20",
|
|
1647
|
+
style: {
|
|
1648
|
+
top: `${(import_dayjs8.default().hour() + import_dayjs8.default().minute() / 60) * 60}px`,
|
|
1649
|
+
left: `${todayIndex * (100 / 7)}%`,
|
|
1650
|
+
width: `${100 / 7}%`
|
|
1651
|
+
},
|
|
1652
|
+
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1653
|
+
className: "w-full border-t border-red-500",
|
|
1654
|
+
children: /* @__PURE__ */ jsx_dev_runtime35.jsxDEV("div", {
|
|
1655
|
+
className: "-mt-1 ml-1 h-2 w-2 rounded-full bg-red-500"
|
|
1656
|
+
}, undefined, false, undefined, this)
|
|
1657
|
+
}, undefined, false, undefined, this)
|
|
1658
|
+
}, undefined, false, undefined, this)
|
|
1659
|
+
]
|
|
1660
|
+
}, undefined, true, undefined, this);
|
|
1661
|
+
};
|
|
1662
|
+
|
|
1663
|
+
// src/features/week-view/week-view.tsx
|
|
1664
|
+
var jsx_dev_runtime36 = require("react/jsx-dev-runtime");
|
|
1665
|
+
import_dayjs9.default.extend(import_weekOfYear2.default);
|
|
1666
|
+
var WeekView = () => {
|
|
1667
|
+
return /* @__PURE__ */ jsx_dev_runtime36.jsxDEV("div", {
|
|
1668
|
+
className: "flex h-full flex-col",
|
|
1669
|
+
"data-testid": "week-view",
|
|
1670
|
+
children: [
|
|
1671
|
+
/* @__PURE__ */ jsx_dev_runtime36.jsxDEV(WeekHeader, {}, undefined, false, undefined, this),
|
|
1672
|
+
/* @__PURE__ */ jsx_dev_runtime36.jsxDEV(ScrollArea, {
|
|
1673
|
+
className: "flex flex-1 overflow-auto",
|
|
1674
|
+
"data-testid": "week-scroll-area",
|
|
1675
|
+
children: [
|
|
1676
|
+
/* @__PURE__ */ jsx_dev_runtime36.jsxDEV(WeekAllDayRow, {}, undefined, false, undefined, this),
|
|
1677
|
+
/* @__PURE__ */ jsx_dev_runtime36.jsxDEV(WeekTimeGrid, {}, undefined, false, undefined, this)
|
|
1678
|
+
]
|
|
1679
|
+
}, undefined, true, undefined, this)
|
|
1680
|
+
]
|
|
1681
|
+
}, undefined, true, undefined, this);
|
|
1682
|
+
};
|
|
1683
|
+
var week_view_default = WeekView;
|
|
1684
|
+
|
|
1685
|
+
// src/features/day-view/day-view.tsx
|
|
1686
|
+
var import_dayjs12 = __toESM(require("dayjs"));
|
|
1687
|
+
var import_react16 = require("react");
|
|
1688
|
+
|
|
1689
|
+
// src/features/day-view/day-all-day-row.tsx
|
|
1690
|
+
var import_react14 = require("react");
|
|
1691
|
+
var jsx_dev_runtime37 = require("react/jsx-dev-runtime");
|
|
1692
|
+
var DayAllDayRow = () => {
|
|
1693
|
+
const { currentDate, getEventsForDate } = useCalendarContext();
|
|
1694
|
+
const dayEvents = getEventsForDate(currentDate);
|
|
1695
|
+
const { allDayEvents } = import_react14.useMemo(() => {
|
|
1696
|
+
const allDayEvts = dayEvents.filter((event) => event.all_day);
|
|
1697
|
+
const regularEvts = dayEvents.filter((event) => !event.all_day);
|
|
1698
|
+
return { allDayEvents: allDayEvts, regularEvents: regularEvts };
|
|
1699
|
+
}, [dayEvents]);
|
|
1700
|
+
const { processedAllDayEvents } = import_react14.useMemo(() => {
|
|
1701
|
+
const sortedEvents = [...allDayEvents].sort((a, b) => {
|
|
1702
|
+
return a.start.diff(b.start);
|
|
1703
|
+
});
|
|
1704
|
+
const rows = [];
|
|
1705
|
+
const processedEvents = [];
|
|
1706
|
+
sortedEvents.forEach((event, rowIndex) => {
|
|
1707
|
+
let placed = false;
|
|
1708
|
+
while (!placed) {
|
|
1709
|
+
if (rowIndex >= rows.length) {
|
|
1710
|
+
rows.push([]);
|
|
1711
|
+
placed = true;
|
|
1712
|
+
} else {
|
|
1713
|
+
placed = true;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
rows[rowIndex].push({ event });
|
|
1717
|
+
processedEvents.push({
|
|
1718
|
+
...event,
|
|
1719
|
+
left: 0,
|
|
1720
|
+
width: 100,
|
|
1721
|
+
top: rowIndex * EVENT_BAR_HEIGHT,
|
|
1722
|
+
height: EVENT_BAR_HEIGHT,
|
|
1723
|
+
all_day: true
|
|
1724
|
+
});
|
|
1725
|
+
});
|
|
1726
|
+
return {
|
|
1727
|
+
processedAllDayEvents: processedEvents,
|
|
1728
|
+
allDayRowsCount: Math.max(1, rows.length)
|
|
1729
|
+
};
|
|
1730
|
+
}, [allDayEvents]);
|
|
1731
|
+
return /* @__PURE__ */ jsx_dev_runtime37.jsxDEV("div", {
|
|
1732
|
+
"data-testid": "day-all-day-row",
|
|
1733
|
+
className: "grid grid-cols-8 border-b border-x",
|
|
1734
|
+
children: [
|
|
1735
|
+
/* @__PURE__ */ jsx_dev_runtime37.jsxDEV("div", {
|
|
1736
|
+
className: "col-span-2 flex shrink-0 items-center justify-end border-r pr-2 md:col-span-1",
|
|
1737
|
+
children: /* @__PURE__ */ jsx_dev_runtime37.jsxDEV("span", {
|
|
1738
|
+
className: "text-muted-foreground text-[10px] whitespace-nowrap sm:text-xs",
|
|
1739
|
+
children: "All-day"
|
|
1740
|
+
}, undefined, false, undefined, this)
|
|
1741
|
+
}, undefined, false, undefined, this),
|
|
1742
|
+
/* @__PURE__ */ jsx_dev_runtime37.jsxDEV("div", {
|
|
1743
|
+
className: "relative col-span-6 md:col-span-7 ",
|
|
1744
|
+
children: /* @__PURE__ */ jsx_dev_runtime37.jsxDEV(DroppableCell, {
|
|
1745
|
+
id: `all-day-${currentDate.format("YYYY-MM-DD")}`,
|
|
1746
|
+
type: "day-cell",
|
|
1747
|
+
date: currentDate,
|
|
1748
|
+
className: "hover:bg-accent w-full cursor-pointer min-h-10 flex flex-col",
|
|
1749
|
+
children: processedAllDayEvents.map((event, index) => {
|
|
1750
|
+
return /* @__PURE__ */ jsx_dev_runtime37.jsxDEV("div", {
|
|
1751
|
+
style: { height: EVENT_BAR_HEIGHT + "px" },
|
|
1752
|
+
children: /* @__PURE__ */ jsx_dev_runtime37.jsxDEV(DraggableEvent, {
|
|
1753
|
+
elementId: `all-day-${event.id}-${index}`,
|
|
1754
|
+
event,
|
|
1755
|
+
className: "overflow-clip text-xs",
|
|
1756
|
+
style: { width: `calc(100% - var(--spacing) * 2)` }
|
|
1757
|
+
}, undefined, false, undefined, this)
|
|
1758
|
+
}, `all-day-${event.id}-${index}`, false, undefined, this);
|
|
1759
|
+
})
|
|
1760
|
+
}, undefined, false, undefined, this)
|
|
1761
|
+
}, undefined, false, undefined, this)
|
|
1762
|
+
]
|
|
1763
|
+
}, undefined, true, undefined, this);
|
|
1764
|
+
};
|
|
1765
|
+
|
|
1766
|
+
// src/features/day-view/day-header.tsx
|
|
1767
|
+
var import_react15 = require("motion/react");
|
|
1768
|
+
var import_dayjs10 = __toESM(require("dayjs"));
|
|
1769
|
+
var jsx_dev_runtime38 = require("react/jsx-dev-runtime");
|
|
1770
|
+
var DayHeader = () => {
|
|
1771
|
+
const { currentDate, stickyHeader } = useCalendarContext();
|
|
1772
|
+
const isToday = currentDate.isSame(import_dayjs10.default(), "day");
|
|
1773
|
+
return /* @__PURE__ */ jsx_dev_runtime38.jsxDEV("div", {
|
|
1774
|
+
"data-testid": "day-header",
|
|
1775
|
+
className: cn("flex items-center justify-center border-b p-2 border-x bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
|
|
1776
|
+
children: /* @__PURE__ */ jsx_dev_runtime38.jsxDEV(import_react15.AnimatePresence, {
|
|
1777
|
+
mode: "wait",
|
|
1778
|
+
children: /* @__PURE__ */ jsx_dev_runtime38.jsxDEV(import_react15.motion.div, {
|
|
1779
|
+
initial: { opacity: 0, y: -10 },
|
|
1780
|
+
animate: { opacity: 1, y: 0 },
|
|
1781
|
+
exit: { opacity: 0, y: -10 },
|
|
1782
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
1783
|
+
className: cn("flex items-center text-center text-base font-semibold sm:text-xl", isToday && "text-primary"),
|
|
1784
|
+
children: [
|
|
1785
|
+
/* @__PURE__ */ jsx_dev_runtime38.jsxDEV("span", {
|
|
1786
|
+
className: "xs:inline hidden",
|
|
1787
|
+
children: currentDate.format("dddd, ")
|
|
1788
|
+
}, undefined, false, undefined, this),
|
|
1789
|
+
currentDate.format("MMMM D, YYYY"),
|
|
1790
|
+
isToday && /* @__PURE__ */ jsx_dev_runtime38.jsxDEV("span", {
|
|
1791
|
+
className: "bg-primary text-primary-foreground ml-2 rounded-full px-1 py-0.5 text-xs sm:px-2 sm:text-sm",
|
|
1792
|
+
children: "Today"
|
|
1793
|
+
}, undefined, false, undefined, this)
|
|
1794
|
+
]
|
|
1795
|
+
}, currentDate.format("YYYY-MM-DD"), true, undefined, this)
|
|
1796
|
+
}, undefined, false, undefined, this)
|
|
1797
|
+
}, undefined, false, undefined, this);
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
// src/features/day-view/day-time-col.tsx
|
|
1801
|
+
var import_dayjs11 = __toESM(require("dayjs"));
|
|
1802
|
+
var jsx_dev_runtime39 = require("react/jsx-dev-runtime");
|
|
1803
|
+
var hours3 = Array.from({ length: 24 }, (_, i) => i).map((hour) => {
|
|
1804
|
+
return import_dayjs11.default().hour(hour).minute(0);
|
|
1805
|
+
});
|
|
1806
|
+
var DayTimeCol = ({ className }) => {
|
|
1807
|
+
return /* @__PURE__ */ jsx_dev_runtime39.jsxDEV("div", {
|
|
1808
|
+
"data-testid": "day-time-col",
|
|
1809
|
+
className: `col-span-2 h-full md:col-span-1 ${className}`,
|
|
1810
|
+
children: hours3.map((time) => /* @__PURE__ */ jsx_dev_runtime39.jsxDEV("div", {
|
|
1811
|
+
"data-testid": `day-time-hour-${time.format("HH")}`,
|
|
1812
|
+
className: "h-[60px] border-b text-right",
|
|
1813
|
+
children: /* @__PURE__ */ jsx_dev_runtime39.jsxDEV("span", {
|
|
1814
|
+
className: "text-muted-foreground pr-2 text-right text-[10px] sm:text-xs",
|
|
1815
|
+
children: time.format("h A")
|
|
1816
|
+
}, undefined, false, undefined, this)
|
|
1817
|
+
}, time.format("HH:mm"), false, undefined, this))
|
|
1818
|
+
}, undefined, false, undefined, this);
|
|
1819
|
+
};
|
|
1820
|
+
|
|
1821
|
+
// src/features/day-view/day-view.tsx
|
|
1822
|
+
var jsx_dev_runtime40 = require("react/jsx-dev-runtime");
|
|
1823
|
+
var DayView = () => {
|
|
1824
|
+
const { currentDate } = useCalendarContext();
|
|
1825
|
+
const hours4 = Array.from({ length: 24 }, (_, i) => i).map((hour) => {
|
|
1826
|
+
return import_dayjs12.default().hour(hour).minute(0);
|
|
1827
|
+
});
|
|
1828
|
+
const timeSegments = [0, 15, 30, 45];
|
|
1829
|
+
const isToday = currentDate.isSame(import_dayjs12.default(), "day");
|
|
1830
|
+
const cellDate = currentDate.format("YYYY-MM-DD");
|
|
1831
|
+
return /* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1832
|
+
"data-testid": "day-view",
|
|
1833
|
+
className: "flex h-full flex-col",
|
|
1834
|
+
children: [
|
|
1835
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DayHeader, {}, undefined, false, undefined, this),
|
|
1836
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(ScrollArea, {
|
|
1837
|
+
"data-testid": "day-scroll-area",
|
|
1838
|
+
className: "relative flex-1 overflow-y-auto",
|
|
1839
|
+
children: [
|
|
1840
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DayAllDayRow, {}, undefined, false, undefined, this),
|
|
1841
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1842
|
+
"data-testid": "day-time-grid",
|
|
1843
|
+
className: "grid grid-cols-8 divide-x border-x",
|
|
1844
|
+
style: { height: `${hours4.length * 60}px` },
|
|
1845
|
+
children: [
|
|
1846
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DayTimeCol, {
|
|
1847
|
+
className: "col-span-2 h-full md:col-span-1"
|
|
1848
|
+
}, undefined, false, undefined, this),
|
|
1849
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1850
|
+
"data-testid": "day-events-column",
|
|
1851
|
+
className: "relative col-span-6 h-full md:col-span-7",
|
|
1852
|
+
children: [
|
|
1853
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1854
|
+
"data-testid": "day-background-grid",
|
|
1855
|
+
className: "absolute inset-0 z-0",
|
|
1856
|
+
children: hours4.map((hour, index) => /* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1857
|
+
className: "h-[60px] border-b",
|
|
1858
|
+
children: timeSegments.slice(1).map((minutes) => /* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1859
|
+
className: "border-border absolute w-full border-t border-dashed",
|
|
1860
|
+
style: { top: `${index * 60 + minutes}px` }
|
|
1861
|
+
}, `bg-${hour.format("HH")}-${minutes}`, false, undefined, this))
|
|
1862
|
+
}, `bg-${currentDate.format("YYYY-MM-DD")}-${hour.format("HH")}`, false, undefined, this))
|
|
1863
|
+
}, undefined, false, undefined, this),
|
|
1864
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1865
|
+
"data-testid": "day-interactive-layer",
|
|
1866
|
+
className: "pointer-events-auto absolute inset-0 z-20",
|
|
1867
|
+
children: hours4.map((time) => {
|
|
1868
|
+
const hour = time.hour();
|
|
1869
|
+
return /* @__PURE__ */ jsx_dev_runtime40.jsxDEV(import_react16.Fragment, {
|
|
1870
|
+
children: [
|
|
1871
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DroppableCell, {
|
|
1872
|
+
id: `time-cell-${cellDate}-${time.format("HH")}-00`,
|
|
1873
|
+
type: "time-cell",
|
|
1874
|
+
date: currentDate,
|
|
1875
|
+
hour,
|
|
1876
|
+
minute: 0,
|
|
1877
|
+
className: cn("hover:bg-accent h-[15px] cursor-pointer")
|
|
1878
|
+
}, undefined, false, undefined, this),
|
|
1879
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DroppableCell, {
|
|
1880
|
+
id: `time-cell-${cellDate}-${time.format("HH")}-15`,
|
|
1881
|
+
type: "time-cell",
|
|
1882
|
+
date: currentDate,
|
|
1883
|
+
hour,
|
|
1884
|
+
minute: 15,
|
|
1885
|
+
className: "hover:bg-accent h-[15px] cursor-pointer"
|
|
1886
|
+
}, undefined, false, undefined, this),
|
|
1887
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DroppableCell, {
|
|
1888
|
+
id: `time-cell-${cellDate}-${time.format("HH")}-30`,
|
|
1889
|
+
type: "time-cell",
|
|
1890
|
+
date: currentDate,
|
|
1891
|
+
hour,
|
|
1892
|
+
minute: 30,
|
|
1893
|
+
className: "hover:bg-accent h-[15px] cursor-pointer"
|
|
1894
|
+
}, undefined, false, undefined, this),
|
|
1895
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DroppableCell, {
|
|
1896
|
+
id: `time-cell-${cellDate}-${time.format("HH")}-45`,
|
|
1897
|
+
type: "time-cell",
|
|
1898
|
+
date: currentDate,
|
|
1899
|
+
hour,
|
|
1900
|
+
minute: 45,
|
|
1901
|
+
className: "hover:bg-accent h-[15px] cursor-pointer"
|
|
1902
|
+
}, undefined, false, undefined, this)
|
|
1903
|
+
]
|
|
1904
|
+
}, `${cellDate}-${time.format("HH")}`, true, undefined, this);
|
|
1905
|
+
})
|
|
1906
|
+
}, undefined, false, undefined, this),
|
|
1907
|
+
/* @__PURE__ */ jsx_dev_runtime40.jsxDEV(DayEventsLayer, {
|
|
1908
|
+
day: currentDate
|
|
1909
|
+
}, undefined, false, undefined, this),
|
|
1910
|
+
isToday && /* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1911
|
+
"data-testid": "day-current-time-indicator",
|
|
1912
|
+
className: "absolute right-0 left-0 z-40 border-t border-red-500",
|
|
1913
|
+
style: {
|
|
1914
|
+
top: `${(import_dayjs12.default().hour() + import_dayjs12.default().minute() / 60) * 60}px`
|
|
1915
|
+
},
|
|
1916
|
+
children: /* @__PURE__ */ jsx_dev_runtime40.jsxDEV("div", {
|
|
1917
|
+
className: "-mt-1 -ml-1 h-2 w-2 rounded-full bg-red-500"
|
|
1918
|
+
}, undefined, false, undefined, this)
|
|
1919
|
+
}, undefined, false, undefined, this)
|
|
1920
|
+
]
|
|
1921
|
+
}, undefined, true, undefined, this)
|
|
1922
|
+
]
|
|
1923
|
+
}, undefined, true, undefined, this)
|
|
1924
|
+
]
|
|
1925
|
+
}, undefined, true, undefined, this)
|
|
1926
|
+
]
|
|
1927
|
+
}, undefined, true, undefined, this);
|
|
1928
|
+
};
|
|
1929
|
+
var day_view_default = DayView;
|
|
1930
|
+
|
|
1931
|
+
// src/components/event-form/event-form.tsx
|
|
1932
|
+
var import_dayjs13 = __toESM(require("dayjs"));
|
|
1933
|
+
var import_react17 = require("react");
|
|
1934
|
+
var jsx_dev_runtime41 = require("react/jsx-dev-runtime");
|
|
1935
|
+
var colorOptions = [
|
|
1936
|
+
{ value: "bg-blue-100 text-blue-800", label: "Blue" },
|
|
1937
|
+
{ value: "bg-green-100 text-green-800", label: "Green" },
|
|
1938
|
+
{ value: "bg-purple-100 text-purple-800", label: "Purple" },
|
|
1939
|
+
{ value: "bg-red-100 text-red-800", label: "Red" },
|
|
1940
|
+
{ value: "bg-yellow-100 text-yellow-800", label: "Yellow" },
|
|
1941
|
+
{ value: "bg-pink-100 text-pink-800", label: "Pink" },
|
|
1942
|
+
{ value: "bg-indigo-100 text-indigo-800", label: "Indigo" },
|
|
1943
|
+
{ value: "bg-amber-100 text-amber-800", label: "Amber" },
|
|
1944
|
+
{ value: "bg-emerald-100 text-emerald-800", label: "Emerald" },
|
|
1945
|
+
{ value: "bg-sky-100 text-sky-800", label: "Sky" },
|
|
1946
|
+
{ value: "bg-violet-100 text-violet-800", label: "Violet" },
|
|
1947
|
+
{ value: "bg-rose-100 text-rose-800", label: "Rose" },
|
|
1948
|
+
{ value: "bg-teal-100 text-teal-800", label: "Teal" },
|
|
1949
|
+
{ value: "bg-orange-100 text-orange-800", label: "Orange" }
|
|
1950
|
+
];
|
|
1951
|
+
var EventForm = ({
|
|
1952
|
+
selectedEvent,
|
|
1953
|
+
selectedDate,
|
|
1954
|
+
onClose,
|
|
1955
|
+
onUpdate,
|
|
1956
|
+
onDelete,
|
|
1957
|
+
onAdd
|
|
1958
|
+
}) => {
|
|
1959
|
+
const start = selectedEvent?.originalStart ?? selectedEvent?.start;
|
|
1960
|
+
const end = selectedEvent?.originalEnd ?? selectedEvent?.end;
|
|
1961
|
+
const defaultStartDate = selectedDate?.toDate() || new Date;
|
|
1962
|
+
const defaultEndDate = selectedDate?.add(1, "hour").toDate() || import_dayjs13.default().add(1, "hour").toDate();
|
|
1963
|
+
const [startDate, setStartDate] = import_react17.useState(start?.toDate() || defaultStartDate);
|
|
1964
|
+
const [endDate, setEndDate] = import_react17.useState(end?.toDate() || defaultEndDate);
|
|
1965
|
+
const [isAllDay, setIsAllDay] = import_react17.useState(selectedEvent?.all_day || false);
|
|
1966
|
+
const [selectedColor, setSelectedColor] = import_react17.useState(selectedEvent?.color || colorOptions[0].value);
|
|
1967
|
+
const [startTime, setStartTime] = import_react17.useState(selectedEvent ? selectedEvent.start.format("HH:mm") : import_dayjs13.default(defaultStartDate).format("HH:mm"));
|
|
1968
|
+
const [endTime, setEndTime] = import_react17.useState(selectedEvent ? selectedEvent.end.format("HH:mm") : import_dayjs13.default(defaultEndDate).format("HH:mm"));
|
|
1969
|
+
const [formValues, setFormValues] = import_react17.useState({
|
|
1970
|
+
title: selectedEvent?.title || "",
|
|
1971
|
+
description: selectedEvent?.description || "",
|
|
1972
|
+
location: selectedEvent?.location || ""
|
|
1973
|
+
});
|
|
1974
|
+
const handleStartDateChange = (date) => {
|
|
1975
|
+
if (date)
|
|
1976
|
+
setStartDate(date);
|
|
1977
|
+
};
|
|
1978
|
+
const handleEndDateChange = (date) => {
|
|
1979
|
+
if (date)
|
|
1980
|
+
setEndDate(date);
|
|
1981
|
+
};
|
|
1982
|
+
const handleInputChange = (e) => {
|
|
1983
|
+
const { name, value } = e.target;
|
|
1984
|
+
setFormValues((prev) => ({ ...prev, [name]: value }));
|
|
1985
|
+
};
|
|
1986
|
+
const handleTimeChange = (e, isStart) => {
|
|
1987
|
+
const timeValue = e.target.value;
|
|
1988
|
+
if (isStart) {
|
|
1989
|
+
setStartTime(timeValue);
|
|
1990
|
+
} else {
|
|
1991
|
+
setEndTime(timeValue);
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
import_react17.useEffect(() => {
|
|
1995
|
+
if (isAllDay) {
|
|
1996
|
+
setEndTime("23:59");
|
|
1997
|
+
}
|
|
1998
|
+
}, [isAllDay]);
|
|
1999
|
+
const handleSubmit = (e) => {
|
|
2000
|
+
e.preventDefault();
|
|
2001
|
+
const [startHours, startMinutes] = startTime.split(":").map(Number);
|
|
2002
|
+
const [endHours, endMinutes] = endTime.split(":").map(Number);
|
|
2003
|
+
let startDateTime = import_dayjs13.default(startDate).hour(startHours).minute(startMinutes);
|
|
2004
|
+
let endDateTime = import_dayjs13.default(endDate).hour(endHours).minute(endMinutes);
|
|
2005
|
+
if (isAllDay) {
|
|
2006
|
+
startDateTime = startDateTime.hour(0).minute(0);
|
|
2007
|
+
endDateTime = endDateTime.hour(23).minute(59);
|
|
2008
|
+
}
|
|
2009
|
+
const eventData = {
|
|
2010
|
+
id: selectedEvent?.id || import_dayjs13.default().format("YYYYMMDDHHmmss"),
|
|
2011
|
+
title: formValues.title,
|
|
2012
|
+
start: startDateTime,
|
|
2013
|
+
end: endDateTime,
|
|
2014
|
+
description: formValues.description,
|
|
2015
|
+
location: formValues.location,
|
|
2016
|
+
all_day: isAllDay,
|
|
2017
|
+
color: selectedColor
|
|
2018
|
+
};
|
|
2019
|
+
if (selectedEvent.id) {
|
|
2020
|
+
onUpdate?.(eventData);
|
|
2021
|
+
} else {
|
|
2022
|
+
onAdd?.(eventData);
|
|
2023
|
+
}
|
|
2024
|
+
onClose();
|
|
2025
|
+
};
|
|
2026
|
+
const handleDelete = () => {
|
|
2027
|
+
if (selectedEvent.id) {
|
|
2028
|
+
onDelete?.(selectedEvent);
|
|
2029
|
+
onClose();
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
import_react17.useEffect(() => {
|
|
2033
|
+
if (import_dayjs13.default(startDate).isAfter(import_dayjs13.default(endDate))) {
|
|
2034
|
+
setEndDate(startDate);
|
|
2035
|
+
}
|
|
2036
|
+
}, [startDate, endDate]);
|
|
2037
|
+
return /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Dialog, {
|
|
2038
|
+
open: true,
|
|
2039
|
+
onOpenChange: onClose,
|
|
2040
|
+
children: /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DialogContent, {
|
|
2041
|
+
className: "w-[90vw] max-w-[500px] p-4 sm:p-6",
|
|
2042
|
+
children: /* @__PURE__ */ jsx_dev_runtime41.jsxDEV("form", {
|
|
2043
|
+
onSubmit: handleSubmit,
|
|
2044
|
+
children: [
|
|
2045
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DialogHeader, {
|
|
2046
|
+
className: "mb-2 sm:mb-4",
|
|
2047
|
+
children: [
|
|
2048
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DialogTitle, {
|
|
2049
|
+
className: "text-base sm:text-lg",
|
|
2050
|
+
children: selectedEvent.id ? "Edit Event" : "Create Event"
|
|
2051
|
+
}, undefined, false, undefined, this),
|
|
2052
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DialogDescription, {
|
|
2053
|
+
className: "text-xs sm:text-sm",
|
|
2054
|
+
children: selectedEvent.id ? "Edit your event details" : "Add a new event to your calendar"
|
|
2055
|
+
}, undefined, false, undefined, this)
|
|
2056
|
+
]
|
|
2057
|
+
}, undefined, true, undefined, this),
|
|
2058
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2059
|
+
className: "grid gap-3 py-2 sm:gap-4 sm:py-4",
|
|
2060
|
+
children: [
|
|
2061
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2062
|
+
className: "grid gap-2",
|
|
2063
|
+
children: [
|
|
2064
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2065
|
+
htmlFor: "title",
|
|
2066
|
+
className: "text-xs sm:text-sm",
|
|
2067
|
+
children: "Title"
|
|
2068
|
+
}, undefined, false, undefined, this),
|
|
2069
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Input, {
|
|
2070
|
+
id: "title",
|
|
2071
|
+
name: "title",
|
|
2072
|
+
value: formValues.title,
|
|
2073
|
+
onChange: handleInputChange,
|
|
2074
|
+
placeholder: "Event title",
|
|
2075
|
+
required: true,
|
|
2076
|
+
autoFocus: true,
|
|
2077
|
+
className: "h-8 text-sm sm:h-9"
|
|
2078
|
+
}, undefined, false, undefined, this)
|
|
2079
|
+
]
|
|
2080
|
+
}, undefined, true, undefined, this),
|
|
2081
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2082
|
+
className: "flex items-center space-x-2",
|
|
2083
|
+
children: [
|
|
2084
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Checkbox, {
|
|
2085
|
+
id: "all_day",
|
|
2086
|
+
checked: isAllDay,
|
|
2087
|
+
onCheckedChange: (checked) => setIsAllDay(checked === true)
|
|
2088
|
+
}, undefined, false, undefined, this),
|
|
2089
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2090
|
+
htmlFor: "all_day",
|
|
2091
|
+
className: "text-xs sm:text-sm",
|
|
2092
|
+
children: "All day"
|
|
2093
|
+
}, undefined, false, undefined, this)
|
|
2094
|
+
]
|
|
2095
|
+
}, undefined, true, undefined, this),
|
|
2096
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2097
|
+
className: "grid grid-cols-2 gap-2 sm:gap-4",
|
|
2098
|
+
children: [
|
|
2099
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2100
|
+
children: [
|
|
2101
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2102
|
+
className: "text-xs sm:text-sm",
|
|
2103
|
+
children: "Start Date"
|
|
2104
|
+
}, undefined, false, undefined, this),
|
|
2105
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DatePicker, {
|
|
2106
|
+
date: startDate,
|
|
2107
|
+
setDate: handleStartDateChange,
|
|
2108
|
+
className: "mt-1",
|
|
2109
|
+
closeOnSelect: true
|
|
2110
|
+
}, undefined, false, undefined, this)
|
|
2111
|
+
]
|
|
2112
|
+
}, undefined, true, undefined, this),
|
|
2113
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2114
|
+
children: [
|
|
2115
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2116
|
+
className: "text-xs sm:text-sm",
|
|
2117
|
+
children: "End Date"
|
|
2118
|
+
}, undefined, false, undefined, this),
|
|
2119
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DatePicker, {
|
|
2120
|
+
date: endDate,
|
|
2121
|
+
setDate: handleEndDateChange,
|
|
2122
|
+
className: "mt-1",
|
|
2123
|
+
closeOnSelect: true
|
|
2124
|
+
}, undefined, false, undefined, this)
|
|
2125
|
+
]
|
|
2126
|
+
}, undefined, true, undefined, this)
|
|
2127
|
+
]
|
|
2128
|
+
}, undefined, true, undefined, this),
|
|
2129
|
+
!isAllDay && /* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2130
|
+
className: "grid grid-cols-2 gap-2 sm:gap-4",
|
|
2131
|
+
children: [
|
|
2132
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2133
|
+
children: [
|
|
2134
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2135
|
+
htmlFor: "start-time",
|
|
2136
|
+
className: "text-xs sm:text-sm",
|
|
2137
|
+
children: "Start Time"
|
|
2138
|
+
}, undefined, false, undefined, this),
|
|
2139
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Input, {
|
|
2140
|
+
id: "start-time",
|
|
2141
|
+
type: "time",
|
|
2142
|
+
value: startTime,
|
|
2143
|
+
onChange: (e) => handleTimeChange(e, true),
|
|
2144
|
+
className: "mt-1 h-8 text-sm sm:h-9"
|
|
2145
|
+
}, undefined, false, undefined, this)
|
|
2146
|
+
]
|
|
2147
|
+
}, undefined, true, undefined, this),
|
|
2148
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2149
|
+
children: [
|
|
2150
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2151
|
+
htmlFor: "end-time",
|
|
2152
|
+
className: "text-xs sm:text-sm",
|
|
2153
|
+
children: "End Time"
|
|
2154
|
+
}, undefined, false, undefined, this),
|
|
2155
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Input, {
|
|
2156
|
+
id: "end-time",
|
|
2157
|
+
type: "time",
|
|
2158
|
+
value: endTime,
|
|
2159
|
+
onChange: (e) => handleTimeChange(e, false),
|
|
2160
|
+
className: "mt-1 h-8 text-sm sm:h-9"
|
|
2161
|
+
}, undefined, false, undefined, this)
|
|
2162
|
+
]
|
|
2163
|
+
}, undefined, true, undefined, this)
|
|
2164
|
+
]
|
|
2165
|
+
}, undefined, true, undefined, this),
|
|
2166
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2167
|
+
className: "grid gap-1 sm:gap-2",
|
|
2168
|
+
children: [
|
|
2169
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2170
|
+
className: "text-xs sm:text-sm",
|
|
2171
|
+
children: "Color"
|
|
2172
|
+
}, undefined, false, undefined, this),
|
|
2173
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2174
|
+
className: "flex flex-wrap gap-2",
|
|
2175
|
+
children: /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(TooltipProvider, {
|
|
2176
|
+
children: colorOptions.map((color) => /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Tooltip, {
|
|
2177
|
+
children: [
|
|
2178
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(TooltipTrigger, {
|
|
2179
|
+
asChild: true,
|
|
2180
|
+
children: /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Button, {
|
|
2181
|
+
variant: "ghost",
|
|
2182
|
+
type: "button",
|
|
2183
|
+
className: cn(`${color.value} h-6 w-6 rounded-full sm:h-8 sm:w-8`, selectedColor === color.value && "ring-2 ring-black ring-offset-1 sm:ring-offset-2"),
|
|
2184
|
+
onClick: () => setSelectedColor(color.value),
|
|
2185
|
+
"aria-label": color.label
|
|
2186
|
+
}, color.value, false, undefined, this)
|
|
2187
|
+
}, undefined, false, undefined, this),
|
|
2188
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(TooltipContent, {
|
|
2189
|
+
children: /* @__PURE__ */ jsx_dev_runtime41.jsxDEV("p", {
|
|
2190
|
+
className: "text-xs sm:text-sm",
|
|
2191
|
+
children: color.label
|
|
2192
|
+
}, undefined, false, undefined, this)
|
|
2193
|
+
}, undefined, false, undefined, this)
|
|
2194
|
+
]
|
|
2195
|
+
}, color.value, true, undefined, this))
|
|
2196
|
+
}, undefined, false, undefined, this)
|
|
2197
|
+
}, undefined, false, undefined, this)
|
|
2198
|
+
]
|
|
2199
|
+
}, undefined, true, undefined, this),
|
|
2200
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2201
|
+
className: "grid gap-1 sm:gap-2",
|
|
2202
|
+
children: [
|
|
2203
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2204
|
+
htmlFor: "location",
|
|
2205
|
+
className: "text-xs sm:text-sm",
|
|
2206
|
+
children: "Location"
|
|
2207
|
+
}, undefined, false, undefined, this),
|
|
2208
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Input, {
|
|
2209
|
+
id: "location",
|
|
2210
|
+
name: "location",
|
|
2211
|
+
value: formValues.location,
|
|
2212
|
+
onChange: handleInputChange,
|
|
2213
|
+
placeholder: "Event location (optional)",
|
|
2214
|
+
className: "h-8 text-sm sm:h-9"
|
|
2215
|
+
}, undefined, false, undefined, this)
|
|
2216
|
+
]
|
|
2217
|
+
}, undefined, true, undefined, this),
|
|
2218
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2219
|
+
className: "grid gap-1 sm:gap-2",
|
|
2220
|
+
children: [
|
|
2221
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Label2, {
|
|
2222
|
+
htmlFor: "description",
|
|
2223
|
+
className: "text-xs sm:text-sm",
|
|
2224
|
+
children: "Description"
|
|
2225
|
+
}, undefined, false, undefined, this),
|
|
2226
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Input, {
|
|
2227
|
+
id: "description",
|
|
2228
|
+
name: "description",
|
|
2229
|
+
value: formValues.description,
|
|
2230
|
+
onChange: handleInputChange,
|
|
2231
|
+
placeholder: "Event description (optional)",
|
|
2232
|
+
className: "h-8 text-sm sm:h-9"
|
|
2233
|
+
}, undefined, false, undefined, this)
|
|
2234
|
+
]
|
|
2235
|
+
}, undefined, true, undefined, this)
|
|
2236
|
+
]
|
|
2237
|
+
}, undefined, true, undefined, this),
|
|
2238
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(DialogFooter, {
|
|
2239
|
+
className: "mt-2 flex flex-col-reverse gap-2 sm:mt-4 sm:flex-row sm:gap-0",
|
|
2240
|
+
children: [
|
|
2241
|
+
selectedEvent.id && /* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Button, {
|
|
2242
|
+
type: "button",
|
|
2243
|
+
variant: "destructive",
|
|
2244
|
+
onClick: handleDelete,
|
|
2245
|
+
className: "w-full sm:mr-auto sm:w-auto",
|
|
2246
|
+
size: "sm",
|
|
2247
|
+
children: "Delete"
|
|
2248
|
+
}, undefined, false, undefined, this),
|
|
2249
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV("div", {
|
|
2250
|
+
className: "flex w-full gap-2 sm:w-auto",
|
|
2251
|
+
children: [
|
|
2252
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Button, {
|
|
2253
|
+
type: "button",
|
|
2254
|
+
variant: "outline",
|
|
2255
|
+
onClick: onClose,
|
|
2256
|
+
className: "flex-1 sm:flex-none",
|
|
2257
|
+
size: "sm",
|
|
2258
|
+
children: "Cancel"
|
|
2259
|
+
}, undefined, false, undefined, this),
|
|
2260
|
+
/* @__PURE__ */ jsx_dev_runtime41.jsxDEV(Button, {
|
|
2261
|
+
type: "submit",
|
|
2262
|
+
className: "flex-1 sm:flex-none",
|
|
2263
|
+
size: "sm",
|
|
2264
|
+
children: selectedEvent.id ? "Update" : "Create"
|
|
2265
|
+
}, undefined, false, undefined, this)
|
|
2266
|
+
]
|
|
2267
|
+
}, undefined, true, undefined, this)
|
|
2268
|
+
]
|
|
2269
|
+
}, undefined, true, undefined, this)
|
|
2270
|
+
]
|
|
2271
|
+
}, undefined, true, undefined, this)
|
|
2272
|
+
}, undefined, false, undefined, this)
|
|
2273
|
+
}, undefined, false, undefined, this);
|
|
2274
|
+
};
|
|
2275
|
+
|
|
2276
|
+
// src/components/header/base-header.tsx
|
|
2277
|
+
var import_lucide_react11 = require("lucide-react");
|
|
2278
|
+
var import_react20 = require("react");
|
|
2279
|
+
|
|
2280
|
+
// src/components/header/title-content.tsx
|
|
2281
|
+
var import_dayjs14 = __toESM(require("dayjs"));
|
|
2282
|
+
var import_react18 = require("motion/react");
|
|
2283
|
+
var import_lucide_react9 = require("lucide-react");
|
|
2284
|
+
var import_react19 = require("react");
|
|
2285
|
+
var jsx_dev_runtime42 = require("react/jsx-dev-runtime");
|
|
2286
|
+
var months = [
|
|
2287
|
+
"January",
|
|
2288
|
+
"February",
|
|
2289
|
+
"March",
|
|
2290
|
+
"April",
|
|
2291
|
+
"May",
|
|
2292
|
+
"June",
|
|
2293
|
+
"July",
|
|
2294
|
+
"August",
|
|
2295
|
+
"September",
|
|
2296
|
+
"October",
|
|
2297
|
+
"November",
|
|
2298
|
+
"December"
|
|
2299
|
+
];
|
|
2300
|
+
var animationVariants = {
|
|
2301
|
+
initial: { opacity: 0, y: 10 },
|
|
2302
|
+
animate: { opacity: 1, y: 0 },
|
|
2303
|
+
exit: { opacity: 0, y: -10 }
|
|
2304
|
+
};
|
|
2305
|
+
var TitleContent = () => {
|
|
2306
|
+
const { currentDate, view, setCurrentDate } = useCalendarContext();
|
|
2307
|
+
const [monthPopoverOpen, setMonthPopoverOpen] = import_react19.useState(false);
|
|
2308
|
+
const [yearPopoverOpen, setYearPopoverOpen] = import_react19.useState(false);
|
|
2309
|
+
const [weekPopoverOpen, setWeekPopoverOpen] = import_react19.useState(false);
|
|
2310
|
+
const [dayPopoverOpen, setDayPopoverOpen] = import_react19.useState(false);
|
|
2311
|
+
const currentYear = currentDate.year();
|
|
2312
|
+
const years = Array.from({ length: 11 }, (_, i) => currentYear - 5 + i);
|
|
2313
|
+
const handleMonthChange = (month) => {
|
|
2314
|
+
const newDate = currentDate.month(month);
|
|
2315
|
+
setCurrentDate(newDate);
|
|
2316
|
+
setMonthPopoverOpen(false);
|
|
2317
|
+
};
|
|
2318
|
+
const handleYearChange = (year) => {
|
|
2319
|
+
const newDate = currentDate.year(year);
|
|
2320
|
+
setCurrentDate(newDate);
|
|
2321
|
+
setYearPopoverOpen(false);
|
|
2322
|
+
};
|
|
2323
|
+
return /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(jsx_dev_runtime42.Fragment, {
|
|
2324
|
+
children: [
|
|
2325
|
+
view !== "year" && /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Popover, {
|
|
2326
|
+
open: monthPopoverOpen,
|
|
2327
|
+
onOpenChange: setMonthPopoverOpen,
|
|
2328
|
+
children: [
|
|
2329
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverTrigger, {
|
|
2330
|
+
asChild: true,
|
|
2331
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2332
|
+
variant: "ghost",
|
|
2333
|
+
className: "flex items-center gap-1 px-2 font-semibold",
|
|
2334
|
+
children: [
|
|
2335
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.AnimatePresence, {
|
|
2336
|
+
mode: "wait",
|
|
2337
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.motion.span, {
|
|
2338
|
+
initial: "initial",
|
|
2339
|
+
animate: "animate",
|
|
2340
|
+
exit: "exit",
|
|
2341
|
+
variants: animationVariants,
|
|
2342
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
2343
|
+
children: currentDate.format("MMMM")
|
|
2344
|
+
}, `month-${currentDate.month()}`, false, undefined, this)
|
|
2345
|
+
}, undefined, false, undefined, this),
|
|
2346
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_lucide_react9.ChevronDown, {
|
|
2347
|
+
className: "h-4 w-4"
|
|
2348
|
+
}, undefined, false, undefined, this)
|
|
2349
|
+
]
|
|
2350
|
+
}, undefined, true, undefined, this)
|
|
2351
|
+
}, undefined, false, undefined, this),
|
|
2352
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverContent, {
|
|
2353
|
+
className: "w-40 p-0",
|
|
2354
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2355
|
+
className: "flex max-h-60 flex-col overflow-auto",
|
|
2356
|
+
children: months.map((month, index) => /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2357
|
+
variant: "ghost",
|
|
2358
|
+
className: cn("justify-start font-normal", currentDate.month() === index && "bg-primary/10"),
|
|
2359
|
+
onClick: () => handleMonthChange(index),
|
|
2360
|
+
children: month
|
|
2361
|
+
}, month, false, undefined, this))
|
|
2362
|
+
}, undefined, false, undefined, this)
|
|
2363
|
+
}, undefined, false, undefined, this)
|
|
2364
|
+
]
|
|
2365
|
+
}, undefined, true, undefined, this),
|
|
2366
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Popover, {
|
|
2367
|
+
open: yearPopoverOpen,
|
|
2368
|
+
onOpenChange: setYearPopoverOpen,
|
|
2369
|
+
children: [
|
|
2370
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverTrigger, {
|
|
2371
|
+
asChild: true,
|
|
2372
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2373
|
+
variant: "ghost",
|
|
2374
|
+
className: "flex items-center gap-1 px-2 font-semibold",
|
|
2375
|
+
children: [
|
|
2376
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.AnimatePresence, {
|
|
2377
|
+
mode: "wait",
|
|
2378
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.motion.span, {
|
|
2379
|
+
initial: "initial",
|
|
2380
|
+
animate: "animate",
|
|
2381
|
+
exit: "exit",
|
|
2382
|
+
variants: animationVariants,
|
|
2383
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
2384
|
+
children: currentDate.format("YYYY")
|
|
2385
|
+
}, `year-${currentDate.year()}`, false, undefined, this)
|
|
2386
|
+
}, undefined, false, undefined, this),
|
|
2387
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_lucide_react9.ChevronDown, {
|
|
2388
|
+
className: "h-4 w-4"
|
|
2389
|
+
}, undefined, false, undefined, this)
|
|
2390
|
+
]
|
|
2391
|
+
}, undefined, true, undefined, this)
|
|
2392
|
+
}, undefined, false, undefined, this),
|
|
2393
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverContent, {
|
|
2394
|
+
className: "w-24 p-0",
|
|
2395
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2396
|
+
className: "flex max-h-60 flex-col overflow-auto",
|
|
2397
|
+
children: years.map((year) => /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2398
|
+
variant: "ghost",
|
|
2399
|
+
className: cn("justify-start font-normal", currentDate.year() === year && "bg-primary/10"),
|
|
2400
|
+
onClick: () => handleYearChange(year),
|
|
2401
|
+
children: year
|
|
2402
|
+
}, year, false, undefined, this))
|
|
2403
|
+
}, undefined, false, undefined, this)
|
|
2404
|
+
}, undefined, false, undefined, this)
|
|
2405
|
+
]
|
|
2406
|
+
}, undefined, true, undefined, this),
|
|
2407
|
+
view === "week" && /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Popover, {
|
|
2408
|
+
open: weekPopoverOpen,
|
|
2409
|
+
onOpenChange: setWeekPopoverOpen,
|
|
2410
|
+
children: [
|
|
2411
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverTrigger, {
|
|
2412
|
+
asChild: true,
|
|
2413
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2414
|
+
variant: "ghost",
|
|
2415
|
+
className: "flex items-center gap-1 px-2 font-semibold",
|
|
2416
|
+
children: [
|
|
2417
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.AnimatePresence, {
|
|
2418
|
+
mode: "wait",
|
|
2419
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.motion.span, {
|
|
2420
|
+
initial: "initial",
|
|
2421
|
+
animate: "animate",
|
|
2422
|
+
exit: "exit",
|
|
2423
|
+
variants: animationVariants,
|
|
2424
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
2425
|
+
children: `${currentDate.startOf("week").format("MMM D")} - ${currentDate.endOf("week").format("MMM D")}`
|
|
2426
|
+
}, `week-range-${currentDate.format("YYYY-MM-DD")}`, false, undefined, this)
|
|
2427
|
+
}, undefined, false, undefined, this),
|
|
2428
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_lucide_react9.ChevronDown, {
|
|
2429
|
+
className: "ml-1 h-3 w-3 opacity-70"
|
|
2430
|
+
}, undefined, false, undefined, this)
|
|
2431
|
+
]
|
|
2432
|
+
}, undefined, true, undefined, this)
|
|
2433
|
+
}, undefined, false, undefined, this),
|
|
2434
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverContent, {
|
|
2435
|
+
className: "w-56 p-0",
|
|
2436
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2437
|
+
className: "flex max-h-60 flex-col overflow-auto",
|
|
2438
|
+
children: Array.from({ length: 7 }, (_, i) => {
|
|
2439
|
+
const weekDate = currentDate.subtract(3, "week").add(i, "week");
|
|
2440
|
+
const startOfWeek = weekDate.startOf("week");
|
|
2441
|
+
const endOfWeek = weekDate.endOf("week");
|
|
2442
|
+
const isCurrentWeek = weekDate.isSame(currentDate, "week");
|
|
2443
|
+
return /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2444
|
+
variant: "ghost",
|
|
2445
|
+
className: cn("justify-start font-normal", isCurrentWeek && "bg-primary/10"),
|
|
2446
|
+
onClick: () => {
|
|
2447
|
+
setCurrentDate(startOfWeek);
|
|
2448
|
+
setWeekPopoverOpen(false);
|
|
2449
|
+
},
|
|
2450
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2451
|
+
className: "flex w-full items-center justify-between",
|
|
2452
|
+
children: [
|
|
2453
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV("span", {
|
|
2454
|
+
children: `${startOfWeek.format("MMM D")} - ${endOfWeek.format("D")}`
|
|
2455
|
+
}, undefined, false, undefined, this),
|
|
2456
|
+
startOfWeek.month() !== endOfWeek.month() && /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("span", {
|
|
2457
|
+
className: "text-xs opacity-70",
|
|
2458
|
+
children: `${startOfWeek.format("MMM")}-${endOfWeek.format("MMM")}`
|
|
2459
|
+
}, undefined, false, undefined, this)
|
|
2460
|
+
]
|
|
2461
|
+
}, undefined, true, undefined, this)
|
|
2462
|
+
}, startOfWeek.format("YYYY-MM-DD"), false, undefined, this);
|
|
2463
|
+
})
|
|
2464
|
+
}, undefined, false, undefined, this)
|
|
2465
|
+
}, undefined, false, undefined, this)
|
|
2466
|
+
]
|
|
2467
|
+
}, undefined, true, undefined, this),
|
|
2468
|
+
view === "day" && /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Popover, {
|
|
2469
|
+
open: dayPopoverOpen,
|
|
2470
|
+
onOpenChange: setDayPopoverOpen,
|
|
2471
|
+
children: [
|
|
2472
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverTrigger, {
|
|
2473
|
+
asChild: true,
|
|
2474
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2475
|
+
variant: "ghost",
|
|
2476
|
+
className: "flex items-center gap-1 px-2 font-semibold",
|
|
2477
|
+
children: [
|
|
2478
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.AnimatePresence, {
|
|
2479
|
+
mode: "wait",
|
|
2480
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_react18.motion.span, {
|
|
2481
|
+
initial: "initial",
|
|
2482
|
+
animate: "animate",
|
|
2483
|
+
exit: "exit",
|
|
2484
|
+
variants: animationVariants,
|
|
2485
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
2486
|
+
children: currentDate.format("dddd, D")
|
|
2487
|
+
}, `day-info-${currentDate.format("YYYY-MM-DD")}`, false, undefined, this)
|
|
2488
|
+
}, undefined, false, undefined, this),
|
|
2489
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(import_lucide_react9.ChevronDown, {
|
|
2490
|
+
className: "ml-1 h-3 w-3 opacity-70"
|
|
2491
|
+
}, undefined, false, undefined, this)
|
|
2492
|
+
]
|
|
2493
|
+
}, undefined, true, undefined, this)
|
|
2494
|
+
}, undefined, false, undefined, this),
|
|
2495
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV(PopoverContent, {
|
|
2496
|
+
className: "w-56 p-0",
|
|
2497
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2498
|
+
className: "flex max-h-60 flex-col overflow-auto",
|
|
2499
|
+
children: (() => {
|
|
2500
|
+
const firstDayOfMonth = currentDate.startOf("month");
|
|
2501
|
+
const daysInMonth = currentDate.daysInMonth();
|
|
2502
|
+
return Array.from({ length: daysInMonth }, (_, i) => {
|
|
2503
|
+
const dayDate = firstDayOfMonth.date(i + 1);
|
|
2504
|
+
const isCurrentDay = dayDate.isSame(currentDate, "day");
|
|
2505
|
+
const isToday = dayDate.isSame(import_dayjs14.default(), "day");
|
|
2506
|
+
return /* @__PURE__ */ jsx_dev_runtime42.jsxDEV(Button, {
|
|
2507
|
+
variant: "ghost",
|
|
2508
|
+
className: cn("justify-start font-normal", isCurrentDay && "bg-primary/10"),
|
|
2509
|
+
onClick: () => {
|
|
2510
|
+
setCurrentDate(dayDate);
|
|
2511
|
+
setDayPopoverOpen(false);
|
|
2512
|
+
},
|
|
2513
|
+
children: /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("div", {
|
|
2514
|
+
className: "flex w-full items-center justify-between",
|
|
2515
|
+
children: [
|
|
2516
|
+
/* @__PURE__ */ jsx_dev_runtime42.jsxDEV("span", {
|
|
2517
|
+
children: dayDate.format("dddd, MMM D")
|
|
2518
|
+
}, undefined, false, undefined, this),
|
|
2519
|
+
isToday && /* @__PURE__ */ jsx_dev_runtime42.jsxDEV("span", {
|
|
2520
|
+
className: "bg-primary text-primary-foreground rounded-sm px-1 text-xs",
|
|
2521
|
+
children: "Today"
|
|
2522
|
+
}, undefined, false, undefined, this)
|
|
2523
|
+
]
|
|
2524
|
+
}, undefined, true, undefined, this)
|
|
2525
|
+
}, dayDate.format("YYYY-MM-DD"), false, undefined, this);
|
|
2526
|
+
});
|
|
2527
|
+
})()
|
|
2528
|
+
}, undefined, false, undefined, this)
|
|
2529
|
+
}, undefined, false, undefined, this)
|
|
2530
|
+
]
|
|
2531
|
+
}, undefined, true, undefined, this)
|
|
2532
|
+
]
|
|
2533
|
+
}, undefined, true, undefined, this);
|
|
2534
|
+
};
|
|
2535
|
+
var title_content_default = TitleContent;
|
|
2536
|
+
|
|
2537
|
+
// src/components/header/view-controls.tsx
|
|
2538
|
+
var import_lucide_react10 = require("lucide-react");
|
|
2539
|
+
var jsx_dev_runtime43 = require("react/jsx-dev-runtime");
|
|
2540
|
+
var ViewControls = ({
|
|
2541
|
+
currentView,
|
|
2542
|
+
onChange,
|
|
2543
|
+
variant = "default",
|
|
2544
|
+
size = "sm",
|
|
2545
|
+
className,
|
|
2546
|
+
onToday,
|
|
2547
|
+
onNext,
|
|
2548
|
+
onPrevious
|
|
2549
|
+
}) => {
|
|
2550
|
+
const isGrid = variant === "grid";
|
|
2551
|
+
const getButtonClassName = (viewType) => {
|
|
2552
|
+
return cn(isGrid ? "w-full" : "", viewType === "year" ? isGrid ? "w-full" : "hidden md:inline-flex" : "", currentView === viewType && "bg-primary/80");
|
|
2553
|
+
};
|
|
2554
|
+
const getBtnVariant = (viewType) => {
|
|
2555
|
+
return currentView === viewType ? "default" : "outline";
|
|
2556
|
+
};
|
|
2557
|
+
return /* @__PURE__ */ jsx_dev_runtime43.jsxDEV("div", {
|
|
2558
|
+
className: cn(isGrid ? "grid grid-cols-2 gap-2" : "flex gap-1", className),
|
|
2559
|
+
children: [
|
|
2560
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2561
|
+
onClick: onPrevious,
|
|
2562
|
+
variant: "outline",
|
|
2563
|
+
size,
|
|
2564
|
+
children: /* @__PURE__ */ jsx_dev_runtime43.jsxDEV(import_lucide_react10.ChevronLeft, {
|
|
2565
|
+
className: "h-4 w-4"
|
|
2566
|
+
}, undefined, false, undefined, this)
|
|
2567
|
+
}, undefined, false, undefined, this),
|
|
2568
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2569
|
+
onClick: onNext,
|
|
2570
|
+
variant: "outline",
|
|
2571
|
+
size,
|
|
2572
|
+
children: /* @__PURE__ */ jsx_dev_runtime43.jsxDEV(import_lucide_react10.ChevronRight, {
|
|
2573
|
+
className: "h-4 w-4"
|
|
2574
|
+
}, undefined, false, undefined, this)
|
|
2575
|
+
}, undefined, false, undefined, this),
|
|
2576
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2577
|
+
onClick: () => onChange("day"),
|
|
2578
|
+
variant: getBtnVariant("day"),
|
|
2579
|
+
size,
|
|
2580
|
+
className: getButtonClassName("day"),
|
|
2581
|
+
children: "Day"
|
|
2582
|
+
}, undefined, false, undefined, this),
|
|
2583
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2584
|
+
onClick: () => onChange("week"),
|
|
2585
|
+
variant: getBtnVariant("week"),
|
|
2586
|
+
size,
|
|
2587
|
+
className: getButtonClassName("week"),
|
|
2588
|
+
children: "Week"
|
|
2589
|
+
}, undefined, false, undefined, this),
|
|
2590
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2591
|
+
onClick: () => onChange("month"),
|
|
2592
|
+
variant: getBtnVariant("month"),
|
|
2593
|
+
size,
|
|
2594
|
+
className: getButtonClassName("month"),
|
|
2595
|
+
children: "Month"
|
|
2596
|
+
}, undefined, false, undefined, this),
|
|
2597
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2598
|
+
onClick: () => onChange("year"),
|
|
2599
|
+
variant: getBtnVariant("year"),
|
|
2600
|
+
size,
|
|
2601
|
+
className: getButtonClassName("year"),
|
|
2602
|
+
children: "Year"
|
|
2603
|
+
}, undefined, false, undefined, this),
|
|
2604
|
+
/* @__PURE__ */ jsx_dev_runtime43.jsxDEV(Button, {
|
|
2605
|
+
onClick: onToday,
|
|
2606
|
+
variant: "outline",
|
|
2607
|
+
size,
|
|
2608
|
+
children: "Today"
|
|
2609
|
+
}, undefined, false, undefined, this)
|
|
2610
|
+
]
|
|
2611
|
+
}, undefined, true, undefined, this);
|
|
2612
|
+
};
|
|
2613
|
+
var view_controls_default = ViewControls;
|
|
2614
|
+
|
|
2615
|
+
// src/components/header/base-header.tsx
|
|
2616
|
+
var jsx_dev_runtime44 = require("react/jsx-dev-runtime");
|
|
2617
|
+
var Header2 = () => {
|
|
2618
|
+
const {
|
|
2619
|
+
currentDate,
|
|
2620
|
+
view,
|
|
2621
|
+
setView,
|
|
2622
|
+
nextPeriod,
|
|
2623
|
+
prevPeriod,
|
|
2624
|
+
today,
|
|
2625
|
+
openEventForm
|
|
2626
|
+
} = useCalendarContext();
|
|
2627
|
+
const [mobilePopoverOpen, setMobilePopoverOpen] = import_react20.useState(false);
|
|
2628
|
+
const handleViewChange = (newView, closePopover = false) => {
|
|
2629
|
+
setView(newView);
|
|
2630
|
+
if (closePopover) {
|
|
2631
|
+
setMobilePopoverOpen(false);
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
const handleNavigation = {
|
|
2635
|
+
today: () => {
|
|
2636
|
+
today();
|
|
2637
|
+
setMobilePopoverOpen(false);
|
|
2638
|
+
},
|
|
2639
|
+
previous: () => {
|
|
2640
|
+
prevPeriod();
|
|
2641
|
+
setMobilePopoverOpen(false);
|
|
2642
|
+
},
|
|
2643
|
+
next: () => {
|
|
2644
|
+
nextPeriod();
|
|
2645
|
+
setMobilePopoverOpen(false);
|
|
2646
|
+
}
|
|
2647
|
+
};
|
|
2648
|
+
const NewEventButton = import_react20.useCallback(() => /* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2649
|
+
className: "flex items-center gap-2",
|
|
2650
|
+
children: /* @__PURE__ */ jsx_dev_runtime44.jsxDEV(Button, {
|
|
2651
|
+
onClick: () => openEventForm(currentDate),
|
|
2652
|
+
variant: "default",
|
|
2653
|
+
size: "sm",
|
|
2654
|
+
className: "flex items-center gap-1",
|
|
2655
|
+
children: [
|
|
2656
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(import_lucide_react11.Plus, {
|
|
2657
|
+
className: "h-4 w-4"
|
|
2658
|
+
}, undefined, false, undefined, this),
|
|
2659
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("span", {
|
|
2660
|
+
className: "hidden md:inline",
|
|
2661
|
+
children: "New Event"
|
|
2662
|
+
}, undefined, false, undefined, this),
|
|
2663
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("span", {
|
|
2664
|
+
className: "md:hidden",
|
|
2665
|
+
children: "New"
|
|
2666
|
+
}, undefined, false, undefined, this)
|
|
2667
|
+
]
|
|
2668
|
+
}, undefined, true, undefined, this)
|
|
2669
|
+
}, undefined, false, undefined, this), [currentDate, openEventForm]);
|
|
2670
|
+
return /* @__PURE__ */ jsx_dev_runtime44.jsxDEV(jsx_dev_runtime44.Fragment, {
|
|
2671
|
+
children: /* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2672
|
+
className: "@container grid grid-cols-12 items-center gap-2 border-b p-2 sm:p-4",
|
|
2673
|
+
children: [
|
|
2674
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2675
|
+
className: "col-span-12 flex flex-wrap items-center justify-center gap-2 @4xl:col-span-5 @4xl:justify-start",
|
|
2676
|
+
children: [
|
|
2677
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(import_lucide_react11.Calendar, {
|
|
2678
|
+
className: "h-5 w-5"
|
|
2679
|
+
}, undefined, false, undefined, this),
|
|
2680
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(title_content_default, {}, undefined, false, undefined, this)
|
|
2681
|
+
]
|
|
2682
|
+
}, undefined, true, undefined, this),
|
|
2683
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2684
|
+
className: "col-span-12 flex flex-wrap justify-center gap-1 @4xl:col-span-7 @4xl:justify-end",
|
|
2685
|
+
children: [
|
|
2686
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2687
|
+
className: "hidden items-center justify-end gap-1 sm:flex",
|
|
2688
|
+
children: [
|
|
2689
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(view_controls_default, {
|
|
2690
|
+
currentView: view,
|
|
2691
|
+
onChange: setView,
|
|
2692
|
+
onToday: today,
|
|
2693
|
+
onNext: nextPeriod,
|
|
2694
|
+
onPrevious: prevPeriod,
|
|
2695
|
+
variant: "default",
|
|
2696
|
+
className: "justify-end"
|
|
2697
|
+
}, undefined, false, undefined, this),
|
|
2698
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(NewEventButton, {}, undefined, false, undefined, this)
|
|
2699
|
+
]
|
|
2700
|
+
}, undefined, true, undefined, this),
|
|
2701
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2702
|
+
className: "flex items-center justify-end gap-1 sm:hidden",
|
|
2703
|
+
children: [
|
|
2704
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(NewEventButton, {}, undefined, false, undefined, this),
|
|
2705
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(Popover, {
|
|
2706
|
+
open: mobilePopoverOpen,
|
|
2707
|
+
onOpenChange: setMobilePopoverOpen,
|
|
2708
|
+
children: [
|
|
2709
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(PopoverTrigger, {
|
|
2710
|
+
asChild: true,
|
|
2711
|
+
children: /* @__PURE__ */ jsx_dev_runtime44.jsxDEV(Button, {
|
|
2712
|
+
variant: "outline",
|
|
2713
|
+
size: "sm",
|
|
2714
|
+
children: /* @__PURE__ */ jsx_dev_runtime44.jsxDEV(import_lucide_react11.Menu, {
|
|
2715
|
+
className: "h-4 w-4"
|
|
2716
|
+
}, undefined, false, undefined, this)
|
|
2717
|
+
}, undefined, false, undefined, this)
|
|
2718
|
+
}, undefined, false, undefined, this),
|
|
2719
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(PopoverContent, {
|
|
2720
|
+
align: "end",
|
|
2721
|
+
className: "w-[240px] p-2",
|
|
2722
|
+
children: /* @__PURE__ */ jsx_dev_runtime44.jsxDEV("div", {
|
|
2723
|
+
className: "space-y-2",
|
|
2724
|
+
children: [
|
|
2725
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV("h3", {
|
|
2726
|
+
className: "mb-1 text-sm font-medium",
|
|
2727
|
+
children: "View & Navigation"
|
|
2728
|
+
}, undefined, false, undefined, this),
|
|
2729
|
+
/* @__PURE__ */ jsx_dev_runtime44.jsxDEV(view_controls_default, {
|
|
2730
|
+
currentView: view,
|
|
2731
|
+
onChange: (newView) => handleViewChange(newView, true),
|
|
2732
|
+
onToday: handleNavigation.today,
|
|
2733
|
+
onNext: handleNavigation.next,
|
|
2734
|
+
onPrevious: handleNavigation.previous,
|
|
2735
|
+
variant: "grid"
|
|
2736
|
+
}, undefined, false, undefined, this)
|
|
2737
|
+
]
|
|
2738
|
+
}, undefined, true, undefined, this)
|
|
2739
|
+
}, undefined, false, undefined, this)
|
|
2740
|
+
]
|
|
2741
|
+
}, undefined, true, undefined, this)
|
|
2742
|
+
]
|
|
2743
|
+
}, undefined, true, undefined, this)
|
|
2744
|
+
]
|
|
2745
|
+
}, undefined, true, undefined, this)
|
|
2746
|
+
]
|
|
2747
|
+
}, undefined, true, undefined, this)
|
|
2748
|
+
}, undefined, false, undefined, this);
|
|
2749
|
+
};
|
|
2750
|
+
var base_header_default = Header2;
|
|
2751
|
+
// src/features/year-view/year-view.tsx
|
|
2752
|
+
var import_dayjs15 = __toESM(require("dayjs"));
|
|
2753
|
+
var import_react21 = require("motion/react");
|
|
2754
|
+
var jsx_dev_runtime45 = require("react/jsx-dev-runtime");
|
|
2755
|
+
var YearView = () => {
|
|
2756
|
+
const { currentDate, selectDate, events, setView, getEventsForDate } = useCalendarContext();
|
|
2757
|
+
const year = currentDate.year();
|
|
2758
|
+
const months2 = Array.from({ length: 12 }, (_, i) => {
|
|
2759
|
+
const monthDate = import_dayjs15.default().year(year).month(i).startOf("month");
|
|
2760
|
+
return {
|
|
2761
|
+
date: monthDate,
|
|
2762
|
+
name: monthDate.format("MMMM"),
|
|
2763
|
+
daysInMonth: monthDate.daysInMonth(),
|
|
2764
|
+
firstDayOfMonth: monthDate.startOf("month").day()
|
|
2765
|
+
};
|
|
2766
|
+
});
|
|
2767
|
+
const monthsWithEventCount = months2.map((month) => {
|
|
2768
|
+
const eventsInMonth = events.filter((event) => event.start.year() === year && event.start.month() === month.date.month());
|
|
2769
|
+
return {
|
|
2770
|
+
...month,
|
|
2771
|
+
eventCount: eventsInMonth.length
|
|
2772
|
+
};
|
|
2773
|
+
});
|
|
2774
|
+
const handleMonthClick = (date) => {
|
|
2775
|
+
selectDate(date);
|
|
2776
|
+
setView("month");
|
|
2777
|
+
};
|
|
2778
|
+
const handleDayClick = (date, event) => {
|
|
2779
|
+
event.stopPropagation();
|
|
2780
|
+
selectDate(date);
|
|
2781
|
+
setView("day");
|
|
2782
|
+
};
|
|
2783
|
+
const renderMiniCalendar = (month) => {
|
|
2784
|
+
const firstDayOfCalendar = month.date.startOf("month").startOf("week");
|
|
2785
|
+
const daysArray = Array.from({ length: 42 }, (_, i) => {
|
|
2786
|
+
const day = firstDayOfCalendar.add(i, "day");
|
|
2787
|
+
const isCurrentMonth = day.month() === month.date.month();
|
|
2788
|
+
const isToday = day.isSame(import_dayjs15.default(), "day");
|
|
2789
|
+
const isCurrentDate = day.isSame(currentDate, "day");
|
|
2790
|
+
const dayEvents = getEventsForDate(day);
|
|
2791
|
+
const hasEvents = dayEvents.length > 0;
|
|
2792
|
+
return {
|
|
2793
|
+
day,
|
|
2794
|
+
isCurrentMonth,
|
|
2795
|
+
isToday,
|
|
2796
|
+
isCurrentDate,
|
|
2797
|
+
hasEvents,
|
|
2798
|
+
eventCount: dayEvents.length,
|
|
2799
|
+
events: dayEvents
|
|
2800
|
+
};
|
|
2801
|
+
});
|
|
2802
|
+
return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2803
|
+
"data-testid": `year-mini-calendar-${month.date.format("MM")}`,
|
|
2804
|
+
className: "grid grid-cols-7 gap-[1px] text-[0.6rem]",
|
|
2805
|
+
children: [
|
|
2806
|
+
["S", "M", "T", "W", "T", "F", "S"].map((dayName, i) => /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2807
|
+
className: "text-muted-foreground h-3 text-center",
|
|
2808
|
+
children: dayName
|
|
2809
|
+
}, `header-${i}`, false, undefined, this)),
|
|
2810
|
+
daysArray.map((dayInfo, i) => /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2811
|
+
"data-testid": `year-day-${dayInfo.day.format("YYYY-MM-DD")}`,
|
|
2812
|
+
onClick: (e) => handleDayClick(dayInfo.day, e),
|
|
2813
|
+
className: cn("relative flex aspect-square w-full cursor-pointer flex-col items-center justify-center", "hover:bg-accent rounded-sm transition-colors duration-200", !dayInfo.isCurrentMonth && "text-muted-foreground opacity-50", dayInfo.isToday && "bg-primary text-primary-foreground rounded-full", dayInfo.isCurrentDate && !dayInfo.isToday && "bg-muted rounded-full font-bold", dayInfo.hasEvents && !dayInfo.isToday && !dayInfo.isCurrentDate && "font-medium"),
|
|
2814
|
+
title: dayInfo.hasEvents ? `${dayInfo.eventCount} event${dayInfo.eventCount > 1 ? "s" : ""}` : "",
|
|
2815
|
+
children: [
|
|
2816
|
+
/* @__PURE__ */ jsx_dev_runtime45.jsxDEV("span", {
|
|
2817
|
+
className: "text-center leading-none",
|
|
2818
|
+
children: dayInfo.day.date()
|
|
2819
|
+
}, undefined, false, undefined, this),
|
|
2820
|
+
dayInfo.hasEvents && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2821
|
+
className: cn("absolute bottom-0 flex w-full justify-center space-x-[1px]", dayInfo.isToday ? "bottom-[1px]" : ""),
|
|
2822
|
+
children: [
|
|
2823
|
+
dayInfo.eventCount > 0 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("span", {
|
|
2824
|
+
className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-primary")
|
|
2825
|
+
}, undefined, false, undefined, this),
|
|
2826
|
+
dayInfo.eventCount > 1 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("span", {
|
|
2827
|
+
className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-blue-500")
|
|
2828
|
+
}, undefined, false, undefined, this),
|
|
2829
|
+
dayInfo.eventCount > 2 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("span", {
|
|
2830
|
+
className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-green-500")
|
|
2831
|
+
}, undefined, false, undefined, this)
|
|
2832
|
+
]
|
|
2833
|
+
}, undefined, true, undefined, this)
|
|
2834
|
+
]
|
|
2835
|
+
}, `day-${i}`, true, undefined, this))
|
|
2836
|
+
]
|
|
2837
|
+
}, undefined, true, undefined, this);
|
|
2838
|
+
};
|
|
2839
|
+
return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(ScrollArea, {
|
|
2840
|
+
"data-testid": "year-view",
|
|
2841
|
+
className: "h-full",
|
|
2842
|
+
children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2843
|
+
"data-testid": "year-grid",
|
|
2844
|
+
className: "grid auto-rows-fr grid-cols-1 gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
2845
|
+
children: monthsWithEventCount.map((month, index) => /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("div", {
|
|
2846
|
+
"data-testid": `year-month-${month.date.format("MM")}`,
|
|
2847
|
+
onClick: () => handleMonthClick(month.date),
|
|
2848
|
+
className: "hover:border-primary flex cursor-pointer flex-col rounded-lg border p-3 transition-all duration-200 hover:scale-[1.01] hover:shadow-md",
|
|
2849
|
+
children: [
|
|
2850
|
+
/* @__PURE__ */ jsx_dev_runtime45.jsxDEV(import_react21.AnimatePresence, {
|
|
2851
|
+
mode: "wait",
|
|
2852
|
+
children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(import_react21.motion.div, {
|
|
2853
|
+
initial: { opacity: 0, y: -10 },
|
|
2854
|
+
animate: { opacity: 1, y: 0 },
|
|
2855
|
+
exit: { opacity: 0, y: -10 },
|
|
2856
|
+
transition: {
|
|
2857
|
+
duration: 0.25,
|
|
2858
|
+
ease: "easeInOut",
|
|
2859
|
+
delay: index * 0.05
|
|
2860
|
+
},
|
|
2861
|
+
className: "mb-2 flex items-center justify-between",
|
|
2862
|
+
children: [
|
|
2863
|
+
/* @__PURE__ */ jsx_dev_runtime45.jsxDEV("h3", {
|
|
2864
|
+
"data-testid": `year-month-title-${month.date.format("MM")}`,
|
|
2865
|
+
className: "text-lg font-medium",
|
|
2866
|
+
children: month.name
|
|
2867
|
+
}, undefined, false, undefined, this),
|
|
2868
|
+
month.eventCount > 0 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV("span", {
|
|
2869
|
+
"data-testid": `year-month-event-count-${month.date.format("MM")}`,
|
|
2870
|
+
className: "bg-primary text-primary-foreground rounded-full px-2 py-1 text-xs",
|
|
2871
|
+
children: [
|
|
2872
|
+
month.eventCount,
|
|
2873
|
+
" ",
|
|
2874
|
+
month.eventCount === 1 ? "event" : "events"
|
|
2875
|
+
]
|
|
2876
|
+
}, undefined, true, undefined, this)
|
|
2877
|
+
]
|
|
2878
|
+
}, `month-${index}`, true, undefined, this)
|
|
2879
|
+
}, undefined, false, undefined, this),
|
|
2880
|
+
renderMiniCalendar(month)
|
|
2881
|
+
]
|
|
2882
|
+
}, month.name, true, undefined, this))
|
|
2883
|
+
}, undefined, false, undefined, this)
|
|
2884
|
+
}, undefined, false, undefined, this);
|
|
2885
|
+
};
|
|
2886
|
+
var year_view_default = YearView;
|
|
2887
|
+
|
|
2888
|
+
// src/components/ilamy-calendar/ilamy-calendar.tsx
|
|
2889
|
+
var import_react24 = require("motion/react");
|
|
2890
|
+
|
|
2891
|
+
// src/features/drag-and-drop/calendar-dnd-context.tsx
|
|
2892
|
+
var import_core3 = require("@dnd-kit/core");
|
|
2893
|
+
var import_dayjs16 = __toESM(require("dayjs"));
|
|
2894
|
+
var import_react22 = __toESM(require("react"));
|
|
2895
|
+
var import_modifiers = require("@dnd-kit/modifiers");
|
|
2896
|
+
var jsx_dev_runtime46 = require("react/jsx-dev-runtime");
|
|
2897
|
+
function CalendarDndContext({ children }) {
|
|
2898
|
+
const { updateEvent, view, disableDragAndDrop } = useCalendarContext();
|
|
2899
|
+
const [activeEvent, setActiveEvent] = import_react22.default.useState(null);
|
|
2900
|
+
const mouseSensor = import_core3.useSensor(import_core3.MouseSensor, {
|
|
2901
|
+
activationConstraint: {
|
|
2902
|
+
distance: 2
|
|
2903
|
+
}
|
|
2904
|
+
});
|
|
2905
|
+
const touchSensor = import_core3.useSensor(import_core3.TouchSensor, {
|
|
2906
|
+
activationConstraint: {
|
|
2907
|
+
delay: 100,
|
|
2908
|
+
tolerance: 5
|
|
2909
|
+
}
|
|
2910
|
+
});
|
|
2911
|
+
const sensors = import_core3.useSensors(mouseSensor, touchSensor);
|
|
2912
|
+
const handleDragStart = (event) => {
|
|
2913
|
+
const { active } = event;
|
|
2914
|
+
if (active.data.current?.type === "calendar-event") {
|
|
2915
|
+
setActiveEvent(active.data.current.event);
|
|
2916
|
+
}
|
|
2917
|
+
};
|
|
2918
|
+
const handleDragEnd = (event) => {
|
|
2919
|
+
const { active, over } = event;
|
|
2920
|
+
if (!active || !over || !activeEvent) {
|
|
2921
|
+
setActiveEvent(null);
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
if (over.data.current?.type === "time-cell") {
|
|
2925
|
+
const { date, hour = 0, minute = 0 } = over.data.current;
|
|
2926
|
+
const originalStart = activeEvent.originalStart ?? activeEvent.start;
|
|
2927
|
+
const originalEnd = activeEvent.originalEnd ?? activeEvent.end;
|
|
2928
|
+
const durationMinutes = originalEnd.diff(originalStart, "minute");
|
|
2929
|
+
const newStart = import_dayjs16.default(date).hour(hour).minute(minute || 0);
|
|
2930
|
+
let newEnd = newStart.add(durationMinutes, "minute");
|
|
2931
|
+
if (newEnd.isSame(newEnd.startOf("day"))) {
|
|
2932
|
+
newEnd = newEnd.subtract(1, "day").endOf("day");
|
|
2933
|
+
}
|
|
2934
|
+
updateEvent(activeEvent.id, {
|
|
2935
|
+
start: newStart,
|
|
2936
|
+
end: newEnd
|
|
2937
|
+
});
|
|
2938
|
+
} else if (over.data.current?.type === "day-cell") {
|
|
2939
|
+
const { date } = over.data.current;
|
|
2940
|
+
const newDate = import_dayjs16.default(date);
|
|
2941
|
+
const isMultiDayEvent = !activeEvent.start.isSame(activeEvent.end, "day");
|
|
2942
|
+
const originalStart = activeEvent.originalStart ?? activeEvent.start;
|
|
2943
|
+
const originalEnd = activeEvent.originalEnd ?? activeEvent.end;
|
|
2944
|
+
if (isMultiDayEvent) {
|
|
2945
|
+
if (view === "week") {
|
|
2946
|
+
const startHour = originalStart.hour();
|
|
2947
|
+
const startMinute = originalStart.minute();
|
|
2948
|
+
const endHour = originalEnd.hour();
|
|
2949
|
+
const endMinute = originalEnd.minute();
|
|
2950
|
+
const durationDays = originalEnd.diff(originalStart, "day");
|
|
2951
|
+
const newStart = newDate.startOf("day").hour(startHour).minute(startMinute);
|
|
2952
|
+
const newEnd = newStart.add(durationDays, "day").hour(endHour).minute(endMinute);
|
|
2953
|
+
updateEvent(activeEvent.id, {
|
|
2954
|
+
start: newStart,
|
|
2955
|
+
end: newEnd,
|
|
2956
|
+
originalStart: undefined,
|
|
2957
|
+
originalEnd: undefined
|
|
2958
|
+
});
|
|
2959
|
+
} else {
|
|
2960
|
+
const daysDifference = newDate.diff(originalStart.startOf("day"), "day");
|
|
2961
|
+
const newStart = originalStart.add(daysDifference, "day");
|
|
2962
|
+
const newEnd = originalEnd.add(daysDifference, "day");
|
|
2963
|
+
updateEvent(activeEvent.id, {
|
|
2964
|
+
start: newStart,
|
|
2965
|
+
end: newEnd,
|
|
2966
|
+
originalStart: undefined,
|
|
2967
|
+
originalEnd: undefined
|
|
2968
|
+
});
|
|
2969
|
+
}
|
|
2970
|
+
} else {
|
|
2971
|
+
const newStart = newDate.hour(activeEvent.start.hour()).minute(activeEvent.start.minute());
|
|
2972
|
+
const durationMinutes = activeEvent.end.diff(activeEvent.start, "minute");
|
|
2973
|
+
const newEnd = newStart.add(durationMinutes, "minute");
|
|
2974
|
+
updateEvent(activeEvent.id, {
|
|
2975
|
+
start: newStart,
|
|
2976
|
+
end: newEnd,
|
|
2977
|
+
originalStart: undefined,
|
|
2978
|
+
originalEnd: undefined
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
setActiveEvent(null);
|
|
2983
|
+
};
|
|
2984
|
+
const handleDragCancel = (_event) => {
|
|
2985
|
+
setActiveEvent(null);
|
|
2986
|
+
};
|
|
2987
|
+
if (disableDragAndDrop) {
|
|
2988
|
+
return children;
|
|
2989
|
+
}
|
|
2990
|
+
return /* @__PURE__ */ jsx_dev_runtime46.jsxDEV(import_core3.DndContext, {
|
|
2991
|
+
sensors,
|
|
2992
|
+
onDragStart: handleDragStart,
|
|
2993
|
+
onDragEnd: handleDragEnd,
|
|
2994
|
+
onDragCancel: handleDragCancel,
|
|
2995
|
+
collisionDetection: import_core3.pointerWithin,
|
|
2996
|
+
children: [
|
|
2997
|
+
children,
|
|
2998
|
+
/* @__PURE__ */ jsx_dev_runtime46.jsxDEV(import_core3.DragOverlay, {
|
|
2999
|
+
modifiers: [import_modifiers.snapCenterToCursor],
|
|
3000
|
+
children: activeEvent && /* @__PURE__ */ jsx_dev_runtime46.jsxDEV("div", {
|
|
3001
|
+
className: cn("cursor-grab truncate rounded bg-amber-200 p-2 text-[10px] shadow-lg sm:text-xs", activeEvent.backgroundColor || "bg-blue-500", activeEvent.color || "text-white"),
|
|
3002
|
+
children: activeEvent?.title
|
|
3003
|
+
}, undefined, false, undefined, this)
|
|
3004
|
+
}, undefined, false, undefined, this)
|
|
3005
|
+
]
|
|
3006
|
+
}, undefined, true, undefined, this);
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
// src/contexts/calendar-context/provider.tsx
|
|
3010
|
+
var import_dayjs17 = __toESM(require("dayjs"));
|
|
3011
|
+
var import_react23 = require("react");
|
|
3012
|
+
var jsx_dev_runtime47 = require("react/jsx-dev-runtime");
|
|
3013
|
+
var CalendarProvider = ({
|
|
3014
|
+
children,
|
|
3015
|
+
initialEvents = [],
|
|
3016
|
+
firstDayOfWeek = 0,
|
|
3017
|
+
renderEvent,
|
|
3018
|
+
onEventClick,
|
|
3019
|
+
onCellClick,
|
|
3020
|
+
onViewChange,
|
|
3021
|
+
locale,
|
|
3022
|
+
timezone: timezone2,
|
|
3023
|
+
disableCellClick,
|
|
3024
|
+
disableEventClick,
|
|
3025
|
+
disableDragAndDrop,
|
|
3026
|
+
dayMaxEvents,
|
|
3027
|
+
stickyHeader
|
|
3028
|
+
}) => {
|
|
3029
|
+
const [currentDate, setCurrentDate] = import_react23.useState(import_dayjs17.default());
|
|
3030
|
+
const [view, setView] = import_react23.useState("month");
|
|
3031
|
+
const [events, setEvents] = import_react23.useState(initialEvents);
|
|
3032
|
+
const [isEventFormOpen, setIsEventFormOpen] = import_react23.useState(false);
|
|
3033
|
+
const [selectedEvent, setSelectedEvent] = import_react23.useState(null);
|
|
3034
|
+
const [selectedDate, setSelectedDate] = import_react23.useState(null);
|
|
3035
|
+
const [currentLocale, setCurrentLocale] = import_react23.useState(locale || "en");
|
|
3036
|
+
import_react23.useEffect(() => {
|
|
3037
|
+
if (initialEvents) {
|
|
3038
|
+
setEvents(initialEvents);
|
|
3039
|
+
}
|
|
3040
|
+
}, [initialEvents]);
|
|
3041
|
+
import_react23.useEffect(() => {
|
|
3042
|
+
if (locale) {
|
|
3043
|
+
setCurrentLocale(locale);
|
|
3044
|
+
import_dayjs17.default.locale(locale);
|
|
3045
|
+
}
|
|
3046
|
+
}, [locale]);
|
|
3047
|
+
import_react23.useEffect(() => {
|
|
3048
|
+
if (timezone2) {
|
|
3049
|
+
setCurrentDate((prevDate) => prevDate.tz(timezone2));
|
|
3050
|
+
}
|
|
3051
|
+
}, [timezone2]);
|
|
3052
|
+
const selectDate = import_react23.useCallback((date) => {
|
|
3053
|
+
setCurrentDate(date);
|
|
3054
|
+
}, []);
|
|
3055
|
+
const nextPeriod = import_react23.useCallback(() => {
|
|
3056
|
+
switch (view) {
|
|
3057
|
+
case "month":
|
|
3058
|
+
setCurrentDate((currentDate2) => currentDate2.add(1, "month"));
|
|
3059
|
+
break;
|
|
3060
|
+
case "week":
|
|
3061
|
+
setCurrentDate((currentDate2) => currentDate2.add(1, "week"));
|
|
3062
|
+
break;
|
|
3063
|
+
case "day":
|
|
3064
|
+
setCurrentDate((currentDate2) => currentDate2.add(1, "day"));
|
|
3065
|
+
break;
|
|
3066
|
+
case "year":
|
|
3067
|
+
setCurrentDate((currentDate2) => currentDate2.add(1, "year"));
|
|
3068
|
+
break;
|
|
3069
|
+
}
|
|
3070
|
+
}, [view]);
|
|
3071
|
+
const prevPeriod = import_react23.useCallback(() => {
|
|
3072
|
+
switch (view) {
|
|
3073
|
+
case "month":
|
|
3074
|
+
setCurrentDate((currentDate2) => currentDate2.subtract(1, "month"));
|
|
3075
|
+
break;
|
|
3076
|
+
case "week":
|
|
3077
|
+
setCurrentDate((currentDate2) => currentDate2.subtract(1, "week"));
|
|
3078
|
+
break;
|
|
3079
|
+
case "day":
|
|
3080
|
+
setCurrentDate((currentDate2) => currentDate2.subtract(1, "day"));
|
|
3081
|
+
break;
|
|
3082
|
+
case "year":
|
|
3083
|
+
setCurrentDate((currentDate2) => currentDate2.subtract(1, "year"));
|
|
3084
|
+
break;
|
|
3085
|
+
}
|
|
3086
|
+
}, [view]);
|
|
3087
|
+
const today = import_react23.useCallback(() => {
|
|
3088
|
+
setCurrentDate(import_dayjs17.default());
|
|
3089
|
+
}, []);
|
|
3090
|
+
const addEvent = import_react23.useCallback((event) => {
|
|
3091
|
+
setEvents((prevEvents) => [...prevEvents, event]);
|
|
3092
|
+
}, []);
|
|
3093
|
+
const updateEvent = import_react23.useCallback((eventId, updatedEvent) => {
|
|
3094
|
+
setEvents((prevEvents) => prevEvents.map((event) => event.id === eventId ? { ...event, ...updatedEvent } : event));
|
|
3095
|
+
}, []);
|
|
3096
|
+
const deleteEvent = import_react23.useCallback((eventId) => {
|
|
3097
|
+
setEvents((prevEvents) => prevEvents.filter((event) => event.id !== eventId));
|
|
3098
|
+
}, []);
|
|
3099
|
+
const editEvent = import_react23.useCallback((event) => {
|
|
3100
|
+
setSelectedEvent(event);
|
|
3101
|
+
setIsEventFormOpen(true);
|
|
3102
|
+
}, []);
|
|
3103
|
+
const closeEventForm = import_react23.useCallback(() => {
|
|
3104
|
+
setSelectedDate(null);
|
|
3105
|
+
setSelectedEvent(null);
|
|
3106
|
+
setIsEventFormOpen(false);
|
|
3107
|
+
}, []);
|
|
3108
|
+
const handleViewChange = import_react23.useCallback((newView) => {
|
|
3109
|
+
setView(newView);
|
|
3110
|
+
onViewChange?.(newView);
|
|
3111
|
+
}, [onViewChange]);
|
|
3112
|
+
const handleEventClick = import_react23.useCallback((event) => {
|
|
3113
|
+
if (disableCellClick)
|
|
3114
|
+
return;
|
|
3115
|
+
if (onEventClick) {
|
|
3116
|
+
onEventClick(event);
|
|
3117
|
+
} else {
|
|
3118
|
+
editEvent(event);
|
|
3119
|
+
}
|
|
3120
|
+
}, [disableCellClick, onEventClick, editEvent]);
|
|
3121
|
+
const handleDateClick = import_react23.useCallback((startDate, endDate) => {
|
|
3122
|
+
if (disableCellClick)
|
|
3123
|
+
return;
|
|
3124
|
+
if (onCellClick) {
|
|
3125
|
+
onCellClick(startDate, endDate);
|
|
3126
|
+
} else {
|
|
3127
|
+
setSelectedDate(startDate);
|
|
3128
|
+
setSelectedEvent({
|
|
3129
|
+
title: `New Event`,
|
|
3130
|
+
start: startDate,
|
|
3131
|
+
end: endDate,
|
|
3132
|
+
description: "",
|
|
3133
|
+
all_day: false,
|
|
3134
|
+
isRecurring: false,
|
|
3135
|
+
recurrence: null,
|
|
3136
|
+
parentEventId: null
|
|
3137
|
+
});
|
|
3138
|
+
setIsEventFormOpen(true);
|
|
3139
|
+
}
|
|
3140
|
+
}, [onCellClick, disableCellClick]);
|
|
3141
|
+
const getNextOccurrence = import_react23.useCallback((date, freq, int, days) => {
|
|
3142
|
+
switch (freq) {
|
|
3143
|
+
case "daily":
|
|
3144
|
+
return date.add(int, "day");
|
|
3145
|
+
case "weekly":
|
|
3146
|
+
if (days && days.length > 0) {
|
|
3147
|
+
let nextDate = date.add(1, "day");
|
|
3148
|
+
let loopCount = 0;
|
|
3149
|
+
while (loopCount < 7) {
|
|
3150
|
+
if (days.includes(nextDate.day())) {
|
|
3151
|
+
return nextDate;
|
|
3152
|
+
}
|
|
3153
|
+
nextDate = nextDate.add(1, "day");
|
|
3154
|
+
loopCount++;
|
|
3155
|
+
}
|
|
3156
|
+
return date.add(int, "week");
|
|
3157
|
+
} else {
|
|
3158
|
+
return date.add(int, "week");
|
|
3159
|
+
}
|
|
3160
|
+
case "monthly":
|
|
3161
|
+
return date.add(int, "month");
|
|
3162
|
+
case "yearly":
|
|
3163
|
+
return date.add(int, "year");
|
|
3164
|
+
}
|
|
3165
|
+
}, []);
|
|
3166
|
+
const expandRecurringEvent = import_react23.useCallback((baseEvent, startDate, endDate) => {
|
|
3167
|
+
const expandedEvents = [];
|
|
3168
|
+
if (!baseEvent.recurrence)
|
|
3169
|
+
return [baseEvent];
|
|
3170
|
+
const {
|
|
3171
|
+
frequency,
|
|
3172
|
+
interval,
|
|
3173
|
+
endDate: recurrenceEndDate,
|
|
3174
|
+
count,
|
|
3175
|
+
daysOfWeek,
|
|
3176
|
+
exceptions = []
|
|
3177
|
+
} = baseEvent.recurrence;
|
|
3178
|
+
const existingExceptions = events.filter((event) => event.parentEventId === baseEvent.id && event.isException);
|
|
3179
|
+
const duration = baseEvent.end.diff(baseEvent.start, "minute");
|
|
3180
|
+
const maxEndDate = recurrenceEndDate && recurrenceEndDate.isBefore(endDate) ? recurrenceEndDate : endDate;
|
|
3181
|
+
let currentDate2 = baseEvent.start.clone();
|
|
3182
|
+
let occurrences = 0;
|
|
3183
|
+
if (currentDate2.isAfter(maxEndDate)) {
|
|
3184
|
+
return [];
|
|
3185
|
+
}
|
|
3186
|
+
if (currentDate2.isBefore(startDate)) {
|
|
3187
|
+
switch (frequency) {
|
|
3188
|
+
case "daily": {
|
|
3189
|
+
const daysToAdd = Math.floor(startDate.diff(currentDate2, "day") / interval) * interval;
|
|
3190
|
+
if (daysToAdd > 0) {
|
|
3191
|
+
currentDate2 = currentDate2.add(daysToAdd, "day");
|
|
3192
|
+
}
|
|
3193
|
+
break;
|
|
3194
|
+
}
|
|
3195
|
+
case "weekly": {
|
|
3196
|
+
if (!daysOfWeek || daysOfWeek.length === 0) {
|
|
3197
|
+
const weeksToAdd = Math.floor(startDate.diff(currentDate2, "week") / interval) * interval;
|
|
3198
|
+
if (weeksToAdd > 0) {
|
|
3199
|
+
currentDate2 = currentDate2.add(weeksToAdd, "week");
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
break;
|
|
3203
|
+
}
|
|
3204
|
+
case "monthly": {
|
|
3205
|
+
const monthsToAdd = Math.floor(startDate.diff(currentDate2, "month") / interval) * interval;
|
|
3206
|
+
if (monthsToAdd > 0) {
|
|
3207
|
+
currentDate2 = currentDate2.add(monthsToAdd, "month");
|
|
3208
|
+
}
|
|
3209
|
+
break;
|
|
3210
|
+
}
|
|
3211
|
+
case "yearly": {
|
|
3212
|
+
const yearsToAdd = Math.floor(startDate.diff(currentDate2, "year") / interval) * interval;
|
|
3213
|
+
if (yearsToAdd > 0) {
|
|
3214
|
+
currentDate2 = currentDate2.add(yearsToAdd, "year");
|
|
3215
|
+
}
|
|
3216
|
+
break;
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
while ((currentDate2.isBefore(maxEndDate) || currentDate2.isSame(maxEndDate, "day")) && (count === undefined || occurrences < count)) {
|
|
3221
|
+
const currentDateStr = currentDate2.format("YYYY-MM-DD");
|
|
3222
|
+
if (exceptions.some((date) => date.format("YYYY-MM-DD") === currentDateStr)) {
|
|
3223
|
+
currentDate2 = getNextOccurrence(currentDate2, frequency, interval, daysOfWeek);
|
|
3224
|
+
continue;
|
|
3225
|
+
}
|
|
3226
|
+
if (frequency === "weekly" && daysOfWeek && daysOfWeek.length > 0 && !daysOfWeek.includes(currentDate2.day())) {
|
|
3227
|
+
currentDate2 = currentDate2.add(1, "day");
|
|
3228
|
+
continue;
|
|
3229
|
+
}
|
|
3230
|
+
const exceptionEvent = existingExceptions.find((event) => event.start.format("YYYY-MM-DD") === currentDateStr);
|
|
3231
|
+
if (exceptionEvent) {
|
|
3232
|
+
expandedEvents.push(exceptionEvent);
|
|
3233
|
+
} else if (currentDate2.isAfter(startDate.subtract(1, "day"))) {
|
|
3234
|
+
const eventInstance = {
|
|
3235
|
+
...baseEvent,
|
|
3236
|
+
id: `${baseEvent.id}-${currentDate2.format("YYYYMMDD")}`,
|
|
3237
|
+
start: currentDate2.clone(),
|
|
3238
|
+
end: currentDate2.clone().add(duration, "minute"),
|
|
3239
|
+
isRecurring: true,
|
|
3240
|
+
parentEventId: baseEvent.id
|
|
3241
|
+
};
|
|
3242
|
+
expandedEvents.push(eventInstance);
|
|
3243
|
+
}
|
|
3244
|
+
occurrences++;
|
|
3245
|
+
currentDate2 = getNextOccurrence(currentDate2, frequency, interval, daysOfWeek);
|
|
3246
|
+
}
|
|
3247
|
+
return expandedEvents;
|
|
3248
|
+
}, [events, getNextOccurrence]);
|
|
3249
|
+
const getEventsForDateRange = import_react23.useCallback((start, end) => {
|
|
3250
|
+
const startDate = start.startOf("day");
|
|
3251
|
+
const endDate = end.endOf("day");
|
|
3252
|
+
const regularEvents = events.filter((event) => {
|
|
3253
|
+
return (event.start.isAfter(startDate) || event.start.isSame(startDate)) && (event.start.isBefore(endDate) || event.start.isSame(endDate)) || (event.end.isAfter(startDate) || event.end.isSame(startDate)) && (event.end.isBefore(endDate) || event.end.isSame(endDate)) || event.start.isBefore(startDate) && event.end.isAfter(endDate);
|
|
3254
|
+
});
|
|
3255
|
+
const recurringParentEvents = events.filter((event) => event.recurrence && !event.parentEventId);
|
|
3256
|
+
let recurringEvents = [];
|
|
3257
|
+
recurringParentEvents.forEach((parentEvent) => {
|
|
3258
|
+
const expanded = expandRecurringEvent(parentEvent, startDate, endDate);
|
|
3259
|
+
recurringEvents = [...recurringEvents, ...expanded];
|
|
3260
|
+
});
|
|
3261
|
+
return [...regularEvents, ...recurringEvents].filter((event, index, self) => index === self.findIndex((e) => e.id === event.id));
|
|
3262
|
+
}, [events, expandRecurringEvent]);
|
|
3263
|
+
const getEventsForDate = import_react23.useCallback((date) => {
|
|
3264
|
+
const day = date.startOf("day");
|
|
3265
|
+
const nextDay = day.add(1, "day");
|
|
3266
|
+
return getEventsForDateRange(day, nextDay);
|
|
3267
|
+
}, [getEventsForDateRange]);
|
|
3268
|
+
const addRecurringEvent = import_react23.useCallback((event) => {
|
|
3269
|
+
setEvents((prevEvents) => [...prevEvents, event]);
|
|
3270
|
+
}, []);
|
|
3271
|
+
const deleteRecurringEvent = import_react23.useCallback((eventId, deleteAll) => {
|
|
3272
|
+
setEvents((prevEvents) => {
|
|
3273
|
+
const event = prevEvents.find((e) => e.id === eventId);
|
|
3274
|
+
if (!event)
|
|
3275
|
+
return prevEvents;
|
|
3276
|
+
if (event.parentEventId && !deleteAll) {
|
|
3277
|
+
const parentEvent = prevEvents.find((e) => e.id === event.parentEventId);
|
|
3278
|
+
if (!parentEvent || !parentEvent.recurrence)
|
|
3279
|
+
return prevEvents;
|
|
3280
|
+
return prevEvents.map((e) => {
|
|
3281
|
+
if (e.id === event.parentEventId) {
|
|
3282
|
+
return {
|
|
3283
|
+
...e,
|
|
3284
|
+
recurrence: {
|
|
3285
|
+
...e.recurrence,
|
|
3286
|
+
exceptions: [
|
|
3287
|
+
...e.recurrence.exceptions || [],
|
|
3288
|
+
event.start.startOf("day")
|
|
3289
|
+
]
|
|
3290
|
+
}
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
return e;
|
|
3294
|
+
});
|
|
3295
|
+
} else if (event.parentEventId && deleteAll) {
|
|
3296
|
+
return prevEvents.filter((e) => e.id !== event.parentEventId && e.parentEventId !== event.parentEventId);
|
|
3297
|
+
} else if (event.recurrence) {
|
|
3298
|
+
return prevEvents.filter((e) => e.id !== event.id && e.parentEventId !== event.id);
|
|
3299
|
+
} else {
|
|
3300
|
+
return prevEvents.filter((e) => e.id !== event.id);
|
|
3301
|
+
}
|
|
3302
|
+
});
|
|
3303
|
+
}, []);
|
|
3304
|
+
const updateRecurringEvent = import_react23.useCallback((eventId, updatedEvent, updateAll) => {
|
|
3305
|
+
setEvents((prevEvents) => {
|
|
3306
|
+
const event = prevEvents.find((e) => e.id === eventId);
|
|
3307
|
+
if (!event)
|
|
3308
|
+
return prevEvents;
|
|
3309
|
+
if (event.parentEventId && !updateAll) {
|
|
3310
|
+
const exceptionEvent = {
|
|
3311
|
+
...event,
|
|
3312
|
+
...updatedEvent,
|
|
3313
|
+
isException: true
|
|
3314
|
+
};
|
|
3315
|
+
const updatedEvents = prevEvents.map((e) => {
|
|
3316
|
+
if (e.id === event.parentEventId) {
|
|
3317
|
+
return {
|
|
3318
|
+
...e,
|
|
3319
|
+
recurrence: {
|
|
3320
|
+
...e.recurrence,
|
|
3321
|
+
exceptions: [
|
|
3322
|
+
...e.recurrence.exceptions || [],
|
|
3323
|
+
event.start.startOf("day")
|
|
3324
|
+
]
|
|
3325
|
+
}
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
return e;
|
|
3329
|
+
});
|
|
3330
|
+
return [...updatedEvents, exceptionEvent];
|
|
3331
|
+
} else if (event.parentEventId && updateAll) {
|
|
3332
|
+
return prevEvents.map((e) => {
|
|
3333
|
+
if (e.id === event.parentEventId) {
|
|
3334
|
+
return { ...e, ...updatedEvent };
|
|
3335
|
+
}
|
|
3336
|
+
return e;
|
|
3337
|
+
});
|
|
3338
|
+
} else if (event.recurrence) {
|
|
3339
|
+
return prevEvents.map((e) => {
|
|
3340
|
+
if (e.id === event.id) {
|
|
3341
|
+
return { ...e, ...updatedEvent };
|
|
3342
|
+
}
|
|
3343
|
+
return e;
|
|
3344
|
+
});
|
|
3345
|
+
} else {
|
|
3346
|
+
return prevEvents.map((e) => {
|
|
3347
|
+
if (e.id === event.id) {
|
|
3348
|
+
return { ...e, ...updatedEvent };
|
|
3349
|
+
}
|
|
3350
|
+
return e;
|
|
3351
|
+
});
|
|
3352
|
+
}
|
|
3353
|
+
});
|
|
3354
|
+
}, []);
|
|
3355
|
+
const createExceptionForRecurringEvent = import_react23.useCallback((eventId, date) => {
|
|
3356
|
+
setEvents((prevEvents) => {
|
|
3357
|
+
const event = prevEvents.find((e) => e.id === eventId);
|
|
3358
|
+
if (!event || !event.recurrence)
|
|
3359
|
+
return prevEvents;
|
|
3360
|
+
return prevEvents.map((e) => {
|
|
3361
|
+
if (e.id === eventId) {
|
|
3362
|
+
return {
|
|
3363
|
+
...e,
|
|
3364
|
+
recurrence: {
|
|
3365
|
+
...e.recurrence,
|
|
3366
|
+
exceptions: [
|
|
3367
|
+
...e.recurrence.exceptions || [],
|
|
3368
|
+
date.startOf("day")
|
|
3369
|
+
]
|
|
3370
|
+
}
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
return e;
|
|
3374
|
+
});
|
|
3375
|
+
});
|
|
3376
|
+
}, []);
|
|
3377
|
+
const contextValue = import_react23.useMemo(() => ({
|
|
3378
|
+
currentDate,
|
|
3379
|
+
view,
|
|
3380
|
+
events,
|
|
3381
|
+
currentLocale,
|
|
3382
|
+
isEventFormOpen,
|
|
3383
|
+
selectedEvent,
|
|
3384
|
+
selectedDate,
|
|
3385
|
+
firstDayOfWeek,
|
|
3386
|
+
setCurrentDate,
|
|
3387
|
+
selectDate,
|
|
3388
|
+
setView: handleViewChange,
|
|
3389
|
+
nextPeriod,
|
|
3390
|
+
prevPeriod,
|
|
3391
|
+
today,
|
|
3392
|
+
addEvent,
|
|
3393
|
+
updateEvent,
|
|
3394
|
+
deleteEvent,
|
|
3395
|
+
openEventForm: () => setIsEventFormOpen(true),
|
|
3396
|
+
closeEventForm,
|
|
3397
|
+
getEventsForDate,
|
|
3398
|
+
getEventsForDateRange,
|
|
3399
|
+
expandRecurringEvent,
|
|
3400
|
+
addRecurringEvent,
|
|
3401
|
+
deleteRecurringEvent,
|
|
3402
|
+
updateRecurringEvent,
|
|
3403
|
+
createExceptionForRecurringEvent,
|
|
3404
|
+
renderEvent,
|
|
3405
|
+
onEventClick: handleEventClick,
|
|
3406
|
+
onCellClick: handleDateClick,
|
|
3407
|
+
locale,
|
|
3408
|
+
timezone: timezone2,
|
|
3409
|
+
disableCellClick,
|
|
3410
|
+
disableEventClick,
|
|
3411
|
+
disableDragAndDrop,
|
|
3412
|
+
dayMaxEvents,
|
|
3413
|
+
stickyHeader
|
|
3414
|
+
}), [
|
|
3415
|
+
currentDate,
|
|
3416
|
+
view,
|
|
3417
|
+
events,
|
|
3418
|
+
currentLocale,
|
|
3419
|
+
isEventFormOpen,
|
|
3420
|
+
selectedEvent,
|
|
3421
|
+
selectedDate,
|
|
3422
|
+
firstDayOfWeek,
|
|
3423
|
+
selectDate,
|
|
3424
|
+
handleViewChange,
|
|
3425
|
+
nextPeriod,
|
|
3426
|
+
prevPeriod,
|
|
3427
|
+
today,
|
|
3428
|
+
addEvent,
|
|
3429
|
+
updateEvent,
|
|
3430
|
+
deleteEvent,
|
|
3431
|
+
closeEventForm,
|
|
3432
|
+
getEventsForDate,
|
|
3433
|
+
getEventsForDateRange,
|
|
3434
|
+
expandRecurringEvent,
|
|
3435
|
+
addRecurringEvent,
|
|
3436
|
+
deleteRecurringEvent,
|
|
3437
|
+
updateRecurringEvent,
|
|
3438
|
+
createExceptionForRecurringEvent,
|
|
3439
|
+
renderEvent,
|
|
3440
|
+
handleEventClick,
|
|
3441
|
+
handleDateClick,
|
|
3442
|
+
locale,
|
|
3443
|
+
timezone2,
|
|
3444
|
+
disableCellClick,
|
|
3445
|
+
disableEventClick,
|
|
3446
|
+
disableDragAndDrop,
|
|
3447
|
+
dayMaxEvents,
|
|
3448
|
+
stickyHeader
|
|
3449
|
+
]);
|
|
3450
|
+
return /* @__PURE__ */ jsx_dev_runtime47.jsxDEV(CalendarContext.Provider, {
|
|
3451
|
+
value: contextValue,
|
|
3452
|
+
children
|
|
3453
|
+
}, undefined, false, undefined, this);
|
|
3454
|
+
};
|
|
3455
|
+
|
|
3456
|
+
// src/components/ilamy-calendar/ilamy-calendar.tsx
|
|
3457
|
+
var jsx_dev_runtime48 = require("react/jsx-dev-runtime");
|
|
3458
|
+
var CalendarContent = () => {
|
|
3459
|
+
const {
|
|
3460
|
+
view,
|
|
3461
|
+
isEventFormOpen,
|
|
3462
|
+
closeEventForm,
|
|
3463
|
+
selectedEvent,
|
|
3464
|
+
selectedDate,
|
|
3465
|
+
addEvent,
|
|
3466
|
+
updateEvent,
|
|
3467
|
+
deleteEvent,
|
|
3468
|
+
dayMaxEvents
|
|
3469
|
+
} = useCalendarContext();
|
|
3470
|
+
const viewMap = {
|
|
3471
|
+
month: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(MonthView, {
|
|
3472
|
+
dayMaxEvents
|
|
3473
|
+
}, "month", false, undefined, this),
|
|
3474
|
+
week: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(week_view_default, {}, "week", false, undefined, this),
|
|
3475
|
+
day: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(day_view_default, {}, "day", false, undefined, this),
|
|
3476
|
+
year: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(year_view_default, {}, "year", false, undefined, this)
|
|
3477
|
+
};
|
|
3478
|
+
const handleOnUpdate = (event) => {
|
|
3479
|
+
updateEvent(event.id, event);
|
|
3480
|
+
};
|
|
3481
|
+
const handleOnDelete = (event) => {
|
|
3482
|
+
deleteEvent(event.id);
|
|
3483
|
+
};
|
|
3484
|
+
return /* @__PURE__ */ jsx_dev_runtime48.jsxDEV("div", {
|
|
3485
|
+
className: "flex flex-col w-full h-full",
|
|
3486
|
+
children: [
|
|
3487
|
+
/* @__PURE__ */ jsx_dev_runtime48.jsxDEV(base_header_default, {}, undefined, false, undefined, this),
|
|
3488
|
+
/* @__PURE__ */ jsx_dev_runtime48.jsxDEV(CalendarDndContext, {
|
|
3489
|
+
children: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(import_react24.AnimatePresence, {
|
|
3490
|
+
mode: "wait",
|
|
3491
|
+
children: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(import_react24.motion.div, {
|
|
3492
|
+
initial: { opacity: 0, x: 20 },
|
|
3493
|
+
animate: { opacity: 1, x: 0 },
|
|
3494
|
+
exit: { opacity: 0, x: -20 },
|
|
3495
|
+
transition: { duration: 0.1, ease: "easeInOut" },
|
|
3496
|
+
className: "h-full w-full",
|
|
3497
|
+
children: viewMap[view]
|
|
3498
|
+
}, view, false, undefined, this)
|
|
3499
|
+
}, undefined, false, undefined, this)
|
|
3500
|
+
}, undefined, false, undefined, this),
|
|
3501
|
+
isEventFormOpen && /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(EventForm, {
|
|
3502
|
+
onClose: closeEventForm,
|
|
3503
|
+
selectedEvent,
|
|
3504
|
+
selectedDate,
|
|
3505
|
+
onAdd: addEvent,
|
|
3506
|
+
onUpdate: handleOnUpdate,
|
|
3507
|
+
onDelete: handleOnDelete
|
|
3508
|
+
}, undefined, false, undefined, this)
|
|
3509
|
+
]
|
|
3510
|
+
}, undefined, true, undefined, this);
|
|
3511
|
+
};
|
|
3512
|
+
var dayNumberMap = {
|
|
3513
|
+
sunday: 0,
|
|
3514
|
+
monday: 1,
|
|
3515
|
+
tuesday: 2,
|
|
3516
|
+
wednesday: 3,
|
|
3517
|
+
thursday: 4,
|
|
3518
|
+
friday: 5,
|
|
3519
|
+
saturday: 6
|
|
3520
|
+
};
|
|
3521
|
+
var DEFAULT_DAY_MAX_EVENTS = 6;
|
|
3522
|
+
var IlamyCalendar = ({
|
|
3523
|
+
events,
|
|
3524
|
+
firstDayOfWeek = "sunday",
|
|
3525
|
+
renderEvent,
|
|
3526
|
+
onEventClick,
|
|
3527
|
+
onCellClick,
|
|
3528
|
+
onViewChange,
|
|
3529
|
+
locale,
|
|
3530
|
+
timezone: timezone2,
|
|
3531
|
+
disableCellClick,
|
|
3532
|
+
disableEventClick,
|
|
3533
|
+
disableDragAndDrop,
|
|
3534
|
+
dayMaxEvents = DEFAULT_DAY_MAX_EVENTS,
|
|
3535
|
+
stickyHeader = true
|
|
3536
|
+
}) => {
|
|
3537
|
+
return /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(CalendarProvider, {
|
|
3538
|
+
initialEvents: events,
|
|
3539
|
+
firstDayOfWeek: dayNumberMap[firstDayOfWeek],
|
|
3540
|
+
renderEvent,
|
|
3541
|
+
onEventClick,
|
|
3542
|
+
onCellClick,
|
|
3543
|
+
onViewChange,
|
|
3544
|
+
locale,
|
|
3545
|
+
timezone: timezone2,
|
|
3546
|
+
disableCellClick,
|
|
3547
|
+
disableEventClick,
|
|
3548
|
+
disableDragAndDrop,
|
|
3549
|
+
dayMaxEvents,
|
|
3550
|
+
stickyHeader,
|
|
3551
|
+
children: /* @__PURE__ */ jsx_dev_runtime48.jsxDEV(CalendarContent, {}, undefined, false, undefined, this)
|
|
3552
|
+
}, undefined, false, undefined, this);
|
|
3553
|
+
};
|