@open-mercato/core 0.6.6-develop.6314.1.c7b8291aa2 → 0.6.6-develop.6330.1.a261878aa8
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +7 -12
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +5 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +2 -2
- package/dist/modules/customers/ai-tools/_shared.js +158 -0
- package/dist/modules/customers/ai-tools/_shared.js.map +7 -0
- package/dist/modules/customers/ai-tools/companies-pack.js +15 -121
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +9 -107
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -0
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +12 -1
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/TimeGrid.js +3 -0
- package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js.map +1 -1
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +76 -67
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +3 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +4 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/runs.js +1 -0
- package/dist/modules/data_sync/api/runs.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/data/validators.js +1 -0
- package/dist/modules/data_sync/data/validators.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +20 -0
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/entities/api/records.js +11 -1
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +17 -10
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +32 -0
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +13 -5
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/en.js +11 -1
- package/dist/modules/shipping_carriers/i18n/en.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/pl.js +11 -1
- package/dist/modules/shipping_carriers/i18n/pl.js.map +2 -2
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js +25 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +3 -17
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +19 -14
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +7 -10
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -7
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +3 -2
- package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +3 -2
- package/src/modules/customers/ai-tools/_shared.ts +270 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +17 -157
- package/src/modules/customers/ai-tools/people-pack.ts +11 -133
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -0
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +29 -11
- package/src/modules/customers/components/calendar/TimeGrid.tsx +3 -0
- package/src/modules/customers/components/calendar/types.ts +1 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +89 -71
- package/src/modules/customers/i18n/de.json +1 -0
- package/src/modules/customers/i18n/en.json +1 -0
- package/src/modules/customers/i18n/es.json +1 -0
- package/src/modules/customers/i18n/pl.json +1 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
- package/src/modules/data_sync/api/runs.ts +1 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +3 -1
- package/src/modules/data_sync/data/validators.ts +1 -0
- package/src/modules/data_sync/i18n/de.json +1 -0
- package/src/modules/data_sync/i18n/en.json +1 -0
- package/src/modules/data_sync/i18n/es.json +1 -0
- package/src/modules/data_sync/i18n/pl.json +1 -0
- package/src/modules/data_sync/lib/sync-run-service.ts +23 -0
- package/src/modules/entities/api/records.ts +17 -1
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +25 -12
- package/src/modules/messages/api/unread-count/route.ts +40 -0
- package/src/modules/query_index/components/QueryIndexesTable.tsx +17 -15
- package/src/modules/shipping_carriers/i18n/de.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.ts +10 -0
- package/src/modules/shipping_carriers/i18n/es.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.ts +10 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.tsx +35 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +3 -22
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +30 -13
|
@@ -19,6 +19,12 @@ import {
|
|
|
19
19
|
type AiToolExecutionContext,
|
|
20
20
|
} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'
|
|
21
21
|
import { assertTenantScope, type CustomersAiToolDefinition, type CustomersToolContext } from './types'
|
|
22
|
+
import {
|
|
23
|
+
buildRelatedRecords,
|
|
24
|
+
toCustomerListSummary,
|
|
25
|
+
toIso,
|
|
26
|
+
type CustomerRelatedRecords,
|
|
27
|
+
} from './_shared'
|
|
22
28
|
|
|
23
29
|
const listCompaniesInput = z
|
|
24
30
|
.object({
|
|
@@ -108,27 +114,13 @@ const listCompaniesTool = defineApiBackedAiTool<
|
|
|
108
114
|
const data = (response.data ?? {}) as ListCompaniesApiResponse
|
|
109
115
|
const rawItems: ListCompaniesApiItem[] = Array.isArray(data.items) ? data.items : []
|
|
110
116
|
return {
|
|
111
|
-
items: rawItems.map((row) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
primaryPhone: row.primary_phone ?? row.primaryPhone ?? null,
|
|
119
|
-
status: row.status ?? null,
|
|
120
|
-
lifecycleStage: row.lifecycle_stage ?? row.lifecycleStage ?? null,
|
|
121
|
-
source: row.source ?? null,
|
|
122
|
-
ownerUserId: row.owner_user_id ?? row.ownerUserId ?? null,
|
|
123
|
-
organizationId: row.organization_id ?? row.organizationId ?? null,
|
|
124
|
-
tenantId: row.tenant_id ?? row.tenantId ?? null,
|
|
125
|
-
domain: row.domain ?? null,
|
|
126
|
-
websiteUrl: row.website_url ?? row.websiteUrl ?? null,
|
|
127
|
-
industry: row.industry ?? null,
|
|
128
|
-
sizeBucket: row.size_bucket ?? row.sizeBucket ?? null,
|
|
129
|
-
createdAt,
|
|
130
|
-
}
|
|
131
|
-
}),
|
|
117
|
+
items: rawItems.map((row) => ({
|
|
118
|
+
...toCustomerListSummary(row),
|
|
119
|
+
domain: row.domain ?? null,
|
|
120
|
+
websiteUrl: row.website_url ?? row.websiteUrl ?? null,
|
|
121
|
+
industry: row.industry ?? null,
|
|
122
|
+
sizeBucket: row.size_bucket ?? row.sizeBucket ?? null,
|
|
123
|
+
})),
|
|
132
124
|
total: typeof data.total === 'number' ? data.total : 0,
|
|
133
125
|
limit,
|
|
134
126
|
offset,
|
|
@@ -146,13 +138,6 @@ const getCompanyInput = z.object({
|
|
|
146
138
|
|
|
147
139
|
type GetCompanyInput = z.infer<typeof getCompanyInput>
|
|
148
140
|
|
|
149
|
-
function toIsoCompany(value: unknown): string | null {
|
|
150
|
-
if (!value) return null
|
|
151
|
-
const dt = value instanceof Date ? value : new Date(String(value))
|
|
152
|
-
if (Number.isNaN(dt.getTime())) return null
|
|
153
|
-
return dt.toISOString()
|
|
154
|
-
}
|
|
155
|
-
|
|
156
141
|
const getCompanyTool: CustomersAiToolDefinition = {
|
|
157
142
|
name: 'customers.get_company',
|
|
158
143
|
displayName: 'Get company',
|
|
@@ -193,134 +178,9 @@ const getCompanyTool: CustomersAiToolDefinition = {
|
|
|
193
178
|
const profileRow = (data.profile ?? null) as Record<string, unknown> | null
|
|
194
179
|
const customFields = (data.customFields ?? {}) as Record<string, unknown>
|
|
195
180
|
|
|
196
|
-
let related:
|
|
181
|
+
let related: CustomerRelatedRecords | null = null
|
|
197
182
|
if (includeRelated) {
|
|
198
|
-
|
|
199
|
-
const activities = Array.isArray(data.activities) ? (data.activities as Array<Record<string, unknown>>) : []
|
|
200
|
-
const notes = Array.isArray(data.comments) ? (data.comments as Array<Record<string, unknown>>) : []
|
|
201
|
-
const todos = Array.isArray(data.todos) ? (data.todos as Array<Record<string, unknown>>) : []
|
|
202
|
-
const interactions = Array.isArray(data.interactions) ? (data.interactions as Array<Record<string, unknown>>) : []
|
|
203
|
-
const tagsRows = Array.isArray(data.tags) ? (data.tags as Array<Record<string, unknown>>) : []
|
|
204
|
-
const dealsRows = Array.isArray(data.deals) ? (data.deals as Array<Record<string, unknown>>) : []
|
|
205
|
-
const peopleRows = Array.isArray(data.people) ? (data.people as Array<Record<string, unknown>>) : []
|
|
206
|
-
related = {
|
|
207
|
-
addresses: addresses.map((address) => ({
|
|
208
|
-
id: address.id,
|
|
209
|
-
name: address.name ?? null,
|
|
210
|
-
purpose: address.purpose ?? null,
|
|
211
|
-
addressLine1: address.addressLine1 ?? null,
|
|
212
|
-
addressLine2: address.addressLine2 ?? null,
|
|
213
|
-
city: address.city ?? null,
|
|
214
|
-
region: address.region ?? null,
|
|
215
|
-
postalCode: address.postalCode ?? null,
|
|
216
|
-
country: address.country ?? null,
|
|
217
|
-
isPrimary: !!address.isPrimary,
|
|
218
|
-
})),
|
|
219
|
-
activities: activities.map((activity) => ({
|
|
220
|
-
id: activity.id,
|
|
221
|
-
activityType: activity.activityType,
|
|
222
|
-
subject: activity.subject ?? null,
|
|
223
|
-
body: activity.body ?? null,
|
|
224
|
-
occurredAt: toIsoCompany(activity.occurredAt),
|
|
225
|
-
createdAt: toIsoCompany(activity.createdAt),
|
|
226
|
-
})),
|
|
227
|
-
notes: notes.map((comment) => ({
|
|
228
|
-
id: comment.id,
|
|
229
|
-
body: comment.body,
|
|
230
|
-
authorUserId: comment.authorUserId ?? null,
|
|
231
|
-
createdAt: toIsoCompany(comment.createdAt),
|
|
232
|
-
})),
|
|
233
|
-
tasks: todos.map((task) => ({
|
|
234
|
-
id: task.id,
|
|
235
|
-
todoId: task.todoId ?? task.id,
|
|
236
|
-
todoSource: task.todoSource ?? null,
|
|
237
|
-
createdAt: toIsoCompany(task.createdAt),
|
|
238
|
-
})),
|
|
239
|
-
interactions: interactions.map((interaction) => ({
|
|
240
|
-
id: interaction.id,
|
|
241
|
-
interactionType: interaction.interactionType,
|
|
242
|
-
title: interaction.title ?? null,
|
|
243
|
-
status: interaction.status,
|
|
244
|
-
scheduledAt: toIsoCompany(interaction.scheduledAt),
|
|
245
|
-
occurredAt: toIsoCompany(interaction.occurredAt),
|
|
246
|
-
})),
|
|
247
|
-
tags: tagsRows
|
|
248
|
-
.map((tag) => {
|
|
249
|
-
if (!tag || typeof tag !== 'object') return null
|
|
250
|
-
const id = typeof tag.id === 'string' ? tag.id : null
|
|
251
|
-
const label = typeof tag.label === 'string' ? tag.label : null
|
|
252
|
-
if (!id || !label) return null
|
|
253
|
-
const slug = typeof tag.slug === 'string' ? tag.slug : label
|
|
254
|
-
const color = typeof tag.color === 'string' ? tag.color : null
|
|
255
|
-
return { id, slug, label, color }
|
|
256
|
-
})
|
|
257
|
-
.filter(
|
|
258
|
-
(entry): entry is { id: string; slug: string; label: string; color: string | null } =>
|
|
259
|
-
entry !== null,
|
|
260
|
-
),
|
|
261
|
-
deals: dealsRows
|
|
262
|
-
.map((deal) => {
|
|
263
|
-
if (!deal || typeof deal !== 'object') return null
|
|
264
|
-
const id = typeof deal.id === 'string' ? deal.id : null
|
|
265
|
-
if (!id) return null
|
|
266
|
-
return {
|
|
267
|
-
id,
|
|
268
|
-
title: typeof deal.title === 'string' ? deal.title : '',
|
|
269
|
-
status: typeof deal.status === 'string' ? deal.status : null,
|
|
270
|
-
pipelineStageId:
|
|
271
|
-
typeof deal.pipelineStageId === 'string' ? deal.pipelineStageId : null,
|
|
272
|
-
valueAmount:
|
|
273
|
-
typeof deal.valueAmount === 'string'
|
|
274
|
-
? deal.valueAmount
|
|
275
|
-
: deal.valueAmount === null || deal.valueAmount === undefined
|
|
276
|
-
? null
|
|
277
|
-
: String(deal.valueAmount),
|
|
278
|
-
valueCurrency:
|
|
279
|
-
typeof deal.valueCurrency === 'string' ? deal.valueCurrency : null,
|
|
280
|
-
}
|
|
281
|
-
})
|
|
282
|
-
.filter(
|
|
283
|
-
(
|
|
284
|
-
value,
|
|
285
|
-
): value is {
|
|
286
|
-
id: string
|
|
287
|
-
title: string
|
|
288
|
-
status: string | null
|
|
289
|
-
pipelineStageId: string | null
|
|
290
|
-
valueAmount: string | null
|
|
291
|
-
valueCurrency: string | null
|
|
292
|
-
} => value !== null,
|
|
293
|
-
),
|
|
294
|
-
people: peopleRows
|
|
295
|
-
.map((person) => {
|
|
296
|
-
if (!person || typeof person !== 'object') return null
|
|
297
|
-
const id = typeof person.id === 'string' ? person.id : null
|
|
298
|
-
const displayName = typeof person.displayName === 'string' ? person.displayName : null
|
|
299
|
-
if (!id || !displayName) return null
|
|
300
|
-
return {
|
|
301
|
-
id,
|
|
302
|
-
displayName,
|
|
303
|
-
primaryEmail:
|
|
304
|
-
typeof person.primaryEmail === 'string' ? person.primaryEmail : null,
|
|
305
|
-
primaryPhone:
|
|
306
|
-
typeof person.primaryPhone === 'string' ? person.primaryPhone : null,
|
|
307
|
-
jobTitle: typeof person.jobTitle === 'string' ? person.jobTitle : null,
|
|
308
|
-
department: typeof person.department === 'string' ? person.department : null,
|
|
309
|
-
}
|
|
310
|
-
})
|
|
311
|
-
.filter(
|
|
312
|
-
(
|
|
313
|
-
value,
|
|
314
|
-
): value is {
|
|
315
|
-
id: string
|
|
316
|
-
displayName: string
|
|
317
|
-
primaryEmail: string | null
|
|
318
|
-
primaryPhone: string | null
|
|
319
|
-
jobTitle: string | null
|
|
320
|
-
department: string | null
|
|
321
|
-
} => value !== null,
|
|
322
|
-
),
|
|
323
|
-
}
|
|
183
|
+
related = buildRelatedRecords(data, { includePeople: true })
|
|
324
184
|
}
|
|
325
185
|
return {
|
|
326
186
|
found: true as const,
|
|
@@ -336,8 +196,8 @@ const getCompanyTool: CustomersAiToolDefinition = {
|
|
|
336
196
|
ownerUserId: companyRow.ownerUserId ?? null,
|
|
337
197
|
organizationId: companyRow.organizationId ?? null,
|
|
338
198
|
tenantId: companyRow.tenantId ?? null,
|
|
339
|
-
createdAt:
|
|
340
|
-
updatedAt:
|
|
199
|
+
createdAt: toIso(companyRow.createdAt),
|
|
200
|
+
updatedAt: toIso(companyRow.updatedAt),
|
|
341
201
|
},
|
|
342
202
|
profile: profileRow
|
|
343
203
|
? {
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
* documented aggregate detail route). Tool name, schema, requiredFeatures,
|
|
18
18
|
* and output shape are unchanged.
|
|
19
19
|
*/
|
|
20
|
-
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
21
20
|
import { z } from 'zod'
|
|
22
21
|
import { defineApiBackedAiTool } from '@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool'
|
|
23
22
|
import {
|
|
@@ -30,20 +29,17 @@ import {
|
|
|
30
29
|
CustomerPersonProfile,
|
|
31
30
|
} from '../data/entities'
|
|
32
31
|
import { assertTenantScope, type CustomersAiToolDefinition, type CustomersToolContext } from './types'
|
|
32
|
+
import {
|
|
33
|
+
buildRelatedRecords,
|
|
34
|
+
buildScope,
|
|
35
|
+
resolveEm,
|
|
36
|
+
toCustomerListSummary,
|
|
37
|
+
toIso,
|
|
38
|
+
type CustomerRelatedRecords,
|
|
39
|
+
} from './_shared'
|
|
33
40
|
|
|
34
41
|
const NIL_UUID = '00000000-0000-0000-0000-000000000000'
|
|
35
42
|
|
|
36
|
-
function resolveEm(ctx: CustomersToolContext | AiToolExecutionContext): EntityManager {
|
|
37
|
-
return ctx.container.resolve<EntityManager>('em')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function buildScope(ctx: CustomersToolContext | AiToolExecutionContext, tenantId: string) {
|
|
41
|
-
return {
|
|
42
|
-
tenantId,
|
|
43
|
-
organizationId: ctx.organizationId,
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
43
|
const listPeopleInput = z
|
|
48
44
|
.object({
|
|
49
45
|
q: z.string().trim().optional().describe('Optional search text matched against display name / email / phone. Omit or leave empty to list all.'),
|
|
@@ -146,23 +142,7 @@ const listPeopleTool = defineApiBackedAiTool<ListPeopleInput, ListPeopleApiRespo
|
|
|
146
142
|
const data = (response.data ?? {}) as ListPeopleApiResponse
|
|
147
143
|
const rawItems: ListPeopleApiItem[] = Array.isArray(data.items) ? data.items : []
|
|
148
144
|
return {
|
|
149
|
-
items: rawItems.map((row) =>
|
|
150
|
-
const createdAtRaw = row.created_at ?? row.createdAt ?? null
|
|
151
|
-
const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null
|
|
152
|
-
return {
|
|
153
|
-
id: row.id,
|
|
154
|
-
displayName: row.display_name ?? row.displayName ?? null,
|
|
155
|
-
primaryEmail: row.primary_email ?? row.primaryEmail ?? null,
|
|
156
|
-
primaryPhone: row.primary_phone ?? row.primaryPhone ?? null,
|
|
157
|
-
status: row.status ?? null,
|
|
158
|
-
lifecycleStage: row.lifecycle_stage ?? row.lifecycleStage ?? null,
|
|
159
|
-
source: row.source ?? null,
|
|
160
|
-
ownerUserId: row.owner_user_id ?? row.ownerUserId ?? null,
|
|
161
|
-
organizationId: row.organization_id ?? row.organizationId ?? null,
|
|
162
|
-
tenantId: row.tenant_id ?? row.tenantId ?? null,
|
|
163
|
-
createdAt,
|
|
164
|
-
}
|
|
165
|
-
}),
|
|
145
|
+
items: rawItems.map((row) => toCustomerListSummary(row)),
|
|
166
146
|
total: typeof data.total === 'number' ? data.total : 0,
|
|
167
147
|
limit,
|
|
168
148
|
offset,
|
|
@@ -182,13 +162,6 @@ type GetPersonInput = z.infer<typeof getPersonInput>
|
|
|
182
162
|
|
|
183
163
|
type ApiPersonDetailRow = Record<string, unknown> | null | undefined
|
|
184
164
|
|
|
185
|
-
function toIso(value: unknown): string | null {
|
|
186
|
-
if (!value) return null
|
|
187
|
-
const dt = value instanceof Date ? value : new Date(String(value))
|
|
188
|
-
if (Number.isNaN(dt.getTime())) return null
|
|
189
|
-
return dt.toISOString()
|
|
190
|
-
}
|
|
191
|
-
|
|
192
165
|
const getPersonTool: CustomersAiToolDefinition = {
|
|
193
166
|
name: 'customers.get_person',
|
|
194
167
|
displayName: 'Get person',
|
|
@@ -226,104 +199,9 @@ const getPersonTool: CustomersAiToolDefinition = {
|
|
|
226
199
|
const profileRow = (data.profile ?? null) as ApiPersonDetailRow
|
|
227
200
|
const customFields = (data.customFields ?? {}) as Record<string, unknown>
|
|
228
201
|
|
|
229
|
-
let related:
|
|
202
|
+
let related: CustomerRelatedRecords | null = null
|
|
230
203
|
if (includeRelated) {
|
|
231
|
-
|
|
232
|
-
const activities = Array.isArray(data.activities) ? (data.activities as Array<Record<string, unknown>>) : []
|
|
233
|
-
const notes = Array.isArray(data.comments) ? (data.comments as Array<Record<string, unknown>>) : []
|
|
234
|
-
const todos = Array.isArray(data.todos) ? (data.todos as Array<Record<string, unknown>>) : []
|
|
235
|
-
const interactions = Array.isArray(data.interactions) ? (data.interactions as Array<Record<string, unknown>>) : []
|
|
236
|
-
const tagsRows = Array.isArray(data.tags) ? (data.tags as Array<Record<string, unknown>>) : []
|
|
237
|
-
const dealsRows = Array.isArray(data.deals) ? (data.deals as Array<Record<string, unknown>>) : []
|
|
238
|
-
related = {
|
|
239
|
-
addresses: addresses.map((address) => ({
|
|
240
|
-
id: address.id,
|
|
241
|
-
name: address.name ?? null,
|
|
242
|
-
purpose: address.purpose ?? null,
|
|
243
|
-
addressLine1: address.addressLine1 ?? null,
|
|
244
|
-
addressLine2: address.addressLine2 ?? null,
|
|
245
|
-
city: address.city ?? null,
|
|
246
|
-
region: address.region ?? null,
|
|
247
|
-
postalCode: address.postalCode ?? null,
|
|
248
|
-
country: address.country ?? null,
|
|
249
|
-
isPrimary: !!address.isPrimary,
|
|
250
|
-
})),
|
|
251
|
-
activities: activities.map((activity) => ({
|
|
252
|
-
id: activity.id,
|
|
253
|
-
activityType: activity.activityType,
|
|
254
|
-
subject: activity.subject ?? null,
|
|
255
|
-
body: activity.body ?? null,
|
|
256
|
-
occurredAt: toIso(activity.occurredAt),
|
|
257
|
-
createdAt: toIso(activity.createdAt),
|
|
258
|
-
})),
|
|
259
|
-
notes: notes.map((comment) => ({
|
|
260
|
-
id: comment.id,
|
|
261
|
-
body: comment.body,
|
|
262
|
-
authorUserId: comment.authorUserId ?? null,
|
|
263
|
-
createdAt: toIso(comment.createdAt),
|
|
264
|
-
})),
|
|
265
|
-
tasks: todos.map((task) => ({
|
|
266
|
-
id: task.id,
|
|
267
|
-
todoId: task.todoId ?? task.id,
|
|
268
|
-
todoSource: task.todoSource ?? null,
|
|
269
|
-
createdAt: toIso(task.createdAt),
|
|
270
|
-
})),
|
|
271
|
-
interactions: interactions.map((interaction) => ({
|
|
272
|
-
id: interaction.id,
|
|
273
|
-
interactionType: interaction.interactionType,
|
|
274
|
-
title: interaction.title ?? null,
|
|
275
|
-
status: interaction.status,
|
|
276
|
-
scheduledAt: toIso(interaction.scheduledAt),
|
|
277
|
-
occurredAt: toIso(interaction.occurredAt),
|
|
278
|
-
})),
|
|
279
|
-
tags: tagsRows
|
|
280
|
-
.map((tag) => {
|
|
281
|
-
if (!tag || typeof tag !== 'object') return null
|
|
282
|
-
const id = typeof tag.id === 'string' ? tag.id : null
|
|
283
|
-
const label = typeof tag.label === 'string' ? tag.label : null
|
|
284
|
-
if (!id || !label) return null
|
|
285
|
-
const slug = typeof tag.slug === 'string' ? tag.slug : label
|
|
286
|
-
const color = typeof tag.color === 'string' ? tag.color : null
|
|
287
|
-
return { id, slug, label, color }
|
|
288
|
-
})
|
|
289
|
-
.filter(
|
|
290
|
-
(entry): entry is { id: string; slug: string; label: string; color: string | null } =>
|
|
291
|
-
entry !== null,
|
|
292
|
-
),
|
|
293
|
-
deals: dealsRows
|
|
294
|
-
.map((deal) => {
|
|
295
|
-
if (!deal || typeof deal !== 'object') return null
|
|
296
|
-
const id = typeof deal.id === 'string' ? deal.id : null
|
|
297
|
-
if (!id) return null
|
|
298
|
-
return {
|
|
299
|
-
id,
|
|
300
|
-
title: typeof deal.title === 'string' ? deal.title : '',
|
|
301
|
-
status: typeof deal.status === 'string' ? deal.status : null,
|
|
302
|
-
pipelineStageId:
|
|
303
|
-
typeof deal.pipelineStageId === 'string' ? deal.pipelineStageId : null,
|
|
304
|
-
valueAmount:
|
|
305
|
-
typeof deal.valueAmount === 'string'
|
|
306
|
-
? deal.valueAmount
|
|
307
|
-
: deal.valueAmount === null || deal.valueAmount === undefined
|
|
308
|
-
? null
|
|
309
|
-
: String(deal.valueAmount),
|
|
310
|
-
valueCurrency:
|
|
311
|
-
typeof deal.valueCurrency === 'string' ? deal.valueCurrency : null,
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
.filter(
|
|
315
|
-
(
|
|
316
|
-
value,
|
|
317
|
-
): value is {
|
|
318
|
-
id: string
|
|
319
|
-
title: string
|
|
320
|
-
status: string | null
|
|
321
|
-
pipelineStageId: string | null
|
|
322
|
-
valueAmount: string | null
|
|
323
|
-
valueCurrency: string | null
|
|
324
|
-
} => value !== null,
|
|
325
|
-
),
|
|
326
|
-
}
|
|
204
|
+
related = buildRelatedRecords(data)
|
|
327
205
|
}
|
|
328
206
|
|
|
329
207
|
return {
|
|
@@ -499,6 +499,7 @@ export function CalendarScreen() {
|
|
|
499
499
|
showWeekends={preferences.showWeekends}
|
|
500
500
|
showConflicts={preferences.conflictWarnings}
|
|
501
501
|
aiSummaries={preferences.aiSummaries}
|
|
502
|
+
canManage={canManage}
|
|
502
503
|
highlightItemId={highlightItemId}
|
|
503
504
|
onItemClick={openEditEditor}
|
|
504
505
|
onJoin={handleJoin}
|
|
@@ -5,6 +5,7 @@ import { Sparkles } from 'lucide-react'
|
|
|
5
5
|
import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
6
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
7
7
|
import { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'
|
|
8
|
+
import { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'
|
|
8
9
|
import { formatTimeRange } from './EventBlock'
|
|
9
10
|
import type { CalendarItem, CalendarPlatform } from './types'
|
|
10
11
|
|
|
@@ -20,6 +21,7 @@ export type EventPeekPopoverProps = {
|
|
|
20
21
|
open: boolean
|
|
21
22
|
joinUrl: string | null
|
|
22
23
|
aiSummaries: boolean
|
|
24
|
+
canManage?: boolean
|
|
23
25
|
onOpenChange(open: boolean): void
|
|
24
26
|
onJoin(item: CalendarItem): void
|
|
25
27
|
onEdit(item: CalendarItem): void
|
|
@@ -31,6 +33,7 @@ export function EventPeekPopover({
|
|
|
31
33
|
open,
|
|
32
34
|
joinUrl,
|
|
33
35
|
aiSummaries,
|
|
36
|
+
canManage = true,
|
|
34
37
|
onOpenChange,
|
|
35
38
|
onJoin,
|
|
36
39
|
onEdit,
|
|
@@ -81,17 +84,32 @@ export function EventPeekPopover({
|
|
|
81
84
|
{t('customers.calendar.peek.join', 'Join')}
|
|
82
85
|
</Button>
|
|
83
86
|
) : null}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
{canManage ? (
|
|
88
|
+
<Button
|
|
89
|
+
type="button"
|
|
90
|
+
size="sm"
|
|
91
|
+
variant="secondary"
|
|
92
|
+
onClick={() => {
|
|
93
|
+
onOpenChange(false)
|
|
94
|
+
onEdit(item)
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{t('customers.calendar.peek.edit', 'Edit')}
|
|
98
|
+
</Button>
|
|
99
|
+
) : (
|
|
100
|
+
<SimpleTooltip
|
|
101
|
+
content={t(
|
|
102
|
+
'customers.calendar.peek.editForbidden',
|
|
103
|
+
"You don't have permission to edit events",
|
|
104
|
+
)}
|
|
105
|
+
>
|
|
106
|
+
<span className="inline-flex">
|
|
107
|
+
<Button type="button" size="sm" variant="secondary" disabled className="pointer-events-none">
|
|
108
|
+
{t('customers.calendar.peek.edit', 'Edit')}
|
|
109
|
+
</Button>
|
|
110
|
+
</span>
|
|
111
|
+
</SimpleTooltip>
|
|
112
|
+
)}
|
|
95
113
|
</div>
|
|
96
114
|
</div>
|
|
97
115
|
</PopoverContent>
|
|
@@ -160,6 +160,7 @@ export function TimeGrid({
|
|
|
160
160
|
showWeekends,
|
|
161
161
|
showConflicts,
|
|
162
162
|
aiSummaries,
|
|
163
|
+
canManage = true,
|
|
163
164
|
highlightItemId,
|
|
164
165
|
onItemClick,
|
|
165
166
|
onJoin,
|
|
@@ -351,6 +352,7 @@ export function TimeGrid({
|
|
|
351
352
|
open={selectedId === item.id}
|
|
352
353
|
joinUrl={resolveJoinUrl(item.location)}
|
|
353
354
|
aiSummaries={aiSummaries}
|
|
355
|
+
canManage={canManage}
|
|
354
356
|
onOpenChange={(open) => setSelectedId(open ? item.id : null)}
|
|
355
357
|
onJoin={onJoin}
|
|
356
358
|
onEdit={onItemClick}
|
|
@@ -462,6 +464,7 @@ export function TimeGrid({
|
|
|
462
464
|
open={selectedId === block.item.id}
|
|
463
465
|
joinUrl={resolveJoinUrl(block.item.location)}
|
|
464
466
|
aiSummaries={aiSummaries}
|
|
467
|
+
canManage={canManage}
|
|
465
468
|
onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}
|
|
466
469
|
onJoin={onJoin}
|
|
467
470
|
onEdit={onItemClick}
|