@open-mercato/core 0.4.11-develop.1299.78ca9c88e2 → 0.4.11-develop.1347.c693e6dfee

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 (60) hide show
  1. package/dist/modules/customers/api/companies/[id]/route.js +3 -2
  2. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  3. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +59 -91
  4. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
  5. package/dist/modules/customers/api/interactions/tasks/route.js +115 -0
  6. package/dist/modules/customers/api/interactions/tasks/route.js.map +7 -0
  7. package/dist/modules/customers/api/people/[id]/route.js +3 -2
  8. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  9. package/dist/modules/customers/api/todos/route.js +14 -134
  10. package/dist/modules/customers/api/todos/route.js.map +2 -2
  11. package/dist/modules/customers/backend/customer-tasks/page.js +10 -0
  12. package/dist/modules/customers/backend/customer-tasks/page.js.map +7 -0
  13. package/dist/modules/customers/backend/customer-tasks/page.meta.js +25 -0
  14. package/dist/modules/customers/backend/customer-tasks/page.meta.js.map +7 -0
  15. package/dist/modules/customers/commands/interactions.js +40 -4
  16. package/dist/modules/customers/commands/interactions.js.map +2 -2
  17. package/dist/modules/customers/components/CustomerTodosTable.js +77 -47
  18. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  19. package/dist/modules/customers/components/detail/TasksSection.js +4 -4
  20. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  21. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +2 -1
  22. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  23. package/dist/modules/customers/components/detail/utils.js +3 -0
  24. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  25. package/dist/modules/customers/data/entities.js +2 -2
  26. package/dist/modules/customers/data/entities.js.map +2 -2
  27. package/dist/modules/customers/data/validators.js +2 -2
  28. package/dist/modules/customers/data/validators.js.map +2 -2
  29. package/dist/modules/customers/lib/interactionCompatibility.js +12 -2
  30. package/dist/modules/customers/lib/interactionCompatibility.js.map +2 -2
  31. package/dist/modules/customers/lib/todoCompatibility.js +167 -4
  32. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  33. package/dist/modules/customers/migrations/Migration20260401172819.js +45 -0
  34. package/dist/modules/customers/migrations/Migration20260401172819.js.map +7 -0
  35. package/dist/modules/customers/search.js +3 -2
  36. package/dist/modules/customers/search.js.map +2 -2
  37. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +10 -2
  38. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +2 -2
  39. package/package.json +3 -3
  40. package/src/modules/customers/api/companies/[id]/route.ts +6 -5
  41. package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +69 -126
  42. package/src/modules/customers/api/interactions/tasks/route.ts +122 -0
  43. package/src/modules/customers/api/people/[id]/route.ts +3 -2
  44. package/src/modules/customers/api/todos/route.ts +13 -181
  45. package/src/modules/customers/backend/customer-tasks/page.meta.ts +23 -0
  46. package/src/modules/customers/backend/customer-tasks/page.tsx +12 -0
  47. package/src/modules/customers/commands/interactions.ts +50 -2
  48. package/src/modules/customers/components/CustomerTodosTable.tsx +91 -66
  49. package/src/modules/customers/components/detail/TasksSection.tsx +8 -8
  50. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +2 -1
  51. package/src/modules/customers/components/detail/types.ts +6 -0
  52. package/src/modules/customers/components/detail/utils.ts +3 -0
  53. package/src/modules/customers/data/entities.ts +2 -2
  54. package/src/modules/customers/data/validators.ts +2 -2
  55. package/src/modules/customers/lib/interactionCompatibility.ts +16 -0
  56. package/src/modules/customers/lib/todoCompatibility.ts +229 -10
  57. package/src/modules/customers/migrations/.snapshot-open-mercato.json +1 -1
  58. package/src/modules/customers/migrations/Migration20260401172819.ts +45 -0
  59. package/src/modules/customers/search.ts +3 -2
  60. package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +24 -23
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/commands/interactions.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n normalizeAuthorUserId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { DefaultDataEngine, type DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CustomerInteraction } from '../data/entities'\nimport {\n interactionCreateSchema,\n interactionUpdateSchema,\n interactionCompleteSchema,\n interactionCancelSchema,\n type InteractionCreateInput,\n type InteractionUpdateInput,\n type InteractionCompleteInput,\n type InteractionCancelInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n requireCustomerEntity,\n extractUndoPayload,\n requireDealInScope,\n resolveParentResourceKind,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { recomputeNextInteraction } from '../lib/interactionProjection'\n\nconst INTERACTION_ENTITY_ID = 'customers:customer_interaction'\nconst interactionCrudIndexer: CrudIndexerConfig<CustomerInteraction> = {\n entityType: 'customers:customer_interaction' as const,\n}\n\nconst interactionCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'interaction',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype InteractionSnapshot = {\n interaction: {\n id: string\n organizationId: string\n tenantId: string\n entityId: string\n entityKind: string | null\n dealId: string | null\n interactionType: string\n title: string | null\n body: string | null\n status: string\n scheduledAt: Date | null\n occurredAt: Date | null\n priority: number | null\n authorUserId: string | null\n ownerUserId: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n source: string | null\n }\n custom?: Record<string, unknown>\n}\n\ntype InteractionUndoPayload = {\n before?: InteractionSnapshot | null\n after?: InteractionSnapshot | null\n}\n\nasync function loadInteractionSnapshot(em: EntityManager, id: string): Promise<InteractionSnapshot | null> {\n const interaction = await em.findOne(CustomerInteraction, { id }, { populate: ['entity'] })\n if (!interaction) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n tenantId: interaction.tenantId,\n organizationId: interaction.organizationId,\n })\n const entityRef = interaction.entity\n const entityKind = (typeof entityRef === 'object' && entityRef !== null && 'kind' in entityRef)\n ? (entityRef as { kind: string }).kind\n : null\n return {\n interaction: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n entityId: typeof entityRef === 'string' ? entityRef : entityRef.id,\n entityKind,\n dealId: interaction.dealId ?? null,\n interactionType: interaction.interactionType,\n title: interaction.title ?? null,\n body: interaction.body ?? null,\n status: interaction.status,\n scheduledAt: interaction.scheduledAt ?? null,\n occurredAt: interaction.occurredAt ?? null,\n priority: interaction.priority ?? null,\n authorUserId: interaction.authorUserId ?? null,\n ownerUserId: interaction.ownerUserId ?? null,\n appearanceIcon: interaction.appearanceIcon ?? null,\n appearanceColor: interaction.appearanceColor ?? null,\n source: interaction.source ?? null,\n },\n custom,\n }\n}\n\nasync function setInteractionCustomFields(\n dataEngine: DataEngine,\n interactionId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>\n) {\n if (!values || !Object.keys(values).length) return\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: INTERACTION_ENTITY_ID,\n recordId: interactionId,\n organizationId,\n tenantId,\n values,\n notify: false,\n })\n}\n\nasync function emitLifecycleEvent(\n ctx: CommandRuntimeContext,\n eventId: string,\n payload: Record<string, unknown>\n): Promise<void> {\n let bus: { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> } | null = null\n try {\n bus = ctx.container.resolve('eventBus')\n } catch {\n bus = null\n }\n if (!bus) return\n await bus\n .emitEvent(eventId, payload, { persistent: true })\n .catch(() => undefined)\n}\n\nasync function emitInteractionRevertedEvent(\n ctx: CommandRuntimeContext,\n interaction: InteractionSnapshot['interaction'],\n): Promise<void> {\n await emitLifecycleEvent(ctx, 'customers.interaction.reverted', {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n status: interaction.status,\n occurredAt: interaction.occurredAt?.toISOString() ?? null,\n })\n}\n\ntype InteractionIdentifiers = {\n id: string\n organizationId: string\n tenantId: string\n}\n\ntype InteractionProjectionMutation = {\n entityId: string\n nextInteractionId: string | null\n}\n\nfunction createTransactionalDataEngine(ctx: CommandRuntimeContext, em: EntityManager): DataEngine {\n const emWithConnection = em as EntityManager & { getConnection?: () => unknown }\n if (typeof emWithConnection.getConnection !== 'function') {\n return ctx.container.resolve('dataEngine') as DataEngine\n }\n return new DefaultDataEngine(em, ctx.container)\n}\n\nasync function runInTransaction<TResult>(\n em: EntityManager,\n operation: (trx: EntityManager) => Promise<TResult>,\n): Promise<TResult> {\n const transactionalEm = em as EntityManager & {\n transactional?: (callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n if (typeof transactionalEm.transactional === 'function') {\n return transactionalEm.transactional((trx) => operation(trx))\n }\n return operation(em)\n}\n\nasync function emitNextInteractionUpdatedEvent(\n ctx: CommandRuntimeContext,\n projection: InteractionProjectionMutation,\n identifiers: InteractionIdentifiers,\n): Promise<void> {\n await emitLifecycleEvent(ctx, 'customers.next_interaction.updated', {\n id: projection.entityId,\n entityId: projection.entityId,\n nextInteractionId: projection.nextInteractionId,\n organizationId: identifiers.organizationId,\n tenantId: identifiers.tenantId,\n })\n}\n\n// \u2500\u2500\u2500 Create \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst createInteractionCommand: CommandHandler<InteractionCreateInput, { interactionId: string; entityId: string }> = {\n id: 'customers.interactions.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(interactionCreateSchema, rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedAuthor = normalizeAuthorUserId(parsed.authorUserId ?? null, ctx.auth)\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const entity = await requireCustomerEntity(trx, parsed.entityId, undefined, 'Customer not found')\n ensureTenantScope(ctx, entity.tenantId)\n ensureOrganizationScope(ctx, entity.organizationId)\n\n if (parsed.dealId) {\n await requireDealInScope(trx, parsed.dealId, entity.tenantId, entity.organizationId)\n }\n\n const interaction = trx.create(CustomerInteraction, {\n ...(parsed.id ? { id: parsed.id } : {}),\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n interactionType: parsed.interactionType,\n title: parsed.title ?? null,\n body: parsed.body ?? null,\n status: parsed.status ?? 'planned',\n scheduledAt: parsed.scheduledAt ?? null,\n occurredAt: parsed.occurredAt ?? null,\n priority: parsed.priority ?? null,\n authorUserId: normalizedAuthor,\n ownerUserId: parsed.ownerUserId ?? null,\n dealId: parsed.dealId ?? null,\n source: parsed.source ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n await trx.flush()\n\n await setInteractionCustomFields(\n createTransactionalDataEngine(ctx, trx),\n interaction.id,\n entity.organizationId,\n entity.tenantId,\n custom,\n )\n\n return {\n interaction,\n entityId: entity.id,\n }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n\n return { interactionId: interaction.id, entityId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.create', 'Create interaction'),\n resourceKind: 'customers.interaction',\n resourceId: result.interactionId,\n parentResourceKind: resolveParentResourceKind(snapshot?.interaction?.entityKind),\n parentResourceId: snapshot?.interaction?.entityId ?? null,\n tenantId: snapshot?.interaction.tenantId ?? null,\n organizationId: snapshot?.interaction.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const interactionId = logEntry?.resourceId\n if (!interactionId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const record = await trx.findOne(CustomerInteraction, { id: interactionId })\n if (!record) return null\n const entityId = typeof record.entity === 'string' ? record.entity : record.entity.id\n trx.remove(record)\n await trx.flush()\n return {\n entityId,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }\n })\n if (!result) return\n const projection = await recomputeNextInteraction(em, result.entityId)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: result.entityId,\n nextInteractionId: projection.nextInteractionId,\n }, result.identifiers)\n },\n}\n\n// \u2500\u2500\u2500 Update \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interactionId: string }> = {\n id: 'customers.interactions.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(interactionUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(interactionUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n if (parsed.dealId !== undefined) {\n if (parsed.dealId) {\n await requireDealInScope(trx, parsed.dealId, interaction.tenantId, interaction.organizationId)\n }\n interaction.dealId = parsed.dealId ?? null\n }\n if (parsed.interactionType !== undefined) interaction.interactionType = parsed.interactionType\n if (parsed.title !== undefined) interaction.title = parsed.title ?? null\n if (parsed.body !== undefined) interaction.body = parsed.body ?? null\n if (parsed.status !== undefined) interaction.status = parsed.status\n if (parsed.scheduledAt !== undefined) interaction.scheduledAt = parsed.scheduledAt ?? null\n if (parsed.occurredAt !== undefined) interaction.occurredAt = parsed.occurredAt ?? null\n if (parsed.priority !== undefined) interaction.priority = parsed.priority ?? null\n if (parsed.authorUserId !== undefined) interaction.authorUserId = parsed.authorUserId ?? null\n if (parsed.ownerUserId !== undefined) interaction.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.appearanceIcon !== undefined) interaction.appearanceIcon = parsed.appearanceIcon ?? null\n if (parsed.appearanceColor !== undefined) interaction.appearanceColor = parsed.appearanceColor ?? null\n\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n await setInteractionCustomFields(\n createTransactionalDataEngine(ctx, trx),\n interaction.id,\n interaction.organizationId,\n interaction.tenantId,\n custom,\n )\n\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.update', 'Update interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {\n let interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n const entity = await requireCustomerEntity(trx, before.interaction.entityId, undefined, 'Customer not found')\n\n if (!interaction) {\n interaction = trx.create(CustomerInteraction, {\n id: before.interaction.id,\n organizationId: before.interaction.organizationId,\n tenantId: before.interaction.tenantId,\n entity,\n interactionType: before.interaction.interactionType,\n title: before.interaction.title,\n body: before.interaction.body,\n status: before.interaction.status,\n scheduledAt: before.interaction.scheduledAt,\n occurredAt: before.interaction.occurredAt,\n priority: before.interaction.priority,\n authorUserId: before.interaction.authorUserId,\n ownerUserId: before.interaction.ownerUserId,\n dealId: before.interaction.dealId,\n source: before.interaction.source,\n appearanceIcon: before.interaction.appearanceIcon,\n appearanceColor: before.interaction.appearanceColor,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n } else {\n interaction.entity = entity\n interaction.interactionType = before.interaction.interactionType\n interaction.title = before.interaction.title\n interaction.body = before.interaction.body\n interaction.status = before.interaction.status\n interaction.scheduledAt = before.interaction.scheduledAt\n interaction.occurredAt = before.interaction.occurredAt\n interaction.priority = before.interaction.priority\n interaction.authorUserId = before.interaction.authorUserId\n interaction.ownerUserId = before.interaction.ownerUserId\n interaction.dealId = before.interaction.dealId\n interaction.source = before.interaction.source\n interaction.appearanceIcon = before.interaction.appearanceIcon\n interaction.appearanceColor = before.interaction.appearanceColor\n }\n\n await trx.flush()\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: createTransactionalDataEngine(ctx, trx),\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId,\n }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Complete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst completeInteractionCommand: CommandHandler<InteractionCompleteInput, { interactionId: string }> = {\n id: 'customers.interactions.complete',\n async prepare(rawInput, ctx) {\n const parsed = interactionCompleteSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = interactionCompleteSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n interaction.status = 'done'\n interaction.occurredAt = parsed.occurredAt ?? new Date()\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const identifiers = {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitLifecycleEvent(ctx, 'customers.interaction.completed', identifiers)\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, identifiers)\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.complete', 'Complete interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) return null\n\n interaction.status = before.interaction.status\n interaction.occurredAt = before.interaction.occurredAt\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n if (!result) return\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: result.interaction,\n identifiers: {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitInteractionRevertedEvent(ctx, before.interaction)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId: result.nextInteractionId,\n }, {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Cancel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst cancelInteractionCommand: CommandHandler<InteractionCancelInput, { interactionId: string }> = {\n id: 'customers.interactions.cancel',\n async prepare(rawInput, ctx) {\n const parsed = interactionCancelSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = interactionCancelSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n interaction.status = 'canceled'\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const identifiers = {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitLifecycleEvent(ctx, 'customers.interaction.canceled', identifiers)\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, identifiers)\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.cancel', 'Cancel interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) return null\n\n interaction.status = before.interaction.status\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n if (!result) return\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: result.interaction,\n identifiers: {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitInteractionRevertedEvent(ctx, before.interaction)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId: result.nextInteractionId,\n }, {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Delete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst deleteInteractionCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { interactionId: string }> =\n {\n id: 'customers.interactions.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Interaction id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Interaction id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n interaction.deletedAt = new Date()\n await trx.flush()\n\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n return { interactionId: interaction.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.interactions.delete', 'Delete interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {\n const entity = await requireCustomerEntity(trx, before.interaction.entityId, undefined, 'Customer not found')\n let interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) {\n interaction = trx.create(CustomerInteraction, {\n id: before.interaction.id,\n organizationId: before.interaction.organizationId,\n tenantId: before.interaction.tenantId,\n entity,\n interactionType: before.interaction.interactionType,\n title: before.interaction.title,\n body: before.interaction.body,\n status: before.interaction.status,\n scheduledAt: before.interaction.scheduledAt,\n occurredAt: before.interaction.occurredAt,\n priority: before.interaction.priority,\n authorUserId: before.interaction.authorUserId,\n ownerUserId: before.interaction.ownerUserId,\n dealId: before.interaction.dealId,\n source: before.interaction.source,\n appearanceIcon: before.interaction.appearanceIcon,\n appearanceColor: before.interaction.appearanceColor,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n } else {\n interaction.deletedAt = null\n interaction.entity = entity\n interaction.interactionType = before.interaction.interactionType\n interaction.title = before.interaction.title\n interaction.body = before.interaction.body\n interaction.status = before.interaction.status\n interaction.scheduledAt = before.interaction.scheduledAt\n interaction.occurredAt = before.interaction.occurredAt\n interaction.priority = before.interaction.priority\n interaction.authorUserId = before.interaction.authorUserId\n interaction.ownerUserId = before.interaction.ownerUserId\n interaction.dealId = before.interaction.dealId\n interaction.source = before.interaction.source\n interaction.appearanceIcon = before.interaction.appearanceIcon\n interaction.appearanceColor = before.interaction.appearanceColor\n }\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: createTransactionalDataEngine(ctx, trx),\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId,\n }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n },\n }\n\n// \u2500\u2500\u2500 Recompute Next (internal repair) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst recomputeNextSchema = z.object({ entityId: z.string().min(1) })\n\nconst recomputeNextCommand: CommandHandler<{ entityId: string }, { entityId: string }> = {\n id: 'customers.interaction.recompute_next',\n async execute(rawInput, ctx) {\n const parsed = recomputeNextSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const projection = await recomputeNextInteraction(em, parsed.entityId)\n const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: parsed.entityId,\n nextInteractionId: projection.nextInteractionId,\n }, {\n id: parsed.entityId,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n })\n return { entityId: parsed.entityId }\n },\n}\n\nregisterCommand(createInteractionCommand)\nregisterCommand(updateInteractionCommand)\nregisterCommand(completeInteractionCommand)\nregisterCommand(cancelInteractionCommand)\nregisterCommand(deleteInteractionCommand)\nregisterCommand(recomputeNextCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n normalizeAuthorUserId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { DefaultDataEngine, type DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CustomerInteraction } from '../data/entities'\nimport {\n interactionCreateSchema,\n interactionUpdateSchema,\n interactionCompleteSchema,\n interactionCancelSchema,\n type InteractionCreateInput,\n type InteractionUpdateInput,\n type InteractionCompleteInput,\n type InteractionCancelInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n requireCustomerEntity,\n extractUndoPayload,\n requireDealInScope,\n resolveParentResourceKind,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { recomputeNextInteraction } from '../lib/interactionProjection'\n\nconst INTERACTION_ENTITY_ID = 'customers:customer_interaction'\nconst interactionCrudIndexer: CrudIndexerConfig<CustomerInteraction> = {\n entityType: 'customers:customer_interaction' as const,\n}\n\nconst interactionCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'interaction',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n entityId:\n ctx.entity && typeof ctx.entity === 'object' && 'entity' in (ctx.entity as Record<string, unknown>)\n ? (() => {\n const entityRef = (ctx.entity as CustomerInteraction).entity\n return typeof entityRef === 'string' ? entityRef : entityRef?.id ?? null\n })()\n : null,\n interactionType:\n ctx.entity && typeof ctx.entity === 'object' && 'interactionType' in (ctx.entity as Record<string, unknown>)\n ? (ctx.entity as CustomerInteraction).interactionType\n : null,\n status:\n ctx.entity && typeof ctx.entity === 'object' && 'status' in (ctx.entity as Record<string, unknown>)\n ? (ctx.entity as CustomerInteraction).status\n : null,\n source:\n ctx.entity && typeof ctx.entity === 'object' && 'source' in (ctx.entity as Record<string, unknown>)\n ? (ctx.entity as CustomerInteraction).source ?? null\n : null,\n ...(ctx.syncOrigin ? { syncOrigin: ctx.syncOrigin } : {}),\n }),\n}\n\ntype InteractionSnapshot = {\n interaction: {\n id: string\n organizationId: string\n tenantId: string\n entityId: string\n entityKind: string | null\n dealId: string | null\n interactionType: string\n title: string | null\n body: string | null\n status: string\n scheduledAt: Date | null\n occurredAt: Date | null\n priority: number | null\n authorUserId: string | null\n ownerUserId: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n source: string | null\n }\n custom?: Record<string, unknown>\n}\n\ntype InteractionUndoPayload = {\n before?: InteractionSnapshot | null\n after?: InteractionSnapshot | null\n}\n\nasync function loadInteractionSnapshot(em: EntityManager, id: string): Promise<InteractionSnapshot | null> {\n const interaction = await em.findOne(CustomerInteraction, { id }, { populate: ['entity'] })\n if (!interaction) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n tenantId: interaction.tenantId,\n organizationId: interaction.organizationId,\n })\n const entityRef = interaction.entity\n const entityKind = (typeof entityRef === 'object' && entityRef !== null && 'kind' in entityRef)\n ? (entityRef as { kind: string }).kind\n : null\n return {\n interaction: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n entityId: typeof entityRef === 'string' ? entityRef : entityRef.id,\n entityKind,\n dealId: interaction.dealId ?? null,\n interactionType: interaction.interactionType,\n title: interaction.title ?? null,\n body: interaction.body ?? null,\n status: interaction.status,\n scheduledAt: interaction.scheduledAt ?? null,\n occurredAt: interaction.occurredAt ?? null,\n priority: interaction.priority ?? null,\n authorUserId: interaction.authorUserId ?? null,\n ownerUserId: interaction.ownerUserId ?? null,\n appearanceIcon: interaction.appearanceIcon ?? null,\n appearanceColor: interaction.appearanceColor ?? null,\n source: interaction.source ?? null,\n },\n custom,\n }\n}\n\nasync function setInteractionCustomFields(\n dataEngine: DataEngine,\n interactionId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>\n) {\n if (!values || !Object.keys(values).length) return\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: INTERACTION_ENTITY_ID,\n recordId: interactionId,\n organizationId,\n tenantId,\n values,\n notify: false,\n })\n}\n\nasync function emitLifecycleEvent(\n ctx: CommandRuntimeContext,\n eventId: string,\n payload: Record<string, unknown>\n): Promise<void> {\n let bus: { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> } | null = null\n try {\n bus = ctx.container.resolve('eventBus')\n } catch {\n bus = null\n }\n if (!bus) return\n await bus\n .emitEvent(eventId, payload, { persistent: true })\n .catch(() => undefined)\n}\n\nasync function emitInteractionRevertedEvent(\n ctx: CommandRuntimeContext,\n interaction: InteractionSnapshot['interaction'],\n): Promise<void> {\n await emitLifecycleEvent(ctx, 'customers.interaction.reverted', {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n entityId: interaction.entityId,\n interactionType: interaction.interactionType,\n source: interaction.source ?? null,\n status: interaction.status,\n occurredAt: interaction.occurredAt?.toISOString() ?? null,\n ...(ctx.syncOrigin ? { syncOrigin: ctx.syncOrigin } : {}),\n })\n}\n\ntype InteractionIdentifiers = {\n id: string\n organizationId: string\n tenantId: string\n}\n\ntype InteractionProjectionMutation = {\n entityId: string\n nextInteractionId: string | null\n}\n\nfunction createTransactionalDataEngine(ctx: CommandRuntimeContext, em: EntityManager): DataEngine {\n const emWithConnection = em as EntityManager & { getConnection?: () => unknown }\n if (typeof emWithConnection.getConnection !== 'function') {\n return ctx.container.resolve('dataEngine') as DataEngine\n }\n return new DefaultDataEngine(em, ctx.container)\n}\n\nasync function runInTransaction<TResult>(\n em: EntityManager,\n operation: (trx: EntityManager) => Promise<TResult>,\n): Promise<TResult> {\n const transactionalEm = em as EntityManager & {\n transactional?: (callback: (trx: EntityManager) => Promise<TResult>) => Promise<TResult>\n }\n if (typeof transactionalEm.transactional === 'function') {\n return transactionalEm.transactional((trx) => operation(trx))\n }\n return operation(em)\n}\n\nasync function emitNextInteractionUpdatedEvent(\n ctx: CommandRuntimeContext,\n projection: InteractionProjectionMutation,\n identifiers: InteractionIdentifiers,\n): Promise<void> {\n await emitLifecycleEvent(ctx, 'customers.next_interaction.updated', {\n id: projection.entityId,\n entityId: projection.entityId,\n nextInteractionId: projection.nextInteractionId,\n organizationId: identifiers.organizationId,\n tenantId: identifiers.tenantId,\n })\n}\n\n// \u2500\u2500\u2500 Create \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst createInteractionCommand: CommandHandler<InteractionCreateInput, { interactionId: string; entityId: string }> = {\n id: 'customers.interactions.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(interactionCreateSchema, rawInput)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedAuthor = normalizeAuthorUserId(parsed.authorUserId ?? null, ctx.auth)\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const entity = await requireCustomerEntity(trx, parsed.entityId, undefined, 'Customer not found')\n ensureTenantScope(ctx, entity.tenantId)\n ensureOrganizationScope(ctx, entity.organizationId)\n\n if (parsed.dealId) {\n await requireDealInScope(trx, parsed.dealId, entity.tenantId, entity.organizationId)\n }\n\n const interaction = trx.create(CustomerInteraction, {\n ...(parsed.id ? { id: parsed.id } : {}),\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n interactionType: parsed.interactionType,\n title: parsed.title ?? null,\n body: parsed.body ?? null,\n status: parsed.status ?? 'planned',\n scheduledAt: parsed.scheduledAt ?? null,\n occurredAt: parsed.occurredAt ?? null,\n priority: parsed.priority ?? null,\n authorUserId: normalizedAuthor,\n ownerUserId: parsed.ownerUserId ?? null,\n dealId: parsed.dealId ?? null,\n source: parsed.source ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n await trx.flush()\n\n await setInteractionCustomFields(\n createTransactionalDataEngine(ctx, trx),\n interaction.id,\n entity.organizationId,\n entity.tenantId,\n custom,\n )\n\n return {\n interaction,\n entityId: entity.id,\n }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n\n return { interactionId: interaction.id, entityId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.create', 'Create interaction'),\n resourceKind: 'customers.interaction',\n resourceId: result.interactionId,\n parentResourceKind: resolveParentResourceKind(snapshot?.interaction?.entityKind),\n parentResourceId: snapshot?.interaction?.entityId ?? null,\n tenantId: snapshot?.interaction.tenantId ?? null,\n organizationId: snapshot?.interaction.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const interactionId = logEntry?.resourceId\n if (!interactionId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const record = await trx.findOne(CustomerInteraction, { id: interactionId })\n if (!record) return null\n const entityId = typeof record.entity === 'string' ? record.entity : record.entity.id\n trx.remove(record)\n await trx.flush()\n return {\n entityId,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }\n })\n if (!result) return\n const projection = await recomputeNextInteraction(em, result.entityId)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: result.entityId,\n nextInteractionId: projection.nextInteractionId,\n }, result.identifiers)\n },\n}\n\n// \u2500\u2500\u2500 Update \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interactionId: string }> = {\n id: 'customers.interactions.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(interactionUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(interactionUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n if (parsed.dealId !== undefined) {\n if (parsed.dealId) {\n await requireDealInScope(trx, parsed.dealId, interaction.tenantId, interaction.organizationId)\n }\n interaction.dealId = parsed.dealId ?? null\n }\n if (parsed.interactionType !== undefined) interaction.interactionType = parsed.interactionType\n if (parsed.title !== undefined) interaction.title = parsed.title ?? null\n if (parsed.body !== undefined) interaction.body = parsed.body ?? null\n if (parsed.status !== undefined) interaction.status = parsed.status\n if (parsed.scheduledAt !== undefined) interaction.scheduledAt = parsed.scheduledAt ?? null\n if (parsed.occurredAt !== undefined) interaction.occurredAt = parsed.occurredAt ?? null\n if (parsed.priority !== undefined) interaction.priority = parsed.priority ?? null\n if (parsed.authorUserId !== undefined) interaction.authorUserId = parsed.authorUserId ?? null\n if (parsed.ownerUserId !== undefined) interaction.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.appearanceIcon !== undefined) interaction.appearanceIcon = parsed.appearanceIcon ?? null\n if (parsed.appearanceColor !== undefined) interaction.appearanceColor = parsed.appearanceColor ?? null\n\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n await setInteractionCustomFields(\n createTransactionalDataEngine(ctx, trx),\n interaction.id,\n interaction.organizationId,\n interaction.tenantId,\n custom,\n )\n\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.update', 'Update interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {\n let interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n const entity = await requireCustomerEntity(trx, before.interaction.entityId, undefined, 'Customer not found')\n\n if (!interaction) {\n interaction = trx.create(CustomerInteraction, {\n id: before.interaction.id,\n organizationId: before.interaction.organizationId,\n tenantId: before.interaction.tenantId,\n entity,\n interactionType: before.interaction.interactionType,\n title: before.interaction.title,\n body: before.interaction.body,\n status: before.interaction.status,\n scheduledAt: before.interaction.scheduledAt,\n occurredAt: before.interaction.occurredAt,\n priority: before.interaction.priority,\n authorUserId: before.interaction.authorUserId,\n ownerUserId: before.interaction.ownerUserId,\n dealId: before.interaction.dealId,\n source: before.interaction.source,\n appearanceIcon: before.interaction.appearanceIcon,\n appearanceColor: before.interaction.appearanceColor,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n } else {\n interaction.entity = entity\n interaction.interactionType = before.interaction.interactionType\n interaction.title = before.interaction.title\n interaction.body = before.interaction.body\n interaction.status = before.interaction.status\n interaction.scheduledAt = before.interaction.scheduledAt\n interaction.occurredAt = before.interaction.occurredAt\n interaction.priority = before.interaction.priority\n interaction.authorUserId = before.interaction.authorUserId\n interaction.ownerUserId = before.interaction.ownerUserId\n interaction.dealId = before.interaction.dealId\n interaction.source = before.interaction.source\n interaction.appearanceIcon = before.interaction.appearanceIcon\n interaction.appearanceColor = before.interaction.appearanceColor\n }\n\n await trx.flush()\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: createTransactionalDataEngine(ctx, trx),\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId,\n }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Complete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst completeInteractionCommand: CommandHandler<InteractionCompleteInput, { interactionId: string }> = {\n id: 'customers.interactions.complete',\n async prepare(rawInput, ctx) {\n const parsed = interactionCompleteSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = interactionCompleteSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n interaction.status = 'done'\n interaction.occurredAt = parsed.occurredAt ?? new Date()\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const identifiers = {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers,\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitLifecycleEvent(ctx, 'customers.interaction.completed', {\n ...identifiers,\n entityId,\n interactionType: interaction.interactionType,\n status: interaction.status,\n source: interaction.source ?? null,\n occurredAt: interaction.occurredAt?.toISOString() ?? null,\n ...(ctx.syncOrigin ? { syncOrigin: ctx.syncOrigin } : {}),\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, identifiers)\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.complete', 'Complete interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) return null\n\n interaction.status = before.interaction.status\n interaction.occurredAt = before.interaction.occurredAt\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n if (!result) return\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: result.interaction,\n identifiers: {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitInteractionRevertedEvent(ctx, before.interaction)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId: result.nextInteractionId,\n }, {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Cancel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst cancelInteractionCommand: CommandHandler<InteractionCancelInput, { interactionId: string }> = {\n id: 'customers.interactions.cancel',\n async prepare(rawInput, ctx) {\n const parsed = interactionCancelSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = interactionCancelSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: parsed.id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n interaction.status = 'canceled'\n await trx.flush()\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const identifiers = {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: interaction,\n identifiers,\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitLifecycleEvent(ctx, 'customers.interaction.canceled', {\n ...identifiers,\n entityId,\n interactionType: interaction.interactionType,\n status: interaction.status,\n source: interaction.source ?? null,\n ...(ctx.syncOrigin ? { syncOrigin: ctx.syncOrigin } : {}),\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, identifiers)\n\n return { interactionId: interaction.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadInteractionSnapshot(em, result.interactionId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as InteractionSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.interactions.cancel', 'Cancel interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) return null\n\n interaction.status = before.interaction.status\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n if (!result) return\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: result.interaction,\n identifiers: {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitInteractionRevertedEvent(ctx, before.interaction)\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId: result.nextInteractionId,\n }, {\n id: result.interaction.id,\n organizationId: result.interaction.organizationId,\n tenantId: result.interaction.tenantId,\n })\n },\n}\n\n// \u2500\u2500\u2500 Delete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst deleteInteractionCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { interactionId: string }> =\n {\n id: 'customers.interactions.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Interaction id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadInteractionSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Interaction id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, entityId } = await runInTransaction(em, async (trx) => {\n const interaction = await trx.findOne(CustomerInteraction, { id, deletedAt: null })\n if (!interaction) throw new CrudHttpError(404, { error: 'Interaction not found' })\n ensureTenantScope(ctx, interaction.tenantId)\n ensureOrganizationScope(ctx, interaction.organizationId)\n\n const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id\n interaction.deletedAt = new Date()\n await trx.flush()\n\n return { interaction, entityId }\n })\n\n const projection = await recomputeNextInteraction(em, entityId)\n const nextInteractionId = projection.nextInteractionId\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, { entityId, nextInteractionId }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n return { interactionId: interaction.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as InteractionSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.interactions.delete', 'Delete interaction'),\n resourceKind: 'customers.interaction',\n resourceId: before.interaction.id,\n parentResourceKind: resolveParentResourceKind(before.interaction.entityKind),\n parentResourceId: before.interaction.entityId ?? null,\n tenantId: before.interaction.tenantId,\n organizationId: before.interaction.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies InteractionUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<InteractionUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {\n const entity = await requireCustomerEntity(trx, before.interaction.entityId, undefined, 'Customer not found')\n let interaction = await trx.findOne(CustomerInteraction, { id: before.interaction.id })\n if (!interaction) {\n interaction = trx.create(CustomerInteraction, {\n id: before.interaction.id,\n organizationId: before.interaction.organizationId,\n tenantId: before.interaction.tenantId,\n entity,\n interactionType: before.interaction.interactionType,\n title: before.interaction.title,\n body: before.interaction.body,\n status: before.interaction.status,\n scheduledAt: before.interaction.scheduledAt,\n occurredAt: before.interaction.occurredAt,\n priority: before.interaction.priority,\n authorUserId: before.interaction.authorUserId,\n ownerUserId: before.interaction.ownerUserId,\n dealId: before.interaction.dealId,\n source: before.interaction.source,\n appearanceIcon: before.interaction.appearanceIcon,\n appearanceColor: before.interaction.appearanceColor,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n trx.persist(interaction)\n } else {\n interaction.deletedAt = null\n interaction.entity = entity\n interaction.interactionType = before.interaction.interactionType\n interaction.title = before.interaction.title\n interaction.body = before.interaction.body\n interaction.status = before.interaction.status\n interaction.scheduledAt = before.interaction.scheduledAt\n interaction.occurredAt = before.interaction.occurredAt\n interaction.priority = before.interaction.priority\n interaction.authorUserId = before.interaction.authorUserId\n interaction.ownerUserId = before.interaction.ownerUserId\n interaction.dealId = before.interaction.dealId\n interaction.source = before.interaction.source\n interaction.appearanceIcon = before.interaction.appearanceIcon\n interaction.appearanceColor = before.interaction.appearanceColor\n }\n await trx.flush()\n\n const projection = await recomputeNextInteraction(trx, before.interaction.entityId)\n\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: createTransactionalDataEngine(ctx, trx),\n entityId: INTERACTION_ENTITY_ID,\n recordId: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n\n return {\n interaction,\n nextInteractionId: projection.nextInteractionId,\n }\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: interaction,\n identifiers: {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n },\n syncOrigin: ctx.syncOrigin,\n indexer: interactionCrudIndexer,\n events: interactionCrudEvents,\n })\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: before.interaction.entityId,\n nextInteractionId,\n }, {\n id: interaction.id,\n organizationId: interaction.organizationId,\n tenantId: interaction.tenantId,\n })\n },\n }\n\n// \u2500\u2500\u2500 Recompute Next (internal repair) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst recomputeNextSchema = z.object({ entityId: z.string().min(1) })\n\nconst recomputeNextCommand: CommandHandler<{ entityId: string }, { entityId: string }> = {\n id: 'customers.interaction.recompute_next',\n async execute(rawInput, ctx) {\n const parsed = recomputeNextSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const projection = await recomputeNextInteraction(em, parsed.entityId)\n const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')\n await emitNextInteractionUpdatedEvent(ctx, {\n entityId: parsed.entityId,\n nextInteractionId: projection.nextInteractionId,\n }, {\n id: parsed.entityId,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n })\n return { entityId: parsed.entityId }\n },\n}\n\nregisterCommand(createInteractionCommand)\nregisterCommand(updateInteractionCommand)\nregisterCommand(completeInteractionCommand)\nregisterCommand(cancelInteractionCommand)\nregisterCommand(deleteInteractionCommand)\nregisterCommand(recomputeNextCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": ["interaction", "entityId"]
7
7
  }
@@ -9,11 +9,12 @@ import { RowActions } from "@open-mercato/ui/backend/RowActions";
9
9
  import { BooleanIcon } from "@open-mercato/ui/backend/ValueIcons";
10
10
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
11
11
  import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
12
- import { buildCrudExportUrl } from "@open-mercato/ui/backend/utils/crud";
13
12
  import { Button } from "@open-mercato/ui/primitives/button";
14
13
  import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
15
14
  import { useT } from "@open-mercato/shared/lib/i18n/context";
15
+ import { resolveTodoHref } from "./detail/utils.js";
16
16
  const TASKS_TAB_QUERY = "tab=tasks";
17
+ const CUSTOMER_TASKS_API_PATH = "/api/customers/interactions/tasks";
17
18
  function buildCustomerHref(item) {
18
19
  const customerId = item.customer?.id;
19
20
  if (!customerId) return null;
@@ -21,6 +22,24 @@ function buildCustomerHref(item) {
21
22
  const base = kind === "company" ? `/backend/customers/companies-v2/${customerId}` : `/backend/customers/people-v2/${customerId}`;
22
23
  return `${base}?${TASKS_TAB_QUERY}`;
23
24
  }
25
+ function buildCustomerTasksQueryString(input) {
26
+ const usp = new URLSearchParams({
27
+ page: String(input.page),
28
+ pageSize: String(input.pageSize)
29
+ });
30
+ if (input.search.trim().length > 0) usp.set("search", input.search.trim());
31
+ if (input.all) usp.set("all", "true");
32
+ return usp.toString();
33
+ }
34
+ function readValueAtPath(record, path) {
35
+ const segments = path.split(".").filter((segment) => segment.length > 0);
36
+ let current = record;
37
+ for (const segment of segments) {
38
+ if (!current || typeof current !== "object") return null;
39
+ current = current[segment];
40
+ }
41
+ return current ?? null;
42
+ }
24
43
  function CustomerTodosTable() {
25
44
  const t = useT();
26
45
  const router = useRouter();
@@ -28,14 +47,11 @@ function CustomerTodosTable() {
28
47
  const [search, setSearch] = React.useState("");
29
48
  const [page, setPage] = React.useState(1);
30
49
  const [pageSize] = React.useState(50);
31
- const params = React.useMemo(() => {
32
- const usp = new URLSearchParams({
33
- page: String(page),
34
- pageSize: String(pageSize)
35
- });
36
- if (search.trim().length > 0) usp.set("search", search.trim());
37
- return usp.toString();
38
- }, [page, pageSize, search]);
50
+ const params = React.useMemo(() => buildCustomerTasksQueryString({
51
+ page,
52
+ pageSize,
53
+ search
54
+ }), [page, pageSize, search]);
39
55
  const columns = React.useMemo(() => [
40
56
  {
41
57
  accessorKey: "customer.displayName",
@@ -54,9 +70,9 @@ function CustomerTodosTable() {
54
70
  header: t("customers.workPlan.customerTodos.table.column.todo"),
55
71
  cell: ({ row }) => {
56
72
  const title = row.original.todoTitle ?? t("customers.workPlan.customerTodos.table.column.todo.unnamed");
57
- const todoId = row.original.todoId;
58
- if (!todoId) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: title });
59
- return /* @__PURE__ */ jsx(Link, { href: `/backend/todos/${todoId}/edit`, className: "underline-offset-2 hover:underline", children: title });
73
+ const todoHref = row.original.externalHref ?? resolveTodoHref(row.original.todoSource, row.original.todoId);
74
+ if (!todoHref) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: title });
75
+ return /* @__PURE__ */ jsx(Link, { href: todoHref, className: "underline-offset-2 hover:underline", children: title });
60
76
  },
61
77
  meta: { priority: 2 }
62
78
  },
@@ -76,15 +92,25 @@ function CustomerTodosTable() {
76
92
  return { field: accessorKey, header };
77
93
  }).filter((col) => !!col);
78
94
  }, [columns]);
