@arbidocs/blocks 0.4.137 → 0.4.139

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 (203) hide show
  1. package/dist/agents/definitions/AgentConnectInstructions.d.ts +12 -0
  2. package/dist/agents/definitions/defaults.d.ts +12 -0
  3. package/dist/agents/definitions/index.d.ts +2 -0
  4. package/dist/agents/index.cjs +457 -418
  5. package/dist/agents/index.js +12 -13
  6. package/dist/agents/skills/SkillLibraryDetail.d.ts +26 -0
  7. package/dist/agents/skills/index.d.ts +2 -0
  8. package/dist/agents/skills/skillLibrary.d.ts +46 -0
  9. package/dist/calendar/CalendarFormDialog.d.ts +13 -0
  10. package/dist/calendar/ProposeTimeDialog.d.ts +22 -0
  11. package/dist/calendar/WeeklyHoursEditor.d.ts +7 -0
  12. package/dist/calendar/access-setup.d.ts +8 -0
  13. package/dist/calendar/api-mapping.d.ts +22 -0
  14. package/dist/calendar/booking-form.d.ts +46 -0
  15. package/dist/calendar/conference.d.ts +11 -0
  16. package/dist/calendar/errors.d.ts +7 -0
  17. package/dist/calendar/feeds.d.ts +2 -0
  18. package/dist/calendar/freebusy.d.ts +22 -0
  19. package/dist/calendar/ics.d.ts +33 -0
  20. package/dist/calendar/index.cjs +472 -4293
  21. package/dist/calendar/index.cjs.map +1 -1
  22. package/dist/calendar/index.d.ts +17 -1
  23. package/dist/calendar/index.js +1 -4227
  24. package/dist/calendar/index.js.map +1 -1
  25. package/dist/calendar/requests.d.ts +42 -0
  26. package/dist/calendar/room-window.d.ts +6 -0
  27. package/dist/calendar/settings-value.d.ts +4 -0
  28. package/dist/calls/index.cjs +4 -4
  29. package/dist/calls/index.js +3 -3
  30. package/dist/chat/index.cjs +141 -141
  31. package/dist/chat/index.js +6 -6
  32. package/dist/{chunk-M33QUNFH.js → chunk-22WFGXG2.js} +3 -3
  33. package/dist/{chunk-M33QUNFH.js.map → chunk-22WFGXG2.js.map} +1 -1
  34. package/dist/{chunk-VMESMX7N.js → chunk-453PNNNW.js} +3 -3
  35. package/dist/{chunk-VMESMX7N.js.map → chunk-453PNNNW.js.map} +1 -1
  36. package/dist/{chunk-2KUCVSFF.js → chunk-45LRMW54.js} +3 -3
  37. package/dist/{chunk-2KUCVSFF.js.map → chunk-45LRMW54.js.map} +1 -1
  38. package/dist/chunk-5FTIHRZH.cjs +177 -0
  39. package/dist/chunk-5FTIHRZH.cjs.map +1 -0
  40. package/dist/{chunk-FUTMU4FR.js → chunk-5HFPRI3W.js} +3 -3
  41. package/dist/{chunk-FUTMU4FR.js.map → chunk-5HFPRI3W.js.map} +1 -1
  42. package/dist/{chunk-JY73DJOS.cjs → chunk-5UXDUOOB.cjs} +84 -1211
  43. package/dist/chunk-5UXDUOOB.cjs.map +1 -0
  44. package/dist/{chunk-ATJUVHVB.js → chunk-6QMWP5IU.js} +1445 -11
  45. package/dist/chunk-6QMWP5IU.js.map +1 -0
  46. package/dist/chunk-6YTHQ73P.cjs +5334 -0
  47. package/dist/chunk-6YTHQ73P.cjs.map +1 -0
  48. package/dist/{chunk-KMNZ2RVO.js → chunk-7QUUZBQZ.js} +15 -1109
  49. package/dist/chunk-7QUUZBQZ.js.map +1 -0
  50. package/dist/{chunk-C3ZRLULA.cjs → chunk-7X255TOM.cjs} +5 -5
  51. package/dist/{chunk-C3ZRLULA.cjs.map → chunk-7X255TOM.cjs.map} +1 -1
  52. package/dist/chunk-A3XPS2EU.js +245 -0
  53. package/dist/chunk-A3XPS2EU.js.map +1 -0
  54. package/dist/chunk-B3AHCIV5.js +5206 -0
  55. package/dist/chunk-B3AHCIV5.js.map +1 -0
  56. package/dist/{chunk-2Q7FDZAY.js → chunk-BPBSSMRB.js} +5 -163
  57. package/dist/chunk-BPBSSMRB.js.map +1 -0
  58. package/dist/{chunk-KSHKTOY2.js → chunk-CKCBBYTA.js} +205 -5
  59. package/dist/chunk-CKCBBYTA.js.map +1 -0
  60. package/dist/chunk-CYNF5PZI.js +170 -0
  61. package/dist/chunk-CYNF5PZI.js.map +1 -0
  62. package/dist/{chunk-OPTBQSCV.cjs → chunk-DJM7DLCT.cjs} +3 -3
  63. package/dist/{chunk-OPTBQSCV.cjs.map → chunk-DJM7DLCT.cjs.map} +1 -1
  64. package/dist/{chunk-E5OYHJMU.js → chunk-DN55PRGS.js} +4 -4
  65. package/dist/{chunk-E5OYHJMU.js.map → chunk-DN55PRGS.js.map} +1 -1
  66. package/dist/{chunk-VHJHY7TT.js → chunk-ECERC6TI.js} +3 -3
  67. package/dist/{chunk-VHJHY7TT.js.map → chunk-ECERC6TI.js.map} +1 -1
  68. package/dist/{chunk-KDUGTKVI.cjs → chunk-GFNELPDP.cjs} +17 -6
  69. package/dist/chunk-GFNELPDP.cjs.map +1 -0
  70. package/dist/{chunk-OGBXV326.cjs → chunk-GFRQG36Y.cjs} +2 -243
  71. package/dist/chunk-GFRQG36Y.cjs.map +1 -0
  72. package/dist/{chunk-WXYQ66KC.cjs → chunk-HEMU73OP.cjs} +2 -166
  73. package/dist/chunk-HEMU73OP.cjs.map +1 -0
  74. package/dist/{chunk-UUHUQHXR.cjs → chunk-JZNXRMLH.cjs} +6 -6
  75. package/dist/{chunk-UUHUQHXR.cjs.map → chunk-JZNXRMLH.cjs.map} +1 -1
  76. package/dist/{chunk-HDYWXEQU.cjs → chunk-K3HNLWZZ.cjs} +8 -8
  77. package/dist/{chunk-HDYWXEQU.cjs.map → chunk-K3HNLWZZ.cjs.map} +1 -1
  78. package/dist/{chunk-7M4C6CK7.js → chunk-KTFDUSON.js} +4 -4
  79. package/dist/{chunk-7M4C6CK7.js.map → chunk-KTFDUSON.js.map} +1 -1
  80. package/dist/{chunk-HLB4DIYV.cjs → chunk-MABUMUCA.cjs} +6 -6
  81. package/dist/{chunk-HLB4DIYV.cjs.map → chunk-MABUMUCA.cjs.map} +1 -1
  82. package/dist/{chunk-RQ2Y7USX.cjs → chunk-MIDXCYZB.cjs} +235 -15
  83. package/dist/chunk-MIDXCYZB.cjs.map +1 -0
  84. package/dist/{chunk-L3T7OJRX.js → chunk-MTPWZQTL.js} +4 -4
  85. package/dist/{chunk-L3T7OJRX.js.map → chunk-MTPWZQTL.js.map} +1 -1
  86. package/dist/{chunk-BUNZWOPX.cjs → chunk-O4ZIQDUT.cjs} +5 -5
  87. package/dist/{chunk-BUNZWOPX.cjs.map → chunk-O4ZIQDUT.cjs.map} +1 -1
  88. package/dist/{chunk-W3VYZXNS.js → chunk-O6W6RW3B.js} +5 -240
  89. package/dist/chunk-O6W6RW3B.js.map +1 -0
  90. package/dist/{chunk-WS5EX7DN.cjs → chunk-OGP6MQXQ.cjs} +3 -3
  91. package/dist/{chunk-WS5EX7DN.cjs.map → chunk-OGP6MQXQ.cjs.map} +1 -1
  92. package/dist/{chunk-6F7SZCVL.cjs → chunk-OWCEQKAR.cjs} +3 -3
  93. package/dist/{chunk-6F7SZCVL.cjs.map → chunk-OWCEQKAR.cjs.map} +1 -1
  94. package/dist/{chunk-OQ7RUNOC.js → chunk-PC5KVHX3.js} +22 -6
  95. package/dist/chunk-PC5KVHX3.js.map +1 -0
  96. package/dist/{chunk-CHVCTKF4.cjs → chunk-ULEDHANM.cjs} +1543 -66
  97. package/dist/chunk-ULEDHANM.cjs.map +1 -0
  98. package/dist/{chunk-L2PAPOZ5.js → chunk-US3S4DCB.js} +17 -6
  99. package/dist/chunk-US3S4DCB.js.map +1 -0
  100. package/dist/chunk-V46W7YLI.cjs +252 -0
  101. package/dist/chunk-V46W7YLI.cjs.map +1 -0
  102. package/dist/{chunk-3RJN2VTL.js → chunk-XDQXDWE7.js} +3 -3
  103. package/dist/{chunk-3RJN2VTL.js.map → chunk-XDQXDWE7.js.map} +1 -1
  104. package/dist/{chunk-EHOPZBAX.cjs → chunk-XOC44HQY.cjs} +12 -12
  105. package/dist/{chunk-EHOPZBAX.cjs.map → chunk-XOC44HQY.cjs.map} +1 -1
  106. package/dist/{chunk-YOMPLCP6.js → chunk-Y5KTM3V5.js} +3 -3
  107. package/dist/{chunk-YOMPLCP6.js.map → chunk-Y5KTM3V5.js.map} +1 -1
  108. package/dist/{chunk-DWZXSPMB.cjs → chunk-ZAVEMQ37.cjs} +3 -3
  109. package/dist/{chunk-DWZXSPMB.cjs.map → chunk-ZAVEMQ37.cjs.map} +1 -1
  110. package/dist/{chunk-AAFX64WD.cjs → chunk-ZXAWOLBQ.cjs} +22 -5
  111. package/dist/chunk-ZXAWOLBQ.cjs.map +1 -0
  112. package/dist/citations/QuietMarks.d.ts +5 -2
  113. package/dist/citations/index.cjs +15 -14
  114. package/dist/citations/index.js +3 -2
  115. package/dist/collaboration/index.cjs +51 -51
  116. package/dist/collaboration/index.js +3 -3
  117. package/dist/connect/docx.cjs +6 -6
  118. package/dist/connect/docx.js +5 -5
  119. package/dist/connect/index.cjs +6595 -1600
  120. package/dist/connect/index.cjs.map +1 -1
  121. package/dist/connect/index.d.ts +5 -0
  122. package/dist/connect/index.js +5064 -90
  123. package/dist/connect/index.js.map +1 -1
  124. package/dist/connection/ConnectedAgentCreator.d.ts +37 -0
  125. package/dist/connection/ConnectedSkillsLibrary.d.ts +26 -0
  126. package/dist/connection/ConnectedWorkflowHistory.d.ts +45 -0
  127. package/dist/connection/ConnectionProvider.d.ts +3 -1
  128. package/dist/connection/calendar/AddCalendarDialogs.d.ts +9 -0
  129. package/dist/connection/calendar/BookingPagesPanel.d.ts +13 -0
  130. package/dist/connection/calendar/CalendarAccountsPanel.d.ts +5 -0
  131. package/dist/connection/calendar/CalendarSettingsDialog.d.ts +12 -0
  132. package/dist/connection/calendar/ConnectedCalendar.d.ts +13 -0
  133. package/dist/connection/calendar/ConnectedMailInviteCard.d.ts +12 -0
  134. package/dist/connection/calendar/ConnectedPublicBooking.d.ts +9 -0
  135. package/dist/connection/calendar/ConnectedUpcomingEvents.d.ts +12 -0
  136. package/dist/connection/calendar/CopyField.d.ts +9 -0
  137. package/dist/connection/calendar/EventEditorDialog.d.ts +29 -0
  138. package/dist/connection/calendar/EventScheduling.d.ts +8 -0
  139. package/dist/connection/calendar/InvitationsPanel.d.ts +5 -0
  140. package/dist/connection/calendar/OpenAccessPanel.d.ts +7 -0
  141. package/dist/connection/calendar/PublishCalendarDialog.d.ts +8 -0
  142. package/dist/connection/calendar/RoomsDirectoryPanel.d.ts +8 -0
  143. package/dist/connection/calendar/ShareCalendarDialog.d.ts +6 -0
  144. package/dist/connection/calendar/copy.d.ts +2 -0
  145. package/dist/connection/calendar/index.d.ts +6 -0
  146. package/dist/connection/calendar/store.d.ts +47 -0
  147. package/dist/connection/calendar/types.d.ts +36 -0
  148. package/dist/connection/calendar/useWebinarAttendee.d.ts +3 -0
  149. package/dist/connection/notification-center/ConnectedNotificationCenter.d.ts +15 -0
  150. package/dist/connection/notification-center/NotificationCenter.d.ts +37 -0
  151. package/dist/connection/notification-center/NotificationEvent.d.ts +33 -0
  152. package/dist/connection/notification-center/index.d.ts +4 -0
  153. package/dist/connection/notification-center/items.d.ts +44 -0
  154. package/dist/document-tools/index.cjs +1 -1
  155. package/dist/document-tools/index.js +1 -1
  156. package/dist/facts/index.cjs +6 -6
  157. package/dist/facts/index.js +6 -6
  158. package/dist/files/index.cjs +6 -6
  159. package/dist/files/index.js +6 -6
  160. package/dist/home/index.cjs +20 -20
  161. package/dist/home/index.js +5 -5
  162. package/dist/index.cjs +969 -928
  163. package/dist/index.cjs.map +1 -1
  164. package/dist/index.js +26 -25
  165. package/dist/index.js.map +1 -1
  166. package/dist/retrieval/index.cjs +1 -1
  167. package/dist/retrieval/index.js +1 -1
  168. package/dist/settings/index.cjs +58 -72
  169. package/dist/settings/index.cjs.map +1 -1
  170. package/dist/settings/index.js +6 -23
  171. package/dist/settings/index.js.map +1 -1
  172. package/dist/shell/index.cjs +61 -60
  173. package/dist/shell/index.js +5 -4
  174. package/dist/site/index.cjs +5 -5
  175. package/dist/site/index.js +1 -1
  176. package/dist/studio/index.cjs +11 -11
  177. package/dist/studio/index.js +9 -9
  178. package/dist/workflow-canvas/index.cjs +69 -70
  179. package/dist/workflow-canvas/index.cjs.map +1 -1
  180. package/dist/workflow-canvas/index.js +14 -15
  181. package/dist/workflow-canvas/index.js.map +1 -1
  182. package/dist/workspaces/index.cjs +2 -2
  183. package/dist/workspaces/index.js +2 -2
  184. package/node_modules/@arbidocs/coedit/package.json +1 -1
  185. package/package.json +4 -4
  186. package/dist/chunk-2Q7FDZAY.js.map +0 -1
  187. package/dist/chunk-AAFX64WD.cjs.map +0 -1
  188. package/dist/chunk-ATJUVHVB.js.map +0 -1
  189. package/dist/chunk-CHVCTKF4.cjs.map +0 -1
  190. package/dist/chunk-CQCC7LE7.js +0 -210
  191. package/dist/chunk-CQCC7LE7.js.map +0 -1
  192. package/dist/chunk-JY73DJOS.cjs.map +0 -1
  193. package/dist/chunk-KDUGTKVI.cjs.map +0 -1
  194. package/dist/chunk-KMNZ2RVO.js.map +0 -1
  195. package/dist/chunk-KSHKTOY2.js.map +0 -1
  196. package/dist/chunk-L2PAPOZ5.js.map +0 -1
  197. package/dist/chunk-OGBXV326.cjs.map +0 -1
  198. package/dist/chunk-OQ7RUNOC.js.map +0 -1
  199. package/dist/chunk-RFIBUWLF.cjs +0 -232
  200. package/dist/chunk-RFIBUWLF.cjs.map +0 -1
  201. package/dist/chunk-RQ2Y7USX.cjs.map +0 -1
  202. package/dist/chunk-W3VYZXNS.js.map +0 -1
  203. package/dist/chunk-WXYQ66KC.cjs.map +0 -1
@@ -1,4242 +1,484 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var chunk6YTHQ73P_cjs = require('../chunk-6YTHQ73P.cjs');
4
5
  var chunkBIXHB4LV_cjs = require('../chunk-BIXHB4LV.cjs');
5
6
  require('../chunk-DES3K4SD.cjs');
6
- var react = require('react');
7
- var FullCalendar = require('@fullcalendar/react');
8
- var dayGridPlugin = require('@fullcalendar/daygrid');
9
- var timeGridPlugin = require('@fullcalendar/timegrid');
10
- var listPlugin = require('@fullcalendar/list');
11
- var interactionPlugin = require('@fullcalendar/interaction');
12
- var multiMonthPlugin = require('@fullcalendar/multimonth');
13
- var lucideReact = require('lucide-react');
14
- var ui = require('@arbidocs/react/ui');
15
- var jsxRuntime = require('react/jsx-runtime');
16
- var core = require('@fullcalendar/core');
17
- var internal = require('@fullcalendar/core/internal');
18
- var temporalPolyfill = require('temporal-polyfill');
19
- var reactDom = require('react-dom');
20
- var client = require('react-dom/client');
21
7
 
22
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
23
8
 
24
- var FullCalendar__default = /*#__PURE__*/_interopDefault(FullCalendar);
25
- var dayGridPlugin__default = /*#__PURE__*/_interopDefault(dayGridPlugin);
26
- var timeGridPlugin__default = /*#__PURE__*/_interopDefault(timeGridPlugin);
27
- var listPlugin__default = /*#__PURE__*/_interopDefault(listPlugin);
28
- var interactionPlugin__default = /*#__PURE__*/_interopDefault(interactionPlugin);
29
- var multiMonthPlugin__default = /*#__PURE__*/_interopDefault(multiMonthPlugin);
30
9
 
