@open-mercato/core 0.9.0 → 0.9.1-develop.7459.1.99e3accd30

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 (243) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/customer_dictionary_entry/index.js +2 -0
  3. package/dist/generated/entities/customer_dictionary_entry/index.js.map +2 -2
  4. package/dist/generated/entities/customer_interaction/index.js +2 -0
  5. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/catalog/commands/categories.js +1 -1
  9. package/dist/modules/catalog/commands/categories.js.map +2 -2
  10. package/dist/modules/catalog/commands/productDeleteChildren.js +389 -0
  11. package/dist/modules/catalog/commands/productDeleteChildren.js.map +7 -0
  12. package/dist/modules/catalog/commands/products.js +52 -17
  13. package/dist/modules/catalog/commands/products.js.map +2 -2
  14. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +4 -6
  15. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +2 -2
  16. package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js +4 -6
  17. package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js.map +2 -2
  18. package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js +47 -11
  19. package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js.map +3 -3
  20. package/dist/modules/communication_channels/commands/deliver-outbound-message.js +5 -1
  21. package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
  22. package/dist/modules/communication_channels/lib/inbound-message-origin.js +1 -1
  23. package/dist/modules/communication_channels/lib/inbound-message-origin.js.map +2 -2
  24. package/dist/modules/communication_channels/lib/oauth-state.js +4 -1
  25. package/dist/modules/communication_channels/lib/oauth-state.js.map +2 -2
  26. package/dist/modules/communication_channels/lib/use-connect-channel.js +10 -0
  27. package/dist/modules/communication_channels/lib/use-connect-channel.js.map +2 -2
  28. package/dist/modules/customers/api/activity-types/route.js +151 -0
  29. package/dist/modules/customers/api/activity-types/route.js.map +7 -0
  30. package/dist/modules/customers/api/deals/[id]/people/route.js +58 -5
  31. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  32. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +13 -5
  33. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  34. package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -5
  35. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  36. package/dist/modules/customers/api/interactions/route.js +3 -0
  37. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  38. package/dist/modules/customers/api/interactions/tasks/route.js +1 -0
  39. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  40. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +18 -0
  41. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +2 -2
  42. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +0 -23
  43. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  44. package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -17
  45. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  46. package/dist/modules/customers/calendar-event-types.js +548 -0
  47. package/dist/modules/customers/calendar-event-types.js.map +7 -0
  48. package/dist/modules/customers/commands/dictionaries.js +70 -10
  49. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  50. package/dist/modules/customers/commands/interactions.js +187 -22
  51. package/dist/modules/customers/commands/interactions.js.map +3 -3
  52. package/dist/modules/customers/components/ActivityTypeEditor.js +288 -0
  53. package/dist/modules/customers/components/ActivityTypeEditor.js.map +7 -0
  54. package/dist/modules/customers/components/DictionarySettings.js +3 -1
  55. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  56. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -297
  57. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +3 -3
  58. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +9 -74
  59. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  60. package/dist/modules/customers/components/calendar/TimeGrid.js +20 -16
  61. package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
  62. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js +218 -0
  63. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js.map +7 -0
  64. package/dist/modules/customers/components/calendar/editor/LocationField.js +7 -3
  65. package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
  66. package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -2
  67. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  68. package/dist/modules/customers/components/calendar/editor/PriorityField.js +3 -1
  69. package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +2 -2
  70. package/dist/modules/customers/components/calendar/editor/RepeatField.js +9 -1
  71. package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +2 -2
  72. package/dist/modules/customers/components/calendar/editor/ResourcesField.js +4 -1
  73. package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +2 -2
  74. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +15 -7
  75. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
  76. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +3 -1
  77. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
  78. package/dist/modules/customers/components/calendar/editor/hooks.js +28 -13
  79. package/dist/modules/customers/components/calendar/editor/hooks.js.map +3 -3
  80. package/dist/modules/customers/components/calendar/editor/inputs.js +14 -6
  81. package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
  82. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js +54 -0
  83. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js.map +7 -0
  84. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js +82 -0
  85. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js.map +7 -0
  86. package/dist/modules/customers/components/calendar/types.js +1 -0
  87. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  88. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +78 -343
  89. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  90. package/dist/modules/customers/components/detail/CreatePersonDialog.js +12 -11
  91. package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +2 -2
  92. package/dist/modules/customers/components/detail/DealForm.js +7 -3
  93. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  94. package/dist/modules/customers/components/detail/DealPeopleSection.js +206 -0
  95. package/dist/modules/customers/components/detail/DealPeopleSection.js.map +7 -0
  96. package/dist/modules/customers/components/detail/LinkedPeopleSection.js +342 -0
  97. package/dist/modules/customers/components/detail/LinkedPeopleSection.js.map +7 -0
  98. package/dist/modules/customers/components/detail/PersonCard.js +5 -2
  99. package/dist/modules/customers/components/detail/PersonCard.js.map +2 -2
  100. package/dist/modules/customers/components/linking/adapters/personAdapter.js +3 -0
  101. package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +2 -2
  102. package/dist/modules/customers/data/entities.js +6 -0
  103. package/dist/modules/customers/data/entities.js.map +2 -2
  104. package/dist/modules/customers/data/validators.js +39 -10
  105. package/dist/modules/customers/data/validators.js.map +2 -2
  106. package/dist/modules/customers/di.js +20 -1
  107. package/dist/modules/customers/di.js.map +2 -2
  108. package/dist/modules/customers/extension-points.js +13 -0
  109. package/dist/modules/customers/extension-points.js.map +2 -2
  110. package/dist/modules/customers/lib/calendar/conflicts.js +59 -16
  111. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  112. package/dist/modules/customers/lib/calendar/editorPayload.js +34 -16
  113. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  114. package/dist/modules/customers/lib/calendar/eventTypeResolver.js +197 -0
  115. package/dist/modules/customers/lib/calendar/eventTypeResolver.js.map +7 -0
  116. package/dist/modules/customers/lib/calendar/interactionApplicability.js +67 -0
  117. package/dist/modules/customers/lib/calendar/interactionApplicability.js.map +7 -0
  118. package/dist/modules/customers/lib/calendar/mapItem.js +5 -2
  119. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  120. package/dist/modules/customers/lib/calendar/recurrence.js +62 -1
  121. package/dist/modules/customers/lib/calendar/recurrence.js.map +2 -2
  122. package/dist/modules/customers/lib/calendar/timezone.js +111 -0
  123. package/dist/modules/customers/lib/calendar/timezone.js.map +7 -0
  124. package/dist/modules/customers/lib/interactionReadModel.js +1 -0
  125. package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
  126. package/dist/modules/customers/lib/todoCompatibility.js +1 -0
  127. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  128. package/dist/modules/customers/migrations/Migration20260928175058_customers.js +17 -0
  129. package/dist/modules/customers/migrations/Migration20260928175058_customers.js.map +7 -0
  130. package/dist/modules/customers/migrations/Migration20260930110235_customers.js +17 -0
  131. package/dist/modules/customers/migrations/Migration20260930110235_customers.js.map +7 -0
  132. package/dist/modules/dictionaries/components/DictionaryTable.js +60 -51
  133. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  134. package/dist/modules/messages/subscribers/message-notification.js +13 -1
  135. package/dist/modules/messages/subscribers/message-notification.js.map +2 -2
  136. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +201 -53
  137. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  138. package/dist/modules/payment_gateways/lib/gateway-service.js +37 -11
  139. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  140. package/dist/modules/planner/lib/availabilityMerge.js +101 -38
  141. package/dist/modules/planner/lib/availabilityMerge.js.map +3 -3
  142. package/dist/modules/planner/services/plannerAvailabilityService.js.map +2 -2
  143. package/dist/modules/sales/components/documents/LineItemDialog.js +159 -81
  144. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  145. package/dist/modules/sales/components/documents/lineItemUtils.js +7 -0
  146. package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
  147. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +12 -7
  148. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
  149. package/dist/modules/sync_excel/lib/adapters/customers.js +28 -25
  150. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  151. package/generated/entities/customer_dictionary_entry/index.ts +1 -0
  152. package/generated/entities/customer_interaction/index.ts +1 -0
  153. package/generated/entity-fields-registry.ts +2 -0
  154. package/package.json +9 -8
  155. package/src/modules/auth/i18n/de.json +3 -0
  156. package/src/modules/auth/i18n/en.json +3 -0
  157. package/src/modules/auth/i18n/es.json +3 -0
  158. package/src/modules/auth/i18n/ko.json +3 -0
  159. package/src/modules/auth/i18n/pl.json +3 -0
  160. package/src/modules/catalog/commands/categories.ts +1 -1
  161. package/src/modules/catalog/commands/productDeleteChildren.ts +557 -0
  162. package/src/modules/catalog/commands/products.ts +58 -17
  163. package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +4 -6
  164. package/src/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.ts +4 -6
  165. package/src/modules/communication_channels/api/post/oauth/[provider]/initiate/route.ts +46 -10
  166. package/src/modules/communication_channels/commands/deliver-outbound-message.ts +6 -1
  167. package/src/modules/communication_channels/i18n/de.json +4 -0
  168. package/src/modules/communication_channels/i18n/en.json +4 -0
  169. package/src/modules/communication_channels/i18n/es.json +4 -0
  170. package/src/modules/communication_channels/i18n/ko.json +4 -0
  171. package/src/modules/communication_channels/i18n/pl.json +4 -0
  172. package/src/modules/communication_channels/lib/inbound-message-origin.ts +2 -6
  173. package/src/modules/communication_channels/lib/oauth-state.ts +4 -1
  174. package/src/modules/communication_channels/lib/use-connect-channel.ts +10 -0
  175. package/src/modules/customers/api/activity-types/route.ts +154 -0
  176. package/src/modules/customers/api/deals/[id]/people/route.ts +82 -3
  177. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -1
  178. package/src/modules/customers/api/dictionaries/[kind]/route.ts +18 -2
  179. package/src/modules/customers/api/interactions/route.ts +4 -0
  180. package/src/modules/customers/api/interactions/tasks/route.ts +1 -0
  181. package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +20 -0
  182. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +0 -29
  183. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +15 -17
  184. package/src/modules/customers/calendar-event-types.ts +674 -0
  185. package/src/modules/customers/commands/dictionaries.ts +84 -8
  186. package/src/modules/customers/commands/interactions.ts +244 -21
  187. package/src/modules/customers/components/ActivityTypeEditor.tsx +239 -0
  188. package/src/modules/customers/components/DictionarySettings.tsx +5 -3
  189. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +347 -218
  190. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +18 -96
  191. package/src/modules/customers/components/calendar/TimeGrid.tsx +20 -18
  192. package/src/modules/customers/components/calendar/editor/EventTypePanel.tsx +230 -0
  193. package/src/modules/customers/components/calendar/editor/LocationField.tsx +7 -1
  194. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +4 -0
  195. package/src/modules/customers/components/calendar/editor/PriorityField.tsx +3 -0
  196. package/src/modules/customers/components/calendar/editor/RepeatField.tsx +10 -0
  197. package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +4 -0
  198. package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +16 -4
  199. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +3 -0
  200. package/src/modules/customers/components/calendar/editor/hooks.ts +29 -13
  201. package/src/modules/customers/components/calendar/editor/inputs.tsx +17 -5
  202. package/src/modules/customers/components/calendar/editor/useCalendarCustomFields.ts +49 -0
  203. package/src/modules/customers/components/calendar/editor/useEventTypeCatalog.ts +100 -0
  204. package/src/modules/customers/components/calendar/types.ts +1 -0
  205. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +94 -388
  206. package/src/modules/customers/components/detail/CreatePersonDialog.tsx +39 -19
  207. package/src/modules/customers/components/detail/DealForm.tsx +7 -3
  208. package/src/modules/customers/components/detail/DealPeopleSection.tsx +256 -0
  209. package/src/modules/customers/components/detail/LinkedPeopleSection.tsx +474 -0
  210. package/src/modules/customers/components/detail/PersonCard.tsx +12 -4
  211. package/src/modules/customers/components/detail/types.ts +1 -0
  212. package/src/modules/customers/components/linking/adapters/personAdapter.tsx +4 -0
  213. package/src/modules/customers/data/entities.ts +8 -1
  214. package/src/modules/customers/data/validators.ts +42 -7
  215. package/src/modules/customers/di.ts +21 -0
  216. package/src/modules/customers/extension-points.ts +13 -0
  217. package/src/modules/customers/i18n/de.json +104 -8
  218. package/src/modules/customers/i18n/en.json +104 -8
  219. package/src/modules/customers/i18n/es.json +104 -8
  220. package/src/modules/customers/i18n/ko.json +104 -8
  221. package/src/modules/customers/i18n/pl.json +104 -8
  222. package/src/modules/customers/lib/calendar/conflicts.ts +106 -27
  223. package/src/modules/customers/lib/calendar/editorPayload.ts +39 -19
  224. package/src/modules/customers/lib/calendar/eventTypeResolver.ts +258 -0
  225. package/src/modules/customers/lib/calendar/interactionApplicability.ts +99 -0
  226. package/src/modules/customers/lib/calendar/mapItem.ts +6 -2
  227. package/src/modules/customers/lib/calendar/recurrence.ts +65 -1
  228. package/src/modules/customers/lib/calendar/timezone.ts +117 -0
  229. package/src/modules/customers/lib/interactionReadModel.ts +1 -0
  230. package/src/modules/customers/lib/todoCompatibility.ts +2 -0
  231. package/src/modules/customers/migrations/.snapshot-open-mercato.json +34 -0
  232. package/src/modules/customers/migrations/Migration20260928175058_customers.ts +15 -0
  233. package/src/modules/customers/migrations/Migration20260930110235_customers.ts +15 -0
  234. package/src/modules/dictionaries/components/DictionaryTable.tsx +63 -56
  235. package/src/modules/messages/subscribers/message-notification.ts +13 -3
  236. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +243 -62
  237. package/src/modules/payment_gateways/lib/gateway-service.ts +39 -12
  238. package/src/modules/planner/lib/availabilityMerge.ts +106 -41
  239. package/src/modules/planner/services/plannerAvailabilityService.ts +4 -0
  240. package/src/modules/sales/components/documents/LineItemDialog.tsx +194 -111
  241. package/src/modules/sales/components/documents/lineItemUtils.ts +18 -0
  242. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +25 -13
  243. package/src/modules/sync_excel/lib/adapters/customers.ts +33 -27
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/calendar/CalendarEventEditor.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Calendar, X } from 'lucide-react'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { CrudForm, type CrudFormGroup, type CrudFormGroupComponentProps } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n buildEditorTypeOptions,\n buildInteractionPayload,\n computeDurationMinutes,\n createDefaultFormState,\n defaultRepeatDaysForDateInput,\n editorKindOfInteractionType,\n KIND_CONFIG,\n parseItemToFormState,\n resolveSavedOwnerUserId,\n type EditorFormState,\n type EditorKind,\n type EditorPriority,\n} from '../../lib/calendar/editorPayload'\nimport type { ConflictScope } from '../../lib/calendar/preferences'\nimport { renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { normalizeCustomFieldSubmitValue } from '../detail/customFieldUtils'\nimport type { CalendarItem } from './types'\nimport { EDITOR_SCROLL_EVENT, Field } from './editor/inputs'\nimport { SegmentGroup } from './editor/SegmentGroup'\nimport { PriorityField } from './editor/PriorityField'\nimport { RelatedToField } from './editor/RelatedToField'\nimport { RepeatField } from './editor/RepeatField'\nimport { PeopleField } from './editor/PeopleField'\nimport { ResourcesField } from './editor/ResourcesField'\nimport { ScheduleSection } from './editor/ScheduleSection'\nimport { LocationField } from './editor/LocationField'\nimport { useConflictProbe, useEditorLabelResolution } from './editor/hooks'\n\nexport interface CalendarEventEditorProps {\n open: boolean\n mode: 'create' | 'edit'\n item?: CalendarItem | null\n defaultDate?: Date\n defaultRange?: { start: Date; end: Date } | null\n typeLabels: Record<string, string>\n typeIcons?: Record<string, string | null>\n conflictScope?: ConflictScope\n currentUserId?: string | null\n resourcesEnabled?: boolean\n staffEnabled?: boolean\n onOpenChange(open: boolean): void\n onSaved(): void\n}\n\nconst FORM_ID = 'customers-calendar-event-editor'\nconst INTERACTION_ENTITY_IDS = [E.customers.customer_interaction]\n\nconst PEOPLE_FIELD_TEXT = {\n attendees: { labelKey: 'customers.calendar.editor.attendees', label: 'Attendees', placeholderKey: 'customers.calendar.editor.addPeoplePlaceholder', placeholder: 'Add staff or customer\u2026' },\n participants: { labelKey: 'customers.calendar.editor.participants', label: 'Participants', placeholderKey: 'customers.calendar.editor.addPeoplePlaceholder', placeholder: 'Add staff or customer\u2026' },\n to: { labelKey: 'customers.calendar.editor.to', label: 'To', placeholderKey: 'customers.calendar.editor.addRecipientPlaceholder', placeholder: 'Add recipient\u2026' },\n} as const\n\n// CrudForm values carry the flattened EditorFormState keys (seeded via\n// initialValues) plus cf_* custom-field keys managed by CrudForm itself.\nfunction formStateOfValues(values: Record<string, unknown>): EditorFormState {\n return values as unknown as EditorFormState\n}\n\nfunction customFieldInitialValues(item: CalendarItem): Record<string, unknown> {\n const customValues = (item.raw as Record<string, unknown>).customValues\n if (!customValues || typeof customValues !== 'object' || Array.isArray(customValues)) return {}\n return Object.fromEntries(\n Object.entries(customValues as Record<string, unknown>).map(([key, value]) => [`cf_${key}`, value]),\n )\n}\n\ntype EditorBodyProps = {\n ctx: CrudFormGroupComponentProps\n open: boolean\n isEdit: boolean\n item?: CalendarItem | null\n typeLabels: Record<string, string>\n typeIcons: Record<string, string | null>\n conflictScope: ConflictScope\n currentUserId: string | null\n resourcesEnabled: boolean\n staffEnabled: boolean\n}\n\nfunction EditorBody({\n ctx,\n open,\n isEdit,\n item,\n typeLabels,\n typeIcons,\n conflictScope,\n currentUserId,\n resourcesEnabled,\n staffEnabled,\n}: EditorBodyProps) {\n const t = useT()\n const { setValue, errors } = ctx\n const form = formStateOfValues(ctx.values)\n const config = KIND_CONFIG[form.kind]\n\n const update = React.useCallback(\n (patch: Partial<EditorFormState>) => {\n for (const [key, value] of Object.entries(patch)) setValue(key, value)\n },\n [setValue],\n )\n\n useEditorLabelResolution(open, form, update)\n // Probe against the owner the interaction will actually be SAVED with so the\n // editor warning matches the grid's post-save conflict rings: tasks own via\n // their assignee, other kinds stay ownerless on create / keep the existing\n // owner on edit (conflicts then come from shared participants).\n const draftOwnerUserId = resolveSavedOwnerUserId(config, form, isEdit, item?.ownerUserId ?? null)\n // Self-exclude by the underlying interaction id (raw.id): findEditorConflictItems\n // drops candidates by raw.id, and every expanded occurrence of a recurring series\n // shares it \u2014 so the edited record never conflicts with itself.\n const conflict = useConflictProbe(open, form, config, isEdit && item ? item.raw.id : null, draftOwnerUserId, conflictScope, currentUserId)\n\n const kindLabels = React.useMemo(\n () => ({\n meeting: t('customers.calendar.editor.types.meeting', 'meeting'),\n call: t('customers.calendar.editor.types.call', 'call'),\n email: t('customers.calendar.editor.types.email', 'email'),\n note: t('customers.calendar.editor.types.note', 'note'),\n event: t('customers.calendar.editor.types.event', 'event'),\n task: t('customers.calendar.editor.types.task', 'task'),\n }),\n [t],\n ) satisfies Record<EditorKind, string>\n\n const selectedType = form.category ?? form.kind\n const typeOptions = React.useMemo(\n () => buildEditorTypeOptions({ typeLabels, typeIcons, selectedValue: selectedType, kindLabels }),\n [typeLabels, typeIcons, selectedType, kindLabels],\n )\n const typeSwitcherOptions = React.useMemo(\n () =>\n typeOptions.map((option) => ({\n value: option.value,\n label: option.label,\n icon: renderDictionaryIcon(option.icon, 'h-4 w-4'),\n })),\n [typeOptions],\n )\n\n // Candidates for the Call \"insert phone from contact\" button: the linked\n // person (companies have no phone) + customer attendees. Their userId is the\n // person id, so the picker can resolve primary_phone from the people API.\n const phoneContactIds = React.useMemo(() => {\n const ids: string[] = []\n if (form.relatedTo && form.relatedTo.kind !== 'company') ids.push(form.relatedTo.id)\n for (const participant of form.participants) {\n if (participant.isCustomer && participant.userId) ids.push(participant.userId)\n }\n return Array.from(new Set(ids))\n }, [form.relatedTo, form.participants])\n\n const titleLabel = form.kind === 'email'\n ? t('customers.calendar.editor.titleLabel.email', 'Subject')\n : form.kind === 'note'\n ? t('customers.calendar.editor.titleLabel.note', 'Note')\n : t('customers.calendar.editor.titleLabel.generic', 'Title')\n\n return (\n // Single column on phones (full-screen sheet). On lg+ the dialog widens and\n // the fields group into two thematic columns: WHEN (schedule + repeat) on\n // the left, CONTEXT (related record, category, location) on the right;\n // people/resources and the task fields pair up below; title, description\n // and the type switcher span both columns.\n <div className=\"grid w-full grid-cols-1 items-start gap-4 lg:grid-cols-2 lg:gap-x-6\">\n {conflict ? (\n <Alert status=\"warning\" className=\"rounded-lg lg:col-span-2\">\n <AlertTitle>{t('customers.calendar.editor.conflictTitle', 'Calendar conflict')}</AlertTitle>\n <AlertDescription>{conflict}</AlertDescription>\n </Alert>\n ) : null}\n <div className=\"w-full lg:col-span-2\">\n <SegmentGroup<string>\n ariaLabel={t('customers.calendar.editor.typeSwitcher', 'Event type')}\n value={selectedType}\n onChange={(type) => update({ kind: editorKindOfInteractionType(type), category: type })}\n options={typeSwitcherOptions}\n />\n </div>\n <Field label={titleLabel} error={errors.title} className=\"lg:col-span-2\">\n <Input\n type=\"text\"\n value={form.title}\n onChange={(event) => update({ title: event.target.value })}\n placeholder={t('customers.calendar.editor.titlePlaceholder', 'Add a title\u2026')}\n aria-label={titleLabel}\n autoFocus\n size=\"lg\"\n />\n </Field>\n <div className=\"flex w-full flex-col gap-4\">\n <ScheduleSection\n dateLabel={config.dateLabel}\n hasAllDay={config.hasAllDay}\n hasEnd={config.hasEnd}\n allDay={form.allDay}\n date={form.date}\n startTime={form.startTime}\n endDate={form.endDate}\n endTime={form.endTime}\n endsError={errors.ends}\n onAllDayChange={(allDay) => update({ allDay })}\n onDateChange={(date) => {\n const untouchedDefault =\n JSON.stringify(form.repeatDays) === JSON.stringify(defaultRepeatDaysForDateInput(form.date))\n update(\n untouchedDefault\n ? { date, repeatDays: defaultRepeatDaysForDateInput(date) }\n : { date },\n )\n }}\n onStartTimeChange={(startTime) => update({ startTime })}\n onEndDateChange={(endDate) => update({ endDate })}\n onEndTimeChange={(endTime) => update({ endTime })}\n />\n {config.hasRepeat ? (\n <RepeatField\n freq={form.repeatFreq}\n days={form.repeatDays}\n endType={form.repeatEndType}\n count={form.repeatCount}\n untilDate={form.repeatUntilDate}\n onFreqChange={(repeatFreq) =>\n update(\n repeatFreq === 'weekly'\n ? { repeatFreq, repeatDays: defaultRepeatDaysForDateInput(form.date) }\n : { repeatFreq },\n )}\n onToggleDay={(index) =>\n update({ repeatDays: form.repeatDays.map((active, dayIndex) => (dayIndex === index ? !active : active)) })}\n onEndTypeChange={(repeatEndType) => update({ repeatEndType })}\n onCountChange={(repeatCount) => update({ repeatCount })}\n onUntilDateChange={(repeatUntilDate) => update({ repeatUntilDate })}\n />\n ) : null}\n {config.people && config.people !== 'assignee' ? (\n <Field label={t(PEOPLE_FIELD_TEXT[config.people].labelKey, PEOPLE_FIELD_TEXT[config.people].label)}>\n <PeopleField\n mode=\"multi\"\n includeCustomers\n includeStaff={staffEnabled}\n placeholder={t(PEOPLE_FIELD_TEXT[config.people].placeholderKey, PEOPLE_FIELD_TEXT[config.people].placeholder)}\n ariaLabel={t(PEOPLE_FIELD_TEXT[config.people].labelKey, PEOPLE_FIELD_TEXT[config.people].label)}\n value={form.participants}\n onChange={(participants) => update({ participants })}\n />\n </Field>\n ) : null}\n {config.people === 'assignee' && staffEnabled ? (\n <Field label={t('customers.calendar.editor.assignee', 'Assignee')} error={errors.assignee}>\n <PeopleField\n mode=\"single\"\n includeCustomers={false}\n includeStaff\n placeholder={t('customers.calendar.editor.assigneePlaceholder', 'Assign to a team member\u2026')}\n ariaLabel={t('customers.calendar.editor.assignee', 'Assignee')}\n value={form.assigneeUserId\n ? [{ userId: form.assigneeUserId, name: form.assigneeName ?? form.assigneeUserId, isCustomer: false }]\n : []}\n onChange={(entries) => {\n const next = entries[entries.length - 1] ?? null\n update({ assigneeUserId: next?.userId ?? null, assigneeName: next?.name ?? null })\n }}\n />\n </Field>\n ) : null}\n </div>\n <div className=\"flex w-full flex-col gap-4\">\n <Field label={t('customers.calendar.editor.relatedTo', 'Related to')} error={errors.relatedTo}>\n <RelatedToField\n label={t('customers.calendar.editor.relatedTo', 'Related to')}\n value={form.relatedTo}\n deal={form.dealId && form.dealLabel ? { id: form.dealId, label: form.dealLabel } : null}\n onChange={(relatedTo) => update({ relatedTo })}\n onDealChange={(deal) => update({ dealId: deal?.id ?? null, dealLabel: deal?.label ?? null })}\n error={errors.relatedTo}\n />\n </Field>\n {config.location ? (\n <LocationField\n variant={config.location}\n value={form.location}\n onChange={(location) => update({ location })}\n phoneContactIds={phoneContactIds}\n />\n ) : null}\n {resourcesEnabled ? (\n <Field label={t('customers.calendar.editor.resources', 'Resources')}>\n <ResourcesField\n placeholder={t('customers.calendar.editor.resourcesPlaceholder', 'Add a resource\u2026')}\n ariaLabel={t('customers.calendar.editor.resources', 'Resources')}\n value={form.resources}\n onChange={(resources) => update({ resources })}\n />\n </Field>\n ) : null}\n {config.hasPriority ? (\n <Field label={t('customers.calendar.editor.priority.label', 'Priority')}>\n <PriorityField\n value={form.priority}\n ariaLabel={t('customers.calendar.editor.priority.label', 'Priority')}\n labels={{\n low: t('customers.calendar.editor.priority.low', 'Low'),\n medium: t('customers.calendar.editor.priority.medium', 'Medium'),\n high: t('customers.calendar.editor.priority.high', 'High'),\n }}\n onChange={(priority) => update({ priority })}\n />\n </Field>\n ) : null}\n </div>\n <Field label={t('customers.calendar.editor.description', 'Description')} className=\"lg:col-span-2\">\n <Textarea\n value={form.description}\n onChange={(event) => update({ description: event.target.value })}\n placeholder={t('customers.calendar.editor.descriptionPlaceholder', 'Add details\u2026')}\n aria-label={t('customers.calendar.editor.description', 'Description')}\n className=\"h-20 resize-none\"\n />\n </Field>\n </div>\n )\n}\n\nexport function CalendarEventEditor({\n open,\n mode,\n item,\n defaultDate,\n defaultRange,\n typeLabels,\n typeIcons,\n conflictScope,\n currentUserId,\n resourcesEnabled,\n staffEnabled,\n onOpenChange,\n onSaved,\n}: CalendarEventEditorProps) {\n const t = useT()\n const [saving, setSaving] = React.useState(false)\n const isEdit = mode === 'edit' && Boolean(item?.id)\n\n // CrudForm reads initialValues once, so every dialog open gets a fresh form\n // instance keyed by the open sequence + edited record.\n const [openSeq, setOpenSeq] = React.useState(0)\n const wasOpenRef = React.useRef(false)\n React.useEffect(() => {\n if (open && !wasOpenRef.current) setOpenSeq((seq) => seq + 1)\n wasOpenRef.current = open\n }, [open])\n const formKey = `${mode}:${item?.id ?? 'new'}:${openSeq}`\n\n const initialValues = React.useMemo<Record<string, unknown>>(() => {\n if (isEdit && item) {\n return {\n ...parseItemToFormState(item),\n ...customFieldInitialValues(item),\n id: item.id,\n updatedAt: item.updatedAt ?? undefined,\n }\n }\n return { ...createDefaultFormState(defaultDate ?? null, undefined, defaultRange ?? null) }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- openSeq re-seeds defaults per dialog open\n }, [isEdit, item, defaultDate, defaultRange, openSeq])\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n const form = formStateOfValues(values)\n const config = KIND_CONFIG[form.kind]\n const fieldErrors: Record<string, string> = {}\n if (!form.title.trim()) {\n fieldErrors.title = t('customers.calendar.editor.validation.titleRequired', 'Title is required')\n }\n if (!form.relatedTo) {\n fieldErrors.relatedTo = t('customers.calendar.editor.validation.relatedToRequired', 'Select a person or company to link this event')\n }\n if (config.hasEnd && !form.allDay && computeDurationMinutes(form) === null) {\n fieldErrors.ends = t('customers.calendar.editor.validation.endsBeforeStarts', 'End must be after start')\n }\n // A task must be assigned to a team member \u2014 surface the requirement inline\n // instead of letting the save fail with no visible reason (#3747 feedback).\n if (config.people === 'assignee' && staffEnabled !== false && !form.assigneeUserId) {\n fieldErrors.assignee = t('customers.calendar.editor.validation.assigneeRequired', 'Assign this task to a team member')\n }\n if (Object.keys(fieldErrors).length > 0) {\n throw createCrudFormError(Object.values(fieldErrors)[0], fieldErrors)\n }\n setSaving(true)\n try {\n const payload = buildInteractionPayload(form, {\n mode,\n id: item?.id,\n resourcesEnabled: resourcesEnabled === true,\n staffEnabled: staffEnabled !== false,\n })\n const custom = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n for (const [key, value] of Object.entries(custom)) payload[`cf_${key}`] = value\n // CrudForm supplies the optimistic-lock header (auto-derived from\n // initialValues.updatedAt) via scoped request headers around onSubmit.\n await apiCallOrThrow('/api/customers/interactions', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n flash(t('customers.calendar.editor.saved', 'Event saved'), 'success')\n onOpenChange(false)\n requestAnimationFrame(() => { onSaved() })\n } catch (err) {\n // Surface an optimistic-lock 409 as the persistent conflict bar and\n // close \u2014 the bar renders at page level, behind the dialog overlay.\n if (extractOptimisticLockConflict(err)) {\n surfaceRecordConflict(err, t)\n onOpenChange(false)\n return\n }\n throw err\n } finally {\n setSaving(false)\n }\n },\n [isEdit, item?.id, mode, onOpenChange, onSaved, resourcesEnabled, staffEnabled, t],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'details',\n bare: true,\n component: (ctx) => (\n <EditorBody\n ctx={ctx}\n open={open}\n isEdit={isEdit}\n item={item}\n typeLabels={typeLabels}\n typeIcons={typeIcons ?? {}}\n conflictScope={conflictScope ?? 'all'}\n currentUserId={currentUserId ?? null}\n resourcesEnabled={resourcesEnabled === true}\n staffEnabled={staffEnabled !== false}\n />\n ),\n },\n { id: 'customFields', kind: 'customFields' },\n ],\n [open, isEdit, item, typeLabels, typeIcons, conflictScope, currentUserId, resourcesEnabled, staffEnabled],\n )\n\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: () => {\n const formElement = document.getElementById(FORM_ID)\n if (formElement instanceof HTMLFormElement) formElement.requestSubmit()\n },\n disabled: saving,\n })\n\n const dialogTitle = isEdit ? t('customers.calendar.editor.title.edit', 'Edit event') : t('customers.calendar.editor.title.create', 'New event')\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n onKeyDown={handleKeyDown}\n // Only dismiss on a genuine click OUTSIDE the whole editor. Radix\n // relays a click inside the dialog (but outside an open DS\n // DatePicker/Select popover) up to the dialog as an \"interact\n // outside\" event when it dismisses that popover \u2014 without this guard\n // it would tear down the entire editor. Keep it open when the target\n // is inside the dialog body or inside any portalled popover.\n onInteractOutside={(event) => {\n const target = event.detail.originalEvent.target as HTMLElement | null\n if (target?.closest('[data-dialog-content]') || target?.closest('[data-radix-popper-content-wrapper]')) {\n event.preventDefault()\n }\n }}\n aria-describedby={undefined}\n dismissible={false}\n className=\"flex h-dvh max-h-dvh w-screen max-w-none flex-col gap-0 overflow-hidden rounded-none border-0 bg-background p-0 shadow-xl sm:h-auto sm:max-h-[calc(100dvh-4rem)] sm:w-full sm:max-w-lg sm:rounded-2xl sm:border-0 lg:max-w-3xl\"\n >\n <VisuallyHidden>\n <DialogTitle>{dialogTitle}</DialogTitle>\n </VisuallyHidden>\n <div className=\"flex shrink-0 items-center gap-3 border-b border-border bg-background py-4 pl-5 pr-4\">\n <Calendar aria-hidden className=\"size-6 shrink-0 text-foreground\" strokeWidth={1.75} />\n <p className=\"min-w-0 flex-1 text-sm font-medium leading-5 text-foreground\">{dialogTitle}</p>\n <IconButton\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onOpenChange(false)}\n aria-label={t('customers.calendar.editor.close', 'Close')}\n className=\"shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-5\" />\n </IconButton>\n </div>\n <div\n className=\"flex-1 overflow-y-auto\"\n onScroll={() => {\n // Tell the DS date/time fields to close their (controlled) popover\n // so a portalled popover doesn't float over the form or drift away\n // from its field while scrolling (#3747 feedback). Radix ignores\n // synthetic dismiss events, so the fields drive their own `open`.\n document.dispatchEvent(new CustomEvent(EDITOR_SCROLL_EVENT))\n }}\n >\n <div className=\"px-4 py-4 sm:px-6 sm:py-5\">\n <CrudForm<Record<string, unknown>>\n key={formKey}\n formId={FORM_ID}\n embedded\n hideFooterActions\n customFieldsManageMode=\"page\"\n fields={[]}\n groups={groups}\n initialValues={initialValues}\n entityIds={INTERACTION_ENTITY_IDS}\n onSubmit={handleSubmit}\n />\n </div>\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-3 border-t border-border bg-background px-5 py-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n >\n {t('customers.calendar.editor.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={saving}\n >\n {saving ? t('customers.calendar.editor.saving', 'Saving\u2026') : t('customers.calendar.editor.save', 'Save event')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Calendar, X } from 'lucide-react'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { CrudForm, type CrudFormGroup, type CrudFormGroupComponentProps } from '@open-mercato/ui/backend/CrudForm'\nimport { useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { projectCalendarCustomValues, useCalendarCustomFields, validateCalendarCustomValues } from './editor/useCalendarCustomFields'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { calendarDayEndInstant, calendarDayStartInstant, calendarWallTimeToInstant, calendarTimezoneOptions, defaultCalendarTimezone, isCalendarTimezone } from '../../lib/calendar/timezone'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n buildRecurrenceRule,\n buildInteractionPayload,\n computeDurationMinutes,\n createDefaultFormState,\n parseItemToFormState,\n resolveSavedOwnerUserId,\n type EditorFormState,\n} from '../../lib/calendar/editorPayload'\nimport type { ConflictScope } from '../../lib/calendar/preferences'\nimport { renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { normalizeCustomFieldSubmitValue } from '../detail/customFieldUtils'\nimport type { CalendarItem } from './types'\nimport { EDITOR_SCROLL_EVENT, Field } from './editor/inputs'\nimport { SegmentGroup } from './editor/SegmentGroup'\nimport { RelatedToField } from './editor/RelatedToField'\nimport { useConflictProbe, useEditorLabelResolution } from './editor/hooks'\nimport { EventTypePanel } from './editor/EventTypePanel'\nimport { eventTypeConfig, eventTypeOptions, isSelectableEventType, selectedEventType, useEventTypeCatalog } from './editor/useEventTypeCatalog'\nimport type { ScopedCalendarEventType } from '../../lib/calendar/eventTypeResolver'\n\nexport interface CalendarEventEditorProps {\n open: boolean\n mode: 'create' | 'edit'\n item?: CalendarItem | null\n defaultDate?: Date\n defaultRange?: { start: Date; end: Date } | null\n /** @deprecated Event-type labels are loaded from the scoped catalog. */\n typeLabels?: Record<string, string>\n typeIcons?: Record<string, string | null>\n conflictScope?: ConflictScope\n currentUserId?: string | null\n resourcesEnabled?: boolean\n staffEnabled?: boolean\n onOpenChange(open: boolean): void\n onSaved(): void\n}\n\nconst FORM_ID = 'customers-calendar-event-editor'\nconst INTERACTION_INJECTION_SPOT = `crud-form:${E.customers.customer_interaction.replace(/:/g, '.')}`\n\n// CrudForm values carry the flattened EditorFormState keys (seeded via\n// initialValues) plus cf_* custom-field keys managed by CrudForm itself.\nfunction formStateOfValues(values: Record<string, unknown>): EditorFormState {\n return values as unknown as EditorFormState\n}\n\nfunction customFieldInitialValues(item: CalendarItem): Record<string, unknown> {\n const customValues = (item.raw as Record<string, unknown>).customValues\n if (!customValues || typeof customValues !== 'object' || Array.isArray(customValues)) return {}\n return Object.fromEntries(\n Object.entries(customValues as Record<string, unknown>).map(([key, value]) => [`cf_${key}`, value]),\n )\n}\n\nfunction typeChangeDiscardFields(error: unknown): string[] | null {\n if (!error || typeof error !== 'object') return null\n const details = error as { status?: unknown; code?: unknown; fields?: unknown }\n if (details.status !== 409 || details.code !== 'calendar_type_change_confirmation_required') return null\n if (!Array.isArray(details.fields) || details.fields.length === 0 ||\n !details.fields.every((field) => typeof field === 'string' && field.length > 0)) return null\n return details.fields\n}\n\ntype EditorBodyProps = Pick<CrudFormGroupComponentProps, 'values' | 'errors' | 'setValue'> & {\n open: boolean\n isEdit: boolean\n item?: CalendarItem | null\n conflictScope: ConflictScope\n currentUserId: string | null\n resourcesEnabled: boolean\n staffEnabled: boolean\n saving: boolean\n catalogItems: readonly ScopedCalendarEventType[]\n catalogReady: boolean\n catalogError: boolean\n onRetryCatalog(): void\n onSelectedTypeChange(key: string): void\n}\n\nfunction CatalogStatusAlert({ error, onRetry }: { error: boolean; onRetry(): void }) {\n const t = useT()\n return (\n <Alert status={error ? 'error' : 'information'} className=\"rounded-lg lg:col-span-2\">\n <AlertDescription>\n {error\n ? t('customers.calendar.editor.catalogLoadFailed')\n : t('customers.calendar.editor.catalogLoading')}\n </AlertDescription>\n {error ? (\n <Button type=\"button\" variant=\"outline\" onClick={onRetry}>\n {t('customers.calendar.errors.retry')}\n </Button>\n ) : null}\n </Alert>\n )\n}\n\nconst TimezoneField = React.memo(function TimezoneField({\n value,\n error,\n disabled,\n onChange,\n}: {\n value: string | null | undefined\n error?: string\n disabled: boolean\n onChange(timezone: string): void\n}) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const timezone = value ?? defaultCalendarTimezone()\n const options = React.useMemo(() => open ? calendarTimezoneOptions(timezone) : [timezone], [open, timezone])\n const items = React.useMemo(\n () => options.map((timezone) => <SelectItem key={timezone} value={timezone}>{timezone}</SelectItem>),\n [options],\n )\n return (\n <Field label={t('customers.calendar.editor.timezone', 'Time zone')} error={error}>\n <Select value={timezone} onValueChange={onChange} disabled={disabled} open={open} onOpenChange={setOpen}>\n <SelectTrigger aria-label={t('customers.calendar.editor.timezone', 'Time zone')}><SelectValue /></SelectTrigger>\n <SelectContent>{items}</SelectContent>\n </Select>\n </Field>\n )\n})\n\nconst TypeSwitcher = React.memo(SegmentGroup) as typeof SegmentGroup\nconst NO_RESOURCES: EditorFormState['resources'] = []\nconst MemoRelatedToField = React.memo(RelatedToField)\n\n// CrudForm re-invokes the group renderer on every one of its own renders;\n// memoizing on the form state identities skips the ones that change neither\n// the values nor the errors.\nconst EditorBody = React.memo(function EditorBody({\n values,\n errors,\n setValue,\n open,\n isEdit,\n item,\n conflictScope,\n currentUserId,\n resourcesEnabled,\n staffEnabled,\n saving,\n catalogItems,\n catalogReady,\n catalogError,\n onRetryCatalog,\n onSelectedTypeChange,\n}: EditorBodyProps) {\n const t = useT()\n const form = formStateOfValues(values)\n const selectedType = form.category ?? form.kind\n const definition = selectedEventType(catalogItems, selectedType)\n const config = eventTypeConfig(definition)\n\n const update = React.useCallback(\n (patch: Partial<EditorFormState>) => {\n for (const [key, value] of Object.entries(patch)) setValue(key, value)\n },\n [setValue],\n )\n\n const updateTimezone = React.useCallback((timezone: string) => setValue('timezone', timezone), [setValue])\n const selectType = React.useCallback((type: string) => {\n const nextDefinition = selectedEventType(catalogItems, type)\n update({ kind: nextDefinition.behavior.baseKind, category: type })\n onSelectedTypeChange(type)\n }, [catalogItems, update, onSelectedTypeChange])\n const updateRelatedTo = React.useCallback((relatedTo: EditorFormState['relatedTo']) => update({ relatedTo }), [update])\n const updateDeal = React.useCallback(\n (deal: { id: string; label: string } | null) => update({ dealId: deal?.id ?? null, dealLabel: deal?.label ?? null }),\n [update],\n )\n const deal = React.useMemo(\n () => form.dealId && form.dealLabel ? { id: form.dealId, label: form.dealLabel } : null,\n [form.dealId, form.dealLabel],\n )\n const capabilities = React.useMemo(() => ({ resourcesEnabled, staffEnabled }), [resourcesEnabled, staffEnabled])\n\n useEditorLabelResolution(open, form, update)\n // Probe against the owner the interaction will actually be SAVED with so the\n // editor warning matches the grid's post-save conflict rings: tasks own via\n // their assignee, other kinds stay ownerless on create / keep the existing\n // owner on edit (conflicts then come from shared participants).\n const draftOwnerUserId = resolveSavedOwnerUserId(config, form, isEdit, item?.ownerUserId ?? null)\n // Self-exclude by the underlying interaction id (raw.id): findEditorConflictItems\n // drops candidates by raw.id, and every expanded occurrence of a recurring series\n // shares it \u2014 so the edited record never conflicts with itself.\n // Resources count toward a conflict only when the selected type can book them.\n const draftResources = resourcesEnabled && definition.behavior.fields.resources ? form.resources : NO_RESOURCES\n const conflict = useConflictProbe(open, form, config, isEdit && item ? item.raw.id : null, draftOwnerUserId, conflictScope, currentUserId, draftResources)\n\n const typeOptions = React.useMemo(\n () => eventTypeOptions(catalogItems, selectedType, t),\n [catalogItems, selectedType, t],\n )\n const typeSwitcherOptions = React.useMemo(\n () =>\n typeOptions.map((option) => ({\n value: option.value,\n label: option.label,\n icon: renderDictionaryIcon(option.icon, 'h-4 w-4'),\n })),\n [typeOptions],\n )\n\n const titleLabel = form.kind === 'email'\n ? t('customers.calendar.editor.titleLabel.email', 'Subject')\n : form.kind === 'note'\n ? t('customers.calendar.editor.titleLabel.note', 'Note')\n : t('customers.calendar.editor.titleLabel.generic', 'Title')\n\n return (\n <div className=\"grid w-full grid-cols-1 items-start gap-4 lg:grid-cols-2 lg:gap-x-6\">\n {conflict ? (\n <Alert status=\"warning\" className=\"rounded-lg lg:col-span-2\">\n <AlertTitle>{t('customers.calendar.editor.conflictTitle', 'Calendar conflict')}</AlertTitle>\n <AlertDescription>{conflict}</AlertDescription>\n </Alert>\n ) : null}\n {!catalogReady ? (\n <CatalogStatusAlert error={catalogError} onRetry={onRetryCatalog} />\n ) : null}\n {catalogReady && (definition.historical || catalogItems.some((item) => item.key === selectedType && !item.selectable)) ? (\n <Alert status=\"warning\" className=\"rounded-lg lg:col-span-2\">\n <AlertDescription>{t('customers.calendar.editor.historicalType')}</AlertDescription>\n </Alert>\n ) : null}\n <div className=\"w-full lg:col-span-2\">\n <TypeSwitcher<string>\n ariaLabel={t('customers.calendar.editor.typeSwitcher', 'Event type')}\n value={selectedType}\n onChange={selectType}\n disabled={!catalogReady}\n options={typeSwitcherOptions}\n />\n </div>\n <Field label={titleLabel} error={errors.title} className=\"lg:col-span-2\">\n <Input\n type=\"text\"\n value={form.title}\n onChange={(event) => update({ title: event.target.value })}\n placeholder={t('customers.calendar.editor.titlePlaceholder', 'Add a title\u2026')}\n aria-label={titleLabel}\n autoFocus\n size=\"lg\"\n />\n </Field>\n <TimezoneField value={form.timezone} error={errors.timezone} disabled={saving} onChange={updateTimezone} />\n <div className=\"lg:col-span-2\">\n <Field label={t('customers.calendar.editor.relatedTo', 'Related to')} error={errors.relatedTo}>\n <MemoRelatedToField\n label={t('customers.calendar.editor.relatedTo', 'Related to')}\n value={form.relatedTo}\n deal={deal}\n onChange={updateRelatedTo}\n onDealChange={updateDeal}\n error={errors.relatedTo}\n />\n </Field>\n </div>\n {catalogReady ? (\n <div className=\"lg:col-span-2\">\n <EventTypePanel\n definition={definition}\n panelKey={definition.panelKey}\n mode={isEdit ? 'edit' : 'create'}\n values={values}\n errors={errors}\n disabled={saving}\n capabilities={capabilities}\n setValue={setValue}\n />\n </div>\n ) : null}\n <Field label={t('customers.calendar.editor.description', 'Description')} className=\"lg:col-span-2\">\n <Textarea\n value={form.description}\n onChange={(event) => update({ description: event.target.value })}\n placeholder={t('customers.calendar.editor.descriptionPlaceholder', 'Add details\u2026')}\n aria-label={t('customers.calendar.editor.description', 'Description')}\n className=\"h-20 resize-none\"\n />\n </Field>\n </div>\n )\n})\n\nexport function CalendarEventEditor({\n open,\n mode,\n item,\n defaultDate,\n defaultRange,\n conflictScope,\n currentUserId,\n resourcesEnabled,\n staffEnabled,\n onOpenChange,\n onSaved,\n}: CalendarEventEditorProps) {\n const t = useT()\n const [saving, setSaving] = React.useState(false)\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const dirtyRef = React.useRef(false)\n const closeConfirmPendingRef = React.useRef(false)\n const [closePromptOpen, setClosePromptOpen] = React.useState(false)\n // The shared confirm answers Cmd/Ctrl+Enter with its confirm action, which\n // here discards the draft \u2014 on the very shortcut that saves the form. The\n // shortcut is swallowed while the prompt is up; the buttons and Escape (keep\n // editing) still answer it. Owned by an effect so the listener is removed\n // even when the editor unmounts with the prompt still open.\n React.useEffect(() => {\n if (!closePromptOpen) return\n const swallowSubmitShortcut = (event: KeyboardEvent) => {\n if (event.key !== 'Enter' || !(event.metaKey || event.ctrlKey)) return\n event.preventDefault()\n event.stopImmediatePropagation()\n }\n window.addEventListener('keydown', swallowSubmitShortcut, true)\n return () => window.removeEventListener('keydown', swallowSubmitShortcut, true)\n }, [closePromptOpen])\n const requestClose = React.useCallback(async () => {\n if (saving || closeConfirmPendingRef.current) return\n if (dirtyRef.current) {\n closeConfirmPendingRef.current = true\n setClosePromptOpen(true)\n try {\n const confirmed = await confirm({\n title: t('ui.forms.confirmUnsavedChanges', 'You have unsaved changes. Are you sure you want to leave?'),\n confirmText: t('customers.deals.detail.unsavedConfirm', 'Discard changes'),\n cancelText: t('customers.deals.detail.unsavedCancel', 'Keep editing'),\n variant: 'destructive',\n })\n if (!confirmed) return\n } finally {\n closeConfirmPendingRef.current = false\n setClosePromptOpen(false)\n }\n }\n onOpenChange(false)\n }, [confirm, onOpenChange, saving, t])\n const handleDirtyChange = React.useCallback((dirty: boolean) => { dirtyRef.current = dirty }, [])\n React.useEffect(() => { if (!open) dirtyRef.current = false }, [open])\n const isEdit = mode === 'edit' && Boolean(item?.id)\n const catalog = useEventTypeCatalog(open)\n const { items: catalogItems, status: catalogStatus, retry: retryCatalog } = catalog\n const [selectedTypeKey, setSelectedTypeKey] = React.useState(() => isEdit && item ? item.interactionType : 'meeting')\n const autoSelectedCreateType = !isEdit && catalog.status === 'ready' && !isSelectableEventType(catalog.items, 'meeting')\n ? catalog.items.find((entry) => entry.selectable && !entry.historical) ?? null\n : null\n\n // CrudForm reads initialValues once, so every dialog open gets a fresh form\n // instance keyed by the open sequence + edited record.\n const [openSeq, setOpenSeq] = React.useState(0)\n const wasOpenRef = React.useRef(false)\n React.useEffect(() => {\n if (open && !wasOpenRef.current) setOpenSeq((seq) => seq + 1)\n wasOpenRef.current = open\n }, [open])\n const formKey = `${mode}:${item?.id ?? 'new'}:${openSeq}:${autoSelectedCreateType?.key ?? 'default'}`\n\n const initialValues = React.useMemo<Record<string, unknown>>(() => {\n if (isEdit && item) {\n return {\n ...parseItemToFormState(item),\n ...customFieldInitialValues(item),\n id: item.id,\n updatedAt: item.updatedAt ?? undefined,\n }\n }\n const defaults = createDefaultFormState(defaultDate ?? null, undefined, defaultRange ?? null)\n if (!autoSelectedCreateType) return { ...defaults }\n return {\n ...defaults,\n kind: autoSelectedCreateType.behavior.baseKind,\n category: autoSelectedCreateType.key,\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- openSeq re-seeds defaults per dialog open\n }, [isEdit, item, defaultDate, defaultRange, openSeq, autoSelectedCreateType])\n const initialTypeKey = String(initialValues.category ?? initialValues.kind ?? 'meeting')\n React.useEffect(() => { setSelectedTypeKey(initialTypeKey) }, [initialTypeKey, formKey])\n const selectedDefinition = selectedEventType(catalog.items, selectedTypeKey)\n const customFields = useCalendarCustomFields(open, E.customers.customer_interaction, selectedDefinition.behavior.customFieldsetIds)\n const injectionWidgets = useInjectionWidgets(INTERACTION_INJECTION_SPOT)\n const canCreateType = isSelectableEventType(catalog.items, selectedTypeKey)\n const formReady = isEdit || catalog.status === 'ready'\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n const form = formStateOfValues(values)\n if (catalogStatus !== 'ready' || customFields.status !== 'ready' || injectionWidgets.loading || injectionWidgets.error) {\n throw createCrudFormError(t('customers.calendar.editor.catalogLoadFailed'))\n }\n const definition = selectedEventType(catalogItems, form.category ?? form.kind)\n const selectedKey = form.category ?? form.kind\n if ((mode === 'create' || selectedKey !== initialTypeKey) &&\n !isSelectableEventType(catalogItems, selectedKey)) {\n throw createCrudFormError(t('customers.calendar.editor.typeUnavailable'))\n }\n const config = eventTypeConfig(definition)\n const fieldErrors: Record<string, string> = {}\n const timezone = form.timezone ?? defaultCalendarTimezone()\n const startTime = form.allDay && config.hasAllDay ? '00:00' : form.startTime\n if (!isCalendarTimezone(timezone)) fieldErrors.timezone = t('customers.calendar.editor.validation.timezoneInvalid', 'Choose a valid time zone')\n else if (!(form.allDay && config.hasAllDay ? calendarDayStartInstant(form.date, timezone) : calendarWallTimeToInstant(form.date, startTime, timezone))) {\n fieldErrors[form.allDay && config.hasAllDay ? 'date' : 'startTime'] = t('customers.calendar.editor.validation.timezoneGap', 'This local time does not exist in the selected time zone')\n }\n if (config.hasEnd && !form.allDay && isCalendarTimezone(timezone) && !calendarWallTimeToInstant(form.endDate, form.endTime, timezone)) {\n fieldErrors.ends = t('customers.calendar.editor.validation.timezoneGap', 'This local time does not exist in the selected time zone')\n }\n if (config.hasRepeat && form.repeatFreq !== 'none' && isCalendarTimezone(timezone) && form.repeatEndType === 'date' && form.repeatUntilDate && !calendarDayEndInstant(form.repeatUntilDate, timezone)) {\n fieldErrors.repeatUntilDate = t('customers.calendar.editor.validation.timezoneGap', 'This local time does not exist in the selected time zone')\n }\n if (!form.title.trim()) {\n fieldErrors.title = t('customers.calendar.editor.validation.titleRequired', 'Title is required')\n }\n if (!form.relatedTo) {\n fieldErrors.relatedTo = t('customers.calendar.editor.validation.relatedToRequired', 'Select a person or company to link this event')\n }\n if (!fieldErrors.ends && !fieldErrors.startTime && !fieldErrors.date && config.hasEnd && !form.allDay && computeDurationMinutes(form) === null) {\n fieldErrors.ends = t('customers.calendar.editor.validation.endsBeforeStarts', 'End must be after start')\n }\n // A task must be assigned to a team member \u2014 surface the requirement inline\n // instead of letting the save fail with no visible reason (#3747 feedback).\n if (config.people === 'assignee' && staffEnabled !== false && !form.assigneeUserId) {\n fieldErrors.assignee = t('customers.calendar.editor.validation.assigneeRequired', 'Assign this task to a team member')\n }\n if (Object.keys(fieldErrors).length > 0) {\n throw createCrudFormError(Object.values(fieldErrors)[0], fieldErrors)\n }\n const customValidation = validateCalendarCustomValues(values, customFields.definitions)\n if (!customValidation.ok) {\n const translatedErrors = Object.fromEntries(Object.entries(customValidation.fieldErrors).map(([key, message]) => [key, t(message, message)]))\n throw createCrudFormError(Object.values(translatedErrors)[0], translatedErrors)\n }\n setSaving(true)\n try {\n const payload = buildInteractionPayload({ ...form, timezone }, {\n config,\n mode,\n id: item?.id,\n resourcesEnabled: resourcesEnabled === true,\n staffEnabled: staffEnabled !== false,\n })\n payload.enforceSelectableType = true\n const applicable = definition.behavior.fields\n const time = form.allDay && applicable.allDay ? '00:00' : form.startTime\n payload.time = time\n payload.scheduledAt = (form.allDay && applicable.allDay ? calendarDayStartInstant(form.date, timezone) : calendarWallTimeToInstant(form.date, time, timezone))!.toISOString()\n payload.timezone = timezone\n payload.allDay = applicable.allDay ? form.allDay : null\n payload.durationMinutes = applicable.endTime && !(form.allDay && applicable.allDay) ? computeDurationMinutes(form) : null\n payload.location = applicable.location === 'none' ? null : form.location.trim() || null\n const recurrenceRule = applicable.recurrence ? buildRecurrenceRule(form) : null\n payload.recurrenceRule = recurrenceRule\n payload.recurrenceEnd = recurrenceRule && form.repeatEndType === 'date' && form.repeatUntilDate\n ? calendarDayEndInstant(form.repeatUntilDate, timezone)!.toISOString()\n : null\n payload.participants = applicable.people !== 'none' && applicable.people !== 'assignee' && form.participants.length\n ? form.participants.map((participant) => ({\n userId: participant.userId,\n name: participant.name,\n email: participant.email,\n status: participant.isCustomer ? 'customer' : 'pending',\n }))\n : null\n if (applicable.people === 'assignee' && staffEnabled !== false) payload.ownerUserId = form.assigneeUserId ?? null\n else delete payload.ownerUserId\n if (applicable.priority) payload.priority = form.priority === 'low' ? 10 : form.priority === 'high' ? 90 : 50\n else delete payload.priority\n if (!applicable.resources) delete payload.linkedEntities\n const custom = collectCustomFieldValues(projectCalendarCustomValues(values, customFields.definitions), {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n for (const [key, value] of Object.entries(custom)) payload[`cf_${key}`] = value\n // CrudForm supplies the optimistic-lock header (auto-derived from\n // initialValues.updatedAt) via scoped request headers around onSubmit.\n const submitInteraction = (confirmDiscardInapplicableValues: boolean) => apiCallOrThrow('/api/customers/interactions', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(confirmDiscardInapplicableValues\n ? { ...payload, confirmDiscardInapplicableValues: true }\n : payload),\n })\n try {\n await submitInteraction(false)\n } catch (error) {\n const fields = typeChangeDiscardFields(error)\n if (!fields) throw error\n const approved = await confirm({\n title: t('customers.calendar.editor.discardTitle'),\n text: `${t('customers.calendar.editor.discardDescription')} ${t('customers.calendar.editor.discardFields')} ${fields.map((field) => {\n const definition = customFields.allDefinitions.find((entry) => `cf_${entry.key}` === field)\n if (definition?.label) return definition.label\n const labelKeys: Record<string, string> = {\n location: 'customers.calendar.editor.location',\n participants: 'customers.calendar.editor.attendees',\n linkedEntities: 'customers.calendar.editor.resources',\n allDay: 'customers.calendar.editor.allDay',\n durationMinutes: 'customers.calendar.editor.dates.ends',\n priority: 'customers.calendar.editor.priority.label',\n recurrenceRule: 'customers.calendar.editor.repeat.label',\n recurrenceEnd: 'customers.calendar.editor.repeat.ends',\n }\n return t(labelKeys[field] ?? 'customers.calendar.editor.discardUnknownField')\n }).join(', ')}`,\n confirmText: t('customers.calendar.editor.discardConfirm'),\n cancelText: t('customers.calendar.editor.cancel'),\n variant: 'destructive',\n })\n if (!approved) return\n await submitInteraction(true)\n }\n flash(t('customers.calendar.editor.saved', 'Event saved'), 'success')\n onOpenChange(false)\n requestAnimationFrame(() => { onSaved() })\n } catch (err) {\n // Surface an optimistic-lock 409 as the persistent conflict bar and\n // close \u2014 the bar renders at page level, behind the dialog overlay.\n if (extractOptimisticLockConflict(err)) {\n surfaceRecordConflict(err, t)\n onOpenChange(false)\n return\n }\n throw err\n } finally {\n setSaving(false)\n }\n },\n [catalogItems, catalogStatus, customFields.status, customFields.definitions, customFields.allDefinitions, injectionWidgets.loading, injectionWidgets.error, confirm, initialTypeKey, isEdit, item?.id, mode, onOpenChange, onSaved, resourcesEnabled, staffEnabled, t],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'details',\n bare: true,\n component: (ctx) => (\n <EditorBody\n values={ctx.values}\n errors={ctx.errors}\n setValue={ctx.setValue}\n open={open}\n isEdit={isEdit}\n item={item}\n conflictScope={conflictScope ?? 'all'}\n currentUserId={currentUserId ?? null}\n resourcesEnabled={resourcesEnabled === true}\n staffEnabled={staffEnabled !== false}\n saving={saving}\n catalogItems={catalogItems}\n catalogReady={catalogStatus === 'ready'}\n catalogError={catalogStatus === 'error'}\n onRetryCatalog={retryCatalog}\n onSelectedTypeChange={setSelectedTypeKey}\n />\n ),\n },\n ...(customFields.fields.length ? [{ id: 'customFields', title: t('entities.customFields.title'), fields: customFields.fields.map((field) => field.id) }] : []),\n ],\n [open, isEdit, item, conflictScope, currentUserId, resourcesEnabled, staffEnabled, saving, catalogItems, catalogStatus, retryCatalog, customFields.fields, t],\n )\n\n const handleKeyDown = useDialogKeyHandler({\n onCancel: () => { void requestClose() },\n onConfirm: () => {\n const formElement = document.getElementById(FORM_ID)\n if (formElement instanceof HTMLFormElement) formElement.requestSubmit()\n },\n disabled: saving || customFields.status !== 'ready' || injectionWidgets.loading || !!injectionWidgets.error || catalog.status !== 'ready' || (mode === 'create' && !canCreateType),\n })\n\n const dialogTitle = isEdit ? t('customers.calendar.editor.title.edit', 'Edit event') : t('customers.calendar.editor.title.create', 'New event')\n\n return (\n <Dialog open={open} onOpenChange={(nextOpen) => { if (nextOpen) onOpenChange(true); else void requestClose() }}>\n <DialogContent\n onKeyDown={handleKeyDown}\n // Only dismiss on a genuine click OUTSIDE the whole editor. Radix\n // relays a click inside the dialog (but outside an open DS\n // DatePicker/Select popover) up to the dialog as an \"interact\n // outside\" event when it dismisses that popover \u2014 without this guard\n // it would tear down the entire editor. Keep it open when the target\n // is inside the dialog body or inside any portalled popover. The\n // shared confirm renders as a native modal `<dialog>` on top of the\n // editor; answering it is not an outside click either, otherwise it\n // would re-request the close it is asking about.\n onInteractOutside={(event) => {\n const target = event.detail.originalEvent.target as HTMLElement | null\n if (target?.closest('[data-dialog-content]') || target?.closest('[data-radix-popper-content-wrapper]') || target?.closest('dialog')) {\n event.preventDefault()\n }\n }}\n aria-describedby={undefined}\n dismissible={false}\n className=\"flex h-dvh max-h-dvh w-screen max-w-none flex-col gap-0 overflow-hidden rounded-none border-0 bg-background p-0 shadow-xl sm:h-auto sm:max-h-[calc(100dvh-4rem)] sm:w-full sm:max-w-lg sm:rounded-2xl sm:border-0 lg:max-w-3xl\"\n >\n <VisuallyHidden>\n <DialogTitle>{dialogTitle}</DialogTitle>\n </VisuallyHidden>\n <div className=\"flex shrink-0 items-center gap-3 border-b border-border bg-background py-4 pl-5 pr-4\">\n <Calendar aria-hidden className=\"size-6 shrink-0 text-foreground\" strokeWidth={1.75} />\n <p className=\"min-w-0 flex-1 text-sm font-medium leading-5 text-foreground\">{dialogTitle}</p>\n <IconButton\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => { void requestClose() }}\n aria-label={t('customers.calendar.editor.close', 'Close')}\n className=\"shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-5\" />\n </IconButton>\n </div>\n <div\n className=\"flex-1 overflow-y-auto\"\n onScroll={() => {\n // Tell the DS date/time fields to close their (controlled) popover\n // so a portalled popover doesn't float over the form or drift away\n // from its field while scrolling (#3747 feedback). Radix ignores\n // synthetic dismiss events, so the fields drive their own `open`.\n document.dispatchEvent(new CustomEvent(EDITOR_SCROLL_EVENT))\n }}\n >\n <div className=\"px-4 py-4 sm:px-6 sm:py-5\">\n {formReady ? (\n <CrudForm<Record<string, unknown>>\n key={formKey}\n formId={FORM_ID}\n embedded\n trackDirtyWhenEmbedded\n onDirtyChange={handleDirtyChange}\n hideFooterActions\n customFieldsManageMode=\"page\"\n fields={customFields.fields}\n groups={groups}\n initialValues={initialValues}\n injectionSpotId={INTERACTION_INJECTION_SPOT}\n onSubmit={handleSubmit}\n />\n ) : (\n <CatalogStatusAlert error={catalog.status === 'error'} onRetry={catalog.retry} />\n )}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-3 border-t border-border bg-background px-5 py-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n >\n {t('customers.calendar.editor.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={saving || customFields.status !== 'ready' || injectionWidgets.loading || !!injectionWidgets.error || catalog.status !== 'ready' || (mode === 'create' && !canCreateType)}\n >\n {saving ? t('customers.calendar.editor.saving', 'Saving\u2026') : t('customers.calendar.editor.save', 'Save event')}\n </Button>\n </div>\n </DialogContent>\n {ConfirmDialogElement}\n </Dialog>\n )\n}\n"],
5
+ "mappings": ";AA6GI,SACE,KADF;AA3GJ,YAAY,WAAW;AACvB,SAAS,UAAU,SAAS;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,YAAY;AACrB,SAAS,sBAAsB;AAC/B,SAAS,qCAAqC;AAC9C,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,aAAa;AACtB,SAAS,gBAAsE;AAC/E,SAAS,2BAA2B;AACpC,SAAS,6BAA6B,yBAAyB,oCAAoC;AACnG,SAAS,gCAAgC;AACzC,SAAS,OAAO,kBAAkB,kBAAkB;AACpD,SAAS,cAAc;AACvB,SAAS,QAAQ,eAAe,mBAAmB;AACnD,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,QAAQ,eAAe,YAAY,eAAe,mBAAmB;AAC9E,SAAS,uBAAuB,yBAAyB,2BAA2B,yBAAyB,yBAAyB,0BAA0B;AAChK,SAAS,gBAAgB;AACzB,SAAS,2BAA2B;AACpC,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,4BAA4B;AACrC,SAAS,uCAAuC;AAEhD,SAAS,qBAAqB,aAAa;AAC3C,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB,gCAAgC;AAC3D,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB,kBAAkB,uBAAuB,mBAAmB,2BAA2B;AAoBjH,MAAM,UAAU;AAChB,MAAM,6BAA6B,aAAa,EAAE,UAAU,qBAAqB,QAAQ,MAAM,GAAG,CAAC;AAInG,SAAS,kBAAkB,QAAkD;AAC3E,SAAO;AACT;AAEA,SAAS,yBAAyB,MAA6C;AAC7E,QAAM,eAAgB,KAAK,IAAgC;AAC3D,MAAI,CAAC,gBAAgB,OAAO,iBAAiB,YAAY,MAAM,QAAQ,YAAY,EAAG,QAAO,CAAC;AAC9F,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,YAAuC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,EACpG;AACF;AAEA,SAAS,wBAAwB,OAAiC;AAChE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,UAAU;AAChB,MAAI,QAAQ,WAAW,OAAO,QAAQ,SAAS,6CAA8C,QAAO;AACpG,MAAI,CAAC,MAAM,QAAQ,QAAQ,MAAM,KAAK,QAAQ,OAAO,WAAW,KAC9D,CAAC,QAAQ,OAAO,MAAM,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,EAAG,QAAO;AAC1F,SAAO,QAAQ;AACjB;AAkBA,SAAS,mBAAmB,EAAE,OAAO,QAAQ,GAAwC;AACnF,QAAM,IAAI,KAAK;AACf,SACE,qBAAC,SAAM,QAAQ,QAAQ,UAAU,eAAe,WAAU,4BACxD;AAAA,wBAAC,oBACE,kBACG,EAAE,6CAA6C,IAC/C,EAAE,0CAA0C,GAClD;AAAA,IACC,QACC,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,SAC9C,YAAE,iCAAiC,GACtC,IACE;AAAA,KACN;AAEJ;AAEA,MAAM,gBAAgB,MAAM,KAAK,SAASA,eAAc;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAC5C,QAAM,WAAW,SAAS,wBAAwB;AAClD,QAAM,UAAU,MAAM,QAAQ,MAAM,OAAO,wBAAwB,QAAQ,IAAI,CAAC,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC;AAC3G,QAAM,QAAQ,MAAM;AAAA,IAClB,MAAM,QAAQ,IAAI,CAACC,cAAa,oBAAC,cAA0B,OAAOA,WAAW,UAAAA,aAA5BA,SAAqC,CAAa;AAAA,IACnG,CAAC,OAAO;AAAA,EACV;AACA,SACE,oBAAC,SAAM,OAAO,EAAE,sCAAsC,WAAW,GAAG,OAClE,+BAAC,UAAO,OAAO,UAAU,eAAe,UAAU,UAAoB,MAAY,cAAc,SAC9F;AAAA,wBAAC,iBAAc,cAAY,EAAE,sCAAsC,WAAW,GAAG,8BAAC,eAAY,GAAE;AAAA,IAChG,oBAAC,iBAAe,iBAAM;AAAA,KACxB,GACF;AAEJ,CAAC;AAED,MAAM,eAAe,MAAM,KAAK,YAAY;AAC5C,MAAM,eAA6C,CAAC;AACpD,MAAM,qBAAqB,MAAM,KAAK,cAAc;AAKpD,MAAM,aAAa,MAAM,KAAK,SAASC,YAAW;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,IAAI,KAAK;AACf,QAAM,OAAO,kBAAkB,MAAM;AACrC,QAAM,eAAe,KAAK,YAAY,KAAK;AAC3C,QAAM,aAAa,kBAAkB,cAAc,YAAY;AAC/D,QAAM,SAAS,gBAAgB,UAAU;AAEzC,QAAM,SAAS,MAAM;AAAA,IACnB,CAAC,UAAoC;AACnC,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,EAAG,UAAS,KAAK,KAAK;AAAA,IACvE;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,iBAAiB,MAAM,YAAY,CAAC,aAAqB,SAAS,YAAY,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACzG,QAAM,aAAa,MAAM,YAAY,CAAC,SAAiB;AACrD,UAAM,iBAAiB,kBAAkB,cAAc,IAAI;AAC3D,WAAO,EAAE,MAAM,eAAe,SAAS,UAAU,UAAU,KAAK,CAAC;AACjE,yBAAqB,IAAI;AAAA,EAC3B,GAAG,CAAC,cAAc,QAAQ,oBAAoB,CAAC;AAC/C,QAAM,kBAAkB,MAAM,YAAY,CAAC,cAA4C,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;AACtH,QAAM,aAAa,MAAM;AAAA,IACvB,CAACC,UAA+C,OAAO,EAAE,QAAQA,OAAM,MAAM,MAAM,WAAWA,OAAM,SAAS,KAAK,CAAC;AAAA,IACnH,CAAC,MAAM;AAAA,EACT;AACA,QAAM,OAAO,MAAM;AAAA,IACjB,MAAM,KAAK,UAAU,KAAK,YAAY,EAAE,IAAI,KAAK,QAAQ,OAAO,KAAK,UAAU,IAAI;AAAA,IACnF,CAAC,KAAK,QAAQ,KAAK,SAAS;AAAA,EAC9B;AACA,QAAM,eAAe,MAAM,QAAQ,OAAO,EAAE,kBAAkB,aAAa,IAAI,CAAC,kBAAkB,YAAY,CAAC;AAE/G,2BAAyB,MAAM,MAAM,MAAM;AAK3C,QAAM,mBAAmB,wBAAwB,QAAQ,MAAM,QAAQ,MAAM,eAAe,IAAI;AAKhG,QAAM,iBAAiB,oBAAoB,WAAW,SAAS,OAAO,YAAY,KAAK,YAAY;AACnG,QAAM,WAAW,iBAAiB,MAAM,MAAM,QAAQ,UAAU,OAAO,KAAK,IAAI,KAAK,MAAM,kBAAkB,eAAe,eAAe,cAAc;AAEzJ,QAAM,cAAc,MAAM;AAAA,IACxB,MAAM,iBAAiB,cAAc,cAAc,CAAC;AAAA,IACpD,CAAC,cAAc,cAAc,CAAC;AAAA,EAChC;AACA,QAAM,sBAAsB,MAAM;AAAA,IAChC,MACE,YAAY,IAAI,CAAC,YAAY;AAAA,MAC3B,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,MAAM,qBAAqB,OAAO,MAAM,SAAS;AAAA,IACnD,EAAE;AAAA,IACJ,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,aAAa,KAAK,SAAS,UAC7B,EAAE,8CAA8C,SAAS,IACzD,KAAK,SAAS,SACZ,EAAE,6CAA6C,MAAM,IACrD,EAAE,gDAAgD,OAAO;AAE/D,SACE,qBAAC,SAAI,WAAU,uEACZ;AAAA,eACC,qBAAC,SAAM,QAAO,WAAU,WAAU,4BAChC;AAAA,0BAAC,cAAY,YAAE,2CAA2C,mBAAmB,GAAE;AAAA,MAC/E,oBAAC,oBAAkB,oBAAS;AAAA,OAC9B,IACE;AAAA,IACH,CAAC,eACA,oBAAC,sBAAmB,OAAO,cAAc,SAAS,gBAAgB,IAChE;AAAA,IACH,iBAAiB,WAAW,cAAc,aAAa,KAAK,CAACC,UAASA,MAAK,QAAQ,gBAAgB,CAACA,MAAK,UAAU,KAClH,oBAAC,SAAM,QAAO,WAAU,WAAU,4BAChC,8BAAC,oBAAkB,YAAE,0CAA0C,GAAE,GACnE,IACE;AAAA,IACJ,oBAAC,SAAI,WAAU,wBACb;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,EAAE,0CAA0C,YAAY;AAAA,QACnE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,UAAU,CAAC;AAAA,QACX,SAAS;AAAA;AAAA,IACX,GACF;AAAA,IACA,oBAAC,SAAM,OAAO,YAAY,OAAO,OAAO,OAAO,WAAU,iBACvD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAO,KAAK;AAAA,QACZ,UAAU,CAAC,UAAU,OAAO,EAAE,OAAO,MAAM,OAAO,MAAM,CAAC;AAAA,QACzD,aAAa,EAAE,8CAA8C,mBAAc;AAAA,QAC3E,cAAY;AAAA,QACZ,WAAS;AAAA,QACT,MAAK;AAAA;AAAA,IACP,GACF;AAAA,IACA,oBAAC,iBAAc,OAAO,KAAK,UAAU,OAAO,OAAO,UAAU,UAAU,QAAQ,UAAU,gBAAgB;AAAA,IACzG,oBAAC,SAAI,WAAU,iBACb,8BAAC,SAAM,OAAO,EAAE,uCAAuC,YAAY,GAAG,OAAO,OAAO,WAClF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,uCAAuC,YAAY;AAAA,QAC5D,OAAO,KAAK;AAAA,QACZ;AAAA,QACA,UAAU;AAAA,QACV,cAAc;AAAA,QACd,OAAO,OAAO;AAAA;AAAA,IAChB,GACF,GACF;AAAA,IACC,eACC,oBAAC,SAAI,WAAU,iBACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,UAAU,WAAW;AAAA,QACrB,MAAM,SAAS,SAAS;AAAA,QACxB;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV;AAAA,QACA;AAAA;AAAA,IACF,GACF,IACE;AAAA,IACJ,oBAAC,SAAM,OAAO,EAAE,yCAAyC,aAAa,GAAG,WAAU,iBACjF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,KAAK;AAAA,QACZ,UAAU,CAAC,UAAU,OAAO,EAAE,aAAa,MAAM,OAAO,MAAM,CAAC;AAAA,QAC/D,aAAa,EAAE,oDAAoD,mBAAc;AAAA,QACjF,cAAY,EAAE,yCAAyC,aAAa;AAAA,QACpE,WAAU;AAAA;AAAA,IACZ,GACF;AAAA,KACF;AAEJ,CAAC;AAEM,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,KAAK;AAChD,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,WAAW,MAAM,OAAO,KAAK;AACnC,QAAM,yBAAyB,MAAM,OAAO,KAAK;AACjD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,KAAK;AAMlE,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,gBAAiB;AACtB,UAAM,wBAAwB,CAAC,UAAyB;AACtD,UAAI,MAAM,QAAQ,WAAW,EAAE,MAAM,WAAW,MAAM,SAAU;AAChE,YAAM,eAAe;AACrB,YAAM,yBAAyB;AAAA,IACjC;AACA,WAAO,iBAAiB,WAAW,uBAAuB,IAAI;AAC9D,WAAO,MAAM,OAAO,oBAAoB,WAAW,uBAAuB,IAAI;AAAA,EAChF,GAAG,CAAC,eAAe,CAAC;AACpB,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,QAAI,UAAU,uBAAuB,QAAS;AAC9C,QAAI,SAAS,SAAS;AACpB,6BAAuB,UAAU;AACjC,yBAAmB,IAAI;AACvB,UAAI;AACF,cAAM,YAAY,MAAM,QAAQ;AAAA,UAC9B,OAAO,EAAE,kCAAkC,2DAA2D;AAAA,UACtG,aAAa,EAAE,yCAAyC,iBAAiB;AAAA,UACzE,YAAY,EAAE,wCAAwC,cAAc;AAAA,UACpE,SAAS;AAAA,QACX,CAAC;AACD,YAAI,CAAC,UAAW;AAAA,MAClB,UAAE;AACA,+BAAuB,UAAU;AACjC,2BAAmB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,SAAS,cAAc,QAAQ,CAAC,CAAC;AACrC,QAAM,oBAAoB,MAAM,YAAY,CAAC,UAAmB;AAAE,aAAS,UAAU;AAAA,EAAM,GAAG,CAAC,CAAC;AAChG,QAAM,UAAU,MAAM;AAAE,QAAI,CAAC,KAAM,UAAS,UAAU;AAAA,EAAM,GAAG,CAAC,IAAI,CAAC;AACrE,QAAM,SAAS,SAAS,UAAU,QAAQ,MAAM,EAAE;AAClD,QAAM,UAAU,oBAAoB,IAAI;AACxC,QAAM,EAAE,OAAO,cAAc,QAAQ,eAAe,OAAO,aAAa,IAAI;AAC5E,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,MAAM,UAAU,OAAO,KAAK,kBAAkB,SAAS;AACpH,QAAM,yBAAyB,CAAC,UAAU,QAAQ,WAAW,WAAW,CAAC,sBAAsB,QAAQ,OAAO,SAAS,IACnH,QAAQ,MAAM,KAAK,CAAC,UAAU,MAAM,cAAc,CAAC,MAAM,UAAU,KAAK,OACxE;AAIJ,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,CAAC;AAC9C,QAAM,aAAa,MAAM,OAAO,KAAK;AACrC,QAAM,UAAU,MAAM;AACpB,QAAI,QAAQ,CAAC,WAAW,QAAS,YAAW,CAAC,QAAQ,MAAM,CAAC;AAC5D,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,IAAI,CAAC;AACT,QAAM,UAAU,GAAG,IAAI,IAAI,MAAM,MAAM,KAAK,IAAI,OAAO,IAAI,wBAAwB,OAAO,SAAS;AAEnG,QAAM,gBAAgB,MAAM,QAAiC,MAAM;AACjE,QAAI,UAAU,MAAM;AAClB,aAAO;AAAA,QACL,GAAG,qBAAqB,IAAI;AAAA,QAC5B,GAAG,yBAAyB,IAAI;AAAA,QAChC,IAAI,KAAK;AAAA,QACT,WAAW,KAAK,aAAa;AAAA,MAC/B;AAAA,IACF;AACA,UAAM,WAAW,uBAAuB,eAAe,MAAM,QAAW,gBAAgB,IAAI;AAC5F,QAAI,CAAC,uBAAwB,QAAO,EAAE,GAAG,SAAS;AAClD,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,uBAAuB,SAAS;AAAA,MACtC,UAAU,uBAAuB;AAAA,IACnC;AAAA,EAEF,GAAG,CAAC,QAAQ,MAAM,aAAa,cAAc,SAAS,sBAAsB,CAAC;AAC7E,QAAM,iBAAiB,OAAO,cAAc,YAAY,cAAc,QAAQ,SAAS;AACvF,QAAM,UAAU,MAAM;AAAE,uBAAmB,cAAc;AAAA,EAAE,GAAG,CAAC,gBAAgB,OAAO,CAAC;AACvF,QAAM,qBAAqB,kBAAkB,QAAQ,OAAO,eAAe;AAC3E,QAAM,eAAe,wBAAwB,MAAM,EAAE,UAAU,sBAAsB,mBAAmB,SAAS,iBAAiB;AAClI,QAAM,mBAAmB,oBAAoB,0BAA0B;AACvE,QAAM,gBAAgB,sBAAsB,QAAQ,OAAO,eAAe;AAC1E,QAAM,YAAY,UAAU,QAAQ,WAAW;AAE/C,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,WAAoC;AACzC,YAAM,OAAO,kBAAkB,MAAM;AACrC,UAAI,kBAAkB,WAAW,aAAa,WAAW,WAAW,iBAAiB,WAAW,iBAAiB,OAAO;AACtH,cAAM,oBAAoB,EAAE,6CAA6C,CAAC;AAAA,MAC5E;AACA,YAAM,aAAa,kBAAkB,cAAc,KAAK,YAAY,KAAK,IAAI;AAC7E,YAAM,cAAc,KAAK,YAAY,KAAK;AAC1C,WAAK,SAAS,YAAY,gBAAgB,mBACxC,CAAC,sBAAsB,cAAc,WAAW,GAAG;AACnD,cAAM,oBAAoB,EAAE,2CAA2C,CAAC;AAAA,MAC1E;AACA,YAAM,SAAS,gBAAgB,UAAU;AACzC,YAAM,cAAsC,CAAC;AAC7C,YAAM,WAAW,KAAK,YAAY,wBAAwB;AAC1D,YAAM,YAAY,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;AACnE,UAAI,CAAC,mBAAmB,QAAQ,EAAG,aAAY,WAAW,EAAE,wDAAwD,0BAA0B;AAAA,eACrI,EAAE,KAAK,UAAU,OAAO,YAAY,wBAAwB,KAAK,MAAM,QAAQ,IAAI,0BAA0B,KAAK,MAAM,WAAW,QAAQ,IAAI;AACtJ,oBAAY,KAAK,UAAU,OAAO,YAAY,SAAS,WAAW,IAAI,EAAE,oDAAoD,0DAA0D;AAAA,MACxL;AACA,UAAI,OAAO,UAAU,CAAC,KAAK,UAAU,mBAAmB,QAAQ,KAAK,CAAC,0BAA0B,KAAK,SAAS,KAAK,SAAS,QAAQ,GAAG;AACrI,oBAAY,OAAO,EAAE,oDAAoD,0DAA0D;AAAA,MACrI;AACA,UAAI,OAAO,aAAa,KAAK,eAAe,UAAU,mBAAmB,QAAQ,KAAK,KAAK,kBAAkB,UAAU,KAAK,mBAAmB,CAAC,sBAAsB,KAAK,iBAAiB,QAAQ,GAAG;AACrM,oBAAY,kBAAkB,EAAE,oDAAoD,0DAA0D;AAAA,MAChJ;AACA,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACtB,oBAAY,QAAQ,EAAE,sDAAsD,mBAAmB;AAAA,MACjG;AACA,UAAI,CAAC,KAAK,WAAW;AACnB,oBAAY,YAAY,EAAE,0DAA0D,+CAA+C;AAAA,MACrI;AACA,UAAI,CAAC,YAAY,QAAQ,CAAC,YAAY,aAAa,CAAC,YAAY,QAAQ,OAAO,UAAU,CAAC,KAAK,UAAU,uBAAuB,IAAI,MAAM,MAAM;AAC9I,oBAAY,OAAO,EAAE,yDAAyD,yBAAyB;AAAA,MACzG;AAGA,UAAI,OAAO,WAAW,cAAc,iBAAiB,SAAS,CAAC,KAAK,gBAAgB;AAClF,oBAAY,WAAW,EAAE,yDAAyD,mCAAmC;AAAA,MACvH;AACA,UAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GAAG;AACvC,cAAM,oBAAoB,OAAO,OAAO,WAAW,EAAE,CAAC,GAAG,WAAW;AAAA,MACtE;AACA,YAAM,mBAAmB,6BAA6B,QAAQ,aAAa,WAAW;AACtF,UAAI,CAAC,iBAAiB,IAAI;AACxB,cAAM,mBAAmB,OAAO,YAAY,OAAO,QAAQ,iBAAiB,WAAW,EAAE,IAAI,CAAC,CAAC,KAAK,OAAO,MAAM,CAAC,KAAK,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC;AAC5I,cAAM,oBAAoB,OAAO,OAAO,gBAAgB,EAAE,CAAC,GAAG,gBAAgB;AAAA,MAChF;AACA,gBAAU,IAAI;AACd,UAAI;AACF,cAAM,UAAU,wBAAwB,EAAE,GAAG,MAAM,SAAS,GAAG;AAAA,UAC7D;AAAA,UACA;AAAA,UACA,IAAI,MAAM;AAAA,UACV,kBAAkB,qBAAqB;AAAA,UACvC,cAAc,iBAAiB;AAAA,QACjC,CAAC;AACD,gBAAQ,wBAAwB;AAChC,cAAM,aAAa,WAAW,SAAS;AACvC,cAAM,OAAO,KAAK,UAAU,WAAW,SAAS,UAAU,KAAK;AAC/D,gBAAQ,OAAO;AACf,gBAAQ,eAAe,KAAK,UAAU,WAAW,SAAS,wBAAwB,KAAK,MAAM,QAAQ,IAAI,0BAA0B,KAAK,MAAM,MAAM,QAAQ,GAAI,YAAY;AAC5K,gBAAQ,WAAW;AACnB,gBAAQ,SAAS,WAAW,SAAS,KAAK,SAAS;AACnD,gBAAQ,kBAAkB,WAAW,WAAW,EAAE,KAAK,UAAU,WAAW,UAAU,uBAAuB,IAAI,IAAI;AACrH,gBAAQ,WAAW,WAAW,aAAa,SAAS,OAAO,KAAK,SAAS,KAAK,KAAK;AACnF,cAAM,iBAAiB,WAAW,aAAa,oBAAoB,IAAI,IAAI;AAC3E,gBAAQ,iBAAiB;AACzB,gBAAQ,gBAAgB,kBAAkB,KAAK,kBAAkB,UAAU,KAAK,kBAC5E,sBAAsB,KAAK,iBAAiB,QAAQ,EAAG,YAAY,IACnE;AACJ,gBAAQ,eAAe,WAAW,WAAW,UAAU,WAAW,WAAW,cAAc,KAAK,aAAa,SACzG,KAAK,aAAa,IAAI,CAAC,iBAAiB;AAAA,UACtC,QAAQ,YAAY;AAAA,UACpB,MAAM,YAAY;AAAA,UAClB,OAAO,YAAY;AAAA,UACnB,QAAQ,YAAY,aAAa,aAAa;AAAA,QAChD,EAAE,IACF;AACJ,YAAI,WAAW,WAAW,cAAc,iBAAiB,MAAO,SAAQ,cAAc,KAAK,kBAAkB;AAAA,YACxG,QAAO,QAAQ;AACpB,YAAI,WAAW,SAAU,SAAQ,WAAW,KAAK,aAAa,QAAQ,KAAK,KAAK,aAAa,SAAS,KAAK;AAAA,YACtG,QAAO,QAAQ;AACpB,YAAI,CAAC,WAAW,UAAW,QAAO,QAAQ;AAC1C,cAAM,SAAS,yBAAyB,4BAA4B,QAAQ,aAAa,WAAW,GAAG;AAAA,UACrG,WAAW,CAAC,UAAU,gCAAgC,KAAK;AAAA,QAC7D,CAAC;AACD,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,EAAG,SAAQ,MAAM,GAAG,EAAE,IAAI;AAG1E,cAAM,oBAAoB,CAAC,qCAA8C,eAAe,+BAA+B;AAAA,UACrH,QAAQ,SAAS,QAAQ;AAAA,UACzB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,mCACjB,EAAE,GAAG,SAAS,kCAAkC,KAAK,IACrD,OAAO;AAAA,QACb,CAAC;AACD,YAAI;AACF,gBAAM,kBAAkB,KAAK;AAAA,QAC/B,SAAS,OAAO;AACd,gBAAM,SAAS,wBAAwB,KAAK;AAC5C,cAAI,CAAC,OAAQ,OAAM;AACnB,gBAAM,WAAW,MAAM,QAAQ;AAAA,YAC7B,OAAO,EAAE,wCAAwC;AAAA,YACjD,MAAM,GAAG,EAAE,8CAA8C,CAAC,IAAI,EAAE,yCAAyC,CAAC,IAAI,OAAO,IAAI,CAAC,UAAU;AAClI,oBAAMC,cAAa,aAAa,eAAe,KAAK,CAAC,UAAU,MAAM,MAAM,GAAG,OAAO,KAAK;AAC1F,kBAAIA,aAAY,MAAO,QAAOA,YAAW;AACzC,oBAAM,YAAoC;AAAA,gBACxC,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,gBAAgB;AAAA,gBAChB,QAAQ;AAAA,gBACR,iBAAiB;AAAA,gBACjB,UAAU;AAAA,gBACV,gBAAgB;AAAA,gBAChB,eAAe;AAAA,cACjB;AACA,qBAAO,EAAE,UAAU,KAAK,KAAK,+CAA+C;AAAA,YAC9E,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,YACb,aAAa,EAAE,0CAA0C;AAAA,YACzD,YAAY,EAAE,kCAAkC;AAAA,YAChD,SAAS;AAAA,UACX,CAAC;AACD,cAAI,CAAC,SAAU;AACf,gBAAM,kBAAkB,IAAI;AAAA,QAC9B;AACA,cAAM,EAAE,mCAAmC,aAAa,GAAG,SAAS;AACpE,qBAAa,KAAK;AAClB,8BAAsB,MAAM;AAAE,kBAAQ;AAAA,QAAE,CAAC;AAAA,MAC3C,SAAS,KAAK;AAGZ,YAAI,8BAA8B,GAAG,GAAG;AACtC,gCAAsB,KAAK,CAAC;AAC5B,uBAAa,KAAK;AAClB;AAAA,QACF;AACA,cAAM;AAAA,MACR,UAAE;AACA,kBAAU,KAAK;AAAA,MACjB;AAAA,IACF;AAAA,IACA,CAAC,cAAc,eAAe,aAAa,QAAQ,aAAa,aAAa,aAAa,gBAAgB,iBAAiB,SAAS,iBAAiB,OAAO,SAAS,gBAAgB,QAAQ,MAAM,IAAI,MAAM,cAAc,SAAS,kBAAkB,cAAc,CAAC;AAAA,EACvQ;AAEA,QAAM,SAAS,MAAM;AAAA,IACnB,MAAM;AAAA,MACJ;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW,CAAC,QACV;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,IAAI;AAAA,YACZ,QAAQ,IAAI;AAAA,YACZ,UAAU,IAAI;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA,YACA,eAAe,iBAAiB;AAAA,YAChC,eAAe,iBAAiB;AAAA,YAChC,kBAAkB,qBAAqB;AAAA,YACvC,cAAc,iBAAiB;AAAA,YAC/B;AAAA,YACA;AAAA,YACA,cAAc,kBAAkB;AAAA,YAChC,cAAc,kBAAkB;AAAA,YAChC,gBAAgB;AAAA,YAChB,sBAAsB;AAAA;AAAA,QACxB;AAAA,MAEJ;AAAA,MACA,GAAI,aAAa,OAAO,SAAS,CAAC,EAAE,IAAI,gBAAgB,OAAO,EAAE,6BAA6B,GAAG,QAAQ,aAAa,OAAO,IAAI,CAAC,UAAU,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC;AAAA,IAC9J;AAAA,IACA,CAAC,MAAM,QAAQ,MAAM,eAAe,eAAe,kBAAkB,cAAc,QAAQ,cAAc,eAAe,cAAc,aAAa,QAAQ,CAAC;AAAA,EAC9J;AAEA,QAAM,gBAAgB,oBAAoB;AAAA,IACxC,UAAU,MAAM;AAAE,WAAK,aAAa;AAAA,IAAE;AAAA,IACtC,WAAW,MAAM;AACf,YAAM,cAAc,SAAS,eAAe,OAAO;AACnD,UAAI,uBAAuB,gBAAiB,aAAY,cAAc;AAAA,IACxE;AAAA,IACA,UAAU,UAAU,aAAa,WAAW,WAAW,iBAAiB,WAAW,CAAC,CAAC,iBAAiB,SAAS,QAAQ,WAAW,WAAY,SAAS,YAAY,CAAC;AAAA,EACtK,CAAC;AAED,QAAM,cAAc,SAAS,EAAE,wCAAwC,YAAY,IAAI,EAAE,0CAA0C,WAAW;AAE9I,SACE,qBAAC,UAAO,MAAY,cAAc,CAAC,aAAa;AAAE,QAAI,SAAU,cAAa,IAAI;AAAA,QAAQ,MAAK,aAAa;AAAA,EAAE,GAC3G;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QAUX,mBAAmB,CAAC,UAAU;AAC5B,gBAAM,SAAS,MAAM,OAAO,cAAc;AAC1C,cAAI,QAAQ,QAAQ,uBAAuB,KAAK,QAAQ,QAAQ,qCAAqC,KAAK,QAAQ,QAAQ,QAAQ,GAAG;AACnI,kBAAM,eAAe;AAAA,UACvB;AAAA,QACF;AAAA,QACA,oBAAkB;AAAA,QAClB,aAAa;AAAA,QACb,WAAU;AAAA,QAEV;AAAA,8BAAC,kBACC,8BAAC,eAAa,uBAAY,GAC5B;AAAA,UACA,qBAAC,SAAI,WAAU,wFACb;AAAA,gCAAC,YAAS,eAAW,MAAC,WAAU,mCAAkC,aAAa,MAAM;AAAA,YACrF,oBAAC,OAAE,WAAU,gEAAgE,uBAAY;AAAA,YACzF;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS,MAAM;AAAE,uBAAK,aAAa;AAAA,gBAAE;AAAA,gBACrC,cAAY,EAAE,mCAAmC,OAAO;AAAA,gBACxD,WAAU;AAAA,gBAEV,8BAAC,KAAE,eAAW,MAAC,WAAU,UAAS;AAAA;AAAA,YACpC;AAAA,aACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,UAAU,MAAM;AAKd,yBAAS,cAAc,IAAI,YAAY,mBAAmB,CAAC;AAAA,cAC7D;AAAA,cAEA,8BAAC,SAAI,WAAU,6BACZ,sBACC;AAAA,gBAAC;AAAA;AAAA,kBAEC,QAAQ;AAAA,kBACR,UAAQ;AAAA,kBACR,wBAAsB;AAAA,kBACtB,eAAe;AAAA,kBACf,mBAAiB;AAAA,kBACjB,wBAAuB;AAAA,kBACvB,QAAQ,aAAa;AAAA,kBACrB;AAAA,kBACA;AAAA,kBACA,iBAAiB;AAAA,kBACjB,UAAU;AAAA;AAAA,gBAXL;AAAA,cAYP,IAEA,oBAAC,sBAAmB,OAAO,QAAQ,WAAW,SAAS,SAAS,QAAQ,OAAO,GAEnF;AAAA;AAAA,UACF;AAAA,UACA,qBAAC,SAAI,WAAU,+FACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS,MAAM,aAAa,KAAK;AAAA,gBAEhC,YAAE,oCAAoC,QAAQ;AAAA;AAAA,YACjD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAM;AAAA,gBACN,UAAU,UAAU,aAAa,WAAW,WAAW,iBAAiB,WAAW,CAAC,CAAC,iBAAiB,SAAS,QAAQ,WAAW,WAAY,SAAS,YAAY,CAAC;AAAA,gBAEnK,mBAAS,EAAE,oCAAoC,cAAS,IAAI,EAAE,kCAAkC,YAAY;AAAA;AAAA,YAC/G;AAAA,aACF;AAAA;AAAA;AAAA,IACF;AAAA,IACC;AAAA,KACH;AAEJ;",
6
+ "names": ["TimezoneField", "timezone", "EditorBody", "deal", "item", "definition"]
7
7
  }