79
- const { data, isLoading, error, refetch, isFetching } = useQuery({
80
- queryKey: ["customers-todos", params, scopeVersion],
81
- queryFn: async () => {
82
- return readApiResultOrThrow(
83
- `/api/customers/todos?${params}`,
84
- void 0,
85
- { errorMessage: t("customers.workPlan.customerTodos.table.error.load") }
95
+ const buildPreparedExport = React.useCallback((exportRows, exportColumns) => ({
96
+ columns: exportColumns.map((col) => ({ field: col.field, header: col.header })),
97
+ rows: exportRows.map((row) => {
98
+ const record = row;
99
+ return Object.fromEntries(
100
+ exportColumns.map((col) => [col.field, readValueAtPath(record, col.field)])
86
101
  );
87
- },
102
+ })
103
+ }), []);
104
+ const fetchTasks = React.useCallback(async (queryString) => {
105
+ return readApiResultOrThrow(
106
+ `${CUSTOMER_TASKS_API_PATH}?${queryString}`,
107
+ void 0,
108
+ { errorMessage: t("customers.workPlan.customerTodos.table.error.load") }
109
+ );
110
+ }, [t]);
111
+ const { data, isLoading, error, refetch, isFetching } = useQuery({
112
+ queryKey: ["customers-interactions-tasks", params, scopeVersion],
113
+ queryFn: async () => fetchTasks(params),
88
114
  placeholderData: keepPreviousData
89
115
  });
90
116
  const rows = data?.items ?? [];
@@ -92,26 +118,28 @@ function CustomerTodosTable() {
92
118
  view: {
93
119
  description: t("customers.workPlan.customerTodos.table.export.view"),
94
120
  prepare: async () => {
95
- const rowsForExport = rows.map((row) => {
96
- const out = {};
97
- for (const col of viewExportColumns) {
98
- out[col.field] = row[col.field];
99
- }
100
- return out;
101
- });
102
- const prepared = {
103
- columns: viewExportColumns.map((col) => ({ field: col.field, header: col.header })),
104
- rows: rowsForExport
121
+ return {
122
+ prepared: buildPreparedExport(rows, viewExportColumns),
123
+ filename: "customer_todos_view"
105
124
  };
106
- return { prepared, filename: "customer_todos_view" };
107
125
  }
108
126
  },
109
127
  full: {
110
128
  description: t("customers.workPlan.customerTodos.table.export.full"),
111
- getUrl: (format) => buildCrudExportUrl("customers/todos", { exportScope: "full", all: "true" }, format),
112
- filename: () => "customer_todos_full"
129
+ prepare: async (_format) => {
130
+ const fullData = await fetchTasks(buildCustomerTasksQueryString({
131
+ page: 1,
132
+ pageSize,
133
+ search,
134
+ all: true
135
+ }));
136
+ return {
137
+ prepared: buildPreparedExport(fullData.items, viewExportColumns),
138
+ filename: "customer_todos_full"
139
+ };
140
+ }
113
141
  }
114
- }), [rows, t, viewExportColumns]);
142
+ }), [buildPreparedExport, fetchTasks, pageSize, rows, search, t, viewExportColumns]);
115
143
  const handleRefresh = React.useCallback(async () => {
116
144
  try {
117
145
  await refetch();
@@ -154,19 +182,21 @@ function CustomerTodosTable() {
154
182
  perspective: { tableId: "customers.todos.list" },
155
183
  rowActions: (row) => {
156
184
  const customerLink = buildCustomerHref(row);
157
- if (!customerLink) return null;
158
- return /* @__PURE__ */ jsx(
159
- RowActions,
160
- {
161
- items: [
162
- {
163
- id: "open-customer",
164
- label: t("customers.workPlan.customerTodos.table.actions.openCustomer"),
165
- href: customerLink
166
- }
167
- ]
168
- }
169
- );
185
+ const todoHref = row.externalHref ?? resolveTodoHref(row.todoSource, row.todoId);
186
+ const items = [
187
+ customerLink ? {
188
+ id: "open-customer",
189
+ label: t("customers.workPlan.customerTodos.table.actions.openCustomer"),
190
+ href: customerLink
191
+ } : null,
192
+ todoHref ? {
193
+ id: "open-task",
194
+ label: t("customers.workPlan.customerTodos.table.actions.openTask"),
195
+ href: todoHref
196
+ } : null
197
+ ].filter((item) => !!item);
198
+ if (!items.length) return null;
199
+ return /* @__PURE__ */ jsx(RowActions, { items });
170
200
  },
171
201
  onRowClick: handleNavigate,
172
202
  pagination: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/CustomerTodosTable.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useQuery, keepPreviousData } from '@tanstack/react-query'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { PreparedExport } from '@open-mercato/shared/lib/crud/exporters'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildCrudExportUrl } from '@open-mercato/ui/backend/utils/crud'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype CustomerTodoItem = {\n id: string\n todoId: string\n todoSource: string\n todoTitle: string | null\n todoIsDone: boolean | null\n todoPriority?: number | null\n todoSeverity?: string | null\n todoDescription?: string | null\n todoDueAt?: string | null\n todoCustomValues?: Record<string, unknown> | null\n todoOrganizationId: string | null\n organizationId: string\n tenantId: string\n createdAt: string\n customer: {\n id: string | null\n displayName: string | null\n kind: string | null\n }\n}\n\ntype CustomerTodosResponse = {\n items: CustomerTodoItem[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst TASKS_TAB_QUERY = 'tab=tasks'\n\nfunction buildCustomerHref(item: CustomerTodoItem): string | null {\n const customerId = item.customer?.id\n if (!customerId) return null\n const kind = (item.customer?.kind ?? '').toLowerCase()\n const base =\n kind === 'company'\n ? `/backend/customers/companies-v2/${customerId}`\n : `/backend/customers/people-v2/${customerId}`\n return `${base}?${TASKS_TAB_QUERY}`\n}\n\n// SPEC-046b: To enable canonical interactions mode, switch this table to\n// /api/customers/interactions?status=planned&pageSize=N&page=N&search=...\n//\n// Column mapping (InteractionSummary \u2192 CustomerTodoItem shape):\n// interaction.id \u2192 todoId (also use as id)\n// interaction.title \u2192 todoTitle\n// interaction.status \u2192 todoIsDone: status === 'done'\n// interaction.entityId \u2192 requires a separate lookup or API enricher\n// to resolve customer displayName/kind\n//\n// The main gap is the `customer` sub-object: the interactions API does not\n// embed customer details. Options:\n// a) Add a response enricher to the interactions API that populates\n// customer displayName/kind from entityId\n// b) Fetch customer details client-side for visible rows\n// c) Add an /api/customers/interactions/table endpoint that joins entities\n//\n// Export config would switch from 'customers/todos' to 'customers/interactions'\n// with exportScope: 'full' and an adjusted column mapping.\nexport function CustomerTodosTable(): React.JSX.Element {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [search, setSearch] = React.useState('')\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n\n const params = React.useMemo(() => {\n const usp = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n })\n if (search.trim().length > 0) usp.set('search', search.trim())\n return usp.toString()\n }, [page, pageSize, search])\n\n const columns = React.useMemo<ColumnDef<CustomerTodoItem>[]>(() => [\n {\n accessorKey: 'customer.displayName',\n header: t('customers.workPlan.customerTodos.table.column.customer'),\n cell: ({ row }) => {\n const name = row.original.customer?.displayName\n if (!name) return <span className=\"text-muted-foreground\">\u2014</span>\n const href = buildCustomerHref(row.original)\n if (!href) return name\n return (\n <Link href={href} className=\"underline-offset-2 hover:underline\">\n {name}\n </Link>\n )\n },\n meta: { priority: 1 },\n },\n {\n accessorKey: 'todoTitle',\n header: t('customers.workPlan.customerTodos.table.column.todo'),\n cell: ({ row }) => {\n const title = row.original.todoTitle ?? t('customers.workPlan.customerTodos.table.column.todo.unnamed')\n const todoId = row.original.todoId\n if (!todoId) return <span className=\"text-muted-foreground\">{title}</span>\n return (\n <Link href={`/backend/todos/${todoId}/edit`} className=\"underline-offset-2 hover:underline\">\n {title}\n </Link>\n )\n },\n meta: { priority: 2 },\n },\n {\n accessorKey: 'todoIsDone',\n header: t('customers.workPlan.customerTodos.table.column.done'),\n cell: ({ row }) => <BooleanIcon value={row.original.todoIsDone === true} />,\n meta: { priority: 3 },\n },\n ], [t])\n\n const viewExportColumns = React.useMemo(() => {\n return columns\n .map((col) => {\n const accessorKey = (col as any).accessorKey\n if (!accessorKey || typeof accessorKey !== 'string') return null\n if ((col as any).meta?.hidden) return null\n const header = typeof col.header === 'string'\n ? col.header\n : accessorKey\n return { field: accessorKey, header }\n })\n .filter((col): col is { field: string; header: string } => !!col)\n }, [columns])\n\n const { data, isLoading, error, refetch, isFetching } = useQuery<CustomerTodosResponse>({\n queryKey: ['customers-todos', params, scopeVersion],\n queryFn: async () => {\n return readApiResultOrThrow<CustomerTodosResponse>(\n `/api/customers/todos?${params}`,\n undefined,\n { errorMessage: t('customers.workPlan.customerTodos.table.error.load') },\n )\n },\n placeholderData: keepPreviousData,\n })\n\n const rows = data?.items ?? []\n\n const exportConfig = React.useMemo(() => ({\n view: {\n description: t('customers.workPlan.customerTodos.table.export.view'),\n prepare: async (): Promise<{ prepared: PreparedExport; filename: string }> => {\n const rowsForExport = rows.map((row) => {\n const out: Record<string, unknown> = {}\n for (const col of viewExportColumns) {\n out[col.field] = (row as Record<string, unknown>)[col.field]\n }\n return out\n })\n const prepared: PreparedExport = {\n columns: viewExportColumns.map((col) => ({ field: col.field, header: col.header })),\n rows: rowsForExport,\n }\n return { prepared, filename: 'customer_todos_view' }\n },\n },\n full: {\n description: t('customers.workPlan.customerTodos.table.export.full'),\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl('customers/todos', { exportScope: 'full', all: 'true' }, format),\n filename: () => 'customer_todos_full',\n },\n }), [rows, t, viewExportColumns])\n\n const handleRefresh = React.useCallback(async () => {\n try {\n await refetch()\n flash(t('customers.workPlan.customerTodos.table.flash.refreshed'), 'success')\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.workPlan.customerTodos.table.error.load')\n flash(message, 'error')\n }\n }, [refetch, t])\n\n const handleNavigate = React.useCallback((item: CustomerTodoItem) => {\n const href = buildCustomerHref(item)\n if (!href) return\n router.push(href)\n }, [router])\n\n const errorMessage = error ? (error instanceof Error ? error.message : t('customers.workPlan.customerTodos.table.error.load')) : null\n const emptyStateMessage = !isLoading && !errorMessage && rows.length === 0\n ? (search ? t('customers.workPlan.customerTodos.table.state.noMatches') : t('customers.workPlan.customerTodos.table.state.empty'))\n : undefined\n\n return (\n <DataTable\n title={t('customers.workPlan.customerTodos.table.title')}\n actions={(\n <Button\n variant=\"outline\"\n onClick={() => { void handleRefresh() }}\n disabled={isFetching}\n >\n {t('customers.workPlan.customerTodos.table.actions.refresh')}\n </Button>\n )}\n columns={columns}\n data={rows}\n exporter={exportConfig}\n searchValue={search}\n onSearchChange={(value) => {\n setSearch(value)\n setPage(1)\n }}\n perspective={{ tableId: 'customers.todos.list' }}\n rowActions={(row) => {\n const customerLink = buildCustomerHref(row)\n if (!customerLink) return null\n return (\n <RowActions\n items={[\n {\n id: 'open-customer',\n label: t('customers.workPlan.customerTodos.table.actions.openCustomer'),\n href: customerLink,\n },\n ]}\n />\n )\n }}\n onRowClick={handleNavigate}\n pagination={{\n page,\n pageSize,\n total: data?.total ?? 0,\n totalPages: data?.totalPages ?? 0,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n error={errorMessage}\n emptyState={emptyStateMessage}\n />\n )\n}\n\nexport default CustomerTodosTable\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useQuery, keepPreviousData } from '@tanstack/react-query'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { PreparedExport } from '@open-mercato/shared/lib/crud/exporters'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTodoHref } from './detail/utils'\n\ntype CustomerTodoItem = {\n id: string\n todoId: string\n todoSource: string\n todoTitle: string | null\n todoIsDone: boolean | null\n todoPriority?: number | null\n todoSeverity?: string | null\n todoDescription?: string | null\n todoDueAt?: string | null\n todoCustomValues?: Record<string, unknown> | null\n todoOrganizationId: string | null\n organizationId: string\n tenantId: string\n createdAt: string\n externalHref?: string | null\n _integrations?: Record<string, unknown>\n customer: {\n id: string | null\n displayName: string | null\n kind: string | null\n }\n}\n\ntype CustomerTodosResponse = {\n items: CustomerTodoItem[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst TASKS_TAB_QUERY = 'tab=tasks'\nconst CUSTOMER_TASKS_API_PATH = '/api/customers/interactions/tasks'\n\nfunction buildCustomerHref(item: CustomerTodoItem): string | null {\n const customerId = item.customer?.id\n if (!customerId) return null\n const kind = (item.customer?.kind ?? '').toLowerCase()\n const base =\n kind === 'company'\n ? `/backend/customers/companies-v2/${customerId}`\n : `/backend/customers/people-v2/${customerId}`\n return `${base}?${TASKS_TAB_QUERY}`\n}\n\nfunction buildCustomerTasksQueryString(input: {\n page: number\n pageSize: number\n search: string\n all?: boolean\n}): string {\n const usp = new URLSearchParams({\n page: String(input.page),\n pageSize: String(input.pageSize),\n })\n if (input.search.trim().length > 0) usp.set('search', input.search.trim())\n if (input.all) usp.set('all', 'true')\n return usp.toString()\n}\n\nfunction readValueAtPath(record: Record<string, unknown>, path: string): unknown {\n const segments = path.split('.').filter((segment) => segment.length > 0)\n let current: unknown = record\n for (const segment of segments) {\n if (!current || typeof current !== 'object') return null\n current = (current as Record<string, unknown>)[segment]\n }\n return current ?? null\n}\n\nexport function CustomerTodosTable(): React.JSX.Element {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [search, setSearch] = React.useState('')\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n\n const params = React.useMemo(() => buildCustomerTasksQueryString({\n page,\n pageSize,\n search,\n }), [page, pageSize, search])\n\n const columns = React.useMemo<ColumnDef<CustomerTodoItem>[]>(() => [\n {\n accessorKey: 'customer.displayName',\n header: t('customers.workPlan.customerTodos.table.column.customer'),\n cell: ({ row }) => {\n const name = row.original.customer?.displayName\n if (!name) return <span className=\"text-muted-foreground\">\u2014</span>\n const href = buildCustomerHref(row.original)\n if (!href) return name\n return (\n <Link href={href} className=\"underline-offset-2 hover:underline\">\n {name}\n </Link>\n )\n },\n meta: { priority: 1 },\n },\n {\n accessorKey: 'todoTitle',\n header: t('customers.workPlan.customerTodos.table.column.todo'),\n cell: ({ row }) => {\n const title = row.original.todoTitle ?? t('customers.workPlan.customerTodos.table.column.todo.unnamed')\n const todoHref = row.original.externalHref ?? resolveTodoHref(row.original.todoSource, row.original.todoId)\n if (!todoHref) return <span className=\"text-muted-foreground\">{title}</span>\n return (\n <Link href={todoHref} className=\"underline-offset-2 hover:underline\">\n {title}\n </Link>\n )\n },\n meta: { priority: 2 },\n },\n {\n accessorKey: 'todoIsDone',\n header: t('customers.workPlan.customerTodos.table.column.done'),\n cell: ({ row }) => <BooleanIcon value={row.original.todoIsDone === true} />,\n meta: { priority: 3 },\n },\n ], [t])\n\n const viewExportColumns = React.useMemo(() => {\n return columns\n .map((col) => {\n const accessorKey = (col as any).accessorKey\n if (!accessorKey || typeof accessorKey !== 'string') return null\n if ((col as any).meta?.hidden) return null\n const header = typeof col.header === 'string'\n ? col.header\n : accessorKey\n return { field: accessorKey, header }\n })\n .filter((col): col is { field: string; header: string } => !!col)\n }, [columns])\n\n const buildPreparedExport = React.useCallback((\n exportRows: CustomerTodoItem[],\n exportColumns: Array<{ field: string; header: string }>,\n ): PreparedExport => ({\n columns: exportColumns.map((col) => ({ field: col.field, header: col.header })),\n rows: exportRows.map((row) => {\n const record = row as Record<string, unknown>\n return Object.fromEntries(\n exportColumns.map((col) => [col.field, readValueAtPath(record, col.field)]),\n )\n }),\n }), [])\n\n const fetchTasks = React.useCallback(async (queryString: string): Promise<CustomerTodosResponse> => {\n return readApiResultOrThrow<CustomerTodosResponse>(\n `${CUSTOMER_TASKS_API_PATH}?${queryString}`,\n undefined,\n { errorMessage: t('customers.workPlan.customerTodos.table.error.load') },\n )\n }, [t])\n\n const { data, isLoading, error, refetch, isFetching } = useQuery<CustomerTodosResponse>({\n queryKey: ['customers-interactions-tasks', params, scopeVersion],\n queryFn: async () => fetchTasks(params),\n placeholderData: keepPreviousData,\n })\n\n const rows = data?.items ?? []\n\n const exportConfig = React.useMemo(() => ({\n view: {\n description: t('customers.workPlan.customerTodos.table.export.view'),\n prepare: async (): Promise<{ prepared: PreparedExport; filename: string }> => {\n return {\n prepared: buildPreparedExport(rows, viewExportColumns),\n filename: 'customer_todos_view',\n }\n },\n },\n full: {\n description: t('customers.workPlan.customerTodos.table.export.full'),\n prepare: async (_format: DataTableExportFormat): Promise<{ prepared: PreparedExport; filename: string }> => {\n const fullData = await fetchTasks(buildCustomerTasksQueryString({\n page: 1,\n pageSize,\n search,\n all: true,\n }))\n return {\n prepared: buildPreparedExport(fullData.items, viewExportColumns),\n filename: 'customer_todos_full',\n }\n },\n },\n }), [buildPreparedExport, fetchTasks, pageSize, rows, search, t, viewExportColumns])\n\n const handleRefresh = React.useCallback(async () => {\n try {\n await refetch()\n flash(t('customers.workPlan.customerTodos.table.flash.refreshed'), 'success')\n } catch (err) {\n const message = err instanceof Error ? err.message : t('customers.workPlan.customerTodos.table.error.load')\n flash(message, 'error')\n }\n }, [refetch, t])\n\n const handleNavigate = React.useCallback((item: CustomerTodoItem) => {\n const href = buildCustomerHref(item)\n if (!href) return\n router.push(href)\n }, [router])\n\n const errorMessage = error ? (error instanceof Error ? error.message : t('customers.workPlan.customerTodos.table.error.load')) : null\n const emptyStateMessage = !isLoading && !errorMessage && rows.length === 0\n ? (search ? t('customers.workPlan.customerTodos.table.state.noMatches') : t('customers.workPlan.customerTodos.table.state.empty'))\n : undefined\n\n return (\n <DataTable\n title={t('customers.workPlan.customerTodos.table.title')}\n actions={(\n <Button\n variant=\"outline\"\n onClick={() => { void handleRefresh() }}\n disabled={isFetching}\n >\n {t('customers.workPlan.customerTodos.table.actions.refresh')}\n </Button>\n )}\n columns={columns}\n data={rows}\n exporter={exportConfig}\n searchValue={search}\n onSearchChange={(value) => {\n setSearch(value)\n setPage(1)\n }}\n perspective={{ tableId: 'customers.todos.list' }}\n rowActions={(row) => {\n const customerLink = buildCustomerHref(row)\n const todoHref = row.externalHref ?? resolveTodoHref(row.todoSource, row.todoId)\n const items = [\n customerLink ? {\n id: 'open-customer',\n label: t('customers.workPlan.customerTodos.table.actions.openCustomer'),\n href: customerLink,\n } : null,\n todoHref ? {\n id: 'open-task',\n label: t('customers.workPlan.customerTodos.table.actions.openTask'),\n href: todoHref,\n } : null,\n ].filter((item): item is { id: string; label: string; href: string } => !!item)\n if (!items.length) return null\n return <RowActions items={items} />\n }}\n onRowClick={handleNavigate}\n pagination={{\n page,\n pageSize,\n total: data?.total ?? 0,\n totalPages: data?.totalPages ?? 0,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n error={errorMessage}\n emptyState={emptyStateMessage}\n />\n )\n}\n\nexport default CustomerTodosTable\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -375,7 +375,7 @@ function TasksSection({
375
375
  !isInitialLoading && hasTasks ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
376
376
  error ? /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: error }) : null,
377
377
  sortedTasks.map((task) => {
378
- const todoHref = resolveTodoHref(task.todoSource, task.todoId);
378
+ const todoHref = task.externalHref ?? resolveTodoHref(task.todoSource, task.todoId);
379
379
  const createdLabel = formatDateTime(task.createdAt) ?? emptyLabel;
380
380
  const meta = renderTaskMeta(task);
381
381
  const title = task.title ?? t("customers.people.detail.tasks.untitled", "Untitled task");
@@ -474,9 +474,9 @@ function TasksSection({
474
474
  isLoadingMore ? /* @__PURE__ */ jsxs("div", { className: "flex justify-center text-xs text-muted-foreground", children: [
475
475
  /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-3 w-3 animate-spin" }),
476
476
  t("customers.people.detail.tasks.loadingMore", "Loading\u2026")
477
- ] }) : null,
478
- /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: "/backend/customer-tasks", children: t("customers.people.detail.tasks.viewAll", "View all tasks") }) }) })
479
- ] }) : null
477
+ ] }) : null
478
+ ] }) : null,
479
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: "/backend/customer-tasks", children: t("customers.people.detail.tasks.viewAll", "View all tasks") }) }) })
480
480
  ] }),
481
481
  /* @__PURE__ */ jsx(
482
482
  TaskDialog,