calendarkit-pro 1.2.1 → 1.3.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/README.md +24 -2
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1024 -712
- package/dist/index.mjs +1001 -686
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
cn: () => cn
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
var
|
|
38
|
+
var import_react20 = __toESM(require("react"));
|
|
39
39
|
var import_core3 = require("@dnd-kit/core");
|
|
40
40
|
var import_modifiers = require("@dnd-kit/modifiers");
|
|
41
41
|
var import_framer_motion4 = require("framer-motion");
|
|
@@ -200,19 +200,24 @@ var import_lucide_react3 = require("lucide-react");
|
|
|
200
200
|
var import_react2 = __toESM(require("react"));
|
|
201
201
|
var import_date_fns3 = require("date-fns");
|
|
202
202
|
|
|
203
|
-
// src/
|
|
203
|
+
// src/core/week.ts
|
|
204
204
|
var import_date_fns2 = require("date-fns");
|
|
205
|
-
|
|
205
|
+
function resolveWeekStartsOn(locale, fallback) {
|
|
206
|
+
return locale?.options?.weekStartsOn ?? fallback;
|
|
207
|
+
}
|
|
208
|
+
function getWeekDays(date, weekStartsOn) {
|
|
209
|
+
return (0, import_date_fns2.eachDayOfInterval)({
|
|
210
|
+
start: (0, import_date_fns2.startOfWeek)(date, { weekStartsOn }),
|
|
211
|
+
end: (0, import_date_fns2.endOfWeek)(date, { weekStartsOn })
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function getMonthGrid(date, weekStartsOn) {
|
|
206
215
|
const monthStart = (0, import_date_fns2.startOfMonth)(date);
|
|
207
216
|
return (0, import_date_fns2.eachDayOfInterval)({
|
|
208
|
-
start: (0, import_date_fns2.startOfWeek)(monthStart, { weekStartsOn
|
|
209
|
-
end: (0, import_date_fns2.endOfWeek)((0, import_date_fns2.endOfMonth)(monthStart), { weekStartsOn
|
|
217
|
+
start: (0, import_date_fns2.startOfWeek)(monthStart, { weekStartsOn }),
|
|
218
|
+
end: (0, import_date_fns2.endOfWeek)((0, import_date_fns2.endOfMonth)(monthStart), { weekStartsOn })
|
|
210
219
|
});
|
|
211
|
-
}
|
|
212
|
-
var uses24HourClock = (locale) => {
|
|
213
|
-
if (!locale) return false;
|
|
214
|
-
return !/[ap]\.?m/i.test((0, import_date_fns2.format)(new Date(2e3, 0, 1, 13, 0), "p", { locale }));
|
|
215
|
-
};
|
|
220
|
+
}
|
|
216
221
|
|
|
217
222
|
// src/components/MiniCalendar.tsx
|
|
218
223
|
var import_lucide_react2 = require("lucide-react");
|
|
@@ -227,7 +232,7 @@ var MiniCalendar = ({
|
|
|
227
232
|
import_react2.default.useEffect(() => {
|
|
228
233
|
setViewDate(currentDate);
|
|
229
234
|
}, [currentDate]);
|
|
230
|
-
const weekStartsOn = locale
|
|
235
|
+
const weekStartsOn = resolveWeekStartsOn(locale, 0);
|
|
231
236
|
const days = import_react2.default.useMemo(
|
|
232
237
|
() => getMonthGrid(viewDate, weekStartsOn),
|
|
233
238
|
[viewDate, weekStartsOn]
|
|
@@ -296,7 +301,195 @@ var MiniCalendar = ({
|
|
|
296
301
|
|
|
297
302
|
// src/components/Sidebar.tsx
|
|
298
303
|
var import_date_fns_tz = require("date-fns-tz");
|
|
304
|
+
var import_date_fns5 = require("date-fns");
|
|
305
|
+
|
|
306
|
+
// src/core/format.ts
|
|
299
307
|
var import_date_fns4 = require("date-fns");
|
|
308
|
+
|
|
309
|
+
// src/locales/index.ts
|
|
310
|
+
var en = {
|
|
311
|
+
today: "Today",
|
|
312
|
+
month: "Month",
|
|
313
|
+
week: "Week",
|
|
314
|
+
day: "Day",
|
|
315
|
+
agenda: "Agenda",
|
|
316
|
+
resource: "Resources",
|
|
317
|
+
createEvent: "Create Event",
|
|
318
|
+
editEvent: "Edit Event",
|
|
319
|
+
delete: "Delete",
|
|
320
|
+
save: "Save",
|
|
321
|
+
cancel: "Cancel",
|
|
322
|
+
title: "Add title",
|
|
323
|
+
start: "Start",
|
|
324
|
+
end: "End",
|
|
325
|
+
allDay: "All Day",
|
|
326
|
+
description: "Description",
|
|
327
|
+
repeat: "Repeat",
|
|
328
|
+
noRepeat: "Does not repeat",
|
|
329
|
+
selectCalendar: "Select Calendar",
|
|
330
|
+
selectType: "Select Type",
|
|
331
|
+
daily: "Daily",
|
|
332
|
+
weekly: "Weekly",
|
|
333
|
+
monthly: "Monthly",
|
|
334
|
+
yearly: "Yearly",
|
|
335
|
+
search: "Search events...",
|
|
336
|
+
allTypes: "All Types",
|
|
337
|
+
timezone: "Time zone",
|
|
338
|
+
localTime: "Local Time",
|
|
339
|
+
create: "Create",
|
|
340
|
+
calendars: "Calendars",
|
|
341
|
+
event: "Event",
|
|
342
|
+
task: "Task",
|
|
343
|
+
appointmentSchedule: "Appointment schedule",
|
|
344
|
+
new: "New",
|
|
345
|
+
dateAndTime: "Date & Time",
|
|
346
|
+
whosJoining: "Who's joining?",
|
|
347
|
+
suggestedTimes: "Suggested times for guests",
|
|
348
|
+
viewSuggestions: "View suggestions",
|
|
349
|
+
whereWillItBe: "Where will it be?",
|
|
350
|
+
location: "Enter address",
|
|
351
|
+
descriptionAndAttachments: "Description",
|
|
352
|
+
dragAndDrop: "Drag & drop files or",
|
|
353
|
+
guests: "Guests",
|
|
354
|
+
addGuests: "Add guests",
|
|
355
|
+
addAttachment: "Upload files",
|
|
356
|
+
moreOptions: "More options",
|
|
357
|
+
doesNotRepeat: "Does not repeat",
|
|
358
|
+
locationHelpText: 'Enter a physical address (e.g. "123 Main St") to generate the map.',
|
|
359
|
+
notes: "Notes...",
|
|
360
|
+
guestCount: "guest",
|
|
361
|
+
guestsCount: "guests",
|
|
362
|
+
repeatFor: "Repeat for",
|
|
363
|
+
times: "times",
|
|
364
|
+
until: "Until",
|
|
365
|
+
endRepeat: "End repeat",
|
|
366
|
+
never: "Never",
|
|
367
|
+
afterOccurrences: "After occurrences",
|
|
368
|
+
onDate: "On date",
|
|
369
|
+
tomorrow: "Tomorrow",
|
|
370
|
+
edit: "Edit",
|
|
371
|
+
duplicate: "Duplicate",
|
|
372
|
+
eventSingular: "event",
|
|
373
|
+
eventPlural: "events",
|
|
374
|
+
allCaughtUp: "All caught up!",
|
|
375
|
+
noEventsScheduled: "No events scheduled",
|
|
376
|
+
noUpcoming: "Your schedule is clear",
|
|
377
|
+
noUpcomingHint: "No upcoming events to show. Create a new event to start planning."
|
|
378
|
+
};
|
|
379
|
+
var fr = {
|
|
380
|
+
today: "Aujourd'hui",
|
|
381
|
+
month: "Mois",
|
|
382
|
+
week: "Semaine",
|
|
383
|
+
day: "Jour",
|
|
384
|
+
agenda: "Agenda",
|
|
385
|
+
resource: "Ressources",
|
|
386
|
+
createEvent: "Cr\xE9er un \xE9v\xE9nement",
|
|
387
|
+
editEvent: "Modifier l'\xE9v\xE9nement",
|
|
388
|
+
delete: "Supprimer",
|
|
389
|
+
save: "Enregistrer",
|
|
390
|
+
cancel: "Annuler",
|
|
391
|
+
title: "Ajouter un titre",
|
|
392
|
+
start: "D\xE9but",
|
|
393
|
+
end: "Fin",
|
|
394
|
+
allDay: "Toute la journ\xE9e",
|
|
395
|
+
description: "Description",
|
|
396
|
+
repeat: "R\xE9p\xE9ter",
|
|
397
|
+
noRepeat: "Ne se r\xE9p\xE8te pas",
|
|
398
|
+
selectCalendar: "S\xE9lectionner un calendrier",
|
|
399
|
+
selectType: "S\xE9lectionner un type",
|
|
400
|
+
daily: "Quotidien",
|
|
401
|
+
weekly: "Hebdomadaire",
|
|
402
|
+
monthly: "Mensuel",
|
|
403
|
+
yearly: "Annuel",
|
|
404
|
+
search: "Rechercher...",
|
|
405
|
+
allTypes: "Tous les types",
|
|
406
|
+
timezone: "Fuseau horaire",
|
|
407
|
+
localTime: "Heure locale",
|
|
408
|
+
create: "Cr\xE9er",
|
|
409
|
+
calendars: "Calendriers",
|
|
410
|
+
event: "\xC9v\xE9nement",
|
|
411
|
+
task: "T\xE2che",
|
|
412
|
+
appointmentSchedule: "Planning de rendez-vous",
|
|
413
|
+
new: "Nouveau",
|
|
414
|
+
dateAndTime: "Date et heure",
|
|
415
|
+
whosJoining: "Qui participe ?",
|
|
416
|
+
suggestedTimes: "Horaires sugg\xE9r\xE9s",
|
|
417
|
+
viewSuggestions: "Voir les suggestions",
|
|
418
|
+
whereWillItBe: "O\xF9 aura lieu ?",
|
|
419
|
+
location: "Entrer une adresse",
|
|
420
|
+
descriptionAndAttachments: "Description",
|
|
421
|
+
dragAndDrop: "Glisser-d\xE9poser des fichiers ou",
|
|
422
|
+
guests: "Invit\xE9s",
|
|
423
|
+
addGuests: "Ajouter des invit\xE9s",
|
|
424
|
+
addAttachment: "T\xE9l\xE9charger des fichiers",
|
|
425
|
+
moreOptions: "Plus d'options",
|
|
426
|
+
doesNotRepeat: "Ne se r\xE9p\xE8te pas",
|
|
427
|
+
locationHelpText: 'Entrez une adresse physique (ex: "123 Rue Principale") pour g\xE9n\xE9rer la carte.',
|
|
428
|
+
notes: "Notes...",
|
|
429
|
+
guestCount: "invit\xE9",
|
|
430
|
+
guestsCount: "invit\xE9s",
|
|
431
|
+
repeatFor: "R\xE9p\xE9ter pendant",
|
|
432
|
+
times: "fois",
|
|
433
|
+
until: "Jusqu'au",
|
|
434
|
+
endRepeat: "Fin de r\xE9p\xE9tition",
|
|
435
|
+
never: "Jamais",
|
|
436
|
+
afterOccurrences: "Apr\xE8s occurrences",
|
|
437
|
+
onDate: "\xC0 la date",
|
|
438
|
+
tomorrow: "Demain",
|
|
439
|
+
edit: "Modifier",
|
|
440
|
+
duplicate: "Dupliquer",
|
|
441
|
+
eventSingular: "\xE9v\xE9nement",
|
|
442
|
+
eventPlural: "\xE9v\xE9nements",
|
|
443
|
+
allCaughtUp: "Tout est \xE0 jour !",
|
|
444
|
+
noEventsScheduled: "Aucun \xE9v\xE9nement pr\xE9vu",
|
|
445
|
+
noUpcoming: "Votre planning est libre",
|
|
446
|
+
noUpcomingHint: "Aucun \xE9v\xE9nement \xE0 venir. Cr\xE9ez un nouvel \xE9v\xE9nement pour commencer \xE0 planifier."
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// src/core/format.ts
|
|
450
|
+
var clockCache = /* @__PURE__ */ new WeakMap();
|
|
451
|
+
function uses24HourClock(locale) {
|
|
452
|
+
if (!locale) return false;
|
|
453
|
+
let is24 = clockCache.get(locale);
|
|
454
|
+
if (is24 === void 0) {
|
|
455
|
+
is24 = !/[ap]\.?m/i.test((0, import_date_fns4.format)(new Date(2e3, 0, 1, 13, 0), "p", { locale }));
|
|
456
|
+
clockCache.set(locale, is24);
|
|
457
|
+
}
|
|
458
|
+
return is24;
|
|
459
|
+
}
|
|
460
|
+
var H24 = { hour: "H:mm", time: "H:mm", compact: "H:mm" };
|
|
461
|
+
var H12 = { hour: "h a", time: "h:mm a", compact: "h:mm" };
|
|
462
|
+
function timeFormats(locale) {
|
|
463
|
+
return uses24HourClock(locale) ? H24 : H12;
|
|
464
|
+
}
|
|
465
|
+
var MAX_FORMATTERS = 50;
|
|
466
|
+
var formatters = /* @__PURE__ */ new Map();
|
|
467
|
+
function getDateTimeFormat(locale, timeZone, options) {
|
|
468
|
+
const key = `${locale}|${timeZone ?? ""}|${JSON.stringify(options)}`;
|
|
469
|
+
let formatter = formatters.get(key);
|
|
470
|
+
if (formatter) {
|
|
471
|
+
formatters.delete(key);
|
|
472
|
+
} else {
|
|
473
|
+
formatter = new Intl.DateTimeFormat(locale, { ...options, timeZone });
|
|
474
|
+
if (formatters.size >= MAX_FORMATTERS) {
|
|
475
|
+
formatters.delete(formatters.keys().next().value);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
formatters.set(key, formatter);
|
|
479
|
+
return formatter;
|
|
480
|
+
}
|
|
481
|
+
function timeZoneAbbreviation(date, timeZone) {
|
|
482
|
+
try {
|
|
483
|
+
return getDateTimeFormat("en-US", timeZone, { timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value ?? "";
|
|
484
|
+
} catch {
|
|
485
|
+
return "";
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function resolveTranslations(language, overrides) {
|
|
489
|
+
return { ...language === "fr" ? fr : en, ...overrides };
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/components/Sidebar.tsx
|
|
300
493
|
var Sidebar = ({
|
|
301
494
|
currentDate,
|
|
302
495
|
onDateChange,
|
|
@@ -327,14 +520,7 @@ var Sidebar = ({
|
|
|
327
520
|
{ id: "3", label: "Tasks", color: "#6366f1", active: true }
|
|
328
521
|
];
|
|
329
522
|
const displayCalendars = calendars || defaultCalendars;
|
|
330
|
-
const getAcronym = (tz) =>
|
|
331
|
-
if (!tz || !now) return "LOC";
|
|
332
|
-
try {
|
|
333
|
-
return new Intl.DateTimeFormat("en-US", { timeZone: tz, timeZoneName: "short" }).formatToParts(now).find((part) => part.type === "timeZoneName")?.value || "";
|
|
334
|
-
} catch {
|
|
335
|
-
return "";
|
|
336
|
-
}
|
|
337
|
-
};
|
|
523
|
+
const getAcronym = (tz) => !tz || !now ? "LOC" : timeZoneAbbreviation(now, tz);
|
|
338
524
|
const timezones = [
|
|
339
525
|
{ value: "", label: translations?.localTime || "Local Time", acronym: "LOC" },
|
|
340
526
|
{ value: "UTC", label: "UTC", acronym: "UTC" },
|
|
@@ -358,14 +544,11 @@ var Sidebar = ({
|
|
|
358
544
|
let acronym = tz.acronym;
|
|
359
545
|
try {
|
|
360
546
|
if (!tz.value) {
|
|
361
|
-
time = (0,
|
|
362
|
-
|
|
363
|
-
acronym = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(now).find((part) => part.type === "timeZoneName")?.value || "LOC";
|
|
364
|
-
} catch {
|
|
365
|
-
}
|
|
547
|
+
time = (0, import_date_fns5.format)(now, "HH:mm");
|
|
548
|
+
acronym = timeZoneAbbreviation(now) || "LOC";
|
|
366
549
|
} else {
|
|
367
550
|
const zDate = (0, import_date_fns_tz.toZonedTime)(now, tz.value);
|
|
368
|
-
time = (0,
|
|
551
|
+
time = (0, import_date_fns5.format)(zDate, "HH:mm");
|
|
369
552
|
const dynAcronym = getAcronym(tz.value);
|
|
370
553
|
if (dynAcronym && !dynAcronym.includes("GMT") && !dynAcronym.includes("Time")) {
|
|
371
554
|
acronym = dynAcronym;
|
|
@@ -458,31 +641,197 @@ var Sidebar = ({
|
|
|
458
641
|
|
|
459
642
|
// src/views/MonthView.tsx
|
|
460
643
|
var import_react6 = __toESM(require("react"));
|
|
461
|
-
var
|
|
644
|
+
var import_date_fns8 = require("date-fns");
|
|
645
|
+
|
|
646
|
+
// src/core/events.ts
|
|
647
|
+
var import_date_fns7 = require("date-fns");
|
|
648
|
+
|
|
649
|
+
// src/core/timezone.ts
|
|
650
|
+
var import_date_fns6 = require("date-fns");
|
|
462
651
|
var import_date_fns_tz2 = require("date-fns-tz");
|
|
463
652
|
|
|
653
|
+
// src/core/warn.ts
|
|
654
|
+
var warned = /* @__PURE__ */ new Set();
|
|
655
|
+
function isProductionBuild() {
|
|
656
|
+
try {
|
|
657
|
+
return process.env.NODE_ENV === "production";
|
|
658
|
+
} catch {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function warnOnce(key, message) {
|
|
663
|
+
if (isProductionBuild() || warned.has(key)) return;
|
|
664
|
+
warned.add(key);
|
|
665
|
+
console.warn(`[calendarkit-pro] ${message}`);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/core/timezone.ts
|
|
669
|
+
var validity = /* @__PURE__ */ new Map();
|
|
670
|
+
function resolveTimeZone(tz) {
|
|
671
|
+
if (!tz) return void 0;
|
|
672
|
+
let valid = validity.get(tz);
|
|
673
|
+
if (valid === void 0) {
|
|
674
|
+
try {
|
|
675
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
676
|
+
valid = true;
|
|
677
|
+
} catch {
|
|
678
|
+
valid = false;
|
|
679
|
+
}
|
|
680
|
+
validity.set(tz, valid);
|
|
681
|
+
}
|
|
682
|
+
if (!valid) {
|
|
683
|
+
warnOnce(`invalid-timezone:${tz}`, `Unknown timezone "${tz}", falling back to local time.`);
|
|
684
|
+
return void 0;
|
|
685
|
+
}
|
|
686
|
+
return tz;
|
|
687
|
+
}
|
|
688
|
+
function toDisplay(date, tz) {
|
|
689
|
+
const zone = resolveTimeZone(tz);
|
|
690
|
+
return zone ? (0, import_date_fns_tz2.toZonedTime)(date, zone) : date;
|
|
691
|
+
}
|
|
692
|
+
function fromDisplay(wall, tz) {
|
|
693
|
+
const zone = resolveTimeZone(tz);
|
|
694
|
+
return zone ? (0, import_date_fns_tz2.fromZonedTime)(wall, zone) : new Date(wall);
|
|
695
|
+
}
|
|
696
|
+
function minutesSinceDisplayMidnight(date, tz) {
|
|
697
|
+
const wall = toDisplay(date, tz);
|
|
698
|
+
return wall.getHours() * 60 + wall.getMinutes();
|
|
699
|
+
}
|
|
700
|
+
function isSameDisplayDay(date, day, tz) {
|
|
701
|
+
return (0, import_date_fns6.isSameDay)(toDisplay(date, tz), day);
|
|
702
|
+
}
|
|
703
|
+
function displayToday(tz, now = /* @__PURE__ */ new Date()) {
|
|
704
|
+
return (0, import_date_fns6.startOfDay)(toDisplay(now, tz));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// src/core/events.ts
|
|
708
|
+
var toDate = (value) => value === void 0 || value === null ? void 0 : value instanceof Date ? value : new Date(value);
|
|
709
|
+
var isValidDate = (date) => !!date && !Number.isNaN(date.getTime());
|
|
710
|
+
var normalizedEvent = /* @__PURE__ */ new WeakMap();
|
|
711
|
+
var normalizedList = /* @__PURE__ */ new WeakMap();
|
|
712
|
+
function normalizeEvent(event) {
|
|
713
|
+
const cached = normalizedEvent.get(event);
|
|
714
|
+
if (cached !== void 0) return cached;
|
|
715
|
+
const start = toDate(event.start);
|
|
716
|
+
const end = toDate(event.end);
|
|
717
|
+
let result = null;
|
|
718
|
+
if (!isValidDate(start) || !isValidDate(end)) {
|
|
719
|
+
warnOnce(`invalid-date:${event.id}`, `Event "${event.id}" has an invalid start or end date and was skipped.`);
|
|
720
|
+
} else if (end.getTime() < start.getTime()) {
|
|
721
|
+
warnOnce(`end-before-start:${event.id}`, `Event "${event.id}" ends before it starts and was skipped.`);
|
|
722
|
+
} else {
|
|
723
|
+
const needsCopy = start !== event.start || end !== event.end || needsRecurrenceCopy(event);
|
|
724
|
+
result = needsCopy ? {
|
|
725
|
+
...event,
|
|
726
|
+
start,
|
|
727
|
+
end,
|
|
728
|
+
recurrence: event.recurrence && {
|
|
729
|
+
...event.recurrence,
|
|
730
|
+
until: toDate(event.recurrence.until),
|
|
731
|
+
exdates: event.recurrence.exdates?.map((d) => toDate(d))
|
|
732
|
+
}
|
|
733
|
+
} : event;
|
|
734
|
+
}
|
|
735
|
+
normalizedEvent.set(event, result);
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
function needsRecurrenceCopy(event) {
|
|
739
|
+
const r = event.recurrence;
|
|
740
|
+
if (!r) return false;
|
|
741
|
+
return r.until !== void 0 && !(r.until instanceof Date) || !!r.exdates?.some((d) => !(d instanceof Date));
|
|
742
|
+
}
|
|
743
|
+
function normalizeEvents(events) {
|
|
744
|
+
const cached = normalizedList.get(events);
|
|
745
|
+
if (cached) return cached;
|
|
746
|
+
const seen = /* @__PURE__ */ new Set();
|
|
747
|
+
const result = [];
|
|
748
|
+
for (const event of events) {
|
|
749
|
+
const normalized = normalizeEvent(event);
|
|
750
|
+
if (!normalized) continue;
|
|
751
|
+
if (seen.has(normalized.id)) {
|
|
752
|
+
warnOnce(`duplicate-id:${normalized.id}`, `Duplicate event id "${normalized.id}": ids must be unique.`);
|
|
753
|
+
}
|
|
754
|
+
seen.add(normalized.id);
|
|
755
|
+
result.push(normalized);
|
|
756
|
+
}
|
|
757
|
+
normalizedList.set(events, result);
|
|
758
|
+
return result;
|
|
759
|
+
}
|
|
760
|
+
var dayKey = (wall) => (0, import_date_fns7.format)(wall, "yyyy-MM-dd");
|
|
761
|
+
function memoByZone(cache, events, tz, compute) {
|
|
762
|
+
let byZone = cache.get(events);
|
|
763
|
+
if (!byZone) {
|
|
764
|
+
byZone = /* @__PURE__ */ new Map();
|
|
765
|
+
cache.set(events, byZone);
|
|
766
|
+
}
|
|
767
|
+
const key = tz ?? "";
|
|
768
|
+
let value = byZone.get(key);
|
|
769
|
+
if (value === void 0) {
|
|
770
|
+
value = compute();
|
|
771
|
+
byZone.set(key, value);
|
|
772
|
+
}
|
|
773
|
+
return value;
|
|
774
|
+
}
|
|
775
|
+
var startDayCache = /* @__PURE__ */ new WeakMap();
|
|
776
|
+
function eventsByStartDay(events, tz) {
|
|
777
|
+
return memoByZone(startDayCache, events, tz, () => {
|
|
778
|
+
const map = /* @__PURE__ */ new Map();
|
|
779
|
+
for (const event of events) {
|
|
780
|
+
const key = dayKey(toDisplay(event.start, tz));
|
|
781
|
+
const bucket = map.get(key);
|
|
782
|
+
if (bucket) bucket.push(event);
|
|
783
|
+
else map.set(key, [event]);
|
|
784
|
+
}
|
|
785
|
+
return map;
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
var segmentCache = /* @__PURE__ */ new WeakMap();
|
|
789
|
+
function segmentsByDisplayDay(events, tz, range) {
|
|
790
|
+
const cacheKey = range ? `${tz ?? ""}|${range.start.getTime()}|${range.end.getTime()}` : tz;
|
|
791
|
+
return memoByZone(segmentCache, events, cacheKey, () => {
|
|
792
|
+
const map = /* @__PURE__ */ new Map();
|
|
793
|
+
for (const event of events) {
|
|
794
|
+
const wallStart = toDisplay(event.start, tz);
|
|
795
|
+
const rawEnd = toDisplay(event.end, tz);
|
|
796
|
+
const wallEnd = rawEnd < wallStart ? wallStart : rawEnd;
|
|
797
|
+
if (range && (wallEnd < range.start || wallStart >= range.end)) continue;
|
|
798
|
+
let day = (0, import_date_fns7.startOfDay)(range && wallStart < range.start ? range.start : wallStart);
|
|
799
|
+
const stop = range && wallEnd > range.end ? range.end : wallEnd;
|
|
800
|
+
do {
|
|
801
|
+
const next = (0, import_date_fns7.addDays)(day, 1);
|
|
802
|
+
const start = wallStart > day ? wallStart : day;
|
|
803
|
+
const end = wallEnd < next ? wallEnd : next;
|
|
804
|
+
if (end > start || wallStart.getTime() === wallEnd.getTime()) {
|
|
805
|
+
const key = dayKey(day);
|
|
806
|
+
const bucket = map.get(key);
|
|
807
|
+
const segment = { event, start, end };
|
|
808
|
+
if (bucket) bucket.push(segment);
|
|
809
|
+
else map.set(key, [segment]);
|
|
810
|
+
}
|
|
811
|
+
day = next;
|
|
812
|
+
} while (day < stop);
|
|
813
|
+
}
|
|
814
|
+
return map;
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
|
|
464
818
|
// src/components/dnd/DraggableEvent.tsx
|
|
465
819
|
var import_react4 = __toESM(require("react"));
|
|
466
820
|
var import_core = require("@dnd-kit/core");
|
|
467
821
|
var import_utilities = require("@dnd-kit/utilities");
|
|
468
|
-
var
|
|
822
|
+
var DraggableEventImpl = ({ event, dragId, grabOffsetMs, children, className, style: propStyle, ...props }) => {
|
|
469
823
|
const dragDisabled = isEventDragDisabled(event);
|
|
470
824
|
const { attributes, listeners, setNodeRef, transform, isDragging } = (0, import_core.useDraggable)({
|
|
471
|
-
id: event.id,
|
|
472
|
-
data: { event },
|
|
825
|
+
id: dragId ?? event.id,
|
|
826
|
+
data: { event, grabOffsetMs },
|
|
473
827
|
disabled: dragDisabled
|
|
474
828
|
});
|
|
475
829
|
const style = {
|
|
476
830
|
...propStyle,
|
|
477
831
|
transform: import_utilities.CSS.Translate.toString(transform),
|
|
478
832
|
zIndex: isDragging ? 100 : propStyle?.zIndex,
|
|
479
|
-
//
|
|
480
|
-
// so that the DragOverlay (the "ghost") is the only thing the user focuses on.
|
|
481
|
-
// If we set opacity: 0, it disappears. If 0.1, it's a faint placeholder.
|
|
482
|
-
// The user asked for "Make the entire dragged item transparent".
|
|
483
|
-
// Usually this means the original item should be faded out while the drag overlay is moving.
|
|
833
|
+
// Hide the original while dragging: the DragOverlay ghost is what the user follows.
|
|
484
834
|
opacity: isDragging ? 0 : propStyle?.opacity
|
|
485
|
-
// Hiding original element completely
|
|
486
835
|
};
|
|
487
836
|
return /* @__PURE__ */ import_react4.default.createElement(
|
|
488
837
|
"div",
|
|
@@ -497,33 +846,56 @@ var DraggableEvent = ({ event, children, className, style: propStyle, ...props }
|
|
|
497
846
|
children
|
|
498
847
|
);
|
|
499
848
|
};
|
|
849
|
+
var DraggableEvent = import_react4.default.memo(DraggableEventImpl);
|
|
500
850
|
|
|
501
851
|
// src/components/dnd/DroppableCell.tsx
|
|
502
852
|
var import_react5 = __toESM(require("react"));
|
|
503
853
|
var import_core2 = require("@dnd-kit/core");
|
|
504
|
-
var
|
|
854
|
+
var QUARTER_HOVER = [
|
|
855
|
+
"hover:bg-blue-50/50 dark:hover:bg-blue-900/10",
|
|
856
|
+
"hover:bg-blue-50/80 dark:hover:bg-blue-900/20",
|
|
857
|
+
"hover:bg-blue-100/50 dark:hover:bg-blue-900/30",
|
|
858
|
+
"hover:bg-blue-100/80 dark:hover:bg-blue-900/40"
|
|
859
|
+
];
|
|
860
|
+
var QUARTER_ACTIVE = [
|
|
861
|
+
"bg-blue-50/50 dark:bg-blue-900/10 ring-2 ring-primary ring-inset",
|
|
862
|
+
"bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-primary ring-inset",
|
|
863
|
+
"bg-blue-100/50 dark:bg-blue-900/30 ring-2 ring-primary ring-inset",
|
|
864
|
+
"bg-blue-100/80 dark:bg-blue-900/40 ring-2 ring-primary ring-inset"
|
|
865
|
+
];
|
|
866
|
+
var quarterOf = (date) => Math.min(3, Math.floor(date.getMinutes() / 15));
|
|
867
|
+
var DroppableCellImpl = ({ id, date, resourceId, children, className, style, onClick, onSlotClick }) => {
|
|
505
868
|
const { isOver, setNodeRef } = (0, import_core2.useDroppable)({
|
|
506
869
|
id,
|
|
507
870
|
data: { date, resourceId }
|
|
508
871
|
});
|
|
509
|
-
const
|
|
510
|
-
const quarterClass = minutes === 0 ? "hover:bg-blue-50/50 dark:hover:bg-blue-900/10" : minutes === 15 ? "hover:bg-blue-50/80 dark:hover:bg-blue-900/20" : minutes === 30 ? "hover:bg-blue-100/50 dark:hover:bg-blue-900/30" : "hover:bg-blue-100/80 dark:hover:bg-blue-900/40";
|
|
511
|
-
const activeQuarterClass = minutes === 0 ? "bg-blue-50/50 dark:bg-blue-900/10 ring-2 ring-primary ring-inset" : minutes === 15 ? "bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-primary ring-inset" : minutes === 30 ? "bg-blue-100/50 dark:bg-blue-900/30 ring-2 ring-primary ring-inset" : "bg-blue-100/80 dark:bg-blue-900/40 ring-2 ring-primary ring-inset";
|
|
872
|
+
const quarter = quarterOf(date);
|
|
512
873
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
513
874
|
"div",
|
|
514
875
|
{
|
|
515
876
|
ref: setNodeRef,
|
|
516
877
|
className: cn(
|
|
517
878
|
className,
|
|
518
|
-
|
|
519
|
-
isOver &&
|
|
879
|
+
QUARTER_HOVER[quarter],
|
|
880
|
+
isOver && QUARTER_ACTIVE[quarter],
|
|
881
|
+
onSlotClick && "cursor-pointer"
|
|
520
882
|
),
|
|
521
883
|
style,
|
|
522
|
-
onClick
|
|
884
|
+
onClick: onSlotClick ? () => onSlotClick(date, resourceId) : onClick
|
|
523
885
|
},
|
|
524
886
|
children
|
|
525
887
|
);
|
|
526
888
|
};
|
|
889
|
+
var shallowEqualStyle = (a, b) => {
|
|
890
|
+
if (a === b) return true;
|
|
891
|
+
if (!a || !b) return false;
|
|
892
|
+
const keys = Object.keys(a);
|
|
893
|
+
return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);
|
|
894
|
+
};
|
|
895
|
+
var DroppableCell = import_react5.default.memo(
|
|
896
|
+
DroppableCellImpl,
|
|
897
|
+
(prev, next) => prev.id === next.id && prev.date.getTime() === next.date.getTime() && prev.resourceId === next.resourceId && prev.children === next.children && prev.className === next.className && prev.onClick === next.onClick && prev.onSlotClick === next.onSlotClick && shallowEqualStyle(prev.style, next.style)
|
|
898
|
+
);
|
|
527
899
|
|
|
528
900
|
// src/views/MonthView.tsx
|
|
529
901
|
var EventItem = import_react6.default.memo(({ event, onEventClick }) => /* @__PURE__ */ import_react6.default.createElement(DraggableEvent, { event }, /* @__PURE__ */ import_react6.default.createElement(
|
|
@@ -555,42 +927,22 @@ var MonthView = ({
|
|
|
555
927
|
timezone,
|
|
556
928
|
locale
|
|
557
929
|
}) => {
|
|
558
|
-
const weekStartsOn = locale
|
|
559
|
-
const days = (0, import_react6.useMemo)(
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
);
|
|
563
|
-
const weekDays = (0, import_react6.useMemo)(() => {
|
|
564
|
-
const start = (0, import_date_fns5.startOfWeek)(currentDate, { weekStartsOn });
|
|
565
|
-
const end = (0, import_date_fns5.endOfWeek)(currentDate, { weekStartsOn });
|
|
566
|
-
return (0, import_date_fns5.eachDayOfInterval)({ start, end });
|
|
567
|
-
}, [currentDate, weekStartsOn]);
|
|
568
|
-
const getZonedDate = (0, import_react6.useCallback)((date) => {
|
|
569
|
-
return timezone ? (0, import_date_fns_tz2.toZonedTime)(date, timezone) : date;
|
|
570
|
-
}, [timezone]);
|
|
571
|
-
const eventsByDay = (0, import_react6.useMemo)(() => {
|
|
572
|
-
const map = /* @__PURE__ */ new Map();
|
|
573
|
-
events.forEach((event) => {
|
|
574
|
-
const zonedStart = getZonedDate(event.start);
|
|
575
|
-
const key = (0, import_date_fns5.format)(zonedStart, "yyyy-MM-dd");
|
|
576
|
-
if (!map.has(key)) {
|
|
577
|
-
map.set(key, []);
|
|
578
|
-
}
|
|
579
|
-
map.get(key).push(event);
|
|
580
|
-
});
|
|
581
|
-
return map;
|
|
582
|
-
}, [events, getZonedDate]);
|
|
930
|
+
const weekStartsOn = resolveWeekStartsOn(locale, 1);
|
|
931
|
+
const days = (0, import_react6.useMemo)(() => getMonthGrid(currentDate, weekStartsOn), [currentDate, weekStartsOn]);
|
|
932
|
+
const weekDays = (0, import_react6.useMemo)(() => getWeekDays(currentDate, weekStartsOn), [currentDate, weekStartsOn]);
|
|
933
|
+
const eventsByDay = eventsByStartDay(events, timezone);
|
|
934
|
+
const today = displayToday(timezone);
|
|
583
935
|
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] scrollbar-hide border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-y-auto flex-1 relative" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "grid grid-cols-7 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/30 via-muted/40 to-muted/30 sticky top-0 z-20 backdrop-blur-sm" }, weekDays.map((day) => /* @__PURE__ */ import_react6.default.createElement(
|
|
584
936
|
"div",
|
|
585
937
|
{
|
|
586
938
|
key: day.toISOString(),
|
|
587
939
|
className: "py-3 text-center text-xs font-semibold text-muted-foreground border-r-[0.5px] border-border/30 last:border-r-0 uppercase tracking-wider"
|
|
588
940
|
},
|
|
589
|
-
(0,
|
|
941
|
+
(0, import_date_fns8.format)(day, "EEE", { locale })
|
|
590
942
|
))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "grid grid-cols-7", style: { gridAutoRows: "130px" } }, days.map((day) => {
|
|
591
|
-
const
|
|
592
|
-
const dayEvents = eventsByDay.get(
|
|
593
|
-
const isCurrentMonth = (0,
|
|
943
|
+
const dayKey2 = (0, import_date_fns8.format)(day, "yyyy-MM-dd");
|
|
944
|
+
const dayEvents = eventsByDay.get(dayKey2) || [];
|
|
945
|
+
const isCurrentMonth = (0, import_date_fns8.isSameMonth)(day, currentDate);
|
|
594
946
|
const cellId = day.toISOString();
|
|
595
947
|
return /* @__PURE__ */ import_react6.default.createElement(
|
|
596
948
|
DroppableCell,
|
|
@@ -601,26 +953,87 @@ var MonthView = ({
|
|
|
601
953
|
className: cn(
|
|
602
954
|
"h-[130px] p-2 border-b-[0.5px] border-r-[0.5px] border-border/30 last:border-r-0 relative transition-all duration-200 hover:bg-accent/5 flex flex-col gap-1.5 overflow-hidden group",
|
|
603
955
|
!isCurrentMonth && "bg-muted/5 text-muted-foreground/60",
|
|
604
|
-
(0,
|
|
956
|
+
(0, import_date_fns8.isSameDay)(day, today) && "bg-primary/5 ring-1 ring-inset ring-primary/20"
|
|
605
957
|
),
|
|
606
958
|
onClick: () => onDateClick?.(day)
|
|
607
959
|
},
|
|
608
960
|
/* @__PURE__ */ import_react6.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: cn(
|
|
609
961
|
"text-sm font-semibold w-7 h-7 flex items-center justify-center rounded-full transition-all duration-200",
|
|
610
|
-
(0,
|
|
611
|
-
) }, (0,
|
|
612
|
-
/* @__PURE__ */ import_react6.default.createElement("div", { className: "flex-1 flex flex-col gap-1 scrollbar-hide overflow-y-auto overflow-x-hidden" }, dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ import_react6.default.createElement(EventItem, { key: `${event.id}-${
|
|
962
|
+
(0, import_date_fns8.isSameDay)(day, today) ? "bg-primary text-primary-foreground shadow-md shadow-primary/30" : "group-hover:bg-accent"
|
|
963
|
+
) }, (0, import_date_fns8.format)(day, "d", { locale })), dayEvents.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-[10px] font-medium text-muted-foreground/60 bg-muted/50 px-1.5 py-0.5 rounded-full" }, dayEvents.length)),
|
|
964
|
+
/* @__PURE__ */ import_react6.default.createElement("div", { className: "flex-1 flex flex-col gap-1 scrollbar-hide overflow-y-auto overflow-x-hidden" }, dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ import_react6.default.createElement(EventItem, { key: `${event.id}-${dayKey2}`, event, onEventClick })), dayEvents.length > 4 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-[10px] text-primary font-semibold text-center py-1 px-2 rounded-md bg-primary/5 hover:bg-primary/10 cursor-pointer transition-colors" }, "+", dayEvents.length - 4, " more"))
|
|
613
965
|
);
|
|
614
966
|
}))));
|
|
615
967
|
};
|
|
616
968
|
|
|
617
969
|
// src/views/WeekView.tsx
|
|
618
970
|
var import_react8 = __toESM(require("react"));
|
|
619
|
-
var
|
|
620
|
-
|
|
971
|
+
var import_date_fns9 = require("date-fns");
|
|
972
|
+
|
|
973
|
+
// src/core/layout.ts
|
|
974
|
+
var layoutCache = /* @__PURE__ */ new WeakMap();
|
|
975
|
+
function layoutDayEvents(segments) {
|
|
976
|
+
const cached = layoutCache.get(segments);
|
|
977
|
+
if (cached) return cached;
|
|
978
|
+
const sorted = [...segments].sort(
|
|
979
|
+
(a, b) => a.start.getTime() - b.start.getTime() || b.end.getTime() - a.end.getTime() || (a.event.id < b.event.id ? -1 : a.event.id > b.event.id ? 1 : 0)
|
|
980
|
+
);
|
|
981
|
+
const result = [];
|
|
982
|
+
let cluster = [];
|
|
983
|
+
let columnEnds = [];
|
|
984
|
+
let clusterEnd = -Infinity;
|
|
985
|
+
const closeCluster = () => {
|
|
986
|
+
for (const placed of cluster) placed.columns = columnEnds.length;
|
|
987
|
+
cluster = [];
|
|
988
|
+
columnEnds = [];
|
|
989
|
+
};
|
|
990
|
+
for (const segment of sorted) {
|
|
991
|
+
const start = segment.start.getTime();
|
|
992
|
+
const end = Math.max(segment.end.getTime(), start + 1);
|
|
993
|
+
if (start >= clusterEnd) closeCluster();
|
|
994
|
+
let column = columnEnds.findIndex((columnEnd) => columnEnd <= start);
|
|
995
|
+
if (column === -1) {
|
|
996
|
+
column = columnEnds.length;
|
|
997
|
+
columnEnds.push(end);
|
|
998
|
+
} else {
|
|
999
|
+
columnEnds[column] = end;
|
|
1000
|
+
}
|
|
1001
|
+
const placed = { ...segment, column, columns: 1 };
|
|
1002
|
+
cluster.push(placed);
|
|
1003
|
+
result.push(placed);
|
|
1004
|
+
clusterEnd = Math.max(clusterEnd, end);
|
|
1005
|
+
}
|
|
1006
|
+
closeCluster();
|
|
1007
|
+
layoutCache.set(segments, result);
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
621
1010
|
|
|
622
1011
|
// src/components/dnd/ResizableEvent.tsx
|
|
623
1012
|
var import_react7 = __toESM(require("react"));
|
|
1013
|
+
|
|
1014
|
+
// src/core/dnd.ts
|
|
1015
|
+
function computeDrop({ event, overDate, overResourceId, grabOffsetMs = 0, view, tz }) {
|
|
1016
|
+
let wallStart;
|
|
1017
|
+
if (view === "month") {
|
|
1018
|
+
const original = toDisplay(event.start, tz);
|
|
1019
|
+
wallStart = new Date(overDate);
|
|
1020
|
+
wallStart.setHours(original.getHours(), original.getMinutes(), original.getSeconds(), original.getMilliseconds());
|
|
1021
|
+
} else {
|
|
1022
|
+
wallStart = new Date(overDate.getTime() - grabOffsetMs);
|
|
1023
|
+
wallStart.setSeconds(0, 0);
|
|
1024
|
+
}
|
|
1025
|
+
const start = fromDisplay(wallStart, tz);
|
|
1026
|
+
const end = new Date(start.getTime() + (event.end.getTime() - event.start.getTime()));
|
|
1027
|
+
const resourceId = overResourceId ?? event.resourceId;
|
|
1028
|
+
if (start.getTime() === event.start.getTime() && resourceId === event.resourceId) return null;
|
|
1029
|
+
return { start, end, resourceId };
|
|
1030
|
+
}
|
|
1031
|
+
function computeResizeEnd(event, deltaMinutes, minDuration = 15) {
|
|
1032
|
+
const minEnd = event.start.getTime() + minDuration * 6e4;
|
|
1033
|
+
return new Date(Math.max(event.end.getTime() + deltaMinutes * 6e4, minEnd));
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// src/components/dnd/ResizableEvent.tsx
|
|
624
1037
|
var ResizableEvent = ({
|
|
625
1038
|
event,
|
|
626
1039
|
hourHeight,
|
|
@@ -662,14 +1075,8 @@ var ResizableEvent = ({
|
|
|
662
1075
|
setIsResizing(false);
|
|
663
1076
|
const finalHeight = resizeHeightRef.current;
|
|
664
1077
|
if (finalHeight !== null && containerRef.current && onResize) {
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
const minutesDiff = heightDiff / hourHeight * 60;
|
|
668
|
-
const newEnd = new Date(event.end);
|
|
669
|
-
newEnd.setMinutes(newEnd.getMinutes() + minutesDiff);
|
|
670
|
-
if (newEnd > event.start) {
|
|
671
|
-
onResize(event, newEnd);
|
|
672
|
-
}
|
|
1078
|
+
const minutesDiff = (finalHeight - startHeightRef.current) / hourHeight * 60;
|
|
1079
|
+
onResize(event, computeResizeEnd(event, minutesDiff, minDuration));
|
|
673
1080
|
}
|
|
674
1081
|
resizeHeightRef.current = null;
|
|
675
1082
|
setResizeHeight(null);
|
|
@@ -720,7 +1127,16 @@ var ResizableEvent = ({
|
|
|
720
1127
|
};
|
|
721
1128
|
|
|
722
1129
|
// src/views/WeekView.tsx
|
|
723
|
-
var
|
|
1130
|
+
var HOUR_HEIGHT = 60;
|
|
1131
|
+
var HOURS = Array.from({ length: 24 }, (_, i) => i);
|
|
1132
|
+
var QUARTERS = [0, 15, 30, 45];
|
|
1133
|
+
var NO_SEGMENTS = [];
|
|
1134
|
+
var slotDate = (day, hour, minute) => {
|
|
1135
|
+
const date = new Date(day);
|
|
1136
|
+
date.setHours(hour, minute, 0, 0);
|
|
1137
|
+
return date;
|
|
1138
|
+
};
|
|
1139
|
+
var WeekViewImpl = ({
|
|
724
1140
|
currentDate,
|
|
725
1141
|
events,
|
|
726
1142
|
onEventClick,
|
|
@@ -730,14 +1146,16 @@ var WeekView = ({
|
|
|
730
1146
|
locale,
|
|
731
1147
|
readonly
|
|
732
1148
|
}) => {
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
const
|
|
738
|
-
|
|
1149
|
+
const weekDays = import_react8.default.useMemo(
|
|
1150
|
+
() => getWeekDays(currentDate, resolveWeekStartsOn(locale, 1)),
|
|
1151
|
+
[currentDate, locale]
|
|
1152
|
+
);
|
|
1153
|
+
const visibleRange = import_react8.default.useMemo(
|
|
1154
|
+
() => ({ start: weekDays[0], end: (0, import_date_fns9.addDays)(weekDays[weekDays.length - 1], 1) }),
|
|
1155
|
+
[weekDays]
|
|
1156
|
+
);
|
|
739
1157
|
const scrollContainerRef = import_react8.default.useRef(null);
|
|
740
|
-
const [now, setNow] = import_react8.default.useState(/* @__PURE__ */ new Date());
|
|
1158
|
+
const [now, setNow] = import_react8.default.useState(() => /* @__PURE__ */ new Date());
|
|
741
1159
|
import_react8.default.useEffect(() => {
|
|
742
1160
|
const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
743
1161
|
return () => clearInterval(interval);
|
|
@@ -745,132 +1163,93 @@ var WeekView = ({
|
|
|
745
1163
|
import_react8.default.useEffect(() => {
|
|
746
1164
|
if (scrollContainerRef.current) {
|
|
747
1165
|
const offsetHour = 4;
|
|
748
|
-
scrollContainerRef.current.scrollTop = ((/* @__PURE__ */ new Date()).getHours() - offsetHour) *
|
|
1166
|
+
scrollContainerRef.current.scrollTop = (toDisplay(/* @__PURE__ */ new Date(), timezone).getHours() - offsetHour) * HOUR_HEIGHT;
|
|
749
1167
|
}
|
|
750
|
-
}, []);
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
if (!tz) {
|
|
760
|
-
displayTime = (0, import_date_fns6.format)(date, "HH:mm");
|
|
761
|
-
try {
|
|
762
|
-
acronym = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value || "";
|
|
763
|
-
} catch {
|
|
764
|
-
acronym = "LOC";
|
|
765
|
-
}
|
|
766
|
-
} else {
|
|
767
|
-
try {
|
|
768
|
-
const zDate = (0, import_date_fns_tz3.toZonedTime)(date, tz);
|
|
769
|
-
displayTime = (0, import_date_fns6.format)(zDate, "HH:mm");
|
|
770
|
-
acronym = new Intl.DateTimeFormat("en-US", { timeZone: tz, timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value || "";
|
|
771
|
-
} catch {
|
|
772
|
-
displayTime = (0, import_date_fns6.format)(date, "HH:mm");
|
|
773
|
-
acronym = tz;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-col items-center justify-center leading-tight" }, /* @__PURE__ */ import_react8.default.createElement("span", null, displayTime), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] opacity-75" }, "(", acronym, ")"));
|
|
777
|
-
};
|
|
778
|
-
const is24h = uses24HourClock(locale);
|
|
779
|
-
const timeFormat = is24h ? "H:mm" : "h a";
|
|
780
|
-
const eventTimeFormat = is24h ? "H:mm" : "h:mm a";
|
|
781
|
-
const nowFormat = is24h ? "H:mm" : "h:mm";
|
|
1168
|
+
}, [timezone]);
|
|
1169
|
+
const segmentsByDay = segmentsByDisplayDay(events, timezone, visibleRange);
|
|
1170
|
+
const today = displayToday(timezone, now);
|
|
1171
|
+
const zonedNow = toDisplay(now, timezone);
|
|
1172
|
+
const nowTop = minutesSinceDisplayMidnight(now, timezone) / 60 * HOUR_HEIGHT;
|
|
1173
|
+
const showsToday = weekDays.some((day) => (0, import_date_fns9.isSameDay)(day, today));
|
|
1174
|
+
const zone = resolveTimeZone(timezone);
|
|
1175
|
+
const zoneLabel = timeZoneAbbreviation(now, zone) || zone || "LOC";
|
|
1176
|
+
const formats = timeFormats(locale);
|
|
782
1177
|
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
783
1178
|
"div",
|
|
784
1179
|
{
|
|
785
1180
|
ref: scrollContainerRef,
|
|
786
1181
|
className: "flex-1 overflow-y-auto scrollbar-hide relative bg-background scroll-smooth"
|
|
787
1182
|
},
|
|
788
|
-
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 z-20 sticky top-0 backdrop-blur-sm" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-none p-3 text-center text-xs font-semibold text-muted-foreground w-16 flex items-center justify-center border-r-[0.5px] border-border/30 bg-muted/10" },
|
|
1183
|
+
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 z-20 sticky top-0 backdrop-blur-sm" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-none p-3 text-center text-xs font-semibold text-muted-foreground w-16 flex items-center justify-center border-r-[0.5px] border-border/30 bg-muted/10" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-col items-center justify-center leading-tight" }, /* @__PURE__ */ import_react8.default.createElement("span", null, (0, import_date_fns9.format)(zonedNow, "HH:mm")), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] opacity-75" }, "(", zoneLabel, ")"))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-1 grid grid-cols-7" }, weekDays.map((day, index) => /* @__PURE__ */ import_react8.default.createElement("div", { key: day.toISOString(), className: cn("py-3 px-2 text-center", index > 0 && "border-l-[0.5px] border-border/30") }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1.5" }, (0, import_date_fns9.format)(day, "EEE", { locale })), /* @__PURE__ */ import_react8.default.createElement("div", { className: cn(
|
|
789
1184
|
"w-9 h-9 flex items-center justify-center rounded-xl mx-auto text-sm font-semibold transition-all duration-200",
|
|
790
|
-
(0,
|
|
791
|
-
) }, (0,
|
|
1185
|
+
(0, import_date_fns9.isSameDay)(day, today) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30 scale-110" : "text-foreground hover:bg-accent/80"
|
|
1186
|
+
) }, (0, import_date_fns9.format)(day, "d", { locale })))))),
|
|
792
1187
|
/* @__PURE__ */ import_react8.default.createElement(
|
|
793
1188
|
"div",
|
|
794
1189
|
{
|
|
795
1190
|
className: "flex min-w-full relative",
|
|
796
|
-
style: { height:
|
|
1191
|
+
style: { height: HOURS.length * HOUR_HEIGHT }
|
|
797
1192
|
},
|
|
798
|
-
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-none w-16 border-r-[0.5px] border-border/30 relative bg-muted/5" },
|
|
1193
|
+
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-none w-16 border-r-[0.5px] border-border/30 relative bg-muted/5" }, HOURS.map((hour) => /* @__PURE__ */ import_react8.default.createElement(
|
|
799
1194
|
"div",
|
|
800
1195
|
{
|
|
801
1196
|
key: hour,
|
|
802
1197
|
className: "relative w-full text-[11px] text-muted-foreground/80 text-right pr-3 font-medium tabular-nums box-border",
|
|
803
|
-
style: { height:
|
|
1198
|
+
style: { height: HOUR_HEIGHT }
|
|
804
1199
|
},
|
|
805
|
-
/* @__PURE__ */ import_react8.default.createElement("span", { className: "block -translate-y-1/2" }, hour !== 0 && (0,
|
|
806
|
-
))
|
|
1200
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "block -translate-y-1/2" }, hour !== 0 && (0, import_date_fns9.format)(slotDate(currentDate, hour, 0), formats.hour, { locale }))
|
|
1201
|
+
)), showsToday && /* @__PURE__ */ import_react8.default.createElement(
|
|
1202
|
+
"div",
|
|
1203
|
+
{
|
|
1204
|
+
className: "absolute left-0 w-full pointer-events-none z-30 flex justify-end pr-2",
|
|
1205
|
+
style: { top: `${nowTop}px` }
|
|
1206
|
+
},
|
|
1207
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-bold text-primary-foreground bg-primary px-1.5 py-0.5 rounded-md shadow-md -translate-y-1/2 backdrop-blur-none" }, (0, import_date_fns9.format)(zonedNow, formats.compact, { locale }))
|
|
1208
|
+
)),
|
|
807
1209
|
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-1 grid grid-cols-7 relative" }, weekDays.map((day, dayIndex) => {
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
"
|
|
815
|
-
{
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
{
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
date: cellDate,
|
|
830
|
-
className: "w-full absolute left-0 right-0 z-0 transition-colors",
|
|
831
|
-
style: {
|
|
832
|
-
height: "25%",
|
|
833
|
-
top: `${minute / 60 * 100}%`
|
|
834
|
-
}
|
|
1210
|
+
const dayKey2 = (0, import_date_fns9.format)(day, "yyyy-MM-dd");
|
|
1211
|
+
const positioned = layoutDayEvents(segmentsByDay.get(dayKey2) ?? NO_SEGMENTS);
|
|
1212
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { key: dayKey2, className: cn("relative h-full", dayIndex > 0 && "border-l-[0.5px] border-border/30") }, HOURS.map((hour) => /* @__PURE__ */ import_react8.default.createElement(
|
|
1213
|
+
"div",
|
|
1214
|
+
{
|
|
1215
|
+
key: hour,
|
|
1216
|
+
className: "w-full border-b-[0.5px] border-dashed border-border/20 box-border relative hover:bg-accent/5 transition-colors",
|
|
1217
|
+
style: { height: HOUR_HEIGHT }
|
|
1218
|
+
},
|
|
1219
|
+
QUARTERS.map((minute) => {
|
|
1220
|
+
const cellDate = slotDate(day, hour, minute);
|
|
1221
|
+
return /* @__PURE__ */ import_react8.default.createElement(
|
|
1222
|
+
DroppableCell,
|
|
1223
|
+
{
|
|
1224
|
+
key: minute,
|
|
1225
|
+
id: cellDate.toISOString(),
|
|
1226
|
+
date: cellDate,
|
|
1227
|
+
className: "w-full absolute left-0 right-0 z-0 transition-colors",
|
|
1228
|
+
style: {
|
|
1229
|
+
height: "25%",
|
|
1230
|
+
top: `${minute / 60 * 100}%`
|
|
835
1231
|
},
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
);
|
|
846
|
-
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
const s1 = getZonedDate(event.start).getTime();
|
|
850
|
-
const e1 = getZonedDate(event.end).getTime();
|
|
851
|
-
const s2 = getZonedDate(e.start).getTime();
|
|
852
|
-
const e2 = getZonedDate(e.end).getTime();
|
|
853
|
-
return s1 < e2 && e1 > s2;
|
|
854
|
-
});
|
|
855
|
-
const group = [event, ...overlappingEvents].sort(
|
|
856
|
-
(a, b) => getZonedDate(a.start).getTime() - getZonedDate(b.start).getTime() || (a.id > b.id ? 1 : -1)
|
|
857
|
-
// stable sort
|
|
858
|
-
);
|
|
859
|
-
const index = group.findIndex((e) => e.id === event.id);
|
|
860
|
-
const count = group.length;
|
|
861
|
-
const widthPercent = 100 / count;
|
|
862
|
-
const leftPercent = index * widthPercent;
|
|
863
|
-
const zonedEventStart = getZonedDate(event.start);
|
|
864
|
-
const zonedEventEnd = getZonedDate(event.end);
|
|
865
|
-
const startMinutes = zonedEventStart.getHours() * 60 + zonedEventStart.getMinutes();
|
|
866
|
-
const durationMinutes = (0, import_date_fns6.differenceInMinutes)(zonedEventEnd, zonedEventStart);
|
|
867
|
-
const top = startMinutes / 60 * hourHeight;
|
|
868
|
-
const height = durationMinutes / 60 * hourHeight;
|
|
1232
|
+
onSlotClick: onTimeSlotClick
|
|
1233
|
+
}
|
|
1234
|
+
);
|
|
1235
|
+
})
|
|
1236
|
+
)), positioned.map(({ event, start, end, column, columns }) => {
|
|
1237
|
+
const widthPercent = 100 / columns;
|
|
1238
|
+
const leftPercent = column * widthPercent;
|
|
1239
|
+
const zonedEventStart = toDisplay(event.start, timezone);
|
|
1240
|
+
const zonedEventEnd = toDisplay(event.end, timezone);
|
|
1241
|
+
const startMinutes = start.getHours() * 60 + start.getMinutes();
|
|
1242
|
+
const durationMinutes = (0, import_date_fns9.differenceInMinutes)(end, start);
|
|
1243
|
+
const top = startMinutes / 60 * HOUR_HEIGHT;
|
|
1244
|
+
const height = durationMinutes / 60 * HOUR_HEIGHT;
|
|
869
1245
|
const isShortEvent = durationMinutes < 60;
|
|
1246
|
+
const isLastSegment = end.getTime() === zonedEventEnd.getTime();
|
|
870
1247
|
return /* @__PURE__ */ import_react8.default.createElement(
|
|
871
1248
|
DraggableEvent,
|
|
872
1249
|
{
|
|
873
|
-
key: `${event.id}-${
|
|
1250
|
+
key: `${event.id}-${dayKey2}`,
|
|
1251
|
+
dragId: `${event.id}@${dayKey2}`,
|
|
1252
|
+
grabOffsetMs: start.getTime() - zonedEventStart.getTime(),
|
|
874
1253
|
event,
|
|
875
1254
|
className: `absolute z-10 transition-all ${readonly ? "cursor-default" : ""}`,
|
|
876
1255
|
style: {
|
|
@@ -879,15 +1258,15 @@ var WeekView = ({
|
|
|
879
1258
|
left: `${leftPercent}%`,
|
|
880
1259
|
width: `${widthPercent}%`,
|
|
881
1260
|
// Add minimal spacing between overlapping events
|
|
882
|
-
paddingRight:
|
|
1261
|
+
paddingRight: columns > 1 ? "2px" : "0"
|
|
883
1262
|
}
|
|
884
1263
|
},
|
|
885
1264
|
/* @__PURE__ */ import_react8.default.createElement(
|
|
886
1265
|
ResizableEvent,
|
|
887
1266
|
{
|
|
888
|
-
readonly,
|
|
1267
|
+
readonly: readonly || !isLastSegment,
|
|
889
1268
|
event,
|
|
890
|
-
hourHeight,
|
|
1269
|
+
hourHeight: HOUR_HEIGHT,
|
|
891
1270
|
onResize: onEventResize,
|
|
892
1271
|
className: "h-full",
|
|
893
1272
|
style: { height: "100%" }
|
|
@@ -902,7 +1281,7 @@ var WeekView = ({
|
|
|
902
1281
|
!event.color && "border-primary/20 bg-primary/10",
|
|
903
1282
|
isShortEvent ? "px-1 flex items-center justify-center" : "p-2",
|
|
904
1283
|
// Add active border for overlapped events to distinguish them
|
|
905
|
-
|
|
1284
|
+
columns > 1 && "border-l-4 border-l-primary/50"
|
|
906
1285
|
),
|
|
907
1286
|
style: {
|
|
908
1287
|
height: "100%",
|
|
@@ -915,46 +1294,43 @@ var WeekView = ({
|
|
|
915
1294
|
e.stopPropagation();
|
|
916
1295
|
onEventClick?.(event);
|
|
917
1296
|
},
|
|
918
|
-
title:
|
|
1297
|
+
title: columns > 1 ? `${event.title} (${column + 1}/${columns})` : void 0
|
|
919
1298
|
},
|
|
920
1299
|
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: cn(
|
|
921
1300
|
"font-semibold truncate text-foreground/90 leading-tight",
|
|
922
1301
|
isShortEvent ? "text-xs text-center" : "text-xs"
|
|
923
|
-
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement("div", { className: "text-[10px] text-muted-foreground truncate mt-0.5 font-medium leading-tight" }, (0,
|
|
1302
|
+
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement("div", { className: "text-[10px] text-muted-foreground truncate mt-0.5 font-medium leading-tight" }, (0, import_date_fns9.format)(zonedEventStart, formats.time, { locale }), " - ", (0, import_date_fns9.format)(zonedEventEnd, formats.time, { locale })), event.description && height > 50 && /* @__PURE__ */ import_react8.default.createElement("div", { className: "text-[10px] text-muted-foreground/80 truncate mt-1 leading-tight opacity-80" }, event.description)), columns > 1 && !isShortEvent && /* @__PURE__ */ import_react8.default.createElement("div", { className: "absolute top-1 right-1 bg-background/80 backdrop-blur-sm rounded-full w-4 h-4 flex items-center justify-center text-[9px] font-bold text-muted-foreground border border-border shadow-sm" }, columns))
|
|
924
1303
|
)
|
|
925
1304
|
)
|
|
926
1305
|
);
|
|
927
|
-
}), (0,
|
|
1306
|
+
}), (0, import_date_fns9.isSameDay)(day, today) && /* @__PURE__ */ import_react8.default.createElement(
|
|
928
1307
|
"div",
|
|
929
1308
|
{
|
|
930
1309
|
className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
|
|
931
|
-
style: {
|
|
932
|
-
top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
|
|
933
|
-
}
|
|
1310
|
+
style: { top: `${nowTop}px` }
|
|
934
1311
|
},
|
|
935
1312
|
/* @__PURE__ */ import_react8.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
|
|
936
1313
|
/* @__PURE__ */ import_react8.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
|
|
937
1314
|
));
|
|
938
1315
|
}))
|
|
939
|
-
),
|
|
940
|
-
/* @__PURE__ */ import_react8.default.createElement(
|
|
941
|
-
"div",
|
|
942
|
-
{
|
|
943
|
-
className: "absolute left-0 w-16 pointer-events-none z-30 flex justify-end pr-2",
|
|
944
|
-
style: {
|
|
945
|
-
top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight + 80}px`
|
|
946
|
-
}
|
|
947
|
-
},
|
|
948
|
-
/* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-bold text-primary-foreground bg-primary px-1.5 py-0.5 rounded-md shadow-md -translate-y-1/2 backdrop-blur-none" }, (0, import_date_fns6.format)(zonedNow, nowFormat, { locale }))
|
|
949
1316
|
)
|
|
950
1317
|
));
|
|
951
1318
|
};
|
|
1319
|
+
var WeekView = import_react8.default.memo(WeekViewImpl);
|
|
952
1320
|
|
|
953
1321
|
// src/views/DayView.tsx
|
|
954
1322
|
var import_react9 = __toESM(require("react"));
|
|
955
|
-
var
|
|
956
|
-
var
|
|
957
|
-
var
|
|
1323
|
+
var import_date_fns10 = require("date-fns");
|
|
1324
|
+
var HOUR_HEIGHT2 = 80;
|
|
1325
|
+
var HOURS2 = Array.from({ length: 24 }, (_, i) => i);
|
|
1326
|
+
var QUARTERS2 = [0, 15, 30, 45];
|
|
1327
|
+
var NO_SEGMENTS2 = [];
|
|
1328
|
+
var slotDate2 = (day, hour, minute) => {
|
|
1329
|
+
const date = new Date(day);
|
|
1330
|
+
date.setHours(hour, minute, 0, 0);
|
|
1331
|
+
return date;
|
|
1332
|
+
};
|
|
1333
|
+
var DayViewImpl = ({
|
|
958
1334
|
currentDate,
|
|
959
1335
|
events,
|
|
960
1336
|
onEventClick,
|
|
@@ -964,10 +1340,12 @@ var DayView = ({
|
|
|
964
1340
|
locale,
|
|
965
1341
|
readonly
|
|
966
1342
|
}) => {
|
|
967
|
-
const
|
|
968
|
-
|
|
1343
|
+
const visibleRange = import_react9.default.useMemo(() => {
|
|
1344
|
+
const start = (0, import_date_fns10.startOfDay)(currentDate);
|
|
1345
|
+
return { start, end: (0, import_date_fns10.addDays)(start, 1) };
|
|
1346
|
+
}, [currentDate]);
|
|
969
1347
|
const scrollContainerRef = import_react9.default.useRef(null);
|
|
970
|
-
const [now, setNow] = import_react9.default.useState(/* @__PURE__ */ new Date());
|
|
1348
|
+
const [now, setNow] = import_react9.default.useState(() => /* @__PURE__ */ new Date());
|
|
971
1349
|
import_react9.default.useEffect(() => {
|
|
972
1350
|
const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
973
1351
|
return () => clearInterval(interval);
|
|
@@ -975,99 +1353,71 @@ var DayView = ({
|
|
|
975
1353
|
import_react9.default.useEffect(() => {
|
|
976
1354
|
if (scrollContainerRef.current) {
|
|
977
1355
|
const offsetHour = 3;
|
|
978
|
-
scrollContainerRef.current.scrollTop = ((/* @__PURE__ */ new Date()).getHours() - offsetHour) *
|
|
1356
|
+
scrollContainerRef.current.scrollTop = (toDisplay(/* @__PURE__ */ new Date(), timezone).getHours() - offsetHour) * HOUR_HEIGHT2;
|
|
979
1357
|
}
|
|
980
|
-
}, []);
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
const zonedNow =
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
});
|
|
989
|
-
const is24h = uses24HourClock(locale);
|
|
990
|
-
const timeFormat = is24h ? "H:mm" : "h a";
|
|
991
|
-
const eventTimeFormat = is24h ? "H:mm" : "h:mm a";
|
|
992
|
-
const nowFormat = is24h ? "H:mm" : "h:mm a";
|
|
993
|
-
return /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden shadow-sm" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 py-4 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 text-center shrink-0" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center justify-center gap-3" }, /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-xl font-semibold capitalize text-foreground" }, (0, import_date_fns7.format)(currentDate, "EEEE, MMMM d, yyyy", { locale })), (0, import_date_fns7.isToday)(currentDate) && /* @__PURE__ */ import_react9.default.createElement("span", { className: "text-xs font-semibold bg-primary text-primary-foreground px-3 py-1 rounded-full shadow-md shadow-primary/20" }, "Today"))), /* @__PURE__ */ import_react9.default.createElement("div", { ref: scrollContainerRef, className: "flex-1 overflow-y-auto relative" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex relative", style: { height: hours.length * hourHeight } }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "w-20 bg-muted/5 border-r-[0.5px] border-border/30 relative" }, hours.map((hour) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1358
|
+
}, [timezone]);
|
|
1359
|
+
const dayKey2 = (0, import_date_fns10.format)(currentDate, "yyyy-MM-dd");
|
|
1360
|
+
const positioned = layoutDayEvents(segmentsByDisplayDay(events, timezone, visibleRange).get(dayKey2) ?? NO_SEGMENTS2);
|
|
1361
|
+
const isToday2 = (0, import_date_fns10.isSameDay)(currentDate, displayToday(timezone, now));
|
|
1362
|
+
const zonedNow = toDisplay(now, timezone);
|
|
1363
|
+
const nowTop = minutesSinceDisplayMidnight(now, timezone) / 60 * HOUR_HEIGHT2;
|
|
1364
|
+
const formats = timeFormats(locale);
|
|
1365
|
+
return /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden shadow-sm" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 py-4 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 text-center shrink-0" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center justify-center gap-3" }, /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-xl font-semibold capitalize text-foreground" }, (0, import_date_fns10.format)(currentDate, "EEEE, MMMM d, yyyy", { locale })), isToday2 && /* @__PURE__ */ import_react9.default.createElement("span", { className: "text-xs font-semibold bg-primary text-primary-foreground px-3 py-1 rounded-full shadow-md shadow-primary/20" }, "Today"))), /* @__PURE__ */ import_react9.default.createElement("div", { ref: scrollContainerRef, className: "flex-1 overflow-y-auto relative" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex relative", style: { height: HOURS2.length * HOUR_HEIGHT2 } }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "w-20 bg-muted/5 border-r-[0.5px] border-border/30 relative" }, HOURS2.map((hour) => /* @__PURE__ */ import_react9.default.createElement(
|
|
994
1366
|
"div",
|
|
995
1367
|
{
|
|
996
1368
|
key: hour,
|
|
997
1369
|
className: "relative w-full",
|
|
998
|
-
style: { height:
|
|
1370
|
+
style: { height: HOUR_HEIGHT2 }
|
|
999
1371
|
},
|
|
1000
|
-
hour !== 0 && /* @__PURE__ */ import_react9.default.createElement("span", { className: "absolute w-full text-center -top-3 left-1/2 -translate-x-1/2 text-[11px] text-muted-foreground/80 font-medium tabular-nums bg-background px-1.5 py-0.5 rounded-md" }, (0,
|
|
1001
|
-
)),
|
|
1372
|
+
hour !== 0 && /* @__PURE__ */ import_react9.default.createElement("span", { className: "absolute w-full text-center -top-3 left-1/2 -translate-x-1/2 text-[11px] text-muted-foreground/80 font-medium tabular-nums bg-background px-1.5 py-0.5 rounded-md" }, (0, import_date_fns10.format)(slotDate2(currentDate, hour, 0), formats.hour, { locale }))
|
|
1373
|
+
)), isToday2 && /* @__PURE__ */ import_react9.default.createElement(
|
|
1002
1374
|
"div",
|
|
1003
1375
|
{
|
|
1004
1376
|
className: "absolute left-0 w-full pointer-events-none z-30 flex justify-end pr-2",
|
|
1005
|
-
style: {
|
|
1006
|
-
top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
|
|
1007
|
-
}
|
|
1377
|
+
style: { top: `${nowTop}px` }
|
|
1008
1378
|
},
|
|
1009
|
-
/* @__PURE__ */ import_react9.default.createElement("span", { className: "text-[10px] font-bold text-white bg-primary px-2 py-1 rounded-lg shadow-md shadow-primary/30 -translate-y-1/2" }, (0,
|
|
1010
|
-
)), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex-1 relative" },
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
style: {
|
|
1030
|
-
height: "25%",
|
|
1031
|
-
top: `${minute / 60 * 100}%`
|
|
1032
|
-
}
|
|
1379
|
+
/* @__PURE__ */ import_react9.default.createElement("span", { className: "text-[10px] font-bold text-white bg-primary px-2 py-1 rounded-lg shadow-md shadow-primary/30 -translate-y-1/2" }, (0, import_date_fns10.format)(zonedNow, formats.time, { locale }))
|
|
1380
|
+
)), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex-1 relative" }, HOURS2.map((hour) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1381
|
+
"div",
|
|
1382
|
+
{
|
|
1383
|
+
key: hour,
|
|
1384
|
+
className: "border-b-[0.5px] border-dashed border-border/20 box-border relative hover:bg-accent/5 transition-colors",
|
|
1385
|
+
style: { height: HOUR_HEIGHT2 }
|
|
1386
|
+
},
|
|
1387
|
+
QUARTERS2.map((minute) => {
|
|
1388
|
+
const cellDate = slotDate2(currentDate, hour, minute);
|
|
1389
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1390
|
+
DroppableCell,
|
|
1391
|
+
{
|
|
1392
|
+
key: minute,
|
|
1393
|
+
id: cellDate.toISOString(),
|
|
1394
|
+
date: cellDate,
|
|
1395
|
+
className: "w-full absolute left-0 right-0 z-0 transition-colors",
|
|
1396
|
+
style: {
|
|
1397
|
+
height: "25%",
|
|
1398
|
+
top: `${minute / 60 * 100}%`
|
|
1033
1399
|
},
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
);
|
|
1044
|
-
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
const s1 = getZonedDate(event.start).getTime();
|
|
1048
|
-
const e1 = getZonedDate(event.end).getTime();
|
|
1049
|
-
const s2 = getZonedDate(e.start).getTime();
|
|
1050
|
-
const e2 = getZonedDate(e.end).getTime();
|
|
1051
|
-
return s1 < e2 && e1 > s2;
|
|
1052
|
-
});
|
|
1053
|
-
const group = [event, ...overlappingEvents].sort(
|
|
1054
|
-
(a, b) => getZonedDate(a.start).getTime() - getZonedDate(b.start).getTime() || (a.id > b.id ? 1 : -1)
|
|
1055
|
-
);
|
|
1056
|
-
const index = group.findIndex((e) => e.id === event.id);
|
|
1057
|
-
const count = group.length;
|
|
1058
|
-
const widthPercent = 100 / count;
|
|
1059
|
-
const leftPercent = index * widthPercent;
|
|
1060
|
-
const zonedStart = getZonedDate(event.start);
|
|
1061
|
-
const zonedEnd = getZonedDate(event.end);
|
|
1062
|
-
const startMinutes = zonedStart.getHours() * 60 + zonedStart.getMinutes();
|
|
1063
|
-
const durationMinutes = (0, import_date_fns7.differenceInMinutes)(zonedEnd, zonedStart);
|
|
1064
|
-
const top = startMinutes / 60 * hourHeight;
|
|
1065
|
-
const height = durationMinutes / 60 * hourHeight;
|
|
1400
|
+
onSlotClick: onTimeSlotClick
|
|
1401
|
+
}
|
|
1402
|
+
);
|
|
1403
|
+
})
|
|
1404
|
+
)), positioned.map(({ event, start, end, column, columns }) => {
|
|
1405
|
+
const widthPercent = 100 / columns;
|
|
1406
|
+
const leftPercent = column * widthPercent;
|
|
1407
|
+
const zonedStart = toDisplay(event.start, timezone);
|
|
1408
|
+
const zonedEnd = toDisplay(event.end, timezone);
|
|
1409
|
+
const startMinutes = start.getHours() * 60 + start.getMinutes();
|
|
1410
|
+
const durationMinutes = (0, import_date_fns10.differenceInMinutes)(end, start);
|
|
1411
|
+
const top = startMinutes / 60 * HOUR_HEIGHT2;
|
|
1412
|
+
const height = durationMinutes / 60 * HOUR_HEIGHT2;
|
|
1066
1413
|
const isShortEvent = durationMinutes < 45;
|
|
1414
|
+
const isLastSegment = end.getTime() === zonedEnd.getTime();
|
|
1067
1415
|
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1068
1416
|
DraggableEvent,
|
|
1069
1417
|
{
|
|
1070
|
-
key: `${event.id}-${
|
|
1418
|
+
key: `${event.id}-${dayKey2}`,
|
|
1419
|
+
dragId: `${event.id}@${dayKey2}`,
|
|
1420
|
+
grabOffsetMs: start.getTime() - zonedStart.getTime(),
|
|
1071
1421
|
event,
|
|
1072
1422
|
className: `absolute z-10 transition-all ${readonly ? "cursor-default" : ""}`,
|
|
1073
1423
|
style: {
|
|
@@ -1075,15 +1425,15 @@ var DayView = ({
|
|
|
1075
1425
|
height: `${Math.max(height, 28)}px`,
|
|
1076
1426
|
left: `calc(${leftPercent}% + 4px)`,
|
|
1077
1427
|
width: `calc(${widthPercent}% - 8px)`,
|
|
1078
|
-
paddingRight:
|
|
1428
|
+
paddingRight: columns > 1 ? "2px" : "0"
|
|
1079
1429
|
}
|
|
1080
1430
|
},
|
|
1081
1431
|
/* @__PURE__ */ import_react9.default.createElement(
|
|
1082
1432
|
ResizableEvent,
|
|
1083
1433
|
{
|
|
1084
|
-
readonly,
|
|
1434
|
+
readonly: readonly || !isLastSegment,
|
|
1085
1435
|
event,
|
|
1086
|
-
hourHeight,
|
|
1436
|
+
hourHeight: HOUR_HEIGHT2,
|
|
1087
1437
|
onResize: onEventResize,
|
|
1088
1438
|
className: "h-full",
|
|
1089
1439
|
style: { height: "100%" }
|
|
@@ -1097,44 +1447,43 @@ var DayView = ({
|
|
|
1097
1447
|
readonly || isEventDragDisabled(event) ? "cursor-default" : "cursor-grab active:cursor-grabbing",
|
|
1098
1448
|
!event.color && "bg-primary/10 border-primary/20",
|
|
1099
1449
|
isShortEvent ? "px-2 flex items-center" : "px-3 py-2",
|
|
1100
|
-
|
|
1450
|
+
columns > 1 && "border-l-4"
|
|
1101
1451
|
),
|
|
1102
1452
|
style: {
|
|
1103
1453
|
backgroundColor: event.color ? `${event.color}15` : void 0,
|
|
1104
1454
|
borderColor: event.color ? `${event.color}30` : void 0,
|
|
1105
1455
|
borderLeftColor: event.color || "var(--primary)",
|
|
1106
|
-
borderLeftWidth:
|
|
1456
|
+
borderLeftWidth: columns > 1 ? "4px" : "3px"
|
|
1107
1457
|
},
|
|
1108
1458
|
onClick: (e) => {
|
|
1109
1459
|
e.stopPropagation();
|
|
1110
1460
|
onEventClick?.(event);
|
|
1111
1461
|
},
|
|
1112
|
-
title:
|
|
1462
|
+
title: columns > 1 ? `${event.title} (${column + 1}/${columns})` : void 0
|
|
1113
1463
|
},
|
|
1114
1464
|
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: cn(
|
|
1115
1465
|
"font-semibold truncate leading-tight",
|
|
1116
1466
|
isShortEvent ? "text-xs" : "text-sm",
|
|
1117
1467
|
event.color ? "text-foreground" : "text-foreground/90"
|
|
1118
|
-
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "text-xs text-muted-foreground mt-0.5 font-medium" }, (0,
|
|
1468
|
+
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "text-xs text-muted-foreground mt-0.5 font-medium" }, (0, import_date_fns10.format)(zonedStart, formats.time, { locale }), " - ", (0, import_date_fns10.format)(zonedEnd, formats.time, { locale })), event.description && height > 60 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "text-xs text-muted-foreground/80 mt-1 line-clamp-2" }, event.description)), columns > 1 && !isShortEvent && /* @__PURE__ */ import_react9.default.createElement("div", { className: "absolute top-1.5 right-1.5 bg-background/90 backdrop-blur-sm rounded-full w-5 h-5 flex items-center justify-center text-[10px] font-bold text-muted-foreground border border-border shadow-sm" }, columns))
|
|
1119
1469
|
)
|
|
1120
1470
|
)
|
|
1121
1471
|
);
|
|
1122
|
-
}),
|
|
1472
|
+
}), isToday2 && /* @__PURE__ */ import_react9.default.createElement(
|
|
1123
1473
|
"div",
|
|
1124
1474
|
{
|
|
1125
1475
|
className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
|
|
1126
|
-
style: {
|
|
1127
|
-
top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
|
|
1128
|
-
}
|
|
1476
|
+
style: { top: `${nowTop}px` }
|
|
1129
1477
|
},
|
|
1130
1478
|
/* @__PURE__ */ import_react9.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
|
|
1131
1479
|
/* @__PURE__ */ import_react9.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
|
|
1132
1480
|
)))));
|
|
1133
1481
|
};
|
|
1482
|
+
var DayView = import_react9.default.memo(DayViewImpl);
|
|
1134
1483
|
|
|
1135
1484
|
// src/views/AgendaView.tsx
|
|
1136
1485
|
var import_react11 = __toESM(require("react"));
|
|
1137
|
-
var
|
|
1486
|
+
var import_date_fns11 = require("date-fns");
|
|
1138
1487
|
|
|
1139
1488
|
// src/components/EmptyState.tsx
|
|
1140
1489
|
var import_react10 = __toESM(require("react"));
|
|
@@ -1153,17 +1502,17 @@ var AgendaEmptyState = ({ onCreateEvent, translations }) => /* @__PURE__ */ impo
|
|
|
1153
1502
|
var import_framer_motion = require("framer-motion");
|
|
1154
1503
|
var import_lucide_react5 = require("lucide-react");
|
|
1155
1504
|
var formatDuration = (start, end) => {
|
|
1156
|
-
const minutes = (0,
|
|
1505
|
+
const minutes = (0, import_date_fns11.differenceInMinutes)(end, start);
|
|
1157
1506
|
if (minutes < 60) return `${minutes}m`;
|
|
1158
1507
|
const hours = Math.floor(minutes / 60);
|
|
1159
1508
|
const remainingMinutes = minutes % 60;
|
|
1160
1509
|
if (remainingMinutes === 0) return `${hours}h`;
|
|
1161
1510
|
return `${hours}h ${remainingMinutes}m`;
|
|
1162
1511
|
};
|
|
1163
|
-
var getDateLabel = (date, locale, translations) => {
|
|
1164
|
-
if ((0,
|
|
1165
|
-
if ((0,
|
|
1166
|
-
return (0,
|
|
1512
|
+
var getDateLabel = (date, today, locale, translations) => {
|
|
1513
|
+
if ((0, import_date_fns11.isSameDay)(date, today)) return translations?.today || "Today";
|
|
1514
|
+
if ((0, import_date_fns11.isSameDay)(date, (0, import_date_fns11.addDays)(today, 1))) return translations?.tomorrow || "Tomorrow";
|
|
1515
|
+
return (0, import_date_fns11.format)(date, "EEEE", { locale });
|
|
1167
1516
|
};
|
|
1168
1517
|
var AgendaView = ({
|
|
1169
1518
|
currentDate,
|
|
@@ -1171,24 +1520,24 @@ var AgendaView = ({
|
|
|
1171
1520
|
onEventClick,
|
|
1172
1521
|
onCreateEvent,
|
|
1173
1522
|
locale,
|
|
1174
|
-
translations
|
|
1523
|
+
translations,
|
|
1524
|
+
timezone
|
|
1175
1525
|
}) => {
|
|
1176
1526
|
const is24h = uses24HourClock(locale);
|
|
1177
|
-
const
|
|
1178
|
-
const
|
|
1527
|
+
const { time: timePattern, compact: compactTimePattern } = timeFormats(locale);
|
|
1528
|
+
const today = displayToday(timezone);
|
|
1179
1529
|
const groupedEvents = (0, import_react11.useMemo)(() => {
|
|
1180
|
-
const
|
|
1530
|
+
const byDay = eventsByStartDay(events, timezone);
|
|
1181
1531
|
const groups = [];
|
|
1182
|
-
const sortedEvents = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
|
|
1183
1532
|
for (let i = 0; i < 30; i++) {
|
|
1184
|
-
const day = (0,
|
|
1185
|
-
const dayEvents =
|
|
1186
|
-
if (dayEvents
|
|
1187
|
-
groups.push({ date: day, events: dayEvents });
|
|
1533
|
+
const day = (0, import_date_fns11.addDays)((0, import_date_fns11.startOfDay)(currentDate), i);
|
|
1534
|
+
const dayEvents = byDay.get((0, import_date_fns11.format)(day, "yyyy-MM-dd"));
|
|
1535
|
+
if (dayEvents?.length) {
|
|
1536
|
+
groups.push({ date: day, events: [...dayEvents].sort((a, b) => a.start.getTime() - b.start.getTime()) });
|
|
1188
1537
|
}
|
|
1189
1538
|
}
|
|
1190
1539
|
return groups;
|
|
1191
|
-
}, [currentDate, events]);
|
|
1540
|
+
}, [currentDate, events, timezone]);
|
|
1192
1541
|
const container = {
|
|
1193
1542
|
hidden: { opacity: 0 },
|
|
1194
1543
|
show: {
|
|
@@ -1219,11 +1568,11 @@ var AgendaView = ({
|
|
|
1219
1568
|
},
|
|
1220
1569
|
/* @__PURE__ */ import_react11.default.createElement("div", { className: "sticky top-0 bg-background/95 backdrop-blur-md py-4 z-10 border-b border-border/50" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: cn(
|
|
1221
1570
|
"flex flex-col items-center justify-center w-16 h-16 rounded-2xl transition-all",
|
|
1222
|
-
(0,
|
|
1223
|
-
) }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-2xl font-bold leading-none" }, (0,
|
|
1571
|
+
(0, import_date_fns11.isSameDay)(group.date, today) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30" : "bg-muted/50 text-foreground"
|
|
1572
|
+
) }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-2xl font-bold leading-none" }, (0, import_date_fns11.format)(group.date, "d")), /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs font-medium uppercase tracking-wide opacity-80" }, (0, import_date_fns11.format)(group.date, "MMM", { locale }))), /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react11.default.createElement("span", { className: cn(
|
|
1224
1573
|
"text-lg font-semibold",
|
|
1225
|
-
(0,
|
|
1226
|
-
) }, getDateLabel(group.date, locale, translations)), /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-sm text-muted-foreground" }, group.events.length, " ", group.events.length !== 1 ? translations?.eventPlural || "events" : translations?.eventSingular || "event")))),
|
|
1574
|
+
(0, import_date_fns11.isSameDay)(group.date, today) && "text-primary"
|
|
1575
|
+
) }, getDateLabel(group.date, today, locale, translations)), /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-sm text-muted-foreground" }, group.events.length, " ", group.events.length !== 1 ? translations?.eventPlural || "events" : translations?.eventSingular || "event")))),
|
|
1227
1576
|
/* @__PURE__ */ import_react11.default.createElement("div", { className: "py-4 space-y-3" }, group.events.map((event) => /* @__PURE__ */ import_react11.default.createElement(
|
|
1228
1577
|
import_framer_motion.motion.div,
|
|
1229
1578
|
{
|
|
@@ -1245,14 +1594,14 @@ var AgendaView = ({
|
|
|
1245
1594
|
style: { backgroundColor: event.color || "var(--primary)" }
|
|
1246
1595
|
}
|
|
1247
1596
|
),
|
|
1248
|
-
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center min-w-[70px] pl-2" }, event.allDay ? /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs font-semibold text-muted-foreground bg-muted/80 px-2.5 py-1 rounded-full" }, translations?.allDay || "All Day")) : /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-base font-semibold text-foreground" }, (0,
|
|
1597
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center min-w-[70px] pl-2" }, event.allDay ? /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs font-semibold text-muted-foreground bg-muted/80 px-2.5 py-1 rounded-full" }, translations?.allDay || "All Day")) : /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-base font-semibold text-foreground" }, (0, import_date_fns11.format)(toDisplay(event.start, timezone), compactTimePattern, { locale })), !is24h && /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs text-muted-foreground uppercase" }, (0, import_date_fns11.format)(toDisplay(event.start, timezone), "a")), /* @__PURE__ */ import_react11.default.createElement("div", { className: "w-px h-3 bg-border my-1" }), /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs text-muted-foreground/70 font-medium" }, formatDuration(event.start, event.end)))),
|
|
1249
1598
|
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex-1 min-w-0 space-y-2" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-start justify-between gap-2" }, /* @__PURE__ */ import_react11.default.createElement("h4", { className: "text-base font-semibold text-foreground group-hover:text-primary transition-colors line-clamp-1" }, event.title), /* @__PURE__ */ import_react11.default.createElement(
|
|
1250
1599
|
"div",
|
|
1251
1600
|
{
|
|
1252
1601
|
className: "w-3 h-3 rounded-full shrink-0 mt-1.5",
|
|
1253
1602
|
style: { backgroundColor: event.color || "var(--primary)" }
|
|
1254
1603
|
}
|
|
1255
|
-
)), event.description && /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-sm text-muted-foreground line-clamp-2 leading-relaxed" }, event.description), /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-wrap items-center gap-3 pt-1" }, !event.allDay && /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react5.Clock, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react11.default.createElement("span", null, (0,
|
|
1604
|
+
)), event.description && /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-sm text-muted-foreground line-clamp-2 leading-relaxed" }, event.description), /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-wrap items-center gap-3 pt-1" }, !event.allDay && /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react5.Clock, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react11.default.createElement("span", null, (0, import_date_fns11.format)(toDisplay(event.start, timezone), timePattern, { locale }), " - ", (0, import_date_fns11.format)(toDisplay(event.end, timezone), timePattern, { locale }))), event.guests && event.guests.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react5.Users, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react11.default.createElement("span", null, event.guests.length, " ", event.guests.length !== 1 ? translations?.guestsCount || "guests" : translations?.guestCount || "guest")), event.attachments && event.attachments.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react5.Paperclip, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react11.default.createElement("span", null, event.attachments.length)), event.reminders && event.reminders.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react5.Bell, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react11.default.createElement("span", null, event.reminders.length)))),
|
|
1256
1605
|
/* @__PURE__ */ import_react11.default.createElement("div", { className: "absolute right-4 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react11.default.createElement("svg", { className: "w-5 h-5 text-muted-foreground", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react11.default.createElement("path", { d: "M9 18l6-6-6-6" })))
|
|
1257
1606
|
)))
|
|
1258
1607
|
))
|
|
@@ -1261,25 +1610,26 @@ var AgendaView = ({
|
|
|
1261
1610
|
|
|
1262
1611
|
// src/views/ResourceView.tsx
|
|
1263
1612
|
var import_react12 = __toESM(require("react"));
|
|
1264
|
-
var
|
|
1613
|
+
var import_date_fns12 = require("date-fns");
|
|
1265
1614
|
var ResourceView = ({
|
|
1266
1615
|
currentDate,
|
|
1267
1616
|
events,
|
|
1268
1617
|
resources,
|
|
1269
1618
|
onEventClick,
|
|
1270
1619
|
onTimeSlotClick,
|
|
1271
|
-
locale
|
|
1620
|
+
locale,
|
|
1621
|
+
timezone
|
|
1272
1622
|
}) => {
|
|
1273
1623
|
const containerRef = (0, import_react12.useRef)(null);
|
|
1274
1624
|
const hours = Array.from({ length: 24 }, (_, i) => i);
|
|
1275
1625
|
const hourWidth = 100;
|
|
1276
|
-
const timeFormat =
|
|
1626
|
+
const timeFormat = timeFormats(locale).hour;
|
|
1277
1627
|
const getEventStyle = (event) => {
|
|
1278
|
-
const start =
|
|
1279
|
-
const end =
|
|
1280
|
-
const dayStart = (0,
|
|
1281
|
-
const startMinutes = (0,
|
|
1282
|
-
const durationMinutes = (0,
|
|
1628
|
+
const start = toDisplay(event.start, timezone);
|
|
1629
|
+
const end = toDisplay(event.end, timezone);
|
|
1630
|
+
const dayStart = (0, import_date_fns12.startOfDay)(currentDate);
|
|
1631
|
+
const startMinutes = (0, import_date_fns12.differenceInMinutes)(start, dayStart);
|
|
1632
|
+
const durationMinutes = (0, import_date_fns12.differenceInMinutes)(end, start);
|
|
1283
1633
|
const left = startMinutes / 60 * hourWidth;
|
|
1284
1634
|
const width = durationMinutes / 60 * hourWidth;
|
|
1285
1635
|
return {
|
|
@@ -1295,10 +1645,10 @@ var ResourceView = ({
|
|
|
1295
1645
|
className: "border-r border-border/50 text-xs text-muted-foreground p-2 font-medium shrink-0",
|
|
1296
1646
|
style: { width: hourWidth }
|
|
1297
1647
|
},
|
|
1298
|
-
(0,
|
|
1648
|
+
(0, import_date_fns12.format)((/* @__PURE__ */ new Date()).setHours(hour, 0, 0, 0), timeFormat, { locale })
|
|
1299
1649
|
))))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex-1 overflow-auto relative", ref: containerRef }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "min-w-fit" }, resources.map((resource) => {
|
|
1300
1650
|
const resourceEvents = events.filter(
|
|
1301
|
-
(e) => e.resourceId === resource.id && (
|
|
1651
|
+
(e) => e.resourceId === resource.id && isSameDisplayDay(e.start, currentDate, timezone)
|
|
1302
1652
|
);
|
|
1303
1653
|
return /* @__PURE__ */ import_react12.default.createElement("div", { key: resource.id, className: "flex border-b border-border min-h-[100px]" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-48 shrink-0 border-r border-border p-4 bg-background sticky left-0 z-10 flex items-center gap-3" }, resource.avatar ? /* @__PURE__ */ import_react12.default.createElement("img", { src: resource.avatar, alt: resource.label, className: "w-8 h-8 rounded-full object-cover" }) : /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-bold text-primary" }, resource.label.substring(0, 2).toUpperCase()), /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-sm font-medium" }, resource.label), /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-xs text-muted-foreground" }, "ID: ", resource.id))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "relative flex", style: { width: hours.length * hourWidth } }, hours.map((hour) => /* @__PURE__ */ import_react12.default.createElement(
|
|
1304
1654
|
"div",
|
|
@@ -1308,20 +1658,18 @@ var ResourceView = ({
|
|
|
1308
1658
|
style: { width: hourWidth }
|
|
1309
1659
|
},
|
|
1310
1660
|
[0, 15, 30, 45].map((minute) => {
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
const slotId = `${resource.id}-${
|
|
1661
|
+
const slotDate3 = new Date(currentDate);
|
|
1662
|
+
slotDate3.setHours(hour, minute, 0, 0);
|
|
1663
|
+
const slotId = `${resource.id}-${slotDate3.toISOString()}`;
|
|
1314
1664
|
return /* @__PURE__ */ import_react12.default.createElement(
|
|
1315
1665
|
DroppableCell,
|
|
1316
1666
|
{
|
|
1317
1667
|
key: minute,
|
|
1318
1668
|
id: slotId,
|
|
1319
|
-
date:
|
|
1669
|
+
date: slotDate3,
|
|
1320
1670
|
resourceId: resource.id,
|
|
1321
1671
|
className: "h-full flex-1 border-r border-border/10 last:border-border/30 hover:bg-accent/10 transition-colors",
|
|
1322
|
-
|
|
1323
|
-
onTimeSlotClick?.(slotDate, resource.id);
|
|
1324
|
-
}
|
|
1672
|
+
onSlotClick: onTimeSlotClick
|
|
1325
1673
|
}
|
|
1326
1674
|
);
|
|
1327
1675
|
})
|
|
@@ -1407,7 +1755,7 @@ var Modal = ({
|
|
|
1407
1755
|
};
|
|
1408
1756
|
|
|
1409
1757
|
// src/components/EventModal.tsx
|
|
1410
|
-
var
|
|
1758
|
+
var import_date_fns13 = require("date-fns");
|
|
1411
1759
|
var import_framer_motion2 = require("framer-motion");
|
|
1412
1760
|
var import_lucide_react7 = require("lucide-react");
|
|
1413
1761
|
var REMINDER_OPTIONS = [
|
|
@@ -1544,7 +1892,7 @@ var EventModal = ({
|
|
|
1544
1892
|
};
|
|
1545
1893
|
const formatDateForInput = (date) => {
|
|
1546
1894
|
if (!date) return "";
|
|
1547
|
-
return (0,
|
|
1895
|
+
return (0, import_date_fns13.format)(date, "yyyy-MM-dd'T'HH:mm");
|
|
1548
1896
|
};
|
|
1549
1897
|
const handleDateChange = (field, value) => {
|
|
1550
1898
|
const date = new Date(value);
|
|
@@ -1594,7 +1942,7 @@ var EventModal = ({
|
|
|
1594
1942
|
};
|
|
1595
1943
|
const getDurationText = () => {
|
|
1596
1944
|
if (!formData.start || !formData.end) return "";
|
|
1597
|
-
const mins = (0,
|
|
1945
|
+
const mins = (0, import_date_fns13.differenceInMinutes)(formData.end, formData.start);
|
|
1598
1946
|
if (mins < 60) return `${mins} min`;
|
|
1599
1947
|
const hours = Math.floor(mins / 60);
|
|
1600
1948
|
const remainingMins = mins % 60;
|
|
@@ -1641,7 +1989,7 @@ var EventModal = ({
|
|
|
1641
1989
|
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
1642
1990
|
))),
|
|
1643
1991
|
/* @__PURE__ */ import_react14.default.createElement("h1", { className: "text-2xl font-bold text-foreground mb-3 leading-tight" }, event?.title || "(No title)"),
|
|
1644
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-3 text-sm" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Calendar, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react14.default.createElement("span", { className: "font-medium" }, event?.start && (0,
|
|
1992
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-3 text-sm" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Calendar, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react14.default.createElement("span", { className: "font-medium" }, event?.start && (0, import_date_fns13.format)(new Date(event.start), "EEE, MMM d"))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Clock, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react14.default.createElement("span", { className: "font-medium" }, event?.start && (0, import_date_fns13.format)(new Date(event.start), "h:mm a"), " \u2013 ", event?.end && (0, import_date_fns13.format)(new Date(event.end), "h:mm a"))))
|
|
1645
1993
|
), /* @__PURE__ */ import_react14.default.createElement("div", { className: "px-6 pb-6 space-y-4 overflow-y-auto flex-1" }, event?.location && /* @__PURE__ */ import_react14.default.createElement(
|
|
1646
1994
|
import_framer_motion2.motion.div,
|
|
1647
1995
|
{
|
|
@@ -2167,146 +2515,6 @@ var useEventContextMenu = () => {
|
|
|
2167
2515
|
};
|
|
2168
2516
|
};
|
|
2169
2517
|
|
|
2170
|
-
// src/locales/index.ts
|
|
2171
|
-
var en = {
|
|
2172
|
-
today: "Today",
|
|
2173
|
-
month: "Month",
|
|
2174
|
-
week: "Week",
|
|
2175
|
-
day: "Day",
|
|
2176
|
-
agenda: "Agenda",
|
|
2177
|
-
resource: "Resources",
|
|
2178
|
-
createEvent: "Create Event",
|
|
2179
|
-
editEvent: "Edit Event",
|
|
2180
|
-
delete: "Delete",
|
|
2181
|
-
save: "Save",
|
|
2182
|
-
cancel: "Cancel",
|
|
2183
|
-
title: "Add title",
|
|
2184
|
-
start: "Start",
|
|
2185
|
-
end: "End",
|
|
2186
|
-
allDay: "All Day",
|
|
2187
|
-
description: "Description",
|
|
2188
|
-
repeat: "Repeat",
|
|
2189
|
-
noRepeat: "Does not repeat",
|
|
2190
|
-
selectCalendar: "Select Calendar",
|
|
2191
|
-
selectType: "Select Type",
|
|
2192
|
-
daily: "Daily",
|
|
2193
|
-
weekly: "Weekly",
|
|
2194
|
-
monthly: "Monthly",
|
|
2195
|
-
yearly: "Yearly",
|
|
2196
|
-
search: "Search events...",
|
|
2197
|
-
allTypes: "All Types",
|
|
2198
|
-
timezone: "Time zone",
|
|
2199
|
-
localTime: "Local Time",
|
|
2200
|
-
create: "Create",
|
|
2201
|
-
calendars: "Calendars",
|
|
2202
|
-
event: "Event",
|
|
2203
|
-
task: "Task",
|
|
2204
|
-
appointmentSchedule: "Appointment schedule",
|
|
2205
|
-
new: "New",
|
|
2206
|
-
dateAndTime: "Date & Time",
|
|
2207
|
-
whosJoining: "Who's joining?",
|
|
2208
|
-
suggestedTimes: "Suggested times for guests",
|
|
2209
|
-
viewSuggestions: "View suggestions",
|
|
2210
|
-
whereWillItBe: "Where will it be?",
|
|
2211
|
-
location: "Enter address",
|
|
2212
|
-
descriptionAndAttachments: "Description",
|
|
2213
|
-
dragAndDrop: "Drag & drop files or",
|
|
2214
|
-
guests: "Guests",
|
|
2215
|
-
addGuests: "Add guests",
|
|
2216
|
-
addAttachment: "Upload files",
|
|
2217
|
-
moreOptions: "More options",
|
|
2218
|
-
doesNotRepeat: "Does not repeat",
|
|
2219
|
-
locationHelpText: 'Enter a physical address (e.g. "123 Main St") to generate the map.',
|
|
2220
|
-
notes: "Notes...",
|
|
2221
|
-
guestCount: "guest",
|
|
2222
|
-
guestsCount: "guests",
|
|
2223
|
-
repeatFor: "Repeat for",
|
|
2224
|
-
times: "times",
|
|
2225
|
-
until: "Until",
|
|
2226
|
-
endRepeat: "End repeat",
|
|
2227
|
-
never: "Never",
|
|
2228
|
-
afterOccurrences: "After occurrences",
|
|
2229
|
-
onDate: "On date",
|
|
2230
|
-
tomorrow: "Tomorrow",
|
|
2231
|
-
edit: "Edit",
|
|
2232
|
-
duplicate: "Duplicate",
|
|
2233
|
-
eventSingular: "event",
|
|
2234
|
-
eventPlural: "events",
|
|
2235
|
-
allCaughtUp: "All caught up!",
|
|
2236
|
-
noEventsScheduled: "No events scheduled",
|
|
2237
|
-
noUpcoming: "Your schedule is clear",
|
|
2238
|
-
noUpcomingHint: "No upcoming events to show. Create a new event to start planning."
|
|
2239
|
-
};
|
|
2240
|
-
var fr = {
|
|
2241
|
-
today: "Aujourd'hui",
|
|
2242
|
-
month: "Mois",
|
|
2243
|
-
week: "Semaine",
|
|
2244
|
-
day: "Jour",
|
|
2245
|
-
agenda: "Agenda",
|
|
2246
|
-
resource: "Ressources",
|
|
2247
|
-
createEvent: "Cr\xE9er un \xE9v\xE9nement",
|
|
2248
|
-
editEvent: "Modifier l'\xE9v\xE9nement",
|
|
2249
|
-
delete: "Supprimer",
|
|
2250
|
-
save: "Enregistrer",
|
|
2251
|
-
cancel: "Annuler",
|
|
2252
|
-
title: "Ajouter un titre",
|
|
2253
|
-
start: "D\xE9but",
|
|
2254
|
-
end: "Fin",
|
|
2255
|
-
allDay: "Toute la journ\xE9e",
|
|
2256
|
-
description: "Description",
|
|
2257
|
-
repeat: "R\xE9p\xE9ter",
|
|
2258
|
-
noRepeat: "Ne se r\xE9p\xE8te pas",
|
|
2259
|
-
selectCalendar: "S\xE9lectionner un calendrier",
|
|
2260
|
-
selectType: "S\xE9lectionner un type",
|
|
2261
|
-
daily: "Quotidien",
|
|
2262
|
-
weekly: "Hebdomadaire",
|
|
2263
|
-
monthly: "Mensuel",
|
|
2264
|
-
yearly: "Annuel",
|
|
2265
|
-
search: "Rechercher...",
|
|
2266
|
-
allTypes: "Tous les types",
|
|
2267
|
-
timezone: "Fuseau horaire",
|
|
2268
|
-
localTime: "Heure locale",
|
|
2269
|
-
create: "Cr\xE9er",
|
|
2270
|
-
calendars: "Calendriers",
|
|
2271
|
-
event: "\xC9v\xE9nement",
|
|
2272
|
-
task: "T\xE2che",
|
|
2273
|
-
appointmentSchedule: "Planning de rendez-vous",
|
|
2274
|
-
new: "Nouveau",
|
|
2275
|
-
dateAndTime: "Date et heure",
|
|
2276
|
-
whosJoining: "Qui participe ?",
|
|
2277
|
-
suggestedTimes: "Horaires sugg\xE9r\xE9s",
|
|
2278
|
-
viewSuggestions: "Voir les suggestions",
|
|
2279
|
-
whereWillItBe: "O\xF9 aura lieu ?",
|
|
2280
|
-
location: "Entrer une adresse",
|
|
2281
|
-
descriptionAndAttachments: "Description",
|
|
2282
|
-
dragAndDrop: "Glisser-d\xE9poser des fichiers ou",
|
|
2283
|
-
guests: "Invit\xE9s",
|
|
2284
|
-
addGuests: "Ajouter des invit\xE9s",
|
|
2285
|
-
addAttachment: "T\xE9l\xE9charger des fichiers",
|
|
2286
|
-
moreOptions: "Plus d'options",
|
|
2287
|
-
doesNotRepeat: "Ne se r\xE9p\xE8te pas",
|
|
2288
|
-
locationHelpText: 'Entrez une adresse physique (ex: "123 Rue Principale") pour g\xE9n\xE9rer la carte.',
|
|
2289
|
-
notes: "Notes...",
|
|
2290
|
-
guestCount: "invit\xE9",
|
|
2291
|
-
guestsCount: "invit\xE9s",
|
|
2292
|
-
repeatFor: "R\xE9p\xE9ter pendant",
|
|
2293
|
-
times: "fois",
|
|
2294
|
-
until: "Jusqu'au",
|
|
2295
|
-
endRepeat: "Fin de r\xE9p\xE9tition",
|
|
2296
|
-
never: "Jamais",
|
|
2297
|
-
afterOccurrences: "Apr\xE8s occurrences",
|
|
2298
|
-
onDate: "\xC0 la date",
|
|
2299
|
-
tomorrow: "Demain",
|
|
2300
|
-
edit: "Modifier",
|
|
2301
|
-
duplicate: "Dupliquer",
|
|
2302
|
-
eventSingular: "\xE9v\xE9nement",
|
|
2303
|
-
eventPlural: "\xE9v\xE9nements",
|
|
2304
|
-
allCaughtUp: "Tout est \xE0 jour !",
|
|
2305
|
-
noEventsScheduled: "Aucun \xE9v\xE9nement pr\xE9vu",
|
|
2306
|
-
noUpcoming: "Votre planning est libre",
|
|
2307
|
-
noUpcomingHint: "Aucun \xE9v\xE9nement \xE0 venir. Cr\xE9ez un nouvel \xE9v\xE9nement pour commencer \xE0 planifier."
|
|
2308
|
-
};
|
|
2309
|
-
|
|
2310
2518
|
// src/lib/theme.ts
|
|
2311
2519
|
function colorToHsl(color) {
|
|
2312
2520
|
let r = 0, g = 0, b = 0;
|
|
@@ -2387,10 +2595,149 @@ function getThemeStyles(theme) {
|
|
|
2387
2595
|
}
|
|
2388
2596
|
|
|
2389
2597
|
// src/hooks/useCalendarLogic.ts
|
|
2390
|
-
var
|
|
2391
|
-
var
|
|
2392
|
-
|
|
2598
|
+
var import_react18 = require("react");
|
|
2599
|
+
var import_date_fns15 = require("date-fns");
|
|
2600
|
+
|
|
2601
|
+
// src/core/recurrence.ts
|
|
2602
|
+
var import_date_fns14 = require("date-fns");
|
|
2393
2603
|
var import_rrule = require("rrule");
|
|
2604
|
+
var WEEKDAYS = [import_rrule.RRule.MO, import_rrule.RRule.TU, import_rrule.RRule.WE, import_rrule.RRule.TH, import_rrule.RRule.FR, import_rrule.RRule.SA, import_rrule.RRule.SU];
|
|
2605
|
+
var toFloating = (instant, tz) => {
|
|
2606
|
+
const w = toDisplay(instant, tz);
|
|
2607
|
+
return new Date(Date.UTC(w.getFullYear(), w.getMonth(), w.getDate(), w.getHours(), w.getMinutes(), w.getSeconds(), w.getMilliseconds()));
|
|
2608
|
+
};
|
|
2609
|
+
var fromFloating = (floating, tz) => fromDisplay(
|
|
2610
|
+
new Date(
|
|
2611
|
+
floating.getUTCFullYear(),
|
|
2612
|
+
floating.getUTCMonth(),
|
|
2613
|
+
floating.getUTCDate(),
|
|
2614
|
+
floating.getUTCHours(),
|
|
2615
|
+
floating.getUTCMinutes(),
|
|
2616
|
+
floating.getUTCSeconds(),
|
|
2617
|
+
floating.getUTCMilliseconds()
|
|
2618
|
+
),
|
|
2619
|
+
tz
|
|
2620
|
+
);
|
|
2621
|
+
var minuteKey = (date) => Math.floor(date.getTime() / 6e4);
|
|
2622
|
+
var FREQUENCIES = { DAILY: import_rrule.RRule.DAILY, WEEKLY: import_rrule.RRule.WEEKLY, MONTHLY: import_rrule.RRule.MONTHLY, YEARLY: import_rrule.RRule.YEARLY };
|
|
2623
|
+
function buildRule(event, tz) {
|
|
2624
|
+
const r = event.recurrence;
|
|
2625
|
+
const freq = FREQUENCIES[r.freq];
|
|
2626
|
+
if (freq === void 0) throw new Error(`unsupported frequency "${r.freq}"`);
|
|
2627
|
+
return new import_rrule.RRule({
|
|
2628
|
+
freq,
|
|
2629
|
+
interval: r.interval || 1,
|
|
2630
|
+
dtstart: toFloating(event.start, tz),
|
|
2631
|
+
until: r.until ? toFloating(r.until, tz) : void 0,
|
|
2632
|
+
count: r.count,
|
|
2633
|
+
byweekday: r.byweekday?.length ? r.byweekday.map((d) => WEEKDAYS[d]) : void 0
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
function occurrencesInMonth(event, monthStart, tz) {
|
|
2637
|
+
const rule = buildRule(event, tz);
|
|
2638
|
+
const excluded = new Set((event.recurrence.exdates ?? []).map(minuteKey));
|
|
2639
|
+
const duration = event.end.getTime() - event.start.getTime();
|
|
2640
|
+
const from = toFloating(monthStart, tz);
|
|
2641
|
+
const to = toFloating((0, import_date_fns14.addMonths)(monthStart, 1), tz);
|
|
2642
|
+
const result = [];
|
|
2643
|
+
for (const floating of rule.between(from, to, true)) {
|
|
2644
|
+
if (floating.getTime() === to.getTime()) continue;
|
|
2645
|
+
const start = fromFloating(floating, tz);
|
|
2646
|
+
if (excluded.has(minuteKey(start))) continue;
|
|
2647
|
+
result.push({
|
|
2648
|
+
...event,
|
|
2649
|
+
id: `${event.id}-${start.getTime()}`,
|
|
2650
|
+
originalEventId: event.id,
|
|
2651
|
+
occurrenceStart: start,
|
|
2652
|
+
start,
|
|
2653
|
+
end: new Date(start.getTime() + duration)
|
|
2654
|
+
});
|
|
2655
|
+
}
|
|
2656
|
+
return result;
|
|
2657
|
+
}
|
|
2658
|
+
var MAX_MONTHS_PER_EVENT = 12;
|
|
2659
|
+
var occurrenceCache = /* @__PURE__ */ new WeakMap();
|
|
2660
|
+
function cachedMonth(event, monthStart, tz) {
|
|
2661
|
+
let months = occurrenceCache.get(event);
|
|
2662
|
+
if (!months) {
|
|
2663
|
+
months = /* @__PURE__ */ new Map();
|
|
2664
|
+
occurrenceCache.set(event, months);
|
|
2665
|
+
}
|
|
2666
|
+
const key = `${monthStart.getFullYear()}-${monthStart.getMonth()}|${tz ?? ""}`;
|
|
2667
|
+
let occurrences = months.get(key);
|
|
2668
|
+
if (occurrences) {
|
|
2669
|
+
months.delete(key);
|
|
2670
|
+
} else {
|
|
2671
|
+
occurrences = occurrencesInMonth(event, monthStart, tz);
|
|
2672
|
+
if (months.size >= MAX_MONTHS_PER_EVENT) months.delete(months.keys().next().value);
|
|
2673
|
+
}
|
|
2674
|
+
months.set(key, occurrences);
|
|
2675
|
+
return occurrences;
|
|
2676
|
+
}
|
|
2677
|
+
function expandRecurrences(events, range, anchorTz) {
|
|
2678
|
+
const result = [];
|
|
2679
|
+
const firstMonth = (0, import_date_fns14.startOfMonth)(toDisplay(range.start, anchorTz));
|
|
2680
|
+
const lastMonth = (0, import_date_fns14.startOfMonth)(toDisplay(range.end, anchorTz));
|
|
2681
|
+
for (const event of events) {
|
|
2682
|
+
if (!event.recurrence) {
|
|
2683
|
+
result.push(event);
|
|
2684
|
+
continue;
|
|
2685
|
+
}
|
|
2686
|
+
try {
|
|
2687
|
+
for (let month = firstMonth; month <= lastMonth; month = (0, import_date_fns14.addMonths)(month, 1)) {
|
|
2688
|
+
for (const occurrence of cachedMonth(event, fromDisplay(month, anchorTz), anchorTz)) {
|
|
2689
|
+
if (occurrence.end >= range.start && occurrence.start <= range.end) result.push(occurrence);
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
} catch (error) {
|
|
2693
|
+
warnOnce(`invalid-recurrence:${event.id}`, `Event "${event.id}" has an invalid recurrence rule: ${String(error)}`);
|
|
2694
|
+
result.push(event);
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
return result;
|
|
2698
|
+
}
|
|
2699
|
+
function stripOccurrenceFields(event) {
|
|
2700
|
+
const { originalEventId: _originalEventId, occurrenceStart: _occurrenceStart, ...rest } = event;
|
|
2701
|
+
return rest;
|
|
2702
|
+
}
|
|
2703
|
+
var shiftFloating = (instant, deltaMs, tz) => fromFloating(new Date(toFloating(instant, tz).getTime() + deltaMs), tz);
|
|
2704
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2705
|
+
var floatingDay = (floating) => Math.floor(floating.getTime() / DAY_MS);
|
|
2706
|
+
function shiftSeries(master, occurrence, newStart, newEnd, anchorTz) {
|
|
2707
|
+
const fromFloat = toFloating(occurrence.start, anchorTz);
|
|
2708
|
+
const toFloat = toFloating(newStart, anchorTz);
|
|
2709
|
+
const deltaMs = toFloat.getTime() - fromFloat.getTime();
|
|
2710
|
+
const dayDelta = floatingDay(toFloat) - floatingDay(fromFloat);
|
|
2711
|
+
const start = shiftFloating(master.start, deltaMs, anchorTz);
|
|
2712
|
+
const end = new Date(start.getTime() + (newEnd.getTime() - newStart.getTime()));
|
|
2713
|
+
const recurrence = master.recurrence && {
|
|
2714
|
+
...master.recurrence,
|
|
2715
|
+
byweekday: master.recurrence.byweekday && dayDelta % 7 !== 0 ? master.recurrence.byweekday.map((d) => ((d + dayDelta) % 7 + 7) % 7) : master.recurrence.byweekday,
|
|
2716
|
+
exdates: master.recurrence.exdates?.map((d) => shiftFloating(d, deltaMs, anchorTz))
|
|
2717
|
+
};
|
|
2718
|
+
return stripOccurrenceFields({ ...master, start, end, recurrence });
|
|
2719
|
+
}
|
|
2720
|
+
function excludeOccurrence(master, occurrenceStart) {
|
|
2721
|
+
const recurrence = master.recurrence ?? { freq: "DAILY" };
|
|
2722
|
+
return { ...master, recurrence: { ...recurrence, exdates: [...recurrence.exdates ?? [], occurrenceStart] } };
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
// src/hooks/useStableCallback.ts
|
|
2726
|
+
var import_react17 = require("react");
|
|
2727
|
+
function useStableCallback(fn) {
|
|
2728
|
+
const ref = (0, import_react17.useRef)(fn);
|
|
2729
|
+
ref.current = fn;
|
|
2730
|
+
return (0, import_react17.useCallback)((...args) => ref.current(...args), []);
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// src/hooks/useCalendarLogic.ts
|
|
2734
|
+
function expansionRange(monthStart) {
|
|
2735
|
+
return {
|
|
2736
|
+
start: (0, import_date_fns15.startOfWeek)((0, import_date_fns15.startOfMonth)((0, import_date_fns15.subMonths)(monthStart, 1))),
|
|
2737
|
+
end: (0, import_date_fns15.addDays)((0, import_date_fns15.endOfMonth)((0, import_date_fns15.addMonths)(monthStart, 1)), 37)
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2740
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
2394
2741
|
var useCalendarLogic = ({
|
|
2395
2742
|
events,
|
|
2396
2743
|
view: controlledView,
|
|
@@ -2401,211 +2748,192 @@ var useCalendarLogic = ({
|
|
|
2401
2748
|
onEventUpdate,
|
|
2402
2749
|
onEventCreate,
|
|
2403
2750
|
onEventDelete,
|
|
2751
|
+
onEventDrop,
|
|
2752
|
+
onEventResize,
|
|
2753
|
+
onOccurrenceDelete,
|
|
2404
2754
|
readOnly,
|
|
2405
2755
|
timezone
|
|
2406
2756
|
}) => {
|
|
2407
|
-
const [internalView, setInternalView] = (0,
|
|
2408
|
-
const [internalDate, setInternalDate] = (0,
|
|
2409
|
-
const [isSidebarOpen, setIsSidebarOpen] = (0,
|
|
2410
|
-
const [isModalOpen, setIsModalOpen] = (0,
|
|
2411
|
-
const [selectedEvent, setSelectedEvent] = (0,
|
|
2412
|
-
const [modalInitialDate, setModalInitialDate] = (0,
|
|
2757
|
+
const [internalView, setInternalView] = (0, import_react18.useState)("week");
|
|
2758
|
+
const [internalDate, setInternalDate] = (0, import_react18.useState)(() => /* @__PURE__ */ new Date());
|
|
2759
|
+
const [isSidebarOpen, setIsSidebarOpen] = (0, import_react18.useState)(true);
|
|
2760
|
+
const [isModalOpen, setIsModalOpen] = (0, import_react18.useState)(false);
|
|
2761
|
+
const [selectedEvent, setSelectedEvent] = (0, import_react18.useState)(null);
|
|
2762
|
+
const [modalInitialDate, setModalInitialDate] = (0, import_react18.useState)(void 0);
|
|
2763
|
+
const [modalInitialResourceId, setModalInitialResourceId] = (0, import_react18.useState)(void 0);
|
|
2413
2764
|
const view = controlledView ?? internalView;
|
|
2414
2765
|
const currentDate = controlledDate ?? internalDate;
|
|
2415
|
-
const
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
interval: event.recurrence.interval || 1,
|
|
2425
|
-
dtstart: new Date(event.start),
|
|
2426
|
-
until: event.recurrence.until ? new Date(event.recurrence.until) : void 0,
|
|
2427
|
-
count: event.recurrence.count
|
|
2428
|
-
});
|
|
2429
|
-
const dates = rule.between(rangeStart, rangeEnd);
|
|
2430
|
-
dates.forEach((date) => {
|
|
2431
|
-
const duration = (0, import_date_fns11.differenceInMilliseconds)(new Date(event.end), new Date(event.start));
|
|
2432
|
-
allEvents.push({
|
|
2433
|
-
...event,
|
|
2434
|
-
id: `${event.id}-${date.getTime()}`,
|
|
2435
|
-
// Unique ID for each instance
|
|
2436
|
-
originalEventId: event.id,
|
|
2437
|
-
// Reference to original
|
|
2438
|
-
start: date,
|
|
2439
|
-
end: new Date(date.getTime() + duration)
|
|
2440
|
-
});
|
|
2441
|
-
});
|
|
2442
|
-
} catch (e) {
|
|
2443
|
-
console.error("Error parsing recurrence rule", e);
|
|
2444
|
-
allEvents.push(event);
|
|
2445
|
-
}
|
|
2446
|
-
} else {
|
|
2447
|
-
allEvents.push(event);
|
|
2448
|
-
}
|
|
2449
|
-
});
|
|
2450
|
-
return allEvents;
|
|
2451
|
-
}, [events, currentDate]);
|
|
2452
|
-
const handleViewChange = (newView) => {
|
|
2766
|
+
const normalizedEvents = (0, import_react18.useMemo)(() => normalizeEvents(events), [events]);
|
|
2767
|
+
const monthKey = (0, import_date_fns15.format)(currentDate, "yyyy-MM");
|
|
2768
|
+
const range = (0, import_react18.useMemo)(() => expansionRange(/* @__PURE__ */ new Date(`${monthKey}-01T00:00:00`)), [monthKey]);
|
|
2769
|
+
const expandedEvents = (0, import_react18.useMemo)(
|
|
2770
|
+
() => expandRecurrences(normalizedEvents, range, timezone),
|
|
2771
|
+
[normalizedEvents, range, timezone]
|
|
2772
|
+
);
|
|
2773
|
+
const masterOf = (occurrence) => normalizedEvents.find((e) => e.id === occurrence.originalEventId);
|
|
2774
|
+
const handleViewChange = useStableCallback((newView) => {
|
|
2453
2775
|
if (controlledOnViewChange) {
|
|
2454
2776
|
controlledOnViewChange(newView);
|
|
2455
2777
|
} else {
|
|
2456
2778
|
setInternalView(newView);
|
|
2457
2779
|
}
|
|
2458
|
-
};
|
|
2459
|
-
const handleDateChange = (newDate) => {
|
|
2780
|
+
});
|
|
2781
|
+
const handleDateChange = useStableCallback((newDate) => {
|
|
2460
2782
|
if (controlledOnDateChange) {
|
|
2461
2783
|
controlledOnDateChange(newDate);
|
|
2462
2784
|
} else {
|
|
2463
2785
|
setInternalDate(newDate);
|
|
2464
2786
|
}
|
|
2465
|
-
};
|
|
2466
|
-
const handlePrev = () => {
|
|
2787
|
+
});
|
|
2788
|
+
const handlePrev = useStableCallback(() => {
|
|
2467
2789
|
switch (view) {
|
|
2468
2790
|
case "month":
|
|
2469
|
-
handleDateChange((0,
|
|
2791
|
+
handleDateChange((0, import_date_fns15.subMonths)(currentDate, 1));
|
|
2470
2792
|
break;
|
|
2471
2793
|
case "week":
|
|
2472
|
-
handleDateChange((0,
|
|
2794
|
+
handleDateChange((0, import_date_fns15.subWeeks)(currentDate, 1));
|
|
2473
2795
|
break;
|
|
2474
2796
|
case "day":
|
|
2475
2797
|
case "resource":
|
|
2476
|
-
handleDateChange((0,
|
|
2798
|
+
handleDateChange((0, import_date_fns15.subDays)(currentDate, 1));
|
|
2477
2799
|
break;
|
|
2478
2800
|
case "agenda":
|
|
2479
|
-
handleDateChange((0,
|
|
2801
|
+
handleDateChange((0, import_date_fns15.subDays)(currentDate, 7));
|
|
2480
2802
|
break;
|
|
2481
2803
|
}
|
|
2482
|
-
};
|
|
2483
|
-
const handleNext = () => {
|
|
2804
|
+
});
|
|
2805
|
+
const handleNext = useStableCallback(() => {
|
|
2484
2806
|
switch (view) {
|
|
2485
2807
|
case "month":
|
|
2486
|
-
handleDateChange((0,
|
|
2808
|
+
handleDateChange((0, import_date_fns15.addMonths)(currentDate, 1));
|
|
2487
2809
|
break;
|
|
2488
2810
|
case "week":
|
|
2489
|
-
handleDateChange((0,
|
|
2811
|
+
handleDateChange((0, import_date_fns15.addWeeks)(currentDate, 1));
|
|
2490
2812
|
break;
|
|
2491
2813
|
case "day":
|
|
2492
2814
|
case "resource":
|
|
2493
|
-
handleDateChange((0,
|
|
2815
|
+
handleDateChange((0, import_date_fns15.addDays)(currentDate, 1));
|
|
2494
2816
|
break;
|
|
2495
2817
|
case "agenda":
|
|
2496
|
-
handleDateChange((0,
|
|
2818
|
+
handleDateChange((0, import_date_fns15.addDays)(currentDate, 7));
|
|
2497
2819
|
break;
|
|
2498
2820
|
}
|
|
2499
|
-
};
|
|
2500
|
-
const handleToday = () => {
|
|
2821
|
+
});
|
|
2822
|
+
const handleToday = useStableCallback(() => {
|
|
2501
2823
|
handleDateChange(/* @__PURE__ */ new Date());
|
|
2502
|
-
};
|
|
2503
|
-
const handleDateClick = (date) => {
|
|
2824
|
+
});
|
|
2825
|
+
const handleDateClick = useStableCallback((date) => {
|
|
2504
2826
|
handleDateChange(date);
|
|
2505
2827
|
handleViewChange("day");
|
|
2506
|
-
};
|
|
2507
|
-
const handleTimeSlotClick = (date) => {
|
|
2828
|
+
});
|
|
2829
|
+
const handleTimeSlotClick = useStableCallback((date, resourceId) => {
|
|
2508
2830
|
if (readOnly) return;
|
|
2509
2831
|
setSelectedEvent(null);
|
|
2510
2832
|
setModalInitialDate(date);
|
|
2833
|
+
setModalInitialResourceId(resourceId);
|
|
2511
2834
|
setIsModalOpen(true);
|
|
2512
|
-
};
|
|
2513
|
-
const handleEventClickInternal = (event) => {
|
|
2514
|
-
|
|
2515
|
-
onEventClick(event);
|
|
2516
|
-
}
|
|
2835
|
+
});
|
|
2836
|
+
const handleEventClickInternal = useStableCallback((event) => {
|
|
2837
|
+
onEventClick?.(event);
|
|
2517
2838
|
if (!readOnly) {
|
|
2518
2839
|
setSelectedEvent(event);
|
|
2519
2840
|
setModalInitialDate(void 0);
|
|
2841
|
+
setModalInitialResourceId(void 0);
|
|
2520
2842
|
setIsModalOpen(true);
|
|
2521
2843
|
}
|
|
2522
|
-
};
|
|
2523
|
-
const handleCreateEvent = () => {
|
|
2844
|
+
});
|
|
2845
|
+
const handleCreateEvent = useStableCallback(() => {
|
|
2524
2846
|
if (readOnly) return;
|
|
2525
2847
|
setSelectedEvent(null);
|
|
2526
2848
|
setModalInitialDate(/* @__PURE__ */ new Date());
|
|
2849
|
+
setModalInitialResourceId(void 0);
|
|
2527
2850
|
setIsModalOpen(true);
|
|
2528
|
-
};
|
|
2529
|
-
const handleModalSave = (eventData) => {
|
|
2530
|
-
let effectiveEventId = selectedEvent?.id;
|
|
2851
|
+
});
|
|
2852
|
+
const handleModalSave = useStableCallback((eventData) => {
|
|
2531
2853
|
if (selectedEvent?.originalEventId) {
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
}
|
|
2854
|
+
const master = masterOf(selectedEvent);
|
|
2855
|
+
if (!master) return;
|
|
2856
|
+
const edited = {
|
|
2857
|
+
...master,
|
|
2858
|
+
...stripOccurrenceFields(eventData),
|
|
2859
|
+
id: master.id,
|
|
2860
|
+
start: master.start,
|
|
2861
|
+
end: master.end
|
|
2862
|
+
};
|
|
2863
|
+
onEventUpdate?.(
|
|
2864
|
+
shiftSeries(edited, selectedEvent, eventData.start ?? selectedEvent.start, eventData.end ?? selectedEvent.end, timezone)
|
|
2865
|
+
);
|
|
2866
|
+
} else if (selectedEvent) {
|
|
2867
|
+
onEventUpdate?.({ ...eventData, id: selectedEvent.id });
|
|
2541
2868
|
} else {
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
2546
|
-
};
|
|
2547
|
-
const handleModalDelete = (eventId) => {
|
|
2548
|
-
let effectiveEventId = eventId;
|
|
2549
|
-
if (selectedEvent?.originalEventId && selectedEvent.id === eventId) {
|
|
2550
|
-
effectiveEventId = selectedEvent.originalEventId;
|
|
2869
|
+
onEventCreate?.(
|
|
2870
|
+
modalInitialResourceId && eventData.resourceId === void 0 ? { ...eventData, resourceId: modalInitialResourceId } : eventData
|
|
2871
|
+
);
|
|
2551
2872
|
}
|
|
2552
|
-
|
|
2553
|
-
|
|
2873
|
+
});
|
|
2874
|
+
const handleEventDelete = useStableCallback((event) => {
|
|
2875
|
+
if (!event.originalEventId) {
|
|
2876
|
+
onEventDelete?.(event.id);
|
|
2877
|
+
return;
|
|
2554
2878
|
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
if (!over) return;
|
|
2559
|
-
const activeEvent = active.data.current?.event;
|
|
2560
|
-
const overDate = over.data.current?.date;
|
|
2561
|
-
if (!activeEvent || !overDate) return;
|
|
2562
|
-
const originalStart = new Date(activeEvent.start);
|
|
2563
|
-
const originalEnd = new Date(activeEvent.end);
|
|
2564
|
-
const duration = (0, import_date_fns11.differenceInMilliseconds)(originalEnd, originalStart);
|
|
2565
|
-
let newStart;
|
|
2566
|
-
if (view === "month") {
|
|
2567
|
-
if (timezone) {
|
|
2568
|
-
const zonedOriginal = (0, import_date_fns_tz5.toZonedTime)(originalStart, timezone);
|
|
2569
|
-
const zonedNew = new Date(overDate);
|
|
2570
|
-
zonedNew.setHours(zonedOriginal.getHours());
|
|
2571
|
-
zonedNew.setMinutes(zonedOriginal.getMinutes());
|
|
2572
|
-
zonedNew.setSeconds(zonedOriginal.getSeconds());
|
|
2573
|
-
zonedNew.setMilliseconds(zonedOriginal.getMilliseconds());
|
|
2574
|
-
newStart = (0, import_date_fns_tz5.fromZonedTime)(zonedNew, timezone);
|
|
2575
|
-
} else {
|
|
2576
|
-
newStart = new Date(overDate);
|
|
2577
|
-
newStart.setHours(originalStart.getHours());
|
|
2578
|
-
newStart.setMinutes(originalStart.getMinutes());
|
|
2579
|
-
newStart.setSeconds(originalStart.getSeconds());
|
|
2580
|
-
newStart.setMilliseconds(originalStart.getMilliseconds());
|
|
2581
|
-
}
|
|
2879
|
+
const master = masterOf(event);
|
|
2880
|
+
if (onOccurrenceDelete && master) {
|
|
2881
|
+
onOccurrenceDelete(event, excludeOccurrence(master, event.occurrenceStart ?? event.start));
|
|
2582
2882
|
} else {
|
|
2583
|
-
|
|
2584
|
-
newStart = (0, import_date_fns_tz5.fromZonedTime)(overDate, timezone);
|
|
2585
|
-
} else {
|
|
2586
|
-
newStart = new Date(overDate);
|
|
2587
|
-
}
|
|
2588
|
-
newStart.setSeconds(0);
|
|
2589
|
-
newStart.setMilliseconds(0);
|
|
2590
|
-
}
|
|
2591
|
-
const newEnd = new Date(newStart.getTime() + duration);
|
|
2592
|
-
let newResourceId = activeEvent.resourceId;
|
|
2593
|
-
const overResourceId = over.data.current?.resourceId;
|
|
2594
|
-
if (overResourceId) {
|
|
2595
|
-
newResourceId = overResourceId;
|
|
2883
|
+
onEventDelete?.(event.originalEventId);
|
|
2596
2884
|
}
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
start: newStart,
|
|
2604
|
-
end: newEnd,
|
|
2605
|
-
resourceId: newResourceId
|
|
2606
|
-
});
|
|
2885
|
+
});
|
|
2886
|
+
const handleModalDelete = useStableCallback((eventId) => {
|
|
2887
|
+
if (selectedEvent && selectedEvent.id === eventId) {
|
|
2888
|
+
handleEventDelete(selectedEvent);
|
|
2889
|
+
} else {
|
|
2890
|
+
onEventDelete?.(eventId);
|
|
2607
2891
|
}
|
|
2892
|
+
});
|
|
2893
|
+
const handleEventDuplicate = useStableCallback((event) => {
|
|
2894
|
+
const { recurrence: _recurrence, ...copy } = stripOccurrenceFields(event);
|
|
2895
|
+
onEventCreate?.({
|
|
2896
|
+
...copy,
|
|
2897
|
+
id: `${event.originalEventId ?? event.id}-copy-${Date.now()}`,
|
|
2898
|
+
title: `${event.title} (Copy)`,
|
|
2899
|
+
start: new Date(event.start.getTime() + DAY_MS2),
|
|
2900
|
+
end: new Date(event.end.getTime() + DAY_MS2)
|
|
2901
|
+
});
|
|
2902
|
+
});
|
|
2903
|
+
const applyChange = (event, start, end) => {
|
|
2904
|
+
if (!event.originalEventId) return { original: event, updated: { ...event, start, end } };
|
|
2905
|
+
const master = masterOf(event);
|
|
2906
|
+
if (!master) return null;
|
|
2907
|
+
return { original: master, updated: shiftSeries(master, event, start, end, timezone) };
|
|
2608
2908
|
};
|
|
2909
|
+
const handleDragEnd = useStableCallback((dragEvent) => {
|
|
2910
|
+
const { active, over } = dragEvent;
|
|
2911
|
+
if (!over) return;
|
|
2912
|
+
const dragged = active.data.current?.event;
|
|
2913
|
+
const overDate = over.data.current?.date;
|
|
2914
|
+
if (!dragged || !overDate) return;
|
|
2915
|
+
const drop = computeDrop({
|
|
2916
|
+
event: dragged,
|
|
2917
|
+
overDate,
|
|
2918
|
+
overResourceId: over.data.current?.resourceId,
|
|
2919
|
+
grabOffsetMs: active.data.current?.grabOffsetMs,
|
|
2920
|
+
view,
|
|
2921
|
+
tz: timezone
|
|
2922
|
+
});
|
|
2923
|
+
if (!drop) return;
|
|
2924
|
+
const change = applyChange(dragged, drop.start, drop.end);
|
|
2925
|
+
if (!change) return;
|
|
2926
|
+
const updated = { ...change.updated, resourceId: drop.resourceId };
|
|
2927
|
+
onEventDrop?.(change.original, updated.start, updated.end);
|
|
2928
|
+
onEventUpdate?.(updated);
|
|
2929
|
+
});
|
|
2930
|
+
const handleEventResize = useStableCallback((event, newEnd) => {
|
|
2931
|
+
if (readOnly) return;
|
|
2932
|
+
const change = applyChange(event, event.start, newEnd);
|
|
2933
|
+
if (!change) return;
|
|
2934
|
+
onEventResize?.(change.original, change.updated.start, change.updated.end);
|
|
2935
|
+
onEventUpdate?.(change.updated);
|
|
2936
|
+
});
|
|
2609
2937
|
return {
|
|
2610
2938
|
view,
|
|
2611
2939
|
currentDate,
|
|
@@ -2627,15 +2955,18 @@ var useCalendarLogic = ({
|
|
|
2627
2955
|
handleCreateEvent,
|
|
2628
2956
|
handleModalSave,
|
|
2629
2957
|
handleModalDelete,
|
|
2958
|
+
handleEventDelete,
|
|
2959
|
+
handleEventDuplicate,
|
|
2960
|
+
handleEventResize,
|
|
2630
2961
|
handleDragEnd
|
|
2631
2962
|
};
|
|
2632
2963
|
};
|
|
2633
2964
|
|
|
2634
2965
|
// src/index.tsx
|
|
2635
|
-
var
|
|
2966
|
+
var import_date_fns16 = require("date-fns");
|
|
2636
2967
|
|
|
2637
2968
|
// src/hooks/useSwipeGesture.ts
|
|
2638
|
-
var
|
|
2969
|
+
var import_react19 = require("react");
|
|
2639
2970
|
var useSwipeGesture = (options) => {
|
|
2640
2971
|
const {
|
|
2641
2972
|
onSwipeLeft,
|
|
@@ -2647,9 +2978,9 @@ var useSwipeGesture = (options) => {
|
|
|
2647
2978
|
allowedTime = 500,
|
|
2648
2979
|
enabled = true
|
|
2649
2980
|
} = options;
|
|
2650
|
-
const touchInfoRef = (0,
|
|
2651
|
-
const elementRef = (0,
|
|
2652
|
-
const handleTouchStart = (0,
|
|
2981
|
+
const touchInfoRef = (0, import_react19.useRef)(null);
|
|
2982
|
+
const elementRef = (0, import_react19.useRef)(null);
|
|
2983
|
+
const handleTouchStart = (0, import_react19.useCallback)((e) => {
|
|
2653
2984
|
if (!enabled) return;
|
|
2654
2985
|
const touch = e.touches[0];
|
|
2655
2986
|
touchInfoRef.current = {
|
|
@@ -2658,7 +2989,7 @@ var useSwipeGesture = (options) => {
|
|
|
2658
2989
|
startTime: Date.now()
|
|
2659
2990
|
};
|
|
2660
2991
|
}, [enabled]);
|
|
2661
|
-
const handleTouchEnd = (0,
|
|
2992
|
+
const handleTouchEnd = (0, import_react19.useCallback)((e) => {
|
|
2662
2993
|
if (!enabled || !touchInfoRef.current) return;
|
|
2663
2994
|
const touch = e.changedTouches[0];
|
|
2664
2995
|
const { startX, startY, startTime } = touchInfoRef.current;
|
|
@@ -2682,7 +3013,7 @@ var useSwipeGesture = (options) => {
|
|
|
2682
3013
|
}
|
|
2683
3014
|
touchInfoRef.current = null;
|
|
2684
3015
|
}, [enabled, threshold, restraint, allowedTime, onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown]);
|
|
2685
|
-
(0,
|
|
3016
|
+
(0, import_react19.useEffect)(() => {
|
|
2686
3017
|
const element = elementRef.current;
|
|
2687
3018
|
if (!element) return;
|
|
2688
3019
|
element.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
@@ -2716,7 +3047,9 @@ var Scheduler = ({
|
|
|
2716
3047
|
onEventCreate,
|
|
2717
3048
|
onEventUpdate,
|
|
2718
3049
|
onEventDelete,
|
|
3050
|
+
onEventDrop,
|
|
2719
3051
|
onEventResize,
|
|
3052
|
+
onOccurrenceDelete,
|
|
2720
3053
|
timezone,
|
|
2721
3054
|
onTimezoneChange,
|
|
2722
3055
|
className,
|
|
@@ -2738,7 +3071,7 @@ var Scheduler = ({
|
|
|
2738
3071
|
locale
|
|
2739
3072
|
// Date-fns locale
|
|
2740
3073
|
}) => {
|
|
2741
|
-
const [activeDragEvent, setActiveDragEvent] = (0,
|
|
3074
|
+
const [activeDragEvent, setActiveDragEvent] = (0, import_react20.useState)(null);
|
|
2742
3075
|
const {
|
|
2743
3076
|
contextMenuEvent,
|
|
2744
3077
|
contextMenuPosition,
|
|
@@ -2764,9 +3097,11 @@ var Scheduler = ({
|
|
|
2764
3097
|
handleCreateEvent,
|
|
2765
3098
|
handleModalSave,
|
|
2766
3099
|
handleModalDelete,
|
|
3100
|
+
handleEventDelete,
|
|
3101
|
+
handleEventDuplicate,
|
|
3102
|
+
handleEventResize,
|
|
2767
3103
|
handleDragEnd,
|
|
2768
3104
|
expandedEvents
|
|
2769
|
-
// New export
|
|
2770
3105
|
} = useCalendarLogic({
|
|
2771
3106
|
events,
|
|
2772
3107
|
view: controlledView,
|
|
@@ -2777,6 +3112,9 @@ var Scheduler = ({
|
|
|
2777
3112
|
onEventUpdate,
|
|
2778
3113
|
onEventCreate,
|
|
2779
3114
|
onEventDelete,
|
|
3115
|
+
onEventDrop,
|
|
3116
|
+
onEventResize,
|
|
3117
|
+
onOccurrenceDelete,
|
|
2780
3118
|
readOnly,
|
|
2781
3119
|
timezone
|
|
2782
3120
|
});
|
|
@@ -2791,57 +3129,40 @@ var Scheduler = ({
|
|
|
2791
3129
|
const snapToGrid = (0, import_modifiers.createSnapModifier)(gridSize);
|
|
2792
3130
|
const modifiers = [snapToGrid, import_modifiers.restrictToWindowEdges];
|
|
2793
3131
|
const dndSensors = readOnly ? [] : sensors;
|
|
2794
|
-
const
|
|
2795
|
-
if (readOnly) return;
|
|
2796
|
-
if (onEventResize) {
|
|
2797
|
-
onEventResize(event, event.start, newEnd);
|
|
2798
|
-
}
|
|
2799
|
-
if (onEventUpdate) {
|
|
2800
|
-
onEventUpdate({
|
|
2801
|
-
...event,
|
|
2802
|
-
end: newEnd
|
|
2803
|
-
});
|
|
2804
|
-
}
|
|
2805
|
-
};
|
|
2806
|
-
const id = (0, import_react19.useId)();
|
|
3132
|
+
const id = (0, import_react20.useId)();
|
|
2807
3133
|
const swipeRef = useViewSwipe(handlePrev, handleNext, true);
|
|
2808
|
-
const
|
|
2809
|
-
const
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
};
|
|
2813
|
-
const overlayTimeFormat = uses24HourClock(locale) ? "H:mm" : "h:mm a";
|
|
2814
|
-
const handleDragStart = (event) => {
|
|
2815
|
-
const { active } = event;
|
|
2816
|
-
const draggedEvent = expandedEvents.find((e) => e.id === active.id);
|
|
3134
|
+
const t = (0, import_react20.useMemo)(() => resolveTranslations(language, translations), [language, translations]);
|
|
3135
|
+
const overlayTimeFormat = timeFormats(locale).time;
|
|
3136
|
+
const handleDragStart = (0, import_react20.useCallback)((event) => {
|
|
3137
|
+
const draggedEvent = event.active.data.current?.event;
|
|
2817
3138
|
if (draggedEvent) {
|
|
2818
3139
|
setActiveDragEvent(draggedEvent);
|
|
2819
3140
|
}
|
|
2820
|
-
};
|
|
2821
|
-
const onDragEndWrapper = (event) => {
|
|
3141
|
+
}, []);
|
|
3142
|
+
const onDragEndWrapper = (0, import_react20.useCallback)((event) => {
|
|
2822
3143
|
setActiveDragEvent(null);
|
|
2823
3144
|
handleDragEnd(event);
|
|
2824
|
-
};
|
|
3145
|
+
}, [handleDragEnd]);
|
|
2825
3146
|
const getDragHeight = () => {
|
|
2826
3147
|
if (!activeDragEvent) return void 0;
|
|
2827
3148
|
if (view === "resource") {
|
|
2828
3149
|
return 80;
|
|
2829
3150
|
}
|
|
2830
3151
|
if (view !== "week" && view !== "day") return void 0;
|
|
2831
|
-
const duration = (0,
|
|
3152
|
+
const duration = (0, import_date_fns16.differenceInMinutes)(activeDragEvent.end, activeDragEvent.start);
|
|
2832
3153
|
const hourHeight = view === "day" ? 80 : 60;
|
|
2833
3154
|
return duration / 60 * hourHeight;
|
|
2834
3155
|
};
|
|
2835
3156
|
const getDragWidth = () => {
|
|
2836
3157
|
if (view === "month") return "100%";
|
|
2837
3158
|
if (view === "resource" && activeDragEvent) {
|
|
2838
|
-
const duration = (0,
|
|
3159
|
+
const duration = (0, import_date_fns16.differenceInMinutes)(activeDragEvent.end, activeDragEvent.start);
|
|
2839
3160
|
const width = duration / 60 * 100;
|
|
2840
3161
|
return `${Math.max(width, 4)}px`;
|
|
2841
3162
|
}
|
|
2842
3163
|
return "150px";
|
|
2843
3164
|
};
|
|
2844
|
-
const filteredEvents = (0,
|
|
3165
|
+
const filteredEvents = (0, import_react20.useMemo)(() => {
|
|
2845
3166
|
if (!calendars) return expandedEvents;
|
|
2846
3167
|
const activeCalendarIds = calendars.filter((c) => c.active !== false).map((c) => c.id);
|
|
2847
3168
|
return expandedEvents.filter((e) => {
|
|
@@ -2849,7 +3170,7 @@ var Scheduler = ({
|
|
|
2849
3170
|
return activeCalendarIds.includes(e.calendarId);
|
|
2850
3171
|
});
|
|
2851
3172
|
}, [expandedEvents, calendars]);
|
|
2852
|
-
return /* @__PURE__ */
|
|
3173
|
+
return /* @__PURE__ */ import_react20.default.createElement(
|
|
2853
3174
|
import_core3.DndContext,
|
|
2854
3175
|
{
|
|
2855
3176
|
id,
|
|
@@ -2858,13 +3179,13 @@ var Scheduler = ({
|
|
|
2858
3179
|
onDragEnd: onDragEndWrapper,
|
|
2859
3180
|
modifiers
|
|
2860
3181
|
},
|
|
2861
|
-
/* @__PURE__ */
|
|
3182
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
2862
3183
|
"div",
|
|
2863
3184
|
{
|
|
2864
3185
|
className: cn("flex flex-col h-full bg-background text-foreground relative", className),
|
|
2865
3186
|
style: getThemeStyles(theme)
|
|
2866
3187
|
},
|
|
2867
|
-
/* @__PURE__ */
|
|
3188
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
2868
3189
|
CalendarHeader,
|
|
2869
3190
|
{
|
|
2870
3191
|
currentDate,
|
|
@@ -2883,7 +3204,7 @@ var Scheduler = ({
|
|
|
2883
3204
|
locale
|
|
2884
3205
|
}
|
|
2885
3206
|
),
|
|
2886
|
-
/* @__PURE__ */
|
|
3207
|
+
/* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react20.default.createElement(
|
|
2887
3208
|
import_framer_motion4.motion.div,
|
|
2888
3209
|
{
|
|
2889
3210
|
className: cn(
|
|
@@ -2899,7 +3220,7 @@ var Scheduler = ({
|
|
|
2899
3220
|
ease: [0.4, 0, 0.2, 1]
|
|
2900
3221
|
}
|
|
2901
3222
|
},
|
|
2902
|
-
/* @__PURE__ */
|
|
3223
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
2903
3224
|
Sidebar,
|
|
2904
3225
|
{
|
|
2905
3226
|
currentDate,
|
|
@@ -2916,7 +3237,7 @@ var Scheduler = ({
|
|
|
2916
3237
|
locale
|
|
2917
3238
|
}
|
|
2918
3239
|
)
|
|
2919
|
-
), /* @__PURE__ */
|
|
3240
|
+
), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex-1 flex flex-col overflow-hidden relative" }, isLoading ? /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex-1 overflow-auto p-0 md:p-4" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-full min-w-full" }, view === "month" && /* @__PURE__ */ import_react20.default.createElement(MonthViewSkeleton, null), view === "week" && /* @__PURE__ */ import_react20.default.createElement(WeekViewSkeleton, null), view === "day" && /* @__PURE__ */ import_react20.default.createElement(DayViewSkeleton, null), view === "agenda" && /* @__PURE__ */ import_react20.default.createElement(AgendaViewSkeleton, null), view === "resource" && /* @__PURE__ */ import_react20.default.createElement(WeekViewSkeleton, null))) : /* @__PURE__ */ import_react20.default.createElement("div", { ref: swipeRef, className: "flex-1 overflow-auto p-0 md:p-4 touch-pan-y" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-full min-w-full" }, /* @__PURE__ */ import_react20.default.createElement(import_framer_motion4.AnimatePresence, { mode: "wait", initial: false }, /* @__PURE__ */ import_react20.default.createElement(
|
|
2920
3241
|
import_framer_motion4.motion.div,
|
|
2921
3242
|
{
|
|
2922
3243
|
key: `${view}-${currentDate.toISOString()}-${timezone || "local"}`,
|
|
@@ -2941,7 +3262,7 @@ var Scheduler = ({
|
|
|
2941
3262
|
},
|
|
2942
3263
|
className: "h-full"
|
|
2943
3264
|
},
|
|
2944
|
-
view === "month" && /* @__PURE__ */
|
|
3265
|
+
view === "month" && /* @__PURE__ */ import_react20.default.createElement(
|
|
2945
3266
|
MonthView,
|
|
2946
3267
|
{
|
|
2947
3268
|
currentDate,
|
|
@@ -2952,7 +3273,7 @@ var Scheduler = ({
|
|
|
2952
3273
|
locale
|
|
2953
3274
|
}
|
|
2954
3275
|
),
|
|
2955
|
-
view === "week" && /* @__PURE__ */
|
|
3276
|
+
view === "week" && /* @__PURE__ */ import_react20.default.createElement(
|
|
2956
3277
|
WeekView,
|
|
2957
3278
|
{
|
|
2958
3279
|
currentDate,
|
|
@@ -2965,7 +3286,7 @@ var Scheduler = ({
|
|
|
2965
3286
|
readonly: readOnly
|
|
2966
3287
|
}
|
|
2967
3288
|
),
|
|
2968
|
-
view === "day" && /* @__PURE__ */
|
|
3289
|
+
view === "day" && /* @__PURE__ */ import_react20.default.createElement(
|
|
2969
3290
|
DayView,
|
|
2970
3291
|
{
|
|
2971
3292
|
currentDate,
|
|
@@ -2978,7 +3299,7 @@ var Scheduler = ({
|
|
|
2978
3299
|
readonly: readOnly
|
|
2979
3300
|
}
|
|
2980
3301
|
),
|
|
2981
|
-
view === "agenda" && /* @__PURE__ */
|
|
3302
|
+
view === "agenda" && /* @__PURE__ */ import_react20.default.createElement(
|
|
2982
3303
|
AgendaView,
|
|
2983
3304
|
{
|
|
2984
3305
|
currentDate,
|
|
@@ -2986,30 +3307,29 @@ var Scheduler = ({
|
|
|
2986
3307
|
onEventClick: handleEventClickInternal,
|
|
2987
3308
|
onCreateEvent: handleCreateEvent,
|
|
2988
3309
|
locale,
|
|
2989
|
-
translations: t
|
|
3310
|
+
translations: t,
|
|
3311
|
+
timezone
|
|
2990
3312
|
}
|
|
2991
3313
|
),
|
|
2992
|
-
view === "resource" && resources && /* @__PURE__ */
|
|
3314
|
+
view === "resource" && resources && /* @__PURE__ */ import_react20.default.createElement(
|
|
2993
3315
|
ResourceView,
|
|
2994
3316
|
{
|
|
2995
3317
|
currentDate,
|
|
2996
3318
|
events: filteredEvents,
|
|
2997
3319
|
resources,
|
|
2998
3320
|
onEventClick: handleEventClickInternal,
|
|
2999
|
-
onTimeSlotClick:
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
},
|
|
3003
|
-
locale
|
|
3321
|
+
onTimeSlotClick: handleTimeSlotClick,
|
|
3322
|
+
locale,
|
|
3323
|
+
timezone
|
|
3004
3324
|
}
|
|
3005
3325
|
)
|
|
3006
|
-
)))), /* @__PURE__ */
|
|
3326
|
+
)))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "md:hidden absolute bottom-6 right-6 z-50" }, /* @__PURE__ */ import_react20.default.createElement(
|
|
3007
3327
|
"button",
|
|
3008
3328
|
{
|
|
3009
3329
|
onClick: handleCreateEvent,
|
|
3010
3330
|
className: "w-14 h-14 bg-blue-600 rounded-full shadow-lg flex items-center justify-center text-white active:scale-90 transition-transform"
|
|
3011
3331
|
},
|
|
3012
|
-
/* @__PURE__ */
|
|
3332
|
+
/* @__PURE__ */ import_react20.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react20.default.createElement("path", { d: "M5 12h14" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M12 5v14" }))
|
|
3013
3333
|
)))),
|
|
3014
3334
|
renderEventForm ? renderEventForm({
|
|
3015
3335
|
isOpen: isModalOpen,
|
|
@@ -3018,7 +3338,7 @@ var Scheduler = ({
|
|
|
3018
3338
|
initialDate: modalInitialDate,
|
|
3019
3339
|
onSave: handleModalSave,
|
|
3020
3340
|
onDelete: handleModalDelete
|
|
3021
|
-
}) : /* @__PURE__ */
|
|
3341
|
+
}) : /* @__PURE__ */ import_react20.default.createElement(
|
|
3022
3342
|
EventModal,
|
|
3023
3343
|
{
|
|
3024
3344
|
isOpen: isModalOpen,
|
|
@@ -3032,7 +3352,7 @@ var Scheduler = ({
|
|
|
3032
3352
|
translations: t
|
|
3033
3353
|
}
|
|
3034
3354
|
),
|
|
3035
|
-
/* @__PURE__ */
|
|
3355
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
3036
3356
|
EventContextMenu,
|
|
3037
3357
|
{
|
|
3038
3358
|
event: contextMenuEvent,
|
|
@@ -3042,20 +3362,12 @@ var Scheduler = ({
|
|
|
3042
3362
|
handleEventClickInternal(event);
|
|
3043
3363
|
closeContextMenu();
|
|
3044
3364
|
},
|
|
3045
|
-
onDelete: (
|
|
3046
|
-
|
|
3365
|
+
onDelete: () => {
|
|
3366
|
+
if (contextMenuEvent) handleEventDelete(contextMenuEvent);
|
|
3047
3367
|
closeContextMenu();
|
|
3048
3368
|
},
|
|
3049
3369
|
onDuplicate: (event) => {
|
|
3050
|
-
|
|
3051
|
-
...event,
|
|
3052
|
-
id: `${event.id}-copy-${Date.now()}`,
|
|
3053
|
-
title: `${event.title} (Copy)`,
|
|
3054
|
-
start: new Date(event.start.getTime() + 24 * 60 * 60 * 1e3),
|
|
3055
|
-
// +1 day
|
|
3056
|
-
end: new Date(event.end.getTime() + 24 * 60 * 60 * 1e3)
|
|
3057
|
-
};
|
|
3058
|
-
onEventCreate?.(duplicatedEvent);
|
|
3370
|
+
handleEventDuplicate(event);
|
|
3059
3371
|
closeContextMenu();
|
|
3060
3372
|
},
|
|
3061
3373
|
translations: {
|
|
@@ -3065,7 +3377,7 @@ var Scheduler = ({
|
|
|
3065
3377
|
}
|
|
3066
3378
|
}
|
|
3067
3379
|
),
|
|
3068
|
-
/* @__PURE__ */
|
|
3380
|
+
/* @__PURE__ */ import_react20.default.createElement(import_core3.DragOverlay, { dropAnimation: null }, activeDragEvent ? /* @__PURE__ */ import_react20.default.createElement(
|
|
3069
3381
|
"div",
|
|
3070
3382
|
{
|
|
3071
3383
|
className: cn(
|
|
@@ -3083,13 +3395,13 @@ var Scheduler = ({
|
|
|
3083
3395
|
transform: "rotate(-2deg) scale(1.02)"
|
|
3084
3396
|
}
|
|
3085
3397
|
},
|
|
3086
|
-
/* @__PURE__ */
|
|
3398
|
+
/* @__PURE__ */ import_react20.default.createElement("div", { className: "p-2.5 h-full flex flex-col" }, /* @__PURE__ */ import_react20.default.createElement(
|
|
3087
3399
|
"div",
|
|
3088
3400
|
{
|
|
3089
3401
|
className: "absolute left-0 top-0 bottom-0 w-1 rounded-l-lg",
|
|
3090
3402
|
style: { backgroundColor: activeDragEvent.color || "var(--primary)" }
|
|
3091
3403
|
}
|
|
3092
|
-
), /* @__PURE__ */
|
|
3404
|
+
), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pl-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "font-semibold truncate text-sm" }, activeDragEvent.title), (view === "week" || view === "day") && getDragHeight() && getDragHeight() > 40 && /* @__PURE__ */ import_react20.default.createElement("div", { className: "text-xs opacity-80 mt-0.5 flex items-center gap-1" }, /* @__PURE__ */ import_react20.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M12 6v6l4 2" })), (0, import_date_fns16.format)(activeDragEvent.start, overlayTimeFormat, { locale }), " - ", (0, import_date_fns16.format)(activeDragEvent.end, overlayTimeFormat, { locale }))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "absolute bottom-1.5 right-1.5 opacity-60" }, /* @__PURE__ */ import_react20.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "9", cy: "5", r: "1.5" }), /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "15", cy: "5", r: "1.5" }), /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "9", cy: "12", r: "1.5" }), /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "15", cy: "12", r: "1.5" }), /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "9", cy: "19", r: "1.5" }), /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "15", cy: "19", r: "1.5" }))))
|
|
3093
3405
|
) : null)
|
|
3094
3406
|
)
|
|
3095
3407
|
);
|