@@ -1,42 +1,29 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { Info, X } from "lucide-react";
4
+ import { X } from "lucide-react";
5
5
  import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
6
6
  import { useT } from "@open-mercato/shared/lib/i18n/context";
7
7
  import { Button } from "@open-mercato/ui/primitives/button";
8
8
  import { Dialog, DialogContent, DialogTitle } from "@open-mercato/ui/primitives/dialog";
9
9
  import { IconButton } from "@open-mercato/ui/primitives/icon-button";
10
10
  import { Switch } from "@open-mercato/ui/primitives/switch";
11
- import { TagInput } from "@open-mercato/ui/primitives/tag-input";
12
- import { SimpleTooltip } from "@open-mercato/ui/primitives/tooltip";
13
11
  import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
14
- import {
15
- MAX_ACTIVITY_TYPES,
16
- MAX_EVENT_CATEGORIES
17
- } from "../../lib/calendar/preferences.js";
12
+ import { getCustomerDictionaryManageHref } from "../../lib/dictionaries.js";
18
13
  import { SegmentGroup } from "./editor/SegmentGroup.js";
19
- function buildDraft(preferences, seedActivityTypes) {
20
- return {
21
- ...preferences,
22
- eventCategories: [...preferences.eventCategories],
23
- activityTypes: preferences.activityTypes.length > 0 ? [...preferences.activityTypes] : seedActivityTypes.slice(0, MAX_ACTIVITY_TYPES)
24
- };
25
- }
26
14
  function CalendarSettingsModal({
27
15
  open,
28
16
  preferences,
29
- seedActivityTypes,
30
17
  onOpenChange,
31
18
  onSave
32
19
  }) {
33
20
  const t = useT();
34
- const [draft, setDraft] = React.useState(() => buildDraft(preferences, seedActivityTypes));
21
+ const [draft, setDraft] = React.useState(preferences);
35
22
  const openRef = React.useRef(false);
36
23
  React.useEffect(() => {
37
- if (open && !openRef.current) setDraft(buildDraft(preferences, seedActivityTypes));
24
+ if (open && !openRef.current) setDraft(preferences);
38
25
  openRef.current = open;
39
- }, [open, preferences, seedActivityTypes]);
26
+ }, [open, preferences]);
40
27
  const handleSave = React.useCallback(() => {
41
28
  onSave(draft);
42
29
  onOpenChange(false);
@@ -50,10 +37,6 @@ function CalendarSettingsModal({
50
37
  { key: "showWeekends", label: t("customers.calendar.settings.showWeekends", "Show weekends") }
51
38
  ];
52
39
  const title = t("customers.calendar.settings.title", "Customization");
53
- const removeTagLabel = React.useCallback(
54
- (tag) => t("customers.calendar.settings.removeTag", "Remove {tag}", { tag }),
55
- [t]
56
- );
57
40
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
58
41
  DialogContent,
59
42
  {
@@ -81,38 +64,10 @@ function CalendarSettingsModal({
81
64
  )
82
65
  ] }),
83
66
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-5", children: [
84
- /* @__PURE__ */ jsx(
85
- SettingsTagInput,
86
- {
87
- label: t("customers.calendar.settings.eventCategories", "Event Categories"),
88
- maxLabel: t("customers.calendar.settings.max", "(max. {count})", { count: MAX_EVENT_CATEGORIES }),
89
- hint: t(
90
- "customers.calendar.settings.eventCategoriesHint",
91
- "Your own grouping labels (e.g. Team Meeting, Sales Call). Offered when creating an event."
92
- ),
93
- placeholder: t("customers.calendar.settings.addCategory", "Add a category\u2026"),
94
- value: draft.eventCategories,
95
- maxTags: MAX_EVENT_CATEGORIES,
96
- removeTagLabel,
97
- onChange: (eventCategories) => setDraft((current) => ({ ...current, eventCategories }))
98
- }
99
- ),
100
- /* @__PURE__ */ jsx(
101
- SettingsTagInput,
102
- {
103
- label: t("customers.calendar.settings.activityTypes", "Activity Types"),
104
- maxLabel: t("customers.calendar.settings.max", "(max. {count})", { count: MAX_ACTIVITY_TYPES }),
105
- hint: t(
106
- "customers.calendar.settings.activityTypesHint",
107
- "The activity types your calendar surfaces when creating an event. Seeded from your workspace dictionary."
108
- ),
109
- placeholder: t("customers.calendar.settings.addType", "Add a type\u2026"),
110
- value: draft.activityTypes,
111
- maxTags: MAX_ACTIVITY_TYPES,
112
- removeTagLabel,
113
- onChange: (activityTypes) => setDraft((current) => ({ ...current, activityTypes }))
114
- }
115
- ),
67
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
68
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground", children: t("customers.calendar.settings.activityTypes", "Activity Types") }),
69
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", asChild: true, children: /* @__PURE__ */ jsx("a", { href: getCustomerDictionaryManageHref("activity-types"), children: t("customers.calendar.settings.manageActivityTypes", "Manage activity types") }) })
70
+ ] }),
116
71
  toggleRows.map((row) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
117
72
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
118
73
  /* @__PURE__ */ jsx(
@@ -153,26 +108,6 @@ function CalendarSettingsModal({
153
108
  }
154
109
  ) });
