@vicacha-devs/strapi-plugin-calendar 0.0.0-stage → 1.0.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.
Files changed (90) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +163 -2
  3. package/dist/admin/CalendarPage-CVqowKst.cjs +1015 -0
  4. package/dist/admin/CalendarPage-Dq6YfSXF.js +1015 -0
  5. package/dist/admin/SettingsPage-7SecVQEi.js +2088 -0
  6. package/dist/admin/SettingsPage-D0aCDb9w.cjs +2088 -0
  7. package/dist/admin/ar-O6QL_nJZ.js +331 -0
  8. package/dist/admin/ar-yKsEpX_y.cjs +331 -0
  9. package/dist/admin/de-BpDxjctz.js +331 -0
  10. package/dist/admin/de-ryVtwWOz.cjs +331 -0
  11. package/dist/admin/en-BHYSUqXv.cjs +331 -0
  12. package/dist/admin/en-BoRq-9QD.js +331 -0
  13. package/dist/admin/es-BZ7WX8Ev.js +331 -0
  14. package/dist/admin/es-T5v93hXW.cjs +331 -0
  15. package/dist/admin/fr-BnDr9DC8.js +331 -0
  16. package/dist/admin/fr-DTdTwx7e.cjs +331 -0
  17. package/dist/admin/index-DO0QbnXX.cjs +3223 -0
  18. package/dist/admin/index-USqxqyAm.js +3216 -0
  19. package/dist/admin/index.cjs +9 -0
  20. package/dist/admin/index.js +9 -0
  21. package/dist/admin/index.mjs +9 -0
  22. package/dist/admin/it-BkJNzy27.cjs +331 -0
  23. package/dist/admin/it-DkdUInap.js +331 -0
  24. package/dist/admin/nl-C2NFORLS.js +331 -0
  25. package/dist/admin/nl-CjnlbeUM.cjs +331 -0
  26. package/dist/admin/pl-BJArPgCQ.cjs +331 -0
  27. package/dist/admin/pl-mv5eXA8W.js +331 -0
  28. package/dist/admin/pt-CSYqSGnz.cjs +331 -0
  29. package/dist/admin/pt-WpvZGj3b.js +331 -0
  30. package/dist/admin/src/components/CalendarSidePanel.d.ts +13 -0
  31. package/dist/admin/src/components/Initializer.d.ts +6 -0
  32. package/dist/admin/src/components/PluginIcon.d.ts +3 -0
  33. package/dist/admin/src/components/RRuleInput.d.ts +20 -0
  34. package/dist/admin/src/components/calendar/CalendarToolbar.d.ts +32 -0
  35. package/dist/admin/src/components/calendar/FullCalendarCanvas.d.ts +21 -0
  36. package/dist/admin/src/components/calendar/FullCalendarDayCell.d.ts +11 -0
  37. package/dist/admin/src/components/calendar/OccurrenceDetailDrawer.d.ts +15 -0
  38. package/dist/admin/src/components/calendar/QuickCreatePanel.d.ts +29 -0
  39. package/dist/admin/src/components/calendar/QuickCreateSubcomponents.d.ts +40 -0
  40. package/dist/admin/src/components/calendar/calendarPageHelpers.d.ts +52 -0
  41. package/dist/admin/src/components/calendar/calendarThemeStyles.d.ts +2 -0
  42. package/dist/admin/src/components/settings/CalendarThemeSection.d.ts +9 -0
  43. package/dist/admin/src/components/settings/CalendarViewsSection.d.ts +10 -0
  44. package/dist/admin/src/components/settings/CollectionSourcesSection.d.ts +12 -0
  45. package/dist/admin/src/components/settings/CompanionSuiteSettingsSection.d.ts +29 -0
  46. package/dist/admin/src/components/settings/SecondaryCalendarsSection.d.ts +11 -0
  47. package/dist/admin/src/fields/rruleField.d.ts +19 -0
  48. package/dist/admin/src/index.d.ts +18 -0
  49. package/dist/admin/src/pages/CalendarPage.d.ts +3 -0
  50. package/dist/admin/src/pages/SettingsPage.d.ts +3 -0
  51. package/dist/admin/src/pages/calendarPageSupport.d.ts +8 -0
  52. package/dist/admin/tr-BhZKvFoK.js +331 -0
  53. package/dist/admin/tr-zUVxuw9X.cjs +331 -0
  54. package/dist/package.json +3 -0
  55. package/dist/server/index.cjs +2585 -0
  56. package/dist/server/index.js +2585 -0
  57. package/dist/server/index.mjs +2585 -0
  58. package/dist/server/src/bootstrap.d.ts +5 -0
  59. package/dist/server/src/config/index.d.ts +7 -0
  60. package/dist/server/src/controllers/admin.d.ts +15 -0
  61. package/dist/server/src/controllers/content-api.d.ts +10 -0
  62. package/dist/server/src/controllers/index.d.ts +21 -0
  63. package/dist/server/src/destroy.d.ts +5 -0
  64. package/dist/server/src/index.d.ts +85 -0
  65. package/dist/server/src/register.d.ts +5 -0
  66. package/dist/server/src/routes/admin.d.ts +17 -0
  67. package/dist/server/src/routes/content-api.d.ts +10 -0
  68. package/dist/server/src/routes/index.d.ts +28 -0
  69. package/dist/server/src/services/builtinSources.d.ts +3 -0
  70. package/dist/server/src/services/ical.d.ts +6 -0
  71. package/dist/server/src/services/index.d.ts +23 -0
  72. package/dist/server/src/services/occurrence.d.ts +6 -0
  73. package/dist/server/src/services/occurrenceDates.d.ts +7 -0
  74. package/dist/server/src/services/quickCreateHelpers.d.ts +20 -0
  75. package/dist/server/src/services/registry.d.ts +19 -0
  76. package/dist/server/src/services/settings.d.ts +6 -0
  77. package/dist/server/src/types.d.ts +98 -0
  78. package/dist/shared/calendarSystems.d.ts +41 -0
  79. package/dist/shared/icalGenerator.d.ts +18 -0
  80. package/dist/shared/index.cjs +1612 -0
  81. package/dist/shared/index.d.ts +6 -0
  82. package/dist/shared/index.js +1612 -0
  83. package/dist/shared/index.mjs +1612 -0
  84. package/dist/shared/localization.d.ts +14 -0
  85. package/dist/shared/pluginId.d.ts +2 -0
  86. package/dist/shared/rruleEngine.d.ts +22 -0
  87. package/dist/shared/themePalettes.d.ts +27 -0
  88. package/dist/shared/themePresets.d.ts +32 -0
  89. package/dist/shared/types.d.ts +311 -0
  90. package/package.json +120 -3
