@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/TimeGrid.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\nimport { addDays } from 'date-fns/addDays'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { packOverlaps } from '../../lib/calendar/layout'\nimport { getVisibleRange } from '../../lib/calendar/range'\nimport {\n applyWeekendVisibility,\n buildDragRange,\n DRAG_SNAP_MINUTES,\n isWeekendDay,\n offsetYToMinutes,\n} from '../../lib/calendar/grid'\nimport { EventBlock, formatTimeRange, resolveEventTone } from './EventBlock'\nimport { EventPeekPopover } from './EventPeekPopover'\nimport type { CalendarItem, TimeGridProps } from './types'\n\nconst HOUR_HEIGHT_PX = 120\nconst HOURS_PER_DAY = 24\nconst GRID_BODY_MAX_HEIGHT_PX = 654\nconst INITIAL_SCROLL_HOUR = 8\nconst BLOCK_VERTICAL_GAP_PX = 1\nconst MIN_BLOCK_HEIGHT_PX = 32\nconst PACKED_COLUMN_GAP_PX = 2\n\nconst NON_WORKING_HATCH_BACKGROUND =\n 'repeating-linear-gradient(45deg, transparent 0px, transparent 8px, var(--border) 8px, var(--border) 9px)'\n\ntype PositionedBlock = {\n item: CalendarItem\n top: number\n height: number\n insetInlineStart: string\n width: string\n}\n\ntype DayColumnData = {\n dayStart: Date\n allDayItems: CalendarItem[]\n blocks: PositionedBlock[]\n}\n\ntype DragState = { dayMs: number; startMin: number; endMin: number; moved: boolean }\n\nfunction buildDayColumn(dayStart: Date, items: CalendarItem[]): DayColumnData {\n const dayEnd = addDays(dayStart, 1)\n const dayStartMs = dayStart.getTime()\n const dayEndMs = dayEnd.getTime()\n const allDayItems: CalendarItem[] = []\n const segments: Array<{ original: CalendarItem; start: Date; end: Date }> = []\n\n for (const item of items) {\n const startMs = item.start.getTime()\n const endMs = item.end.getTime()\n if (startMs >= dayEndMs || endMs <= dayStartMs) continue\n if (item.allDay) {\n allDayItems.push(item)\n continue\n }\n segments.push({\n original: item,\n start: startMs < dayStartMs ? dayStart : item.start,\n end: endMs > dayEndMs ? dayEnd : item.end,\n })\n }\n\n allDayItems.sort((first, second) => first.start.getTime() - second.start.getTime())\n\n const clones = segments.map((segment) => ({ ...segment.original, start: segment.start, end: segment.end }))\n const originalByClone = new Map<CalendarItem, CalendarItem>()\n clones.forEach((clone, index) => originalByClone.set(clone, segments[index].original))\n\n const blocks: PositionedBlock[] = packOverlaps(clones).map(({ item: clone, column, columns }) => {\n const startMinutes = (clone.start.getTime() - dayStartMs) / 60000\n const durationMinutes = (clone.end.getTime() - clone.start.getTime()) / 60000\n const rawTop = (startMinutes / 60) * HOUR_HEIGHT_PX\n const rawHeight = (durationMinutes / 60) * HOUR_HEIGHT_PX\n const widthPct = 100 / columns\n return {\n item: originalByClone.get(clone) ?? clone,\n top: rawTop + BLOCK_VERTICAL_GAP_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, rawHeight - BLOCK_VERTICAL_GAP_PX * 2),\n insetInlineStart: `calc(${column * widthPct}% + ${column * PACKED_COLUMN_GAP_PX}px)`,\n width: `calc(${widthPct}% - ${((columns - 1) * PACKED_COLUMN_GAP_PX) / columns}px)`,\n }\n })\n\n return { dayStart, allDayItems, blocks }\n}\n\ntype ConflictBadgeProps = { count: number }\n\nfunction ConflictBadge({ count }: ConflictBadgeProps) {\n const t = useT()\n const label =\n count === 1\n ? t('customers.calendar.grid.conflictCount', '1 conflict')\n : t('customers.calendar.grid.conflictsCount', '{count} conflicts', { count })\n return (\n <span className=\"pointer-events-none absolute left-2 top-1 z-40 inline-flex items-center gap-1 rounded-full bg-status-error-bg px-2 py-0.5 text-overline font-medium uppercase tracking-wide text-status-error-text\">\n <span aria-hidden className=\"size-1.5 rounded-full bg-status-error-icon\" />\n {label}\n </span>\n )\n}\n\ntype AllDayChipProps = {\n item: CalendarItem\n conflicted: boolean\n highlighted: boolean\n selected: boolean\n nowMs: number\n} & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>\n\nconst AllDayChip = React.forwardRef<HTMLButtonElement, AllDayChipProps>(function AllDayChip(\n { item, conflicted, highlighted, selected, nowMs, className, ...buttonProps },\n ref,\n) {\n const t = useT()\n const tone = resolveEventTone(item, nowMs)\n const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')\n return (\n <Button\n ref={ref}\n type=\"button\"\n variant=\"ghost\"\n aria-label={`${title}, ${t('customers.calendar.grid.allDay', 'All day')}`}\n className={cn(\n 'h-auto w-full min-w-0 justify-start rounded-sm px-2 py-0.5 text-start hover:bg-muted/70',\n tone.surfaceClassName,\n conflicted && 'ring-1 ring-status-warning-icon',\n selected && 'shadow-md ring-2 ring-foreground',\n highlighted && 'motion-safe:animate-pulse',\n 'focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n style={tone.style}\n {...buttonProps}\n >\n <span className={cn('truncate text-xs font-medium', tone.titleClassName)}>{title}</span>\n </Button>\n )\n})\n\nAllDayChip.displayName = 'AllDayChip'\n\nexport function TimeGrid({\n days,\n anchor,\n items,\n conflictIds,\n showWeekends,\n showConflicts,\n aiSummaries,\n canManage = true,\n highlightItemId,\n onItemClick,\n onJoin,\n onNavigate,\n onCreateRange,\n}: TimeGridProps) {\n const t = useT()\n const locale = useLocale()\n const scrollRef = React.useRef<HTMLDivElement | null>(null)\n const nowMs = Date.now()\n const today = startOfDay(new Date())\n const todayMs = today.getTime()\n const anchorMs = anchor.getTime()\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [drag, setDrag] = React.useState<DragState | null>(null)\n\n const dayStarts = React.useMemo(() => {\n const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from\n const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))\n return days === 7 ? applyWeekendVisibility(all, showWeekends, new Date(todayMs)) : all\n }, [days, anchorMs, showWeekends, todayMs])\n\n const dayColumns = React.useMemo(\n () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),\n [dayStarts, items],\n )\n\n const resolveJoinUrl = React.useCallback((location: string | null): string | null => {\n const trimmed = location?.trim() ?? ''\n if (!trimmed) return null\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed\n if (/^www\\./i.test(trimmed)) return `https://${trimmed}`\n return null\n }, [])\n\n const hasAllDayLane = dayColumns.some((column) => column.allDayItems.length > 0)\n\n const formatters = React.useMemo(\n () => ({\n dayNumber: new Intl.DateTimeFormat(locale, { day: '2-digit' }),\n weekdayShort: new Intl.DateTimeFormat(locale, { weekday: 'short' }),\n weekdayLong: new Intl.DateTimeFormat(locale, { weekday: 'long' }),\n }),\n [locale],\n )\n\n const hourLabels = React.useMemo(() => {\n const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric' })\n return Array.from({ length: HOURS_PER_DAY }, (_, hour) => formatter.format(new Date(2024, 0, 1, hour)))\n }, [locale])\n\n React.useEffect(() => {\n const node = scrollRef.current\n if (!node) return\n node.scrollTop = INITIAL_SCROLL_HOUR * HOUR_HEIGHT_PX\n }, [])\n\n React.useEffect(() => {\n if (!highlightItemId) return\n const node = scrollRef.current\n if (!node) return\n const target = items.find((item) => item.id === highlightItemId && !item.allDay)\n if (!target) return\n const minutes = (target.start.getTime() - startOfDay(target.start).getTime()) / 60000\n const top = (minutes / 60) * HOUR_HEIGHT_PX\n const reduceMotion =\n typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n node.scrollTo({ top: Math.max(0, top - HOUR_HEIGHT_PX), behavior: reduceMotion ? 'auto' : 'smooth' })\n }, [highlightItemId, items])\n\n const nonWorkingLabel = t('customers.calendar.grid.nonWorking', 'Non-working day')\n const previousLabel =\n days === 7\n ? t('customers.calendar.previousWeek', 'Previous week')\n : t('customers.calendar.grid.previousDay', 'Previous day')\n const nextLabel =\n days === 7 ? t('customers.calendar.nextWeek', 'Next week') : t('customers.calendar.grid.nextDay', 'Next day')\n\n const headerLabelFor = (dayStart: Date): string => {\n const dayNumber = formatters.dayNumber.format(dayStart)\n if (days === 1) return `${formatters.weekdayLong.format(dayStart).toUpperCase()} \u00B7 ${dayNumber}`\n return `${dayNumber} ${formatters.weekdayShort.format(dayStart).toUpperCase()}`\n }\n\n const canCreateRange = Boolean(onCreateRange)\n\n const beginDrag = (event: React.PointerEvent<HTMLDivElement>, dayStart: Date) => {\n if (!canCreateRange || event.button !== 0) return\n const layer = event.currentTarget\n const rect = layer.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n try {\n layer.setPointerCapture(event.pointerId)\n } catch {\n // Pointer capture is best-effort; ignore environments that reject it.\n }\n setSelectedId(null)\n setDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false })\n }\n\n const moveDrag = (event: React.PointerEvent<HTMLDivElement>) => {\n // Read the layer rect synchronously: `event.currentTarget` is only valid during\n // event dispatch, but the setDrag updater below runs later during re-render.\n const rect = event.currentTarget.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n setDrag((previous) => {\n if (!previous) return previous\n return {\n ...previous,\n endMin: minute,\n moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES,\n }\n })\n }\n\n const endDrag = (dayStart: Date) => {\n setDrag((previous) => {\n if (previous && previous.moved && onCreateRange) {\n const range = buildDragRange(dayStart, previous.startMin, previous.endMin)\n onCreateRange(range.start, range.end)\n }\n return null\n })\n }\n\n return (\n <div className=\"relative flex flex-col overflow-hidden rounded-lg border border-border bg-card\">\n <div\n ref={scrollRef}\n className=\"overflow-auto overscroll-contain\"\n style={{ maxHeight: GRID_BODY_MAX_HEIGHT_PX }}\n >\n <div className=\"sticky top-0 z-30 min-w-full bg-card max-md:w-max\">\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 bg-card md:w-26\">\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={previousLabel} onClick={() => onNavigate(-days)}>\n <ChevronLeft aria-hidden />\n </IconButton>\n </span>\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={nextLabel} onClick={() => onNavigate(days)}>\n <ChevronRight aria-hidden />\n </IconButton>\n </span>\n </div>\n {dayColumns.map(({ dayStart }) => {\n const isToday = isSameDay(dayStart, today)\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'flex min-w-0 flex-1 items-center justify-center border-e border-border bg-muted px-1 py-2 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n <span\n className={cn(\n 'truncate text-xs uppercase tracking-wide',\n isToday ? 'font-semibold text-foreground' : 'font-medium text-muted-foreground',\n )}\n >\n {headerLabelFor(dayStart)}\n </span>\n </div>\n )\n })}\n </div>\n {hasAllDayLane ? (\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 items-center justify-center border-e border-border bg-card py-1 md:w-26\">\n <span className=\"truncate text-overline uppercase tracking-wide text-muted-foreground\">\n {t('customers.calendar.grid.allDay', 'All day')}\n </span>\n </div>\n {dayColumns.map(({ dayStart, allDayItems }) => (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'min-w-0 flex-1 space-y-1 border-e border-border p-1 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n {allDayItems.map((item) => (\n <EventPeekPopover\n key={item.id}\n item={item}\n open={selectedId === item.id}\n joinUrl={resolveJoinUrl(item.location)}\n aiSummaries={aiSummaries}\n canManage={canManage}\n onOpenChange={(open) => setSelectedId(open ? item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <AllDayChip\n item={item}\n conflicted={showConflicts && conflictIds.has(item.id)}\n highlighted={highlightItemId === item.id}\n selected={selectedId === item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-full max-md:w-max\" style={{ height: HOURS_PER_DAY * HOUR_HEIGHT_PX }}>\n <div className=\"sticky start-0 z-10 w-14 shrink-0 border-e border-border bg-card md:w-26\">\n <div className=\"relative h-full\">\n {hourLabels.map((label, hour) =>\n hour === 0 ? null : (\n <span\n key={hour}\n className=\"absolute w-full -translate-y-1/2 px-1 text-center text-xs font-medium text-muted-foreground md:px-3 md:text-sm\"\n style={{ top: hour * HOUR_HEIGHT_PX }}\n >\n {label}\n </span>\n ),\n )}\n </div>\n </div>\n {dayColumns.map(({ dayStart, blocks }) => {\n const nonWorking = isWeekendDay(dayStart)\n const conflictCount = showConflicts\n ? blocks.filter((block) => conflictIds.has(block.item.id)).length\n : 0\n const dragActive = drag && drag.moved && drag.dayMs === dayStart.getTime()\n const dragRange = dragActive ? buildDragRange(dayStart, drag.startMin, drag.endMin) : null\n const dragStartMinutes = dragRange\n ? (dragRange.start.getTime() - startOfDay(dragRange.start).getTime()) / 60000\n : 0\n const dragDurationMinutes = dragRange\n ? (dragRange.end.getTime() - dragRange.start.getTime()) / 60000\n : 0\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'relative min-w-0 flex-1 border-e border-border last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n title={nonWorking ? nonWorkingLabel : undefined}\n >\n {nonWorking ? <span className=\"sr-only\">{nonWorkingLabel}</span> : null}\n <div aria-hidden className=\"absolute inset-0\">\n {Array.from({ length: HOURS_PER_DAY }, (_, hour) => (\n <div key={hour} className=\"relative h-30 border-b border-border\">\n <span className=\"absolute inset-x-0 top-1/2 h-px bg-border/50\" />\n </div>\n ))}\n </div>\n {nonWorking ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{ backgroundImage: NON_WORKING_HATCH_BACKGROUND }}\n />\n ) : null}\n {canCreateRange ? (\n <div\n className=\"absolute inset-0 cursor-cell\"\n onPointerDown={(event) => beginDrag(event, dayStart)}\n onPointerMove={moveDrag}\n onPointerUp={() => endDrag(dayStart)}\n onPointerCancel={() => setDrag(null)}\n aria-hidden\n />\n ) : null}\n {dragRange ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute z-30 flex flex-col gap-0.5 overflow-hidden rounded-md border-2 border-dashed border-foreground bg-accent-indigo/10 px-2 pt-1.5\"\n style={{\n top: (dragStartMinutes / 60) * HOUR_HEIGHT_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, (dragDurationMinutes / 60) * HOUR_HEIGHT_PX),\n insetInlineStart: 8,\n insetInlineEnd: 8,\n }}\n >\n <span className=\"text-overline font-semibold text-foreground\">\n {t('customers.calendar.actions.newEvent', 'New event')}\n </span>\n <span className=\"text-overline text-muted-foreground\">\n {formatTimeRange(locale, dragRange.start, dragRange.end)}\n </span>\n </div>\n ) : null}\n {conflictCount > 0 ? <ConflictBadge count={conflictCount} /> : null}\n {/* Click-through container so empty space reaches the drag-to-create layer\n below; each block re-enables pointer events for its own click/peek. */}\n <div className=\"pointer-events-none absolute inset-y-0\" style={{ insetInlineStart: 8, insetInlineEnd: 8 }}>\n {blocks.map((block) => (\n <EventPeekPopover\n key={`${block.item.id}-${block.top}`}\n item={block.item}\n open={selectedId === block.item.id}\n joinUrl={resolveJoinUrl(block.item.location)}\n aiSummaries={aiSummaries}\n canManage={canManage}\n onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <EventBlock\n item={block.item}\n top={block.top}\n height={block.height}\n insetInlineStart={block.insetInlineStart}\n width={block.width}\n conflicted={showConflicts && conflictIds.has(block.item.id)}\n highlighted={highlightItemId === block.item.id}\n selected={selectedId === block.item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\nimport { addDays } from 'date-fns/addDays'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { packOverlaps } from '../../lib/calendar/layout'\nimport { getVisibleRange } from '../../lib/calendar/range'\nimport {\n applyWeekendVisibility,\n buildDragRange,\n DRAG_SNAP_MINUTES,\n isWeekendDay,\n offsetYToMinutes,\n} from '../../lib/calendar/grid'\nimport { EventBlock, formatTimeRange, resolveEventTone } from './EventBlock'\nimport { EventPeekPopover } from './EventPeekPopover'\nimport type { CalendarItem, TimeGridProps } from './types'\n\nconst HOUR_HEIGHT_PX = 120\nconst HOURS_PER_DAY = 24\nconst GRID_BODY_MAX_HEIGHT_PX = 654\nconst INITIAL_SCROLL_HOUR = 8\nconst BLOCK_VERTICAL_GAP_PX = 1\nconst MIN_BLOCK_HEIGHT_PX = 32\nconst PACKED_COLUMN_GAP_PX = 2\n\nconst NON_WORKING_HATCH_BACKGROUND =\n 'repeating-linear-gradient(45deg, transparent 0px, transparent 8px, var(--border) 8px, var(--border) 9px)'\n\ntype PositionedBlock = {\n item: CalendarItem\n top: number\n height: number\n insetInlineStart: string\n width: string\n}\n\ntype DayColumnData = {\n dayStart: Date\n allDayItems: CalendarItem[]\n blocks: PositionedBlock[]\n}\n\ntype DragState = { dayMs: number; startMin: number; endMin: number; moved: boolean }\n\nfunction buildDayColumn(dayStart: Date, items: CalendarItem[]): DayColumnData {\n const dayEnd = addDays(dayStart, 1)\n const dayStartMs = dayStart.getTime()\n const dayEndMs = dayEnd.getTime()\n const allDayItems: CalendarItem[] = []\n const segments: Array<{ original: CalendarItem; start: Date; end: Date }> = []\n\n for (const item of items) {\n const startMs = item.start.getTime()\n const endMs = item.end.getTime()\n if (startMs >= dayEndMs || endMs <= dayStartMs) continue\n if (item.allDay) {\n allDayItems.push(item)\n continue\n }\n segments.push({\n original: item,\n start: startMs < dayStartMs ? dayStart : item.start,\n end: endMs > dayEndMs ? dayEnd : item.end,\n })\n }\n\n allDayItems.sort((first, second) => first.start.getTime() - second.start.getTime())\n\n const clones = segments.map((segment) => ({ ...segment.original, start: segment.start, end: segment.end }))\n const originalByClone = new Map<CalendarItem, CalendarItem>()\n clones.forEach((clone, index) => originalByClone.set(clone, segments[index].original))\n\n const blocks: PositionedBlock[] = packOverlaps(clones).map(({ item: clone, column, columns }) => {\n const startMinutes = (clone.start.getTime() - dayStartMs) / 60000\n const durationMinutes = (clone.end.getTime() - clone.start.getTime()) / 60000\n const rawTop = (startMinutes / 60) * HOUR_HEIGHT_PX\n const rawHeight = (durationMinutes / 60) * HOUR_HEIGHT_PX\n const widthPct = 100 / columns\n return {\n item: originalByClone.get(clone) ?? clone,\n top: rawTop + BLOCK_VERTICAL_GAP_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, rawHeight - BLOCK_VERTICAL_GAP_PX * 2),\n insetInlineStart: `calc(${column * widthPct}% + ${column * PACKED_COLUMN_GAP_PX}px)`,\n width: `calc(${widthPct}% - ${((columns - 1) * PACKED_COLUMN_GAP_PX) / columns}px)`,\n }\n })\n\n return { dayStart, allDayItems, blocks }\n}\n\ntype ConflictBadgeProps = { count: number }\n\nfunction ConflictBadge({ count }: ConflictBadgeProps) {\n const t = useT()\n const label =\n count === 1\n ? t('customers.calendar.grid.conflictCount', '1 conflict')\n : t('customers.calendar.grid.conflictsCount', '{count} conflicts', { count })\n return (\n <span className=\"pointer-events-none absolute left-2 top-1 z-40 inline-flex items-center gap-1 rounded-full bg-status-error-bg px-2 py-0.5 text-overline font-medium uppercase tracking-wide text-status-error-text\">\n <span aria-hidden className=\"size-1.5 rounded-full bg-status-error-icon\" />\n {label}\n </span>\n )\n}\n\ntype AllDayChipProps = {\n item: CalendarItem\n conflicted: boolean\n highlighted: boolean\n selected: boolean\n nowMs: number\n} & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>\n\nconst AllDayChip = React.forwardRef<HTMLButtonElement, AllDayChipProps>(function AllDayChip(\n { item, conflicted, highlighted, selected, nowMs, className, ...buttonProps },\n ref,\n) {\n const t = useT()\n const tone = resolveEventTone(item, nowMs)\n const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')\n return (\n <Button\n ref={ref}\n type=\"button\"\n variant=\"ghost\"\n aria-label={`${title}, ${t('customers.calendar.grid.allDay', 'All day')}`}\n className={cn(\n 'h-auto w-full min-w-0 justify-start rounded-sm px-2 py-0.5 text-start hover:bg-muted/70',\n tone.surfaceClassName,\n conflicted && 'ring-1 ring-status-warning-icon',\n selected && 'shadow-md ring-2 ring-foreground',\n highlighted && 'motion-safe:animate-pulse',\n 'focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n style={tone.style}\n {...buttonProps}\n >\n <span className={cn('truncate text-xs font-medium', tone.titleClassName)}>{title}</span>\n </Button>\n )\n})\n\nAllDayChip.displayName = 'AllDayChip'\n\nexport function TimeGrid({\n days,\n anchor,\n items,\n conflictIds,\n showWeekends,\n showConflicts,\n aiSummaries,\n canManage = true,\n highlightItemId,\n onItemClick,\n onJoin,\n onNavigate,\n onCreateRange,\n}: TimeGridProps) {\n const t = useT()\n const locale = useLocale()\n const scrollRef = React.useRef<HTMLDivElement | null>(null)\n const nowMs = Date.now()\n const today = startOfDay(new Date())\n const todayMs = today.getTime()\n const anchorMs = anchor.getTime()\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [drag, setDrag] = React.useState<DragState | null>(null)\n const dragRef = React.useRef<DragState | null>(null)\n const updateDrag = (next: DragState | null) => {\n dragRef.current = next\n setDrag(next)\n }\n\n const dayStarts = React.useMemo(() => {\n const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from\n const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))\n return days === 7 ? applyWeekendVisibility(all, showWeekends, new Date(todayMs)) : all\n }, [days, anchorMs, showWeekends, todayMs])\n\n const dayColumns = React.useMemo(\n () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),\n [dayStarts, items],\n )\n\n const resolveJoinUrl = React.useCallback((location: string | null): string | null => {\n const trimmed = location?.trim() ?? ''\n if (!trimmed) return null\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed\n if (/^www\\./i.test(trimmed)) return `https://${trimmed}`\n return null\n }, [])\n\n const hasAllDayLane = dayColumns.some((column) => column.allDayItems.length > 0)\n\n const formatters = React.useMemo(\n () => ({\n dayNumber: new Intl.DateTimeFormat(locale, { day: '2-digit' }),\n weekdayShort: new Intl.DateTimeFormat(locale, { weekday: 'short' }),\n weekdayLong: new Intl.DateTimeFormat(locale, { weekday: 'long' }),\n }),\n [locale],\n )\n\n const hourLabels = React.useMemo(() => {\n const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric' })\n return Array.from({ length: HOURS_PER_DAY }, (_, hour) => formatter.format(new Date(2024, 0, 1, hour)))\n }, [locale])\n\n React.useEffect(() => {\n const node = scrollRef.current\n if (!node) return\n node.scrollTop = INITIAL_SCROLL_HOUR * HOUR_HEIGHT_PX\n }, [])\n\n React.useEffect(() => {\n if (!highlightItemId) return\n const node = scrollRef.current\n if (!node) return\n const target = items.find((item) => item.id === highlightItemId && !item.allDay)\n if (!target) return\n const minutes = (target.start.getTime() - startOfDay(target.start).getTime()) / 60000\n const top = (minutes / 60) * HOUR_HEIGHT_PX\n const reduceMotion =\n typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n node.scrollTo({ top: Math.max(0, top - HOUR_HEIGHT_PX), behavior: reduceMotion ? 'auto' : 'smooth' })\n }, [highlightItemId, items])\n\n const nonWorkingLabel = t('customers.calendar.grid.nonWorking', 'Non-working day')\n const previousLabel =\n days === 7\n ? t('customers.calendar.previousWeek', 'Previous week')\n : t('customers.calendar.grid.previousDay', 'Previous day')\n const nextLabel =\n days === 7 ? t('customers.calendar.nextWeek', 'Next week') : t('customers.calendar.grid.nextDay', 'Next day')\n\n const headerLabelFor = (dayStart: Date): string => {\n const dayNumber = formatters.dayNumber.format(dayStart)\n if (days === 1) return `${formatters.weekdayLong.format(dayStart).toUpperCase()} \u00B7 ${dayNumber}`\n return `${dayNumber} ${formatters.weekdayShort.format(dayStart).toUpperCase()}`\n }\n\n const canCreateRange = Boolean(onCreateRange)\n\n const beginDrag = (event: React.PointerEvent<HTMLDivElement>, dayStart: Date) => {\n if (!canCreateRange || event.button !== 0) return\n const layer = event.currentTarget\n const rect = layer.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n try {\n layer.setPointerCapture(event.pointerId)\n } catch {\n // Pointer capture is best-effort; ignore environments that reject it.\n }\n setSelectedId(null)\n updateDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false })\n }\n\n const moveDrag = (event: React.PointerEvent<HTMLDivElement>) => {\n const previous = dragRef.current\n if (!previous) return\n const rect = event.currentTarget.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n if (minute === previous.endMin) return\n updateDrag({\n ...previous,\n endMin: minute,\n moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES,\n })\n }\n\n const endDrag = (dayStart: Date) => {\n const previous = dragRef.current\n updateDrag(null)\n if (previous && previous.moved && onCreateRange) {\n const range = buildDragRange(dayStart, previous.startMin, previous.endMin)\n onCreateRange(range.start, range.end)\n }\n }\n\n return (\n <div className=\"relative flex flex-col overflow-hidden rounded-lg border border-border bg-card\">\n <div\n ref={scrollRef}\n className=\"overflow-auto overscroll-contain\"\n style={{ maxHeight: GRID_BODY_MAX_HEIGHT_PX }}\n >\n <div className=\"sticky top-0 z-30 min-w-full bg-card max-md:w-max\">\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 bg-card md:w-26\">\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={previousLabel} onClick={() => onNavigate(-days)}>\n <ChevronLeft aria-hidden />\n </IconButton>\n </span>\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={nextLabel} onClick={() => onNavigate(days)}>\n <ChevronRight aria-hidden />\n </IconButton>\n </span>\n </div>\n {dayColumns.map(({ dayStart }) => {\n const isToday = isSameDay(dayStart, today)\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'flex min-w-0 flex-1 items-center justify-center border-e border-border bg-muted px-1 py-2 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n <span\n className={cn(\n 'truncate text-xs uppercase tracking-wide',\n isToday ? 'font-semibold text-foreground' : 'font-medium text-muted-foreground',\n )}\n >\n {headerLabelFor(dayStart)}\n </span>\n </div>\n )\n })}\n </div>\n {hasAllDayLane ? (\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 items-center justify-center border-e border-border bg-card py-1 md:w-26\">\n <span className=\"truncate text-overline uppercase tracking-wide text-muted-foreground\">\n {t('customers.calendar.grid.allDay', 'All day')}\n </span>\n </div>\n {dayColumns.map(({ dayStart, allDayItems }) => (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'min-w-0 flex-1 space-y-1 border-e border-border p-1 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n {allDayItems.map((item) => (\n <EventPeekPopover\n key={item.id}\n item={item}\n open={selectedId === item.id}\n joinUrl={resolveJoinUrl(item.location)}\n aiSummaries={aiSummaries}\n canManage={canManage}\n onOpenChange={(open) => setSelectedId(open ? item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <AllDayChip\n item={item}\n conflicted={showConflicts && conflictIds.has(item.id)}\n highlighted={highlightItemId === item.id}\n selected={selectedId === item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-full max-md:w-max\" style={{ height: HOURS_PER_DAY * HOUR_HEIGHT_PX }}>\n <div className=\"sticky start-0 z-10 w-14 shrink-0 border-e border-border bg-card md:w-26\">\n <div className=\"relative h-full\">\n {hourLabels.map((label, hour) =>\n hour === 0 ? null : (\n <span\n key={hour}\n className=\"absolute w-full -translate-y-1/2 px-1 text-center text-xs font-medium text-muted-foreground md:px-3 md:text-sm\"\n style={{ top: hour * HOUR_HEIGHT_PX }}\n >\n {label}\n </span>\n ),\n )}\n </div>\n </div>\n {dayColumns.map(({ dayStart, blocks }) => {\n const nonWorking = isWeekendDay(dayStart)\n const conflictCount = showConflicts\n ? blocks.filter((block) => conflictIds.has(block.item.id)).length\n : 0\n const dragActive = drag && drag.moved && drag.dayMs === dayStart.getTime()\n const dragRange = dragActive ? buildDragRange(dayStart, drag.startMin, drag.endMin) : null\n const dragStartMinutes = dragRange\n ? (dragRange.start.getTime() - startOfDay(dragRange.start).getTime()) / 60000\n : 0\n const dragDurationMinutes = dragRange\n ? (dragRange.end.getTime() - dragRange.start.getTime()) / 60000\n : 0\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'relative min-w-0 flex-1 border-e border-border last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n title={nonWorking ? nonWorkingLabel : undefined}\n >\n {nonWorking ? <span className=\"sr-only\">{nonWorkingLabel}</span> : null}\n <div aria-hidden className=\"absolute inset-0\">\n {Array.from({ length: HOURS_PER_DAY }, (_, hour) => (\n <div key={hour} className=\"relative h-30 border-b border-border\">\n <span className=\"absolute inset-x-0 top-1/2 h-px bg-border/50\" />\n </div>\n ))}\n </div>\n {nonWorking ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{ backgroundImage: NON_WORKING_HATCH_BACKGROUND }}\n />\n ) : null}\n {canCreateRange ? (\n <div\n className=\"absolute inset-0 cursor-cell\"\n onPointerDown={(event) => beginDrag(event, dayStart)}\n onPointerMove={moveDrag}\n onPointerUp={() => endDrag(dayStart)}\n onPointerCancel={() => updateDrag(null)}\n aria-hidden\n />\n ) : null}\n {dragRange ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute z-30 flex flex-col gap-0.5 overflow-hidden rounded-md border-2 border-dashed border-foreground bg-accent-indigo/10 px-2 pt-1.5\"\n style={{\n top: (dragStartMinutes / 60) * HOUR_HEIGHT_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, (dragDurationMinutes / 60) * HOUR_HEIGHT_PX),\n insetInlineStart: 8,\n insetInlineEnd: 8,\n }}\n >\n <span className=\"text-overline font-semibold text-foreground\">\n {t('customers.calendar.actions.newEvent', 'New event')}\n </span>\n <span className=\"text-overline text-muted-foreground\">\n {formatTimeRange(locale, dragRange.start, dragRange.end)}\n </span>\n </div>\n ) : null}\n {conflictCount > 0 ? <ConflictBadge count={conflictCount} /> : null}\n {/* Click-through container so empty space reaches the drag-to-create layer\n below; each block re-enables pointer events for its own click/peek. */}\n <div className=\"pointer-events-none absolute inset-y-0\" style={{ insetInlineStart: 8, insetInlineEnd: 8 }}>\n {blocks.map((block) => (\n <EventPeekPopover\n key={`${block.item.id}-${block.top}`}\n item={block.item}\n open={selectedId === block.item.id}\n joinUrl={resolveJoinUrl(block.item.location)}\n aiSummaries={aiSummaries}\n canManage={canManage}\n onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <EventBlock\n item={block.item}\n top={block.top}\n height={block.height}\n insetInlineStart={block.insetInlineStart}\n width={block.width}\n conflicted={showConflicts && conflictIds.has(block.item.id)}\n highlighted={highlightItemId === block.item.id}\n selected={selectedId === block.item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": ";AA0GI,SACE,KADF;AAxGJ,YAAY,WAAW;AACvB,SAAS,aAAa,oBAAoB;AAC1C,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AACnB,SAAS,WAAW,YAAY;AAChC,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY,iBAAiB,wBAAwB;AAC9D,SAAS,wBAAwB;AAGjC,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAChC,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;AAC9B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAE7B,MAAM,+BACJ;AAkBF,SAAS,eAAe,UAAgB,OAAsC;AAC5E,QAAM,SAAS,QAAQ,UAAU,CAAC;AAClC,QAAM,aAAa,SAAS,QAAQ;AACpC,QAAM,WAAW,OAAO,QAAQ;AAChC,QAAM,cAA8B,CAAC;AACrC,QAAM,WAAsE,CAAC;AAE7E,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,MAAM,QAAQ;AACnC,UAAM,QAAQ,KAAK,IAAI,QAAQ;AAC/B,QAAI,WAAW,YAAY,SAAS,WAAY;AAChD,QAAI,KAAK,QAAQ;AACf,kBAAY,KAAK,IAAI;AACrB;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,OAAO,UAAU,aAAa,WAAW,KAAK;AAAA,MAC9C,KAAK,QAAQ,WAAW,SAAS,KAAK;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,cAAY,KAAK,CAAC,OAAO,WAAW,MAAM,MAAM,QAAQ,IAAI,OAAO,MAAM,QAAQ,CAAC;AAElF,QAAM,SAAS,SAAS,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,UAAU,OAAO,QAAQ,OAAO,KAAK,QAAQ,IAAI,EAAE;AAC1G,QAAM,kBAAkB,oBAAI,IAAgC;AAC5D,SAAO,QAAQ,CAAC,OAAO,UAAU,gBAAgB,IAAI,OAAO,SAAS,KAAK,EAAE,QAAQ,CAAC;AAErF,QAAM,SAA4B,aAAa,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,OAAO,QAAQ,QAAQ,MAAM;AAC/F,UAAM,gBAAgB,MAAM,MAAM,QAAQ,IAAI,cAAc;AAC5D,UAAM,mBAAmB,MAAM,IAAI,QAAQ,IAAI,MAAM,MAAM,QAAQ,KAAK;AACxE,UAAM,SAAU,eAAe,KAAM;AACrC,UAAM,YAAa,kBAAkB,KAAM;AAC3C,UAAM,WAAW,MAAM;AACvB,WAAO;AAAA,MACL,MAAM,gBAAgB,IAAI,KAAK,KAAK;AAAA,MACpC,KAAK,SAAS;AAAA,MACd,QAAQ,KAAK,IAAI,qBAAqB,YAAY,wBAAwB,CAAC;AAAA,MAC3E,kBAAkB,QAAQ,SAAS,QAAQ,OAAO,SAAS,oBAAoB;AAAA,MAC/E,OAAO,QAAQ,QAAQ,QAAS,UAAU,KAAK,uBAAwB,OAAO;AAAA,IAChF;AAAA,EACF,CAAC;AAED,SAAO,EAAE,UAAU,aAAa,OAAO;AACzC;AAIA,SAAS,cAAc,EAAE,MAAM,GAAuB;AACpD,QAAM,IAAI,KAAK;AACf,QAAM,QACJ,UAAU,IACN,EAAE,yCAAyC,YAAY,IACvD,EAAE,0CAA0C,qBAAqB,EAAE,MAAM,CAAC;AAChF,SACE,qBAAC,UAAK,WAAU,sMACd;AAAA,wBAAC,UAAK,eAAW,MAAC,WAAU,8CAA6C;AAAA,IACxE;AAAA,KACH;AAEJ;AAUA,MAAM,aAAa,MAAM,WAA+C,SAASA,YAC/E,EAAE,MAAM,YAAY,aAAa,UAAU,OAAO,WAAW,GAAG,YAAY,GAC5E,KACA;AACA,QAAM,IAAI,KAAK;AACf,QAAM,OAAO,iBAAiB,MAAM,KAAK;AACzC,QAAM,QAAQ,KAAK,SAAS,EAAE,oCAAoC,UAAU;AAC5E,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,cAAY,GAAG,KAAK,KAAK,EAAE,kCAAkC,SAAS,CAAC;AAAA,MACvE,WAAW;AAAA,QACT;AAAA,QACA,KAAK;AAAA,QACL,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,KAAK;AAAA,MACX,GAAG;AAAA,MAEJ,8BAAC,UAAK,WAAW,GAAG,gCAAgC,KAAK,cAAc,GAAI,iBAAM;AAAA;AAAA,EACnF;AAEJ,CAAC;AAED,WAAW,cAAc;AAElB,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,YAAY,MAAM,OAA8B,IAAI;AAC1D,QAAM,QAAQ,KAAK,IAAI;AACvB,QAAM,QAAQ,WAAW,oBAAI,KAAK,CAAC;AACnC,QAAM,UAAU,MAAM,QAAQ;AAC9B,QAAM,WAAW,OAAO,QAAQ;AAChC,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAwB,IAAI;AACtE,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAA2B,IAAI;AAC7D,QAAM,UAAU,MAAM,OAAyB,IAAI;AACnD,QAAM,aAAa,CAAC,SAA2B;AAC7C,YAAQ,UAAU;AAClB,YAAQ,IAAI;AAAA,EACd;AAEA,QAAM,YAAY,MAAM,QAAQ,MAAM;AACpC,UAAM,aAAa,gBAAgB,SAAS,IAAI,SAAS,OAAO,IAAI,KAAK,QAAQ,GAAG,CAAC,EAAE;AACvF,UAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC,GAAG,UAAU,QAAQ,YAAY,KAAK,CAAC;AACjF,WAAO,SAAS,IAAI,uBAAuB,KAAK,cAAc,IAAI,KAAK,OAAO,CAAC,IAAI;AAAA,EACrF,GAAG,CAAC,MAAM,UAAU,cAAc,OAAO,CAAC;AAE1C,QAAM,aAAa,MAAM;AAAA,IACvB,MAAM,UAAU,IAAI,CAAC,aAAa,eAAe,UAAU,KAAK,CAAC;AAAA,IACjE,CAAC,WAAW,KAAK;AAAA,EACnB;AAEA,QAAM,iBAAiB,MAAM,YAAY,CAAC,aAA2C;AACnF,UAAM,UAAU,UAAU,KAAK,KAAK;AACpC,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,gBAAgB,KAAK,OAAO,EAAG,QAAO;AAC1C,QAAI,UAAU,KAAK,OAAO,EAAG,QAAO,WAAW,OAAO;AACtD,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,WAAW,KAAK,CAAC,WAAW,OAAO,YAAY,SAAS,CAAC;AAE/E,QAAM,aAAa,MAAM;AAAA,IACvB,OAAO;AAAA,MACL,WAAW,IAAI,KAAK,eAAe,QAAQ,EAAE,KAAK,UAAU,CAAC;AAAA,MAC7D,cAAc,IAAI,KAAK,eAAe,QAAQ,EAAE,SAAS,QAAQ,CAAC;AAAA,MAClE,aAAa,IAAI,KAAK,eAAe,QAAQ,EAAE,SAAS,OAAO,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,QAAQ,MAAM;AACrC,UAAM,YAAY,IAAI,KAAK,eAAe,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrE,WAAO,MAAM,KAAK,EAAE,QAAQ,cAAc,GAAG,CAAC,GAAG,SAAS,UAAU,OAAO,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,EACxG,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,UAAU,MAAM;AACpB,UAAM,OAAO,UAAU;AACvB,QAAI,CAAC,KAAM;AACX,SAAK,YAAY,sBAAsB;AAAA,EACzC,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,gBAAiB;AACtB,UAAM,OAAO,UAAU;AACvB,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,mBAAmB,CAAC,KAAK,MAAM;AAC/E,QAAI,CAAC,OAAQ;AACb,UAAM,WAAW,OAAO,MAAM,QAAQ,IAAI,WAAW,OAAO,KAAK,EAAE,QAAQ,KAAK;AAChF,UAAM,MAAO,UAAU,KAAM;AAC7B,UAAM,eACJ,OAAO,WAAW,eAAe,OAAO,WAAW,kCAAkC,EAAE;AACzF,SAAK,SAAS,EAAE,KAAK,KAAK,IAAI,GAAG,MAAM,cAAc,GAAG,UAAU,eAAe,SAAS,SAAS,CAAC;AAAA,EACtG,GAAG,CAAC,iBAAiB,KAAK,CAAC;AAE3B,QAAM,kBAAkB,EAAE,sCAAsC,iBAAiB;AACjF,QAAM,gBACJ,SAAS,IACL,EAAE,mCAAmC,eAAe,IACpD,EAAE,uCAAuC,cAAc;AAC7D,QAAM,YACJ,SAAS,IAAI,EAAE,+BAA+B,WAAW,IAAI,EAAE,mCAAmC,UAAU;AAE9G,QAAM,iBAAiB,CAAC,aAA2B;AACjD,UAAM,YAAY,WAAW,UAAU,OAAO,QAAQ;AACtD,QAAI,SAAS,EAAG,QAAO,GAAG,WAAW,YAAY,OAAO,QAAQ,EAAE,YAAY,CAAC,SAAM,SAAS;AAC9F,WAAO,GAAG,SAAS,IAAI,WAAW,aAAa,OAAO,QAAQ,EAAE,YAAY,CAAC;AAAA,EAC/E;AAEA,QAAM,iBAAiB,QAAQ,aAAa;AAE5C,QAAM,YAAY,CAAC,OAA2C,aAAmB;AAC/E,QAAI,CAAC,kBAAkB,MAAM,WAAW,EAAG;AAC3C,UAAM,QAAQ,MAAM;AACpB,UAAM,OAAO,MAAM,sBAAsB;AACzC,UAAM,SAAS,iBAAiB,MAAM,UAAU,KAAK,KAAK,cAAc;AACxE,QAAI;AACF,YAAM,kBAAkB,MAAM,SAAS;AAAA,IACzC,QAAQ;AAAA,IAER;AACA,kBAAc,IAAI;AAClB,eAAW,EAAE,OAAO,SAAS,QAAQ,GAAG,UAAU,QAAQ,QAAQ,QAAQ,OAAO,MAAM,CAAC;AAAA,EAC1F;AAEA,QAAM,WAAW,CAAC,UAA8C;AAC9D,UAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,SAAU;AACf,UAAM,OAAO,MAAM,cAAc,sBAAsB;AACvD,UAAM,SAAS,iBAAiB,MAAM,UAAU,KAAK,KAAK,cAAc;AACxE,QAAI,WAAW,SAAS,OAAQ;AAChC,eAAW;AAAA,MACT,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,OAAO,SAAS,SAAS,KAAK,IAAI,SAAS,SAAS,QAAQ,KAAK;AAAA,IACnE,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,CAAC,aAAmB;AAClC,UAAM,WAAW,QAAQ;AACzB,eAAW,IAAI;AACf,QAAI,YAAY,SAAS,SAAS,eAAe;AAC/C,YAAM,QAAQ,eAAe,UAAU,SAAS,UAAU,SAAS,MAAM;AACzE,oBAAc,MAAM,OAAO,MAAM,GAAG;AAAA,IACtC;AAAA,EACF;AAEA,SACE,oBAAC,SAAI,WAAU,kFACb;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAU;AAAA,MACV,OAAO,EAAE,WAAW,wBAAwB;AAAA,MAE5C;AAAA,6BAAC,SAAI,WAAU,qDACb;AAAA,+BAAC,SAAI,WAAU,+BACb;AAAA,iCAAC,SAAI,WAAU,0DACb;AAAA,kCAAC,UAAK,WAAU,kEACd,8BAAC,cAAW,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,cAAY,eAAe,SAAS,MAAM,WAAW,CAAC,IAAI,GAC5G,8BAAC,eAAY,eAAW,MAAC,GAC3B,GACF;AAAA,cACA,oBAAC,UAAK,WAAU,kEACd,8BAAC,cAAW,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,cAAY,WAAW,SAAS,MAAM,WAAW,IAAI,GACvG,8BAAC,gBAAa,eAAW,MAAC,GAC5B,GACF;AAAA,eACF;AAAA,YACC,WAAW,IAAI,CAAC,EAAE,SAAS,MAAM;AAChC,oBAAM,UAAU,UAAU,UAAU,KAAK;AACzC,qBACE;AAAA,gBAAC;AAAA;AAAA,kBAEC,WAAW;AAAA,oBACT;AAAA,oBACA,SAAS,KAAK;AAAA,kBAChB;AAAA,kBAEA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAW;AAAA,wBACT;AAAA,wBACA,UAAU,kCAAkC;AAAA,sBAC9C;AAAA,sBAEC,yBAAe,QAAQ;AAAA;AAAA,kBAC1B;AAAA;AAAA,gBAbK,SAAS,QAAQ;AAAA,cAcxB;AAAA,YAEJ,CAAC;AAAA,aACH;AAAA,UACC,gBACC,qBAAC,SAAI,WAAU,+BACb;AAAA,gCAAC,SAAI,WAAU,kHACb,8BAAC,UAAK,WAAU,wEACb,YAAE,kCAAkC,SAAS,GAChD,GACF;AAAA,YACC,WAAW,IAAI,CAAC,EAAE,UAAU,YAAY,MACvC;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAW;AAAA,kBACT;AAAA,kBACA,SAAS,KAAK;AAAA,gBAChB;AAAA,gBAEC,sBAAY,IAAI,CAAC,SAChB;AAAA,kBAAC;AAAA;AAAA,oBAEC;AAAA,oBACA,MAAM,eAAe,KAAK;AAAA,oBAC1B,SAAS,eAAe,KAAK,QAAQ;AAAA,oBACrC;AAAA,oBACA;AAAA,oBACA,cAAc,CAAC,SAAS,cAAc,OAAO,KAAK,KAAK,IAAI;AAAA,oBAC3D;AAAA,oBACA,QAAQ;AAAA,oBAER;AAAA,sBAAC;AAAA;AAAA,wBACC;AAAA,wBACA,YAAY,iBAAiB,YAAY,IAAI,KAAK,EAAE;AAAA,wBACpD,aAAa,oBAAoB,KAAK;AAAA,wBACtC,UAAU,eAAe,KAAK;AAAA,wBAC9B;AAAA;AAAA,oBACF;AAAA;AAAA,kBAhBK,KAAK;AAAA,gBAiBZ,CACD;AAAA;AAAA,cA1BI,SAAS,QAAQ;AAAA,YA2BxB,CACD;AAAA,aACH,IACE;AAAA,WACN;AAAA,QACA,qBAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,QAAQ,gBAAgB,eAAe,GAC5F;AAAA,8BAAC,SAAI,WAAU,4EACb,8BAAC,SAAI,WAAU,mBACZ,qBAAW;AAAA,YAAI,CAAC,OAAO,SACtB,SAAS,IAAI,OACX;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAU;AAAA,gBACV,OAAO,EAAE,KAAK,OAAO,eAAe;AAAA,gBAEnC;AAAA;AAAA,cAJI;AAAA,YAKP;AAAA,UAEJ,GACF,GACF;AAAA,UACC,WAAW,IAAI,CAAC,EAAE,UAAU,OAAO,MAAM;AACxC,kBAAM,aAAa,aAAa,QAAQ;AACxC,kBAAM,gBAAgB,gBAClB,OAAO,OAAO,CAAC,UAAU,YAAY,IAAI,MAAM,KAAK,EAAE,CAAC,EAAE,SACzD;AACJ,kBAAM,aAAa,QAAQ,KAAK,SAAS,KAAK,UAAU,SAAS,QAAQ;AACzE,kBAAM,YAAY,aAAa,eAAe,UAAU,KAAK,UAAU,KAAK,MAAM,IAAI;AACtF,kBAAM,mBAAmB,aACpB,UAAU,MAAM,QAAQ,IAAI,WAAW,UAAU,KAAK,EAAE,QAAQ,KAAK,MACtE;AACJ,kBAAM,sBAAsB,aACvB,UAAU,IAAI,QAAQ,IAAI,UAAU,MAAM,QAAQ,KAAK,MACxD;AACJ,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAW;AAAA,kBACT;AAAA,kBACA,SAAS,KAAK;AAAA,gBAChB;AAAA,gBACA,OAAO,aAAa,kBAAkB;AAAA,gBAErC;AAAA,+BAAa,oBAAC,UAAK,WAAU,WAAW,2BAAgB,IAAU;AAAA,kBACnE,oBAAC,SAAI,eAAW,MAAC,WAAU,oBACxB,gBAAM,KAAK,EAAE,QAAQ,cAAc,GAAG,CAAC,GAAG,SACzC,oBAAC,SAAe,WAAU,wCACxB,8BAAC,UAAK,WAAU,gDAA+C,KADvD,IAEV,CACD,GACH;AAAA,kBACC,aACC;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAW;AAAA,sBACX,WAAU;AAAA,sBACV,OAAO,EAAE,iBAAiB,6BAA6B;AAAA;AAAA,kBACzD,IACE;AAAA,kBACH,iBACC;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,eAAe,CAAC,UAAU,UAAU,OAAO,QAAQ;AAAA,sBACnD,eAAe;AAAA,sBACf,aAAa,MAAM,QAAQ,QAAQ;AAAA,sBACnC,iBAAiB,MAAM,WAAW,IAAI;AAAA,sBACtC,eAAW;AAAA;AAAA,kBACb,IACE;AAAA,kBACH,YACC;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAW;AAAA,sBACX,WAAU;AAAA,sBACV,OAAO;AAAA,wBACL,KAAM,mBAAmB,KAAM;AAAA,wBAC/B,QAAQ,KAAK,IAAI,qBAAsB,sBAAsB,KAAM,cAAc;AAAA,wBACjF,kBAAkB;AAAA,wBAClB,gBAAgB;AAAA,sBAClB;AAAA,sBAEA;AAAA,4CAAC,UAAK,WAAU,+CACb,YAAE,uCAAuC,WAAW,GACvD;AAAA,wBACA,oBAAC,UAAK,WAAU,uCACb,0BAAgB,QAAQ,UAAU,OAAO,UAAU,GAAG,GACzD;AAAA;AAAA;AAAA,kBACF,IACE;AAAA,kBACH,gBAAgB,IAAI,oBAAC,iBAAc,OAAO,eAAe,IAAK;AAAA,kBAG/D,oBAAC,SAAI,WAAU,0CAAyC,OAAO,EAAE,kBAAkB,GAAG,gBAAgB,EAAE,GACrG,iBAAO,IAAI,CAAC,UACX;AAAA,oBAAC;AAAA;AAAA,sBAEC,MAAM,MAAM;AAAA,sBACZ,MAAM,eAAe,MAAM,KAAK;AAAA,sBAChC,SAAS,eAAe,MAAM,KAAK,QAAQ;AAAA,sBAC3C;AAAA,sBACA;AAAA,sBACA,cAAc,CAAC,SAAS,cAAc,OAAO,MAAM,KAAK,KAAK,IAAI;AAAA,sBACjE;AAAA,sBACA,QAAQ;AAAA,sBAER;AAAA,wBAAC;AAAA;AAAA,0BACC,MAAM,MAAM;AAAA,0BACZ,KAAK,MAAM;AAAA,0BACX,QAAQ,MAAM;AAAA,0BACd,kBAAkB,MAAM;AAAA,0BACxB,OAAO,MAAM;AAAA,0BACb,YAAY,iBAAiB,YAAY,IAAI,MAAM,KAAK,EAAE;AAAA,0BAC1D,aAAa,oBAAoB,MAAM,KAAK;AAAA,0BAC5C,UAAU,eAAe,MAAM,KAAK;AAAA,0BACpC;AAAA;AAAA,sBACF;AAAA;AAAA,oBApBK,GAAG,MAAM,KAAK,EAAE,IAAI,MAAM,GAAG;AAAA,kBAqBpC,CACD,GACH;AAAA;AAAA;AAAA,cAhFK,SAAS,QAAQ;AAAA,YAiFxB;AAAA,UAEJ,CAAC;AAAA,WACH;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;",
6
6
  "names": ["AllDayChip"]
7
7
  }
@@ -0,0 +1,218 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { z } from "zod";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ import { registerComponent } from "@open-mercato/shared/modules/widgets/component-registry";
7
+ import { useRegisteredComponent } from "@open-mercato/ui/backend/injection/useRegisteredComponent";
8
+ import { defaultRepeatDaysForDateInput } from "../../../lib/calendar/editorPayload.js";
9
+ import { extensionPoints } from "../../../extension-points.js";
10
+ import { Field } from "./inputs.js";
11
+ import { LocationField } from "./LocationField.js";
12
+ import { PeopleField } from "./PeopleField.js";
13
+ import { PriorityField } from "./PriorityField.js";
14
+ import { RepeatField } from "./RepeatField.js";
15
+ import { ResourcesField } from "./ResourcesField.js";
16
+ import { ScheduleSection } from "./ScheduleSection.js";
17
+ import { eventTypeConfig } from "./useEventTypeCatalog.js";
18
+ const PEOPLE_FIELD_TEXT = {
19
+ attendees: { labelKey: "customers.calendar.editor.attendees", label: "Attendees", placeholderKey: "customers.calendar.editor.addPeoplePlaceholder", placeholder: "Add staff or customer\u2026" },
20
+ participants: { labelKey: "customers.calendar.editor.participants", label: "Participants", placeholderKey: "customers.calendar.editor.addPeoplePlaceholder", placeholder: "Add staff or customer\u2026" },
21
+ to: { labelKey: "customers.calendar.editor.to", label: "To", placeholderKey: "customers.calendar.editor.addRecipientPlaceholder", placeholder: "Add recipient\u2026" }
22
+ };
23
+ const MemoScheduleSection = React.memo(ScheduleSection);
24
+ const MemoRepeatField = React.memo(RepeatField);
25
+ const MemoPeopleField = React.memo(PeopleField);
26
+ const MemoLocationField = React.memo(LocationField);
27
+ const MemoResourcesField = React.memo(ResourcesField);
28
+ const MemoPriorityField = React.memo(PriorityField);
29
+ function DefaultEventTypePanel({ definition, values, errors, disabled, capabilities, setValue }) {
30
+ const t = useT();
31
+ const form = values;
32
+ const config = eventTypeConfig(definition);
33
+ const formRef = React.useRef(form);
34
+ formRef.current = form;
35
+ const handlers = React.useMemo(() => {
36
+ const update = (patch) => {
37
+ for (const [key, value] of Object.entries(patch)) setValue(key, value);
38
+ };
39
+ return {
40
+ allDay: (allDay) => update({ allDay }),
41
+ date: (date) => {
42
+ const current = formRef.current;
43
+ const untouchedDefault = JSON.stringify(current.repeatDays) === JSON.stringify(defaultRepeatDaysForDateInput(current.date));
44
+ update(untouchedDefault ? { date, repeatDays: defaultRepeatDaysForDateInput(date) } : { date });
45
+ },
46
+ startTime: (startTime) => update({ startTime }),
47
+ endDate: (endDate) => update({ endDate }),
48
+ endTime: (endTime) => update({ endTime }),
49
+ repeatFreq: (repeatFreq) => update(repeatFreq === "weekly" ? { repeatFreq, repeatDays: defaultRepeatDaysForDateInput(formRef.current.date) } : { repeatFreq }),
50
+ repeatDay: (index) => update({
51
+ repeatDays: formRef.current.repeatDays.map((active, dayIndex) => dayIndex === index ? !active : active)
52
+ }),
53
+ repeatEndType: (repeatEndType) => update({ repeatEndType }),
54
+ repeatCount: (repeatCount) => update({ repeatCount }),
55
+ repeatUntilDate: (repeatUntilDate) => update({ repeatUntilDate }),
56
+ participants: (participants) => update({ participants }),
57
+ assignee: (entries) => {
58
+ const next = entries[entries.length - 1] ?? null;
59
+ update({ assigneeUserId: next?.userId ?? null, assigneeName: next?.name ?? null });
60
+ },
61
+ location: (location) => update({ location }),
62
+ resources: (resources) => update({ resources }),
63
+ priority: (priority) => update({ priority })
64
+ };
65
+ }, [setValue]);
66
+ const phoneContactIds = React.useMemo(() => {
67
+ const ids = [];
68
+ if (form.relatedTo && form.relatedTo.kind !== "company") ids.push(form.relatedTo.id);
69
+ for (const participant of form.participants) {
70
+ if (participant.isCustomer && participant.userId) ids.push(participant.userId);
71
+ }
72
+ return Array.from(new Set(ids));
73
+ }, [form.relatedTo, form.participants]);
74
+ const assigneeValue = React.useMemo(
75
+ () => form.assigneeUserId ? [{ userId: form.assigneeUserId, name: form.assigneeName ?? form.assigneeUserId, isCustomer: false }] : [],
76
+ [form.assigneeUserId, form.assigneeName]
77
+ );
78
+ const priorityLabels = React.useMemo(() => ({
79
+ low: t("customers.calendar.editor.priority.low", "Low"),
80
+ medium: t("customers.calendar.editor.priority.medium", "Medium"),
81
+ high: t("customers.calendar.editor.priority.high", "High")
82
+ }), [t]);
83
+ return /* @__PURE__ */ jsxs("fieldset", { disabled, className: "grid min-w-0 grid-cols-1 items-start gap-4 border-0 p-0 lg:grid-cols-2 lg:gap-x-6", children: [
84
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
85
+ /* @__PURE__ */ jsx(
86
+ MemoScheduleSection,
87
+ {
88
+ dateLabel: config.dateLabel,
89
+ hasAllDay: config.hasAllDay,
90
+ hasEnd: config.hasEnd,
91
+ allDay: form.allDay,
92
+ date: form.date,
93
+ startTime: form.startTime,
94
+ endDate: form.endDate,
95
+ endTime: form.endTime,
96
+ startError: errors.startTime ?? errors.date,
97
+ endsError: errors.ends,
98
+ disabled,
99
+ onAllDayChange: handlers.allDay,
100
+ onDateChange: handlers.date,
101
+ onStartTimeChange: handlers.startTime,
102
+ onEndDateChange: handlers.endDate,
103
+ onEndTimeChange: handlers.endTime
104
+ }
105
+ ),
106
+ config.hasRepeat ? /* @__PURE__ */ jsx(
107
+ MemoRepeatField,
108
+ {
109
+ freq: form.repeatFreq,
110
+ days: form.repeatDays,
111
+ endType: form.repeatEndType,
112
+ count: form.repeatCount,
113
+ untilDate: form.repeatUntilDate,
114
+ untilError: errors.repeatUntilDate,
115
+ disabled,
116
+ onFreqChange: handlers.repeatFreq,
117
+ onToggleDay: handlers.repeatDay,
118
+ onEndTypeChange: handlers.repeatEndType,
119
+ onCountChange: handlers.repeatCount,
120
+ onUntilDateChange: handlers.repeatUntilDate
121
+ }
122
+ ) : null,
123
+ config.people && config.people !== "assignee" ? /* @__PURE__ */ jsx(Field, { label: t(PEOPLE_FIELD_TEXT[config.people].labelKey, PEOPLE_FIELD_TEXT[config.people].label), children: /* @__PURE__ */ jsx(
124
+ MemoPeopleField,
125
+ {
126
+ mode: "multi",
127
+ includeCustomers: true,
128
+ includeStaff: capabilities.staffEnabled,
129
+ placeholder: t(PEOPLE_FIELD_TEXT[config.people].placeholderKey, PEOPLE_FIELD_TEXT[config.people].placeholder),
130
+ ariaLabel: t(PEOPLE_FIELD_TEXT[config.people].labelKey, PEOPLE_FIELD_TEXT[config.people].label),
131
+ value: form.participants,
132
+ onChange: handlers.participants,
133
+ disabled
134
+ }
135
+ ) }) : null,
136
+ config.people === "assignee" && capabilities.staffEnabled ? /* @__PURE__ */ jsx(Field, { label: t("customers.calendar.editor.assignee", "Assignee"), error: errors.assignee, children: /* @__PURE__ */ jsx(
137
+ MemoPeopleField,
138
+ {
139
+ mode: "single",
140
+ includeCustomers: false,
141
+ includeStaff: true,
142
+ placeholder: t("customers.calendar.editor.assigneePlaceholder", "Assign to a team member\u2026"),
143
+ ariaLabel: t("customers.calendar.editor.assignee", "Assignee"),
144
+ value: assigneeValue,
145
+ onChange: handlers.assignee,
146
+ disabled
147
+ }
148
+ ) }) : null
149
+ ] }),
150
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
151
+ config.location ? /* @__PURE__ */ jsx(
152
+ MemoLocationField,
153
+ {
154
+ variant: config.location,
155
+ value: form.location,
156
+ onChange: handlers.location,
157
+ phoneContactIds,
158
+ disabled
159
+ }
160
+ ) : null,
161
+ capabilities.resourcesEnabled && definition.behavior.fields.resources ? /* @__PURE__ */ jsx(Field, { label: t("customers.calendar.editor.resources", "Resources"), children: /* @__PURE__ */ jsx(
162
+ MemoResourcesField,
163
+ {
164
+ placeholder: t("customers.calendar.editor.resourcesPlaceholder", "Add a resource\u2026"),
165
+ ariaLabel: t("customers.calendar.editor.resources", "Resources"),
166
+ value: form.resources,
167
+ onChange: handlers.resources,
168
+ disabled
169
+ }
170
+ ) }) : null,
171
+ config.hasPriority ? /* @__PURE__ */ jsx(Field, { label: t("customers.calendar.editor.priority.label", "Priority"), children: /* @__PURE__ */ jsx(
172
+ MemoPriorityField,
173
+ {
174
+ value: form.priority,
175
+ ariaLabel: t("customers.calendar.editor.priority.label", "Priority"),
176
+ labels: priorityLabels,
177
+ onChange: handlers.priority,
178
+ disabled
179
+ }
180
+ ) }) : null
181
+ ] })
182
+ ] });
183
+ }
184
+ const callbackSchema = z.custom(
185
+ (value) => typeof value === "function",
186
+ { message: "[internal] expected a field setter" }
187
+ );
188
+ const eventTypePanelPropsSchema = z.object({
189
+ definition: z.custom((value) => value !== null && typeof value === "object"),
190
+ panelKey: z.string().optional(),
191
+ mode: z.enum(["create", "edit"]),
192
+ values: z.record(z.string(), z.unknown()),
193
+ errors: z.record(z.string(), z.string().optional()),
194
+ disabled: z.boolean(),
195
+ capabilities: z.object({ resourcesEnabled: z.boolean(), staffEnabled: z.boolean() }),
196
+ setValue: callbackSchema
197
+ });
198
+ registerComponent({
199
+ id: extensionPoints.hosts.calendarEventTypePanel.componentId,
200
+ component: DefaultEventTypePanel,
201
+ metadata: {
202
+ module: "customers",
203
+ description: "Calendar event editor type-specific panel.",
204
+ propsSchema: eventTypePanelPropsSchema
205
+ }
206
+ });
207
+ function EventTypePanel(props) {
208
+ const Resolved = useRegisteredComponent(
209
+ extensionPoints.hosts.calendarEventTypePanel.componentId,
210
+ DefaultEventTypePanel
211
+ );
212
+ return /* @__PURE__ */ jsx(Resolved, { ...props });
213
+ }
214
+ export {
215
+ DefaultEventTypePanel,
216
+ EventTypePanel
217
+ };
218
+ //# sourceMappingURL=EventTypePanel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/calendar/editor/EventTypePanel.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { registerComponent } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { useRegisteredComponent } from '@open-mercato/ui/backend/injection/useRegisteredComponent'\nimport type { CalendarEventTypePanelProps, EffectiveCalendarEventType } from '../../../calendar-event-types'\nimport { defaultRepeatDaysForDateInput, type EditorFormState } from '../../../lib/calendar/editorPayload'\nimport { extensionPoints } from '../../../extension-points'\nimport { Field } from './inputs'\nimport { LocationField } from './LocationField'\nimport { PeopleField } from './PeopleField'\nimport { PriorityField } from './PriorityField'\nimport { RepeatField } from './RepeatField'\nimport { ResourcesField } from './ResourcesField'\nimport { ScheduleSection } from './ScheduleSection'\nimport { eventTypeConfig } from './useEventTypeCatalog'\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\nconst MemoScheduleSection = React.memo(ScheduleSection)\nconst MemoRepeatField = React.memo(RepeatField)\nconst MemoPeopleField = React.memo(PeopleField)\nconst MemoLocationField = React.memo(LocationField)\nconst MemoResourcesField = React.memo(ResourcesField)\nconst MemoPriorityField = React.memo(PriorityField)\n\nexport function DefaultEventTypePanel({ definition, values, errors, disabled, capabilities, setValue }: CalendarEventTypePanelProps) {\n const t = useT()\n const form = values as unknown as EditorFormState\n const config = eventTypeConfig(definition)\n // The handlers read the latest draft through a ref so their identities depend\n // only on `setValue`. Every field below is memoized, so a keystroke in an\n // unrelated field (title, description) re-renders none of them.\n const formRef = React.useRef(form)\n formRef.current = form\n const handlers = React.useMemo(() => {\n const update = (patch: Partial<EditorFormState>) => {\n for (const [key, value] of Object.entries(patch)) setValue(key, value)\n }\n return {\n allDay: (allDay: boolean) => update({ allDay }),\n date: (date: string) => {\n const current = formRef.current\n const untouchedDefault = JSON.stringify(current.repeatDays) === JSON.stringify(defaultRepeatDaysForDateInput(current.date))\n update(untouchedDefault ? { date, repeatDays: defaultRepeatDaysForDateInput(date) } : { date })\n },\n startTime: (startTime: string) => update({ startTime }),\n endDate: (endDate: string) => update({ endDate }),\n endTime: (endTime: string) => update({ endTime }),\n repeatFreq: (repeatFreq: EditorFormState['repeatFreq']) => update(repeatFreq === 'weekly'\n ? { repeatFreq, repeatDays: defaultRepeatDaysForDateInput(formRef.current.date) }\n : { repeatFreq }),\n repeatDay: (index: number) => update({\n repeatDays: formRef.current.repeatDays.map((active, dayIndex) => dayIndex === index ? !active : active),\n }),\n repeatEndType: (repeatEndType: EditorFormState['repeatEndType']) => update({ repeatEndType }),\n repeatCount: (repeatCount: number) => update({ repeatCount }),\n repeatUntilDate: (repeatUntilDate: string) => update({ repeatUntilDate }),\n participants: (participants: EditorFormState['participants']) => update({ participants }),\n assignee: (entries: EditorFormState['participants']) => {\n const next = entries[entries.length - 1] ?? null\n update({ assigneeUserId: next?.userId ?? null, assigneeName: next?.name ?? null })\n },\n location: (location: string) => update({ location }),\n resources: (resources: EditorFormState['resources']) => update({ resources }),\n priority: (priority: EditorFormState['priority']) => update({ priority }),\n }\n }, [setValue])\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 const assigneeValue = React.useMemo(\n () => form.assigneeUserId\n ? [{ userId: form.assigneeUserId, name: form.assigneeName ?? form.assigneeUserId, isCustomer: false }]\n : [],\n [form.assigneeUserId, form.assigneeName],\n )\n const priorityLabels = React.useMemo(() => ({\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 }), [t])\n\n return (\n <fieldset disabled={disabled} className=\"grid min-w-0 grid-cols-1 items-start gap-4 border-0 p-0 lg:grid-cols-2 lg:gap-x-6\">\n <div className=\"flex w-full flex-col gap-4\">\n <MemoScheduleSection\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 startError={errors.startTime ?? errors.date}\n endsError={errors.ends}\n disabled={disabled}\n onAllDayChange={handlers.allDay}\n onDateChange={handlers.date}\n onStartTimeChange={handlers.startTime}\n onEndDateChange={handlers.endDate}\n onEndTimeChange={handlers.endTime}\n />\n {config.hasRepeat ? (\n <MemoRepeatField\n freq={form.repeatFreq}\n days={form.repeatDays}\n endType={form.repeatEndType}\n count={form.repeatCount}\n untilDate={form.repeatUntilDate}\n untilError={errors.repeatUntilDate}\n disabled={disabled}\n onFreqChange={handlers.repeatFreq}\n onToggleDay={handlers.repeatDay}\n onEndTypeChange={handlers.repeatEndType}\n onCountChange={handlers.repeatCount}\n onUntilDateChange={handlers.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 <MemoPeopleField\n mode=\"multi\"\n includeCustomers\n includeStaff={capabilities.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={handlers.participants}\n disabled={disabled}\n />\n </Field>\n ) : null}\n {config.people === 'assignee' && capabilities.staffEnabled ? (\n <Field label={t('customers.calendar.editor.assignee', 'Assignee')} error={errors.assignee}>\n <MemoPeopleField\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={assigneeValue}\n onChange={handlers.assignee}\n disabled={disabled}\n />\n </Field>\n ) : null}\n </div>\n <div className=\"flex w-full flex-col gap-4\">\n {config.location ? (\n <MemoLocationField\n variant={config.location}\n value={form.location}\n onChange={handlers.location}\n phoneContactIds={phoneContactIds}\n disabled={disabled}\n />\n ) : null}\n {capabilities.resourcesEnabled && definition.behavior.fields.resources ? (\n <Field label={t('customers.calendar.editor.resources', 'Resources')}>\n <MemoResourcesField\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={handlers.resources}\n disabled={disabled}\n />\n </Field>\n ) : null}\n {config.hasPriority ? (\n <Field label={t('customers.calendar.editor.priority.label', 'Priority')}>\n <MemoPriorityField\n value={form.priority}\n ariaLabel={t('customers.calendar.editor.priority.label', 'Priority')}\n labels={priorityLabels}\n onChange={handlers.priority}\n disabled={disabled}\n />\n </Field>\n ) : null}\n </div>\n </fieldset>\n )\n}\n\nconst callbackSchema = z.custom<CalendarEventTypePanelProps['setValue']>(\n (value) => typeof value === 'function',\n { message: '[internal] expected a field setter' },\n)\n\nconst eventTypePanelPropsSchema: z.ZodType<CalendarEventTypePanelProps> = z.object({\n definition: z.custom<EffectiveCalendarEventType>((value) => value !== null && typeof value === 'object'),\n panelKey: z.string().optional(),\n mode: z.enum(['create', 'edit']),\n values: z.record(z.string(), z.unknown()),\n errors: z.record(z.string(), z.string().optional()),\n disabled: z.boolean(),\n capabilities: z.object({ resourcesEnabled: z.boolean(), staffEnabled: z.boolean() }),\n setValue: callbackSchema,\n})\n\nregisterComponent<CalendarEventTypePanelProps>({\n id: extensionPoints.hosts.calendarEventTypePanel.componentId,\n component: DefaultEventTypePanel,\n metadata: {\n module: 'customers',\n description: 'Calendar event editor type-specific panel.',\n propsSchema: eventTypePanelPropsSchema,\n },\n})\n\nexport function EventTypePanel(props: CalendarEventTypePanelProps) {\n const Resolved = useRegisteredComponent<CalendarEventTypePanelProps>(\n extensionPoints.hosts.calendarEventTypePanel.componentId,\n DefaultEventTypePanel,\n )\n return <Resolved {...props} />\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -8,7 +8,8 @@ import { Field } from "./inputs.js";
8
8
  import { fetchPeoplePhones } from "./lookups.js";