155
110
  }
156
- function SettingsTagInput({ label, maxLabel, hint, placeholder, value, maxTags, removeTagLabel, onChange }) {
157
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
158
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
159
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium leading-5 text-foreground", children: label }),
160
- /* @__PURE__ */ jsx("span", { className: "text-sm leading-5 text-muted-foreground", children: maxLabel }),
161
- /* @__PURE__ */ jsx(SimpleTooltip, { content: hint, children: /* @__PURE__ */ jsx("span", { className: "inline-flex text-muted-foreground", tabIndex: 0, role: "img", "aria-label": hint, children: /* @__PURE__ */ jsx(Info, { "aria-hidden": true, className: "size-4" }) }) })
162
- ] }),
163
- /* @__PURE__ */ jsx(
164
- TagInput,
165
- {
166
- value,
167
- onChange,
168
- placeholder,
169
- maxTags,
170
- "aria-label": label,
171
- removeTagLabel
172
- }
173
- )
174
- ] });
175
- }
176
111
  export {
177
112
  CalendarSettingsModal
178
113
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/calendar/CalendarSettingsModal.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Info, X } from 'lucide-react'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { TagInput } from '@open-mercato/ui/primitives/tag-input'\nimport { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport {\n CalendarPreferences,\n ConflictScope,\n MAX_ACTIVITY_TYPES,\n MAX_EVENT_CATEGORIES,\n} from '../../lib/calendar/preferences'\nimport { SegmentGroup } from './editor/SegmentGroup'\n\nexport type CalendarSettingsModalProps = {\n open: boolean\n preferences: CalendarPreferences\n seedActivityTypes: string[]\n onOpenChange(open: boolean): void\n onSave(next: CalendarPreferences): void\n}\n\ntype ToggleKey = 'showCrmActivities' | 'aiSummaries' | 'conflictWarnings' | 'showWeekends'\n\n// An empty Activity Types list is an intentional floor meaning \"surface all\n// dictionary types\" rather than \"surface none\". When the stored list is empty\n// the modal seeds the dictionary types for display. NOTE: since the editor's\n// Category quick-pick was removed (owner feedback, #3552) these lists no longer\n// affect the event editor \u2014 the type switcher always shows the full dictionary.\nfunction buildDraft(preferences: CalendarPreferences, seedActivityTypes: string[]): CalendarPreferences {\n return {\n ...preferences,\n eventCategories: [...preferences.eventCategories],\n activityTypes:\n preferences.activityTypes.length > 0\n ? [...preferences.activityTypes]\n : seedActivityTypes.slice(0, MAX_ACTIVITY_TYPES),\n }\n}\n\nexport function CalendarSettingsModal({\n open,\n preferences,\n seedActivityTypes,\n onOpenChange,\n onSave,\n}: CalendarSettingsModalProps) {\n const t = useT()\n const [draft, setDraft] = React.useState<CalendarPreferences>(() => buildDraft(preferences, seedActivityTypes))\n const openRef = React.useRef(false)\n\n React.useEffect(() => {\n if (open && !openRef.current) setDraft(buildDraft(preferences, seedActivityTypes))\n openRef.current = open\n }, [open, preferences, seedActivityTypes])\n\n const handleSave = React.useCallback(() => {\n onSave(draft)\n onOpenChange(false)\n }, [draft, onOpenChange, onSave])\n\n const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })\n\n const toggle = (key: ToggleKey) => (checked: boolean) => setDraft((current) => ({ ...current, [key]: checked }))\n\n const toggleRows: Array<{ key: ToggleKey; label: string }> = [\n { key: 'showCrmActivities', label: t('customers.calendar.settings.showCrmActivities', 'Show CRM activities on calendar') },\n { key: 'aiSummaries', label: t('customers.calendar.settings.aiSummaries', 'AI summaries') },\n { key: 'conflictWarnings', label: t('customers.calendar.settings.conflictWarnings', 'Conflict warnings') },\n { key: 'showWeekends', label: t('customers.calendar.settings.showWeekends', 'Show weekends') },\n ]\n\n const title = t('customers.calendar.settings.title', 'Customization')\n const removeTagLabel = React.useCallback(\n (tag: string) => t('customers.calendar.settings.removeTag', 'Remove {tag}', { tag }),\n [t],\n )\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n dismissible={false}\n className=\"flex w-full max-w-[400px] flex-col gap-0 overflow-hidden rounded-2xl border-0 bg-card p-0 shadow-xl\"\n >\n <VisuallyHidden>\n <DialogTitle>{title}</DialogTitle>\n </VisuallyHidden>\n <div className=\"flex shrink-0 items-start gap-3.5 border-b border-border py-4 pl-5 pr-4\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <p className=\"text-sm font-medium leading-5 text-foreground\">{title}</p>\n <p className=\"text-xs leading-4 text-muted-foreground\">\n {t('customers.calendar.settings.subtitle', 'Customise your calendar module.')}\n </p>\n </div>\n <IconButton\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onOpenChange(false)}\n aria-label={t('customers.calendar.settings.close', 'Close')}\n className=\"shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-5\" />\n </IconButton>\n </div>\n\n <div className=\"flex flex-col gap-4 p-5\">\n <SettingsTagInput\n label={t('customers.calendar.settings.eventCategories', 'Event Categories')}\n maxLabel={t('customers.calendar.settings.max', '(max. {count})', { count: MAX_EVENT_CATEGORIES })}\n hint={t(\n 'customers.calendar.settings.eventCategoriesHint',\n 'Your own grouping labels (e.g. Team Meeting, Sales Call). Offered when creating an event.',\n )}\n placeholder={t('customers.calendar.settings.addCategory', 'Add a category\u2026')}\n value={draft.eventCategories}\n maxTags={MAX_EVENT_CATEGORIES}\n removeTagLabel={removeTagLabel}\n onChange={(eventCategories) => setDraft((current) => ({ ...current, eventCategories }))}\n />\n <SettingsTagInput\n label={t('customers.calendar.settings.activityTypes', 'Activity Types')}\n maxLabel={t('customers.calendar.settings.max', '(max. {count})', { count: MAX_ACTIVITY_TYPES })}\n hint={t(\n 'customers.calendar.settings.activityTypesHint',\n 'The activity types your calendar surfaces when creating an event. Seeded from your workspace dictionary.',\n )}\n placeholder={t('customers.calendar.settings.addType', 'Add a type\u2026')}\n value={draft.activityTypes}\n maxTags={MAX_ACTIVITY_TYPES}\n removeTagLabel={removeTagLabel}\n onChange={(activityTypes) => setDraft((current) => ({ ...current, activityTypes }))}\n />\n {toggleRows.map((row) => (\n <React.Fragment key={row.key}>\n <div className=\"flex items-center gap-2\">\n <Switch\n checked={draft[row.key]}\n onCheckedChange={toggle(row.key)}\n aria-label={row.label}\n />\n <span className=\"text-sm leading-5 text-foreground\">{row.label}</span>\n </div>\n {row.key === 'conflictWarnings' && draft.conflictWarnings ? (\n <div className=\"flex flex-col gap-1.5 pl-11\">\n <span className=\"text-xs leading-4 text-muted-foreground\">\n {t(\n 'customers.calendar.settings.conflictScopeHint',\n 'Choose whose overlaps the calendar flags as conflicts.',\n )}\n </span>\n <SegmentGroup<ConflictScope>\n ariaLabel={t('customers.calendar.settings.conflictScope', 'Conflict scope')}\n value={draft.conflictScope}\n onChange={(conflictScope) => setDraft((current) => ({ ...current, conflictScope }))}\n options={[\n { value: 'mine', label: t('customers.calendar.settings.conflictScopeMine', 'My meetings') },\n { value: 'all', label: t('customers.calendar.settings.conflictScopeAll', 'All meetings') },\n ]}\n />\n </div>\n ) : null}\n </React.Fragment>\n ))}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-3 border-t border-border px-5 py-4\">\n <Button type=\"button\" variant=\"outline\" className=\"flex-1\" onClick={() => onOpenChange(false)}>\n {t('customers.calendar.settings.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" className=\"flex-1\" onClick={handleSave}>\n {t('customers.calendar.settings.save', 'Save Changes')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\ntype SettingsTagInputProps = {\n label: string\n maxLabel: string\n hint: string\n placeholder: string\n value: string[]\n maxTags: number\n removeTagLabel: (tag: string) => string\n onChange(value: string[]): void\n}\n\nfunction SettingsTagInput({ label, maxLabel, hint, placeholder, value, maxTags, removeTagLabel, onChange }: SettingsTagInputProps) {\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-sm font-medium leading-5 text-foreground\">{label}</span>\n <span className=\"text-sm leading-5 text-muted-foreground\">{maxLabel}</span>\n <SimpleTooltip content={hint}>\n <span className=\"inline-flex text-muted-foreground\" tabIndex={0} role=\"img\" aria-label={hint}>\n <Info aria-hidden className=\"size-4\" />\n </span>\n </SimpleTooltip>\n </div>\n <TagInput\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n maxTags={maxTags}\n aria-label={label}\n removeTagLabel={removeTagLabel}\n />\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { X } from 'lucide-react'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { CalendarPreferences, ConflictScope } from '../../lib/calendar/preferences'\nimport { getCustomerDictionaryManageHref } from '../../lib/dictionaries'\nimport { SegmentGroup } from './editor/SegmentGroup'\n\nexport type CalendarSettingsModalProps = {\n open: boolean\n preferences: CalendarPreferences\n /** @deprecated Activity types are loaded from the scoped catalog. */\n seedActivityTypes?: string[]\n onOpenChange(open: boolean): void\n onSave(next: CalendarPreferences): void\n}\n\ntype ToggleKey = 'showCrmActivities' | 'aiSummaries' | 'conflictWarnings' | 'showWeekends'\n\nexport function CalendarSettingsModal({\n open,\n preferences,\n onOpenChange,\n onSave,\n}: CalendarSettingsModalProps) {\n const t = useT()\n const [draft, setDraft] = React.useState<CalendarPreferences>(preferences)\n const openRef = React.useRef(false)\n\n React.useEffect(() => {\n if (open && !openRef.current) setDraft(preferences)\n openRef.current = open\n }, [open, preferences])\n\n const handleSave = React.useCallback(() => {\n onSave(draft)\n onOpenChange(false)\n }, [draft, onOpenChange, onSave])\n\n const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })\n\n const toggle = (key: ToggleKey) => (checked: boolean) => setDraft((current) => ({ ...current, [key]: checked }))\n\n const toggleRows: Array<{ key: ToggleKey; label: string }> = [\n { key: 'showCrmActivities', label: t('customers.calendar.settings.showCrmActivities', 'Show CRM activities on calendar') },\n { key: 'aiSummaries', label: t('customers.calendar.settings.aiSummaries', 'AI summaries') },\n { key: 'conflictWarnings', label: t('customers.calendar.settings.conflictWarnings', 'Conflict warnings') },\n { key: 'showWeekends', label: t('customers.calendar.settings.showWeekends', 'Show weekends') },\n ]\n\n const title = t('customers.calendar.settings.title', 'Customization')\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n dismissible={false}\n className=\"flex w-full max-w-[400px] flex-col gap-0 overflow-hidden rounded-2xl border-0 bg-card p-0 shadow-xl\"\n >\n <VisuallyHidden>\n <DialogTitle>{title}</DialogTitle>\n </VisuallyHidden>\n <div className=\"flex shrink-0 items-start gap-3.5 border-b border-border py-4 pl-5 pr-4\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <p className=\"text-sm font-medium leading-5 text-foreground\">{title}</p>\n <p className=\"text-xs leading-4 text-muted-foreground\">\n {t('customers.calendar.settings.subtitle', 'Customise your calendar module.')}\n </p>\n </div>\n <IconButton\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onOpenChange(false)}\n aria-label={t('customers.calendar.settings.close', 'Close')}\n className=\"shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-5\" />\n </IconButton>\n </div>\n\n <div className=\"flex flex-col gap-4 p-5\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-sm text-foreground\">\n {t('customers.calendar.settings.activityTypes', 'Activity Types')}\n </span>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" asChild>\n <a href={getCustomerDictionaryManageHref('activity-types')}>\n {t('customers.calendar.settings.manageActivityTypes', 'Manage activity types')}\n </a>\n </Button>\n </div>\n {toggleRows.map((row) => (\n <React.Fragment key={row.key}>\n <div className=\"flex items-center gap-2\">\n <Switch\n checked={draft[row.key]}\n onCheckedChange={toggle(row.key)}\n aria-label={row.label}\n />\n <span className=\"text-sm leading-5 text-foreground\">{row.label}</span>\n </div>\n {row.key === 'conflictWarnings' && draft.conflictWarnings ? (\n <div className=\"flex flex-col gap-1.5 pl-11\">\n <span className=\"text-xs leading-4 text-muted-foreground\">\n {t(\n 'customers.calendar.settings.conflictScopeHint',\n 'Choose whose overlaps the calendar flags as conflicts.',\n )}\n </span>\n <SegmentGroup<ConflictScope>\n ariaLabel={t('customers.calendar.settings.conflictScope', 'Conflict scope')}\n value={draft.conflictScope}\n onChange={(conflictScope) => setDraft((current) => ({ ...current, conflictScope }))}\n options={[\n { value: 'mine', label: t('customers.calendar.settings.conflictScopeMine', 'My meetings') },\n { value: 'all', label: t('customers.calendar.settings.conflictScopeAll', 'All meetings') },\n ]}\n />\n </div>\n ) : null}\n </React.Fragment>\n ))}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-3 border-t border-border px-5 py-4\">\n <Button type=\"button\" variant=\"outline\" className=\"flex-1\" onClick={() => onOpenChange(false)}>\n {t('customers.calendar.settings.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" className=\"flex-1\" onClick={handleSave}>\n {t('customers.calendar.settings.save', 'Save Changes')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -127,6 +127,11 @@ function TimeGrid({
127
127
  const anchorMs = anchor.getTime();
128
128
  const [selectedId, setSelectedId] = React.useState(null);
129
129
  const [drag, setDrag] = React.useState(null);
130
+ const dragRef = React.useRef(null);
131
+ const updateDrag = (next) => {
132
+ dragRef.current = next;
133
+ setDrag(next);
134
+ };
130
135
  const dayStarts = React.useMemo(() => {
131
136
  const rangeStart = getVisibleRange(days === 7 ? "week" : "day", new Date(anchorMs), 0).from;
132
137
  const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index));
@@ -191,28 +196,27 @@ function TimeGrid({
191
196
  } catch {
192
197
  }
193
198
  setSelectedId(null);
194
- setDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false });
199
+ updateDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false });
195
200
  };
