@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
@@ -24,6 +24,8 @@ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
24
24
  import { createLogger } from '@open-mercato/shared/lib/logger'
25
25
  import { CUSTOMER_DICTIONARY_ORGANIZATION_REQUIRED_CODE } from '../../../lib/dictionaries'
26
26
  import { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'
27
+ import { calendarEventTypeBehaviorSchema } from '../../../calendar-event-types'
28
+ import type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'
27
29
 
28
30
  const logger = createLogger('customers')
29
31
 
@@ -35,6 +37,7 @@ const postSchema = z.object({
35
37
  label: z.string().trim().max(150).optional(),
36
38
  color: colorSchema.or(z.null()).optional(),
37
39
  icon: iconSchema.or(z.null()).optional(),
40
+ behavior: calendarEventTypeBehaviorSchema.nullable().optional(),
38
41
  })
39
42
 
40
43
  const querySchema = z.object({
@@ -52,7 +55,7 @@ export async function GET(req: Request, ctx: { params?: { kind?: string } }) {
52
55
  const query = querySchema.parse({
53
56
  organizationId: url.searchParams.get('organizationId') ?? undefined,
54
57
  })
55
- const { translate, em, organizationId, readableOrganizationIds, tenantId, cache } = await resolveDictionaryRouteContext(req, {
58
+ const { translate, em, organizationId, readableOrganizationIds, tenantId, cache, container } = await resolveDictionaryRouteContext(req, {
56
59
  selectedId: query.organizationId ?? undefined,
57
60
  })
58
61
  const { kind, mappedKind } = mapDictionaryKind(ctx.params?.kind)
@@ -64,7 +67,15 @@ export async function GET(req: Request, ctx: { params?: { kind?: string } }) {
64
67
  }
65
68
  const settings = await loadCustomerSettings(em, { tenantId, organizationId })
66
69
  const sortMode = resolveDictionaryEntrySortMode(settings?.dictionarySortModes?.[kind])
67
- const scopedOrganizationIds = readableOrganizationIds.length > 0 ? readableOrganizationIds : [organizationId]
70
+ let scopedOrganizationIds = readableOrganizationIds.length > 0 ? readableOrganizationIds : [organizationId]
71
+ if (mappedKind === 'activity_type') {
72
+ const hierarchy = container.resolve('organizationHierarchyService') as OrganizationHierarchyService
73
+ const ancestors = await hierarchy.resolveAncestorIds({ tenantId, organizationId })
74
+ if (ancestors === null) {
75
+ throw new CrudHttpError(403, { error: translate('customers.errors.organization_forbidden', 'Organization not accessible') })
76
+ }
77
+ scopedOrganizationIds = Array.from(new Set([organizationId, ...ancestors.slice().reverse()]))
78
+ }
68
79
  const canUseCache = Boolean(cache) && mappedKind !== 'person_company_role'
69
80
 
70
81
  let cacheKey: string | null = null
@@ -133,6 +144,7 @@ export async function GET(req: Request, ctx: { params?: { kind?: string } }) {
133
144
  label: entry.label,
134
145
  color: entry.color,
135
146
  icon: entry.icon,
147
+ ...(mappedKind === 'activity_type' ? { behavior: entry.activityTypeBehavior ?? null } : {}),
136
148
  organizationId: entry.organizationId,
137
149
  isInherited: entry.organizationId !== organizationId,
138
150
  createdAt: entry.createdAt,
@@ -213,6 +225,7 @@ export async function POST(req: Request, ctx: { params?: { kind?: string } }) {
213
225
  label: body.label,
214
226
  color: body.color,
215
227
  icon: body.icon,
228
+ behavior: body.behavior,
216
229
  },
217
230
  ctx: context.ctx,
218
231
  })) as CommandExecuteResult<{ entryId: string; mode: 'created' | 'updated' | 'unchanged' }>
@@ -248,8 +261,10 @@ export async function POST(req: Request, ctx: { params?: { kind?: string } }) {
248
261
  label: entry.label,
249
262
  color: entry.color,
250
263
  icon: entry.icon,
264
+ ...(mappedKind === 'activity_type' ? { behavior: entry.activityTypeBehavior ?? null } : {}),
251
265
  organizationId: entry.organizationId,
252
266
  isInherited: false,
267
+ updatedAt: entry.updatedAt,
253
268
  },
254
269
  { status: result.mode === 'created' ? 201 : 200 }
255
270
  )
@@ -288,6 +303,7 @@ const dictionaryEntrySchema = z.object({
288
303
  label: z.string().nullable().optional(),
289
304
  color: z.string().nullable().optional(),
290
305
  icon: z.string().nullable().optional(),
306
+ behavior: calendarEventTypeBehaviorSchema.nullable().optional(),
291
307
  organizationId: z.string().uuid().nullable().optional(),
292
308
  isInherited: z.boolean().optional(),
293
309
  createdAt: z.date().or(z.string()).optional(),
@@ -179,6 +179,7 @@ type InteractionListRow = {
179
179
  appearance_icon: string | null
180
180
  appearance_color: string | null
181
181
  source: string | null
182
+ timezone: string | null
182
183
  duration_minutes: number | null
183
184
  location: string | null
184
185
  all_day: boolean | null
@@ -314,6 +315,7 @@ const INTERACTION_LIST_COLUMNS = [
314
315
  'appearance_icon',
315
316
  'appearance_color',
316
317
  'source',
318
+ 'timezone',
317
319
  'duration_minutes',
318
320
  'location',
319
321
  'all_day',
@@ -713,6 +715,7 @@ export async function GET(req: Request) {
713
715
  source: row.source ?? null,
714
716
  duration: row.duration_minutes ?? null,
715
717
  durationMinutes: row.duration_minutes ?? null,
718
+ timezone: row.timezone ?? null,
716
719
  location: row.location ?? null,
717
720
  allDay: row.all_day ?? null,
718
721
  recurrenceRule: row.recurrence_rule ?? null,
@@ -794,6 +797,7 @@ const interactionListItemSchema = z
794
797
  source: z.string().nullable().optional(),
795
798
  duration: z.number().nullable().optional(),
796
799
  durationMinutes: z.number().nullable().optional(),
800
+ timezone: z.string().nullable().optional(),
797
801
  location: z.string().nullable().optional(),
798
802
  allDay: z.boolean().nullable().optional(),
799
803
  recurrenceRule: z.string().nullable().optional(),
@@ -153,6 +153,7 @@ const todoItemSchema = z.object({
153
153
  todoSeverity: z.string().nullable().optional(),
154
154
  todoDescription: z.string().nullable().optional(),
155
155
  todoDueAt: z.string().nullable().optional(),
156
+ todoTimezone: z.string().nullable().optional(),
156
157
  todoCustomValues: z.record(z.string(), z.unknown()).nullable().optional(),
157
158
  todoOrganizationId: z.string().nullable(),
158
159
  organizationId: z.string(),
@@ -1,3 +1,22 @@
1
+ import React from 'react'
2
+
3
+ const pipelineIcon = React.createElement(
4
+ 'svg',
5
+ {
6
+ width: 16,
7
+ height: 16,
8
+ viewBox: '0 0 24 24',
9
+ fill: 'none',
10
+ stroke: 'currentColor',
11
+ strokeWidth: 2,
12
+ strokeLinecap: 'round',
13
+ strokeLinejoin: 'round',
14
+ },
15
+ React.createElement('rect', { x: 3, y: 4, width: 5, height: 16, rx: 1 }),
16
+ React.createElement('rect', { x: 10, y: 4, width: 5, height: 16, rx: 1 }),
17
+ React.createElement('rect', { x: 17, y: 4, width: 4, height: 16, rx: 1 })
18
+ )
19
+
1
20
  export const metadata = {
2
21
  requireAuth: true,
3
22
  requireFeatures: ['customers.pipelines.manage'],
@@ -6,6 +25,7 @@ export const metadata = {
6
25
  pageGroup: 'Module Configs',
7
26
  pageGroupKey: 'settings.sections.moduleConfigs',
8
27
  pageOrder: 4,
28
+ icon: pipelineIcon,
9
29
  pageContext: 'settings' as const,
10
30
  breadcrumb: [
11
31
  { label: 'Pipeline stages', labelKey: 'customers.config.nav.pipelineStages' },
@@ -42,7 +42,6 @@ type UseDealAssociationsResult = {
42
42
  companiesSaving: boolean
43
43
  handlePeopleAssociationsChange: (nextIds: string[]) => Promise<void>
44
44
  handleCompaniesAssociationsChange: (nextIds: string[]) => Promise<void>
45
- loadLinkedPeoplePage: (page: number, query: string) => Promise<LinkedPageResult>
46
45
  loadLinkedCompaniesPage: (page: number, query: string) => Promise<LinkedPageResult>
47
46
  }
48
47
 
@@ -64,33 +63,6 @@ export function useDealAssociations({
64
63
  setCompaniesEditorIds(data?.linkedCompanyIds ?? [])
65
64
  }, [data?.linkedCompanyIds, data?.linkedPersonIds])
66
65
 
67
- const loadLinkedPeoplePage = React.useCallback(
68
- async (page: number, query: string): Promise<LinkedPageResult> => {
69
- if (!currentDealId) {
70
- return { items: [], totalPages: 1, total: 0 }
71
- }
72
- const params = new URLSearchParams({
73
- page: String(page),
74
- pageSize: '20',
75
- sort: 'name-asc',
76
- })
77
- if (query.trim().length > 0) {
78
- params.set('search', query.trim())
79
- }
80
- const payload = await readApiResultOrThrow<{
81
- items?: DealAssociation[]
82
- total?: number
83
- totalPages?: number
84
- }>(`/api/customers/deals/${encodeURIComponent(currentDealId)}/people?${params.toString()}`)
85
- return {
86
- items: Array.isArray(payload.items) ? payload.items : [],
87
- totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,
88
- total: typeof payload.total === 'number' ? payload.total : 0,
89
- }
90
- },
91
- [currentDealId],
92
- )
93
-
94
66
  const loadLinkedCompaniesPage = React.useCallback(
95
67
  async (page: number, query: string): Promise<LinkedPageResult> => {
96
68
  if (!currentDealId) {
@@ -220,7 +192,6 @@ export function useDealAssociations({
220
192
  companiesSaving,
221
193
  handlePeopleAssociationsChange,
222
194
  handleCompaniesAssociationsChange,
223
- loadLinkedPeoplePage,
224
195
  loadLinkedCompaniesPage,
225
196
  }
226
197
  }
@@ -3,7 +3,7 @@
3
3
  import * as React from 'react'
4
4
  import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
5
5
  import Link from 'next/link'
6
- import { Building2, FileText, Hash, UserSearch, Users } from 'lucide-react'
6
+ import { Building2, FileText, Hash, UserSearch } from 'lucide-react'
7
7
  import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
8
8
  import { useRouter, useSearchParams, usePathname } from 'next/navigation'
9
9
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -24,6 +24,7 @@ import { DealDetailHeader } from '../../../../components/detail/DealDetailHeader
24
24
  import { DealDetailTabs, resolveLegacyTab, type DealTabId } from '../../../../components/detail/DealDetailTabs'
25
25
  import { DealForm, useDealAssociationLookups } from '../../../../components/detail/DealForm'
26
26
  import { DealLinkedEntitiesTab } from '../../../../components/detail/DealLinkedEntitiesTab'
27
+ import { DealPeopleSection } from '../../../../components/detail/DealPeopleSection'
27
28
  import { ConfirmDealLostDialog } from '../../../../components/detail/ConfirmDealLostDialog'
28
29
  import { DealLostSummaryDialog } from '../../../../components/detail/DealLostSummaryDialog'
29
30
  import { DealWonPopup } from '../../../../components/detail/DealWonPopup'
@@ -116,7 +117,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
116
117
  setActiveTab(initialTab)
117
118
  }, [initialTab])
118
119
 
119
- const { searchPeoplePage, fetchPeopleByIds, searchCompaniesPage, fetchCompaniesByIds } = useDealAssociationLookups({
120
+ const { searchCompaniesPage, fetchCompaniesByIds } = useDealAssociationLookups({
120
121
  excludeLinkedDealId: data?.deal.id ?? null,
121
122
  })
122
123
 
@@ -191,7 +192,6 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
191
192
  companiesSaving,
192
193
  handlePeopleAssociationsChange,
193
194
  handleCompaniesAssociationsChange,
194
- loadLinkedPeoplePage,
195
195
  loadLinkedCompaniesPage,
196
196
  } = useDealAssociations({
197
197
  currentDealId,
@@ -534,22 +534,20 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
534
534
 
535
535
  if (activeTab === 'people') {
536
536
  return (
537
- <DealLinkedEntitiesTab
538
- entityLabel={t('customers.deals.detail.tabs.peopleSingular', 'Person')}
539
- entityLabelPlural={t('customers.deals.detail.tabs.people', 'People')}
540
- manageLabel={t('customers.deals.detail.peopleEditorTitle', 'Manage linked people')}
541
- searchPlaceholder={t('customers.deals.detail.peopleSearch', 'Search linked people…')}
542
- linkedItems={data.people}
543
- linkedCount={data.counts.people}
537
+ <DealPeopleSection
538
+ dealId={data.deal.id}
539
+ dealName={dealName}
544
540
  selectedIds={peopleEditorIds}
545
- disabled={peopleSaving || isSaving}
546
- savePending={peopleSaving}
547
- hrefBuilder={(personId) => `/backend/customers/people-v2/${encodeURIComponent(personId)}`}
548
541
  onSaveSelection={(next) => handlePeopleAssociationsChange(next)}
549
- loadLinkedPage={loadLinkedPeoplePage}
550
- searchEntities={searchPeoplePage}
551
- fetchEntitiesByIds={fetchPeopleByIds}
552
- icon={<Users className="size-4" />}
542
+ addActionLabel={t('customers.deals.detail.peopleAdd', 'Add person')}
543
+ disabled={peopleSaving || isSaving}
544
+ emptyLabel={t('customers.deals.detail.peopleEmpty', 'No people linked to this deal yet.')}
545
+ emptyState={{
546
+ title: t('customers.deals.detail.peopleEmptyTitle', 'Link the people involved'),
547
+ actionLabel: t('customers.deals.detail.peopleEmptyAction', 'Add person'),
548
+ }}
549
+ translator={detailTranslator}
550
+ runGuardedMutation={runMutationWithContext}
553
551
  />
554
552
  )
555
553
  }