9
9
  function PhoneSuggestions({
10
10
  contactIds,
11
- onPick
11
+ onPick,
12
+ disabled
12
13
  }) {
13
14
  const t = useT();
14
15
  const [contacts, setContacts] = React.useState([]);
@@ -34,6 +35,7 @@ function PhoneSuggestions({
34
35
  {
35
36
  type: "button",
36
37
  onClick: () => onPick(contact.phone),
38
+ disabled,
37
39
  title: t("customers.calendar.editor.phoneSuggestion.use", "Use {name}\u2019s number", { name: contact.name }),
38
40
  className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
39
41
  children: [
@@ -50,7 +52,8 @@ function LocationField({
50
52
  variant,
51
53
  value,
52
54
  onChange,
53
- phoneContactIds
55
+ phoneContactIds,
56
+ disabled
54
57
  }) {
55
58
  const t = useT();
56
59
  const label = variant === "phoneLink" ? t("customers.calendar.editor.phoneLink", "Phone / link") : t("customers.calendar.editor.location", "Location");
@@ -65,10 +68,11 @@ function LocationField({
65
68
  onChange: (event) => onChange(event.target.value),
66
69
  placeholder,
67
70
  "aria-label": label,
71
+ disabled,
68
72
  leftIcon: variant === "phoneLink" ? /* @__PURE__ */ jsx(Phone, {}) : /* @__PURE__ */ jsx(MapPin, {})
69
73
  }
70
74
  ),
71
- showSuggestions ? /* @__PURE__ */ jsx(PhoneSuggestions, { contactIds: phoneContactIds ?? [], onPick: (phone) => onChange(phone) }) : null
75
+ showSuggestions ? /* @__PURE__ */ jsx(PhoneSuggestions, { contactIds: phoneContactIds ?? [], onPick: (phone) => onChange(phone), disabled }) : null
72
76
  ] });
73
77
  }
74
78
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/calendar/editor/LocationField.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MapPin, Phone, Plus } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Field } from './inputs'\nimport { fetchPeoplePhones, type ContactPhone } from './lookups'\n\n// Below the Call \"Phone / link\" field: when a linked contact has a primary\n// phone and the field is still empty, offer it as a one-click suggestion chip\n// showing the actual number (#3552). Companies/staff have no phone and never\n// appear. The chips vanish once the field is filled.\nfunction PhoneSuggestions({\n contactIds,\n onPick,\n}: {\n contactIds: string[]\n onPick(phone: string): void\n}) {\n const t = useT()\n const [contacts, setContacts] = React.useState<ContactPhone[]>([])\n const idsKey = contactIds.join(',')\n\n React.useEffect(() => {\n if (contactIds.length === 0) {\n setContacts([])\n return\n }\n const controller = new AbortController()\n let cancelled = false\n fetchPeoplePhones(contactIds, controller.signal).then((found) => {\n if (!cancelled) setContacts(found)\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- idsKey captures the ids\n }, [idsKey])\n\n if (contacts.length === 0) return null\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 pt-1.5\">\n {contacts.map((contact) => (\n <button\n key={contact.id}\n type=\"button\"\n onClick={() => onPick(contact.phone)}\n title={t('customers.calendar.editor.phoneSuggestion.use', 'Use {name}\u2019s number', { name: contact.name })}\n className=\"inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Plus aria-hidden className=\"size-3 shrink-0\" />\n <span className=\"shrink-0\">{t('customers.calendar.editor.phoneSuggestion.add', 'Add')}</span>\n <span className=\"truncate\">{contact.name}</span>\n <span className=\"shrink-0 tabular-nums text-foreground\">{contact.phone}</span>\n </button>\n ))}\n </div>\n )\n}\n\nexport function LocationField({\n variant,\n value,\n onChange,\n phoneContactIds,\n}: {\n variant: 'location' | 'phoneLink'\n value: string\n onChange(next: string): void\n /** Person ids whose phone can be suggested (Call variant only). */\n phoneContactIds?: string[]\n}) {\n const t = useT()\n const label = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLink', 'Phone / link')\n : t('customers.calendar.editor.location', 'Location')\n const placeholder = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLinkPlaceholder', 'Add a phone number or link\u2026')\n : t('customers.calendar.editor.locationPlaceholder', 'Add a location or link\u2026')\n // Suggestions only help while the field is empty \u2014 once filled they'd be noise.\n const showSuggestions = variant === 'phoneLink' && value.trim().length === 0\n return (\n <Field label={label}>\n <Input\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n aria-label={label}\n leftIcon={variant === 'phoneLink' ? <Phone /> : <MapPin />}\n />\n {showSuggestions ? (\n <PhoneSuggestions contactIds={phoneContactIds ?? []} onPick={(phone) => onChange(phone)} />\n ) : null}\n </Field>\n )\n}\n"],
5
- "mappings": ";AA6CQ,SAOE,KAPF;AA3CR,YAAY,WAAW;AACvB,SAAS,QAAQ,OAAO,YAAY;AACpC,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,yBAA4C;AAMrD,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AACF,GAGG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAyB,CAAC,CAAC;AACjE,QAAM,SAAS,WAAW,KAAK,GAAG;AAElC,QAAM,UAAU,MAAM;AACpB,QAAI,WAAW,WAAW,GAAG;AAC3B,kBAAY,CAAC,CAAC;AACd;AAAA,IACF;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,YAAY;AAChB,sBAAkB,YAAY,WAAW,MAAM,EAAE,KAAK,CAAC,UAAU;AAC/D,UAAI,CAAC,UAAW,aAAY,KAAK;AAAA,IACnC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW,MAAM;AAAA,IACnB;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,SACE,oBAAC,SAAI,WAAU,8CACZ,mBAAS,IAAI,CAAC,YACb;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,OAAO,QAAQ,KAAK;AAAA,MACnC,OAAO,EAAE,iDAAiD,4BAAuB,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MACvG,WAAU;AAAA,MAEV;AAAA,4BAAC,QAAK,eAAW,MAAC,WAAU,mBAAkB;AAAA,QAC9C,oBAAC,UAAK,WAAU,YAAY,YAAE,iDAAiD,KAAK,GAAE;AAAA,QACtF,oBAAC,UAAK,WAAU,YAAY,kBAAQ,MAAK;AAAA,QACzC,oBAAC,UAAK,WAAU,yCAAyC,kBAAQ,OAAM;AAAA;AAAA;AAAA,IATlE,QAAQ;AAAA,EAUf,CACD,GACH;AAEJ;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,QAAQ,YAAY,cACtB,EAAE,uCAAuC,cAAc,IACvD,EAAE,sCAAsC,UAAU;AACtD,QAAM,cAAc,YAAY,cAC5B,EAAE,kDAAkD,kCAA6B,IACjF,EAAE,iDAAiD,8BAAyB;AAEhF,QAAM,kBAAkB,YAAY,eAAe,MAAM,KAAK,EAAE,WAAW;AAC3E,SACE,qBAAC,SAAM,OACL;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD;AAAA,QACA,cAAY;AAAA,QACZ,UAAU,YAAY,cAAc,oBAAC,SAAM,IAAK,oBAAC,UAAO;AAAA;AAAA,IAC1D;AAAA,IACC,kBACC,oBAAC,oBAAiB,YAAY,mBAAmB,CAAC,GAAG,QAAQ,CAAC,UAAU,SAAS,KAAK,GAAG,IACvF;AAAA,KACN;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MapPin, Phone, Plus } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Field } from './inputs'\nimport { fetchPeoplePhones, type ContactPhone } from './lookups'\n\n// Below the Call \"Phone / link\" field: when a linked contact has a primary\n// phone and the field is still empty, offer it as a one-click suggestion chip\n// showing the actual number (#3552). Companies/staff have no phone and never\n// appear. The chips vanish once the field is filled.\nfunction PhoneSuggestions({\n contactIds,\n onPick,\n disabled,\n}: {\n contactIds: string[]\n onPick(phone: string): void\n disabled?: boolean\n}) {\n const t = useT()\n const [contacts, setContacts] = React.useState<ContactPhone[]>([])\n const idsKey = contactIds.join(',')\n\n React.useEffect(() => {\n if (contactIds.length === 0) {\n setContacts([])\n return\n }\n const controller = new AbortController()\n let cancelled = false\n fetchPeoplePhones(contactIds, controller.signal).then((found) => {\n if (!cancelled) setContacts(found)\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- idsKey captures the ids\n }, [idsKey])\n\n if (contacts.length === 0) return null\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 pt-1.5\">\n {contacts.map((contact) => (\n <button\n key={contact.id}\n type=\"button\"\n onClick={() => onPick(contact.phone)}\n disabled={disabled}\n title={t('customers.calendar.editor.phoneSuggestion.use', 'Use {name}\u2019s number', { name: contact.name })}\n className=\"inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Plus aria-hidden className=\"size-3 shrink-0\" />\n <span className=\"shrink-0\">{t('customers.calendar.editor.phoneSuggestion.add', 'Add')}</span>\n <span className=\"truncate\">{contact.name}</span>\n <span className=\"shrink-0 tabular-nums text-foreground\">{contact.phone}</span>\n </button>\n ))}\n </div>\n )\n}\n\nexport function LocationField({\n variant,\n value,\n onChange,\n phoneContactIds,\n disabled,\n}: {\n variant: 'location' | 'phoneLink'\n value: string\n onChange(next: string): void\n /** Person ids whose phone can be suggested (Call variant only). */\n phoneContactIds?: string[]\n disabled?: boolean\n}) {\n const t = useT()\n const label = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLink', 'Phone / link')\n : t('customers.calendar.editor.location', 'Location')\n const placeholder = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLinkPlaceholder', 'Add a phone number or link\u2026')\n : t('customers.calendar.editor.locationPlaceholder', 'Add a location or link\u2026')\n // Suggestions only help while the field is empty \u2014 once filled they'd be noise.\n const showSuggestions = variant === 'phoneLink' && value.trim().length === 0\n return (\n <Field label={label}>\n <Input\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n aria-label={label}\n disabled={disabled}\n leftIcon={variant === 'phoneLink' ? <Phone /> : <MapPin />}\n />\n {showSuggestions ? (\n <PhoneSuggestions contactIds={phoneContactIds ?? []} onPick={(phone) => onChange(phone)} disabled={disabled} />\n ) : null}\n </Field>\n )\n}\n"],
5
+ "mappings": ";AA+CQ,SAQE,KARF;AA7CR,YAAY,WAAW;AACvB,SAAS,QAAQ,OAAO,YAAY;AACpC,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,yBAA4C;AAMrD,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAyB,CAAC,CAAC;AACjE,QAAM,SAAS,WAAW,KAAK,GAAG;AAElC,QAAM,UAAU,MAAM;AACpB,QAAI,WAAW,WAAW,GAAG;AAC3B,kBAAY,CAAC,CAAC;AACd;AAAA,IACF;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,YAAY;AAChB,sBAAkB,YAAY,WAAW,MAAM,EAAE,KAAK,CAAC,UAAU;AAC/D,UAAI,CAAC,UAAW,aAAY,KAAK;AAAA,IACnC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW,MAAM;AAAA,IACnB;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,SACE,oBAAC,SAAI,WAAU,8CACZ,mBAAS,IAAI,CAAC,YACb;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,OAAO,QAAQ,KAAK;AAAA,MACnC;AAAA,MACA,OAAO,EAAE,iDAAiD,4BAAuB,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MACvG,WAAU;AAAA,MAEV;AAAA,4BAAC,QAAK,eAAW,MAAC,WAAU,mBAAkB;AAAA,QAC9C,oBAAC,UAAK,WAAU,YAAY,YAAE,iDAAiD,KAAK,GAAE;AAAA,QACtF,oBAAC,UAAK,WAAU,YAAY,kBAAQ,MAAK;AAAA,QACzC,oBAAC,UAAK,WAAU,yCAAyC,kBAAQ,OAAM;AAAA;AAAA;AAAA,IAVlE,QAAQ;AAAA,EAWf,CACD,GACH;AAEJ;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,QAAQ,YAAY,cACtB,EAAE,uCAAuC,cAAc,IACvD,EAAE,sCAAsC,UAAU;AACtD,QAAM,cAAc,YAAY,cAC5B,EAAE,kDAAkD,kCAA6B,IACjF,EAAE,iDAAiD,8BAAyB;AAEhF,QAAM,kBAAkB,YAAY,eAAe,MAAM,KAAK,EAAE,WAAW;AAC3E,SACE,qBAAC,SAAM,OACL;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD;AAAA,QACA,cAAY;AAAA,QACZ;AAAA,QACA,UAAU,YAAY,cAAc,oBAAC,SAAM,IAAK,oBAAC,UAAO;AAAA;AAAA,IAC1D;AAAA,IACC,kBACC,oBAAC,oBAAiB,YAAY,mBAAmB,CAAC,GAAG,QAAQ,CAAC,UAAU,SAAS,KAAK,GAAG,UAAoB,IAC3G;AAAA,KACN;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -23,7 +23,8 @@ function PeopleField({
23
23
  value,