196
201
  const moveDrag = (event) => {
202
+ const previous = dragRef.current;
203
+ if (!previous) return;
197
204
  const rect = event.currentTarget.getBoundingClientRect();
198
205
  const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX);
199
- setDrag((previous) => {
200
- if (!previous) return previous;
201
- return {
202
- ...previous,
203
- endMin: minute,
204
- moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES
205
- };
206
+ if (minute === previous.endMin) return;
207
+ updateDrag({
208
+ ...previous,
209
+ endMin: minute,
210
+ moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES
206
211
  });
207
212
  };
208
213
  const endDrag = (dayStart) => {
209
- setDrag((previous) => {
210
- if (previous && previous.moved && onCreateRange) {
211
- const range = buildDragRange(dayStart, previous.startMin, previous.endMin);
212
- onCreateRange(range.start, range.end);
213
- }
214
- return null;
215
- });
214
+ const previous = dragRef.current;
215
+ updateDrag(null);
216
+ if (previous && previous.moved && onCreateRange) {
217
+ const range = buildDragRange(dayStart, previous.startMin, previous.endMin);
218
+ onCreateRange(range.start, range.end);
219
+ }
216
220
  };
217
221
  return /* @__PURE__ */ jsx("div", { className: "relative flex flex-col overflow-hidden rounded-lg border border-border bg-card", children: /* @__PURE__ */ jsxs(
218
222
  "div",
@@ -334,7 +338,7 @@ function TimeGrid({
334
338
  onPointerDown: (event) => beginDrag(event, dayStart),
335
339
  onPointerMove: moveDrag,
336
340
  onPointerUp: () => endDrag(dayStart),
337
- onPointerCancel: () => setDrag(null),
341
+ onPointerCancel: () => updateDrag(null),
338
342
  "aria-hidden": true
339
343
  }
340
344
  ) : null,