@@ -0,0 +1,1015 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { Box, Flex, Badge, Typography, Field, DatePicker, Button, Checkbox, DateTimePicker, TextInput, SingleSelect, SingleSelectOption } from "@strapi/design-system";
3
+ import { useFetchClient } from "@strapi/strapi/admin";
4
+ import { useMemo, useRef, useCallback, useState, useEffect } from "react";
5
+ import { useIntl } from "react-intl";
6
+ import { f as formatCategoryLabel, d as describeRRule, a as formatLocalYmd, p as parseDateTimePickerValue, W as WEEKDAYS, b as buildOrderedRecurrencePresets, e as extractByDays, c as alignStartDateToWeekday, P as PLUGIN_ID, g as buildInitialDateWindow, r as resolveFullCalendarLocale, h as resolveCalendarDirection, m as matchLoadedSourceId, i as computeSourceCounts, j as filterVisibleOccurrences, k as collectAvailableCategories, l as resolveActiveSecondaryCalendars, F as FALLBACK_RECURRENCE_PRESETS, n as mapOccurrencesToFullCalendarEvents, o as buildSecondaryHeaderLabel, q as buildEnabledCalendarViews, C as CalendarToolbar, s as FullCalendarCanvas, t as buildQuickCreateRequestPayload, u as normalizeSelectedEndSlot, v as expandDateWindowToYear } from "./index-USqxqyAm.js";
7
+ import { NavLink } from "react-router-dom";
8
+ const OccurrenceDetailDrawer = ({
9
+ t,
10
+ occurrence,
11
+ rescheduleDate,
12
+ onRescheduleDateChange,
13
+ applyToSeries,
14
+ onApplyToSeriesChange,
15
+ onSaveReschedule,
16
+ onCancelOccurrence,
17
+ onClose
18
+ }) => {
19
+ return /* @__PURE__ */ jsx(
20
+ Box,
21
+ {
22
+ padding: 4,
23
+ background: "neutral0",
24
+ hasRadius: true,
25
+ shadow: "tableShadow",
26
+ style: { borderLeft: `4px solid ${occurrence.color}` },
27
+ children: /* @__PURE__ */ jsxs(
28
+ Flex,
29
+ {
30
+ justifyContent: "space-between",
31
+ alignItems: "flex-start",
32
+ wrap: "wrap",
33
+ gap: 4,
34
+ children: [
35
+ /* @__PURE__ */ jsxs(Box, { style: { flex: 2, minWidth: 260 }, children: [
36
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
37
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: occurrence.sourceLabel }),
38
+ occurrence.category && /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: formatCategoryLabel(occurrence.category) }),
39
+ occurrence.isRecurring && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: describeRRule(occurrence.rrule) }),
40
+ occurrence.alternateDates && Object.values(occurrence.alternateDates).map((alt) => /* @__PURE__ */ jsxs(
41
+ Badge,
42
+ {
43
+ backgroundColor: "warning100",
44
+ textColor: "warning700",
45
+ children: [
46
+ alt.label,
47
+ ": ",
48
+ alt.formatted
49
+ ]
50
+ },
51
+ alt.calendarId
52
+ ))
53
+ ] }),
54
+ /* @__PURE__ */ jsx(Box, { paddingTop: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: occurrence.title }) }),
55
+ /* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", textColor: "neutral600", children: [
56
+ occurrence.occurrenceDate,
57
+ occurrence.location ? ` • ${occurrence.location}` : ""
58
+ ] }) }),
59
+ occurrence.customFields && Object.keys(occurrence.customFields).length > 0 && /* @__PURE__ */ jsx(Box, { paddingTop: 2, children: /* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", children: Object.entries(occurrence.customFields).map(
60
+ ([k, v]) => v !== null && v !== void 0 && String(v).trim() !== "" ? /* @__PURE__ */ jsxs(
61
+ Badge,
62
+ {
63
+ backgroundColor: "neutral100",
64
+ textColor: "neutral700",
65
+ children: [
66
+ k,
67
+ ": ",
68
+ String(v)
69
+ ]
70
+ },
71
+ k
72
+ ) : null
73
+ ) }) })
74
+ ] }),
75
+ /* @__PURE__ */ jsxs(
76
+ Flex,
77
+ {
78
+ direction: "column",
79
+ alignItems: "flex-end",
80
+ gap: 2,
81
+ style: { flex: "1 1 320px", minWidth: 260 },
82
+ children: [
83
+ /* @__PURE__ */ jsxs(
84
+ Flex,
85
+ {
86
+ gap: 2,
87
+ alignItems: "flex-end",
88
+ wrap: "wrap",
89
+ justifyContent: "flex-end",
90
+ children: [
91
+ /* @__PURE__ */ jsx(Box, { style: { minWidth: 180, maxWidth: 220 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
92
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.rescheduleTo", "Reschedule Date") }),
93
+ /* @__PURE__ */ jsx(
94
+ DatePicker,
95
+ {
96
+ size: "S",
97
+ value: parseDateTimePickerValue(rescheduleDate),
98
+ clearLabel: t("common.clear", "Clear"),
99
+ onChange: (date) => onRescheduleDateChange(date ? formatLocalYmd(date) : ""),
100
+ onClear: () => onRescheduleDateChange("")
101
+ }
102
+ )
103
+ ] }) }),
104
+ /* @__PURE__ */ jsx(Button, { size: "S", variant: "secondary", onClick: onSaveReschedule, children: t("calendar.rescheduleAction", "Reschedule") })
105
+ ]
106
+ }
107
+ ),
108
+ occurrence.isRecurring && /* @__PURE__ */ jsx(
109
+ Checkbox,
110
+ {
111
+ checked: applyToSeries,
112
+ onCheckedChange: (checked) => onApplyToSeriesChange(Boolean(checked)),
113
+ children: t("calendar.applyToSeries", "Apply to entire recurring series")
114
+ }
115
+ ),
116
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", paddingTop: 1, children: [
117
+ /* @__PURE__ */ jsx(
118
+ Button,
119
+ {
120
+ size: "S",
121
+ variant: "tertiary",
122
+ tag: NavLink,
123
+ to: `/content-manager/collection-types/${occurrence.uid}/${occurrence.documentId}${occurrence.locale ? `?plugins[i18n][locale]=${encodeURIComponent(occurrence.locale)}` : ""}`,
124
+ children: t("calendar.editInContentManager", "Open in Content Manager")
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx(
128
+ Button,
129
+ {
130
+ size: "S",
131
+ variant: "tertiary",
132
+ tag: "a",
133
+ href: occurrence.calendarLinks.icsPath,
134
+ target: "_blank",
135
+ rel: "noopener noreferrer",
136
+ children: t("calendar.downloadIcs", ".ICS")
137
+ }
138
+ ),
139
+ /* @__PURE__ */ jsx(
140
+ Button,
141
+ {
142
+ size: "S",
143
+ variant: "danger-light",
144
+ onClick: onCancelOccurrence,
145
+ children: t("calendar.cancelInstance", "Cancel Occurrence")
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: onClose, children: t("common.close", "Close") })
149
+ ] })
150
+ ]
151
+ }
152
+ )
153
+ ]
154
+ }
155
+ )
156
+ }
157
+ );
158
+ };
159
+ function resolveActiveQuickSource(enabledSources, selectedSourceId) {
160
+ if (enabledSources.length === 0) return void 0;
161
+ if (selectedSourceId) {
162
+ const exact = enabledSources.find(
163
+ (s) => s.id === selectedSourceId || s.uid === selectedSourceId
164
+ );
165
+ if (exact) return exact;
166
+ }
167
+ return enabledSources[0];
168
+ }
169
+ function sourceIncludesKeyword(source, keyword) {
170
+ if (!source) return false;
171
+ return source.id.toLowerCase().includes(keyword) || source.uid.toLowerCase().includes(keyword);
172
+ }
173
+ function computeToggledWeekdays(selectedWeekdays, code) {
174
+ if (selectedWeekdays.includes(code)) {
175
+ return selectedWeekdays.length > 1 ? selectedWeekdays.filter((d) => d !== code) : [code];
176
+ }
177
+ return WEEKDAYS.map((w) => w.code).filter(
178
+ (c) => c === code || selectedWeekdays.includes(c)
179
+ );
180
+ }
181
+ const QuickCreateHeader = ({
182
+ t,
183
+ isBookingSource,
184
+ isEventSource,
185
+ activeSource,
186
+ enabledSources,
187
+ onSelectedSourceIdChange
188
+ }) => {
189
+ const headingText = isBookingSource ? t("calendar.quickCreateBookingTitle", "New Booking / Reservation") : isEventSource ? t("calendar.quickCreateEventTitle", "New Calendar Event") : t("calendar.quickCreateTitle", "Quick-Create Calendar Entry");
190
+ return /* @__PURE__ */ jsxs(
191
+ Flex,
192
+ {
193
+ justifyContent: "space-between",
194
+ alignItems: "center",
195
+ wrap: "wrap",
196
+ gap: 2,
197
+ children: [
198
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, wrap: "wrap", children: [
199
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: headingText }),
200
+ activeSource && /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: activeSource.label })
201
+ ] }),
202
+ enabledSources.length > 1 && onSelectedSourceIdChange && /* @__PURE__ */ jsxs(Flex, { gap: 1, wrap: "wrap", alignItems: "center", children: [
203
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t("calendar.targetSource", "Create in:") }),
204
+ enabledSources.map((src) => {
205
+ const isSelected = activeSource?.id === src.id;
206
+ return /* @__PURE__ */ jsxs(
207
+ Button,
208
+ {
209
+ size: "S",
210
+ variant: isSelected ? "default" : "tertiary",
211
+ onClick: () => onSelectedSourceIdChange(src.id),
212
+ children: [
213
+ /* @__PURE__ */ jsx(
214
+ "span",
215
+ {
216
+ style: {
217
+ display: "inline-block",
218
+ width: 8,
219
+ height: 8,
220
+ borderRadius: "50%",
221
+ background: src.color,
222
+ marginRight: 6
223
+ }
224
+ }
225
+ ),
226
+ src.label
227
+ ]
228
+ },
229
+ src.id
230
+ );
231
+ })
232
+ ] })
233
+ ]
234
+ }
235
+ );
236
+ };
237
+ const BookingVisitorFields = ({
238
+ t,
239
+ isBookingSource,
240
+ quickCustomerName,
241
+ onQuickCustomerNameChange,
242
+ quickCustomerEmail,
243
+ onQuickCustomerEmailChange,
244
+ quickPartySize,
245
+ onQuickPartySizeChange
246
+ }) => {
247
+ if (!isBookingSource) return null;
248
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
249
+ onQuickCustomerNameChange && /* @__PURE__ */ jsxs(Field.Root, { children: [
250
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.customerName", "Visitor / Customer Name") }),
251
+ /* @__PURE__ */ jsx(
252
+ TextInput,
253
+ {
254
+ value: quickCustomerName,
255
+ onChange: (e) => onQuickCustomerNameChange(e.target.value),
256
+ placeholder: t(
257
+ "placeholder.customer_name",
258
+ "Defaults to reservation title if omitted"
259
+ )
260
+ }
261
+ )
262
+ ] }),
263
+ onQuickCustomerEmailChange && /* @__PURE__ */ jsxs(Field.Root, { children: [
264
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.customerEmail", "Visitor / Customer Email") }),
265
+ /* @__PURE__ */ jsx(
266
+ TextInput,
267
+ {
268
+ value: quickCustomerEmail,
269
+ onChange: (e) => onQuickCustomerEmailChange(e.target.value),
270
+ placeholder: t("placeholder.customer_email", "guest@example.com")
271
+ }
272
+ )
273
+ ] }),
274
+ onQuickPartySizeChange && /* @__PURE__ */ jsxs(Field.Root, { children: [
275
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.partySize", "Party Size (Guests)") }),
276
+ /* @__PURE__ */ jsx(
277
+ TextInput,
278
+ {
279
+ type: "number",
280
+ value: String(quickPartySize || 1),
281
+ onChange: (e) => onQuickPartySizeChange(
282
+ Math.max(1, Number.parseInt(e.target.value || "1", 10) || 1)
283
+ )
284
+ }
285
+ )
286
+ ] })
287
+ ] });
288
+ };
289
+ const QuickCreateRecurrenceSelect = ({
290
+ t,
291
+ supportsRecurrence,
292
+ quickRRule,
293
+ normalizedPresets,
294
+ hasCustomWeeklyOption,
295
+ customWeeklyLabel,
296
+ onRecurrenceSelect
297
+ }) => {
298
+ if (!supportsRecurrence) return null;
299
+ return /* @__PURE__ */ jsxs(Field.Root, { children: [
300
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.recurrence", "Recurrence Preset") }),
301
+ /* @__PURE__ */ jsxs(
302
+ SingleSelect,
303
+ {
304
+ placeholder: t(
305
+ "placeholder.select_recurrence_preset",
306
+ "Select recurrence preset"
307
+ ),
308
+ value: quickRRule || "NONE",
309
+ onChange: onRecurrenceSelect,
310
+ children: [
311
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "NONE", children: t("calendar.singleEntry", "Single Entry") }),
312
+ normalizedPresets.map((preset) => /* @__PURE__ */ jsx(SingleSelectOption, { value: preset.rrule, children: preset.label }, preset.id)),
313
+ hasCustomWeeklyOption && /* @__PURE__ */ jsx(SingleSelectOption, { value: quickRRule, children: customWeeklyLabel })
314
+ ]
315
+ }
316
+ )
317
+ ] });
318
+ };
319
+ const QuickCreateDateFields = ({
320
+ t,
321
+ startDateValue,
322
+ endDateValue,
323
+ onStartDateChange,
324
+ onQuickEndChange
325
+ }) => /* @__PURE__ */ jsxs(Fragment, { children: [
326
+ /* @__PURE__ */ jsxs(Field.Root, { required: true, children: [
327
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.startDate", "Start Date / Time") }),
328
+ /* @__PURE__ */ jsx(
329
+ DateTimePicker,
330
+ {
331
+ value: startDateValue,
332
+ step: 15,
333
+ clearLabel: t("common.clear", "Clear"),
334
+ onChange: (date) => onStartDateChange(date ? date.toISOString() : ""),
335
+ onClear: () => onStartDateChange("")
336
+ }
337
+ )
338
+ ] }),
339
+ onQuickEndChange && /* @__PURE__ */ jsxs(
340
+ Field.Root,
341
+ {
342
+ hint: t(
343
+ "placeholder.end_date_optional",
344
+ "Defaults to +1 hour if omitted"
345
+ ),
346
+ children: [
347
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.endDate", "End Date / Time (optional)") }),
348
+ /* @__PURE__ */ jsx(
349
+ DateTimePicker,
350
+ {
351
+ value: endDateValue,
352
+ step: 15,
353
+ clearLabel: t("common.clear", "Clear"),
354
+ onChange: (date) => onQuickEndChange(date ? date.toISOString() : ""),
355
+ onClear: () => onQuickEndChange("")
356
+ }
357
+ ),
358
+ /* @__PURE__ */ jsx(Field.Hint, {})
359
+ ]
360
+ }
361
+ )
362
+ ] });
363
+ function resolveSubmitLabel(t, isBookingSource, isEventSource) {
364
+ if (isBookingSource) return t("calendar.createBooking", "Create Booking");
365
+ if (isEventSource) return t("calendar.createEvent", "Create Event");
366
+ return t("common.create", "Create Entry");
367
+ }
368
+ function resolveTitleAndLocationLabels(t, isBookingSource) {
369
+ return {
370
+ titleLabel: isBookingSource ? t("calendar.field.bookingTitle", "Reservation Title / Purpose") : t("calendar.field.title", "Title"),
371
+ titlePlaceholder: isBookingSource ? t(
372
+ "placeholder.booking_title",
373
+ "e.g., Guided Visit / Hall Reservation / Counseling"
374
+ ) : t(
375
+ "placeholder.e_g_product_launch_workshop_reservation",
376
+ "e.g., Product Launch / Workshop / Reservation"
377
+ ),
378
+ locationLabel: isBookingSource ? t("calendar.field.assignedHost", "Assigned Host / Resource") : t("calendar.field.location", "Location"),
379
+ locationPlaceholder: isBookingSource ? t("placeholder.assigned_host", "Main Hall / Host / Coordinator") : t("placeholder.room_101_online", "Room 101 / Online")
380
+ };
381
+ }
382
+ const QuickCreatePanel = (props) => {
383
+ const {
384
+ t,
385
+ sources = [],
386
+ selectedSourceId = "",
387
+ onSelectedSourceIdChange,
388
+ quickTitle,
389
+ onQuickTitleChange,
390
+ quickStart,
391
+ onQuickStartChange,
392
+ quickEnd = "",
393
+ onQuickEndChange,
394
+ quickLocation,
395
+ onQuickLocationChange,
396
+ quickRRule,
397
+ onQuickRRuleChange,
398
+ quickCustomerName = "",
399
+ onQuickCustomerNameChange,
400
+ quickCustomerEmail = "",
401
+ onQuickCustomerEmailChange,
402
+ quickPartySize = 1,
403
+ onQuickPartySizeChange,
404
+ recurrencePresets,
405
+ onCancel,
406
+ onSubmit
407
+ } = props;
408
+ const enabledSources = useMemo(
409
+ () => sources.filter((s) => s.enabled !== false),
410
+ [sources]
411
+ );
412
+ const activeSource = useMemo(
413
+ () => resolveActiveQuickSource(enabledSources, selectedSourceId),
414
+ [enabledSources, selectedSourceId]
415
+ );
416
+ const isBookingSource = useMemo(
417
+ () => sourceIncludesKeyword(activeSource, "booking"),
418
+ [activeSource]
419
+ );
420
+ const isEventSource = useMemo(
421
+ () => !activeSource || sourceIncludesKeyword(activeSource, "event"),
422
+ [activeSource]
423
+ );
424
+ const supportsRecurrence = useMemo(
425
+ () => !isBookingSource || Boolean(activeSource?.fields?.rrule),
426
+ [activeSource, isBookingSource]
427
+ );
428
+ const startDateValue = useMemo(
429
+ () => parseDateTimePickerValue(quickStart),
430
+ [quickStart]
431
+ );
432
+ const endDateValue = useMemo(
433
+ () => parseDateTimePickerValue(quickEnd),
434
+ [quickEnd]
435
+ );
436
+ const normalizedPresets = useMemo(
437
+ () => buildOrderedRecurrencePresets(recurrencePresets, startDateValue),
438
+ [recurrencePresets, startDateValue]
439
+ );
440
+ const isWeekly = supportsRecurrence && quickRRule.toUpperCase().includes("FREQ=WEEKLY");
441
+ const selectedWeekdays = useMemo(
442
+ () => extractByDays(quickRRule),
443
+ [quickRRule]
444
+ );
445
+ const hasCustomWeeklyOption = isWeekly && !normalizedPresets.some((p) => p.rrule === quickRRule);
446
+ const customWeeklyLabel = `${t("rrule.freq.weekly", "Weekly")} (${selectedWeekdays.join(", ")})`;
447
+ const alignSingleDayRRule = (days) => {
448
+ if (days.length === 1 && quickStart) {
449
+ const aligned = alignStartDateToWeekday(quickStart, days[0]);
450
+ if (aligned !== quickStart) onQuickStartChange(aligned);
451
+ }
452
+ };
453
+ const handleRecurrenceSelect = (val) => {
454
+ const strVal = String(val);
455
+ const nextRRule = strVal === "NONE" ? "" : strVal;
456
+ onQuickRRuleChange(nextRRule);
457
+ if (nextRRule.toUpperCase().includes("FREQ=WEEKLY")) {
458
+ alignSingleDayRRule(extractByDays(nextRRule));
459
+ }
460
+ };
461
+ const handleToggleWeekday = (code) => {
462
+ const nextDays = computeToggledWeekdays(selectedWeekdays, code);
463
+ onQuickRRuleChange(`FREQ=WEEKLY;INTERVAL=1;BYDAY=${nextDays.join(",")}`);
464
+ alignSingleDayRRule(nextDays);
465
+ };
466
+ const handleStartDateChange = (nextDateStr) => {
467
+ onQuickStartChange(nextDateStr);
468
+ if (!isWeekly || selectedWeekdays.length !== 1 || !nextDateStr) return;
469
+ const dt = parseDateTimePickerValue(nextDateStr);
470
+ const match = dt ? WEEKDAYS.find((w) => w.jsDay === dt.getDay()) : void 0;
471
+ if (match && match.code !== selectedWeekdays[0]) {
472
+ onQuickRRuleChange(`FREQ=WEEKLY;INTERVAL=1;BYDAY=${match.code}`);
473
+ }
474
+ };
475
+ const labels = resolveTitleAndLocationLabels(t, isBookingSource);
476
+ const submitLabel = resolveSubmitLabel(t, isBookingSource, isEventSource);
477
+ const canSubmit = Boolean(quickTitle.trim() && quickStart.trim());
478
+ const borderColor = activeSource?.color || "#0284C7";
479
+ return /* @__PURE__ */ jsx(
480
+ Box,
481
+ {
482
+ padding: 4,
483
+ background: "neutral0",
484
+ hasRadius: true,
485
+ shadow: "tableShadow",
486
+ style: { borderLeft: `4px solid ${borderColor}` },
487
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
488
+ /* @__PURE__ */ jsx(
489
+ QuickCreateHeader,
490
+ {
491
+ t,
492
+ isBookingSource,
493
+ isEventSource,
494
+ activeSource,
495
+ enabledSources,
496
+ onSelectedSourceIdChange
497
+ }
498
+ ),
499
+ /* @__PURE__ */ jsxs(
500
+ "div",
501
+ {
502
+ style: {
503
+ display: "grid",
504
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
505
+ gap: 16
506
+ },
507
+ children: [
508
+ enabledSources.length > 1 && onSelectedSourceIdChange && /* @__PURE__ */ jsxs(Field.Root, { children: [
509
+ /* @__PURE__ */ jsx(Field.Label, { children: t("calendar.field.sourceType", "Entry Collection / Type") }),
510
+ /* @__PURE__ */ jsx(
511
+ SingleSelect,
512
+ {
513
+ value: activeSource?.id || "",
514
+ onChange: (val) => onSelectedSourceIdChange(String(val)),
515
+ children: enabledSources.map((src) => /* @__PURE__ */ jsx(SingleSelectOption, { value: src.id, children: `${src.label} (${src.uid})` }, src.id))
516
+ }
517
+ )
518
+ ] }),
519
+ /* @__PURE__ */ jsxs(Field.Root, { required: true, children: [
520
+ /* @__PURE__ */ jsx(Field.Label, { children: labels.titleLabel }),
521
+ /* @__PURE__ */ jsx(
522
+ TextInput,
523
+ {
524
+ value: quickTitle,
525
+ onChange: (e) => onQuickTitleChange(e.target.value),
526
+ placeholder: labels.titlePlaceholder
527
+ }
528
+ )
529
+ ] }),
530
+ /* @__PURE__ */ jsx(
531
+ QuickCreateDateFields,
532
+ {
533
+ t,
534
+ startDateValue,
535
+ endDateValue,
536
+ onStartDateChange: handleStartDateChange,
537
+ onQuickEndChange
538
+ }
539
+ ),
540
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
541
+ /* @__PURE__ */ jsx(Field.Label, { children: labels.locationLabel }),
542
+ /* @__PURE__ */ jsx(
543
+ TextInput,
544
+ {
545
+ value: quickLocation,
546
+ onChange: (e) => onQuickLocationChange(e.target.value),
547
+ placeholder: labels.locationPlaceholder
548
+ }
549
+ )
550
+ ] }),
551
+ /* @__PURE__ */ jsx(
552
+ BookingVisitorFields,
553
+ {
554
+ t,
555
+ isBookingSource,
556
+ quickCustomerName,
557
+ onQuickCustomerNameChange,
558
+ quickCustomerEmail,
559
+ onQuickCustomerEmailChange,
560
+ quickPartySize,
561
+ onQuickPartySizeChange
562
+ }
563
+ ),
564
+ /* @__PURE__ */ jsx(
565
+ QuickCreateRecurrenceSelect,
566
+ {
567
+ t,
568
+ supportsRecurrence,
569
+ quickRRule,
570
+ normalizedPresets,
571
+ hasCustomWeeklyOption,
572
+ customWeeklyLabel,
573
+ onRecurrenceSelect: handleRecurrenceSelect
574
+ }
575
+ )
576
+ ]
577
+ }
578
+ ),
579
+ isWeekly && /* @__PURE__ */ jsx(Box, { padding: 3, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, wrap: "wrap", children: [
580
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", children: t(
581
+ "calendar.field.repeatWeekdays",
582
+ "Repeat on Day(s) of Week:"
583
+ ) }),
584
+ WEEKDAYS.map((day) => /* @__PURE__ */ jsx(
585
+ Button,
586
+ {
587
+ size: "S",
588
+ variant: selectedWeekdays.includes(day.code) ? "default" : "tertiary",
589
+ onClick: () => handleToggleWeekday(day.code),
590
+ children: t(`weekday.${day.code.toLowerCase()}`, day.label)
591
+ },
592
+ day.code
593
+ ))
594
+ ] }) }),
595
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, justifyContent: "flex-end", children: [
596
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", onClick: onCancel, children: t("common.cancel", "Cancel") }),
597
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: onSubmit, disabled: !canSubmit, children: submitLabel })
598
+ ] })
599
+ ] })
600
+ }
601
+ );
602
+ };
603
+ const getUrlParam = (key) => typeof window === "undefined" ? null : new URLSearchParams(window.location.search).get(key);
604
+ const CalendarPage = () => {
605
+ const { formatMessage, locale } = useIntl();
606
+ const { get, post } = useFetchClient();
607
+ const calendarRef = useRef(null);
608
+ const quickCreateRef = useRef(null);
609
+ const initialViewSyncedRef = useRef(false);
610
+ const t = useCallback(
611
+ (id, defaultMessage) => formatMessage({ id: `${PLUGIN_ID}.${id}`, defaultMessage }),
612
+ [formatMessage]
613
+ );
614
+ const [viewMode, setViewMode] = useState("dayGridMonth");
615
+ const [anchorDate, setAnchorDate] = useState(() => /* @__PURE__ */ new Date());
616
+ const [dateWindow, setDateWindow] = useState(buildInitialDateWindow);
617
+ const [sourceFilter, setSourceFilter] = useState(
618
+ () => getUrlParam("source") || "all"
619
+ );
620
+ const [categoryFilter, setCategoryFilter] = useState("all");
621
+ const [localeOverride, setLocaleOverride] = useState("auto");
622
+ const [secondaryLangMode, setSecondaryLangMode] = useState("local");
623
+ const [occurrences, setOccurrences] = useState([]);
624
+ const [settings, setSettings] = useState(null);
625
+ const [loading, setLoading] = useState(false);
626
+ const [bannerMessage, setBannerMessage] = useState(null);
627
+ const [bannerError, setBannerError] = useState(false);
628
+ const [selectedOccurrence, setSelectedOccurrence] = useState(
629
+ null
630
+ );
631
+ const [rescheduleDate, setRescheduleDate] = useState("");
632
+ const [applyToSeries, setApplyToSeries] = useState(false);
633
+ const [showQuickCreate, setShowQuickCreate] = useState(false);
634
+ const [quickSourceId, setQuickSourceId] = useState("");
635
+ const [quickTitle, setQuickTitle] = useState("");
636
+ const [quickStart, setQuickStart] = useState("");
637
+ const [quickEnd, setQuickEnd] = useState("");
638
+ const [quickLocation, setQuickLocation] = useState("");
639
+ const [quickCategory] = useState("general");
640
+ const [quickRRule, setQuickRRule] = useState("");
641
+ const [quickCustomerName, setQuickCustomerName] = useState("");
642
+ const [quickCustomerEmail, setQuickCustomerEmail] = useState("");
643
+ const [quickPartySize, setQuickPartySize] = useState(1);
644
+ const effectiveLocale = resolveFullCalendarLocale(
645
+ locale,
646
+ settings?.defaultLocale,
647
+ localeOverride
648
+ );
649
+ const effectiveDirection = resolveCalendarDirection(
650
+ effectiveLocale,
651
+ settings?.direction
652
+ );
653
+ const fetchCalendarData = useCallback(async () => {
654
+ setLoading(true);
655
+ const loadErrorMsg = t(
656
+ "calendar.error.load",
657
+ "Could not load calendar occurrences."
658
+ );
659
+ try {
660
+ const params = new URLSearchParams({
661
+ from: dateWindow.from,
662
+ to: dateWindow.to,
663
+ locale: effectiveLocale
664
+ });
665
+ if (categoryFilter !== "all") params.set("category", categoryFilter);
666
+ const res = await get(
667
+ `/${PLUGIN_ID}/calendar?${params.toString()}`
668
+ );
669
+ const payload = res?.data?.data;
670
+ if (!payload) return;
671
+ const loadedOccs = Array.isArray(payload.occurrences) ? payload.occurrences : [];
672
+ setOccurrences(loadedOccs);
673
+ const targetDocId = getUrlParam("documentId");
674
+ const match = targetDocId ? loadedOccs.find((o) => o.documentId === targetDocId) : void 0;
675
+ if (match) {
676
+ setSelectedOccurrence((prev) => prev ?? match);
677
+ setRescheduleDate((prev) => prev || match.occurrenceDate);
678
+ calendarRef.current?.getApi()?.gotoDate(match.startDate);
679
+ }
680
+ if (payload.settings) {
681
+ setSettings(payload.settings);
682
+ if (!initialViewSyncedRef.current && payload.settings.defaultView) {
683
+ initialViewSyncedRef.current = true;
684
+ setViewMode(payload.settings.defaultView);
685
+ calendarRef.current?.getApi()?.changeView(payload.settings.defaultView);
686
+ }
687
+ if (payload.settings.secondaryCalendarLanguage) {
688
+ setSecondaryLangMode(payload.settings.secondaryCalendarLanguage);
689
+ }
690
+ }
691
+ setBannerMessage((prev) => prev === loadErrorMsg ? null : prev);
692
+ } catch {
693
+ setBannerError(true);
694
+ setBannerMessage(loadErrorMsg);
695
+ } finally {
696
+ setLoading(false);
697
+ }
698
+ }, [dateWindow.from, dateWindow.to, effectiveLocale, categoryFilter, get, t]);
699
+ useEffect(() => {
700
+ fetchCalendarData();
701
+ }, [fetchCalendarData]);
702
+ useEffect(() => {
703
+ const loadedSources = settings?.sources ?? [];
704
+ if (loadedSources.length === 0) return;
705
+ if (sourceFilter !== "all") {
706
+ const matchedId = matchLoadedSourceId(loadedSources, sourceFilter);
707
+ if (matchedId && matchedId !== sourceFilter) setSourceFilter(matchedId);
708
+ setQuickSourceId(matchedId ?? sourceFilter);
709
+ return;
710
+ }
711
+ setQuickSourceId((prev) => {
712
+ if (prev && loadedSources.some((s) => s.id === prev)) return prev;
713
+ const first = loadedSources.find((s) => s.enabled !== false) ?? loadedSources[0];
714
+ return first ? first.id : prev;
715
+ });
716
+ }, [settings?.sources, sourceFilter]);
717
+ const sourceCounts = computeSourceCounts(occurrences, settings?.sources);
718
+ const visibleOccurrences = filterVisibleOccurrences(
719
+ occurrences,
720
+ sourceFilter
721
+ );
722
+ const availableCategories = collectAvailableCategories(
723
+ settings?.sources,
724
+ sourceFilter,
725
+ visibleOccurrences
726
+ );
727
+ const activeSecondaryCalendars = resolveActiveSecondaryCalendars(
728
+ secondaryLangMode,
729
+ settings?.secondaryCalendars
730
+ );
731
+ const recurrencePresets = settings?.recurrencePresets?.length ? settings.recurrencePresets : FALLBACK_RECURRENCE_PRESETS;
732
+ const fullCalendarEvents = mapOccurrencesToFullCalendarEvents(
733
+ visibleOccurrences,
734
+ settings?.primaryColor
735
+ );
736
+ const changeFullCalendarView = (nextView) => {
737
+ setViewMode(nextView);
738
+ calendarRef.current?.getApi()?.changeView(nextView);
739
+ };
740
+ const navigateCalendar = (action) => {
741
+ const api = calendarRef.current?.getApi();
742
+ if (!api) return;
743
+ if (action === "prev") api.prev();
744
+ else if (action === "today") api.today();
745
+ else api.next();
746
+ setAnchorDate(api.getDate());
747
+ };
748
+ const handleDatesSet = (start, from, to) => {
749
+ setAnchorDate(start);
750
+ const nextWin = expandDateWindowToYear(start, from, to);
751
+ setDateWindow(
752
+ (prev) => prev.from === nextWin.from && prev.to === nextWin.to ? prev : nextWin
753
+ );
754
+ };
755
+ const scrollQuickCreateIntoView = () => {
756
+ if (typeof window === "undefined") return;
757
+ const opts = {
758
+ behavior: "smooth",
759
+ block: "nearest"
760
+ };
761
+ window.setTimeout(() => quickCreateRef.current?.scrollIntoView(opts), 40);
762
+ };
763
+ const handleSelectSlot = (startStr, endStr) => {
764
+ setQuickStart(startStr);
765
+ setQuickEnd(normalizeSelectedEndSlot(startStr, endStr));
766
+ const sources = settings?.sources ?? [];
767
+ if (sourceFilter !== "all") {
768
+ setQuickSourceId(sourceFilter);
769
+ } else if (!quickSourceId && sources.length) {
770
+ const first = sources.find((s) => s.enabled !== false) ?? sources[0];
771
+ if (first) setQuickSourceId(first.id);
772
+ }
773
+ setShowQuickCreate(true);
774
+ scrollQuickCreateIntoView();
775
+ };
776
+ const handleSelectOccurrence = (occ) => {
777
+ setSelectedOccurrence(occ);
778
+ setRescheduleDate(occ.occurrenceDate);
779
+ setApplyToSeries(false);
780
+ };
781
+ const postReschedule = (occ, newStartDate, newEndDate, series = false, cancelOccurrence = false) => post(`/${PLUGIN_ID}/calendar/reschedule`, {
782
+ sourceId: occ.sourceId,
783
+ uid: occ.uid,
784
+ documentId: occ.documentId,
785
+ locale: occ.locale,
786
+ occurrenceDate: occ.occurrenceDate,
787
+ newStartDate,
788
+ newEndDate,
789
+ applyToSeries: series,
790
+ cancelOccurrence
791
+ });
792
+ const handleEventDropOrResize = async (occ, newStartIso, newEndIso) => {
793
+ try {
794
+ await postReschedule(occ, newStartIso, newEndIso);
795
+ setBannerError(false);
796
+ setBannerMessage(
797
+ `${t("calendar.rescheduled", "Rescheduled")} "${occ.title}" → ${newStartIso.slice(0, 10)}`
798
+ );
799
+ await fetchCalendarData();
800
+ } catch {
801
+ setBannerError(true);
802
+ setBannerMessage(
803
+ t("calendar.error.reschedule", "Failed to reschedule occurrence.")
804
+ );
805
+ }
806
+ };
807
+ const handleQuickCreateSubmit = async () => {
808
+ if (!quickTitle.trim() || !quickStart) return;
809
+ try {
810
+ const payload = buildQuickCreateRequestPayload({
811
+ quickSourceId,
812
+ sourceFilter,
813
+ quickTitle,
814
+ quickStart,
815
+ quickEnd,
816
+ quickLocation,
817
+ quickCategory,
818
+ quickRRule,
819
+ quickCustomerName,
820
+ quickCustomerEmail,
821
+ quickPartySize
822
+ });
823
+ await post(`/${PLUGIN_ID}/calendar/quick-create`, payload);
824
+ setShowQuickCreate(false);
825
+ setQuickTitle("");
826
+ setQuickLocation("");
827
+ setQuickRRule("");
828
+ setQuickCustomerName("");
829
+ setQuickCustomerEmail("");
830
+ setQuickPartySize(1);
831
+ setBannerError(false);
832
+ setBannerMessage(
833
+ t("calendar.created", "Calendar entry created and published.")
834
+ );
835
+ await fetchCalendarData();
836
+ } catch {
837
+ setBannerError(true);
838
+ setBannerMessage(
839
+ t("calendar.error.create", "Could not create calendar entry.")
840
+ );
841
+ }
842
+ };
843
+ const handleRescheduleSelected = async (cancelOccurrence = false) => {
844
+ const occ = selectedOccurrence;
845
+ if (!occ) return;
846
+ try {
847
+ const newStartIso = rescheduleDate ? `${rescheduleDate}${occ.startDate.slice(10)}` : occ.startDate;
848
+ const diffMs = new Date(newStartIso).getTime() - new Date(occ.startDate).getTime();
849
+ const newEndIso = !Number.isNaN(diffMs) && occ.endDate ? new Date(new Date(occ.endDate).getTime() + diffMs).toISOString() : void 0;
850
+ await postReschedule(
851
+ occ,
852
+ newStartIso,
853
+ newEndIso,
854
+ applyToSeries,
855
+ cancelOccurrence
856
+ );
857
+ setSelectedOccurrence(null);
858
+ setBannerError(false);
859
+ setBannerMessage(
860
+ cancelOccurrence ? t("calendar.occurrenceCancelled", "Occurrence cancelled.") : t("calendar.rescheduled", "Schedule updated.")
861
+ );
862
+ await fetchCalendarData();
863
+ } catch {
864
+ setBannerError(true);
865
+ setBannerMessage(
866
+ t("calendar.error.reschedule", "Failed to update schedule.")
867
+ );
868
+ }
869
+ };
870
+ const monthLabel = new Intl.DateTimeFormat(effectiveLocale, {
871
+ month: "long",
872
+ year: "numeric",
873
+ timeZone: "UTC"
874
+ }).format(anchorDate);
875
+ const secondaryHeaderLabel = buildSecondaryHeaderLabel(
876
+ activeSecondaryCalendars,
877
+ anchorDate,
878
+ effectiveLocale,
879
+ secondaryLangMode
880
+ );
881
+ const todayKey = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
882
+ const enabledViews = buildEnabledCalendarViews(settings, effectiveLocale);
883
+ return /* @__PURE__ */ jsx(Box, { padding: 6, background: "neutral100", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
884
+ /* @__PURE__ */ jsx(
885
+ CalendarToolbar,
886
+ {
887
+ t,
888
+ effectiveLocale,
889
+ effectiveDirection,
890
+ localeOverride,
891
+ onLocaleOverrideChange: setLocaleOverride,
892
+ secondaryLangMode,
893
+ onSecondaryLangModeChange: setSecondaryLangMode,
894
+ monthLabel,
895
+ secondaryHeaderLabel,
896
+ loading,
897
+ settings,
898
+ totalOccurrences: occurrences.length,
899
+ sourceCounts,
900
+ sourceFilter,
901
+ onSourceFilterChange: setSourceFilter,
902
+ categoryFilter,
903
+ onCategoryFilterChange: setCategoryFilter,
904
+ availableCategories,
905
+ viewMode,
906
+ enabledViews,
907
+ onViewChange: changeFullCalendarView,
908
+ onNavigate: navigateCalendar,
909
+ onOpenQuickCreate: (targetSourceId) => {
910
+ if (targetSourceId) setQuickSourceId(targetSourceId);
911
+ else if (sourceFilter !== "all") setQuickSourceId(sourceFilter);
912
+ setQuickStart((prev) => prev || todayKey);
913
+ setQuickEnd("");
914
+ setShowQuickCreate(true);
915
+ scrollQuickCreateIntoView();
916
+ }
917
+ }
918
+ ),
919
+ bannerMessage && /* @__PURE__ */ jsx(
920
+ Box,
921
+ {
922
+ padding: 3,
923
+ background: bannerError ? "danger100" : "primary100",
924
+ hasRadius: true,
925
+ style: {
926
+ border: `1px solid ${bannerError ? "#DC2626" : "#0284C7"}`
927
+ },
928
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
929
+ /* @__PURE__ */ jsx(
930
+ Typography,
931
+ {
932
+ variant: "omega",
933
+ fontWeight: "bold",
934
+ textColor: bannerError ? "danger700" : "primary700",
935
+ children: bannerMessage
936
+ }
937
+ ),
938
+ /* @__PURE__ */ jsx(
939
+ Button,
940
+ {
941
+ variant: "tertiary",
942
+ size: "S",
943
+ onClick: () => setBannerMessage(null),
944
+ children: "×"
945
+ }
946
+ )
947
+ ] })
948
+ }
949
+ ),
950
+ showQuickCreate && /* @__PURE__ */ jsx("div", { ref: quickCreateRef, children: /* @__PURE__ */ jsx(
951
+ QuickCreatePanel,
952
+ {
953
+ t,
954
+ sources: settings?.sources ?? [],
955
+ selectedSourceId: quickSourceId,
956
+ onSelectedSourceIdChange: setQuickSourceId,
957
+ quickTitle,
958
+ onQuickTitleChange: setQuickTitle,
959
+ quickStart,
960
+ onQuickStartChange: setQuickStart,
961
+ quickEnd,
962
+ onQuickEndChange: setQuickEnd,
963
+ quickLocation,
964
+ onQuickLocationChange: setQuickLocation,
965
+ quickRRule,
966
+ onQuickRRuleChange: setQuickRRule,
967
+ quickCustomerName,
968
+ onQuickCustomerNameChange: setQuickCustomerName,
969
+ quickCustomerEmail,
970
+ onQuickCustomerEmailChange: setQuickCustomerEmail,
971
+ quickPartySize,
972
+ onQuickPartySizeChange: setQuickPartySize,
973
+ recurrencePresets,
974
+ onCancel: () => setShowQuickCreate(false),
975
+ onSubmit: handleQuickCreateSubmit
976
+ }
977
+ ) }),
978
+ selectedOccurrence && /* @__PURE__ */ jsx(
979
+ OccurrenceDetailDrawer,
980
+ {
981
+ t,
982
+ occurrence: selectedOccurrence,
983
+ rescheduleDate,
984
+ onRescheduleDateChange: setRescheduleDate,
985
+ applyToSeries,
986
+ onApplyToSeriesChange: setApplyToSeries,
987
+ onSaveReschedule: () => handleRescheduleSelected(false),
988
+ onCancelOccurrence: () => handleRescheduleSelected(true),
989
+ onClose: () => setSelectedOccurrence(null)
990
+ }
991
+ ),
992
+ /* @__PURE__ */ jsx(
993
+ FullCalendarCanvas,
994
+ {
995
+ calendarRef,
996
+ locale: effectiveLocale,
997
+ direction: effectiveDirection,
998
+ theme: settings?.theme,
999
+ colorScheme: settings?.colorScheme,
1000
+ themePalette: settings?.themePalette,
1001
+ secondaryCalendarLanguage: secondaryLangMode,
1002
+ settings,
1003
+ events: fullCalendarEvents,
1004
+ activeSecondaryCalendars,
1005
+ onDatesSet: handleDatesSet,
1006
+ onSelectSlot: handleSelectSlot,
1007
+ onSelectOccurrence: handleSelectOccurrence,
1008
+ onDropOrResizeOccurrence: handleEventDropOrResize
1009
+ }
1010
+ )
1011
+ ] }) });
1012
+ };
1013
+ export {
1014
+ CalendarPage
1015
+ };