31
- // src/calendar/labels.ts
32
- var CALENDAR_DEFAULT_LABELS = {
33
- today: "Today",
34
- view: "View",
35
- previous: "Previous",
36
- next: "Next",
37
- day: "Day",
38
- week: "Week",
39
- workWeek: "Work week",
40
- month: "Month",
41
- agenda: "Agenda",
42
- year: "Year",
43
- allDay: "All day",
44
- busy: "Busy",
45
- noTitle: "(No title)",
46
- noEvents: "No events",
47
- weekAbbrev: "W",
48
- more: "more",
49
- newEvent: "New event",
50
- myCalendars: "My calendars",
51
- sharedCalendars: "Shared with me",
52
- workspaceCalendars: "Workspace calendars",
53
- subscribedCalendars: "Subscribed",
54
- overlays: "Also show",
55
- facts: "Dated facts",
56
- workflows: "Workflows",
57
- tasks: "Tasks",
58
- createCalendar: "New calendar",
59
- editCalendar: "Settings and sharing",
60
- importCalendar: "Import .ics",
61
- exportCalendar: "Export .ics",
62
- deleteCalendar: "Delete calendar",
63
- locked: "Locked calendar",
64
- showCalendar: "Show",
65
- hideCalendar: "Hide",
66
- calendarColor: "Colour",
67
- title: "Title",
68
- titlePlaceholder: "Add a title",
69
- calendar: "Calendar",
70
- start: "Start",
71
- end: "End",
72
- startTime: "Start time",
73
- endTime: "End time",
74
- arbiCall: "ARBI call",
75
- arbiWebinar: "ARBI webinar",
76
- startTimeZone: "Start time zone",
77
- endTimeZone: "End time zone",
78
- separateTimeZones: "Time zones",
79
- repeat: "Repeat",
80
- location: "Location",
81
- description: "Description",
82
- attendees: "Guests",
83
- addAttendee: "Add guests by email",
84
- required: "Required",
85
- optional: "Optional",
86
- showAs: "Show as",
87
- sensitivity: "Visibility",
88
- categories: "Categories",
89
- addCategory: "Add a category",
90
- color: "Colour",
91
- defaultColor: "Calendar colour",
92
- reminders: "Reminders",
93
- addReminder: "Add reminder",
94
- useDefaultReminders: "Use calendar default reminders",
95
- conference: "Video call",
96
- addArbiCall: "Add ARBI call",
97
- addArbiWebinar: "Add ARBI webinar",
98
- webinar: "Webinar",
99
- webinarLinkOnSave: "The link is created when you save",
100
- webinarRole: "Webinar role",
101
- cohost: "Co-host",
102
- panelist: "Panelist",
103
- webinarAttendee: "Attendee",
104
- joinWebinar: "Join webinar",
105
- addMeetingLink: "Add meeting link",
106
- meetingLinkPlaceholder: "https://\u2026",
107
- removeConference: "Remove video call",
108
- attachments: "Attachments",
109
- addAttachment: "Add link",
110
- attachmentUrlPlaceholder: "https://\u2026",
111
- attachmentTitlePlaceholder: "Title (optional)",
112
- status: "Status",
113
- save: "Save",
114
- saving: "Saving\u2026",
115
- cancel: "Cancel",
116
- delete: "Delete",
117
- edit: "Edit",
118
- remove: "Remove",
119
- createTitle: "New event",
120
- editTitle: "Edit event",
121
- minutes: "minutes",
122
- hours: "hours",
123
- days: "days",
124
- weeks: "weeks",
125
- beforeStart: "before",
126
- popup: "Notification",
127
- email: "Email",
128
- atStart: "At time of event",
129
- free: "Free",
130
- tentative: "Tentative",
131
- oof: "Out of office",
132
- workingElsewhere: "Working elsewhere",
133
- normal: "Default visibility",
134
- private: "Private",
135
- confidential: "Confidential",
136
- confirmed: "Confirmed",
137
- cancelled: "Cancelled",
138
- join: "Join",
139
- openMeetingChat: "Open meeting chat",
140
- accept: "Yes",
141
- decline: "No",
142
- maybe: "Maybe",
143
- going: "Going?",
144
- organizer: "Organiser",
145
- needsAction: "Awaiting reply",
146
- accepted: "Accepted",
147
- declined: "Declined",
148
- delegated: "Delegated",
149
- recurring: "Repeats",
150
- scopeEditTitle: "Edit recurring event",
151
- scopeDeleteTitle: "Delete recurring event",
152
- scopeThis: "This event",
153
- scopeFollowing: "This and following events",
154
- scopeAll: "All events",
155
- settingsTitle: "Calendar settings",
156
- timeZone: "Time zone",
157
- secondaryTimeZone: "Secondary time zone",
158
- none: "None",
159
- weekStart: "Week starts on",
160
- workingHours: "Working hours",
161
- defaultView: "Default view",
162
- defaultDuration: "Default event length",
163
- defaultCalendar: "Default calendar",
164
- showDeclined: "Show declined events",
165
- showWeekNumbers: "Show week numbers",
166
- autoAddInvitations: "Add invitations to my calendar",
167
- autoAddAll: "From everyone",
168
- autoAddKnown: "Only from people I know",
169
- autoAddNone: "Only after I respond",
170
- declineMessage: "Default decline message",
171
- searchTimeZones: "Search time zones",
172
- invalidRange: "The end must be after the start.",
173
- titleRequired: "Add a title.",
174
- removeFromCalendar: "Remove from calendar",
175
- proposeNewTime: "Propose new time",
176
- scopeRespondTitle: "Respond to a recurring event",
177
- send: "Send",
178
- focusTime: "Focus time",
179
- autoDecline: "Decline new invitations",
180
- declineMessagePlaceholder: "Message for declined invitations (optional)",
181
- schedulingAssistant: "Scheduling assistant",
182
- findATime: "Find a time",
183
- findingTimes: "Finding times\u2026",
184
- noSuggestions: "No free times found in this range.",
185
- everyoneFree: "Everyone available",
186
- unavailableCount: "unavailable",
187
- unknownAvailability: "Availability not shared",
188
- outsideWorkingHours: "Outside working hours",
189
- rooms: "Rooms",
190
- findRoom: "Find a room",
191
- minCapacity: "Min. capacity",
192
- featureFilter: "Feature",
193
- addRoom: "Add",
194
- roomAdded: "Added",
195
- roomFree: "Free",
196
- roomBusy: "Busy",
197
- noRooms: "No rooms match.",
198
- room: "Room",
199
- you: "You",
200
- addCalendar: "Add calendar",
201
- subscribeFromUrl: "Subscribe from URL",
202
- addHolidays: "Holidays",
203
- importIcs: "Import .ics file",
204
- shareCalendar: "Share\u2026",
205
- refreshCalendar: "Refresh",
206
- publishTo: "Publish to\u2026",
207
- suggestions: "Suggestions"
208
- };
209
- var mergeLabels = (labels) => ({
210
- ...CALENDAR_DEFAULT_LABELS,
211
- ...labels
10
+ Object.defineProperty(exports, "ARBI_WEBINAR_LABEL", {
11
+ enumerable: true,
12
+ get: function () { return chunk6YTHQ73P_cjs.ARBI_WEBINAR_LABEL; }
13
+ });
14
+ Object.defineProperty(exports, "CALENDAR_COLORS", {
15
+ enumerable: true,
16
+ get: function () { return chunk6YTHQ73P_cjs.CALENDAR_COLORS; }
17
+ });
18
+ Object.defineProperty(exports, "CALENDAR_DEFAULT_LABELS", {
19
+ enumerable: true,
20
+ get: function () { return chunk6YTHQ73P_cjs.CALENDAR_DEFAULT_LABELS; }
21
+ });
22
+ Object.defineProperty(exports, "CALENDAR_NARROW_WIDTH", {
23
+ enumerable: true,
24
+ get: function () { return chunk6YTHQ73P_cjs.CALENDAR_NARROW_WIDTH; }
25
+ });
26
+ Object.defineProperty(exports, "CalendarFormDialog", {
27
+ enumerable: true,
28
+ get: function () { return chunk6YTHQ73P_cjs.CalendarFormDialog; }
29
+ });
30
+ Object.defineProperty(exports, "CalendarGrid", {
31
+ enumerable: true,
32
+ get: function () { return chunk6YTHQ73P_cjs.CalendarGrid; }
33
+ });
34
+ Object.defineProperty(exports, "CalendarList", {
35
+ enumerable: true,
36
+ get: function () { return chunk6YTHQ73P_cjs.CalendarList; }
37
+ });
38
+ Object.defineProperty(exports, "CalendarPrint", {
39
+ enumerable: true,
40
+ get: function () { return chunk6YTHQ73P_cjs.CalendarPrint; }
41
+ });
42
+ Object.defineProperty(exports, "CalendarSettingsForm", {
43
+ enumerable: true,
44
+ get: function () { return chunk6YTHQ73P_cjs.CalendarSettingsForm; }
45
+ });
46
+ Object.defineProperty(exports, "DEFAULT_EVENT_COLOR", {
47
+ enumerable: true,
48
+ get: function () { return chunk6YTHQ73P_cjs.DEFAULT_EVENT_COLOR; }
49
+ });
50
+ Object.defineProperty(exports, "DEFAULT_INTERVAL", {
51
+ enumerable: true,
52
+ get: function () { return chunk6YTHQ73P_cjs.DEFAULT_INTERVAL; }
53
+ });
54
+ Object.defineProperty(exports, "DEFAULT_RECURRENCE_DESCRIBE_LABELS", {
55
+ enumerable: true,
56
+ get: function () { return chunk6YTHQ73P_cjs.DEFAULT_RECURRENCE_DESCRIBE_LABELS; }
57
+ });
58
+ Object.defineProperty(exports, "DEFAULT_RECURRENCE_EDITOR_LABELS", {
59
+ enumerable: true,
60
+ get: function () { return chunk6YTHQ73P_cjs.DEFAULT_RECURRENCE_EDITOR_LABELS; }
61
+ });
62
+ Object.defineProperty(exports, "DEFAULT_REMINDER_FORMAT_LABELS", {
63
+ enumerable: true,
64
+ get: function () { return chunk6YTHQ73P_cjs.DEFAULT_REMINDER_FORMAT_LABELS; }
65
+ });
66
+ Object.defineProperty(exports, "EventDetails", {
67
+ enumerable: true,
68
+ get: function () { return chunk6YTHQ73P_cjs.EventDetails; }
69
+ });
70
+ Object.defineProperty(exports, "EventEditor", {
71
+ enumerable: true,
72
+ get: function () { return chunk6YTHQ73P_cjs.EventEditor; }
73
+ });
74
+ Object.defineProperty(exports, "JOIN_EARLY_MS", {
75
+ enumerable: true,
76
+ get: function () { return chunk6YTHQ73P_cjs.JOIN_EARLY_MS; }
77
+ });
78
+ Object.defineProperty(exports, "MiniMonth", {
79
+ enumerable: true,
80
+ get: function () { return chunk6YTHQ73P_cjs.MiniMonth; }
81
+ });
82
+ Object.defineProperty(exports, "OVERLAY_COLORS", {
83
+ enumerable: true,
84
+ get: function () { return chunk6YTHQ73P_cjs.OVERLAY_COLORS; }
85
+ });
86
+ Object.defineProperty(exports, "PENDING_EVENT_COLOR", {
87
+ enumerable: true,
88
+ get: function () { return chunk6YTHQ73P_cjs.PENDING_EVENT_COLOR; }
89
+ });
90
+ Object.defineProperty(exports, "ProposeTimeDialog", {
91
+ enumerable: true,
92
+ get: function () { return chunk6YTHQ73P_cjs.ProposeTimeDialog; }
93
+ });
94
+ Object.defineProperty(exports, "REMINDER_PRESETS", {
95
+ enumerable: true,
96
+ get: function () { return chunk6YTHQ73P_cjs.REMINDER_PRESETS; }
97
+ });
98
+ Object.defineProperty(exports, "RRULE_WEEKDAYS", {
99
+ enumerable: true,
100
+ get: function () { return chunk6YTHQ73P_cjs.RRULE_WEEKDAYS; }
101
+ });
102
+ Object.defineProperty(exports, "RecurrenceEditor", {
103
+ enumerable: true,
104
+ get: function () { return chunk6YTHQ73P_cjs.RecurrenceEditor; }
105
+ });
106
+ Object.defineProperty(exports, "RoomFinder", {
107
+ enumerable: true,
108
+ get: function () { return chunk6YTHQ73P_cjs.RoomFinder; }
109
+ });
110
+ Object.defineProperty(exports, "SchedulingAssistant", {
111
+ enumerable: true,
112
+ get: function () { return chunk6YTHQ73P_cjs.SchedulingAssistant; }
113
+ });
114
+ Object.defineProperty(exports, "ScopeDialog", {
115
+ enumerable: true,
116
+ get: function () { return chunk6YTHQ73P_cjs.ScopeDialog; }
117
+ });
118
+ Object.defineProperty(exports, "TimeZonePicker", {
119
+ enumerable: true,
120
+ get: function () { return chunk6YTHQ73P_cjs.TimeZonePicker; }
121
+ });
122
+ Object.defineProperty(exports, "WEEKDAY_NAMES", {
123
+ enumerable: true,
124
+ get: function () { return chunk6YTHQ73P_cjs.WEEKDAY_NAMES; }
125
+ });
126
+ Object.defineProperty(exports, "WeeklyHoursEditor", {
127
+ enumerable: true,
128
+ get: function () { return chunk6YTHQ73P_cjs.WeeklyHoursEditor; }
129
+ });
130
+ Object.defineProperty(exports, "allDayInclusiveEnd", {
131
+ enumerable: true,
132
+ get: function () { return chunk6YTHQ73P_cjs.allDayInclusiveEnd; }
133
+ });
134
+ Object.defineProperty(exports, "applySuggestion", {
135
+ enumerable: true,
136
+ get: function () { return chunk6YTHQ73P_cjs.applySuggestion; }
137
+ });
138
+ Object.defineProperty(exports, "attendeeKey", {
139
+ enumerable: true,
140
+ get: function () { return chunk6YTHQ73P_cjs.attendeeKey; }
141
+ });
142
+ Object.defineProperty(exports, "bookingLink", {
143
+ enumerable: true,
144
+ get: function () { return chunk6YTHQ73P_cjs.bookingLink; }
145
+ });
146
+ Object.defineProperty(exports, "bookingToForm", {
147
+ enumerable: true,
148
+ get: function () { return chunk6YTHQ73P_cjs.bookingToForm; }
149
+ });
150
+ Object.defineProperty(exports, "buildCreateBody", {
151
+ enumerable: true,
152
+ get: function () { return chunk6YTHQ73P_cjs.buildCreateBody; }
153
+ });
154
+ Object.defineProperty(exports, "buildDeleteTarget", {
155
+ enumerable: true,
156
+ get: function () { return chunk6YTHQ73P_cjs.buildDeleteTarget; }
157
+ });
158
+ Object.defineProperty(exports, "buildEditRequest", {
159
+ enumerable: true,
160
+ get: function () { return chunk6YTHQ73P_cjs.buildEditRequest; }
161
+ });
162
+ Object.defineProperty(exports, "buildGridEvents", {
163
+ enumerable: true,
164
+ get: function () { return chunk6YTHQ73P_cjs.buildGridEvents; }
165
+ });
166
+ Object.defineProperty(exports, "buildRRule", {
167
+ enumerable: true,
168
+ get: function () { return chunk6YTHQ73P_cjs.buildRRule; }
169
+ });
170
+ Object.defineProperty(exports, "buildTimeChangeRequest", {
171
+ enumerable: true,
172
+ get: function () { return chunk6YTHQ73P_cjs.buildTimeChangeRequest; }
173
+ });
174
+ Object.defineProperty(exports, "calendarGroup", {
175
+ enumerable: true,
176
+ get: function () { return chunk6YTHQ73P_cjs.calendarGroup; }
177
+ });
178
+ Object.defineProperty(exports, "calendarToListItem", {
179
+ enumerable: true,
180
+ get: function () { return chunk6YTHQ73P_cjs.calendarToListItem; }
181
+ });
182
+ Object.defineProperty(exports, "canJoinEvent", {
183
+ enumerable: true,
184
+ get: function () { return chunk6YTHQ73P_cjs.canJoinEvent; }
185
+ });
186
+ Object.defineProperty(exports, "conferenceUrl", {
187
+ enumerable: true,
188
+ get: function () { return chunk6YTHQ73P_cjs.conferenceUrl; }
189
+ });
190
+ Object.defineProperty(exports, "contrastText", {
191
+ enumerable: true,
192
+ get: function () { return chunk6YTHQ73P_cjs.contrastText; }
193
+ });
194
+ Object.defineProperty(exports, "davHost", {
195
+ enumerable: true,
196
+ get: function () { return chunk6YTHQ73P_cjs.davHost; }
197
+ });
198
+ Object.defineProperty(exports, "dayWindow", {
199
+ enumerable: true,
200
+ get: function () { return chunk6YTHQ73P_cjs.dayWindow; }
201
+ });
202
+ Object.defineProperty(exports, "defaultRecurrenceForm", {
203
+ enumerable: true,
204
+ get: function () { return chunk6YTHQ73P_cjs.defaultRecurrenceForm; }
205
+ });
206
+ Object.defineProperty(exports, "defaultRoomWindow", {
207
+ enumerable: true,
208
+ get: function () { return chunk6YTHQ73P_cjs.defaultRoomWindow; }
209
+ });
210
+ Object.defineProperty(exports, "defaultWeeklyHours", {
211
+ enumerable: true,
212
+ get: function () { return chunk6YTHQ73P_cjs.defaultWeeklyHours; }
213
+ });
214
+ Object.defineProperty(exports, "describeCalendarError", {
215
+ enumerable: true,
216
+ get: function () { return chunk6YTHQ73P_cjs.describeCalendarError; }
217
+ });
218
+ Object.defineProperty(exports, "describeRecurrence", {
219
+ enumerable: true,
220
+ get: function () { return chunk6YTHQ73P_cjs.describeRecurrence; }
221
+ });
222
+ Object.defineProperty(exports, "diffDraft", {
223
+ enumerable: true,
224
+ get: function () { return chunk6YTHQ73P_cjs.diffDraft; }
225
+ });
226
+ Object.defineProperty(exports, "draftFromSlot", {
227
+ enumerable: true,
228
+ get: function () { return chunk6YTHQ73P_cjs.draftFromSlot; }
229
+ });
230
+ Object.defineProperty(exports, "draftRangeUtc", {
231
+ enumerable: true,
232
+ get: function () { return chunk6YTHQ73P_cjs.draftRangeUtc; }
233
+ });
234
+ Object.defineProperty(exports, "effectiveCalendarView", {
235
+ enumerable: true,
236
+ get: function () { return chunk6YTHQ73P_cjs.effectiveCalendarView; }
237
+ });
238
+ Object.defineProperty(exports, "emptyBookingForm", {
239
+ enumerable: true,
240
+ get: function () { return chunk6YTHQ73P_cjs.emptyBookingForm; }
241
+ });
242
+ Object.defineProperty(exports, "eventDays", {
243
+ enumerable: true,
244
+ get: function () { return chunk6YTHQ73P_cjs.eventDays; }
245
+ });
246
+ Object.defineProperty(exports, "eventStateClasses", {
247
+ enumerable: true,
248
+ get: function () { return chunk6YTHQ73P_cjs.eventStateClasses; }
249
+ });
250
+ Object.defineProperty(exports, "eventToDraft", {
251
+ enumerable: true,
252
+ get: function () { return chunk6YTHQ73P_cjs.eventToDraft; }
253
+ });
254
+ Object.defineProperty(exports, "eventToGrid", {
255
+ enumerable: true,
256
+ get: function () { return chunk6YTHQ73P_cjs.eventToGrid; }
257
+ });
258
+ Object.defineProperty(exports, "eventsByDay", {
259
+ enumerable: true,
260
+ get: function () { return chunk6YTHQ73P_cjs.eventsByDay; }
261
+ });
262
+ Object.defineProperty(exports, "formToBookingBody", {
263
+ enumerable: true,
264
+ get: function () { return chunk6YTHQ73P_cjs.formToBookingBody; }
265
+ });
266
+ Object.defineProperty(exports, "formatBusy", {
267
+ enumerable: true,
268
+ get: function () { return chunk6YTHQ73P_cjs.formatBusy; }
269
+ });
270
+ Object.defineProperty(exports, "formatDayLabel", {
271
+ enumerable: true,
272
+ get: function () { return chunk6YTHQ73P_cjs.formatDayLabel; }
273
+ });
274
+ Object.defineProperty(exports, "formatEventWhen", {
275
+ enumerable: true,
276
+ get: function () { return chunk6YTHQ73P_cjs.formatEventWhen; }
277
+ });
278
+ Object.defineProperty(exports, "formatReminder", {
279
+ enumerable: true,
280
+ get: function () { return chunk6YTHQ73P_cjs.formatReminder; }
281
+ });
282
+ Object.defineProperty(exports, "formatSlotRange", {
283
+ enumerable: true,
284
+ get: function () { return chunk6YTHQ73P_cjs.formatSlotRange; }
285
+ });
286
+ Object.defineProperty(exports, "formatSlotTime", {
287
+ enumerable: true,
288
+ get: function () { return chunk6YTHQ73P_cjs.formatSlotTime; }
289
+ });
290
+ Object.defineProperty(exports, "formatZoneLabel", {
291
+ enumerable: true,
292
+ get: function () { return chunk6YTHQ73P_cjs.formatZoneLabel; }
293
+ });
294
+ Object.defineProperty(exports, "freeBusyToRows", {
295
+ enumerable: true,
296
+ get: function () { return chunk6YTHQ73P_cjs.freeBusyToRows; }
297
+ });
298
+ Object.defineProperty(exports, "getTemporalTimeZonePlugin", {
299
+ enumerable: true,
300
+ get: function () { return chunk6YTHQ73P_cjs.getTemporalTimeZonePlugin; }
301
+ });
302
+ Object.defineProperty(exports, "groupSlotsByDay", {
303
+ enumerable: true,
304
+ get: function () { return chunk6YTHQ73P_cjs.groupSlotsByDay; }
305
+ });
306
+ Object.defineProperty(exports, "hourTicks", {
307
+ enumerable: true,
308
+ get: function () { return chunk6YTHQ73P_cjs.hourTicks; }
309
+ });
310
+ Object.defineProperty(exports, "icsProps", {
311
+ enumerable: true,
312
+ get: function () { return chunk6YTHQ73P_cjs.icsProps; }
313
+ });
314
+ Object.defineProperty(exports, "isAllDayDraft", {
315
+ enumerable: true,
316
+ get: function () { return chunk6YTHQ73P_cjs.isAllDayDraft; }
317
+ });
318
+ Object.defineProperty(exports, "isCalendarAttachment", {
319
+ enumerable: true,
320
+ get: function () { return chunk6YTHQ73P_cjs.isCalendarAttachment; }
321
+ });
322
+ Object.defineProperty(exports, "isWebinarConference", {
323
+ enumerable: true,
324
+ get: function () { return chunk6YTHQ73P_cjs.isWebinarConference; }
325
+ });
326
+ Object.defineProperty(exports, "needsScope", {
327
+ enumerable: true,
328
+ get: function () { return chunk6YTHQ73P_cjs.needsScope; }
329
+ });
330
+ Object.defineProperty(exports, "newEventDraft", {
331
+ enumerable: true,
332
+ get: function () { return chunk6YTHQ73P_cjs.newEventDraft; }
333
+ });
334
+ Object.defineProperty(exports, "normalizeFeedUrl", {
335
+ enumerable: true,
336
+ get: function () { return chunk6YTHQ73P_cjs.normalizeFeedUrl; }
337
+ });
338
+ Object.defineProperty(exports, "outsideIntervals", {
339
+ enumerable: true,
340
+ get: function () { return chunk6YTHQ73P_cjs.outsideIntervals; }
341
+ });
342
+ Object.defineProperty(exports, "overlayToGrid", {
343
+ enumerable: true,
344
+ get: function () { return chunk6YTHQ73P_cjs.overlayToGrid; }
345
+ });
346
+ Object.defineProperty(exports, "parseDurations", {
347
+ enumerable: true,
348
+ get: function () { return chunk6YTHQ73P_cjs.parseDurations; }
349
+ });
350
+ Object.defineProperty(exports, "parseIcsInvite", {
351
+ enumerable: true,
352
+ get: function () { return chunk6YTHQ73P_cjs.parseIcsInvite; }
353
+ });
354
+ Object.defineProperty(exports, "parseOverlayLink", {
355
+ enumerable: true,
356
+ get: function () { return chunk6YTHQ73P_cjs.parseOverlayLink; }
357
+ });
358
+ Object.defineProperty(exports, "parseRRule", {
359
+ enumerable: true,
360
+ get: function () { return chunk6YTHQ73P_cjs.parseRRule; }
361
+ });
362
+ Object.defineProperty(exports, "pendingCreateToGrid", {
363
+ enumerable: true,
364
+ get: function () { return chunk6YTHQ73P_cjs.pendingCreateToGrid; }
365
+ });
366
+ Object.defineProperty(exports, "placeIntervals", {
367
+ enumerable: true,
368
+ get: function () { return chunk6YTHQ73P_cjs.placeIntervals; }
369
+ });
370
+ Object.defineProperty(exports, "printCalendar", {
371
+ enumerable: true,
372
+ get: function () { return chunk6YTHQ73P_cjs.printCalendar; }
373
+ });
374
+ Object.defineProperty(exports, "printRange", {
375
+ enumerable: true,
376
+ get: function () { return chunk6YTHQ73P_cjs.printRange; }
377
+ });
378
+ Object.defineProperty(exports, "publicBookingMessage", {
379
+ enumerable: true,
380
+ get: function () { return chunk6YTHQ73P_cjs.publicBookingMessage; }
381
+ });
382
+ Object.defineProperty(exports, "reminderToMinutes", {
383
+ enumerable: true,
384
+ get: function () { return chunk6YTHQ73P_cjs.reminderToMinutes; }
385
+ });
386
+ Object.defineProperty(exports, "scopedTarget", {
387
+ enumerable: true,
388
+ get: function () { return chunk6YTHQ73P_cjs.scopedTarget; }
389
+ });
390
+ Object.defineProperty(exports, "setDraftAllDay", {
391
+ enumerable: true,
392
+ get: function () { return chunk6YTHQ73P_cjs.setDraftAllDay; }
393
+ });
394
+ Object.defineProperty(exports, "setDraftEnd", {
395
+ enumerable: true,
396
+ get: function () { return chunk6YTHQ73P_cjs.setDraftEnd; }
397
+ });
398
+ Object.defineProperty(exports, "setDraftStart", {
399
+ enumerable: true,
400
+ get: function () { return chunk6YTHQ73P_cjs.setDraftStart; }
401
+ });
402
+ Object.defineProperty(exports, "setPosOf", {
403
+ enumerable: true,
404
+ get: function () { return chunk6YTHQ73P_cjs.setPosOf; }
405
+ });
406
+ Object.defineProperty(exports, "setupSteps", {
407
+ enumerable: true,
408
+ get: function () { return chunk6YTHQ73P_cjs.setupSteps; }
409
+ });
410
+ Object.defineProperty(exports, "slugify", {
411
+ enumerable: true,
412
+ get: function () { return chunk6YTHQ73P_cjs.slugify; }
413
+ });
414
+ Object.defineProperty(exports, "specDate", {
415
+ enumerable: true,
416
+ get: function () { return chunk6YTHQ73P_cjs.specDate; }
417
+ });
418
+ Object.defineProperty(exports, "specTime", {
419
+ enumerable: true,
420
+ get: function () { return chunk6YTHQ73P_cjs.specTime; }
421
+ });
422
+ Object.defineProperty(exports, "splitReminderMinutes", {
423
+ enumerable: true,
424
+ get: function () { return chunk6YTHQ73P_cjs.splitReminderMinutes; }
425
+ });
426
+ Object.defineProperty(exports, "toBusinessHours", {
427
+ enumerable: true,
428
+ get: function () { return chunk6YTHQ73P_cjs.toBusinessHours; }
429
+ });
430
+ Object.defineProperty(exports, "toSettingsValue", {
431
+ enumerable: true,
432
+ get: function () { return chunk6YTHQ73P_cjs.toSettingsValue; }
433
+ });
434
+ Object.defineProperty(exports, "toSuggestionViews", {
435
+ enumerable: true,
436
+ get: function () { return chunk6YTHQ73P_cjs.toSuggestionViews; }
437
+ });
438
+ Object.defineProperty(exports, "upcomingOf", {
439
+ enumerable: true,
440
+ get: function () { return chunk6YTHQ73P_cjs.upcomingOf; }
441
+ });
442
+ Object.defineProperty(exports, "validateBookingForm", {
443
+ enumerable: true,
444
+ get: function () { return chunk6YTHQ73P_cjs.validateBookingForm; }
445
+ });
446
+ Object.defineProperty(exports, "validateDraft", {
447
+ enumerable: true,
448
+ get: function () { return chunk6YTHQ73P_cjs.validateDraft; }
449
+ });
450
+ Object.defineProperty(exports, "validateWeekly", {
451
+ enumerable: true,
452
+ get: function () { return chunk6YTHQ73P_cjs.validateWeekly; }
453
+ });
454
+ Object.defineProperty(exports, "weekdayMon0", {
455
+ enumerable: true,
456
+ get: function () { return chunk6YTHQ73P_cjs.weekdayMon0; }
457
+ });
458
+ Object.defineProperty(exports, "weekdayOf", {
459
+ enumerable: true,
460
+ get: function () { return chunk6YTHQ73P_cjs.weekdayOf; }
461
+ });
462
+ Object.defineProperty(exports, "weeklyFromApi", {
463
+ enumerable: true,
464
+ get: function () { return chunk6YTHQ73P_cjs.weeklyFromApi; }
465
+ });
466
+ Object.defineProperty(exports, "weeklyToPayload", {
467
+ enumerable: true,
468
+ get: function () { return chunk6YTHQ73P_cjs.weeklyToPayload; }
469
+ });
470
+ Object.defineProperty(exports, "workWeekHiddenDays", {
471
+ enumerable: true,
472
+ get: function () { return chunk6YTHQ73P_cjs.workWeekHiddenDays; }
473
+ });
474
+ Object.defineProperty(exports, "workingIntervals", {
475
+ enumerable: true,
476
+ get: function () { return chunk6YTHQ73P_cjs.workingIntervals; }
477
+ });
478
+ Object.defineProperty(exports, "zoneOptions", {
479
+ enumerable: true,
480
+ get: function () { return chunk6YTHQ73P_cjs.zoneOptions; }
212
481
  });
213
-
214
- // src/calendar/colors.ts
215
- var CALENDAR_COLORS = [
216
- "#3b82f6",
217
- "#0ea5e9",
218
- "#14b8a6",
219
- "#22c55e",
220
- "#84cc16",
221
- "#eab308",
222
- "#f97316",
223
- "#ef4444",
224
- "#ec4899",
225
- "#a855f7",
226
- "#6366f1",
227
- "#64748b"
228
- ];
229
- function contrastText(hex) {
230
- const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
231
- if (!m) return "#ffffff";
232
- const n = parseInt(m[1], 16);
233
- const ch = [n >> 16 & 255, n >> 8 & 255, n & 255].map((v) => {
234
- const c = v / 255;
235
- return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
236
- });
237
- const lum = 0.2126 * ch[0] + 0.7152 * ch[1] + 0.0722 * ch[2];
238
- return 1.05 / (lum + 0.05) >= (lum + 0.05) / 0.05 ? "#ffffff" : "#111827";
239
- }
240
- var NativeSelect = react.forwardRef(
241
- function NativeSelect2({ className, children, ...props }, ref) {
242
- return /* @__PURE__ */ jsxRuntime.jsx(
243
- "select",
244
- {
245
- ref,
246
- className: ui.cn(
247
- "h-9 rounded-md border border-input bg-background px-2 text-sm text-foreground shadow-sm",
248
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50",
249
- className
250
- ),
251
- ...props,
252
- children
253
- }
254
- );
255
- }
256
- );
257
- function FieldRow({
258
- icon,
259
- label,
260
- children,
261
- className
262
- }) {
263
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex items-start gap-3", className), children: [
264
- /* @__PURE__ */ jsxRuntime.jsx(
265
- "div",
266
- {
267
- className: "mt-2 flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground",
268
- "aria-hidden": true,
269
- children: icon
270
- }
271
- ),
272
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
273
- label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-muted-foreground", children: label }),
274
- children
275
- ] })
276
- ] });
277
- }
278
- function ColorSwatches({
279
- value,
280
- onChange,
281
- allowNone,
282
- noneLabel,
283
- testIdPrefix
284
- }) {
285
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", role: "radiogroup", children: [
286
- allowNone && /* @__PURE__ */ jsxRuntime.jsx(
287
- "button",
288
- {
289
- type: "button",
290
- role: "radio",
291
- "aria-checked": !value,
292
- "aria-label": noneLabel,
293
- title: noneLabel,
294
- onClick: () => onChange(null),
295
- className: ui.cn(
296
- "h-6 rounded-full border border-border px-2 text-xs text-muted-foreground",
297
- !value && "ring-2 ring-ring ring-offset-1 ring-offset-background"
298
- ),
299
- children: noneLabel
300
- }
301
- ),
302
- CALENDAR_COLORS.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
303
- "button",
304
- {
305
- type: "button",
306
- role: "radio",
307
- "aria-checked": value?.toLowerCase() === c,
308
- "aria-label": c,
309
- title: c,
310
- "data-testid": testIdPrefix ? `${testIdPrefix}-${c.slice(1)}` : void 0,
311
- onClick: () => onChange(c),
312
- className: ui.cn(
313
- "h-6 w-6 rounded-full border border-black/10",
314
- value?.toLowerCase() === c && "ring-2 ring-ring ring-offset-1 ring-offset-background"
315
- ),
316
- style: { backgroundColor: c }
317
- },
318
- c
319
- ))
320
- ] });
321
- }
322
- var temporalZonePlugin = null;
323
- function getTemporalTimeZonePlugin() {
324
- if (!temporalZonePlugin) {
325
- class TemporalNamedTimeZone extends internal.NamedTimeZoneImpl {
326
- offsetForArray(a) {
327
- return chunkBIXHB4LV_cjs.wallArrayOffset(a, this.timeZoneName);
328
- }
329
- timestampToArray(ms) {
330
- return chunkBIXHB4LV_cjs.epochToWallArray(ms, this.timeZoneName);
331
- }
332
- }
333
- temporalZonePlugin = core.createPlugin({
334
- name: "arbi-temporal-timezone",
335
- namedTimeZonedImpl: TemporalNamedTimeZone
336
- });
337
- }
338
- return temporalZonePlugin;
339
- }
340
- var FC_VIEW = {
341
- day: "timeGridDay",
342
- week: "timeGridWeek",
343
- work_week: "arbiWorkWeek",
344
- month: "dayGridMonth",
345
- agenda: "arbiAgenda",
346
- year: "multiMonthYear"
347
- };
348
- var VIEW_OF_FC = Object.fromEntries(
349
- Object.entries(FC_VIEW).map(([k, v]) => [v, k])
350
- );
351
- var VIEW_ORDER = [
352
- "day",
353
- "work_week",
354
- "week",
355
- "month",
356
- "agenda",
357
- "year"
358
- ];
359
- var NARROW_VIEWS = ["day", "month", "agenda"];
360
- var CALENDAR_NARROW_WIDTH = 640;
361
- function effectiveCalendarView(view, narrow) {
362
- if (!narrow) return view;
363
- return view === "week" || view === "work_week" || view === "year" ? "day" : view;
364
- }
365
- var viewLabel = (v, l) => ({
366
- day: l.day,
367
- week: l.week,
368
- work_week: l.workWeek,
369
- month: l.month,
370
- agenda: l.agenda,
371
- year: l.year
372
- })[v];
373
- function toBusinessHours(hours) {
374
- if (!hours?.length) return false;
375
- return hours.map((h) => ({
376
- daysOfWeek: [(h.day + 1) % 7],
377
- startTime: h.start,
378
- endTime: h.end === "24:00" ? "24:00:00" : h.end
379
- }));
380
- }
381
- function workWeekHiddenDays(hours) {
382
- const shown = new Set((hours ?? []).map((h) => (h.day + 1) % 7));
383
- if (shown.size === 0) return [0, 6];
384
- return [0, 1, 2, 3, 4, 5, 6].filter((d) => !shown.has(d));
385
- }
386
- function eventStateClasses(e) {
387
- const out = ["arbi-cal-event", `arbi-cal-layer-${e.layer}`];
388
- if (e.layer !== "event") out.push("arbi-cal-overlay");
389
- if (e.status === "cancelled") out.push("arbi-cal-cancelled");
390
- if (e.myPartstat === "declined") out.push("arbi-cal-declined");
391
- else if (e.myPartstat === "needs_action") out.push("arbi-cal-needs-action");
392
- else if (e.myPartstat === "tentative" || e.status === "tentative" || e.showAs === "tentative")
393
- out.push("arbi-cal-tentative");
394
- if (e.showAs === "free") out.push("arbi-cal-free");
395
- if (e.showAs === "oof") out.push("arbi-cal-oof");
396
- if (e.restricted) out.push("arbi-cal-restricted");
397
- return out;
398
- }
399
- function toEventInput(e, zone) {
400
- const editable = e.editable && e.layer === "event" && !e.restricted;
401
- const base = {
402
- id: e.instanceId,
403
- title: e.title,
404
- editable,
405
- startEditable: editable,
406
- durationEditable: editable,
407
- classNames: eventStateClasses(e),
408
- // The inner content paints the block (see calendar.css); the harness only carries the border
409
- // colour (list-view dot, needs-action outline).
410
- backgroundColor: "transparent",
411
- borderColor: e.color,
412
- textColor: "inherit",
413
- extendedProps: { grid: e }
414
- };
415
- if (e.allDay) {
416
- const start = e.startDate ?? chunkBIXHB4LV_cjs.utcToDate(e.startUtc, zone);
417
- const end = e.endDate ?? (e.endUtc ? chunkBIXHB4LV_cjs.utcToDate(e.endUtc, zone) : chunkBIXHB4LV_cjs.addDays(start, 1));
418
- return { ...base, allDay: true, start, end: end > start ? end : chunkBIXHB4LV_cjs.addDays(start, 1) };
419
- }
420
- return { ...base, allDay: false, start: e.startUtc, end: e.endUtc };
421
- }
422
- var LAYER_ICON = { facts: lucideReact.Lightbulb, workflows: lucideReact.Workflow, tasks: lucideReact.ListTodo };
423
- function EventBody({ arg, labels }) {
424
- const g = arg.event.extendedProps.grid;
425
- if (!g) return /* @__PURE__ */ jsxRuntime.jsx("span", { children: arg.event.title });
426
- const title = g.restricted ? labels.busy : g.title.trim() || labels.noTitle;
427
- const type = arg.view.type;
428
- const dot = type === "dayGridMonth" && !arg.event.allDay;
429
- const list = type.startsWith("list") || type === "arbiAgenda";
430
- const style = {
431
- "--arbi-cal-color": g.color,
432
- "--arbi-cal-fg": contrastText(g.color)
433
- };
434
- const OverlayIcon = g.layer !== "event" ? LAYER_ICON[g.layer] : null;
435
- const icons = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
436
- OverlayIcon && /* @__PURE__ */ jsxRuntime.jsx(OverlayIcon, { className: "arbi-cal-icon", "aria-hidden": true }),
437
- g.restricted && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "arbi-cal-icon", "aria-hidden": true }),
438
- g.isRecurring && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Repeat, { className: "arbi-cal-icon", "aria-label": labels.recurring }),
439
- g.hasConference && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "arbi-cal-icon", "aria-hidden": true })
440
- ] });
441
- if (list) {
442
- return /* @__PURE__ */ jsxRuntime.jsxs(
443
- "div",
444
- {
445
- className: "arbi-cal-list-item",
446
- style,
447
- "data-testid": "calendar-event",
448
- "data-instance-id": g.instanceId,
449
- children: [
450
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-title", children: title }),
451
- icons,
452
- g.location && !g.restricted && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "arbi-cal-location", children: [
453
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "arbi-cal-icon", "aria-hidden": true }),
454
- g.location
455
- ] })
456
- ]
457
- }
458
- );
459
- }
460
- if (dot) {
461
- return /* @__PURE__ */ jsxRuntime.jsxs(
462
- "div",
463
- {
464
- className: "arbi-cal-dot-item",
465
- style,
466
- "data-testid": "calendar-event",
467
- "data-instance-id": g.instanceId,
468
- children: [
469
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-dot", "aria-hidden": true }),
470
- arg.timeText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-time", children: arg.timeText }),
471
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-title", children: title })
472
- ]
473
- }
474
- );
475
- }
476
- return /* @__PURE__ */ jsxRuntime.jsxs(
477
- "div",
478
- {
479
- className: "arbi-cal-event-inner",
480
- style,
481
- "data-testid": "calendar-event",
482
- "data-instance-id": g.instanceId,
483
- children: [
484
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "arbi-cal-event-line", children: [
485
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-title", children: title }),
486
- icons
487
- ] }),
488
- !arg.event.allDay && arg.timeText && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "arbi-cal-time", children: arg.timeText }),
489
- !arg.event.allDay && g.location && !g.restricted && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "arbi-cal-location", children: g.location })
490
- ]
491
- }
492
- );
493
- }
494
- function isTypingTarget(t) {
495
- if (!(t instanceof HTMLElement)) return false;
496
- const tag = t.tagName;
497
- return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || t.isContentEditable;
498
- }
499
- function CalendarGrid({
500
- events,
501
- view,
502
- date,
503
- timeZone,
504
- secondaryTimeZone,
505
- weekStart,
506
- workingHours,
507
- showWeekNumbers = false,
508
- nowIndicator = true,
509
- onRangeChange,
510
- onSelectSlot,
511
- onEventClick,
512
- onEventChange,
513
- onViewChange,
514
- onDateChange,
515
- onCreateShortcut,
516
- height,
517
- labels: labelOverrides,
518
- hideToolbar,
519
- toolbarEnd,
520
- className,
521
- keyboardShortcuts = true
522
- }) {
523
- const labels = react.useMemo(() => mergeLabels(labelOverrides), [labelOverrides]);
524
- const zone = chunkBIXHB4LV_cjs.safeZone(timeZone);
525
- const secondZone = secondaryTimeZone && secondaryTimeZone !== zone && chunkBIXHB4LV_cjs.isValidTimeZone(secondaryTimeZone) ? secondaryTimeZone : "";
526
- const rootRef = react.useRef(null);
527
- const calRef = react.useRef(null);
528
- const [narrow, setNarrow] = react.useState(false);
529
- const [title, setTitle] = react.useState("");
530
- const lastRange = react.useRef("");
531
- const effective = effectiveCalendarView(view, narrow);
532
- const cb = react.useRef({
533
- onRangeChange,
534
- onSelectSlot,
535
- onEventClick,
536
- onEventChange,
537
- onViewChange,
538
- onDateChange,
539
- onCreateShortcut
540
- });
541
- cb.current = {
542
- onRangeChange,
543
- onSelectSlot,
544
- onEventClick,
545
- onEventChange,
546
- onViewChange,
547
- onDateChange,
548
- onCreateShortcut
549
- };
550
- const api = react.useCallback(() => calRef.current?.getApi() ?? null, []);
551
- react.useEffect(() => {
552
- const el = rootRef.current;
553
- if (!el || typeof ResizeObserver === "undefined") return;
554
- const ro = new ResizeObserver(([entry]) => {
555
- setNarrow(entry.contentRect.width > 0 && entry.contentRect.width < CALENDAR_NARROW_WIDTH);
556
- });
557
- ro.observe(el);
558
- return () => ro.disconnect();
559
- }, []);
560
- react.useEffect(() => {
561
- const a = api();
562
- if (!a) return;
563
- const fcView = FC_VIEW[effective];
564
- if (a.view.type !== fcView) {
565
- a.changeView(fcView, date);
566
- return;
567
- }
568
- if (chunkBIXHB4LV_cjs.utcToDate(a.getDate(), zone) !== date) a.gotoDate(date);
569
- }, [api, effective, date, zone]);
570
- const fcEvents = react.useMemo(() => events.map((e) => toEventInput(e, zone)), [events, zone]);
571
- const changeView = react.useCallback(
572
- (v) => {
573
- const a = api();
574
- if (a) a.changeView(FC_VIEW[effectiveCalendarView(v, narrow)]);
575
- cb.current.onViewChange?.(v);
576
- },
577
- [api, narrow]
578
- );
579
- const nav = react.useCallback(
580
- (dir) => {
581
- const a = api();
582
- if (!a) return;
583
- if (dir === "prev") a.prev();
584
- else if (dir === "next") a.next();
585
- else a.gotoDate(chunkBIXHB4LV_cjs.utcToDate(Date.now(), zone));
586
- },
587
- [api, zone]
588
- );
589
- react.useEffect(() => {
590
- if (!keyboardShortcuts) return;
591
- const onKey = (e) => {
592
- if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey || isTypingTarget(e.target))
593
- return;
594
- if (typeof document !== "undefined" && document.querySelector('[role="dialog"], [role="alertdialog"]'))
595
- return;
596
- const viewKey = {
597
- d: "day",
598
- w: "week",
599
- x: "work_week",
600
- m: "month",
601
- a: "agenda",
602
- y: "year"
603
- };
604
- const k = e.key.length === 1 ? e.key.toLowerCase() : e.key;
605
- if (k === "t") nav("today");
606
- else if (k === "j" || k === "n" || k === "ArrowRight") nav("next");
607
- else if (k === "k" || k === "p" || k === "ArrowLeft") nav("prev");
608
- else if (viewKey[k]) changeView(viewKey[k]);
609
- else if (k === "c" && cb.current.onCreateShortcut) cb.current.onCreateShortcut();
610
- else return;
611
- e.preventDefault();
612
- };
613
- window.addEventListener("keydown", onKey);
614
- return () => window.removeEventListener("keydown", onKey);
615
- }, [keyboardShortcuts, nav, changeView]);
616
- const onDatesSet = react.useCallback(
617
- (arg) => {
618
- setTitle(arg.view.title);
619
- const anchor = chunkBIXHB4LV_cjs.utcToDate(arg.view.calendar.getDate(), zone);
620
- const kind = VIEW_OF_FC[arg.view.type] ?? effective;
621
- const key = `${kind}|${arg.start.toISOString()}|${arg.end.toISOString()}|${anchor}`;
622
- if (key === lastRange.current) return;
623
- lastRange.current = key;
624
- cb.current.onRangeChange({ start: arg.start, end: arg.end, view: kind, date: anchor });
625
- if (anchor !== date) cb.current.onDateChange?.(anchor);
626
- },
627
- [zone, effective, date]
628
- );
629
- const onSelect = react.useCallback(
630
- (arg) => {
631
- if (!cb.current.onSelectSlot) return;
632
- if (arg.allDay) {
633
- cb.current.onSelectSlot({
634
- startUtc: arg.start.toISOString(),
635
- endUtc: arg.end.toISOString(),
636
- allDay: true,
637
- startDate: arg.startStr.slice(0, 10),
638
- endDate: arg.endStr.slice(0, 10)
639
- });
640
- } else {
641
- cb.current.onSelectSlot({
642
- startUtc: arg.start.toISOString(),
643
- endUtc: arg.end.toISOString(),
644
- allDay: false
645
- });
646
- }
647
- api()?.unselect();
648
- },
649
- [api]
650
- );
651
- const emitChange = react.useCallback((event, revert) => {
652
- const g = event.extendedProps.grid;
653
- if (!g || !cb.current.onEventChange || !event.start) {
654
- revert();
655
- return;
656
- }
657
- const start = event.start;
658
- if (event.allDay) {
659
- const startDate = event.startStr.slice(0, 10);
660
- const endDate = event.endStr ? event.endStr.slice(0, 10) : chunkBIXHB4LV_cjs.addDays(startDate, 1);
661
- const end2 = event.end ?? new Date(start.getTime() + 864e5);
662
- cb.current.onEventChange({
663
- instanceId: g.instanceId,
664
- eventId: g.eventId,
665
- startUtc: start.toISOString(),
666
- endUtc: end2.toISOString(),
667
- allDay: true,
668
- startDate,
669
- endDate,
670
- revert
671
- });
672
- return;
673
- }
674
- const end = event.end ?? new Date(start.getTime() + 36e5);
675
- cb.current.onEventChange({
676
- instanceId: g.instanceId,
677
- eventId: g.eventId,
678
- startUtc: start.toISOString(),
679
- endUtc: end.toISOString(),
680
- allDay: false,
681
- revert
682
- });
683
- }, []);
684
- const slotLabelContent = react.useCallback(
685
- (arg) => {
686
- if (!secondZone) return arg.text;
687
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "arbi-cal-slot-labels", children: [
688
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-slot-secondary", children: (() => {
689
- const t = chunkBIXHB4LV_cjs.convertWall(`${date}T${chunkBIXHB4LV_cjs.utcToTime(arg.date, zone)}`, zone, secondZone).slice(
690
- 11,
691
- 16
692
- );
693
- return t.endsWith(":00") ? t.slice(0, 2) : t;
694
- })() }),
695
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-slot-primary", children: arg.text })
696
- ] });
697
- },
698
- [secondZone, zone, date]
699
- );
700
- const allDayContent = react.useCallback(
701
- (arg) => {
702
- if (!secondZone) return arg.text;
703
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "arbi-cal-slot-labels arbi-cal-zone-labels", children: [
704
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-slot-secondary", title: secondZone, children: chunkBIXHB4LV_cjs.zoneOffsetLabel(secondZone) }),
705
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-slot-primary", title: zone, children: chunkBIXHB4LV_cjs.zoneOffsetLabel(zone) })
706
- ] });
707
- },
708
- [secondZone, zone]
709
- );
710
- const dayHeaderContent = react.useCallback(
711
- (arg) => {
712
- const t = arg.view.type;
713
- if (!t.startsWith("timeGrid") && t !== "arbiWorkWeek") return arg.text;
714
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("arbi-cal-dayhead", arg.isToday && "arbi-cal-dayhead-today"), children: [
715
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-dayhead-dow", children: chunkBIXHB4LV_cjs.formatInZone(arg.date, zone, { weekday: "short" }) }),
716
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "arbi-cal-dayhead-num", children: chunkBIXHB4LV_cjs.formatInZone(arg.date, zone, { day: "numeric" }) })
717
- ] });
718
- },
719
- [zone]
720
- );
721
- const scrollTime = react.useMemo(() => {
722
- const starts = (workingHours ?? []).map((h2) => h2.start).sort();
723
- const first = starts[0] ?? "08:00";
724
- const h = Math.max(0, Number(first.slice(0, 2)) - 1);
725
- return `${String(h).padStart(2, "0")}:00:00`;
726
- }, [workingHours]);
727
- const views = react.useMemo(
728
- () => ({
729
- arbiWorkWeek: {
730
- type: "timeGrid",
731
- duration: { weeks: 1 },
732
- hiddenDays: workWeekHiddenDays(workingHours),
733
- buttonText: labels.workWeek
734
- },
735
- arbiAgenda: {
736
- type: "list",
737
- duration: { days: 14 },
738
- dateAlignment: "day",
739
- buttonText: labels.agenda
740
- },
741
- multiMonthYear: { multiMonthMaxColumns: narrow ? 1 : 3 },
742
- // Growing rows (height auto) never overflow, so cap explicitly there; else fit the cell.
743
- dayGridMonth: { dayMaxEvents: height === "auto" ? 3 : true }
744
- }),
745
- [workingHours, labels, narrow, height]
746
- );
747
- const plugins = react.useMemo(
748
- () => [
749
- dayGridPlugin__default.default,
750
- timeGridPlugin__default.default,
751
- listPlugin__default.default,
752
- interactionPlugin__default.default,
753
- multiMonthPlugin__default.default,
754
- getTemporalTimeZonePlugin()
755
- ],
756
- []
757
- );
758
- const viewChoices = narrow ? NARROW_VIEWS : VIEW_ORDER;
759
- return /* @__PURE__ */ jsxRuntime.jsxs(
760
- "div",
761
- {
762
- ref: rootRef,
763
- className: ui.cn(
764
- "arbi-calendar flex h-full min-h-0 flex-col",
765
- narrow && "arbi-calendar-narrow",
766
- secondZone && "arbi-cal-dual",
767
- className
768
- ),
769
- "data-testid": "calendar-grid",
770
- "data-view": effective,
771
- "data-time-zone": zone,
772
- children: [
773
- !hideToolbar && /* @__PURE__ */ jsxRuntime.jsxs(
774
- "div",
775
- {
776
- className: "arbi-cal-toolbar flex flex-wrap items-center gap-2 px-1 pb-2",
777
- "data-testid": "calendar-toolbar",
778
- children: [
779
- /* @__PURE__ */ jsxRuntime.jsx(
780
- ui.Button,
781
- {
782
- type: "button",
783
- variant: "outline",
784
- size: "sm",
785
- onClick: () => nav("today"),
786
- "data-testid": "calendar-today",
787
- children: labels.today
788
- }
789
- ),
790
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
791
- /* @__PURE__ */ jsxRuntime.jsx(
792
- ui.Button,
793
- {
794
- type: "button",
795
- variant: "ghost",
796
- size: "icon",
797
- className: "h-8 w-8",
798
- "aria-label": labels.previous,
799
- onClick: () => nav("prev"),
800
- "data-testid": "calendar-prev",
801
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
802
- }
803
- ),
804
- /* @__PURE__ */ jsxRuntime.jsx(
805
- ui.Button,
806
- {
807
- type: "button",
808
- variant: "ghost",
809
- size: "icon",
810
- className: "h-8 w-8",
811
- "aria-label": labels.next,
812
- onClick: () => nav("next"),
813
- "data-testid": "calendar-next",
814
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
815
- }
816
- )
817
- ] }),
818
- /* @__PURE__ */ jsxRuntime.jsx(
819
- "h2",
820
- {
821
- className: "min-w-0 flex-1 truncate text-base font-semibold sm:text-lg",
822
- "data-testid": "calendar-title",
823
- "aria-live": "polite",
824
- children: title
825
- }
826
- ),
827
- secondZone && !narrow && /* @__PURE__ */ jsxRuntime.jsxs(
828
- "span",
829
- {
830
- className: "hidden text-xs text-muted-foreground md:inline",
831
- "data-testid": "calendar-zones",
832
- children: [
833
- chunkBIXHB4LV_cjs.zoneCity(zone),
834
- " ",
835
- chunkBIXHB4LV_cjs.zoneOffsetLabel(zone),
836
- " \xB7 ",
837
- chunkBIXHB4LV_cjs.zoneCity(secondZone),
838
- " ",
839
- chunkBIXHB4LV_cjs.zoneOffsetLabel(secondZone)
840
- ]
841
- }
842
- ),
843
- narrow ? /* @__PURE__ */ jsxRuntime.jsx(
844
- NativeSelect,
845
- {
846
- "aria-label": labels.view,
847
- value: effective,
848
- onChange: (e) => changeView(e.target.value),
849
- "data-testid": "calendar-view-select",
850
- className: "h-8",
851
- children: viewChoices.map((v) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: v, children: viewLabel(v, labels) }, v))
852
- }
853
- ) : /* @__PURE__ */ jsxRuntime.jsx(
854
- "div",
855
- {
856
- className: "inline-flex rounded-md border border-border p-0.5",
857
- role: "group",
858
- "data-testid": "calendar-view-switch",
859
- children: viewChoices.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
860
- "button",
861
- {
862
- type: "button",
863
- "aria-pressed": effective === v,
864
- onClick: () => changeView(v),
865
- "data-testid": `calendar-view-${v}`,
866
- className: ui.cn(
867
- "rounded px-2.5 py-1 text-xs font-medium transition-colors",
868
- effective === v ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
869
- ),
870
- children: viewLabel(v, labels)
871
- },
872
- v
873
- ))
874
- }
875
- ),
876
- toolbarEnd
877
- ]
878
- }
879
- ),
880
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "arbi-cal-body min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
881
- FullCalendar__default.default,
882
- {
883
- ref: calRef,
884
- plugins,
885
- timeZone: zone,
886
- initialView: FC_VIEW[effective],
887
- initialDate: date,
888
- headerToolbar: false,
889
- height: height ?? "100%",
890
- views,
891
- events: fcEvents,
892
- firstDay: weekStart,
893
- weekNumbers: showWeekNumbers,
894
- weekNumberCalculation: weekStart === 1 ? "ISO" : "local",
895
- weekText: labels.weekAbbrev,
896
- nowIndicator,
897
- businessHours: toBusinessHours(workingHours),
898
- scrollTime,
899
- slotDuration: "00:30:00",
900
- snapDuration: "00:15:00",
901
- slotLabelFormat: {
902
- hour: "numeric",
903
- minute: "2-digit",
904
- omitZeroMinute: true,
905
- meridiem: "short"
906
- },
907
- eventTimeFormat: {
908
- hour: "numeric",
909
- minute: "2-digit",
910
- omitZeroMinute: true,
911
- meridiem: "short"
912
- },
913
- allDayText: labels.allDay,
914
- noEventsText: labels.noEvents,
915
- moreLinkText: labels.more,
916
- navLinks: true,
917
- navLinkDayClick: (d) => {
918
- const a = api();
919
- a?.changeView(FC_VIEW.day, d);
920
- cb.current.onViewChange?.("day");
921
- },
922
- selectable: !!onSelectSlot,
923
- selectMirror: true,
924
- unselectAuto: true,
925
- editable: !!onEventChange,
926
- eventResizableFromStart: true,
927
- eventStartEditable: !!onEventChange,
928
- eventDurationEditable: !!onEventChange,
929
- stickyHeaderDates: true,
930
- expandRows: true,
931
- dayMaxEvents: height === "auto" ? 3 : true,
932
- eventDisplay: "auto",
933
- datesSet: onDatesSet,
934
- select: onSelect,
935
- eventClick: (arg) => {
936
- arg.jsEvent.preventDefault();
937
- const g = arg.event.extendedProps.grid;
938
- if (g) cb.current.onEventClick?.(g.instanceId, g.eventId);
939
- },
940
- eventDrop: (arg) => emitChange(arg.event, arg.revert),
941
- eventResize: (arg) => emitChange(arg.event, arg.revert),
942
- eventContent: (arg) => /* @__PURE__ */ jsxRuntime.jsx(EventBody, { arg, labels }),
943
- slotLabelContent,
944
- allDayContent,
945
- dayHeaderContent
946
- }
947
- ) })
948
- ]
949
- }
950
- );
951
- }
952
- function MiniMonth({
953
- date,
954
- weekStart,
955
- timeZone,
956
- onSelect,
957
- highlightRange,
958
- showWeekNumbers,
959
- labels: labelOverrides,
960
- className
961
- }) {
962
- const labels = mergeLabels(labelOverrides);
963
- const [view, setView] = react.useState(() => ({ for: date, month: `${date.slice(0, 7)}-01` }));
964
- if (view.for !== date) setView({ for: date, month: `${date.slice(0, 7)}-01` });
965
- const month = view.for === date ? view.month : `${date.slice(0, 7)}-01`;
966
- const setMonth = (m) => setView({ for: date, month: m });
967
- const today = chunkBIXHB4LV_cjs.todayInZone(timeZone);
968
- const days = react.useMemo(() => {
969
- const first = chunkBIXHB4LV_cjs.startOfWeek(month, weekStart);
970
- return Array.from({ length: 42 }, (_, i) => chunkBIXHB4LV_cjs.addDays(first, i));
971
- }, [month, weekStart]);
972
- const weekdays = days.slice(0, 7).map((d) => chunkBIXHB4LV_cjs.formatPlainDate(d, { weekday: "narrow" }));
973
- const monthTitle = chunkBIXHB4LV_cjs.formatPlainDate(month, { month: "long", year: "numeric" });
974
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("select-none text-xs", className), "data-testid": "calendar-mini-month", children: [
975
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex items-center justify-between px-1", children: [
976
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", "aria-live": "polite", children: monthTitle }),
977
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
978
- /* @__PURE__ */ jsxRuntime.jsx(
979
- "button",
980
- {
981
- type: "button",
982
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
983
- "aria-label": labels.previous,
984
- onClick: () => setMonth(chunkBIXHB4LV_cjs.addMonths(month, -1)),
985
- "data-testid": "calendar-mini-prev",
986
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
987
- }
988
- ),
989
- /* @__PURE__ */ jsxRuntime.jsx(
990
- "button",
991
- {
992
- type: "button",
993
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
994
- "aria-label": labels.next,
995
- onClick: () => setMonth(chunkBIXHB4LV_cjs.addMonths(month, 1)),
996
- "data-testid": "calendar-mini-next",
997
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
998
- }
999
- )
1000
- ] })
1001
- ] }),
1002
- /* @__PURE__ */ jsxRuntime.jsxs(
1003
- "div",
1004
- {
1005
- className: ui.cn(
1006
- "grid gap-y-0.5 text-center",
1007
- showWeekNumbers ? "grid-cols-8" : "grid-cols-7"
1008
- ),
1009
- role: "grid",
1010
- "aria-label": monthTitle,
1011
- children: [
1012
- showWeekNumbers && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "py-1 text-[10px] text-muted-foreground", children: labels.weekAbbrev }),
1013
- weekdays.map((w, i) => /* @__PURE__ */ jsxRuntime.jsx(
1014
- "span",
1015
- {
1016
- className: "py-1 text-[10px] font-medium uppercase text-muted-foreground",
1017
- role: "columnheader",
1018
- children: w
1019
- },
1020
- i
1021
- )),
1022
- days.map((d, i) => {
1023
- const inMonth = d.slice(0, 7) === month.slice(0, 7);
1024
- const inRange = !!highlightRange && d >= highlightRange.start && d <= highlightRange.end;
1025
- const selected = d === date;
1026
- const isToday = d === today;
1027
- return /* @__PURE__ */ jsxRuntime.jsx(
1028
- MiniDay,
1029
- {
1030
- d,
1031
- weekCell: showWeekNumbers && i % 7 === 0 ? chunkBIXHB4LV_cjs.isoWeekNumber(d) : null,
1032
- inMonth,
1033
- inRange,
1034
- selected,
1035
- isToday,
1036
- onSelect
1037
- },
1038
- d
1039
- );
1040
- })
1041
- ]
1042
- }
1043
- )
1044
- ] });
1045
- }
1046
- function MiniDay({
1047
- d,
1048
- weekCell,
1049
- inMonth,
1050
- inRange,
1051
- selected,
1052
- isToday,
1053
- onSelect
1054
- }) {
1055
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1056
- weekCell !== null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center text-[10px] text-muted-foreground", children: weekCell }),
1057
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("flex items-center justify-center", inRange && "bg-primary/10"), children: /* @__PURE__ */ jsxRuntime.jsx(
1058
- "button",
1059
- {
1060
- type: "button",
1061
- role: "gridcell",
1062
- "aria-selected": selected,
1063
- "aria-current": isToday ? "date" : void 0,
1064
- "aria-label": chunkBIXHB4LV_cjs.formatPlainDate(d, { dateStyle: "full" }),
1065
- onClick: () => onSelect(d),
1066
- "data-testid": `calendar-mini-day-${d}`,
1067
- className: ui.cn(
1068
- "flex h-7 w-7 items-center justify-center rounded-full tabular-nums transition-colors",
1069
- !inMonth && "text-muted-foreground/60",
1070
- isToday && !selected && "font-semibold text-primary",
1071
- selected ? "bg-primary text-primary-foreground" : "hover:bg-muted"
1072
- ),
1073
- children: Number(d.slice(8, 10))
1074
- }
1075
- ) })
1076
- ] });
1077
- }
1078
- var GROUPS = ["mine", "shared", "workspace", "subscribed", "rooms"];
1079
- var groupLabel = (g, l) => ({
1080
- mine: l.myCalendars,
1081
- shared: l.sharedCalendars,
1082
- workspace: l.workspaceCalendars,
1083
- subscribed: l.subscribedCalendars,
1084
- rooms: l.rooms
1085
- })[g];
1086
- function Swatch({ color, checked }) {
1087
- return /* @__PURE__ */ jsxRuntime.jsx(
1088
- "span",
1089
- {
1090
- className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-[4px] border-2",
1091
- style: { borderColor: color, backgroundColor: checked ? color : "transparent" },
1092
- "aria-hidden": true,
1093
- children: checked && /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", className: "h-3 w-3", fill: "none", stroke: "white", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2.5 6.5l2.5 2.5 4.5-5" }) })
1094
- }
1095
- );
1096
- }
1097
- function CalendarList({
1098
- calendars,
1099
- overlays,
1100
- onToggleHidden,
1101
- onColorChange,
1102
- onToggleOverlay,
1103
- onCreate,
1104
- onEdit,
1105
- onImport,
1106
- onExport,
1107
- onDelete,
1108
- onShare,
1109
- onRefresh,
1110
- onPublish,
1111
- onSubscribe,
1112
- onAddHolidays,
1113
- onImportFile,
1114
- labels: labelOverrides,
1115
- className
1116
- }) {
1117
- const l = mergeLabels(labelOverrides);
1118
- const hasAddMenu = !!(onSubscribe || onAddHolidays || onImportFile);
1119
- const plusButton = /* @__PURE__ */ jsxRuntime.jsx(
1120
- "button",
1121
- {
1122
- type: "button",
1123
- className: "rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
1124
- "aria-label": hasAddMenu ? l.addCalendar : l.createCalendar,
1125
- title: hasAddMenu ? l.addCalendar : l.createCalendar,
1126
- onClick: hasAddMenu ? void 0 : onCreate,
1127
- "data-testid": "calendar-list-create",
1128
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" })
1129
- }
1130
- );
1131
- const overlayRows = [
1132
- ["facts", l.facts, lucideReact.Lightbulb],
1133
- ["workflows", l.workflows, lucideReact.Workflow],
1134
- ["tasks", l.tasks, lucideReact.ListTodo]
1135
- ];
1136
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-3 text-sm", className), "data-testid": "calendar-list", children: [
1137
- GROUPS.map((g) => {
1138
- const items = calendars.filter((c) => c.group === g);
1139
- if (!items.length && g !== "mine") return null;
1140
- return /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": groupLabel(g, l), children: [
1141
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-1 pb-1", children: [
1142
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: groupLabel(g, l) }),
1143
- g === "mine" && (hasAddMenu ? /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
1144
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: plusButton }),
1145
- /* @__PURE__ */ jsxRuntime.jsxs(
1146
- ui.DropdownMenuContent,
1147
- {
1148
- align: "end",
1149
- className: "w-56",
1150
- "data-testid": "calendar-add-menu",
1151
- children: [
1152
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: onCreate, "data-testid": "calendar-add-new", children: l.createCalendar }),
1153
- onSubscribe && /* @__PURE__ */ jsxRuntime.jsx(
1154
- ui.DropdownMenuItem,
1155
- {
1156
- onSelect: onSubscribe,
1157
- "data-testid": "calendar-add-subscribe",
1158
- children: l.subscribeFromUrl
1159
- }
1160
- ),
1161
- onAddHolidays && /* @__PURE__ */ jsxRuntime.jsx(
1162
- ui.DropdownMenuItem,
1163
- {
1164
- onSelect: onAddHolidays,
1165
- "data-testid": "calendar-add-holidays",
1166
- children: l.addHolidays
1167
- }
1168
- ),
1169
- onImportFile && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: onImportFile, "data-testid": "calendar-add-import", children: l.importIcs })
1170
- ]
1171
- }
1172
- )
1173
- ] }) : plusButton)
1174
- ] }),
1175
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: items.map((c) => {
1176
- const name = c.locked ? l.locked : c.name || l.noTitle;
1177
- const isOwner = c.role === "owner";
1178
- return /* @__PURE__ */ jsxRuntime.jsxs(
1179
- "li",
1180
- {
1181
- className: "group flex items-center gap-2 rounded-md px-1 py-1 hover:bg-muted/60",
1182
- "data-testid": `calendar-list-item-${c.id}`,
1183
- children: [
1184
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2", children: [
1185
- /* @__PURE__ */ jsxRuntime.jsx(
1186
- "input",
1187
- {
1188
- type: "checkbox",
1189
- className: "sr-only",
1190
- checked: !c.hidden,
1191
- onChange: () => onToggleHidden(c.id),
1192
- "aria-label": `${c.hidden ? l.showCalendar : l.hideCalendar} ${name}`,
1193
- "data-testid": `calendar-list-toggle-${c.id}`
1194
- }
1195
- ),
1196
- /* @__PURE__ */ jsxRuntime.jsx(Swatch, { color: c.color, checked: !c.hidden }),
1197
- /* @__PURE__ */ jsxRuntime.jsx(
1198
- "span",
1199
- {
1200
- className: ui.cn(
1201
- "min-w-0 truncate",
1202
- c.locked && "italic text-muted-foreground"
1203
- ),
1204
- children: name
1205
- }
1206
- ),
1207
- c.locked && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "h-3 w-3 shrink-0 text-muted-foreground", "aria-hidden": true }),
1208
- c.provider && c.provider !== "native" && /* @__PURE__ */ jsxRuntime.jsx(
1209
- "span",
1210
- {
1211
- className: "shrink-0 rounded border border-border px-1 text-[10px] leading-4 text-muted-foreground",
1212
- "data-testid": `calendar-list-provider-${c.id}`,
1213
- children: {
1214
- google: "Google",
1215
- microsoft: "Outlook",
1216
- caldav: "CalDAV",
1217
- ics: "ICS"
1218
- }[c.provider] ?? c.provider
1219
- }
1220
- )
1221
- ] }),
1222
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
1223
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1224
- "button",
1225
- {
1226
- type: "button",
1227
- className: "rounded p-0.5 text-muted-foreground opacity-60 hover:bg-muted hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100",
1228
- "aria-label": `${l.editCalendar}: ${name}`,
1229
- "data-testid": `calendar-list-menu-${c.id}`,
1230
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EllipsisVertical, { className: "h-4 w-4" })
1231
- }
1232
- ) }),
1233
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", className: "w-56", children: [
1234
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuLabel, { className: "text-xs", children: l.calendarColor }),
1235
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
1236
- ColorSwatches,
1237
- {
1238
- value: c.color,
1239
- onChange: (color) => color && onColorChange(c.id, color)
1240
- }
1241
- ) }),
1242
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
1243
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: () => onEdit(c.id), disabled: c.locked, children: l.editCalendar }),
1244
- onShare && isOwner && c.group !== "subscribed" && /* @__PURE__ */ jsxRuntime.jsx(
1245
- ui.DropdownMenuItem,
1246
- {
1247
- onSelect: () => onShare(c.id),
1248
- disabled: c.locked,
1249
- "data-testid": `calendar-list-share-${c.id}`,
1250
- children: l.shareCalendar
1251
- }
1252
- ),
1253
- onPublish && isOwner && c.group === "mine" && (!c.provider || c.provider === "native") && /* @__PURE__ */ jsxRuntime.jsx(
1254
- ui.DropdownMenuItem,
1255
- {
1256
- onSelect: () => onPublish(c.id),
1257
- disabled: c.locked,
1258
- "data-testid": `calendar-list-publish-${c.id}`,
1259
- children: l.publishTo
1260
- }
1261
- ),
1262
- onRefresh && c.group === "subscribed" && /* @__PURE__ */ jsxRuntime.jsx(
1263
- ui.DropdownMenuItem,
1264
- {
1265
- onSelect: () => onRefresh(c.id),
1266
- "data-testid": `calendar-list-refresh-${c.id}`,
1267
- children: l.refreshCalendar
1268
- }
1269
- ),
1270
- c.canWrite && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: () => onImport(c.id), disabled: c.locked, children: l.importCalendar }),
1271
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: () => onExport(c.id), disabled: c.locked, children: l.exportCalendar }),
1272
- isOwner && !c.isDefault && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1273
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
1274
- /* @__PURE__ */ jsxRuntime.jsx(
1275
- ui.DropdownMenuItem,
1276
- {
1277
- className: "text-destructive focus:text-destructive",
1278
- onSelect: () => onDelete(c.id),
1279
- children: l.deleteCalendar
1280
- }
1281
- )
1282
- ] })
1283
- ] })
1284
- ] })
1285
- ]
1286
- },
1287
- c.id
1288
- );
1289
- }) })
1290
- ] }, g);
1291
- }),
1292
- /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": l.overlays, children: [
1293
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "px-1 pb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: l.overlays }),
1294
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: overlayRows.map(([layer, label, Icon]) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex cursor-pointer items-center gap-2 rounded-md px-1 py-1 hover:bg-muted/60", children: [
1295
- /* @__PURE__ */ jsxRuntime.jsx(
1296
- "input",
1297
- {
1298
- type: "checkbox",
1299
- className: "h-4 w-4 accent-[hsl(var(--primary))]",
1300
- checked: overlays[layer],
1301
- onChange: () => onToggleOverlay(layer),
1302
- "data-testid": `calendar-overlay-${layer}`
1303
- }
1304
- ),
1305
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5 text-muted-foreground", "aria-hidden": true }),
1306
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
1307
- ] }) }, layer)) })
1308
- ] })
1309
- ] });
1310
- }
1311
-
1312
- // src/calendar/draft.ts
1313
- var isAllDayDraft = (d) => !!d.start.date;
1314
- var datePart = (spec) => spec.date ?? (spec.date_time ?? "").slice(0, 10);
1315
- var timePart = (spec) => (spec.date_time ?? "").slice(11, 16);
1316
- var specZone = (spec, defaultZone) => chunkBIXHB4LV_cjs.safeZone(spec.time_zone, defaultZone);
1317
- var specDate = datePart;
1318
- var specTime = timePart;
1319
- function specEpochMs(spec, defaultZone) {
1320
- if (spec.date) return chunkBIXHB4LV_cjs.wallToEpochMs(spec.date, defaultZone);
1321
- return chunkBIXHB4LV_cjs.wallToEpochMs(spec.date_time ?? "", specZone(spec, defaultZone));
1322
- }
1323
- function draftRangeUtc(d, defaultZone) {
1324
- return { startMs: specEpochMs(d.start, defaultZone), endMs: specEpochMs(d.end, defaultZone) };
1325
- }
1326
- function allDayInclusiveEnd(d) {
1327
- const start = d.start.date ?? "";
1328
- const end = d.end.date ?? start;
1329
- const last = chunkBIXHB4LV_cjs.addDays(end, -1);
1330
- return last < start ? start : last;
1331
- }
1332
- function timedSpec(date, time, zone) {
1333
- return { date: null, date_time: `${date}T${time || "00:00"}`, time_zone: zone ?? null };
1334
- }
1335
- function setDraftStart(d, change, defaultZone) {
1336
- if (isAllDayDraft(d)) {
1337
- const oldStart = d.start.date ?? change.date ?? "";
1338
- const start2 = change.date ?? oldStart;
1339
- const days = Math.max(1, chunkBIXHB4LV_cjs.diffDays(oldStart, d.end.date ?? chunkBIXHB4LV_cjs.addDays(oldStart, 1)));
1340
- return { ...d, start: { date: start2 }, end: { date: chunkBIXHB4LV_cjs.addDays(start2, days) } };
1341
- }
1342
- const { startMs, endMs } = draftRangeUtc(d, defaultZone);
1343
- const duration = Math.max(0, endMs - startMs);
1344
- const startZone = change.timeZone !== void 0 ? change.timeZone : d.start.time_zone ?? null;
1345
- const start = timedSpec(
1346
- change.date ?? datePart(d.start),
1347
- change.time ?? timePart(d.start),
1348
- startZone
1349
- );
1350
- const newStartMs = specEpochMs(start, defaultZone);
1351
- const endZone = specZone(d.end, defaultZone);
1352
- const endWall = chunkBIXHB4LV_cjs.utcToWall(newStartMs + duration, endZone);
1353
- return {
1354
- ...d,
1355
- start,
1356
- end: { date: null, date_time: endWall, time_zone: d.end.time_zone ?? null }
1357
- };
1358
- }
1359
- function setDraftEnd(d, change) {
1360
- if (isAllDayDraft(d)) {
1361
- const last = change.date ?? allDayInclusiveEnd(d);
1362
- return { ...d, end: { date: chunkBIXHB4LV_cjs.addDays(last, 1) } };
1363
- }
1364
- const zone = change.timeZone !== void 0 ? change.timeZone : d.end.time_zone ?? null;
1365
- return {
1366
- ...d,
1367
- end: timedSpec(change.date ?? datePart(d.end), change.time ?? timePart(d.end), zone)
1368
- };
1369
- }
1370
- function setDraftAllDay(d, allDay, defaultZone, defaultStartTime = "09:00", defaultDurationMinutes = 60) {
1371
- if (allDay === isAllDayDraft(d)) return d;
1372
- if (allDay) {
1373
- const start2 = datePart(d.start);
1374
- const endDay = datePart(d.end) || start2;
1375
- const lastDay = timePart(d.end) === "00:00" && endDay > start2 ? chunkBIXHB4LV_cjs.addDays(endDay, -1) : endDay;
1376
- return {
1377
- ...d,
1378
- start: { date: start2 },
1379
- end: { date: chunkBIXHB4LV_cjs.addDays(lastDay < start2 ? start2 : lastDay, 1) }
1380
- };
1381
- }
1382
- const zone = chunkBIXHB4LV_cjs.safeZone(defaultZone);
1383
- const start = timedSpec(d.start.date ?? "", defaultStartTime, zone);
1384
- const startMs = specEpochMs(start, zone);
1385
- const end = {
1386
- date: null,
1387
- date_time: chunkBIXHB4LV_cjs.utcToWall(startMs + defaultDurationMinutes * 6e4, zone),
1388
- time_zone: zone
1389
- };
1390
- return { ...d, start, end };
1391
- }
1392
- function draftFromSlot(slot, timeZone, calendarId, title = "") {
1393
- const zone = chunkBIXHB4LV_cjs.safeZone(timeZone);
1394
- if (slot.allDay) {
1395
- const start = slot.startDate ?? chunkBIXHB4LV_cjs.utcToDate(slot.startUtc, zone);
1396
- const end = slot.endDate ?? chunkBIXHB4LV_cjs.addDays(start, 1);
1397
- return { calendar_id: calendarId, title, start: { date: start }, end: { date: end } };
1398
- }
1399
- return {
1400
- calendar_id: calendarId,
1401
- title,
1402
- start: { date: null, date_time: chunkBIXHB4LV_cjs.utcToWall(slot.startUtc, zone), time_zone: zone },
1403
- end: { date: null, date_time: chunkBIXHB4LV_cjs.utcToWall(slot.endUtc, zone), time_zone: zone }
1404
- };
1405
- }
1406
- function validateDraft(d, defaultZone) {
1407
- if (!d.title.trim()) return "titleRequired";
1408
- if (isAllDayDraft(d)) {
1409
- if (!d.start.date || !d.end.date || d.end.date <= d.start.date) return "invalidRange";
1410
- return null;
1411
- }
1412
- if (!d.start.date_time || !d.end.date_time) return "invalidRange";
1413
- const { startMs, endMs } = draftRangeUtc(d, defaultZone);
1414
- if (!(endMs >= startMs)) return "invalidRange";
1415
- return null;
1416
- }
1417
- var ARBI_WEBINAR_LABEL = "ARBI webinar";
1418
- var isWebinarConference = (c) => c?.type === "arbi" && (c.kind === "webinar" || c.label === ARBI_WEBINAR_LABEL);
1419
- var attendeeKey = (a) => a.email?.toLowerCase() || a.user_id || "";
1420
- var RRULE_WEEKDAYS = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
1421
- function weekdayOf(date) {
1422
- return RRULE_WEEKDAYS[temporalPolyfill.Temporal.PlainDate.from(date).dayOfWeek - 1];
1423
- }
1424
- function setPosOf(date, preferLast = false) {
1425
- const d = temporalPolyfill.Temporal.PlainDate.from(date);
1426
- const isLast = d.day + 7 > d.daysInMonth;
1427
- const nth = Math.ceil(d.day / 7);
1428
- if (isLast && (preferLast || nth > 4)) return -1;
1429
- return Math.min(nth, 4);
1430
- }
1431
- function defaultRecurrenceForm(startDate, freq = "none") {
1432
- const d = temporalPolyfill.Temporal.PlainDate.from(startDate);
1433
- return {
1434
- freq,
1435
- interval: 1,
1436
- weekdays: [weekdayOf(startDate)],
1437
- monthlyMode: "day",
1438
- monthDay: d.day,
1439
- setPos: setPosOf(startDate),
1440
- setPosDay: weekdayOf(startDate),
1441
- month: d.month,
1442
- end: "never",
1443
- until: null,
1444
- count: 10,
1445
- raw: ""
1446
- };
1447
- }
1448
- function untilValue(until, ctx) {
1449
- if (ctx.allDay) return until.replace(/-/g, "");
1450
- const zone = ctx.timeZone || "UTC";
1451
- const utc = chunkBIXHB4LV_cjs.wallToUtc(`${until}T23:59:59`, zone);
1452
- const t = temporalPolyfill.Temporal.Instant.from(utc).toZonedDateTimeISO("UTC");
1453
- const p = (n, w = 2) => String(n).padStart(w, "0");
1454
- return `${p(t.year, 4)}${p(t.month)}${p(t.day)}T${p(t.hour)}${p(t.minute)}${p(t.second)}Z`;
1455
- }
1456
- function buildRRule(form, ctx = {}) {
1457
- if (form.freq === "none") return null;
1458
- if (form.freq === "custom") {
1459
- const raw = form.raw.trim().replace(/^RRULE:/i, "");
1460
- return raw || null;
1461
- }
1462
- const parts = [`FREQ=${form.freq.toUpperCase()}`];
1463
- const interval = Math.max(1, Math.floor(form.interval || 1));
1464
- if (interval > 1) parts.push(`INTERVAL=${interval}`);
1465
- if (form.freq === "weekly") {
1466
- const days = RRULE_WEEKDAYS.filter((d) => form.weekdays.includes(d));
1467
- if (days.length) parts.push(`BYDAY=${days.join(",")}`);
1468
- } else if (form.freq === "monthly" || form.freq === "yearly") {
1469
- if (form.freq === "yearly") parts.push(`BYMONTH=${form.month}`);
1470
- if (form.monthlyMode === "day") {
1471
- parts.push(`BYMONTHDAY=${form.monthDay}`);
1472
- } else {
1473
- parts.push(`BYDAY=${form.setPosDay}`);
1474
- parts.push(`BYSETPOS=${form.setPos}`);
1475
- }
1476
- }
1477
- if (form.end === "until" && form.until) parts.push(`UNTIL=${untilValue(form.until, ctx)}`);
1478
- else if (form.end === "count") parts.push(`COUNT=${Math.max(1, Math.floor(form.count || 1))}`);
1479
- return parts.join(";");
1480
- }
1481
- function tokenize(rrule) {
1482
- const out = /* @__PURE__ */ new Map();
1483
- for (const seg of rrule.replace(/^RRULE:/i, "").split(";")) {
1484
- const i = seg.indexOf("=");
1485
- if (i > 0)
1486
- out.set(
1487
- seg.slice(0, i).trim().toUpperCase(),
1488
- seg.slice(i + 1).trim().toUpperCase()
1489
- );
1490
- }
1491
- return out;
1492
- }
1493
- function parseUntil(value, ctx) {
1494
- const m = /^(\d{4})(\d{2})(\d{2})(?:T(\d{2})(\d{2})(\d{2})(Z?))?$/.exec(value);
1495
- if (!m) return null;
1496
- const date = `${m[1]}-${m[2]}-${m[3]}`;
1497
- if (!m[4] || m[7] !== "Z") return date;
1498
- const inst = temporalPolyfill.Temporal.Instant.from(`${date}T${m[4]}:${m[5]}:${m[6]}Z`);
1499
- return inst.toZonedDateTimeISO(ctx.timeZone || "UTC").toPlainDate().toString();
1500
- }
1501
- var SUPPORTED = /* @__PURE__ */ new Set([
1502
- "FREQ",
1503
- "INTERVAL",
1504
- "BYDAY",
1505
- "BYMONTHDAY",
1506
- "BYMONTH",
1507
- "BYSETPOS",
1508
- "UNTIL",
1509
- "COUNT",
1510
- "WKST"
1511
- ]);
1512
- function parseRRule(rrule, startDate, ctx = {}) {
1513
- const base = defaultRecurrenceForm(startDate);
1514
- if (!rrule || !rrule.trim()) return base;
1515
- const raw = rrule.trim().replace(/^RRULE:/i, "");
1516
- const custom = { ...base, freq: "custom", raw };
1517
- const t = tokenize(raw);
1518
- for (const key of t.keys()) if (!SUPPORTED.has(key)) return custom;
1519
- const freq = t.get("FREQ");
1520
- const form = { ...base, raw };
1521
- const interval = Number(t.get("INTERVAL") ?? "1");
1522
- if (!Number.isInteger(interval) || interval < 1) return custom;
1523
- form.interval = interval;
1524
- if (t.has("UNTIL") && t.has("COUNT")) return custom;
1525
- if (t.has("UNTIL")) {
1526
- const until = parseUntil(t.get("UNTIL") ?? "", ctx);
1527
- if (!until) return custom;
1528
- form.end = "until";
1529
- form.until = until;
1530
- } else if (t.has("COUNT")) {
1531
- const count = Number(t.get("COUNT"));
1532
- if (!Number.isInteger(count) || count < 1) return custom;
1533
- form.end = "count";
1534
- form.count = count;
1535
- }
1536
- const byday = t.get("BYDAY");
1537
- const bymonthday = t.get("BYMONTHDAY");
1538
- const bymonth = t.get("BYMONTH");
1539
- const bysetpos = t.get("BYSETPOS");
1540
- const nthWeekday = () => {
1541
- if (!byday || bymonthday) return false;
1542
- const m = /^([+-]?\d)?(MO|TU|WE|TH|FR|SA|SU)$/.exec(byday);
1543
- if (!m) return false;
1544
- const pos = Number(m[1] ?? bysetpos ?? NaN);
1545
- if (m[1] && bysetpos) return false;
1546
- if (![1, 2, 3, 4, -1].includes(pos)) return false;
1547
- form.monthlyMode = "weekday";
1548
- form.setPos = pos;
1549
- form.setPosDay = m[2];
1550
- return true;
1551
- };
1552
- const monthDay = () => {
1553
- if (!bymonthday || byday || bysetpos) return false;
1554
- const n = Number(bymonthday);
1555
- if (!Number.isInteger(n) || n < 1 || n > 31) return false;
1556
- form.monthlyMode = "day";
1557
- form.monthDay = n;
1558
- return true;
1559
- };
1560
- switch (freq) {
1561
- case "DAILY":
1562
- if (byday || bymonthday || bymonth || bysetpos) return custom;
1563
- form.freq = "daily";
1564
- return form;
1565
- case "WEEKLY": {
1566
- if (bymonthday || bymonth || bysetpos) return custom;
1567
- form.freq = "weekly";
1568
- if (byday) {
1569
- const days = byday.split(",");
1570
- if (!days.every((d) => RRULE_WEEKDAYS.includes(d))) return custom;
1571
- form.weekdays = days;
1572
- }
1573
- return form;
1574
- }
1575
- case "MONTHLY":
1576
- if (bymonth) return custom;
1577
- form.freq = "monthly";
1578
- if (!byday && !bymonthday && !bysetpos) return form;
1579
- return nthWeekday() || monthDay() ? form : custom;
1580
- case "YEARLY": {
1581
- form.freq = "yearly";
1582
- if (bymonth) {
1583
- const n = Number(bymonth);
1584
- if (!Number.isInteger(n) || n < 1 || n > 12) return custom;
1585
- form.month = n;
1586
- }
1587
- if (!byday && !bymonthday && !bysetpos) return form;
1588
- if (!bymonth) return custom;
1589
- return nthWeekday() || monthDay() ? form : custom;
1590
- }
1591
- default:
1592
- return custom;
1593
- }
1594
- }
1595
- var DEFAULT_RECURRENCE_DESCRIBE_LABELS = {
1596
- every: "Every",
1597
- day: "day",
1598
- days: "days",
1599
- week: "week",
1600
- weeks: "weeks",
1601
- month: "month",
1602
- months: "months",
1603
- year: "year",
1604
- years: "years",
1605
- on: "on",
1606
- onDay: "on day",
1607
- until: "until",
1608
- times: "times",
1609
- ordinals: { 1: "first", 2: "second", 3: "third", 4: "fourth", [-1]: "last" },
1610
- weekdayNames: {
1611
- MO: "Monday",
1612
- TU: "Tuesday",
1613
- WE: "Wednesday",
1614
- TH: "Thursday",
1615
- FR: "Friday",
1616
- SA: "Saturday",
1617
- SU: "Sunday"
1618
- },
1619
- monthNames: [
1620
- "January",
1621
- "February",
1622
- "March",
1623
- "April",
1624
- "May",
1625
- "June",
1626
- "July",
1627
- "August",
1628
- "September",
1629
- "October",
1630
- "November",
1631
- "December"
1632
- ],
1633
- doesNotRepeat: "Does not repeat",
1634
- custom: "Custom rule"
1635
- };
1636
- function describeRecurrence(form, labels = DEFAULT_RECURRENCE_DESCRIBE_LABELS) {
1637
- const l = labels;
1638
- if (form.freq === "none") return l.doesNotRepeat;
1639
- if (form.freq === "custom") return `${l.custom}: ${form.raw}`;
1640
- const unit = {
1641
- daily: [l.day, l.days],
1642
- weekly: [l.week, l.weeks],
1643
- monthly: [l.month, l.months],
1644
- yearly: [l.year, l.years]
1645
- }[form.freq];
1646
- let text = form.interval > 1 ? `${l.every} ${form.interval} ${unit[1]}` : `${l.every} ${unit[0]}`;
1647
- if (form.freq === "weekly" && form.weekdays.length) {
1648
- const days = RRULE_WEEKDAYS.filter((d) => form.weekdays.includes(d)).map(
1649
- (d) => l.weekdayNames[d]
1650
- );
1651
- text += ` ${l.on} ${days.join(", ")}`;
1652
- }
1653
- if (form.freq === "monthly" || form.freq === "yearly") {
1654
- const monthName = form.freq === "yearly" ? ` ${l.monthNames[form.month - 1]}` : "";
1655
- text += form.monthlyMode === "day" ? form.freq === "yearly" ? ` ${l.on}${monthName} ${form.monthDay}` : ` ${l.onDay} ${form.monthDay}` : ` ${l.on} ${l.ordinals[form.setPos]} ${l.weekdayNames[form.setPosDay]}${monthName ? ` of${monthName}` : ""}`;
1656
- }
1657
- if (form.end === "until" && form.until) text += `, ${l.until} ${form.until}`;
1658
- if (form.end === "count") text += `, ${form.count} ${l.times}`;
1659
- return text;
1660
- }
1661
-
1662
- // src/calendar/recurrence-labels.ts
1663
- var DEFAULT_RECURRENCE_EDITOR_LABELS = {
1664
- doesNotRepeat: "Does not repeat",
1665
- daily: "Daily",
1666
- weekly: "Weekly",
1667
- monthly: "Monthly",
1668
- yearly: "Yearly",
1669
- custom: "Custom rule\u2026",
1670
- every: "Every",
1671
- units: { daily: "day(s)", weekly: "week(s)", monthly: "month(s)", yearly: "year(s)" },
1672
- onDayOfMonth: "On day",
1673
- onThe: "On the",
1674
- ends: "Ends",
1675
- never: "Never",
1676
- onDate: "On",
1677
- after: "After",
1678
- occurrences: "occurrences",
1679
- rrule: "iCalendar rule (RRULE)",
1680
- rrulePlaceholder: "FREQ=WEEKLY;BYDAY=MO,WE",
1681
- weekdayShort: { MO: "M", TU: "T", WE: "W", TH: "T", FR: "F", SA: "S", SU: "S" }
1682
- };
1683
- var SETPOS_OPTIONS = [1, 2, 3, 4, -1];
1684
- function RecurrenceEditor({
1685
- rrule,
1686
- onChange,
1687
- startDate,
1688
- allDay,
1689
- timeZone,
1690
- labels: labelOverrides,
1691
- idPrefix = "calendar-recurrence"
1692
- }) {
1693
- const l = { ...DEFAULT_RECURRENCE_EDITOR_LABELS, ...labelOverrides };
1694
- const ctx = { allDay, timeZone };
1695
- const [form, setForm] = react.useState(() => parseRRule(rrule, startDate, ctx));
1696
- const [emitted, setEmitted] = react.useState(rrule || null);
1697
- if ((rrule || null) !== emitted) {
1698
- setEmitted(rrule || null);
1699
- setForm(parseRRule(rrule, startDate, ctx));
1700
- }
1701
- const update = (patch) => {
1702
- const next = { ...form, ...patch };
1703
- setForm(next);
1704
- const out = buildRRule(next, ctx);
1705
- setEmitted(out);
1706
- onChange(out);
1707
- };
1708
- const setFreq = (freq) => {
1709
- if (freq === "custom") {
1710
- update({ freq, raw: buildRRule(form, ctx) ?? form.raw ?? "" });
1711
- return;
1712
- }
1713
- const seeded = { freq };
1714
- if (form.freq === "none" || form.freq === "custom") {
1715
- seeded.weekdays = [weekdayOf(startDate)];
1716
- seeded.monthDay = Number(startDate.slice(8, 10));
1717
- seeded.setPos = setPosOf(startDate);
1718
- seeded.setPosDay = weekdayOf(startDate);
1719
- seeded.month = Number(startDate.slice(5, 7));
1720
- seeded.interval = 1;
1721
- }
1722
- update(seeded);
1723
- };
1724
- const weekdayName = (d) => DEFAULT_RECURRENCE_DESCRIBE_LABELS.weekdayNames[d];
1725
- const ordinal = (p) => DEFAULT_RECURRENCE_DESCRIBE_LABELS.ordinals[p];
1726
- const monthNames = DEFAULT_RECURRENCE_DESCRIBE_LABELS.monthNames;
1727
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": "calendar-recurrence", children: [
1728
- /* @__PURE__ */ jsxRuntime.jsxs(
1729
- NativeSelect,
1730
- {
1731
- id: `${idPrefix}-freq`,
1732
- "aria-label": l.doesNotRepeat,
1733
- value: form.freq,
1734
- onChange: (e) => setFreq(e.target.value),
1735
- "data-testid": "calendar-recurrence-freq",
1736
- className: "w-full sm:w-56",
1737
- children: [
1738
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "none", children: l.doesNotRepeat }),
1739
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "daily", children: l.daily }),
1740
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "weekly", children: l.weekly }),
1741
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "monthly", children: l.monthly }),
1742
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "yearly", children: l.yearly }),
1743
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", children: l.custom })
1744
- ]
1745
- }
1746
- ),
1747
- form.freq === "custom" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1748
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${idPrefix}-raw`, className: "text-xs text-muted-foreground", children: l.rrule }),
1749
- /* @__PURE__ */ jsxRuntime.jsx(
1750
- ui.Input,
1751
- {
1752
- id: `${idPrefix}-raw`,
1753
- value: form.raw,
1754
- placeholder: l.rrulePlaceholder,
1755
- onChange: (e) => update({ raw: e.target.value }),
1756
- "data-testid": "calendar-recurrence-raw",
1757
- className: "font-mono text-xs"
1758
- }
1759
- )
1760
- ] }),
1761
- form.freq !== "none" && form.freq !== "custom" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-md border border-border p-2", children: [
1762
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [
1763
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: l.every }),
1764
- /* @__PURE__ */ jsxRuntime.jsx(
1765
- ui.Input,
1766
- {
1767
- type: "number",
1768
- min: 1,
1769
- max: 999,
1770
- "aria-label": l.every,
1771
- className: "h-8 w-16",
1772
- value: form.interval,
1773
- onChange: (e) => update({ interval: Math.max(1, Number(e.target.value) || 1) }),
1774
- "data-testid": "calendar-recurrence-interval"
1775
- }
1776
- ),
1777
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: l.units[form.freq] })
1778
- ] }),
1779
- form.freq === "weekly" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", role: "group", "aria-label": l.weekly, children: RRULE_WEEKDAYS.map((d) => {
1780
- const on = form.weekdays.includes(d);
1781
- return /* @__PURE__ */ jsxRuntime.jsx(
1782
- "button",
1783
- {
1784
- type: "button",
1785
- "aria-pressed": on,
1786
- "aria-label": weekdayName(d),
1787
- title: weekdayName(d),
1788
- onClick: () => {
1789
- const next = on ? form.weekdays.filter((x) => x !== d) : [...form.weekdays, d];
1790
- update({ weekdays: next.length ? next : form.weekdays });
1791
- },
1792
- "data-testid": `calendar-recurrence-day-${d}`,
1793
- className: ui.cn(
1794
- "h-8 w-8 rounded-full border text-xs font-medium transition-colors",
1795
- on ? "border-primary bg-primary text-primary-foreground" : "border-border hover:bg-muted"
1796
- ),
1797
- children: l.weekdayShort[d]
1798
- },
1799
- d
1800
- );
1801
- }) }),
1802
- (form.freq === "monthly" || form.freq === "yearly") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 text-sm", children: [
1803
- form.freq === "yearly" && /* @__PURE__ */ jsxRuntime.jsx(
1804
- NativeSelect,
1805
- {
1806
- "aria-label": l.yearly,
1807
- value: form.month,
1808
- onChange: (e) => update({ month: Number(e.target.value) }),
1809
- "data-testid": "calendar-recurrence-month",
1810
- className: "h-8",
1811
- children: monthNames.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: i + 1, children: m }, m))
1812
- }
1813
- ),
1814
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-wrap items-center gap-2", children: [
1815
- /* @__PURE__ */ jsxRuntime.jsx(
1816
- "input",
1817
- {
1818
- type: "radio",
1819
- name: `${idPrefix}-monthly`,
1820
- checked: form.monthlyMode === "day",
1821
- onChange: () => update({ monthlyMode: "day" }),
1822
- "data-testid": "calendar-recurrence-mode-day"
1823
- }
1824
- ),
1825
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: l.onDayOfMonth }),
1826
- /* @__PURE__ */ jsxRuntime.jsx(
1827
- ui.Input,
1828
- {
1829
- type: "number",
1830
- min: 1,
1831
- max: 31,
1832
- "aria-label": l.onDayOfMonth,
1833
- className: "h-8 w-16",
1834
- value: form.monthDay,
1835
- disabled: form.monthlyMode !== "day",
1836
- onChange: (e) => update({ monthDay: Math.min(31, Math.max(1, Number(e.target.value) || 1)) }),
1837
- "data-testid": "calendar-recurrence-monthday"
1838
- }
1839
- )
1840
- ] }),
1841
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-wrap items-center gap-2", children: [
1842
- /* @__PURE__ */ jsxRuntime.jsx(
1843
- "input",
1844
- {
1845
- type: "radio",
1846
- name: `${idPrefix}-monthly`,
1847
- checked: form.monthlyMode === "weekday",
1848
- onChange: () => update({ monthlyMode: "weekday" }),
1849
- "data-testid": "calendar-recurrence-mode-weekday"
1850
- }
1851
- ),
1852
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: l.onThe }),
1853
- /* @__PURE__ */ jsxRuntime.jsx(
1854
- NativeSelect,
1855
- {
1856
- "aria-label": l.onThe,
1857
- className: "h-8",
1858
- value: form.setPos,
1859
- disabled: form.monthlyMode !== "weekday",
1860
- onChange: (e) => update({ setPos: Number(e.target.value) }),
1861
- "data-testid": "calendar-recurrence-setpos",
1862
- children: SETPOS_OPTIONS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p, children: ordinal(p) }, p))
1863
- }
1864
- ),
1865
- /* @__PURE__ */ jsxRuntime.jsx(
1866
- NativeSelect,
1867
- {
1868
- "aria-label": l.weekly,
1869
- className: "h-8",
1870
- value: form.setPosDay,
1871
- disabled: form.monthlyMode !== "weekday",
1872
- onChange: (e) => update({ setPosDay: e.target.value }),
1873
- "data-testid": "calendar-recurrence-setpos-day",
1874
- children: RRULE_WEEKDAYS.map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d, children: weekdayName(d) }, d))
1875
- }
1876
- )
1877
- ] })
1878
- ] }),
1879
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 text-sm", children: [
1880
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-muted-foreground", children: l.ends }),
1881
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
1882
- /* @__PURE__ */ jsxRuntime.jsx(
1883
- "input",
1884
- {
1885
- type: "radio",
1886
- name: `${idPrefix}-end`,
1887
- checked: form.end === "never",
1888
- onChange: () => update({ end: "never" }),
1889
- "data-testid": "calendar-recurrence-end-never"
1890
- }
1891
- ),
1892
- l.never
1893
- ] }),
1894
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-wrap items-center gap-2", children: [
1895
- /* @__PURE__ */ jsxRuntime.jsx(
1896
- "input",
1897
- {
1898
- type: "radio",
1899
- name: `${idPrefix}-end`,
1900
- checked: form.end === "until",
1901
- onChange: () => update({ end: "until", until: form.until ?? startDate }),
1902
- "data-testid": "calendar-recurrence-end-until"
1903
- }
1904
- ),
1905
- l.onDate,
1906
- /* @__PURE__ */ jsxRuntime.jsx(
1907
- ui.Input,
1908
- {
1909
- type: "date",
1910
- "aria-label": l.onDate,
1911
- className: "h-8 w-40",
1912
- value: form.until ?? "",
1913
- min: startDate,
1914
- disabled: form.end !== "until",
1915
- onChange: (e) => update({ until: e.target.value || null }),
1916
- "data-testid": "calendar-recurrence-until"
1917
- }
1918
- )
1919
- ] }),
1920
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-wrap items-center gap-2", children: [
1921
- /* @__PURE__ */ jsxRuntime.jsx(
1922
- "input",
1923
- {
1924
- type: "radio",
1925
- name: `${idPrefix}-end`,
1926
- checked: form.end === "count",
1927
- onChange: () => update({ end: "count" }),
1928
- "data-testid": "calendar-recurrence-end-count"
1929
- }
1930
- ),
1931
- l.after,
1932
- /* @__PURE__ */ jsxRuntime.jsx(
1933
- ui.Input,
1934
- {
1935
- type: "number",
1936
- min: 1,
1937
- max: 999,
1938
- "aria-label": l.occurrences,
1939
- className: "h-8 w-20",
1940
- value: form.count,
1941
- disabled: form.end !== "count",
1942
- onChange: (e) => update({ count: Math.max(1, Number(e.target.value) || 1) }),
1943
- "data-testid": "calendar-recurrence-count"
1944
- }
1945
- ),
1946
- l.occurrences
1947
- ] })
1948
- ] }),
1949
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", "data-testid": "calendar-recurrence-summary", children: describeRecurrence(form) })
1950
- ] })
1951
- ] });
1952
- }
1953
-
1954
- // src/calendar/format.ts
1955
- function formatZoneLabel(zone, at = Date.now()) {
1956
- return `${chunkBIXHB4LV_cjs.zoneCity(zone)} (${chunkBIXHB4LV_cjs.zoneOffsetLabel(zone, at)})`;
1957
- }
1958
- function formatEventWhen(e, zone, locale) {
1959
- const z = chunkBIXHB4LV_cjs.safeZone(zone);
1960
- const dayFmt = {
1961
- weekday: "short",
1962
- day: "numeric",
1963
- month: "short",
1964
- year: "numeric"
1965
- };
1966
- if (e.all_day) {
1967
- const start = e.start.date ?? chunkBIXHB4LV_cjs.utcToDate(e.start_utc, z);
1968
- const endExcl = e.end.date ?? chunkBIXHB4LV_cjs.utcToDate(e.end_utc, z);
1969
- const last = endExcl > start ? chunkBIXHB4LV_cjs.addDays(endExcl, -1) : start;
1970
- const a2 = chunkBIXHB4LV_cjs.formatPlainDate(start, dayFmt, locale);
1971
- return last === start ? a2 : `${a2} \u2013 ${chunkBIXHB4LV_cjs.formatPlainDate(last, dayFmt, locale)}`;
1972
- }
1973
- const timeFmt = { hour: "numeric", minute: "2-digit" };
1974
- const sameDay = chunkBIXHB4LV_cjs.utcToDate(e.start_utc, z) === chunkBIXHB4LV_cjs.utcToDate(e.end_utc, z);
1975
- const a = `${chunkBIXHB4LV_cjs.formatInZone(e.start_utc, z, dayFmt, locale)} \xB7 ${chunkBIXHB4LV_cjs.formatInZone(e.start_utc, z, timeFmt, locale)}`;
1976
- return sameDay ? `${a} \u2013 ${chunkBIXHB4LV_cjs.formatInZone(e.end_utc, z, timeFmt, locale)}` : `${a} \u2013 ${chunkBIXHB4LV_cjs.formatInZone(e.end_utc, z, dayFmt, locale)} \xB7 ${chunkBIXHB4LV_cjs.formatInZone(e.end_utc, z, timeFmt, locale)}`;
1977
- }
1978
- function TimeZonePicker({
1979
- value,
1980
- onChange,
1981
- zones,
1982
- allowNone,
1983
- onClear,
1984
- id,
1985
- ariaLabel,
1986
- disabled,
1987
- labels: labelOverrides,
1988
- className
1989
- }) {
1990
- const labels = mergeLabels(labelOverrides);
1991
- const [open, setOpen] = react.useState(false);
1992
- const options = react.useMemo(() => {
1993
- const now = Date.now();
1994
- const list = zones?.length ? zones : chunkBIXHB4LV_cjs.listTimeZones();
1995
- return list.map((z) => {
1996
- let offset = 0;
1997
- try {
1998
- offset = chunkBIXHB4LV_cjs.zoneOffsetMinutes(z, now);
1999
- } catch {
2000
- return null;
2001
- }
2002
- return { zone: z, offset, label: chunkBIXHB4LV_cjs.zoneOffsetLabel(z, now), city: chunkBIXHB4LV_cjs.zoneCity(z) };
2003
- }).filter((o) => o !== null).sort((a, b) => a.offset - b.offset || a.zone.localeCompare(b.zone));
2004
- }, [zones, open]);
2005
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open, onOpenChange: setOpen, children: [
2006
- /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
2007
- "button",
2008
- {
2009
- type: "button",
2010
- id,
2011
- disabled,
2012
- "aria-label": ariaLabel ?? labels.timeZone,
2013
- "aria-haspopup": "listbox",
2014
- "aria-expanded": open,
2015
- "data-testid": "calendar-tz-picker",
2016
- className: ui.cn(
2017
- "inline-flex h-9 min-w-0 items-center gap-2 rounded-md border border-input bg-background px-2 text-left text-sm shadow-sm",
2018
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50",
2019
- className
2020
- ),
2021
- children: [
2022
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
2023
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: value ? formatZoneLabel(value) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: labels.none }) }),
2024
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true })
2025
- ]
2026
- }
2027
- ) }),
2028
- /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { className: "w-[320px] p-0", align: "start", children: /* @__PURE__ */ jsxRuntime.jsxs(
2029
- ui.Command,
2030
- {
2031
- filter: (itemValue, search) => itemValue.toLowerCase().includes(search.toLowerCase().trim()) ? 1 : 0,
2032
- children: [
2033
- /* @__PURE__ */ jsxRuntime.jsx(ui.CommandInput, { placeholder: labels.searchTimeZones, "data-testid": "calendar-tz-search" }),
2034
- /* @__PURE__ */ jsxRuntime.jsxs(ui.CommandList, { className: "max-h-72", children: [
2035
- /* @__PURE__ */ jsxRuntime.jsx(ui.CommandEmpty, { children: "\u2014" }),
2036
- /* @__PURE__ */ jsxRuntime.jsxs(ui.CommandGroup, { children: [
2037
- allowNone && /* @__PURE__ */ jsxRuntime.jsxs(
2038
- ui.CommandItem,
2039
- {
2040
- value: `__none__ ${labels.none}`,
2041
- onSelect: () => {
2042
- onClear?.();
2043
- setOpen(false);
2044
- },
2045
- children: [
2046
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: ui.cn("mr-2 h-4 w-4", value ? "opacity-0" : "opacity-100") }),
2047
- labels.none
2048
- ]
2049
- }
2050
- ),
2051
- options.map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
2052
- ui.CommandItem,
2053
- {
2054
- value: `${o.zone} ${o.city} ${o.label}`,
2055
- onSelect: () => {
2056
- onChange(o.zone);
2057
- setOpen(false);
2058
- },
2059
- "data-testid": `calendar-tz-option-${o.zone}`,
2060
- children: [
2061
- /* @__PURE__ */ jsxRuntime.jsx(
2062
- lucideReact.Check,
2063
- {
2064
- className: ui.cn(
2065
- "mr-2 h-4 w-4 shrink-0",
2066
- value === o.zone ? "opacity-100" : "opacity-0"
2067
- )
2068
- }
2069
- ),
2070
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: o.zone.replace(/_/g, " ") }),
2071
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 shrink-0 text-xs tabular-nums text-muted-foreground", children: o.label })
2072
- ]
2073
- },
2074
- o.zone
2075
- ))
2076
- ] })
2077
- ] })
2078
- ]
2079
- }
2080
- ) })
2081
- ] });
2082
- }
2083
-
2084
- // src/calendar/reminders.ts
2085
- var UNIT_MINUTES = {
2086
- minutes: 1,
2087
- hours: 60,
2088
- days: 24 * 60,
2089
- weeks: 7 * 24 * 60
2090
- };
2091
- function splitReminderMinutes(minutes) {
2092
- const abs = Math.abs(minutes);
2093
- if (abs === 0) return { value: 0, unit: "minutes" };
2094
- for (const unit of ["weeks", "days", "hours"]) {
2095
- if (abs % UNIT_MINUTES[unit] === 0) return { value: minutes / UNIT_MINUTES[unit], unit };
2096
- }
2097
- return { value: minutes, unit: "minutes" };
2098
- }
2099
- function reminderToMinutes(value, unit) {
2100
- return Math.round(value * UNIT_MINUTES[unit]);
2101
- }
2102
- var DEFAULT_REMINDER_FORMAT_LABELS = {
2103
- atStart: "At time of event",
2104
- before: "before",
2105
- after: "after",
2106
- minute: "minute",
2107
- minutes: "minutes",
2108
- hour: "hour",
2109
- hours: "hours",
2110
- day: "day",
2111
- days: "days",
2112
- week: "week",
2113
- weeks: "weeks"
2114
- };
2115
- function formatReminder(minutesBefore, labels = DEFAULT_REMINDER_FORMAT_LABELS) {
2116
- if (minutesBefore === 0) return labels.atStart;
2117
- const { value, unit } = splitReminderMinutes(Math.abs(minutesBefore));
2118
- const singular = {
2119
- minutes: labels.minute,
2120
- hours: labels.hour,
2121
- days: labels.day,
2122
- weeks: labels.week
2123
- }[unit];
2124
- const word = value === 1 ? singular : labels[unit];
2125
- return `${value} ${word} ${minutesBefore > 0 ? labels.before : labels.after}`;
2126
- }
2127
- var REMINDER_PRESETS = [0, 5, 10, 15, 30, 60, 120, 24 * 60, 2 * 24 * 60, 7 * 24 * 60];
2128
- var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2129
- function Chip({
2130
- children,
2131
- onRemove,
2132
- removeLabel
2133
- }) {
2134
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-muted/60 py-0.5 pl-2 pr-1 text-xs", children: [
2135
- children,
2136
- /* @__PURE__ */ jsxRuntime.jsx(
2137
- "button",
2138
- {
2139
- type: "button",
2140
- onClick: onRemove,
2141
- "aria-label": removeLabel,
2142
- className: "rounded-full p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
2143
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" })
2144
- }
2145
- )
2146
- ] });
2147
- }
2148
- function showAsLabel(v, l) {
2149
- return {
2150
- free: l.free,
2151
- tentative: l.tentative,
2152
- busy: l.busy,
2153
- oof: l.oof,
2154
- working_elsewhere: l.workingElsewhere
2155
- }[v];
2156
- }
2157
- function EventEditor({
2158
- value,
2159
- onChange,
2160
- onSave,
2161
- onCancel,
2162
- onDelete,
2163
- calendars,
2164
- mode,
2165
- canAddCall,
2166
- onAddCall,
2167
- canAddWebinar,
2168
- isWebinarAttendee,
2169
- defaultTimeZone,
2170
- schedulingSlot,
2171
- attendeeSuggestions,
2172
- onAttendeeQueryChange,
2173
- saving,
2174
- error,
2175
- labels: labelOverrides,
2176
- zones,
2177
- className
2178
- }) {
2179
- const l = react.useMemo(() => mergeLabels(labelOverrides), [labelOverrides]);
2180
- const uid = react.useId();
2181
- const id = (s) => `${uid}-${s}`;
2182
- const allDay = isAllDayDraft(value);
2183
- const startZone = value.start.time_zone ?? defaultTimeZone;
2184
- const endZone = value.end.time_zone ?? startZone;
2185
- const [showZones, setShowZones] = react.useState(
2186
- () => !allDay && (startZone !== defaultTimeZone || endZone !== startZone)
2187
- );
2188
- const [attendeeInput, setAttendeeInput] = react.useState("");
2189
- const [categoryInput, setCategoryInput] = react.useState("");
2190
- const [linkInput, setLinkInput] = react.useState(null);
2191
- const [attachUrl, setAttachUrl] = react.useState("");
2192
- const [attachTitle, setAttachTitle] = react.useState("");
2193
- const [addingCall, setAddingCall] = react.useState(false);
2194
- const [webinar, setWebinar] = react.useState(false);
2195
- const [touched, setTouched] = react.useState(false);
2196
- const [focus, setFocus] = react.useState(() => !!value.auto_decline && value.show_as !== "oof");
2197
- const showDecline = value.show_as === "oof" || focus;
2198
- const set = (patch) => onChange({ ...value, ...patch });
2199
- const problem = validateDraft(value, defaultTimeZone);
2200
- const shownProblem = problem === "invalidRange" || touched && problem ? problem : null;
2201
- const writable = calendars.filter((c) => c.canWrite && !c.locked);
2202
- const calendarColor = calendars.find((c) => c.id === value.calendar_id)?.color;
2203
- const attendees = value.attendees ?? [];
2204
- const addAttendees = (raw) => {
2205
- const emails = raw.split(/[\s,;]+/).map((s) => s.trim()).filter((s) => EMAIL_RE.test(s));
2206
- if (!emails.length) return false;
2207
- const have = new Set(attendees.map((a) => (a.email ?? "").toLowerCase()));
2208
- const next = [...attendees];
2209
- for (const email of emails) {
2210
- if (have.has(email.toLowerCase())) continue;
2211
- have.add(email.toLowerCase());
2212
- next.push({ email, role: "required", kind: "individual" });
2213
- }
2214
- set({ attendees: next });
2215
- return true;
2216
- };
2217
- const onAttendeeKey = (e) => {
2218
- if (e.key === "Enter" || e.key === "," || e.key === ";" || e.key === "Tab") {
2219
- if (attendeeInput.trim() && addAttendees(attendeeInput)) {
2220
- e.preventDefault();
2221
- setAttendeeInput("");
2222
- }
2223
- } else if (e.key === "Backspace" && !attendeeInput && attendees.length) {
2224
- set({ attendees: attendees.slice(0, -1) });
2225
- }
2226
- };
2227
- const categories = value.categories ?? [];
2228
- const addCategory = () => {
2229
- const c = categoryInput.trim();
2230
- if (c && !categories.includes(c)) set({ categories: [...categories, c] });
2231
- setCategoryInput("");
2232
- };
2233
- const reminders = value.reminders ?? [];
2234
- const setReminder = (i, r) => set({ reminders: reminders.map((x, j) => j === i ? r : x) });
2235
- const addArbiCall = async () => {
2236
- if (!onAddCall) return;
2237
- setAddingCall(true);
2238
- try {
2239
- const call = await onAddCall();
2240
- if (call)
2241
- set({
2242
- conference: { type: "arbi", url: call.url, call_id: call.call_id, label: l.arbiCall }
2243
- });
2244
- } finally {
2245
- setAddingCall(false);
2246
- }
2247
- };
2248
- const addArbiWebinar = () => set({
2249
- conference: { type: "arbi", kind: "webinar", url: "", label: ARBI_WEBINAR_LABEL, roles: {} }
2250
- });
2251
- const isWebinar = isWebinarConference(value.conference);
2252
- const roles = value.conference?.roles ?? {};
2253
- const setRole = (a, role) => value.conference && set({ conference: { ...value.conference, roles: { ...roles, [attendeeKey(a)]: role } } });
2254
- const attachments = value.attachments ?? [];
2255
- const addAttachment = () => {
2256
- const url = attachUrl.trim();
2257
- if (!url) return;
2258
- set({ attachments: [...attachments, { url, title: attachTitle.trim() || null }] });
2259
- setAttachUrl("");
2260
- setAttachTitle("");
2261
- };
2262
- const startDate = specDate(value.start);
2263
- const submit = () => {
2264
- setTouched(true);
2265
- if (problem || saving) return;
2266
- onSave();
2267
- };
2268
- return /* @__PURE__ */ jsxRuntime.jsxs(
2269
- "form",
2270
- {
2271
- className: ui.cn("flex h-full min-h-0 flex-col", className),
2272
- onSubmit: (e) => {
2273
- e.preventDefault();
2274
- submit();
2275
- },
2276
- "data-testid": "calendar-event-editor",
2277
- "aria-label": mode === "create" ? l.createTitle : l.editTitle,
2278
- children: [
2279
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 space-y-4 overflow-y-auto p-1 scrollbar-themed", children: [
2280
- /* @__PURE__ */ jsxRuntime.jsx(
2281
- ui.Input,
2282
- {
2283
- id: id("title"),
2284
- "aria-label": l.title,
2285
- placeholder: l.titlePlaceholder,
2286
- value: value.title,
2287
- autoFocus: mode === "create",
2288
- onChange: (e) => set({ title: e.target.value }),
2289
- className: "h-11 border-0 border-b border-border rounded-none px-1 text-lg font-medium shadow-none focus-visible:ring-0 focus-visible:border-primary",
2290
- "data-testid": "calendar-editor-title"
2291
- }
2292
- ),
2293
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" }), children: [
2294
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
2295
- /* @__PURE__ */ jsxRuntime.jsx(
2296
- ui.Input,
2297
- {
2298
- type: "date",
2299
- "aria-label": l.start,
2300
- className: "h-9 w-[9.5rem]",
2301
- value: startDate,
2302
- onChange: (e) => e.target.value && onChange(setDraftStart(value, { date: e.target.value }, defaultTimeZone)),
2303
- "data-testid": "calendar-editor-start-date"
2304
- }
2305
- ),
2306
- !allDay && /* @__PURE__ */ jsxRuntime.jsx(
2307
- ui.Input,
2308
- {
2309
- type: "time",
2310
- "aria-label": l.startTime,
2311
- className: "h-9 w-[7rem]",
2312
- step: 300,
2313
- value: specTime(value.start),
2314
- onChange: (e) => e.target.value && onChange(setDraftStart(value, { time: e.target.value }, defaultTimeZone)),
2315
- "data-testid": "calendar-editor-start-time"
2316
- }
2317
- ),
2318
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2013" }),
2319
- !allDay && /* @__PURE__ */ jsxRuntime.jsx(
2320
- ui.Input,
2321
- {
2322
- type: "time",
2323
- "aria-label": l.endTime,
2324
- className: "h-9 w-[7rem]",
2325
- step: 300,
2326
- value: specTime(value.end),
2327
- onChange: (e) => e.target.value && onChange(setDraftEnd(value, { time: e.target.value })),
2328
- "data-testid": "calendar-editor-end-time"
2329
- }
2330
- ),
2331
- /* @__PURE__ */ jsxRuntime.jsx(
2332
- ui.Input,
2333
- {
2334
- type: "date",
2335
- "aria-label": l.end,
2336
- className: "h-9 w-[9.5rem]",
2337
- value: allDay ? allDayInclusiveEnd(value) : specDate(value.end),
2338
- min: startDate,
2339
- onChange: (e) => e.target.value && onChange(setDraftEnd(value, { date: e.target.value })),
2340
- "data-testid": "calendar-editor-end-date"
2341
- }
2342
- )
2343
- ] }),
2344
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-4 pt-1 text-sm", children: [
2345
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
2346
- /* @__PURE__ */ jsxRuntime.jsx(
2347
- ui.Switch,
2348
- {
2349
- checked: allDay,
2350
- onCheckedChange: (on) => onChange(setDraftAllDay(value, on, startZone)),
2351
- "aria-label": l.allDay,
2352
- "data-testid": "calendar-editor-all-day"
2353
- }
2354
- ),
2355
- l.allDay
2356
- ] }),
2357
- !allDay && /* @__PURE__ */ jsxRuntime.jsxs(
2358
- "button",
2359
- {
2360
- type: "button",
2361
- className: "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground",
2362
- onClick: () => setShowZones((v) => !v),
2363
- "aria-expanded": showZones,
2364
- "data-testid": "calendar-editor-zones-toggle",
2365
- children: [
2366
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-3.5 w-3.5" }),
2367
- l.separateTimeZones
2368
- ]
2369
- }
2370
- )
2371
- ] }),
2372
- !allDay && showZones && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 pt-1 sm:grid-cols-2", children: [
2373
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
2374
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: l.startTimeZone }),
2375
- /* @__PURE__ */ jsxRuntime.jsx(
2376
- TimeZonePicker,
2377
- {
2378
- value: startZone,
2379
- zones,
2380
- ariaLabel: l.startTimeZone,
2381
- labels: labelOverrides,
2382
- className: "w-full",
2383
- onChange: (z) => {
2384
- const moved = setDraftStart(value, { timeZone: z }, defaultTimeZone);
2385
- const endFollows = (value.end.time_zone ?? startZone) === startZone;
2386
- onChange(endFollows ? { ...moved, end: { ...moved.end, time_zone: z } } : moved);
2387
- }
2388
- }
2389
- )
2390
- ] }),
2391
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
2392
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: l.endTimeZone }),
2393
- /* @__PURE__ */ jsxRuntime.jsx(
2394
- TimeZonePicker,
2395
- {
2396
- value: endZone,
2397
- zones,
2398
- ariaLabel: l.endTimeZone,
2399
- labels: labelOverrides,
2400
- className: "w-full",
2401
- onChange: (z) => onChange(setDraftEnd(value, { timeZone: z }))
2402
- }
2403
- )
2404
- ] })
2405
- ] })
2406
- ] }),
2407
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Repeat, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx(
2408
- RecurrenceEditor,
2409
- {
2410
- rrule: value.recurrence?.rrule ?? null,
2411
- startDate,
2412
- allDay,
2413
- timeZone: startZone,
2414
- idPrefix: id("rrule"),
2415
- onChange: (rrule) => set({
2416
- recurrence: rrule ? { ...value.recurrence ?? {}, rrule } : value.recurrence?.rdates?.length ? { ...value.recurrence, rrule: null } : null
2417
- })
2418
- }
2419
- ) }),
2420
- writable.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarDays, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsxs(
2421
- NativeSelect,
2422
- {
2423
- "aria-label": l.calendar,
2424
- value: value.calendar_id ?? "",
2425
- onChange: (e) => set({ calendar_id: e.target.value || void 0 }),
2426
- "data-testid": "calendar-editor-calendar",
2427
- className: "w-full sm:w-72",
2428
- children: [
2429
- !value.calendar_id && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.calendar }),
2430
- writable.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.id, children: c.name ?? c.id }, c.id))
2431
- ]
2432
- }
2433
- ) }),
2434
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "h-4 w-4" }), children: value.conference ? /* @__PURE__ */ jsxRuntime.jsxs(
2435
- "div",
2436
- {
2437
- className: "flex min-w-0 items-center gap-2 text-sm",
2438
- "data-testid": "calendar-editor-conference",
2439
- children: [
2440
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: isWebinar ? l.arbiWebinar : value.conference.label || (value.conference.type === "arbi" ? l.arbiCall : l.conference) }),
2441
- value.conference.url ? /* @__PURE__ */ jsxRuntime.jsx(
2442
- "a",
2443
- {
2444
- href: value.conference.url,
2445
- target: "_blank",
2446
- rel: "noreferrer",
2447
- className: "min-w-0 truncate text-xs text-primary underline-offset-2 hover:underline",
2448
- children: value.conference.url.replace(/#.*$/, "")
2449
- }
2450
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate text-xs text-muted-foreground", children: l.webinarLinkOnSave }),
2451
- /* @__PURE__ */ jsxRuntime.jsx(
2452
- "button",
2453
- {
2454
- type: "button",
2455
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
2456
- "aria-label": l.removeConference,
2457
- onClick: () => set({ conference: null }),
2458
- "data-testid": "calendar-editor-conference-remove",
2459
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
2460
- }
2461
- )
2462
- ]
2463
- }
2464
- ) : linkInput !== null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2465
- /* @__PURE__ */ jsxRuntime.jsx(
2466
- ui.Input,
2467
- {
2468
- type: "url",
2469
- "aria-label": l.addMeetingLink,
2470
- placeholder: l.meetingLinkPlaceholder,
2471
- value: linkInput,
2472
- autoFocus: true,
2473
- onChange: (e) => setLinkInput(e.target.value),
2474
- onKeyDown: (e) => {
2475
- if (e.key === "Enter") {
2476
- e.preventDefault();
2477
- if (linkInput.trim())
2478
- set({ conference: { type: "external", url: linkInput.trim() } });
2479
- setLinkInput(null);
2480
- } else if (e.key === "Escape") setLinkInput(null);
2481
- },
2482
- "data-testid": "calendar-editor-link-input"
2483
- }
2484
- ),
2485
- /* @__PURE__ */ jsxRuntime.jsx(
2486
- ui.Button,
2487
- {
2488
- type: "button",
2489
- size: "sm",
2490
- variant: "outline",
2491
- onClick: () => {
2492
- if (linkInput.trim())
2493
- set({ conference: { type: "external", url: linkInput.trim() } });
2494
- setLinkInput(null);
2495
- },
2496
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" })
2497
- }
2498
- )
2499
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
2500
- canAddCall && onAddCall && /* @__PURE__ */ jsxRuntime.jsxs(
2501
- ui.Button,
2502
- {
2503
- type: "button",
2504
- size: "sm",
2505
- variant: "secondary",
2506
- disabled: addingCall,
2507
- onClick: webinar ? addArbiWebinar : addArbiCall,
2508
- "data-testid": "calendar-editor-add-call",
2509
- children: [
2510
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "mr-1 h-4 w-4" }),
2511
- webinar ? l.addArbiWebinar : l.addArbiCall
2512
- ]
2513
- }
2514
- ),
2515
- canAddCall && onAddCall && canAddWebinar && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
2516
- /* @__PURE__ */ jsxRuntime.jsx(
2517
- ui.Switch,
2518
- {
2519
- checked: webinar,
2520
- onCheckedChange: setWebinar,
2521
- "aria-label": l.webinar,
2522
- "data-testid": "calendar-editor-webinar"
2523
- }
2524
- ),
2525
- l.webinar
2526
- ] }),
2527
- /* @__PURE__ */ jsxRuntime.jsx(
2528
- ui.Button,
2529
- {
2530
- type: "button",
2531
- size: "sm",
2532
- variant: "ghost",
2533
- onClick: () => setLinkInput(""),
2534
- "data-testid": "calendar-editor-add-link",
2535
- children: l.addMeetingLink
2536
- }
2537
- )
2538
- ] }) }),
2539
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx(
2540
- ui.Input,
2541
- {
2542
- "aria-label": l.location,
2543
- placeholder: l.location,
2544
- value: value.location ?? "",
2545
- onChange: (e) => set({ location: e.target.value || null }),
2546
- "data-testid": "calendar-editor-location"
2547
- }
2548
- ) }),
2549
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "h-4 w-4" }), children: [
2550
- /* @__PURE__ */ jsxRuntime.jsx(
2551
- ui.Input,
2552
- {
2553
- type: "email",
2554
- multiple: true,
2555
- "aria-label": l.addAttendee,
2556
- placeholder: l.addAttendee,
2557
- value: attendeeInput,
2558
- onChange: (e) => {
2559
- setAttendeeInput(e.target.value);
2560
- onAttendeeQueryChange?.(e.target.value);
2561
- },
2562
- onKeyDown: onAttendeeKey,
2563
- onBlur: () => {
2564
- if (attendeeInput.trim() && addAttendees(attendeeInput)) setAttendeeInput("");
2565
- },
2566
- "data-testid": "calendar-editor-attendee-input"
2567
- }
2568
- ),
2569
- attendeeInput.trim() && (attendeeSuggestions?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2570
- "ul",
2571
- {
2572
- role: "listbox",
2573
- "aria-label": l.suggestions,
2574
- className: "mt-1 max-h-48 overflow-y-auto rounded-md border border-border bg-popover shadow-sm",
2575
- "data-testid": "calendar-editor-attendee-suggestions",
2576
- children: attendeeSuggestions?.filter(
2577
- (s) => !attendees.some((a) => (a.email ?? "").toLowerCase() === s.email.toLowerCase())
2578
- ).slice(0, 8).map((s) => /* @__PURE__ */ jsxRuntime.jsx("li", { role: "option", "aria-selected": false, children: /* @__PURE__ */ jsxRuntime.jsxs(
2579
- "button",
2580
- {
2581
- type: "button",
2582
- className: "flex w-full items-baseline gap-2 px-3 py-1.5 text-left text-sm hover:bg-muted",
2583
- onMouseDown: (e) => e.preventDefault(),
2584
- onClick: () => {
2585
- set({
2586
- attendees: [
2587
- ...attendees,
2588
- {
2589
- email: s.email,
2590
- name: s.name ?? null,
2591
- role: "required",
2592
- kind: "individual"
2593
- }
2594
- ]
2595
- });
2596
- setAttendeeInput("");
2597
- onAttendeeQueryChange?.("");
2598
- },
2599
- "data-testid": "calendar-editor-attendee-suggestion",
2600
- children: [
2601
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: s.name || s.email }),
2602
- s.name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: s.email }),
2603
- s.detail && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 text-xs text-muted-foreground", children: s.detail })
2604
- ]
2605
- }
2606
- ) }, s.email))
2607
- }
2608
- ),
2609
- attendees.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", "data-testid": "calendar-editor-attendees", children: attendees.map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2610
- "li",
2611
- {
2612
- className: "flex items-center gap-2 text-sm",
2613
- children: [
2614
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", title: a.email ?? void 0, children: a.name || a.email || a.user_id }),
2615
- /* @__PURE__ */ jsxRuntime.jsxs(
2616
- NativeSelect,
2617
- {
2618
- "aria-label": `${a.email ?? ""} ${l.required}`,
2619
- className: "h-7 text-xs",
2620
- value: a.role ?? "required",
2621
- onChange: (e) => set({
2622
- attendees: attendees.map(
2623
- (x, j) => j === i ? { ...x, role: e.target.value } : x
2624
- )
2625
- }),
2626
- children: [
2627
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "required", children: l.required }),
2628
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "optional", children: l.optional })
2629
- ]
2630
- }
2631
- ),
2632
- isWebinar && (isWebinarAttendee?.(a) ?? true) && /* @__PURE__ */ jsxRuntime.jsxs(
2633
- NativeSelect,
2634
- {
2635
- "aria-label": `${a.email ?? ""} ${l.webinarRole}`,
2636
- className: "h-7 text-xs",
2637
- value: roles[attendeeKey(a)] ?? "attendee",
2638
- onChange: (e) => setRole(a, e.target.value),
2639
- "data-testid": "calendar-editor-webinar-role",
2640
- children: [
2641
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "cohost", children: l.cohost }),
2642
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "panelist", children: l.panelist }),
2643
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "attendee", children: l.webinarAttendee })
2644
- ]
2645
- }
2646
- ),
2647
- /* @__PURE__ */ jsxRuntime.jsx(
2648
- "button",
2649
- {
2650
- type: "button",
2651
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
2652
- "aria-label": `${l.remove} ${a.email ?? ""}`,
2653
- onClick: () => set({ attendees: attendees.filter((_, j) => j !== i) }),
2654
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
2655
- }
2656
- )
2657
- ]
2658
- },
2659
- `${a.email ?? a.user_id ?? i}`
2660
- )) })
2661
- ] }),
2662
- schedulingSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-8", children: schedulingSlot }),
2663
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TextAlignStart, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx(
2664
- ui.Textarea,
2665
- {
2666
- "aria-label": l.description,
2667
- placeholder: l.description,
2668
- value: value.description ?? "",
2669
- rows: 4,
2670
- onChange: (e) => set({ description: e.target.value || null }),
2671
- "data-testid": "calendar-editor-description"
2672
- }
2673
- ) }),
2674
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: "h-4 w-4" }), label: l.reminders, children: [
2675
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
2676
- /* @__PURE__ */ jsxRuntime.jsx(
2677
- "input",
2678
- {
2679
- type: "checkbox",
2680
- checked: !!value.use_default_reminders,
2681
- onChange: (e) => set({ use_default_reminders: e.target.checked }),
2682
- "data-testid": "calendar-editor-default-reminders"
2683
- }
2684
- ),
2685
- l.useDefaultReminders
2686
- ] }),
2687
- !value.use_default_reminders && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
2688
- reminders.map((r, i) => {
2689
- const { value: n, unit } = splitReminderMinutes(r.minutes_before);
2690
- return /* @__PURE__ */ jsxRuntime.jsxs(
2691
- "div",
2692
- {
2693
- className: "flex flex-wrap items-center gap-2 text-sm",
2694
- "data-testid": "calendar-editor-reminder",
2695
- children: [
2696
- /* @__PURE__ */ jsxRuntime.jsxs(
2697
- NativeSelect,
2698
- {
2699
- "aria-label": l.reminders,
2700
- className: "h-8",
2701
- value: r.action,
2702
- onChange: (e) => setReminder(i, { ...r, action: e.target.value }),
2703
- children: [
2704
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "display", children: l.popup }),
2705
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "email", children: l.email })
2706
- ]
2707
- }
2708
- ),
2709
- /* @__PURE__ */ jsxRuntime.jsx(
2710
- ui.Input,
2711
- {
2712
- type: "number",
2713
- min: 0,
2714
- "aria-label": formatReminder(r.minutes_before),
2715
- className: "h-8 w-20",
2716
- value: n,
2717
- onChange: (e) => setReminder(i, {
2718
- ...r,
2719
- minutes_before: reminderToMinutes(
2720
- Math.max(0, Number(e.target.value) || 0),
2721
- unit
2722
- )
2723
- })
2724
- }
2725
- ),
2726
- /* @__PURE__ */ jsxRuntime.jsxs(
2727
- NativeSelect,
2728
- {
2729
- "aria-label": l.minutes,
2730
- className: "h-8",
2731
- value: unit,
2732
- onChange: (e) => setReminder(i, {
2733
- ...r,
2734
- minutes_before: reminderToMinutes(n, e.target.value)
2735
- }),
2736
- children: [
2737
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "minutes", children: l.minutes }),
2738
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "hours", children: l.hours }),
2739
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "days", children: l.days }),
2740
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "weeks", children: l.weeks })
2741
- ]
2742
- }
2743
- ),
2744
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.beforeStart }),
2745
- /* @__PURE__ */ jsxRuntime.jsx(
2746
- "button",
2747
- {
2748
- type: "button",
2749
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
2750
- "aria-label": `${l.remove} ${formatReminder(r.minutes_before)}`,
2751
- onClick: () => set({ reminders: reminders.filter((_, j) => j !== i) }),
2752
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
2753
- }
2754
- )
2755
- ]
2756
- },
2757
- i
2758
- );
2759
- }),
2760
- reminders.length < 5 && /* @__PURE__ */ jsxRuntime.jsxs(
2761
- ui.Button,
2762
- {
2763
- type: "button",
2764
- size: "sm",
2765
- variant: "ghost",
2766
- onClick: () => set({
2767
- reminders: [
2768
- ...reminders,
2769
- { minutes_before: allDay ? 24 * 60 : 10, action: "display" }
2770
- ]
2771
- }),
2772
- "data-testid": "calendar-editor-add-reminder",
2773
- children: [
2774
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "mr-1 h-4 w-4" }),
2775
- l.addReminder
2776
- ]
2777
- }
2778
- )
2779
- ] })
2780
- ] }),
2781
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "h-4 w-4" }), children: [
2782
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
2783
- /* @__PURE__ */ jsxRuntime.jsx(
2784
- NativeSelect,
2785
- {
2786
- "aria-label": l.showAs,
2787
- value: value.show_as ?? "busy",
2788
- onChange: (e) => set({ show_as: e.target.value }),
2789
- "data-testid": "calendar-editor-show-as",
2790
- children: ["busy", "free", "tentative", "oof", "working_elsewhere"].map((v) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: v, children: showAsLabel(v, l) }, v))
2791
- }
2792
- ),
2793
- /* @__PURE__ */ jsxRuntime.jsxs(
2794
- NativeSelect,
2795
- {
2796
- "aria-label": l.sensitivity,
2797
- value: value.sensitivity ?? "normal",
2798
- onChange: (e) => set({ sensitivity: e.target.value }),
2799
- "data-testid": "calendar-editor-sensitivity",
2800
- children: [
2801
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "normal", children: l.normal }),
2802
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "private", children: l.private }),
2803
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "confidential", children: l.confidential })
2804
- ]
2805
- }
2806
- ),
2807
- /* @__PURE__ */ jsxRuntime.jsxs(
2808
- NativeSelect,
2809
- {
2810
- "aria-label": l.status,
2811
- value: value.status ?? "confirmed",
2812
- onChange: (e) => set({ status: e.target.value }),
2813
- "data-testid": "calendar-editor-status",
2814
- children: [
2815
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "confirmed", children: l.confirmed }),
2816
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "tentative", children: l.tentative }),
2817
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "cancelled", children: l.cancelled })
2818
- ]
2819
- }
2820
- )
2821
- ] }),
2822
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-4 pt-2 text-sm", children: [
2823
- value.show_as !== "oof" && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
2824
- /* @__PURE__ */ jsxRuntime.jsx(
2825
- "input",
2826
- {
2827
- type: "checkbox",
2828
- checked: focus,
2829
- onChange: (e) => {
2830
- setFocus(e.target.checked);
2831
- if (!e.target.checked) set({ auto_decline: false });
2832
- else if (!value.show_as || value.show_as === "free") set({ show_as: "busy" });
2833
- },
2834
- "data-testid": "calendar-editor-focus"
2835
- }
2836
- ),
2837
- l.focusTime
2838
- ] }),
2839
- showDecline && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
2840
- /* @__PURE__ */ jsxRuntime.jsx(
2841
- "input",
2842
- {
2843
- type: "checkbox",
2844
- checked: !!value.auto_decline,
2845
- onChange: (e) => set({ auto_decline: e.target.checked }),
2846
- "data-testid": "calendar-editor-auto-decline"
2847
- }
2848
- ),
2849
- l.autoDecline
2850
- ] })
2851
- ] }),
2852
- showDecline && value.auto_decline && /* @__PURE__ */ jsxRuntime.jsx(
2853
- ui.Input,
2854
- {
2855
- className: "mt-2",
2856
- "aria-label": l.declineMessage,
2857
- placeholder: l.declineMessagePlaceholder,
2858
- value: value.decline_message ?? "",
2859
- maxLength: 1e3,
2860
- onChange: (e) => set({ decline_message: e.target.value || null }),
2861
- "data-testid": "calendar-editor-decline-message"
2862
- }
2863
- )
2864
- ] }),
2865
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
2866
- categories.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
2867
- Chip,
2868
- {
2869
- removeLabel: `${l.remove} ${c}`,
2870
- onRemove: () => set({ categories: categories.filter((x) => x !== c) }),
2871
- children: c
2872
- },
2873
- c
2874
- )),
2875
- /* @__PURE__ */ jsxRuntime.jsx(
2876
- ui.Input,
2877
- {
2878
- "aria-label": l.addCategory,
2879
- placeholder: l.addCategory,
2880
- className: "h-8 w-40",
2881
- value: categoryInput,
2882
- onChange: (e) => setCategoryInput(e.target.value),
2883
- onKeyDown: (e) => {
2884
- if (e.key === "Enter" || e.key === ",") {
2885
- e.preventDefault();
2886
- addCategory();
2887
- }
2888
- },
2889
- onBlur: addCategory,
2890
- "data-testid": "calendar-editor-category-input"
2891
- }
2892
- )
2893
- ] }) }),
2894
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: "h-4 w-4" }), children: [
2895
- /* @__PURE__ */ jsxRuntime.jsx(
2896
- ColorSwatches,
2897
- {
2898
- value: value.color ?? null,
2899
- onChange: (c) => set({ color: c }),
2900
- allowNone: true,
2901
- noneLabel: l.defaultColor,
2902
- testIdPrefix: "calendar-editor-color"
2903
- }
2904
- ),
2905
- !value.color && calendarColor && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: calendarColor })
2906
- ] }),
2907
- /* @__PURE__ */ jsxRuntime.jsxs(FieldRow, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" }), label: l.attachments, children: [
2908
- attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: attachments.map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2 text-sm", children: [
2909
- /* @__PURE__ */ jsxRuntime.jsx(
2910
- "a",
2911
- {
2912
- href: a.url,
2913
- target: "_blank",
2914
- rel: "noreferrer",
2915
- className: "min-w-0 flex-1 truncate text-primary hover:underline",
2916
- children: a.title || a.url
2917
- }
2918
- ),
2919
- /* @__PURE__ */ jsxRuntime.jsx(
2920
- "button",
2921
- {
2922
- type: "button",
2923
- className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
2924
- "aria-label": `${l.remove} ${a.title || a.url}`,
2925
- onClick: () => set({ attachments: attachments.filter((_, j) => j !== i) }),
2926
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
2927
- }
2928
- )
2929
- ] }, `${a.url}-${i}`)) }),
2930
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
2931
- /* @__PURE__ */ jsxRuntime.jsx(
2932
- ui.Input,
2933
- {
2934
- type: "url",
2935
- "aria-label": l.attachmentUrlPlaceholder,
2936
- placeholder: l.attachmentUrlPlaceholder,
2937
- className: "h-8 min-w-0 flex-1",
2938
- value: attachUrl,
2939
- onChange: (e) => setAttachUrl(e.target.value),
2940
- "data-testid": "calendar-editor-attachment-url"
2941
- }
2942
- ),
2943
- /* @__PURE__ */ jsxRuntime.jsx(
2944
- ui.Input,
2945
- {
2946
- "aria-label": l.attachmentTitlePlaceholder,
2947
- placeholder: l.attachmentTitlePlaceholder,
2948
- className: "h-8 w-40",
2949
- value: attachTitle,
2950
- onChange: (e) => setAttachTitle(e.target.value)
2951
- }
2952
- ),
2953
- /* @__PURE__ */ jsxRuntime.jsx(
2954
- ui.Button,
2955
- {
2956
- type: "button",
2957
- size: "sm",
2958
- variant: "outline",
2959
- onClick: addAttachment,
2960
- disabled: !attachUrl.trim(),
2961
- children: l.addAttachment
2962
- }
2963
- )
2964
- ] })
2965
- ] })
2966
- ] }),
2967
- (error || shownProblem) && /* @__PURE__ */ jsxRuntime.jsx(
2968
- "p",
2969
- {
2970
- className: "px-1 pt-2 text-sm text-destructive",
2971
- role: "alert",
2972
- "data-testid": "calendar-editor-error",
2973
- children: error || (shownProblem === "invalidRange" ? l.invalidRange : l.titleRequired)
2974
- }
2975
- ),
2976
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-border pt-3", children: [
2977
- mode === "edit" && onDelete && /* @__PURE__ */ jsxRuntime.jsxs(
2978
- ui.Button,
2979
- {
2980
- type: "button",
2981
- variant: "ghost",
2982
- className: "text-destructive hover:text-destructive",
2983
- onClick: onDelete,
2984
- "data-testid": "calendar-editor-delete",
2985
- children: [
2986
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-1 h-4 w-4" }),
2987
- l.delete
2988
- ]
2989
- }
2990
- ),
2991
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
2992
- /* @__PURE__ */ jsxRuntime.jsx(
2993
- ui.Button,
2994
- {
2995
- type: "button",
2996
- variant: "outline",
2997
- onClick: onCancel,
2998
- "data-testid": "calendar-editor-cancel",
2999
- children: l.cancel
3000
- }
3001
- ),
3002
- /* @__PURE__ */ jsxRuntime.jsx(
3003
- ui.Button,
3004
- {
3005
- type: "submit",
3006
- disabled: !!saving || problem === "invalidRange",
3007
- "data-testid": "calendar-editor-save",
3008
- children: saving ? l.saving : l.save
3009
- }
3010
- )
3011
- ] })
3012
- ]
3013
- }
3014
- );
3015
- }
3016
- var partstatLabel = (p, l) => ({
3017
- needs_action: l.needsAction,
3018
- accepted: l.accepted,
3019
- declined: l.declined,
3020
- tentative: l.tentative,
3021
- delegated: l.delegated
3022
- })[p ?? "needs_action"];
3023
- function Row({ icon, children }) {
3024
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
3025
- /* @__PURE__ */ jsxRuntime.jsx(
3026
- "span",
3027
- {
3028
- className: "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground",
3029
- "aria-hidden": true,
3030
- children: icon
3031
- }
3032
- ),
3033
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children })
3034
- ] });
3035
- }
3036
- function EventDetails({
3037
- event,
3038
- timeZone,
3039
- calendarName,
3040
- calendarColor,
3041
- onEdit,
3042
- onDelete,
3043
- onRespond,
3044
- onProposeTime,
3045
- onJoin,
3046
- onOpenMeetingChat,
3047
- onClose,
3048
- canJoin = true,
3049
- labels: labelOverrides,
3050
- className
3051
- }) {
3052
- const l = mergeLabels(labelOverrides);
3053
- const zone = chunkBIXHB4LV_cjs.safeZone(timeZone);
3054
- const color = event.color || calendarColor || "#3b82f6";
3055
- const restricted = !!event.restricted;
3056
- const title = restricted ? l.busy : event.title?.trim() || l.noTitle;
3057
- const eventZone = event.start.time_zone;
3058
- const otherZone = !event.all_day && eventZone && eventZone !== zone ? chunkBIXHB4LV_cjs.safeZone(eventZone, zone) : null;
3059
- const attendees = event.attendees ?? [];
3060
- const counts = attendees.reduce((acc, a) => {
3061
- const k = a.partstat ?? "needs_action";
3062
- acc[k] = (acc[k] ?? 0) + 1;
3063
- return acc;
3064
- }, {});
3065
- const canRespond = !!onRespond && !event.is_organizer && event.my_partstat != null && !restricted;
3066
- const invitee = event.is_organizer === false && event.my_partstat != null;
3067
- const conference = !restricted ? event.conference : null;
3068
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-3", className), "data-testid": "calendar-event-details", children: [
3069
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
3070
- /* @__PURE__ */ jsxRuntime.jsx(
3071
- "span",
3072
- {
3073
- className: "mt-1.5 h-3 w-3 shrink-0 rounded-sm",
3074
- style: { backgroundColor: color },
3075
- "aria-hidden": true
3076
- }
3077
- ),
3078
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3079
- /* @__PURE__ */ jsxRuntime.jsx(
3080
- "h3",
3081
- {
3082
- className: ui.cn(
3083
- "break-words text-lg font-semibold leading-snug",
3084
- event.status === "cancelled" && "line-through"
3085
- ),
3086
- "data-testid": "calendar-details-title",
3087
- children: title
3088
- }
3089
- ),
3090
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", "data-testid": "calendar-details-when", children: formatEventWhen(event, zone) }),
3091
- otherZone && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
3092
- chunkBIXHB4LV_cjs.formatInZone(event.start_utc, otherZone, { hour: "numeric", minute: "2-digit" }),
3093
- " \u2013",
3094
- " ",
3095
- chunkBIXHB4LV_cjs.formatInZone(event.end_utc, otherZone, { hour: "numeric", minute: "2-digit" }),
3096
- " ",
3097
- chunkBIXHB4LV_cjs.zoneCity(otherZone),
3098
- " (",
3099
- chunkBIXHB4LV_cjs.zoneOffsetLabel(otherZone, event.start_utc),
3100
- ")"
3101
- ] })
3102
- ] }),
3103
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center", children: [
3104
- onEdit && !invitee && event.can_edit !== false && !restricted && /* @__PURE__ */ jsxRuntime.jsx(
3105
- ui.Button,
3106
- {
3107
- type: "button",
3108
- variant: "ghost",
3109
- size: "icon",
3110
- className: "h-8 w-8",
3111
- "aria-label": l.edit,
3112
- onClick: onEdit,
3113
- "data-testid": "calendar-details-edit",
3114
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
3115
- }
3116
- ),
3117
- onDelete && !invitee && event.can_edit !== false && !restricted && /* @__PURE__ */ jsxRuntime.jsx(
3118
- ui.Button,
3119
- {
3120
- type: "button",
3121
- variant: "ghost",
3122
- size: "icon",
3123
- className: "h-8 w-8",
3124
- "aria-label": l.delete,
3125
- onClick: onDelete,
3126
- "data-testid": "calendar-details-delete",
3127
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
3128
- }
3129
- ),
3130
- onDelete && invitee && /* @__PURE__ */ jsxRuntime.jsx(
3131
- ui.Button,
3132
- {
3133
- type: "button",
3134
- variant: "ghost",
3135
- size: "icon",
3136
- className: "h-8 w-8",
3137
- "aria-label": l.removeFromCalendar,
3138
- title: l.removeFromCalendar,
3139
- onClick: onDelete,
3140
- "data-testid": "calendar-details-remove",
3141
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
3142
- }
3143
- ),
3144
- onClose && /* @__PURE__ */ jsxRuntime.jsx(
3145
- ui.Button,
3146
- {
3147
- type: "button",
3148
- variant: "ghost",
3149
- size: "icon",
3150
- className: "h-8 w-8",
3151
- "aria-label": l.cancel,
3152
- onClick: onClose,
3153
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
3154
- }
3155
- )
3156
- ] })
3157
- ] }),
3158
- event.is_recurring && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Repeat, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.recurring }) }),
3159
- conference?.url && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3160
- /* @__PURE__ */ jsxRuntime.jsx(
3161
- ui.Button,
3162
- {
3163
- type: "button",
3164
- size: "sm",
3165
- disabled: !canJoin,
3166
- onClick: () => onJoin ? onJoin() : window.open(conference.url ?? "", "_blank", "noopener"),
3167
- "data-testid": "calendar-details-join",
3168
- children: isWebinarConference(conference) ? l.joinWebinar : `${l.join}${conference.type === "arbi" ? ` ${l.arbiCall}` : ""}`
3169
- }
3170
- ),
3171
- conference.type === "arbi" && onOpenMeetingChat && /* @__PURE__ */ jsxRuntime.jsx(
3172
- ui.Button,
3173
- {
3174
- type: "button",
3175
- size: "sm",
3176
- variant: "outline",
3177
- onClick: onOpenMeetingChat,
3178
- "data-testid": "calendar-details-meeting-chat",
3179
- children: l.openMeetingChat
3180
- }
3181
- ),
3182
- conference.type === "external" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate text-xs text-muted-foreground", children: conference.url })
3183
- ] }) }),
3184
- !restricted && event.location && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words", children: event.location }) }),
3185
- calendarName && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarDays, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: calendarName }) }),
3186
- restricted && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.private }) }),
3187
- !restricted && (event.organizer || attendees.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", "data-testid": "calendar-details-attendees", children: [
3188
- attendees.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
3189
- attendees.length,
3190
- " \xB7",
3191
- " ",
3192
- Object.entries(counts).map(([k, n]) => `${n} ${partstatLabel(k, l).toLowerCase()}`).join(", ")
3193
- ] }),
3194
- event.organizer && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "truncate", children: [
3195
- event.organizer.name || event.organizer.email,
3196
- " ",
3197
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
3198
- "\xB7 ",
3199
- l.organizer
3200
- ] })
3201
- ] }),
3202
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: attendees.filter((a) => !a.is_organizer).map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs(
3203
- "li",
3204
- {
3205
- className: "flex items-center gap-1.5",
3206
- "data-testid": "calendar-details-attendee",
3207
- "data-partstat": a.partstat ?? "needs_action",
3208
- "data-kind": a.kind ?? "individual",
3209
- children: [
3210
- a.partstat === "accepted" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleCheck, { className: "h-3.5 w-3.5 text-green-600", "aria-label": l.accepted }) : a.partstat === "declined" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, { className: "h-3.5 w-3.5 text-destructive", "aria-label": l.declined }) : /* @__PURE__ */ jsxRuntime.jsx(
3211
- lucideReact.Clock,
3212
- {
3213
- className: "h-3.5 w-3.5 text-muted-foreground",
3214
- "aria-label": partstatLabel(a.partstat, l)
3215
- }
3216
- ),
3217
- (a.kind === "room" || a.kind === "resource") && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DoorOpen, { className: "h-3.5 w-3.5 text-muted-foreground", "aria-label": l.room }),
3218
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: a.name || a.email }),
3219
- a.role === "optional" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
3220
- "(",
3221
- l.optional,
3222
- ")"
3223
- ] }),
3224
- /* @__PURE__ */ jsxRuntime.jsx(
3225
- "span",
3226
- {
3227
- className: ui.cn(
3228
- "ml-auto shrink-0 rounded-full px-1.5 py-0.5 text-[10px]",
3229
- a.partstat === "accepted" ? "bg-green-500/15 text-green-700 dark:text-green-400" : a.partstat === "declined" ? "bg-destructive/15 text-destructive" : "bg-muted text-muted-foreground"
3230
- ),
3231
- children: partstatLabel(a.partstat, l)
3232
- }
3233
- )
3234
- ]
3235
- },
3236
- `${a.email ?? a.user_id ?? i}`
3237
- )) })
3238
- ] }) }),
3239
- !restricted && event.description && /* @__PURE__ */ jsxRuntime.jsx(
3240
- "div",
3241
- {
3242
- className: "whitespace-pre-wrap break-words rounded-md bg-muted/40 p-2 text-sm",
3243
- "data-testid": "calendar-details-description",
3244
- children: event.description
3245
- }
3246
- ),
3247
- !restricted && (event.attachments?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-0.5", children: event.attachments?.map((a, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
3248
- "a",
3249
- {
3250
- href: a.url,
3251
- target: "_blank",
3252
- rel: "noreferrer",
3253
- className: "text-primary hover:underline",
3254
- children: a.title || a.url
3255
- }
3256
- ) }, `${a.url}-${i}`)) }) }),
3257
- !restricted && (event.categories?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: event.categories?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-muted px-2 py-0.5 text-xs", children: c }, c)) }) }),
3258
- !restricted && (event.reminders?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: "h-4 w-4" }), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: event.reminders?.map((r) => formatReminder(r.minutes_before)).join(", ") }) }),
3259
- canRespond && /* @__PURE__ */ jsxRuntime.jsxs(
3260
- "div",
3261
- {
3262
- className: "flex flex-wrap items-center gap-2 border-t border-border pt-3",
3263
- "data-testid": "calendar-details-rsvp",
3264
- children: [
3265
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: l.going }),
3266
- [
3267
- ["accepted", l.accept],
3268
- ["declined", l.decline],
3269
- ["tentative", l.maybe]
3270
- ].map(([p, label]) => /* @__PURE__ */ jsxRuntime.jsx(
3271
- ui.Button,
3272
- {
3273
- type: "button",
3274
- size: "sm",
3275
- variant: event.my_partstat === p ? "default" : "outline",
3276
- "aria-pressed": event.my_partstat === p,
3277
- onClick: () => onRespond?.(p),
3278
- "data-testid": `calendar-details-rsvp-${p}`,
3279
- children: label
3280
- },
3281
- p
3282
- )),
3283
- onProposeTime && /* @__PURE__ */ jsxRuntime.jsx(
3284
- ui.Button,
3285
- {
3286
- type: "button",
3287
- size: "sm",
3288
- variant: "ghost",
3289
- onClick: onProposeTime,
3290
- "data-testid": "calendar-details-propose",
3291
- children: l.proposeNewTime
3292
- }
3293
- )
3294
- ]
3295
- }
3296
- )
3297
- ] });
3298
- }
3299
- function ScopeDialog({
3300
- open,
3301
- action,
3302
- onChoose,
3303
- onCancel,
3304
- allowFollowing = true,
3305
- labels: labelOverrides
3306
- }) {
3307
- const l = mergeLabels(labelOverrides);
3308
- const [scope, setScope] = react.useState("this");
3309
- const options = [
3310
- ["this", l.scopeThis],
3311
- ...allowFollowing ? [["following", l.scopeFollowing]] : [],
3312
- ["all", l.scopeAll]
3313
- ];
3314
- const title = action === "edit" ? l.scopeEditTitle : action === "respond" ? l.scopeRespondTitle : l.scopeDeleteTitle;
3315
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open, onOpenChange: (o) => !o && onCancel(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "max-w-sm", "data-testid": "calendar-scope-dialog", children: [
3316
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
3317
- /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: title }),
3318
- /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { className: "sr-only", children: title })
3319
- ] }),
3320
- /* @__PURE__ */ jsxRuntime.jsxs(
3321
- "form",
3322
- {
3323
- onSubmit: (e) => {
3324
- e.preventDefault();
3325
- onChoose(scope);
3326
- },
3327
- children: [
3328
- /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "space-y-2 py-2", children: [
3329
- /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "sr-only", children: title }),
3330
- options.map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex cursor-pointer items-center gap-2 text-sm", children: [
3331
- /* @__PURE__ */ jsxRuntime.jsx(
3332
- "input",
3333
- {
3334
- type: "radio",
3335
- name: "calendar-scope",
3336
- value,
3337
- checked: scope === value,
3338
- onChange: () => setScope(value),
3339
- "data-testid": `calendar-scope-${value}`
3340
- }
3341
- ),
3342
- label
3343
- ] }, value))
3344
- ] }),
3345
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
3346
- /* @__PURE__ */ jsxRuntime.jsx(
3347
- ui.Button,
3348
- {
3349
- type: "button",
3350
- variant: "outline",
3351
- onClick: onCancel,
3352
- "data-testid": "calendar-scope-cancel",
3353
- children: l.cancel
3354
- }
3355
- ),
3356
- /* @__PURE__ */ jsxRuntime.jsx(
3357
- ui.Button,
3358
- {
3359
- type: "submit",
3360
- variant: action === "delete" ? "destructive" : "default",
3361
- "data-testid": "calendar-scope-ok",
3362
- children: action === "delete" ? l.delete : action === "respond" ? l.send : l.save
3363
- }
3364
- )
3365
- ] })
3366
- ]
3367
- }
3368
- )
3369
- ] }) });
3370
- }
3371
-
3372
- // src/calendar/scheduling.ts
3373
- var pad2 = (n) => String(n).padStart(2, "0");
3374
- function dayWindow(date, zone, startHour = 7, endHour = 20) {
3375
- const startMs = chunkBIXHB4LV_cjs.wallToEpochMs(`${date}T${pad2(startHour)}:00`, zone);
3376
- const endMs = endHour >= 24 ? chunkBIXHB4LV_cjs.wallToEpochMs(`${date}T23:59`, zone) + 6e4 : chunkBIXHB4LV_cjs.wallToEpochMs(`${date}T${pad2(endHour)}:00`, zone);
3377
- return { startMs, endMs };
3378
- }
3379
- function placeIntervals(intervals, win) {
3380
- const span = win.endMs - win.startMs;
3381
- if (span <= 0) return [];
3382
- const out = [];
3383
- for (const i of intervals) {
3384
- const s = Math.max(Date.parse(i.startUtc), win.startMs);
3385
- const e = Math.min(Date.parse(i.endUtc), win.endMs);
3386
- if (!(e > s)) continue;
3387
- out.push({
3388
- startMs: s,
3389
- endMs: e,
3390
- leftPct: (s - win.startMs) / span * 100,
3391
- widthPct: (e - s) / span * 100
3392
- });
3393
- }
3394
- return out.sort((a, b) => a.startMs - b.startMs);
3395
- }
3396
- function outsideIntervals(working, win) {
3397
- const span = win.endMs - win.startMs;
3398
- const placed = placeIntervals(working, win);
3399
- const gaps = [];
3400
- let cursor = win.startMs;
3401
- for (const w of placed) {
3402
- if (w.startMs > cursor) gaps.push(mk(cursor, w.startMs));
3403
- cursor = Math.max(cursor, w.endMs);
3404
- }
3405
- if (cursor < win.endMs) gaps.push(mk(cursor, win.endMs));
3406
- return gaps;
3407
- function mk(s, e) {
3408
- return {
3409
- startMs: s,
3410
- endMs: e,
3411
- leftPct: (s - win.startMs) / span * 100,
3412
- widthPct: (e - s) / span * 100
3413
- };
3414
- }
3415
- }
3416
- function hourTicks(date, zone, startHour, endHour) {
3417
- const win = dayWindow(date, zone, startHour, endHour);
3418
- const span = win.endMs - win.startMs;
3419
- const ticks = [];
3420
- for (let h = startHour; h < endHour; h++) {
3421
- const ms = chunkBIXHB4LV_cjs.wallToEpochMs(`${date}T${pad2(h)}:00`, zone);
3422
- ticks.push({ hour: h, leftPct: (ms - win.startMs) / span * 100 });
3423
- }
3424
- return ticks;
3425
- }
3426
- function SchedulingAssistant({
3427
- date,
3428
- timeZone,
3429
- rows,
3430
- selection,
3431
- dayStartHour = 7,
3432
- dayEndHour = 20,
3433
- loading,
3434
- suggestions,
3435
- finding,
3436
- onFindTime,
3437
- onPickSuggestion,
3438
- onDateChange,
3439
- labels: labelOverrides,
3440
- className
3441
- }) {
3442
- const l = mergeLabels(labelOverrides);
3443
- const zone = chunkBIXHB4LV_cjs.safeZone(timeZone);
3444
- const win = dayWindow(date, zone, dayStartHour, dayEndHour);
3445
- const ticks = hourTicks(date, zone, dayStartHour, dayEndHour);
3446
- const sel = selection ? placeIntervals([selection], win)[0] : void 0;
3447
- const time = (iso) => chunkBIXHB4LV_cjs.formatInZone(iso, zone, { hour: "numeric", minute: "2-digit" });
3448
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-2", className), "data-testid": "calendar-scheduling", children: [
3449
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3450
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: l.schedulingAssistant }),
3451
- onDateChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
3452
- /* @__PURE__ */ jsxRuntime.jsx(
3453
- ui.Button,
3454
- {
3455
- type: "button",
3456
- variant: "ghost",
3457
- size: "icon",
3458
- className: "h-7 w-7",
3459
- "aria-label": l.previous,
3460
- onClick: () => onDateChange(chunkBIXHB4LV_cjs.addDays(date, -1)),
3461
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
3462
- }
3463
- ),
3464
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", "data-testid": "calendar-scheduling-date", children: chunkBIXHB4LV_cjs.formatPlainDate(date, { weekday: "short", day: "numeric", month: "short" }) }),
3465
- /* @__PURE__ */ jsxRuntime.jsx(
3466
- ui.Button,
3467
- {
3468
- type: "button",
3469
- variant: "ghost",
3470
- size: "icon",
3471
- className: "h-7 w-7",
3472
- "aria-label": l.next,
3473
- onClick: () => onDateChange(chunkBIXHB4LV_cjs.addDays(date, 1)),
3474
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
3475
- }
3476
- )
3477
- ] })
3478
- ] }),
3479
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("rounded-md border border-border", loading && "opacity-60"), children: [
3480
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex border-b border-border text-[10px] text-muted-foreground", children: [
3481
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-32 shrink-0 sm:w-40" }),
3482
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-5 flex-1", children: ticks.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
3483
- "span",
3484
- {
3485
- className: "absolute top-0.5 -translate-x-1/2",
3486
- style: { left: `${t.leftPct}%` },
3487
- children: t.hour
3488
- },
3489
- t.hour
3490
- )) })
3491
- ] }),
3492
- rows.map((row) => /* @__PURE__ */ jsxRuntime.jsxs(
3493
- "div",
3494
- {
3495
- className: "flex items-stretch border-b border-border last:border-b-0",
3496
- "data-testid": "calendar-scheduling-row",
3497
- "data-known": row.known,
3498
- children: [
3499
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-32 shrink-0 items-center gap-1.5 truncate px-2 py-1 text-xs sm:w-40", children: [
3500
- row.kind === "room" ? /* @__PURE__ */ jsxRuntime.jsx(
3501
- lucideReact.DoorOpen,
3502
- {
3503
- className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
3504
- "aria-label": l.room
3505
- }
3506
- ) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": true }),
3507
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", title: row.label, children: row.label })
3508
- ] }),
3509
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-7 flex-1 overflow-hidden", children: [
3510
- !row.known ? /* @__PURE__ */ jsxRuntime.jsx(
3511
- "div",
3512
- {
3513
- className: "absolute inset-0 flex items-center justify-center bg-[repeating-linear-gradient(45deg,transparent,transparent_4px,hsl(var(--muted))_4px,hsl(var(--muted))_8px)] text-[10px] text-muted-foreground",
3514
- title: l.unknownAvailability,
3515
- children: l.unknownAvailability
3516
- }
3517
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3518
- row.working && outsideIntervals(row.working, win).map((g, i) => /* @__PURE__ */ jsxRuntime.jsx(
3519
- "div",
3520
- {
3521
- className: "absolute inset-y-0 bg-muted",
3522
- style: { left: `${g.leftPct}%`, width: `${g.widthPct}%` },
3523
- title: l.outsideWorkingHours,
3524
- "data-testid": "calendar-scheduling-outside"
3525
- },
3526
- `o${i}`
3527
- )),
3528
- placeIntervals(row.busy, win).map((b, i) => {
3529
- const src = row.busy.find(
3530
- (x) => Math.max(Date.parse(x.startUtc), win.startMs) === b.startMs && Math.min(Date.parse(x.endUtc), win.endMs) === b.endMs
3531
- );
3532
- const tentative = src?.showAs === "tentative";
3533
- const oof = src?.showAs === "oof";
3534
- return /* @__PURE__ */ jsxRuntime.jsx(
3535
- "div",
3536
- {
3537
- className: ui.cn(
3538
- "absolute inset-y-1 rounded-sm",
3539
- oof ? "bg-purple-500/70" : tentative ? "bg-primary/35" : "bg-primary/75"
3540
- ),
3541
- style: { left: `${b.leftPct}%`, width: `${Math.max(b.widthPct, 0.5)}%` },
3542
- title: `${src?.title ? `${src.title} \xB7 ` : ""}${time(new Date(b.startMs).toISOString())} \u2013 ${time(new Date(b.endMs).toISOString())}`,
3543
- "data-testid": "calendar-scheduling-busy"
3544
- },
3545
- `b${i}`
3546
- );
3547
- })
3548
- ] }),
3549
- sel && /* @__PURE__ */ jsxRuntime.jsx(
3550
- "div",
3551
- {
3552
- className: "pointer-events-none absolute inset-y-0 border-x-2 border-green-600 bg-green-500/15",
3553
- style: { left: `${sel.leftPct}%`, width: `${sel.widthPct}%` },
3554
- "aria-hidden": true
3555
- }
3556
- )
3557
- ] })
3558
- ]
3559
- },
3560
- row.id
3561
- ))
3562
- ] }),
3563
- onFindTime && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
3564
- /* @__PURE__ */ jsxRuntime.jsxs(
3565
- ui.Button,
3566
- {
3567
- type: "button",
3568
- size: "sm",
3569
- variant: "outline",
3570
- onClick: onFindTime,
3571
- disabled: finding,
3572
- "data-testid": "calendar-find-time",
3573
- children: [
3574
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "mr-1 h-4 w-4" }),
3575
- finding ? l.findingTimes : l.findATime
3576
- ]
3577
- }
3578
- ),
3579
- suggestions && suggestions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: l.noSuggestions }),
3580
- suggestions && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", "data-testid": "calendar-suggestions", children: suggestions.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
3581
- "button",
3582
- {
3583
- type: "button",
3584
- onClick: () => onPickSuggestion?.(s),
3585
- className: "rounded-md border border-border px-2 py-1 text-left text-xs hover:bg-muted",
3586
- "data-testid": "calendar-suggestion",
3587
- children: [
3588
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "font-medium", children: [
3589
- chunkBIXHB4LV_cjs.formatInZone(s.startUtc, zone, {
3590
- weekday: "short",
3591
- day: "numeric",
3592
- month: "short"
3593
- }),
3594
- " ",
3595
- time(s.startUtc),
3596
- " \u2013 ",
3597
- time(s.endUtc)
3598
- ] }),
3599
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: s.unavailable.length === 0 ? l.everyoneFree : `${s.unavailable.length} ${l.unavailableCount}` })
3600
- ]
3601
- },
3602
- s.startUtc
3603
- )) })
3604
- ] })
3605
- ] });
3606
- }
3607
- function RoomFinder({
3608
- rooms,
3609
- loading,
3610
- minCapacity,
3611
- feature,
3612
- onFiltersChange,
3613
- addedEmails,
3614
- onAdd,
3615
- labels: labelOverrides,
3616
- className
3617
- }) {
3618
- const l = mergeLabels(labelOverrides);
3619
- const added = new Set(addedEmails.map((e) => e.toLowerCase()));
3620
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-2", className), "data-testid": "calendar-room-finder", children: [
3621
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3622
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: l.findRoom }),
3623
- /* @__PURE__ */ jsxRuntime.jsx(
3624
- ui.Input,
3625
- {
3626
- type: "number",
3627
- min: 1,
3628
- className: "h-8 w-28",
3629
- placeholder: l.minCapacity,
3630
- "aria-label": l.minCapacity,
3631
- value: minCapacity ?? "",
3632
- onChange: (e) => onFiltersChange({
3633
- minCapacity: e.target.value ? Math.max(1, Number(e.target.value)) : null,
3634
- feature
3635
- }),
3636
- "data-testid": "calendar-room-capacity"
3637
- }
3638
- ),
3639
- /* @__PURE__ */ jsxRuntime.jsx(
3640
- ui.Input,
3641
- {
3642
- className: "h-8 w-32",
3643
- placeholder: l.featureFilter,
3644
- "aria-label": l.featureFilter,
3645
- value: feature,
3646
- onChange: (e) => onFiltersChange({ minCapacity, feature: e.target.value }),
3647
- "data-testid": "calendar-room-feature"
3648
- }
3649
- )
3650
- ] }),
3651
- /* @__PURE__ */ jsxRuntime.jsxs(
3652
- "ul",
3653
- {
3654
- className: ui.cn(
3655
- "divide-y divide-border rounded-md border border-border",
3656
- loading && "opacity-60"
3657
- ),
3658
- children: [
3659
- rooms.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-xs text-muted-foreground", children: l.noRooms }),
3660
- rooms.map((r) => {
3661
- const isAdded = added.has(r.email.toLowerCase());
3662
- return /* @__PURE__ */ jsxRuntime.jsxs(
3663
- "li",
3664
- {
3665
- className: "flex items-center gap-2 px-3 py-1.5 text-sm",
3666
- "data-testid": "calendar-room",
3667
- "data-room-email": r.email,
3668
- children: [
3669
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DoorOpen, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3670
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3671
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate font-medium", children: r.name }),
3672
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-2 text-xs text-muted-foreground", children: [
3673
- r.capacity != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-0.5", children: [
3674
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "h-3 w-3", "aria-hidden": true }),
3675
- r.capacity
3676
- ] }),
3677
- (r.building || r.floor) && /* @__PURE__ */ jsxRuntime.jsx("span", { children: [r.building, r.floor].filter(Boolean).join(" \xB7 ") }),
3678
- (r.features ?? []).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { children: r.features?.join(", ") })
3679
- ] })
3680
- ] }),
3681
- r.free != null && /* @__PURE__ */ jsxRuntime.jsx(
3682
- "span",
3683
- {
3684
- className: ui.cn(
3685
- "rounded-full px-2 py-0.5 text-xs",
3686
- r.free ? "bg-green-500/15 text-green-700 dark:text-green-400" : "bg-destructive/15 text-destructive"
3687
- ),
3688
- "data-testid": "calendar-room-availability",
3689
- children: r.free ? l.roomFree : l.roomBusy
3690
- }
3691
- ),
3692
- /* @__PURE__ */ jsxRuntime.jsx(
3693
- ui.Button,
3694
- {
3695
- type: "button",
3696
- size: "sm",
3697
- variant: "outline",
3698
- disabled: isAdded,
3699
- onClick: () => onAdd(r),
3700
- "data-testid": "calendar-room-add",
3701
- children: isAdded ? l.roomAdded : l.addRoom
3702
- }
3703
- )
3704
- ]
3705
- },
3706
- r.id
3707
- );
3708
- })
3709
- ]
3710
- }
3711
- )
3712
- ] });
3713
- }
3714
- var mondayFirstName = (day) => chunkBIXHB4LV_cjs.formatPlainDate(`2024-01-0${day + 1}`, { weekday: "long" });
3715
- var sundayFirstName = (day) => chunkBIXHB4LV_cjs.formatPlainDate(day === 0 ? "2023-12-31" : `2024-01-0${day}`, { weekday: "long" });
3716
- var VIEWS = ["day", "work_week", "week", "month", "agenda", "year"];
3717
- var DURATIONS = [15, 30, 45, 60, 90, 120];
3718
- var viewName = (v, l) => ({
3719
- day: l.day,
3720
- week: l.week,
3721
- work_week: l.workWeek,
3722
- month: l.month,
3723
- agenda: l.agenda,
3724
- year: l.year
3725
- })[v];
3726
- function Field({
3727
- label,
3728
- htmlFor,
3729
- children
3730
- }) {
3731
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-1.5 sm:grid-cols-[12rem_1fr] sm:items-center", children: [
3732
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor, className: "text-sm font-medium", children: label }),
3733
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children })
3734
- ] });
3735
- }
3736
- function CalendarSettingsForm({
3737
- value,
3738
- onChange,
3739
- onSave,
3740
- onCancel,
3741
- calendars,
3742
- zones,
3743
- saving,
3744
- error,
3745
- labels: labelOverrides,
3746
- className
3747
- }) {
3748
- const l = mergeLabels(labelOverrides);
3749
- const uid = react.useId();
3750
- const set = (patch) => onChange({ ...value, ...patch });
3751
- const hoursFor = (day) => value.working_hours.find((h) => h.day === day);
3752
- const setHours = (day, patch) => {
3753
- const rest = value.working_hours.filter((h) => h.day !== day);
3754
- if (patch === null) return set({ working_hours: rest });
3755
- const cur = hoursFor(day) ?? { day, start: "09:00", end: "17:00" };
3756
- set({ working_hours: [...rest, { ...cur, ...patch }].sort((a, b) => a.day - b.day) });
3757
- };
3758
- const overlays = value.overlays ?? [];
3759
- const toggleOverlay = (o) => set({ overlays: overlays.includes(o) ? overlays.filter((x) => x !== o) : [...overlays, o] });
3760
- const writable = (calendars ?? []).filter((c) => c.canWrite && !c.locked);
3761
- return /* @__PURE__ */ jsxRuntime.jsxs(
3762
- "form",
3763
- {
3764
- className: ui.cn("space-y-5", className),
3765
- onSubmit: (e) => {
3766
- e.preventDefault();
3767
- onSave();
3768
- },
3769
- "data-testid": "calendar-settings-form",
3770
- "aria-label": l.settingsTitle,
3771
- children: [
3772
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.timeZone, children: /* @__PURE__ */ jsxRuntime.jsx(
3773
- TimeZonePicker,
3774
- {
3775
- value: value.time_zone,
3776
- zones,
3777
- labels: labelOverrides,
3778
- className: "w-full sm:w-80",
3779
- onChange: (z) => set({ time_zone: z })
3780
- }
3781
- ) }),
3782
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.secondaryTimeZone, children: /* @__PURE__ */ jsxRuntime.jsx(
3783
- TimeZonePicker,
3784
- {
3785
- value: value.secondary_time_zone ?? null,
3786
- zones,
3787
- allowNone: true,
3788
- ariaLabel: l.secondaryTimeZone,
3789
- labels: labelOverrides,
3790
- className: "w-full sm:w-80",
3791
- onChange: (z) => set({ secondary_time_zone: z }),
3792
- onClear: () => set({ secondary_time_zone: null })
3793
- }
3794
- ) }),
3795
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.weekStart, htmlFor: `${uid}-week-start`, children: /* @__PURE__ */ jsxRuntime.jsx(
3796
- NativeSelect,
3797
- {
3798
- id: `${uid}-week-start`,
3799
- value: value.week_start,
3800
- onChange: (e) => set({ week_start: Number(e.target.value) }),
3801
- "data-testid": "calendar-settings-week-start",
3802
- children: [1, 0, 6].map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d, children: sundayFirstName(d) }, d))
3803
- }
3804
- ) }),
3805
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.defaultView, htmlFor: `${uid}-view`, children: /* @__PURE__ */ jsxRuntime.jsx(
3806
- NativeSelect,
3807
- {
3808
- id: `${uid}-view`,
3809
- value: value.default_view,
3810
- onChange: (e) => set({ default_view: e.target.value }),
3811
- "data-testid": "calendar-settings-default-view",
3812
- children: VIEWS.map((v) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: v, children: viewName(v, l) }, v))
3813
- }
3814
- ) }),
3815
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.defaultDuration, htmlFor: `${uid}-duration`, children: /* @__PURE__ */ jsxRuntime.jsx(
3816
- NativeSelect,
3817
- {
3818
- id: `${uid}-duration`,
3819
- value: value.default_duration_minutes,
3820
- onChange: (e) => set({ default_duration_minutes: Number(e.target.value) }),
3821
- "data-testid": "calendar-settings-duration",
3822
- children: Array.from(/* @__PURE__ */ new Set([...DURATIONS, value.default_duration_minutes])).sort((a, b) => a - b).map((m) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: m, children: `${m} ${l.minutes}` }, m))
3823
- }
3824
- ) }),
3825
- writable.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.defaultCalendar, htmlFor: `${uid}-calendar`, children: /* @__PURE__ */ jsxRuntime.jsxs(
3826
- NativeSelect,
3827
- {
3828
- id: `${uid}-calendar`,
3829
- value: value.default_calendar_id ?? "",
3830
- onChange: (e) => set({ default_calendar_id: e.target.value || null }),
3831
- "data-testid": "calendar-settings-default-calendar",
3832
- children: [
3833
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014" }),
3834
- writable.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.id, children: c.name ?? c.id }, c.id))
3835
- ]
3836
- }
3837
- ) }),
3838
- /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "space-y-2", children: [
3839
- /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "pb-1 text-sm font-medium", children: l.workingHours }),
3840
- [0, 1, 2, 3, 4, 5, 6].map((day) => {
3841
- const h = hoursFor(day);
3842
- return /* @__PURE__ */ jsxRuntime.jsxs(
3843
- "div",
3844
- {
3845
- className: "flex flex-wrap items-center gap-2 text-sm",
3846
- "data-testid": `calendar-settings-hours-${day}`,
3847
- children: [
3848
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex w-36 items-center gap-2", children: [
3849
- /* @__PURE__ */ jsxRuntime.jsx(
3850
- "input",
3851
- {
3852
- type: "checkbox",
3853
- checked: !!h,
3854
- onChange: (e) => setHours(day, e.target.checked ? {} : null)
3855
- }
3856
- ),
3857
- mondayFirstName(day)
3858
- ] }),
3859
- h && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3860
- /* @__PURE__ */ jsxRuntime.jsx(
3861
- ui.Input,
3862
- {
3863
- type: "time",
3864
- className: "h-8 w-28",
3865
- "aria-label": `${mondayFirstName(day)} ${l.start}`,
3866
- value: h.start,
3867
- onChange: (e) => e.target.value && setHours(day, { start: e.target.value })
3868
- }
3869
- ),
3870
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2013" }),
3871
- /* @__PURE__ */ jsxRuntime.jsx(
3872
- ui.Input,
3873
- {
3874
- type: "time",
3875
- className: "h-8 w-28",
3876
- "aria-label": `${mondayFirstName(day)} ${l.end}`,
3877
- value: h.end === "24:00" ? "23:59" : h.end,
3878
- onChange: (e) => e.target.value && setHours(day, { end: e.target.value })
3879
- }
3880
- )
3881
- ] })
3882
- ]
3883
- },
3884
- day
3885
- );
3886
- })
3887
- ] }),
3888
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [
3889
- ["show_week_numbers", l.showWeekNumbers],
3890
- ["show_declined", l.showDeclined]
3891
- ].map(([key, label]) => /* @__PURE__ */ jsxRuntime.jsxs(
3892
- "label",
3893
- {
3894
- className: "flex items-center justify-between gap-4 text-sm sm:justify-start",
3895
- children: [
3896
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sm:w-48", children: label }),
3897
- /* @__PURE__ */ jsxRuntime.jsx(
3898
- ui.Switch,
3899
- {
3900
- checked: !!value[key],
3901
- onCheckedChange: (on) => set({ [key]: on }),
3902
- "aria-label": label,
3903
- "data-testid": `calendar-settings-${key}`
3904
- }
3905
- )
3906
- ]
3907
- },
3908
- key
3909
- )) }),
3910
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.autoAddInvitations, htmlFor: `${uid}-auto-add`, children: /* @__PURE__ */ jsxRuntime.jsxs(
3911
- NativeSelect,
3912
- {
3913
- id: `${uid}-auto-add`,
3914
- value: value.auto_add_invitations ?? "all",
3915
- onChange: (e) => set({
3916
- auto_add_invitations: e.target.value
3917
- }),
3918
- "data-testid": "calendar-settings-auto-add",
3919
- children: [
3920
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "all", children: l.autoAddAll }),
3921
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "known", children: l.autoAddKnown }),
3922
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "none", children: l.autoAddNone })
3923
- ]
3924
- }
3925
- ) }),
3926
- /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "space-y-1.5", children: [
3927
- /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "pb-1 text-sm font-medium", children: l.overlays }),
3928
- [
3929
- ["facts", l.facts],
3930
- ["workflows", l.workflows],
3931
- ["tasks", l.tasks]
3932
- ].map(([o, label]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
3933
- /* @__PURE__ */ jsxRuntime.jsx(
3934
- "input",
3935
- {
3936
- type: "checkbox",
3937
- checked: overlays.includes(o),
3938
- onChange: () => toggleOverlay(o),
3939
- "data-testid": `calendar-settings-overlay-${o}`
3940
- }
3941
- ),
3942
- label
3943
- ] }, o))
3944
- ] }),
3945
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
3946
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-decline`, className: "text-sm font-medium", children: l.declineMessage }),
3947
- /* @__PURE__ */ jsxRuntime.jsx(
3948
- ui.Textarea,
3949
- {
3950
- id: `${uid}-decline`,
3951
- rows: 2,
3952
- maxLength: 1e3,
3953
- value: value.decline_message ?? "",
3954
- onChange: (e) => set({ decline_message: e.target.value || null })
3955
- }
3956
- )
3957
- ] }),
3958
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error }),
3959
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
3960
- onCancel && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", variant: "outline", onClick: onCancel, children: l.cancel }),
3961
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: !!saving, "data-testid": "calendar-settings-save", children: saving ? l.saving : l.save })
3962
- ] })
3963
- ]
3964
- }
3965
- );
3966
- }
3967
-
3968
- // src/calendar/print-layout.ts
3969
- function printRange(view, date, weekStart = 1, agendaDays = 30) {
3970
- if (view === "day") return { from: date, to: chunkBIXHB4LV_cjs.addDays(date, 1) };
3971
- if (view === "agenda") return { from: date, to: chunkBIXHB4LV_cjs.addDays(date, agendaDays) };
3972
- if (view === "week") {
3973
- const from2 = chunkBIXHB4LV_cjs.startOfWeek(date, weekStart);
3974
- return { from: from2, to: chunkBIXHB4LV_cjs.addDays(from2, 7) };
3975
- }
3976
- const first = `${date.slice(0, 8)}01`;
3977
- const from = chunkBIXHB4LV_cjs.startOfWeek(first, weekStart);
3978
- const nextMonth = chunkBIXHB4LV_cjs.addMonths(first, 1);
3979
- const lead = (chunkBIXHB4LV_cjs.dayOfWeekSun0(nextMonth) - weekStart + 7) % 7;
3980
- const to = lead === 0 ? nextMonth : chunkBIXHB4LV_cjs.addDays(nextMonth, 7 - lead);
3981
- return { from, to };
3982
- }
3983
- function eachDay(from, to) {
3984
- const out = [];
3985
- for (let d = from; d < to; d = chunkBIXHB4LV_cjs.addDays(d, 1)) out.push(d);
3986
- return out;
3987
- }
3988
- function eventDays(e, zone) {
3989
- if (e.all_day) {
3990
- const start = e.start.date ?? chunkBIXHB4LV_cjs.utcToDate(e.start_utc, "UTC");
3991
- const endExcl = e.end.date ?? chunkBIXHB4LV_cjs.addDays(start, 1);
3992
- return eachDay(start, endExcl > start ? endExcl : chunkBIXHB4LV_cjs.addDays(start, 1));
3993
- }
3994
- const startDay = chunkBIXHB4LV_cjs.utcToDate(e.start_utc, zone);
3995
- const lastInstant = new Date(
3996
- Math.max(new Date(e.start_utc).getTime(), new Date(e.end_utc).getTime() - 1)
3997
- );
3998
- const endDay = chunkBIXHB4LV_cjs.utcToDate(lastInstant, zone);
3999
- return eachDay(startDay, chunkBIXHB4LV_cjs.addDays(endDay, 1));
4000
- }
4001
- function timeLabel(e, day, zone) {
4002
- if (e.all_day) return "All day";
4003
- const fmt = new Intl.DateTimeFormat(void 0, {
4004
- timeZone: zone,
4005
- hour: "numeric",
4006
- minute: "2-digit"
4007
- });
4008
- const sDay = chunkBIXHB4LV_cjs.utcToDate(e.start_utc, zone);
4009
- const eDay = chunkBIXHB4LV_cjs.utcToDate(new Date(new Date(e.end_utc).getTime() - 1), zone);
4010
- const s = sDay === day ? fmt.format(new Date(e.start_utc)) : "\u2026";
4011
- const en = eDay === day ? fmt.format(new Date(e.end_utc)) : "\u2026";
4012
- return `${s} \u2013 ${en}`;
4013
- }
4014
- function eventsByDay(events, zone, from, to) {
4015
- const map = /* @__PURE__ */ new Map();
4016
- for (const e of events) {
4017
- for (const d of eventDays(e, zone)) {
4018
- if (d < from || d >= to) continue;
4019
- const list = map.get(d) ?? [];
4020
- list.push(e);
4021
- map.set(d, list);
4022
- }
4023
- }
4024
- for (const list of map.values())
4025
- list.sort(
4026
- (a, b) => Number(b.all_day) - Number(a.all_day) || new Date(a.start_utc).getTime() - new Date(b.start_utc).getTime() || a.title.localeCompare(b.title)
4027
- );
4028
- return map;
4029
- }
4030
- function heading(view, date, from, to) {
4031
- const last = chunkBIXHB4LV_cjs.addDays(to, -1);
4032
- if (view === "day")
4033
- return chunkBIXHB4LV_cjs.formatPlainDate(from, {
4034
- weekday: "long",
4035
- year: "numeric",
4036
- month: "long",
4037
- day: "numeric"
4038
- });
4039
- if (view === "month")
4040
- return chunkBIXHB4LV_cjs.formatPlainDate(`${date.slice(0, 7)}-15`, { year: "numeric", month: "long" });
4041
- const opts = { year: "numeric", month: "short", day: "numeric" };
4042
- return `${chunkBIXHB4LV_cjs.formatPlainDate(from, opts)} \u2013 ${chunkBIXHB4LV_cjs.formatPlainDate(last, opts)}`;
4043
- }
4044
- var STYLE = `
4045
- .arbi-calendar-print { color: #111; background: #fff; font: 12px/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif; }
4046
- .arbi-calendar-print h1 { font-size: 18px; margin: 0 0 8px; }
4047
- .arbi-calendar-print .acp-zone { color: #555; font-size: 11px; margin-bottom: 12px; }
4048
- .arbi-calendar-print table { border-collapse: collapse; width: 100%; table-layout: fixed; }
4049
- .arbi-calendar-print th, .arbi-calendar-print td { border: 1px solid #bbb; padding: 4px; vertical-align: top; text-align: left; }
4050
- .arbi-calendar-print th { background: #f3f3f3; font-weight: 600; }
4051
- .arbi-calendar-print .acp-day { break-inside: avoid; margin-bottom: 10px; }
4052
- .arbi-calendar-print .acp-day h2 { font-size: 13px; margin: 0 0 4px; border-bottom: 1px solid #bbb; padding-bottom: 2px; }
4053
- .arbi-calendar-print .acp-ev { display: flex; gap: 6px; margin: 2px 0; break-inside: avoid; }
4054
- .arbi-calendar-print .acp-time { flex: 0 0 auto; min-width: 92px; color: #333; font-variant-numeric: tabular-nums; }
4055
- .arbi-calendar-print .acp-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 4px; vertical-align: middle; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
4056
- .arbi-calendar-print .acp-meta { color: #555; font-size: 11px; white-space: pre-line; }
4057
- .arbi-calendar-print .acp-muted { color: #888; }
4058
- .arbi-calendar-print .acp-cancelled { text-decoration: line-through; color: #888; }
4059
- .arbi-calendar-print .acp-month td { height: 90px; }
4060
- .arbi-calendar-print .acp-month .acp-out { color: #aaa; }
4061
- .arbi-calendar-print .acp-cell-ev { font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
4062
- @media screen { .arbi-calendar-print[data-screen-hidden='true'] { display: none; } }
4063
- @media print {
4064
- @page { margin: 12mm; }
4065
- body.arbi-printing-calendar > *:not(.arbi-calendar-print-host) { display: none !important; }
4066
- body.arbi-printing-calendar .arbi-calendar-print-host { display: block !important; }
4067
- body.arbi-printing-calendar .arbi-calendar-print { display: block !important; }
4068
- }
4069
- `;
4070
- function CalendarPrint({
4071
- events,
4072
- view,
4073
- date,
4074
- timeZone,
4075
- weekStart = 1,
4076
- agendaDays = 30,
4077
- title,
4078
- calendars,
4079
- screenHidden = false,
4080
- showDetails = true
4081
- }) {
4082
- const zone = chunkBIXHB4LV_cjs.safeZone(timeZone, chunkBIXHB4LV_cjs.detectTimeZone());
4083
- const { from, to } = printRange(view, date, weekStart, agendaDays);
4084
- const byDay = eventsByDay(events, zone, from, to);
4085
- const color = (e) => e.color || calendars?.find((c) => c.id === e.calendar_id)?.color || "#3b82f6";
4086
- const label = (e) => e.restricted && !e.title ? "Busy" : e.title || "(no title)";
4087
- const evLine = (e, day, details) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "acp-ev", "data-testid": "calendar-print-event", children: [
4088
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "acp-time", children: timeLabel(e, day, zone) }),
4089
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
4090
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "acp-dot", style: { background: color(e) } }),
4091
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: e.status === "cancelled" ? "acp-cancelled" : void 0, children: label(e) }),
4092
- details && e.location && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "acp-meta", children: e.location }),
4093
- details && e.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "acp-meta", children: e.description.slice(0, 500) })
4094
- ] })
4095
- ] }, `${e.instance_id}-${day}`);
4096
- let body;
4097
- if (view === "agenda" || view === "day") {
4098
- const days = view === "day" ? [from] : eachDay(from, to).filter((d) => byDay.has(d));
4099
- body = days.length ? days.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "acp-day", children: [
4100
- /* @__PURE__ */ jsxRuntime.jsx("h2", { children: chunkBIXHB4LV_cjs.formatPlainDate(d, { weekday: "long", month: "long", day: "numeric" }) }),
4101
- (byDay.get(d) ?? []).map((e) => evLine(e, d, showDetails)),
4102
- !byDay.get(d)?.length && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "acp-muted", children: "No events" })
4103
- ] }, d)) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "acp-muted", children: "No events" });
4104
- } else if (view === "week") {
4105
- const days = eachDay(from, to);
4106
- body = /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
4107
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: days.map((d) => /* @__PURE__ */ jsxRuntime.jsx("th", { children: chunkBIXHB4LV_cjs.formatPlainDate(d, { weekday: "short", day: "numeric", month: "short" }) }, d)) }) }),
4108
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: days.map((d) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: 480 }, children: (byDay.get(d) ?? []).map((e) => evLine(e, d, false)) }, d)) }) })
4109
- ] });
4110
- } else {
4111
- const days = eachDay(from, to);
4112
- const weeks = [];
4113
- for (let i = 0; i < days.length; i += 7) weeks.push(days.slice(i, i + 7));
4114
- const month = date.slice(0, 7);
4115
- body = /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "acp-month", children: [
4116
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: weeks[0].map((d) => /* @__PURE__ */ jsxRuntime.jsx("th", { children: chunkBIXHB4LV_cjs.formatPlainDate(d, { weekday: "short" }) }, d)) }) }),
4117
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((w) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: w.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("td", { className: d.slice(0, 7) === month ? void 0 : "acp-out", children: [
4118
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: Number(d.slice(8)) }),
4119
- (byDay.get(d) ?? []).slice(0, 6).map((e) => /* @__PURE__ */ jsxRuntime.jsxs(
4120
- "div",
4121
- {
4122
- className: "acp-cell-ev",
4123
- "data-testid": "calendar-print-event",
4124
- children: [
4125
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "acp-dot", style: { background: color(e) } }),
4126
- !e.all_day && `${timeLabel(e, d, zone).split(" \u2013 ")[0]} `,
4127
- label(e)
4128
- ]
4129
- },
4130
- `${e.instance_id}-${d}`
4131
- )),
4132
- (byDay.get(d)?.length ?? 0) > 6 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "acp-cell-ev acp-muted", children: [
4133
- "+",
4134
- (byDay.get(d)?.length ?? 0) - 6,
4135
- " more"
4136
- ] })
4137
- ] }, d)) }, w[0])) })
4138
- ] });
4139
- }
4140
- return /* @__PURE__ */ jsxRuntime.jsxs(
4141
- "div",
4142
- {
4143
- className: "arbi-calendar-print",
4144
- "data-screen-hidden": screenHidden ? "true" : "false",
4145
- "data-testid": "calendar-print",
4146
- children: [
4147
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: STYLE }),
4148
- /* @__PURE__ */ jsxRuntime.jsx("h1", { children: title ?? heading(view, date, from, to) }),
4149
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "acp-zone", children: [
4150
- "Times in ",
4151
- zone.replace(/_/g, " ")
4152
- ] }),
4153
- body
4154
- ]
4155
- }
4156
- );
4157
- }
4158
- function printCalendar(props) {
4159
- const host = document.createElement("div");
4160
- host.className = "arbi-calendar-print-host";
4161
- host.style.display = "none";
4162
- document.body.appendChild(host);
4163
- let unmount = null;
4164
- if (props) {
4165
- const root = client.createRoot(host);
4166
- reactDom.flushSync(() => root.render(/* @__PURE__ */ jsxRuntime.jsx(CalendarPrint, { ...props, screenHidden: false })));
4167
- unmount = () => root.unmount();
4168
- } else {
4169
- const existing = document.querySelector(".arbi-calendar-print");
4170
- if (!existing) {
4171
- host.remove();
4172
- return;
4173
- }
4174
- const clone = existing.cloneNode(true);
4175
- clone.setAttribute("data-screen-hidden", "false");
4176
- host.appendChild(clone);
4177
- }
4178
- document.body.classList.add("arbi-printing-calendar");
4179
- let done = false;
4180
- const cleanup = () => {
4181
- if (done) return;
4182
- done = true;
4183
- window.removeEventListener("afterprint", cleanup);
4184
- document.body.classList.remove("arbi-printing-calendar");
4185
- unmount?.();
4186
- host.remove();
4187
- };
4188
- window.addEventListener("afterprint", cleanup);
4189
- try {
4190
- window.print();
4191
- } finally {
4192
- if (!("onafterprint" in window)) setTimeout(cleanup, 1e3);
4193
- }
4194
- }
4195
-
4196
- // src/calendar/booking-slots.ts
4197
- function formatSlotTime(instant, zone, locale) {
4198
- return chunkBIXHB4LV_cjs.formatInZone(instant, zone, { hour: "numeric", minute: "2-digit" }, locale);
4199
- }
4200
- function formatDayLabel(date, locale) {
4201
- return chunkBIXHB4LV_cjs.formatPlainDate(date, { weekday: "long", month: "long", day: "numeric" }, locale);
4202
- }
4203
- function groupSlotsByDay(slots, zone, locale) {
4204
- const tz = chunkBIXHB4LV_cjs.safeZone(zone, chunkBIXHB4LV_cjs.detectTimeZone());
4205
- const byDay = /* @__PURE__ */ new Map();
4206
- const sorted = [...slots].sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
4207
- for (const start of sorted) {
4208
- const date = chunkBIXHB4LV_cjs.utcToDate(start, tz);
4209
- const list = byDay.get(date) ?? [];
4210
- list.push({ start, label: formatSlotTime(start, tz, locale) });
4211
- byDay.set(date, list);
4212
- }
4213
- return [...byDay.entries()].map(([date, list]) => ({
4214
- date,
4215
- label: formatDayLabel(date, locale),
4216
- slots: list
4217
- }));
4218
- }
4219
- function formatSlotRange(start, end, zone, locale) {
4220
- const tz = chunkBIXHB4LV_cjs.safeZone(zone, chunkBIXHB4LV_cjs.detectTimeZone());
4221
- const fmt = new Intl.DateTimeFormat(locale, {
4222
- timeZone: tz,
4223
- weekday: "long",
4224
- month: "long",
4225
- day: "numeric",
4226
- hour: "numeric",
4227
- minute: "2-digit"
4228
- });
4229
- const s = new Date(start);
4230
- const e = new Date(end);
4231
- const range = fmt.formatRange;
4232
- const text = range ? range.call(fmt, s, e) : `${fmt.format(s)} \u2013 ${formatSlotTime(end, tz, locale)}`;
4233
- return `${text} (${tz.replace(/_/g, " ")})`;
4234
- }
4235
- function zoneOptions(current) {
4236
- const zones = chunkBIXHB4LV_cjs.listTimeZones();
4237
- return zones.includes(current) ? zones : [current, ...zones];
4238
- }
4239
-
4240
482
  Object.defineProperty(exports, "addDays", {
4241
483
  enumerable: true,
4242
484
  get: function () { return chunkBIXHB4LV_cjs.addDays; }
@@ -4313,68 +555,5 @@ Object.defineProperty(exports, "zoneOffsetMinutes", {
4313
555
  enumerable: true,
4314
556
  get: function () { return chunkBIXHB4LV_cjs.zoneOffsetMinutes; }
4315
557
  });
4316
- exports.ARBI_WEBINAR_LABEL = ARBI_WEBINAR_LABEL;
4317
- exports.CALENDAR_COLORS = CALENDAR_COLORS;
4318
- exports.CALENDAR_DEFAULT_LABELS = CALENDAR_DEFAULT_LABELS;
4319
- exports.CALENDAR_NARROW_WIDTH = CALENDAR_NARROW_WIDTH;
4320
- exports.CalendarGrid = CalendarGrid;
4321
- exports.CalendarList = CalendarList;
4322
- exports.CalendarPrint = CalendarPrint;
4323
- exports.CalendarSettingsForm = CalendarSettingsForm;
4324
- exports.DEFAULT_RECURRENCE_DESCRIBE_LABELS = DEFAULT_RECURRENCE_DESCRIBE_LABELS;
4325
- exports.DEFAULT_RECURRENCE_EDITOR_LABELS = DEFAULT_RECURRENCE_EDITOR_LABELS;
4326
- exports.DEFAULT_REMINDER_FORMAT_LABELS = DEFAULT_REMINDER_FORMAT_LABELS;
4327
- exports.EventDetails = EventDetails;
4328
- exports.EventEditor = EventEditor;
4329
- exports.MiniMonth = MiniMonth;
4330
- exports.REMINDER_PRESETS = REMINDER_PRESETS;
4331
- exports.RRULE_WEEKDAYS = RRULE_WEEKDAYS;
4332
- exports.RecurrenceEditor = RecurrenceEditor;
4333
- exports.RoomFinder = RoomFinder;
4334
- exports.SchedulingAssistant = SchedulingAssistant;
4335
- exports.ScopeDialog = ScopeDialog;
4336
- exports.TimeZonePicker = TimeZonePicker;
4337
- exports.allDayInclusiveEnd = allDayInclusiveEnd;
4338
- exports.attendeeKey = attendeeKey;
4339
- exports.buildRRule = buildRRule;
4340
- exports.contrastText = contrastText;
4341
- exports.dayWindow = dayWindow;
4342
- exports.defaultRecurrenceForm = defaultRecurrenceForm;
4343
- exports.describeRecurrence = describeRecurrence;
4344
- exports.draftFromSlot = draftFromSlot;
4345
- exports.draftRangeUtc = draftRangeUtc;
4346
- exports.effectiveCalendarView = effectiveCalendarView;
4347
- exports.eventDays = eventDays;
4348
- exports.eventStateClasses = eventStateClasses;
4349
- exports.eventsByDay = eventsByDay;
4350
- exports.formatDayLabel = formatDayLabel;
4351
- exports.formatEventWhen = formatEventWhen;
4352
- exports.formatReminder = formatReminder;
4353
- exports.formatSlotRange = formatSlotRange;
4354
- exports.formatSlotTime = formatSlotTime;
4355
- exports.formatZoneLabel = formatZoneLabel;
4356
- exports.getTemporalTimeZonePlugin = getTemporalTimeZonePlugin;
4357
- exports.groupSlotsByDay = groupSlotsByDay;
4358
- exports.hourTicks = hourTicks;
4359
- exports.isAllDayDraft = isAllDayDraft;
4360
- exports.isWebinarConference = isWebinarConference;
4361
- exports.outsideIntervals = outsideIntervals;
4362
- exports.parseRRule = parseRRule;
4363
- exports.placeIntervals = placeIntervals;
4364
- exports.printCalendar = printCalendar;
4365
- exports.printRange = printRange;
4366
- exports.reminderToMinutes = reminderToMinutes;
4367
- exports.setDraftAllDay = setDraftAllDay;
4368
- exports.setDraftEnd = setDraftEnd;
4369
- exports.setDraftStart = setDraftStart;
4370
- exports.setPosOf = setPosOf;
4371
- exports.specDate = specDate;
4372
- exports.specTime = specTime;
4373
- exports.splitReminderMinutes = splitReminderMinutes;
4374
- exports.toBusinessHours = toBusinessHours;
4375
- exports.validateDraft = validateDraft;
4376
- exports.weekdayOf = weekdayOf;
4377
- exports.workWeekHiddenDays = workWeekHiddenDays;
4378
- exports.zoneOptions = zoneOptions;
4379
558
  //# sourceMappingURL=index.cjs.map
4380
559
  //# sourceMappingURL=index.cjs.map