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