24
24
  onChange,
25
25
  includeCustomers,
26
- includeStaff = true
26
+ includeStaff = true,
27
+ disabled
27
28
  }) {
28
29
  const t = useT();
29
30
  const activeOrgId = useCurrentOrganization()?.id ?? null;
@@ -94,7 +95,8 @@ function PeopleField({
94
95
  name: participant.name,
95
96
  badge: participant.isCustomer ? customerBadge : participant.userId ? void 0 : guestBadge,
96
97
  onRemove: () => onChange(value.filter((_, entryIndex) => entryIndex !== index)),
97
- removeLabel: t("customers.calendar.editor.removePerson", "Remove {name}", { name: participant.name })
98
+ removeLabel: t("customers.calendar.editor.removePerson", "Remove {name}", { name: participant.name }),
99
+ disabled
98
100
  },
99
101
  participant.userId ?? participant.email ?? index
100
102
  )),
@@ -109,6 +111,7 @@ function PeopleField({
109
111
  "aria-label": ariaLabel,
110
112
  role: "combobox",
111
113
  "aria-expanded": open,
114
+ disabled,
112
115
  className: "min-w-36 flex-1 border-0 bg-transparent px-0 shadow-none hover:bg-transparent focus-within:border-transparent focus-within:shadow-none",
113
116
  inputClassName: "text-sm text-foreground placeholder:text-muted-foreground"
114
117
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/calendar/editor/PeopleField.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorParticipant } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { searchPeopleOptions, type PersonOption } from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'\n\n// Mirrors the server-side guest rule in `interactionParticipantSchema`: a\n// participant with no user record is addressable only by a routable email.\nconst guestEmailSchema = z.string().email().max(320)\n\nfunction normalizeEmail(email: string | null | undefined): string | null {\n const normalized = email?.trim().toLowerCase()\n return normalized ? normalized : null\n}\n\nexport function PeopleField({\n mode,\n placeholder,\n ariaLabel,\n value,\n onChange,\n includeCustomers,\n includeStaff = true,\n}: {\n mode: 'multi' | 'single'\n placeholder: string\n ariaLabel: string\n value: EditorParticipant[]\n onChange(next: EditorParticipant[]): void\n includeCustomers: boolean\n /** Pass false when the staff module is not loaded \u2014 customer-only options. */\n includeStaff?: boolean\n}) {\n const t = useT()\n const activeOrgId = useCurrentOrganization()?.id ?? null\n const [query, setQuery] = React.useState('')\n const [open, setOpen] = React.useState(false)\n const [options, setOptions] = React.useState<PersonOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const close = React.useCallback(() => setOpen(false), [])\n const rootRef = useDropdownDismiss(open, close)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const results = await searchPeopleOptions(query.trim(), {\n includeCustomers,\n includeStaff,\n activeOrgId,\n signal: controller.signal,\n })\n if (cancelled) return\n setOptions(results)\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 250)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [activeOrgId, open, query, includeCustomers, includeStaff])\n\n const selectedIds = new Set(value.map((participant) => participant.userId))\n const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))\n\n // An external guest has no record to search for, so a typed address that\n // matches nothing is the only way to invite one (#5115). Multi mode only \u2014\n // the single-mode field is the task assignee, which becomes `ownerUserId` and\n // must resolve to a real staff user.\n const typedEmail = normalizeEmail(query)\n const selectedEmails = new Set(\n value.map((participant) => normalizeEmail(participant.email)).filter((email): email is string => email !== null),\n )\n const guestEmail =\n mode === 'multi' &&\n typedEmail !== null &&\n guestEmailSchema.safeParse(typedEmail).success &&\n !selectedEmails.has(typedEmail) &&\n !options.some((option) => normalizeEmail(option.email) === typedEmail)\n ? typedEmail\n : null\n const guestLabel = guestEmail\n ? t('customers.calendar.editor.addGuest', 'Invite {email} as a guest', { email: guestEmail })\n : ''\n\n const customerBadge = (\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.customerBadge', 'Customer')}\n </UppercaseBadge>\n )\n\n const guestBadge = (\n <UppercaseBadge className=\"bg-muted text-muted-foreground\">\n {t('customers.calendar.editor.guestBadge', 'Guest')}\n </UppercaseBadge>\n )\n\n return (\n <div\n ref={rootRef}\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2',\n 'min-h-14',\n CONTROL_BORDER,\n )}\n >\n {value.map((participant, index) => (\n <PersonChip\n key={participant.userId ?? participant.email ?? index}\n name={participant.name}\n badge={participant.isCustomer ? customerBadge : participant.userId ? undefined : guestBadge}\n onRemove={() => onChange(value.filter((_, entryIndex) => entryIndex !== index))}\n removeLabel={t('customers.calendar.editor.removePerson', 'Remove {name}', { name: participant.name })}\n />\n ))}\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onFocus={() => setOpen(true)}\n placeholder={placeholder}\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={open}\n className=\"min-w-36 flex-1 border-0 bg-transparent px-0 shadow-none hover:bg-transparent focus-within:border-transparent focus-within:shadow-none\"\n inputClassName=\"text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={ariaLabel} className={DROPDOWN_PANEL_CLASS}>\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && visibleOptions.length === 0 && !guestEmail ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading && guestEmail ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={guestLabel}\n title={guestLabel}\n onClick={() => {\n const participant: EditorParticipant = { name: guestEmail, email: guestEmail, isCustomer: false }\n onChange([...value, participant])\n setQuery('')\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={guestEmail} />\n <span className=\"min-w-0 flex-1 truncate\">{guestLabel}</span>\n {guestBadge}\n </Button>\n ) : null}\n {!loading\n ? visibleOptions.map((option) => (\n <Button\n key={`${option.isCustomer ? 'customer' : 'staff'}:${option.userId}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={composeAccessibleName([\n option.name,\n option.email,\n option.isCustomer ? t('customers.calendar.editor.customerBadge', 'Customer') : null,\n ])}\n title={composeAccessibleName([option.name, option.email])}\n onClick={() => {\n const participant: EditorParticipant = {\n userId: option.userId,\n name: option.name,\n email: option.email ?? undefined,\n isCustomer: option.isCustomer,\n }\n onChange(mode === 'single' ? [participant] : [...value, participant])\n setQuery('')\n if (mode === 'single') setOpen(false)\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={option.name} />\n <span className=\"min-w-0 flex-1 truncate\">\n {option.name}\n {option.email ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.email}</span> : null}\n </span>\n {option.isCustomer ? customerBadge : null}\n </Button>\n ))\n : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorParticipant } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { searchPeopleOptions, type PersonOption } from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'\n\n// Mirrors the server-side guest rule in `interactionParticipantSchema`: a\n// participant with no user record is addressable only by a routable email.\nconst guestEmailSchema = z.string().email().max(320)\n\nfunction normalizeEmail(email: string | null | undefined): string | null {\n const normalized = email?.trim().toLowerCase()\n return normalized ? normalized : null\n}\n\nexport function PeopleField({\n mode,\n placeholder,\n ariaLabel,\n value,\n onChange,\n includeCustomers,\n includeStaff = true,\n disabled,\n}: {\n mode: 'multi' | 'single'\n placeholder: string\n ariaLabel: string\n value: EditorParticipant[]\n onChange(next: EditorParticipant[]): void\n includeCustomers: boolean\n /** Pass false when the staff module is not loaded \u2014 customer-only options. */\n includeStaff?: boolean\n disabled?: boolean\n}) {\n const t = useT()\n const activeOrgId = useCurrentOrganization()?.id ?? null\n const [query, setQuery] = React.useState('')\n const [open, setOpen] = React.useState(false)\n const [options, setOptions] = React.useState<PersonOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const close = React.useCallback(() => setOpen(false), [])\n const rootRef = useDropdownDismiss(open, close)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const results = await searchPeopleOptions(query.trim(), {\n includeCustomers,\n includeStaff,\n activeOrgId,\n signal: controller.signal,\n })\n if (cancelled) return\n setOptions(results)\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 250)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [activeOrgId, open, query, includeCustomers, includeStaff])\n\n const selectedIds = new Set(value.map((participant) => participant.userId))\n const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))\n\n // An external guest has no record to search for, so a typed address that\n // matches nothing is the only way to invite one (#5115). Multi mode only \u2014\n // the single-mode field is the task assignee, which becomes `ownerUserId` and\n // must resolve to a real staff user.\n const typedEmail = normalizeEmail(query)\n const selectedEmails = new Set(\n value.map((participant) => normalizeEmail(participant.email)).filter((email): email is string => email !== null),\n )\n const guestEmail =\n mode === 'multi' &&\n typedEmail !== null &&\n guestEmailSchema.safeParse(typedEmail).success &&\n !selectedEmails.has(typedEmail) &&\n !options.some((option) => normalizeEmail(option.email) === typedEmail)\n ? typedEmail\n : null\n const guestLabel = guestEmail\n ? t('customers.calendar.editor.addGuest', 'Invite {email} as a guest', { email: guestEmail })\n : ''\n\n const customerBadge = (\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.customerBadge', 'Customer')}\n </UppercaseBadge>\n )\n\n const guestBadge = (\n <UppercaseBadge className=\"bg-muted text-muted-foreground\">\n {t('customers.calendar.editor.guestBadge', 'Guest')}\n </UppercaseBadge>\n )\n\n return (\n <div\n ref={rootRef}\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2',\n 'min-h-14',\n CONTROL_BORDER,\n )}\n >\n {value.map((participant, index) => (\n <PersonChip\n key={participant.userId ?? participant.email ?? index}\n name={participant.name}\n badge={participant.isCustomer ? customerBadge : participant.userId ? undefined : guestBadge}\n onRemove={() => onChange(value.filter((_, entryIndex) => entryIndex !== index))}\n removeLabel={t('customers.calendar.editor.removePerson', 'Remove {name}', { name: participant.name })}\n disabled={disabled}\n />\n ))}\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onFocus={() => setOpen(true)}\n placeholder={placeholder}\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled}\n className=\"min-w-36 flex-1 border-0 bg-transparent px-0 shadow-none hover:bg-transparent focus-within:border-transparent focus-within:shadow-none\"\n inputClassName=\"text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={ariaLabel} className={DROPDOWN_PANEL_CLASS}>\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && visibleOptions.length === 0 && !guestEmail ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading && guestEmail ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={guestLabel}\n title={guestLabel}\n onClick={() => {\n const participant: EditorParticipant = { name: guestEmail, email: guestEmail, isCustomer: false }\n onChange([...value, participant])\n setQuery('')\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={guestEmail} />\n <span className=\"min-w-0 flex-1 truncate\">{guestLabel}</span>\n {guestBadge}\n </Button>\n ) : null}\n {!loading\n ? visibleOptions.map((option) => (\n <Button\n key={`${option.isCustomer ? 'customer' : 'staff'}:${option.userId}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={composeAccessibleName([\n option.name,\n option.email,\n option.isCustomer ? t('customers.calendar.editor.customerBadge', 'Customer') : null,\n ])}\n title={composeAccessibleName([option.name, option.email])}\n onClick={() => {\n const participant: EditorParticipant = {\n userId: option.userId,\n name: option.name,\n email: option.email ?? undefined,\n isCustomer: option.isCustomer,\n }\n onChange(mode === 'single' ? [participant] : [...value, participant])\n setQuery('')\n if (mode === 'single') setOpen(false)\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={option.name} />\n <span className=\"min-w-0 flex-1 truncate\">\n {option.name}\n {option.email ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.email}</span> : null}\n </span>\n {option.isCustomer ? customerBadge : null}\n </Button>\n ))\n : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }