@open-mercato/core 0.7.1-develop.7136.1.0f76137a1d → 0.7.1-develop.7148.1.3076e5ccf7

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 (68) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/backend/users/page.js +4 -4
  3. package/dist/modules/auth/backend/users/page.js.map +2 -2
  4. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -0
  5. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  6. package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
  7. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  8. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -0
  9. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  10. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +17 -4
  11. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  12. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +25 -12
  13. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  14. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  15. package/dist/modules/customers/components/linking/adapters/personAdapter.js +1 -1
  16. package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +2 -2
  17. package/dist/modules/customers/migrations/Migration20260901120000_reindex_pipeline_stage_colors.js +16 -0
  18. package/dist/modules/customers/migrations/Migration20260901120000_reindex_pipeline_stage_colors.js.map +7 -0
  19. package/dist/modules/dictionaries/migrations/Migration20260901120000_reindex_dictionary_entries.js +16 -0
  20. package/dist/modules/dictionaries/migrations/Migration20260901120000_reindex_dictionary_entries.js.map +7 -0
  21. package/dist/modules/integrations/backend/integrations/[id]/page.js +16 -3
  22. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  23. package/dist/modules/integrations/backend/integrations/useIntegrationCredentialsFeatureAccess.js +42 -0
  24. package/dist/modules/integrations/backend/integrations/useIntegrationCredentialsFeatureAccess.js.map +7 -0
  25. package/dist/modules/messages/api/route.js +2 -1
  26. package/dist/modules/messages/api/route.js.map +2 -2
  27. package/dist/modules/sales/commands/documents.js +11 -1
  28. package/dist/modules/sales/commands/documents.js.map +2 -2
  29. package/dist/modules/sales/lib/calculations.js +22 -0
  30. package/dist/modules/sales/lib/calculations.js.map +2 -2
  31. package/dist/modules/sales/lib/lineSnapshots.js +11 -1
  32. package/dist/modules/sales/lib/lineSnapshots.js.map +2 -2
  33. package/dist/modules/workflows/migrations/Migration20260901120000_reindex_workflow_definitions.js +16 -0
  34. package/dist/modules/workflows/migrations/Migration20260901120000_reindex_workflow_definitions.js.map +7 -0
  35. package/package.json +7 -7
  36. package/src/modules/auth/backend/users/page.tsx +4 -4
  37. package/src/modules/auth/i18n/de.json +4 -0
  38. package/src/modules/auth/i18n/en.json +4 -0
  39. package/src/modules/auth/i18n/es.json +4 -0
  40. package/src/modules/auth/i18n/ko.json +4 -0
  41. package/src/modules/auth/i18n/pl.json +4 -0
  42. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -0
  43. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
  44. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -0
  45. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +17 -4
  46. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +40 -14
  47. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
  48. package/src/modules/customers/components/linking/adapters/personAdapter.tsx +2 -1
  49. package/src/modules/customers/i18n/de.json +6 -1
  50. package/src/modules/customers/i18n/en.json +6 -1
  51. package/src/modules/customers/i18n/es.json +6 -1
  52. package/src/modules/customers/i18n/ko.json +6 -1
  53. package/src/modules/customers/i18n/pl.json +6 -1
  54. package/src/modules/customers/migrations/Migration20260901120000_reindex_pipeline_stage_colors.ts +22 -0
  55. package/src/modules/dictionaries/migrations/Migration20260901120000_reindex_dictionary_entries.ts +20 -0
  56. package/src/modules/integrations/backend/integrations/[id]/page.tsx +23 -2
  57. package/src/modules/integrations/backend/integrations/useIntegrationCredentialsFeatureAccess.ts +50 -0
  58. package/src/modules/integrations/i18n/de.json +1 -0
  59. package/src/modules/integrations/i18n/en.json +1 -0
  60. package/src/modules/integrations/i18n/es.json +1 -0
  61. package/src/modules/integrations/i18n/ko.json +1 -0
  62. package/src/modules/integrations/i18n/pl.json +1 -0
  63. package/src/modules/messages/api/route.ts +2 -1
  64. package/src/modules/sales/commands/documents.ts +14 -0
  65. package/src/modules/sales/lib/calculations.ts +41 -0
  66. package/src/modules/sales/lib/lineSnapshots.ts +23 -0
  67. package/src/modules/sales/lib/types.ts +9 -0
  68. package/src/modules/workflows/migrations/Migration20260901120000_reindex_workflow_definitions.ts +21 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/ScheduleActivityDialog.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Users, Phone, Check, Mail, Calendar, X, StickyNote } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { validatePhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { PhoneNumberField, SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n useScheduleFormState,\n FIELD_VISIBILITY,\n getFieldLabel,\n DateTimeFields,\n ParticipantsField,\n LocationField,\n FooterFields,\n LinkedEntitiesField,\n} from './schedule'\nimport type { ActivityType, ScheduleActivityEditData } from './schedule'\n\nconst TYPE_TABS: Array<{ type: ActivityType; icon: React.ComponentType<{ className?: string }>; labelKey: string; fallback: string }> = [\n { type: 'meeting', icon: Users, labelKey: 'customers.schedule.types.meeting', fallback: 'Meeting' },\n { type: 'call', icon: Phone, labelKey: 'customers.schedule.types.call', fallback: 'Call' },\n { type: 'task', icon: Check, labelKey: 'customers.schedule.types.task', fallback: 'Task' },\n { type: 'email', icon: Mail, labelKey: 'customers.schedule.types.email', fallback: 'Email' },\n { type: 'note', icon: StickyNote, labelKey: 'customers.schedule.types.note', fallback: 'Note' },\n]\n\ntype DialogChrome = { titleKey: string; titleFallback: string; subtitleKey: string; subtitleFallback: string; saveKey: string; saveFallback: string; saveIcon: React.ComponentType<{ className?: string }> }\n\nconst TYPE_CHROME: Record<ActivityType, DialogChrome> = {\n meeting: {\n titleKey: 'customers.schedule.meeting.title', titleFallback: 'New meeting',\n subtitleKey: 'customers.schedule.meeting.subtitle', subtitleFallback: 'Block time on the calendar with attendees',\n saveKey: 'customers.schedule.meeting.save', saveFallback: 'Save activity', saveIcon: Calendar,\n },\n call: {\n titleKey: 'customers.schedule.call.title', titleFallback: 'Log call',\n subtitleKey: 'customers.schedule.call.subtitle', subtitleFallback: 'Log a call you just had or schedule one',\n saveKey: 'customers.schedule.call.save', saveFallback: 'Log call', saveIcon: Phone,\n },\n task: {\n titleKey: 'customers.schedule.task.title', titleFallback: 'New task',\n subtitleKey: 'customers.schedule.task.subtitle', subtitleFallback: 'Capture something to follow up on',\n saveKey: 'customers.schedule.task.save', saveFallback: 'Save task', saveIcon: Check,\n },\n email: {\n titleKey: 'customers.schedule.email.title', titleFallback: 'Compose email',\n subtitleKey: 'customers.schedule.email.subtitle', subtitleFallback: 'Compose and send a tracked email',\n saveKey: 'customers.schedule.email.save', saveFallback: 'Send email', saveIcon: Mail,\n },\n note: {\n titleKey: 'customers.schedule.note.title', titleFallback: 'Add note',\n subtitleKey: 'customers.schedule.note.subtitle', subtitleFallback: 'Write down a note about this interaction',\n saveKey: 'customers.schedule.note.save', saveFallback: 'Save note', saveIcon: StickyNote,\n },\n}\n\nconst CALL_DIRECTIONS: Array<{ key: 'outbound' | 'inbound'; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'outbound', labelKey: 'customers.schedule.call.direction.outbound', labelFallback: 'Outbound', dot: 'bg-status-info-icon' },\n { key: 'inbound', labelKey: 'customers.schedule.call.direction.inbound', labelFallback: 'Inbound', dot: 'bg-status-success-icon' },\n]\n\nconst CALL_OUTCOMES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'connected', labelKey: 'customers.schedule.call.outcome.connected', labelFallback: 'Connected', dot: 'bg-status-success-icon' },\n { key: 'voicemail', labelKey: 'customers.schedule.call.outcome.voicemail', labelFallback: 'Voicemail', dot: 'bg-status-warning-icon' },\n { key: 'noanswer', labelKey: 'customers.schedule.call.outcome.noAnswer', labelFallback: 'No answer', dot: 'bg-muted-foreground' },\n { key: 'busy', labelKey: 'customers.schedule.call.outcome.busy', labelFallback: 'Busy', dot: 'bg-status-warning-icon' },\n { key: 'badnumber', labelKey: 'customers.schedule.call.outcome.badNumber', labelFallback: 'Bad number', dot: 'bg-status-error-icon' },\n]\n\nconst TASK_PRIORITIES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-muted-foreground' },\n { key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-status-info-icon' },\n { key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-warning-icon' },\n { key: 'urgent', labelKey: 'customers.schedule.task.priority.urgent', labelFallback: 'Urgent', dot: 'bg-status-error-icon' },\n]\n\ninterface ScheduleActivityDialogProps {\n open: boolean\n onClose: () => void\n entityId: string\n dealId?: string | null\n entityName?: string\n companyName?: string | null\n entityType: 'company' | 'person' | 'deal'\n onActivityCreated?: () => void\n /** When provided, dialog opens in edit mode with pre-filled data */\n editData?: ScheduleActivityEditData | null\n /** Default country ISO2 code for phone number input when value is empty/unparsed */\n defaultCountryIso2?: string\n}\n\nexport function ScheduleActivityDialog({\n open,\n onClose,\n entityId,\n dealId = null,\n entityName,\n companyName,\n entityType,\n onActivityCreated,\n editData,\n defaultCountryIso2,\n}: ScheduleActivityDialogProps) {\n const t = useT()\n const state = useScheduleFormState({ open, editData: editData ?? null })\n const visibleFields = FIELD_VISIBILITY[state.activityType]\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const isEditing = Boolean(editData?.id)\n const chrome = TYPE_CHROME[state.activityType]\n const SaveIcon = chrome.saveIcon\n const [callDirection, setCallDirection] = React.useState<'outbound' | 'inbound'>('outbound')\n const [callOutcome, setCallOutcome] = React.useState<string | null>(null)\n const [callPhoneNumber, setCallPhoneNumber] = React.useState('')\n const [callPhoneError, setCallPhoneError] = React.useState<string | null>(null)\n const [taskPriority, setTaskPriority] = React.useState<string>('medium')\n const callPhoneInvalidMessage = React.useMemo(\n () =>\n t(\n 'customers.activities.errors.phoneInvalid',\n 'Enter a valid phone number with country code (e.g. +1 212 555 1234)',\n ),\n [t],\n )\n const translateErrorMessage = React.useCallback(\n (message: string | undefined, fallback: string) => {\n const key = typeof message === 'string' ? message.trim() : ''\n return key ? t(key, key) : fallback\n },\n [t],\n )\n\n React.useEffect(() => {\n if (!open) return\n const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown }) | null | undefined\n const cv = (raw?.customValues && typeof raw.customValues === 'object' ? raw.customValues : null) as Record<string, unknown> | null\n setCallDirection(typeof cv?.callDirection === 'string' && cv.callDirection === 'inbound' ? 'inbound' : 'outbound')\n setCallOutcome(typeof cv?.callOutcome === 'string' ? cv.callOutcome : null)\n // Seed phone number from either top-level `phoneNumber` (newer write path)\n // or legacy `customValues.callPhoneNumber` so previously-saved calls still\n // round-trip on edit (#1808).\n const seededPhone =\n typeof raw?.phoneNumber === 'string' && raw.phoneNumber.trim().length > 0\n ? raw.phoneNumber\n : typeof cv?.callPhoneNumber === 'string'\n ? cv.callPhoneNumber\n : ''\n setCallPhoneNumber(seededPhone)\n setCallPhoneError(null)\n setTaskPriority(typeof cv?.taskPriority === 'string' ? cv.taskPriority : 'medium')\n }, [open, editData])\n\n // Reset per-type chip state when the user switches activity type in create mode.\n // In edit mode, the persisted customValues should win, so we skip the reset.\n React.useEffect(() => {\n if (!open || isEditing) return\n setCallDirection('outbound')\n setCallOutcome(null)\n setCallPhoneNumber('')\n setCallPhoneError(null)\n setTaskPriority('medium')\n }, [state.activityType, open, isEditing])\n\n const handleCallPhoneChange = React.useCallback((next: string | undefined) => {\n setCallPhoneNumber(next ?? '')\n setCallPhoneError(null)\n }, [])\n\n const formSnapshot = React.useMemo(() => JSON.stringify({\n activityType: state.activityType,\n title: state.title,\n date: state.date,\n startTime: state.startTime,\n duration: state.duration,\n allDay: state.allDay,\n description: state.description,\n location: state.location,\n reminderMinutes: state.reminderMinutes,\n visibility: state.visibility,\n participants: state.participants,\n linkedEntities: state.linkedEntities,\n recurrenceEnabled: state.recurrenceEnabled,\n recurrenceDays: state.recurrenceDays,\n recurrenceEndType: state.recurrenceEndType,\n recurrenceCount: state.recurrenceCount,\n recurrenceEndDate: state.recurrenceEndDate,\n guestPermissions: state.guestPermissions,\n }), [\n state.activityType, state.title, state.date, state.startTime, state.duration, state.allDay,\n state.description, state.location, state.reminderMinutes, state.visibility, state.participants,\n state.linkedEntities, state.recurrenceEnabled, state.recurrenceDays, state.recurrenceEndType,\n state.recurrenceCount, state.recurrenceEndDate, state.guestPermissions,\n ])\n const initialSnapshotRef = React.useRef<string | null>(null)\n const snapshotOpenKeyRef = React.useRef<string | null>(null)\n const snapshotSettleCountRef = React.useRef(0)\n const closeConfirmPendingRef = React.useRef(false)\n const openKey = open ? `${editData?.id ?? 'new'}` : null\n React.useEffect(() => {\n if (!open) {\n initialSnapshotRef.current = null\n snapshotOpenKeyRef.current = null\n snapshotSettleCountRef.current = 0\n return\n }\n if (snapshotOpenKeyRef.current !== openKey) {\n snapshotOpenKeyRef.current = openKey\n snapshotSettleCountRef.current = 0\n initialSnapshotRef.current = null\n }\n if (snapshotSettleCountRef.current < 2) {\n initialSnapshotRef.current = formSnapshot\n snapshotSettleCountRef.current += 1\n }\n }, [open, openKey, formSnapshot])\n\n const isDirty = React.useCallback(() => {\n if (initialSnapshotRef.current == null) return false\n return initialSnapshotRef.current !== formSnapshot\n }, [formSnapshot])\n\n const guardedClose = React.useCallback(async () => {\n if (closeConfirmPendingRef.current) return\n if (!isDirty()) {\n onClose()\n return\n }\n closeConfirmPendingRef.current = true\n try {\n const ok = await confirm({\n title: t('customers.schedule.discardConfirm.title', 'Discard unsaved changes?'),\n description: t(\n 'customers.schedule.discardConfirm.description',\n 'You have unsaved edits in this activity. Save them first or continue to discard them.',\n ),\n confirmText: t('customers.schedule.discardConfirm.confirm', 'Discard'),\n cancelText: t('customers.schedule.discardConfirm.cancel', 'Keep editing'),\n variant: 'destructive',\n })\n if (ok) onClose()\n } finally {\n closeConfirmPendingRef.current = false\n }\n }, [confirm, isDirty, onClose, t])\n\n const mutationContextId = React.useMemo(\n () => `customer-activity:${entityType}:${entityId}`,\n [entityId, entityType],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n entityType: 'company' | 'person' | 'deal'\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n resourceKind:\n entityType === 'company'\n ? 'customers.company'\n : entityType === 'person'\n ? 'customers.person'\n : 'customers.deal',\n resourceId: entityId,\n entityType,\n retryLastMutation,\n }),\n [entityId, entityType, mutationContextId, retryLastMutation],\n )\n const runGuardedMutation = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload: Record<string, unknown>) =>\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n }),\n [mutationContext, runMutation],\n )\n\n // Conflict detection -- debounced check when date/time/duration changes\n React.useEffect(() => {\n if (!open || state.allDay || !state.date || !state.startTime) {\n state.setConflict(null)\n return\n }\n const timer = setTimeout(async () => {\n try {\n const localStart = new Date(`${state.date}T${state.startTime}:00`)\n const params = new URLSearchParams({\n date: state.date,\n startTime: state.startTime,\n duration: String(state.duration),\n })\n if (editData?.id) {\n params.set('excludeId', editData.id)\n }\n if (!Number.isNaN(localStart.getTime())) {\n params.set('timezoneOffsetMinutes', String(-localStart.getTimezoneOffset()))\n }\n const data = await readApiResultOrThrow<{\n hasConflicts: boolean\n conflicts: Array<{ id: string; title: string | null; startTime: string; endTime: string; type: string }>\n }>(`/api/customers/interactions/conflicts?${params.toString()}`)\n if (data?.hasConflicts && Array.isArray(data.conflicts) && data.conflicts.length > 0) {\n const descriptions = data.conflicts\n .map((c) => `${c.startTime}\u2013${c.endTime}: ${c.title ?? c.type}`)\n .join(', ')\n state.setConflict(\n t('customers.schedule.conflict.description', 'Overlaps with: {{items}}', { items: descriptions }),\n )\n } else {\n state.setConflict(null)\n }\n } catch {\n state.setConflict(null)\n }\n }, 500)\n return () => clearTimeout(timer)\n }, [editData?.id, open, state.date, state.startTime, state.duration, state.allDay, t]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const trimmedDate = state.date.trim()\n const trimmedStartTime = state.startTime.trim()\n const trimmedCallPhone = callPhoneNumber.trim()\n const isDateMissing = !trimmedDate\n const isTimeMissing = !state.allDay && !trimmedStartTime\n const isSubmitDisabled =\n state.saving ||\n !state.title.trim() ||\n isDateMissing ||\n isTimeMissing\n\n const handleSave = React.useCallback(async () => {\n if (!state.title.trim()) return\n if (isDateMissing) {\n flash(t('customers.activities.errors.dateRequired', 'Date is required'), 'error')\n return\n }\n if (isTimeMissing) {\n flash(t('customers.activities.errors.timeRequired', 'Time is required'), 'error')\n return\n }\n let phoneNumberForPayload: string | undefined\n if (state.activityType === 'call' && trimmedCallPhone) {\n const phoneValidation = validatePhoneNumber(trimmedCallPhone)\n if (!phoneValidation.valid) {\n setCallPhoneError(callPhoneInvalidMessage)\n flash(callPhoneInvalidMessage, 'error')\n return\n }\n phoneNumberForPayload = phoneValidation.normalized ?? trimmedCallPhone\n setCallPhoneError(null)\n if (phoneNumberForPayload !== callPhoneNumber) {\n setCallPhoneNumber(phoneNumberForPayload)\n }\n }\n state.setSaving(true)\n try {\n const scheduledAt = state.allDay\n ? new Date(`${state.date}T00:00:00`).toISOString()\n : new Date(`${state.date}T${state.startTime}:00`).toISOString()\n\n const recurrenceRule = state.recurrenceEnabled\n ? buildRecurrenceRule(state.recurrenceDays, state.recurrenceEndType, state.recurrenceCount, state.recurrenceEndDate)\n : null\n\n const isSaveEdit = Boolean(editData?.id)\n const customValues: Record<string, unknown> = {}\n if (state.activityType === 'call') {\n customValues.callDirection = callDirection\n if (callOutcome) customValues.callOutcome = callOutcome\n if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload\n }\n if (state.activityType === 'task') {\n customValues.taskPriority = taskPriority\n }\n const payload = {\n ...(isSaveEdit ? { id: editData!.id } : {}),\n entityId,\n dealId,\n interactionType: state.activityType,\n title: state.title.trim(),\n body: state.description.trim() || null,\n status: 'planned',\n date: trimmedDate,\n time: state.allDay ? '00:00' : trimmedStartTime,\n phoneNumber: state.activityType === 'call' ? phoneNumberForPayload : undefined,\n scheduledAt,\n durationMinutes: visibleFields.has('duration') && !state.allDay ? state.duration : null,\n location: visibleFields.has('location') ? (state.location.trim() || null) : null,\n allDay: visibleFields.has('allDay') ? state.allDay : null,\n recurrenceRule: visibleFields.has('recurrence') ? recurrenceRule : null,\n recurrenceEnd: visibleFields.has('recurrence') && state.recurrenceEndType === 'date' && state.recurrenceEndDate\n ? new Date(state.recurrenceEndDate).toISOString()\n : null,\n participants: visibleFields.has('participants') && state.participants.length > 0\n ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? 'pending' }))\n : null,\n guestPermissions: visibleFields.has('participants') && state.participants.length > 0 ? state.guestPermissions : null,\n linkedEntities: state.linkedEntities.length > 0\n ? state.linkedEntities.map((e) => ({ id: e.id, type: e.type, label: e.label }))\n : null,\n reminderMinutes: visibleFields.has('reminder') ? state.reminderMinutes : null,\n visibility: visibleFields.has('visibility') ? state.visibility : null,\n ...(Object.keys(customValues).length > 0 ? { customValues } : {}),\n }\n await runGuardedMutation(\n () => {\n const call = () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n // Optimistic lock only applies to edits \u2014 a stale modal save against a\n // concurrently changed/deleted activity surfaces the conflict bar (#2055).\n return isSaveEdit\n ? withScopedApiRequestHeaders(buildOptimisticLockHeader(editData?.updatedAt), call)\n : call()\n },\n {\n operation: isSaveEdit ? 'updateActivity' : 'createActivity',\n interactionId: editData?.id ?? null,\n interactionType: state.activityType,\n },\n )\n flash(t('customers.schedule.saved', 'Activity scheduled'), 'success')\n onClose()\n // Delay data reload so the dialog can unmount cleanly and Radix restores body scroll\n requestAnimationFrame(() => { onActivityCreated?.() })\n } catch (err) {\n // An optimistic-lock 409 was already surfaced as the persistent conflict\n // bar by `runGuardedMutation` (useGuardedMutation \u2192 surfaceRecordConflict).\n // Do NOT additionally flash the raw `record_modified` code here \u2014 that\n // showed an untranslated toast on top of the localized bar (#2055 QA).\n if (extractOptimisticLockConflict(err)) {\n onClose()\n return\n }\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const phoneFieldError = fieldErrors?.phoneNumber\n if (state.activityType === 'call' && phoneFieldError) {\n const translatedPhoneError = translateErrorMessage(phoneFieldError, callPhoneInvalidMessage)\n setCallPhoneError(translatedPhoneError)\n flash(translatedPhoneError, 'error')\n return\n }\n flash(\n translateErrorMessage(message, t('customers.schedule.error', 'Failed to schedule activity')),\n 'error',\n )\n } finally {\n state.setSaving(false)\n }\n }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, state.activityType, state.allDay, state.date, state.description, dealId, state.duration, editData, entityId, state.guestPermissions, state.linkedEntities, state.location, onActivityCreated, onClose, state.participants, state.recurrenceCount, state.recurrenceDays, state.recurrenceEnabled, state.recurrenceEndDate, state.recurrenceEndType, state.reminderMinutes, runGuardedMutation, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })\n\n return (\n <Dialog open={open} onOpenChange={(o) => { if (!o) void guardedClose() }}>\n <DialogContent\n className=\"flex max-h-[90vh] flex-col overflow-hidden border-border p-0 shadow-xl sm:max-w-[760px] sm:rounded-xl [&>[data-dialog-close]]:hidden\"\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n >\n {ConfirmDialogElement}\n <VisuallyHidden>\n <DialogTitle>{isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}</DialogTitle>\n </VisuallyHidden>\n\n {/* Header */}\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-border bg-background px-6 py-5\">\n <div className=\"flex flex-col gap-1\">\n <h2 className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\">\n {isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(chrome.subtitleKey, chrome.subtitleFallback)}\n </p>\n {entityName ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground/80\">\n {t('customers.schedule.context', 'On timeline: {{name}}', { name: entityName })}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n ) : null}\n </div>\n <IconButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { void guardedClose() }} className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-background\" aria-label={t('customers.schedule.cancel', 'Cancel')}>\n <X className=\"size-4 text-muted-foreground\" />\n </IconButton>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-4 bg-background p-6\">\n\n {/* Conflict warning */}\n {state.conflict && (\n <Alert status=\"warning\" className=\"rounded-lg\">\n <AlertTitle>\n {t('customers.schedule.conflict.title', 'Calendar conflict')}\n </AlertTitle>\n <AlertDescription>{state.conflict}</AlertDescription>\n </Alert>\n )}\n\n {/* Type tabs \u2014 large rectangular tiles per Figma */}\n <div className=\"grid grid-cols-4 gap-2\">\n {TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {\n const isActive = state.activityType === type\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => state.setActivityType(type)}\n aria-pressed={isActive}\n className={cn(\n 'flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground',\n )}\n >\n <Icon className=\"size-[18px]\" />\n {t(labelKey, fallback)}\n </button>\n )\n })}\n </div>\n\n {/* Title */}\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'title', t, 'customers.schedule.titleLabel', 'Title')}\n </label>\n <input\n type=\"text\"\n value={state.title}\n onChange={(e) => state.setTitle(e.target.value)}\n placeholder={\n state.activityType === 'email'\n ? t('customers.schedule.subjectPlaceholder', 'Subject...')\n : t('customers.schedule.titlePlaceholder', 'Activity title...')\n }\n className=\"w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground\"\n autoFocus\n />\n </div>\n\n {/* Date/Time/Duration \u2014 placed before per-type chip rows so the call/task\n workflows match Figma 829:50 / 790:280 (date row first, then status chips). */}\n <DateTimeFields\n visible={visibleFields}\n activityType={state.activityType}\n date={state.date}\n setDate={state.setDate}\n startTime={state.startTime}\n setStartTime={state.setStartTime}\n duration={state.duration}\n setDuration={state.setDuration}\n allDay={state.allDay}\n setAllDay={state.setAllDay}\n recurrenceEnabled={state.recurrenceEnabled}\n setRecurrenceEnabled={state.setRecurrenceEnabled}\n recurrenceDays={state.recurrenceDays}\n toggleRecurrenceDay={state.toggleRecurrenceDay}\n recurrenceEndType={state.recurrenceEndType}\n setRecurrenceEndType={state.setRecurrenceEndType}\n recurrenceCount={state.recurrenceCount}\n setRecurrenceCount={state.setRecurrenceCount}\n recurrenceEndDate={state.recurrenceEndDate}\n setRecurrenceEndDate={state.setRecurrenceEndDate}\n />\n\n {/* Call: Direction + Outcome chips */}\n {state.activityType === 'call' && (\n <div className=\"flex flex-col gap-3\">\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.directionLabel', 'Direction')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_DIRECTIONS.map((opt) => {\n const isActive = callDirection === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallDirection(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.outcomeLabel', 'Outcome')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_OUTCOMES.map((opt) => {\n const isActive = callOutcome === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallOutcome(isActive ? null : opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\n\n {/* Task: Priority chips */}\n {state.activityType === 'task' && (\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.task.priorityLabel', 'Priority')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {TASK_PRIORITIES.map((opt) => {\n const isActive = taskPriority === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setTaskPriority(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {/* Participants */}\n <ParticipantsField\n visible={visibleFields}\n activityType={state.activityType}\n participants={state.participants}\n setParticipants={state.setParticipants}\n removeParticipant={state.removeParticipant}\n guestPermissions={state.guestPermissions}\n setGuestPermissions={state.setGuestPermissions}\n />\n\n {/* Location (or phone number for calls) */}\n {state.activityType === 'call' ? (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"schedule-call-phone\" className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.phoneLabel', 'Phone number')}\n </label>\n <PhoneNumberField\n id=\"schedule-call-phone\"\n value={callPhoneNumber}\n onValueChange={handleCallPhoneChange}\n placeholder={t('customers.schedule.call.phonePlaceholder', '+1 555 000 0000')}\n externalError={callPhoneError}\n invalidLabel={callPhoneInvalidMessage}\n minDigits={7}\n defaultCountryIso2={defaultCountryIso2}\n />\n </div>\n ) : (\n <LocationField\n visible={visibleFields}\n activityType={state.activityType}\n location={state.location}\n setLocation={state.setLocation}\n />\n )}\n\n {/* Linked Entities */}\n <LinkedEntitiesField\n visible={visibleFields}\n activityType={state.activityType}\n linkedEntities={state.linkedEntities}\n setLinkedEntities={state.setLinkedEntities}\n />\n\n {/* Description */}\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'description', t, 'customers.schedule.description', 'Description')}\n </label>\n <div className=\"mt-[8px]\">\n <SwitchableMarkdownInput\n value={state.description}\n onChange={state.setDescription}\n isMarkdownEnabled={state.markdownEnabled}\n height={120}\n placeholder={t('customers.schedule.descriptionPlaceholder', 'Add details...')}\n />\n </div>\n </div>\n\n {/* Reminder + Visibility */}\n <FooterFields\n visible={visibleFields}\n activityType={state.activityType}\n reminderMinutes={state.reminderMinutes}\n setReminderMinutes={state.setReminderMinutes}\n visibility={state.visibility}\n setVisibility={state.setVisibility}\n />\n\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex shrink-0 items-center justify-end gap-2.5 border-t border-border bg-muted/50 px-6 py-4\">\n <Button type=\"button\" variant=\"outline\" onClick={() => { void guardedClose() }} className=\"rounded-md border border-input bg-background px-5 py-3 text-sm font-semibold text-foreground\">\n {t('customers.schedule.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={isSubmitDisabled} className=\"flex items-center gap-2 rounded-md bg-foreground px-5 py-3 text-sm font-semibold text-background hover:bg-foreground/90 disabled:opacity-50\">\n <SaveIcon className=\"size-3.5\" />\n {state.saving\n ? t('customers.schedule.saving', 'Saving...')\n : isEditing\n ? t('customers.schedule.update', 'Update activity')\n : t(chrome.saveKey, chrome.saveFallback)}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport type { ScheduleActivityEditData }\n\nfunction buildRecurrenceRule(\n days: boolean[],\n endType: 'never' | 'count' | 'date',\n count: number,\n endDate: string,\n): string {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const selectedDays = days.map((active, i) => (active ? dayNames[i] : null)).filter(Boolean)\n let rule = `FREQ=WEEKLY;BYDAY=${selectedDays.join(',')}`\n if (endType === 'count') rule += `;COUNT=${count}`\n if (endType === 'date' && endDate) rule += `;UNTIL=${endDate.replace(/-/g, '')}T235959Z`\n return rule\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Users, Phone, Check, Mail, Calendar, X, StickyNote } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { validatePhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { PhoneNumberField, SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n useScheduleFormState,\n FIELD_VISIBILITY,\n getFieldLabel,\n DateTimeFields,\n ParticipantsField,\n LocationField,\n FooterFields,\n LinkedEntitiesField,\n} from './schedule'\nimport type { ActivityType, ScheduleActivityEditData } from './schedule'\nimport { PRIORITY_NUMBER, priorityFromNumber, type EditorPriority } from '../../lib/calendar/editorPayload'\n\nconst TYPE_TABS: Array<{ type: ActivityType; icon: React.ComponentType<{ className?: string }>; labelKey: string; fallback: string }> = [\n { type: 'meeting', icon: Users, labelKey: 'customers.schedule.types.meeting', fallback: 'Meeting' },\n { type: 'call', icon: Phone, labelKey: 'customers.schedule.types.call', fallback: 'Call' },\n { type: 'task', icon: Check, labelKey: 'customers.schedule.types.task', fallback: 'Task' },\n { type: 'email', icon: Mail, labelKey: 'customers.schedule.types.email', fallback: 'Email' },\n { type: 'note', icon: StickyNote, labelKey: 'customers.schedule.types.note', fallback: 'Note' },\n]\n\ntype DialogChrome = { titleKey: string; titleFallback: string; subtitleKey: string; subtitleFallback: string; saveKey: string; saveFallback: string; saveIcon: React.ComponentType<{ className?: string }> }\n\nconst TYPE_CHROME: Record<ActivityType, DialogChrome> = {\n meeting: {\n titleKey: 'customers.schedule.meeting.title', titleFallback: 'New meeting',\n subtitleKey: 'customers.schedule.meeting.subtitle', subtitleFallback: 'Block time on the calendar with attendees',\n saveKey: 'customers.schedule.meeting.save', saveFallback: 'Save activity', saveIcon: Calendar,\n },\n call: {\n titleKey: 'customers.schedule.call.title', titleFallback: 'Log call',\n subtitleKey: 'customers.schedule.call.subtitle', subtitleFallback: 'Log a call you just had or schedule one',\n saveKey: 'customers.schedule.call.save', saveFallback: 'Log call', saveIcon: Phone,\n },\n task: {\n titleKey: 'customers.schedule.task.title', titleFallback: 'New task',\n subtitleKey: 'customers.schedule.task.subtitle', subtitleFallback: 'Capture something to follow up on',\n saveKey: 'customers.schedule.task.save', saveFallback: 'Save task', saveIcon: Check,\n },\n email: {\n titleKey: 'customers.schedule.email.title', titleFallback: 'Compose email',\n subtitleKey: 'customers.schedule.email.subtitle', subtitleFallback: 'Compose and send a tracked email',\n saveKey: 'customers.schedule.email.save', saveFallback: 'Send email', saveIcon: Mail,\n },\n note: {\n titleKey: 'customers.schedule.note.title', titleFallback: 'Add note',\n subtitleKey: 'customers.schedule.note.subtitle', subtitleFallback: 'Write down a note about this interaction',\n saveKey: 'customers.schedule.note.save', saveFallback: 'Save note', saveIcon: StickyNote,\n },\n}\n\nconst CALL_DIRECTIONS: Array<{ key: 'outbound' | 'inbound'; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'outbound', labelKey: 'customers.schedule.call.direction.outbound', labelFallback: 'Outbound', dot: 'bg-status-info-icon' },\n { key: 'inbound', labelKey: 'customers.schedule.call.direction.inbound', labelFallback: 'Inbound', dot: 'bg-status-success-icon' },\n]\n\nconst CALL_OUTCOMES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'connected', labelKey: 'customers.schedule.call.outcome.connected', labelFallback: 'Connected', dot: 'bg-status-success-icon' },\n { key: 'voicemail', labelKey: 'customers.schedule.call.outcome.voicemail', labelFallback: 'Voicemail', dot: 'bg-status-warning-icon' },\n { key: 'noanswer', labelKey: 'customers.schedule.call.outcome.noAnswer', labelFallback: 'No answer', dot: 'bg-muted-foreground' },\n { key: 'busy', labelKey: 'customers.schedule.call.outcome.busy', labelFallback: 'Busy', dot: 'bg-status-warning-icon' },\n { key: 'badnumber', labelKey: 'customers.schedule.call.outcome.badNumber', labelFallback: 'Bad number', dot: 'bg-status-error-icon' },\n]\n\n// Task priority is the interaction's own nullable `priority` column (0-100), not a\n// custom field \u2014 the same scale `CalendarEventEditor` writes through\n// `PRIORITY_NUMBER` / `priorityFromNumber`. `null` means \"no priority set\", which the\n// column allows (#5943). Dot colours mirror the calendar editor's `PRIORITY_META` so\n// both controls render the same value identically.\ntype TaskPriorityValue = EditorPriority | null\n\nconst TASK_PRIORITIES: Array<{ key: TaskPriorityValue; labelKey: string; labelFallback: string; dot: string }> = [\n { key: null, labelKey: 'customers.schedule.task.priority.none', labelFallback: 'None', dot: 'bg-muted' },\n { key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-status-info-icon' },\n { key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-muted-foreground' },\n { key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-error-icon' },\n]\n\nfunction readTaskPriorityNumber(raw: { priority?: unknown } | null | undefined): number | null {\n return typeof raw?.priority === 'number' && !Number.isNaN(raw.priority) ? raw.priority : null\n}\n\n// `TaskForm` writes any 0-100 value while these chips only offer three buckets, so a\n// save that did not touch the control must keep the stored number rather than snap it\n// to the bucket midpoint \u2014 `priority` is a sortable column, so rewriting 100 as 90\n// would silently reorder tasks the user never edited.\nfunction buildTaskPriorityPayload(level: TaskPriorityValue, seeded: number | null): number | null {\n if (!level) return null\n if (seeded !== null && priorityFromNumber(seeded) === level) return seeded\n return PRIORITY_NUMBER[level]\n}\n\ninterface ScheduleActivityDialogProps {\n open: boolean\n onClose: () => void\n entityId: string\n dealId?: string | null\n entityName?: string\n companyName?: string | null\n entityType: 'company' | 'person' | 'deal'\n onActivityCreated?: () => void\n /** When provided, dialog opens in edit mode with pre-filled data */\n editData?: ScheduleActivityEditData | null\n /** Default country ISO2 code for phone number input when value is empty/unparsed */\n defaultCountryIso2?: string\n}\n\nexport function ScheduleActivityDialog({\n open,\n onClose,\n entityId,\n dealId = null,\n entityName,\n companyName,\n entityType,\n onActivityCreated,\n editData,\n defaultCountryIso2,\n}: ScheduleActivityDialogProps) {\n const t = useT()\n const state = useScheduleFormState({ open, editData: editData ?? null })\n const visibleFields = FIELD_VISIBILITY[state.activityType]\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const isEditing = Boolean(editData?.id)\n const chrome = TYPE_CHROME[state.activityType]\n const SaveIcon = chrome.saveIcon\n const [callDirection, setCallDirection] = React.useState<'outbound' | 'inbound'>('outbound')\n const [callOutcome, setCallOutcome] = React.useState<string | null>(null)\n const [callPhoneNumber, setCallPhoneNumber] = React.useState('')\n const [callPhoneError, setCallPhoneError] = React.useState<string | null>(null)\n const [taskPriority, setTaskPriority] = React.useState<TaskPriorityValue>(null)\n const [seededTaskPriority, setSeededTaskPriority] = React.useState<number | null>(null)\n const callPhoneInvalidMessage = React.useMemo(\n () =>\n t(\n 'customers.activities.errors.phoneInvalid',\n 'Enter a valid phone number with country code (e.g. +1 212 555 1234)',\n ),\n [t],\n )\n const translateErrorMessage = React.useCallback(\n (message: string | undefined, fallback: string) => {\n const key = typeof message === 'string' ? message.trim() : ''\n return key ? t(key, key) : fallback\n },\n [t],\n )\n\n React.useEffect(() => {\n if (!open) return\n const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown; priority?: unknown }) | null | undefined\n const cv = (raw?.customValues && typeof raw.customValues === 'object' ? raw.customValues : null) as Record<string, unknown> | null\n setCallDirection(typeof cv?.callDirection === 'string' && cv.callDirection === 'inbound' ? 'inbound' : 'outbound')\n setCallOutcome(typeof cv?.callOutcome === 'string' ? cv.callOutcome : null)\n // Seed phone number from either top-level `phoneNumber` (newer write path)\n // or legacy `customValues.callPhoneNumber` so previously-saved calls still\n // round-trip on edit (#1808).\n const seededPhone =\n typeof raw?.phoneNumber === 'string' && raw.phoneNumber.trim().length > 0\n ? raw.phoneNumber\n : typeof cv?.callPhoneNumber === 'string'\n ? cv.callPhoneNumber\n : ''\n setCallPhoneNumber(seededPhone)\n setCallPhoneError(null)\n const seededPriority = readTaskPriorityNumber(raw)\n setSeededTaskPriority(seededPriority)\n setTaskPriority(seededPriority === null ? null : priorityFromNumber(seededPriority))\n }, [open, editData])\n\n // Reset per-type chip state when the user switches activity type in create mode.\n // In edit mode, the persisted customValues should win, so we skip the reset.\n React.useEffect(() => {\n if (!open || isEditing) return\n setCallDirection('outbound')\n setCallOutcome(null)\n setCallPhoneNumber('')\n setCallPhoneError(null)\n setTaskPriority(null)\n setSeededTaskPriority(null)\n }, [state.activityType, open, isEditing])\n\n const handleCallPhoneChange = React.useCallback((next: string | undefined) => {\n setCallPhoneNumber(next ?? '')\n setCallPhoneError(null)\n }, [])\n\n const formSnapshot = React.useMemo(() => JSON.stringify({\n activityType: state.activityType,\n title: state.title,\n date: state.date,\n startTime: state.startTime,\n duration: state.duration,\n allDay: state.allDay,\n description: state.description,\n location: state.location,\n reminderMinutes: state.reminderMinutes,\n visibility: state.visibility,\n participants: state.participants,\n linkedEntities: state.linkedEntities,\n recurrenceEnabled: state.recurrenceEnabled,\n recurrenceDays: state.recurrenceDays,\n recurrenceEndType: state.recurrenceEndType,\n recurrenceCount: state.recurrenceCount,\n recurrenceEndDate: state.recurrenceEndDate,\n guestPermissions: state.guestPermissions,\n }), [\n state.activityType, state.title, state.date, state.startTime, state.duration, state.allDay,\n state.description, state.location, state.reminderMinutes, state.visibility, state.participants,\n state.linkedEntities, state.recurrenceEnabled, state.recurrenceDays, state.recurrenceEndType,\n state.recurrenceCount, state.recurrenceEndDate, state.guestPermissions,\n ])\n const initialSnapshotRef = React.useRef<string | null>(null)\n const snapshotOpenKeyRef = React.useRef<string | null>(null)\n const snapshotSettleCountRef = React.useRef(0)\n const closeConfirmPendingRef = React.useRef(false)\n const openKey = open ? `${editData?.id ?? 'new'}` : null\n React.useEffect(() => {\n if (!open) {\n initialSnapshotRef.current = null\n snapshotOpenKeyRef.current = null\n snapshotSettleCountRef.current = 0\n return\n }\n if (snapshotOpenKeyRef.current !== openKey) {\n snapshotOpenKeyRef.current = openKey\n snapshotSettleCountRef.current = 0\n initialSnapshotRef.current = null\n }\n if (snapshotSettleCountRef.current < 2) {\n initialSnapshotRef.current = formSnapshot\n snapshotSettleCountRef.current += 1\n }\n }, [open, openKey, formSnapshot])\n\n const isDirty = React.useCallback(() => {\n if (initialSnapshotRef.current == null) return false\n return initialSnapshotRef.current !== formSnapshot\n }, [formSnapshot])\n\n const guardedClose = React.useCallback(async () => {\n if (closeConfirmPendingRef.current) return\n if (!isDirty()) {\n onClose()\n return\n }\n closeConfirmPendingRef.current = true\n try {\n const ok = await confirm({\n title: t('customers.schedule.discardConfirm.title', 'Discard unsaved changes?'),\n description: t(\n 'customers.schedule.discardConfirm.description',\n 'You have unsaved edits in this activity. Save them first or continue to discard them.',\n ),\n confirmText: t('customers.schedule.discardConfirm.confirm', 'Discard'),\n cancelText: t('customers.schedule.discardConfirm.cancel', 'Keep editing'),\n variant: 'destructive',\n })\n if (ok) onClose()\n } finally {\n closeConfirmPendingRef.current = false\n }\n }, [confirm, isDirty, onClose, t])\n\n const mutationContextId = React.useMemo(\n () => `customer-activity:${entityType}:${entityId}`,\n [entityId, entityType],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n entityType: 'company' | 'person' | 'deal'\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n resourceKind:\n entityType === 'company'\n ? 'customers.company'\n : entityType === 'person'\n ? 'customers.person'\n : 'customers.deal',\n resourceId: entityId,\n entityType,\n retryLastMutation,\n }),\n [entityId, entityType, mutationContextId, retryLastMutation],\n )\n const runGuardedMutation = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload: Record<string, unknown>) =>\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n }),\n [mutationContext, runMutation],\n )\n\n // Conflict detection -- debounced check when date/time/duration changes\n React.useEffect(() => {\n if (!open || state.allDay || !state.date || !state.startTime) {\n state.setConflict(null)\n return\n }\n const timer = setTimeout(async () => {\n try {\n const localStart = new Date(`${state.date}T${state.startTime}:00`)\n const params = new URLSearchParams({\n date: state.date,\n startTime: state.startTime,\n duration: String(state.duration),\n })\n if (editData?.id) {\n params.set('excludeId', editData.id)\n }\n if (!Number.isNaN(localStart.getTime())) {\n params.set('timezoneOffsetMinutes', String(-localStart.getTimezoneOffset()))\n }\n const data = await readApiResultOrThrow<{\n hasConflicts: boolean\n conflicts: Array<{ id: string; title: string | null; startTime: string; endTime: string; type: string }>\n }>(`/api/customers/interactions/conflicts?${params.toString()}`)\n if (data?.hasConflicts && Array.isArray(data.conflicts) && data.conflicts.length > 0) {\n const descriptions = data.conflicts\n .map((c) => `${c.startTime}\u2013${c.endTime}: ${c.title ?? c.type}`)\n .join(', ')\n state.setConflict(\n t('customers.schedule.conflict.description', 'Overlaps with: {{items}}', { items: descriptions }),\n )\n } else {\n state.setConflict(null)\n }\n } catch {\n state.setConflict(null)\n }\n }, 500)\n return () => clearTimeout(timer)\n }, [editData?.id, open, state.date, state.startTime, state.duration, state.allDay, t]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const trimmedDate = state.date.trim()\n const trimmedStartTime = state.startTime.trim()\n const trimmedCallPhone = callPhoneNumber.trim()\n const isDateMissing = !trimmedDate\n const isTimeMissing = !state.allDay && !trimmedStartTime\n const isSubmitDisabled =\n state.saving ||\n !state.title.trim() ||\n isDateMissing ||\n isTimeMissing\n\n const handleSave = React.useCallback(async () => {\n if (!state.title.trim()) return\n if (isDateMissing) {\n flash(t('customers.activities.errors.dateRequired', 'Date is required'), 'error')\n return\n }\n if (isTimeMissing) {\n flash(t('customers.activities.errors.timeRequired', 'Time is required'), 'error')\n return\n }\n let phoneNumberForPayload: string | undefined\n if (state.activityType === 'call' && trimmedCallPhone) {\n const phoneValidation = validatePhoneNumber(trimmedCallPhone)\n if (!phoneValidation.valid) {\n setCallPhoneError(callPhoneInvalidMessage)\n flash(callPhoneInvalidMessage, 'error')\n return\n }\n phoneNumberForPayload = phoneValidation.normalized ?? trimmedCallPhone\n setCallPhoneError(null)\n if (phoneNumberForPayload !== callPhoneNumber) {\n setCallPhoneNumber(phoneNumberForPayload)\n }\n }\n state.setSaving(true)\n try {\n const scheduledAt = state.allDay\n ? new Date(`${state.date}T00:00:00`).toISOString()\n : new Date(`${state.date}T${state.startTime}:00`).toISOString()\n\n const recurrenceRule = state.recurrenceEnabled\n ? buildRecurrenceRule(state.recurrenceDays, state.recurrenceEndType, state.recurrenceCount, state.recurrenceEndDate)\n : null\n\n const isSaveEdit = Boolean(editData?.id)\n const customValues: Record<string, unknown> = {}\n if (state.activityType === 'call') {\n customValues.callDirection = callDirection\n if (callOutcome) customValues.callOutcome = callOutcome\n if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload\n }\n const payload = {\n ...(isSaveEdit ? { id: editData!.id } : {}),\n entityId,\n dealId,\n interactionType: state.activityType,\n title: state.title.trim(),\n body: state.description.trim() || null,\n status: 'planned',\n date: trimmedDate,\n time: state.allDay ? '00:00' : trimmedStartTime,\n phoneNumber: state.activityType === 'call' ? phoneNumberForPayload : undefined,\n // Only tasks expose the priority control, so other types leave the column\n // untouched rather than clearing it on a type switch (#5943).\n priority: state.activityType === 'task' ? buildTaskPriorityPayload(taskPriority, seededTaskPriority) : undefined,\n scheduledAt,\n durationMinutes: visibleFields.has('duration') && !state.allDay ? state.duration : null,\n location: visibleFields.has('location') ? (state.location.trim() || null) : null,\n allDay: visibleFields.has('allDay') ? state.allDay : null,\n recurrenceRule: visibleFields.has('recurrence') ? recurrenceRule : null,\n recurrenceEnd: visibleFields.has('recurrence') && state.recurrenceEndType === 'date' && state.recurrenceEndDate\n ? new Date(state.recurrenceEndDate).toISOString()\n : null,\n participants: visibleFields.has('participants') && state.participants.length > 0\n ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? 'pending' }))\n : null,\n guestPermissions: visibleFields.has('participants') && state.participants.length > 0 ? state.guestPermissions : null,\n linkedEntities: state.linkedEntities.length > 0\n ? state.linkedEntities.map((e) => ({ id: e.id, type: e.type, label: e.label }))\n : null,\n reminderMinutes: visibleFields.has('reminder') ? state.reminderMinutes : null,\n visibility: visibleFields.has('visibility') ? state.visibility : null,\n ...(Object.keys(customValues).length > 0 ? { customValues } : {}),\n }\n await runGuardedMutation(\n () => {\n const call = () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n // Optimistic lock only applies to edits \u2014 a stale modal save against a\n // concurrently changed/deleted activity surfaces the conflict bar (#2055).\n return isSaveEdit\n ? withScopedApiRequestHeaders(buildOptimisticLockHeader(editData?.updatedAt), call)\n : call()\n },\n {\n operation: isSaveEdit ? 'updateActivity' : 'createActivity',\n interactionId: editData?.id ?? null,\n interactionType: state.activityType,\n },\n )\n flash(t('customers.schedule.saved', 'Activity scheduled'), 'success')\n onClose()\n // Delay data reload so the dialog can unmount cleanly and Radix restores body scroll\n requestAnimationFrame(() => { onActivityCreated?.() })\n } catch (err) {\n // An optimistic-lock 409 was already surfaced as the persistent conflict\n // bar by `runGuardedMutation` (useGuardedMutation \u2192 surfaceRecordConflict).\n // Do NOT additionally flash the raw `record_modified` code here \u2014 that\n // showed an untranslated toast on top of the localized bar (#2055 QA).\n if (extractOptimisticLockConflict(err)) {\n onClose()\n return\n }\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const phoneFieldError = fieldErrors?.phoneNumber\n if (state.activityType === 'call' && phoneFieldError) {\n const translatedPhoneError = translateErrorMessage(phoneFieldError, callPhoneInvalidMessage)\n setCallPhoneError(translatedPhoneError)\n flash(translatedPhoneError, 'error')\n return\n }\n flash(\n translateErrorMessage(message, t('customers.schedule.error', 'Failed to schedule activity')),\n 'error',\n )\n } finally {\n state.setSaving(false)\n }\n }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, state.activityType, state.allDay, state.date, state.description, dealId, state.duration, editData, entityId, state.guestPermissions, state.linkedEntities, state.location, onActivityCreated, onClose, state.participants, state.recurrenceCount, state.recurrenceDays, state.recurrenceEnabled, state.recurrenceEndDate, state.recurrenceEndType, state.reminderMinutes, runGuardedMutation, seededTaskPriority, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })\n\n return (\n <Dialog open={open} onOpenChange={(o) => { if (!o) void guardedClose() }}>\n <DialogContent\n className=\"flex max-h-[90vh] flex-col overflow-hidden border-border p-0 shadow-xl sm:max-w-[760px] sm:rounded-xl [&>[data-dialog-close]]:hidden\"\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n >\n {ConfirmDialogElement}\n <VisuallyHidden>\n <DialogTitle>{isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}</DialogTitle>\n </VisuallyHidden>\n\n {/* Header */}\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-border bg-background px-6 py-5\">\n <div className=\"flex flex-col gap-1\">\n <h2 className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\">\n {isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(chrome.subtitleKey, chrome.subtitleFallback)}\n </p>\n {entityName ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground/80\">\n {t('customers.schedule.context', 'On timeline: {{name}}', { name: entityName })}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n ) : null}\n </div>\n <IconButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { void guardedClose() }} className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-background\" aria-label={t('customers.schedule.cancel', 'Cancel')}>\n <X className=\"size-4 text-muted-foreground\" />\n </IconButton>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-4 bg-background p-6\">\n\n {/* Conflict warning */}\n {state.conflict && (\n <Alert status=\"warning\" className=\"rounded-lg\">\n <AlertTitle>\n {t('customers.schedule.conflict.title', 'Calendar conflict')}\n </AlertTitle>\n <AlertDescription>{state.conflict}</AlertDescription>\n </Alert>\n )}\n\n {/* Type tabs \u2014 large rectangular tiles per Figma */}\n <div className=\"grid grid-cols-4 gap-2\">\n {TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {\n const isActive = state.activityType === type\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => state.setActivityType(type)}\n aria-pressed={isActive}\n className={cn(\n 'flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground',\n )}\n >\n <Icon className=\"size-[18px]\" />\n {t(labelKey, fallback)}\n </button>\n )\n })}\n </div>\n\n {/* Title */}\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'title', t, 'customers.schedule.titleLabel', 'Title')}\n </label>\n <input\n type=\"text\"\n value={state.title}\n onChange={(e) => state.setTitle(e.target.value)}\n placeholder={\n state.activityType === 'email'\n ? t('customers.schedule.subjectPlaceholder', 'Subject...')\n : t('customers.schedule.titlePlaceholder', 'Activity title...')\n }\n className=\"w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground\"\n autoFocus\n />\n </div>\n\n {/* Date/Time/Duration \u2014 placed before per-type chip rows so the call/task\n workflows match Figma 829:50 / 790:280 (date row first, then status chips). */}\n <DateTimeFields\n visible={visibleFields}\n activityType={state.activityType}\n date={state.date}\n setDate={state.setDate}\n startTime={state.startTime}\n setStartTime={state.setStartTime}\n duration={state.duration}\n setDuration={state.setDuration}\n allDay={state.allDay}\n setAllDay={state.setAllDay}\n recurrenceEnabled={state.recurrenceEnabled}\n setRecurrenceEnabled={state.setRecurrenceEnabled}\n recurrenceDays={state.recurrenceDays}\n toggleRecurrenceDay={state.toggleRecurrenceDay}\n recurrenceEndType={state.recurrenceEndType}\n setRecurrenceEndType={state.setRecurrenceEndType}\n recurrenceCount={state.recurrenceCount}\n setRecurrenceCount={state.setRecurrenceCount}\n recurrenceEndDate={state.recurrenceEndDate}\n setRecurrenceEndDate={state.setRecurrenceEndDate}\n />\n\n {/* Call: Direction + Outcome chips */}\n {state.activityType === 'call' && (\n <div className=\"flex flex-col gap-3\">\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.directionLabel', 'Direction')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_DIRECTIONS.map((opt) => {\n const isActive = callDirection === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallDirection(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.outcomeLabel', 'Outcome')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_OUTCOMES.map((opt) => {\n const isActive = callOutcome === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallOutcome(isActive ? null : opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\n\n {/* Task: Priority chips */}\n {state.activityType === 'task' && (\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.task.priorityLabel', 'Priority')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {TASK_PRIORITIES.map((opt) => {\n const isActive = taskPriority === opt.key\n return (\n <button\n key={opt.key ?? 'none'}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setTaskPriority(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {/* Participants */}\n <ParticipantsField\n visible={visibleFields}\n activityType={state.activityType}\n participants={state.participants}\n setParticipants={state.setParticipants}\n removeParticipant={state.removeParticipant}\n guestPermissions={state.guestPermissions}\n setGuestPermissions={state.setGuestPermissions}\n />\n\n {/* Location (or phone number for calls) */}\n {state.activityType === 'call' ? (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"schedule-call-phone\" className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.phoneLabel', 'Phone number')}\n </label>\n <PhoneNumberField\n id=\"schedule-call-phone\"\n value={callPhoneNumber}\n onValueChange={handleCallPhoneChange}\n placeholder={t('customers.schedule.call.phonePlaceholder', '+1 555 000 0000')}\n externalError={callPhoneError}\n invalidLabel={callPhoneInvalidMessage}\n minDigits={7}\n defaultCountryIso2={defaultCountryIso2}\n />\n </div>\n ) : (\n <LocationField\n visible={visibleFields}\n activityType={state.activityType}\n location={state.location}\n setLocation={state.setLocation}\n />\n )}\n\n {/* Linked Entities */}\n <LinkedEntitiesField\n visible={visibleFields}\n activityType={state.activityType}\n linkedEntities={state.linkedEntities}\n setLinkedEntities={state.setLinkedEntities}\n />\n\n {/* Description */}\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'description', t, 'customers.schedule.description', 'Description')}\n </label>\n <div className=\"mt-[8px]\">\n <SwitchableMarkdownInput\n value={state.description}\n onChange={state.setDescription}\n isMarkdownEnabled={state.markdownEnabled}\n height={120}\n placeholder={t('customers.schedule.descriptionPlaceholder', 'Add details...')}\n />\n </div>\n </div>\n\n {/* Reminder + Visibility */}\n <FooterFields\n visible={visibleFields}\n activityType={state.activityType}\n reminderMinutes={state.reminderMinutes}\n setReminderMinutes={state.setReminderMinutes}\n visibility={state.visibility}\n setVisibility={state.setVisibility}\n />\n\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex shrink-0 items-center justify-end gap-2.5 border-t border-border bg-muted/50 px-6 py-4\">\n <Button type=\"button\" variant=\"outline\" onClick={() => { void guardedClose() }} className=\"rounded-md border border-input bg-background px-5 py-3 text-sm font-semibold text-foreground\">\n {t('customers.schedule.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={isSubmitDisabled} className=\"flex items-center gap-2 rounded-md bg-foreground px-5 py-3 text-sm font-semibold text-background hover:bg-foreground/90 disabled:opacity-50\">\n <SaveIcon className=\"size-3.5\" />\n {state.saving\n ? t('customers.schedule.saving', 'Saving...')\n : isEditing\n ? t('customers.schedule.update', 'Update activity')\n : t(chrome.saveKey, chrome.saveFallback)}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport type { ScheduleActivityEditData }\n\nfunction buildRecurrenceRule(\n days: boolean[],\n endType: 'never' | 'count' | 'date',\n count: number,\n endDate: string,\n): string {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const selectedDays = days.map((active, i) => (active ? dayNames[i] : null)).filter(Boolean)\n let rule = `FREQ=WEEKLY;BYDAY=${selectedDays.join(',')}`\n if (endType === 'count') rule += `;COUNT=${count}`\n if (endType === 'date' && endDate) rule += `;UNTIL=${endDate.replace(/-/g, '')}T235959Z`\n return rule\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/detail/schedule/useScheduleFormState.ts"],
4
- "sourcesContent": ["import * as React from 'react'\nimport type { ActivityType } from './fieldConfig'\n\nexport type RsvpStatus = 'pending' | 'accepted' | 'declined' | 'tentative'\n\nexport type Participant = {\n userId?: string\n name: string\n email?: string\n color?: string\n status?: RsvpStatus\n}\n\nexport type LinkedEntity = {\n id: string\n type: 'company' | 'deal' | 'offer'\n label: string\n}\n\nexport type ScheduleActivityEditData = {\n id: string\n /** Record version for the OSS optimistic-lock header on edit (#2055). */\n updatedAt?: string | null\n interactionType?: string\n title?: string | null\n body?: string | null\n scheduledAt?: string | null\n /**\n * Historical timestamp for completed activities (status `done`). Required for\n * the edit prefill to restore the original date/time instead of falling back\n * to \"today\" (#1807).\n */\n occurredAt?: string | null\n durationMinutes?: number | null\n location?: string | null\n allDay?: boolean | null\n recurrenceRule?: string | null\n recurrenceEnd?: string | null\n participants?: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminderMinutes?: number | null\n visibility?: string | null\n linkedEntities?: Array<{ id: string; type: string; label: string }> | null\n guestPermissions?: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n}\n\nexport const PARTICIPANT_COLORS = [\n 'bg-chart-emerald',\n 'bg-chart-blue',\n 'bg-chart-orange',\n 'bg-chart-violet',\n 'bg-chart-pink',\n 'bg-chart-teal',\n]\n\n// Per-Figma defaults for the Reminder dropdown when the user picks an activity\n// type. Meeting/email keep the standard 15 min; tasks default to 1 day (1440 min)\n// because they're plan-ahead artefacts; calls default to 5 min as a stand-in for\n// the Figma \"After call ends\" treatment (which would need a non-numeric sentinel\n// in the API contract \u2014 tracked as a follow-up).\nconst DEFAULT_REMINDER_MINUTES: Record<ActivityType, number> = {\n meeting: 15,\n call: 5,\n task: 1440,\n email: 15,\n note: 15,\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nfunction formatLocalDateInput(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(date.getDate())}`\n}\n\nfunction formatLocalTimeInput(date: Date): string {\n return `${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`\n}\n\ninterface UseScheduleFormStateParams {\n open: boolean\n editData: ScheduleActivityEditData | null | undefined\n}\n\nexport function useScheduleFormState({ open, editData }: UseScheduleFormStateParams) {\n const [activityType, setActivityType] = React.useState<ActivityType>('meeting')\n const [title, setTitle] = React.useState('')\n const [date, setDate] = React.useState(() => formatLocalDateInput(new Date()))\n const [startTime, setStartTime] = React.useState('10:00')\n const [duration, setDuration] = React.useState(30)\n const [allDay, setAllDay] = React.useState(false)\n const [description, setDescription] = React.useState('')\n const [markdownEnabled, setMarkdownEnabled] = React.useState(true)\n const [location, setLocation] = React.useState('')\n const [reminderMinutes, setReminderMinutes] = React.useState(15)\n const [visibility, setVisibility] = React.useState('team')\n const [participants, setParticipants] = React.useState<Participant[]>([])\n const [linkedEntities, setLinkedEntities] = React.useState<LinkedEntity[]>([])\n const [recurrenceEnabled, setRecurrenceEnabled] = React.useState(false)\n const [recurrenceDays, setRecurrenceDays] = React.useState<boolean[]>([true, false, true, false, false, false, false])\n const [recurrenceEndType, setRecurrenceEndType] = React.useState<'never' | 'count' | 'date'>('never')\n const [recurrenceCount, setRecurrenceCount] = React.useState(8)\n const [recurrenceEndDate, setRecurrenceEndDate] = React.useState('')\n const [conflict, setConflict] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [guestPermissions, setGuestPermissions] = React.useState({ canInviteOthers: true, canModify: false, canSeeList: true })\n\n React.useEffect(() => {\n if (open) {\n if (editData) {\n // Edit mode: populate from existing interaction\n const resolvedType = (editData.interactionType as ActivityType) ?? 'meeting'\n setActivityType(resolvedType)\n setTitle(editData.title ?? '')\n // For historical activities the canonical timestamp is `occurredAt`; for\n // planned/future ones it's `scheduledAt`. Without this fallback editing a\n // past activity prefilled to \"today\" instead of its actual moment (#1807).\n // Keep seed values in the user's local timezone, matching the cluster-E\n // local-day convention.\n const sourceTimestamp = editData.occurredAt ?? editData.scheduledAt ?? null\n const seedDate = sourceTimestamp ? new Date(sourceTimestamp) : new Date()\n const seedDateValid = !Number.isNaN(seedDate.getTime())\n const fallbackNow = new Date()\n const dateForForm = seedDateValid ? seedDate : fallbackNow\n setDate(formatLocalDateInput(dateForForm))\n setStartTime(formatLocalTimeInput(dateForForm))\n setDuration(editData.durationMinutes ?? 30)\n setAllDay(editData.allDay ?? false)\n setDescription(editData.body ?? '')\n setLocation(editData.location ?? '')\n // Use per-type default when the editData omits an explicit reminder\n // (the menu-driven \"New X\" flow opens the dialog with `reminderMinutes: null`).\n setReminderMinutes(editData.reminderMinutes ?? DEFAULT_REMINDER_MINUTES[resolvedType])\n setVisibility(editData.visibility ?? 'team')\n setParticipants(\n Array.isArray(editData.participants)\n ? editData.participants.map((p, i) => ({\n userId: p.userId,\n name: p.name ?? p.email ?? p.userId ?? '',\n email: p.email,\n color: PARTICIPANT_COLORS[i % PARTICIPANT_COLORS.length],\n status: (p.status ?? 'pending') as RsvpStatus,\n }))\n : [],\n )\n setLinkedEntities(\n Array.isArray(editData.linkedEntities)\n ? editData.linkedEntities.map((e) => ({ id: e.id, type: e.type as LinkedEntity['type'], label: e.label }))\n : [],\n )\n if (editData.recurrenceRule) {\n setRecurrenceEnabled(true)\n // Parse RRULE to set days and end type\n const rule = editData.recurrenceRule\n const byDayMatch = rule.match(/BYDAY=([A-Z,]+)/)\n if (byDayMatch) {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const activeDays = byDayMatch[1].split(',')\n setRecurrenceDays(dayNames.map((d) => activeDays.includes(d)))\n }\n const countMatch = rule.match(/COUNT=(\\d+)/)\n const untilMatch = rule.match(/UNTIL=(\\d{8})/)\n if (countMatch) {\n setRecurrenceEndType('count')\n setRecurrenceCount(Number(countMatch[1]))\n } else if (untilMatch) {\n setRecurrenceEndType('date')\n const raw = untilMatch[1]\n setRecurrenceEndDate(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`)\n } else {\n setRecurrenceEndType('never')\n }\n } else {\n setRecurrenceEnabled(false)\n }\n if (editData.guestPermissions) {\n setGuestPermissions({\n canInviteOthers: editData.guestPermissions.canInviteOthers ?? true,\n canModify: editData.guestPermissions.canModify ?? false,\n canSeeList: editData.guestPermissions.canSeeList ?? true,\n })\n }\n } else {\n // Create mode: reset all fields\n setActivityType('meeting')\n setTitle('')\n setDate(formatLocalDateInput(new Date()))\n setStartTime('10:00')\n setDuration(30)\n setAllDay(false)\n setDescription('')\n setLocation('')\n setReminderMinutes(DEFAULT_REMINDER_MINUTES.meeting)\n setVisibility('team')\n setParticipants([])\n setLinkedEntities([])\n setRecurrenceEnabled(false)\n }\n setConflict(null)\n }\n return () => {\n // Safety net: restore body scroll if Radix Dialog fails to clean up\n document.body.style.removeProperty('overflow')\n document.body.style.removeProperty('pointer-events')\n }\n }, [open, editData])\n\n // Update the Reminder default when the activity type changes in create mode.\n // Skipped in edit mode (the persisted value wins), and gated by `open` to\n // avoid flipping the default in a closed-but-mounted dialog.\n const lastReminderTypeRef = React.useRef<ActivityType>('meeting')\n React.useEffect(() => {\n if (!open || editData) {\n lastReminderTypeRef.current = activityType\n return\n }\n if (lastReminderTypeRef.current === activityType) return\n lastReminderTypeRef.current = activityType\n setReminderMinutes(DEFAULT_REMINDER_MINUTES[activityType])\n }, [activityType, editData, open])\n\n const removeParticipant = React.useCallback((index: number) => {\n setParticipants((prev) => prev.filter((_, i) => i !== index))\n }, [])\n\n const toggleRecurrenceDay = React.useCallback((index: number) => {\n setRecurrenceDays((prev) => {\n const next = [...prev]\n next[index] = !next[index]\n return next\n })\n }, [])\n\n return {\n activityType,\n setActivityType,\n title,\n setTitle,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n description,\n setDescription,\n markdownEnabled,\n setMarkdownEnabled,\n location,\n setLocation,\n reminderMinutes,\n setReminderMinutes,\n visibility,\n setVisibility,\n participants,\n setParticipants,\n linkedEntities,\n setLinkedEntities,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n setRecurrenceDays,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n conflict,\n setConflict,\n saving,\n setSaving,\n guestPermissions,\n setGuestPermissions,\n removeParticipant,\n toggleRecurrenceDay,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react'\nimport type { ActivityType } from './fieldConfig'\n\nexport type RsvpStatus = 'pending' | 'accepted' | 'declined' | 'tentative'\n\nexport type Participant = {\n userId?: string\n name: string\n email?: string\n color?: string\n status?: RsvpStatus\n}\n\nexport type LinkedEntity = {\n id: string\n type: 'company' | 'deal' | 'offer'\n label: string\n}\n\nexport type ScheduleActivityEditData = {\n id: string\n /** Record version for the OSS optimistic-lock header on edit (#2055). */\n updatedAt?: string | null\n interactionType?: string\n title?: string | null\n body?: string | null\n scheduledAt?: string | null\n /**\n * Historical timestamp for completed activities (status `done`). Required for\n * the edit prefill to restore the original date/time instead of falling back\n * to \"today\" (#1807).\n */\n occurredAt?: string | null\n durationMinutes?: number | null\n /** Interaction priority column (0-100, nullable) backing the task priority control (#5943). */\n priority?: number | null\n location?: string | null\n allDay?: boolean | null\n recurrenceRule?: string | null\n recurrenceEnd?: string | null\n participants?: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminderMinutes?: number | null\n visibility?: string | null\n linkedEntities?: Array<{ id: string; type: string; label: string }> | null\n guestPermissions?: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n}\n\nexport const PARTICIPANT_COLORS = [\n 'bg-chart-emerald',\n 'bg-chart-blue',\n 'bg-chart-orange',\n 'bg-chart-violet',\n 'bg-chart-pink',\n 'bg-chart-teal',\n]\n\n// Per-Figma defaults for the Reminder dropdown when the user picks an activity\n// type. Meeting/email keep the standard 15 min; tasks default to 1 day (1440 min)\n// because they're plan-ahead artefacts; calls default to 5 min as a stand-in for\n// the Figma \"After call ends\" treatment (which would need a non-numeric sentinel\n// in the API contract \u2014 tracked as a follow-up).\nconst DEFAULT_REMINDER_MINUTES: Record<ActivityType, number> = {\n meeting: 15,\n call: 5,\n task: 1440,\n email: 15,\n note: 15,\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nfunction formatLocalDateInput(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(date.getDate())}`\n}\n\nfunction formatLocalTimeInput(date: Date): string {\n return `${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`\n}\n\ninterface UseScheduleFormStateParams {\n open: boolean\n editData: ScheduleActivityEditData | null | undefined\n}\n\nexport function useScheduleFormState({ open, editData }: UseScheduleFormStateParams) {\n const [activityType, setActivityType] = React.useState<ActivityType>('meeting')\n const [title, setTitle] = React.useState('')\n const [date, setDate] = React.useState(() => formatLocalDateInput(new Date()))\n const [startTime, setStartTime] = React.useState('10:00')\n const [duration, setDuration] = React.useState(30)\n const [allDay, setAllDay] = React.useState(false)\n const [description, setDescription] = React.useState('')\n const [markdownEnabled, setMarkdownEnabled] = React.useState(true)\n const [location, setLocation] = React.useState('')\n const [reminderMinutes, setReminderMinutes] = React.useState(15)\n const [visibility, setVisibility] = React.useState('team')\n const [participants, setParticipants] = React.useState<Participant[]>([])\n const [linkedEntities, setLinkedEntities] = React.useState<LinkedEntity[]>([])\n const [recurrenceEnabled, setRecurrenceEnabled] = React.useState(false)\n const [recurrenceDays, setRecurrenceDays] = React.useState<boolean[]>([true, false, true, false, false, false, false])\n const [recurrenceEndType, setRecurrenceEndType] = React.useState<'never' | 'count' | 'date'>('never')\n const [recurrenceCount, setRecurrenceCount] = React.useState(8)\n const [recurrenceEndDate, setRecurrenceEndDate] = React.useState('')\n const [conflict, setConflict] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [guestPermissions, setGuestPermissions] = React.useState({ canInviteOthers: true, canModify: false, canSeeList: true })\n\n React.useEffect(() => {\n if (open) {\n if (editData) {\n // Edit mode: populate from existing interaction\n const resolvedType = (editData.interactionType as ActivityType) ?? 'meeting'\n setActivityType(resolvedType)\n setTitle(editData.title ?? '')\n // For historical activities the canonical timestamp is `occurredAt`; for\n // planned/future ones it's `scheduledAt`. Without this fallback editing a\n // past activity prefilled to \"today\" instead of its actual moment (#1807).\n // Keep seed values in the user's local timezone, matching the cluster-E\n // local-day convention.\n const sourceTimestamp = editData.occurredAt ?? editData.scheduledAt ?? null\n const seedDate = sourceTimestamp ? new Date(sourceTimestamp) : new Date()\n const seedDateValid = !Number.isNaN(seedDate.getTime())\n const fallbackNow = new Date()\n const dateForForm = seedDateValid ? seedDate : fallbackNow\n setDate(formatLocalDateInput(dateForForm))\n setStartTime(formatLocalTimeInput(dateForForm))\n setDuration(editData.durationMinutes ?? 30)\n setAllDay(editData.allDay ?? false)\n setDescription(editData.body ?? '')\n setLocation(editData.location ?? '')\n // Use per-type default when the editData omits an explicit reminder\n // (the menu-driven \"New X\" flow opens the dialog with `reminderMinutes: null`).\n setReminderMinutes(editData.reminderMinutes ?? DEFAULT_REMINDER_MINUTES[resolvedType])\n setVisibility(editData.visibility ?? 'team')\n setParticipants(\n Array.isArray(editData.participants)\n ? editData.participants.map((p, i) => ({\n userId: p.userId,\n name: p.name ?? p.email ?? p.userId ?? '',\n email: p.email,\n color: PARTICIPANT_COLORS[i % PARTICIPANT_COLORS.length],\n status: (p.status ?? 'pending') as RsvpStatus,\n }))\n : [],\n )\n setLinkedEntities(\n Array.isArray(editData.linkedEntities)\n ? editData.linkedEntities.map((e) => ({ id: e.id, type: e.type as LinkedEntity['type'], label: e.label }))\n : [],\n )\n if (editData.recurrenceRule) {\n setRecurrenceEnabled(true)\n // Parse RRULE to set days and end type\n const rule = editData.recurrenceRule\n const byDayMatch = rule.match(/BYDAY=([A-Z,]+)/)\n if (byDayMatch) {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const activeDays = byDayMatch[1].split(',')\n setRecurrenceDays(dayNames.map((d) => activeDays.includes(d)))\n }\n const countMatch = rule.match(/COUNT=(\\d+)/)\n const untilMatch = rule.match(/UNTIL=(\\d{8})/)\n if (countMatch) {\n setRecurrenceEndType('count')\n setRecurrenceCount(Number(countMatch[1]))\n } else if (untilMatch) {\n setRecurrenceEndType('date')\n const raw = untilMatch[1]\n setRecurrenceEndDate(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`)\n } else {\n setRecurrenceEndType('never')\n }\n } else {\n setRecurrenceEnabled(false)\n }\n if (editData.guestPermissions) {\n setGuestPermissions({\n canInviteOthers: editData.guestPermissions.canInviteOthers ?? true,\n canModify: editData.guestPermissions.canModify ?? false,\n canSeeList: editData.guestPermissions.canSeeList ?? true,\n })\n }\n } else {\n // Create mode: reset all fields\n setActivityType('meeting')\n setTitle('')\n setDate(formatLocalDateInput(new Date()))\n setStartTime('10:00')\n setDuration(30)\n setAllDay(false)\n setDescription('')\n setLocation('')\n setReminderMinutes(DEFAULT_REMINDER_MINUTES.meeting)\n setVisibility('team')\n setParticipants([])\n setLinkedEntities([])\n setRecurrenceEnabled(false)\n }\n setConflict(null)\n }\n return () => {\n // Safety net: restore body scroll if Radix Dialog fails to clean up\n document.body.style.removeProperty('overflow')\n document.body.style.removeProperty('pointer-events')\n }\n }, [open, editData])\n\n // Update the Reminder default when the activity type changes in create mode.\n // Skipped in edit mode (the persisted value wins), and gated by `open` to\n // avoid flipping the default in a closed-but-mounted dialog.\n const lastReminderTypeRef = React.useRef<ActivityType>('meeting')\n React.useEffect(() => {\n if (!open || editData) {\n lastReminderTypeRef.current = activityType\n return\n }\n if (lastReminderTypeRef.current === activityType) return\n lastReminderTypeRef.current = activityType\n setReminderMinutes(DEFAULT_REMINDER_MINUTES[activityType])\n }, [activityType, editData, open])\n\n const removeParticipant = React.useCallback((index: number) => {\n setParticipants((prev) => prev.filter((_, i) => i !== index))\n }, [])\n\n const toggleRecurrenceDay = React.useCallback((index: number) => {\n setRecurrenceDays((prev) => {\n const next = [...prev]\n next[index] = !next[index]\n return next\n })\n }, [])\n\n return {\n activityType,\n setActivityType,\n title,\n setTitle,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n description,\n setDescription,\n markdownEnabled,\n setMarkdownEnabled,\n location,\n setLocation,\n reminderMinutes,\n setReminderMinutes,\n visibility,\n setVisibility,\n participants,\n setParticipants,\n linkedEntities,\n setLinkedEntities,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n setRecurrenceDays,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n conflict,\n setConflict,\n saving,\n setSaving,\n guestPermissions,\n setGuestPermissions,\n removeParticipant,\n toggleRecurrenceDay,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -102,7 +102,7 @@ function createPersonLinkAdapter(options) {
102
102
  );
103
103
  const filters = roleOptions.length > 0 ? {
104
104
  options: [
105
- { id: "all", label: "All" },
105
+ { id: "all", label: options.allFilterLabel ?? "All" },
106
106
  ...roleOptions.map((role) => ({ id: role.id, label: role.label }))
107
107
  ],
108
108
  defaultId: "all",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/linking/adapters/personAdapter.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Building2, CalendarDays, Link2, Mail, Phone } from 'lucide-react'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type {\n LinkEntityAdapter,\n LinkEntityFilterOption,\n LinkEntityOption,\n LinkEntityRowContext,\n LinkEntitySearchPage,\n} from '../LinkEntityDialog'\n\nexport type PersonLinkSettings = {\n role: string | null\n isPrimary: boolean\n}\n\ntype PersonDetails = {\n contactEmails: string[]\n contactPhones: string[]\n linkedCompanies: Array<{ id: string; name: string; isPrimary?: boolean }>\n recentActivity: { title: string; occurredAt: string | null; summary?: string | null } | null\n}\n\ntype PersonAdapterOptions = {\n dialogTitle: string\n dialogSubtitle?: string\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n excludeLinkedCompanyId?: string\n excludeIds?: string[]\n defaultAvatarIcon?: React.ReactNode\n pageSize?: number\n addNew?: LinkEntityAdapter<PersonDetails, PersonLinkSettings>['addNew']\n showLinkSettings?: boolean\n roleOptions?: Array<{ id: string; label: string }>\n headerIcon?: React.ReactNode\n}\n\nconst DEFAULT_PAGE_SIZE = 20\n\ntype RecentActivityPayload = {\n title?: string | null\n occurredAt?: string | null\n summary?: string | null\n description?: string | null\n} | null\n\nfunction normalizePersonRecord(record: Record<string, unknown>): LinkEntityOption | null {\n const id = typeof record.id === 'string' ? record.id : null\n if (!id) return null\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n if (!displayName) return null\n const subtitleSource =\n typeof record.primaryEmail === 'string' && record.primaryEmail.trim().length\n ? record.primaryEmail.trim()\n : typeof record.primary_email === 'string' && record.primary_email.trim().length\n ? record.primary_email.trim()\n : typeof record.jobTitle === 'string' && record.jobTitle.trim().length\n ? record.jobTitle.trim()\n : typeof record.job_title === 'string' && record.job_title.trim().length\n ? record.job_title.trim()\n : null\n const role =\n typeof record.roleValue === 'string' && record.roleValue.trim().length\n ? record.roleValue.trim()\n : typeof record.role === 'string' && record.role.trim().length\n ? record.role.trim()\n : null\n const jobTitle =\n typeof record.jobTitle === 'string'\n ? record.jobTitle\n : typeof record.job_title === 'string'\n ? record.job_title\n : null\n const alreadyLinked =\n record.alreadyLinked === true ||\n record.already_linked === true ||\n record.excludedByLink === true\n return {\n id,\n label: displayName,\n subtitle: subtitleSource,\n meta: {\n role,\n jobTitle,\n alreadyLinked,\n primaryEmail:\n typeof record.primaryEmail === 'string'\n ? record.primaryEmail\n : typeof record.primary_email === 'string'\n ? record.primary_email\n : null,\n primaryPhone:\n typeof record.primaryPhone === 'string'\n ? record.primaryPhone\n : typeof record.primary_phone === 'string'\n ? record.primary_phone\n : null,\n },\n }\n}\n\nasync function fetchPersonDetails(id: string): Promise<PersonDetails> {\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/people/${encodeURIComponent(id)}`,\n )\n const emails: string[] = []\n const phones: string[] = []\n if (typeof payload.primaryEmail === 'string' && payload.primaryEmail.trim().length) {\n emails.push(payload.primaryEmail.trim())\n } else if (typeof payload.primary_email === 'string' && payload.primary_email.trim().length) {\n emails.push(payload.primary_email.trim())\n }\n if (typeof payload.primaryPhone === 'string' && payload.primaryPhone.trim().length) {\n phones.push(payload.primaryPhone.trim())\n } else if (typeof payload.primary_phone === 'string' && payload.primary_phone.trim().length) {\n phones.push(payload.primary_phone.trim())\n }\n const companies: Array<{ id: string; name: string; isPrimary?: boolean }> = []\n const rawCompanies = Array.isArray(payload.companies) ? payload.companies : []\n rawCompanies.forEach((entry) => {\n if (!entry || typeof entry !== 'object') return\n const record = entry as Record<string, unknown>\n const companyId = typeof record.id === 'string' ? record.id : null\n const name =\n typeof record.displayName === 'string'\n ? record.displayName\n : typeof record.display_name === 'string'\n ? record.display_name\n : null\n if (!companyId || !name) return\n companies.push({ id: companyId, name, isPrimary: Boolean(record.isPrimary ?? record.is_primary) })\n })\n let recentActivity: PersonDetails['recentActivity'] = null\n const activities = Array.isArray(payload.interactions)\n ? (payload.interactions as RecentActivityPayload[])\n : Array.isArray(payload.activities)\n ? (payload.activities as RecentActivityPayload[])\n : Array.isArray((payload.plannedActivitiesPreview as unknown[]))\n ? (payload.plannedActivitiesPreview as RecentActivityPayload[])\n : []\n if (activities.length > 0) {\n const entry = activities[0]\n if (entry && typeof entry === 'object') {\n recentActivity = {\n title: (entry.title ?? '').toString() || 'Interaction',\n occurredAt: typeof entry.occurredAt === 'string' ? entry.occurredAt : null,\n summary:\n typeof entry.summary === 'string'\n ? entry.summary\n : typeof entry.description === 'string'\n ? entry.description\n : null,\n }\n }\n }\n return { contactEmails: emails, contactPhones: phones, linkedCompanies: companies, recentActivity }\n } catch {\n return { contactEmails: [], contactPhones: [], linkedCompanies: [], recentActivity: null }\n }\n}\n\nfunction formatRelative(dateString: string | null): string {\n if (!dateString) return ''\n try {\n const date = new Date(dateString)\n const now = Date.now()\n const diffMs = now - date.getTime()\n const diffDays = Math.floor(diffMs / 86_400_000)\n if (diffDays <= 0) return 'today'\n if (diffDays === 1) return 'yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`\n return `${Math.floor(diffDays / 365)} years ago`\n } catch {\n return ''\n }\n}\n\nexport function createPersonLinkAdapter(\n options: PersonAdapterOptions,\n): LinkEntityAdapter<PersonDetails, PersonLinkSettings> {\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE\n const roleOptions = options.roleOptions ?? []\n\n const roleKeywords = new Map<string, string[]>(\n roleOptions.map((role) => [\n role.id,\n // build keyword list: id (as words), label words, lowercased\n [\n role.id.replace(/_/g, ' ').toLowerCase(),\n role.label.toLowerCase(),\n ],\n ]),\n )\n\n const filters:\n | {\n options: LinkEntityFilterOption[]\n defaultId?: string\n clientFilter?: (option: LinkEntityOption, filterId: string) => boolean\n }\n | undefined =\n roleOptions.length > 0\n ? {\n options: [\n { id: 'all', label: 'All' },\n ...roleOptions.map((role) => ({ id: role.id, label: role.label })),\n ],\n defaultId: 'all',\n clientFilter: (option, filterId) => {\n if (!filterId || filterId === 'all') return true\n const meta = (option.meta ?? {}) as {\n role?: string | null\n jobTitle?: string | null\n }\n const keywords = roleKeywords.get(filterId) ?? []\n const fields = [\n meta.role?.toLowerCase() ?? '',\n meta.jobTitle?.toLowerCase() ?? '',\n option.subtitle?.toLowerCase() ?? '',\n ]\n return keywords.some((keyword) =>\n fields.some((field) => field.includes(keyword)),\n )\n },\n }\n : undefined\n\n const searchPage = async (\n query: string,\n page: number,\n _filterId?: string,\n ): Promise<LinkEntitySearchPage> => {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'name',\n sortDir: 'asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n if (options.excludeLinkedCompanyId) {\n params.set('excludeLinkedCompanyId', options.excludeLinkedCompanyId)\n }\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/people?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const exclude = new Set(options.excludeIds ?? [])\n const items = rawItems\n .map((candidate) =>\n candidate && typeof candidate === 'object'\n ? normalizePersonRecord(candidate as Record<string, unknown>)\n : null,\n )\n .filter((entry): entry is LinkEntityOption => entry !== null && !exclude.has(entry.id))\n const totalPages = typeof payload.totalPages === 'number' ? payload.totalPages : 1\n const total = typeof payload.total === 'number' ? payload.total : undefined\n return { items, totalPages, total }\n }\n\n const fetchByIds = async (ids: string[]): Promise<LinkEntityOption[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n try {\n const payload = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/customers/people?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, LinkEntityOption>()\n rawItems.forEach((record) => {\n if (!record || typeof record !== 'object') return\n const option = normalizePersonRecord(record as Record<string, unknown>)\n if (option) byId.set(option.id, option)\n })\n return uniqueIds.map((id) => byId.get(id) ?? { id, label: id, subtitle: null })\n } catch {\n return uniqueIds.map((id) => ({ id, label: id, subtitle: null }))\n }\n }\n\n const renderRow = (option: LinkEntityOption, ctx: LinkEntityRowContext): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n role?: string | null\n jobTitle?: string | null\n primaryEmail?: string | null\n }\n const rolePill = meta.role ?? meta.jobTitle ?? null\n return (\n <>\n <Avatar label={option.label} variant=\"monochrome\" size=\"md\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {rolePill ? (\n <span className=\"inline-flex items-center rounded-sm bg-muted px-1.5 py-0.5 text-xs font-semibold text-muted-foreground\">\n {rolePill}\n </span>\n ) : null}\n </div>\n {option.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {option.subtitle}\n </div>\n ) : null}\n </div>\n <span\n role=\"checkbox\"\n aria-checked={ctx.selected}\n aria-label={`Select ${option.label}`}\n className={cn(\n 'inline-flex size-5 shrink-0 items-center justify-center rounded-full border',\n ctx.selected\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n )}\n >\n {ctx.selected ? (\n <svg viewBox=\"0 0 12 12\" className=\"size-3\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.5 6.5l2.5 2.5 4.5-5\" />\n </svg>\n ) : null}\n </span>\n </>\n )\n }\n\n const renderPreview = (\n option: LinkEntityOption,\n details?: PersonDetails,\n ): React.ReactNode => {\n const meta = (option.meta ?? {}) as { jobTitle?: string | null; primaryPhone?: string | null; primaryEmail?: string | null }\n const email = details?.contactEmails?.[0] ?? meta.primaryEmail ?? null\n const phone = details?.contactPhones?.[0] ?? meta.primaryPhone ?? null\n const companies = details?.linkedCompanies ?? []\n const activity = details?.recentActivity ?? null\n const subtitle = option.subtitle ?? meta.jobTitle ?? null\n return (\n <div className=\"flex flex-col gap-3.5 rounded-xl border border-border/70 bg-card p-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar label={option.label} variant=\"monochrome\" size=\"lg\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-bold text-foreground\">{option.label}</div>\n {subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">{subtitle}</div>\n ) : null}\n </div>\n </div>\n\n {email || phone ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Contact\n </div>\n {email ? (\n <div className=\"flex items-center gap-2.5 text-xs text-foreground\">\n <Mail className=\"size-3.5 text-muted-foreground\" />\n <span className=\"truncate\">{email}</span>\n </div>\n ) : null}\n {phone ? (\n <div className=\"flex items-center gap-2.5 text-xs text-foreground\">\n <Phone className=\"size-3.5 text-muted-foreground\" />\n <span className=\"truncate\">{phone}</span>\n </div>\n ) : null}\n </>\n ) : null}\n\n {companies.length > 0 ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Linked companies ({companies.length})\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {companies.map((company) => (\n <div\n key={company.id}\n className=\"flex items-center gap-2 rounded-md bg-muted/70 px-2.5 py-1.5 text-xs font-semibold text-foreground\"\n >\n <Building2 className=\"size-3 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{company.name}</span>\n {company.isPrimary ? (\n <span className=\"inline-flex items-center rounded-full bg-primary px-2 py-0.5 text-xs font-bold text-primary-foreground\">\n PRIMARY\n </span>\n ) : null}\n </div>\n ))}\n </div>\n </>\n ) : null}\n\n {activity ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Recent activity\n </div>\n <div className=\"flex items-start gap-2\">\n <CalendarDays className=\"mt-0.5 size-3 text-muted-foreground\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-xs font-semibold text-foreground\">\n {activity.title}\n {activity.occurredAt ? (\n <span className=\"text-muted-foreground\"> \u00B7 {formatRelative(activity.occurredAt)}</span>\n ) : null}\n </div>\n {activity.summary ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {activity.summary}\n </div>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n </div>\n )\n }\n\n const renderLinkSettings = options.showLinkSettings\n ? (\n settings: PersonLinkSettings,\n onChange: (next: PersonLinkSettings) => void,\n ): React.ReactNode => {\n const currentRole = settings.role ?? ''\n return (\n <div className=\"flex flex-col gap-3\">\n {roleOptions.length > 0 ? (\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-semibold text-muted-foreground\">Role at company</span>\n <select\n value={currentRole}\n onChange={(event) => onChange({ ...settings, role: event.target.value || null })}\n className=\"h-9 rounded-md border border-border bg-card px-3 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring/40\"\n >\n <option value=\"\">\u2014</option>\n {roleOptions.map((role) => (\n <option key={role.id} value={role.id}>\n {role.label}\n </option>\n ))}\n </select>\n </label>\n ) : null}\n <label className=\"flex cursor-pointer items-start gap-2\">\n <input\n type=\"checkbox\"\n checked={Boolean(settings.isPrimary)}\n onChange={(event) => onChange({ ...settings, isPrimary: event.target.checked })}\n className=\"mt-0.5 size-4 shrink-0 rounded-sm border border-border accent-foreground\"\n />\n <span className=\"min-w-0\">\n <span className=\"block text-xs font-semibold text-foreground\">\n Set as PRIMARY contact\n </span>\n <span className=\"mt-0.5 block text-xs text-muted-foreground\">\n Will appear at the top of company contacts\n </span>\n </span>\n </label>\n </div>\n )\n }\n : undefined\n\n return {\n kind: 'person',\n dialogTitle: options.dialogTitle,\n dialogSubtitle: options.dialogSubtitle,\n sectionLabel: options.sectionLabel ?? 'MATCHING CONTACTS',\n searchPlaceholder: options.searchPlaceholder,\n searchEmptyHint: options.searchEmptyHint,\n selectedEmptyHint: options.selectedEmptyHint,\n confirmButtonLabel: options.confirmButtonLabel,\n defaultAvatarIcon: options.defaultAvatarIcon,\n headerIcon: options.headerIcon ?? <Link2 className=\"size-5\" />,\n filters,\n renderRow,\n renderPreview,\n renderLinkSettings,\n initialLinkSettings: options.showLinkSettings ? { role: null, isPrimary: false } : undefined,\n fetchDetails: fetchPersonDetails,\n searchPage,\n fetchByIds,\n addNew: options.addNew,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Building2, CalendarDays, Link2, Mail, Phone } from 'lucide-react'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type {\n LinkEntityAdapter,\n LinkEntityFilterOption,\n LinkEntityOption,\n LinkEntityRowContext,\n LinkEntitySearchPage,\n} from '../LinkEntityDialog'\n\nexport type PersonLinkSettings = {\n role: string | null\n isPrimary: boolean\n}\n\ntype PersonDetails = {\n contactEmails: string[]\n contactPhones: string[]\n linkedCompanies: Array<{ id: string; name: string; isPrimary?: boolean }>\n recentActivity: { title: string; occurredAt: string | null; summary?: string | null } | null\n}\n\ntype PersonAdapterOptions = {\n dialogTitle: string\n dialogSubtitle?: string\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n excludeLinkedCompanyId?: string\n excludeIds?: string[]\n defaultAvatarIcon?: React.ReactNode\n pageSize?: number\n addNew?: LinkEntityAdapter<PersonDetails, PersonLinkSettings>['addNew']\n showLinkSettings?: boolean\n roleOptions?: Array<{ id: string; label: string }>\n allFilterLabel?: string\n headerIcon?: React.ReactNode\n}\n\nconst DEFAULT_PAGE_SIZE = 20\n\ntype RecentActivityPayload = {\n title?: string | null\n occurredAt?: string | null\n summary?: string | null\n description?: string | null\n} | null\n\nfunction normalizePersonRecord(record: Record<string, unknown>): LinkEntityOption | null {\n const id = typeof record.id === 'string' ? record.id : null\n if (!id) return null\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n if (!displayName) return null\n const subtitleSource =\n typeof record.primaryEmail === 'string' && record.primaryEmail.trim().length\n ? record.primaryEmail.trim()\n : typeof record.primary_email === 'string' && record.primary_email.trim().length\n ? record.primary_email.trim()\n : typeof record.jobTitle === 'string' && record.jobTitle.trim().length\n ? record.jobTitle.trim()\n : typeof record.job_title === 'string' && record.job_title.trim().length\n ? record.job_title.trim()\n : null\n const role =\n typeof record.roleValue === 'string' && record.roleValue.trim().length\n ? record.roleValue.trim()\n : typeof record.role === 'string' && record.role.trim().length\n ? record.role.trim()\n : null\n const jobTitle =\n typeof record.jobTitle === 'string'\n ? record.jobTitle\n : typeof record.job_title === 'string'\n ? record.job_title\n : null\n const alreadyLinked =\n record.alreadyLinked === true ||\n record.already_linked === true ||\n record.excludedByLink === true\n return {\n id,\n label: displayName,\n subtitle: subtitleSource,\n meta: {\n role,\n jobTitle,\n alreadyLinked,\n primaryEmail:\n typeof record.primaryEmail === 'string'\n ? record.primaryEmail\n : typeof record.primary_email === 'string'\n ? record.primary_email\n : null,\n primaryPhone:\n typeof record.primaryPhone === 'string'\n ? record.primaryPhone\n : typeof record.primary_phone === 'string'\n ? record.primary_phone\n : null,\n },\n }\n}\n\nasync function fetchPersonDetails(id: string): Promise<PersonDetails> {\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/people/${encodeURIComponent(id)}`,\n )\n const emails: string[] = []\n const phones: string[] = []\n if (typeof payload.primaryEmail === 'string' && payload.primaryEmail.trim().length) {\n emails.push(payload.primaryEmail.trim())\n } else if (typeof payload.primary_email === 'string' && payload.primary_email.trim().length) {\n emails.push(payload.primary_email.trim())\n }\n if (typeof payload.primaryPhone === 'string' && payload.primaryPhone.trim().length) {\n phones.push(payload.primaryPhone.trim())\n } else if (typeof payload.primary_phone === 'string' && payload.primary_phone.trim().length) {\n phones.push(payload.primary_phone.trim())\n }\n const companies: Array<{ id: string; name: string; isPrimary?: boolean }> = []\n const rawCompanies = Array.isArray(payload.companies) ? payload.companies : []\n rawCompanies.forEach((entry) => {\n if (!entry || typeof entry !== 'object') return\n const record = entry as Record<string, unknown>\n const companyId = typeof record.id === 'string' ? record.id : null\n const name =\n typeof record.displayName === 'string'\n ? record.displayName\n : typeof record.display_name === 'string'\n ? record.display_name\n : null\n if (!companyId || !name) return\n companies.push({ id: companyId, name, isPrimary: Boolean(record.isPrimary ?? record.is_primary) })\n })\n let recentActivity: PersonDetails['recentActivity'] = null\n const activities = Array.isArray(payload.interactions)\n ? (payload.interactions as RecentActivityPayload[])\n : Array.isArray(payload.activities)\n ? (payload.activities as RecentActivityPayload[])\n : Array.isArray((payload.plannedActivitiesPreview as unknown[]))\n ? (payload.plannedActivitiesPreview as RecentActivityPayload[])\n : []\n if (activities.length > 0) {\n const entry = activities[0]\n if (entry && typeof entry === 'object') {\n recentActivity = {\n title: (entry.title ?? '').toString() || 'Interaction',\n occurredAt: typeof entry.occurredAt === 'string' ? entry.occurredAt : null,\n summary:\n typeof entry.summary === 'string'\n ? entry.summary\n : typeof entry.description === 'string'\n ? entry.description\n : null,\n }\n }\n }\n return { contactEmails: emails, contactPhones: phones, linkedCompanies: companies, recentActivity }\n } catch {\n return { contactEmails: [], contactPhones: [], linkedCompanies: [], recentActivity: null }\n }\n}\n\nfunction formatRelative(dateString: string | null): string {\n if (!dateString) return ''\n try {\n const date = new Date(dateString)\n const now = Date.now()\n const diffMs = now - date.getTime()\n const diffDays = Math.floor(diffMs / 86_400_000)\n if (diffDays <= 0) return 'today'\n if (diffDays === 1) return 'yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`\n return `${Math.floor(diffDays / 365)} years ago`\n } catch {\n return ''\n }\n}\n\nexport function createPersonLinkAdapter(\n options: PersonAdapterOptions,\n): LinkEntityAdapter<PersonDetails, PersonLinkSettings> {\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE\n const roleOptions = options.roleOptions ?? []\n\n const roleKeywords = new Map<string, string[]>(\n roleOptions.map((role) => [\n role.id,\n // build keyword list: id (as words), label words, lowercased\n [\n role.id.replace(/_/g, ' ').toLowerCase(),\n role.label.toLowerCase(),\n ],\n ]),\n )\n\n const filters:\n | {\n options: LinkEntityFilterOption[]\n defaultId?: string\n clientFilter?: (option: LinkEntityOption, filterId: string) => boolean\n }\n | undefined =\n roleOptions.length > 0\n ? {\n options: [\n { id: 'all', label: options.allFilterLabel ?? 'All' },\n ...roleOptions.map((role) => ({ id: role.id, label: role.label })),\n ],\n defaultId: 'all',\n clientFilter: (option, filterId) => {\n if (!filterId || filterId === 'all') return true\n const meta = (option.meta ?? {}) as {\n role?: string | null\n jobTitle?: string | null\n }\n const keywords = roleKeywords.get(filterId) ?? []\n const fields = [\n meta.role?.toLowerCase() ?? '',\n meta.jobTitle?.toLowerCase() ?? '',\n option.subtitle?.toLowerCase() ?? '',\n ]\n return keywords.some((keyword) =>\n fields.some((field) => field.includes(keyword)),\n )\n },\n }\n : undefined\n\n const searchPage = async (\n query: string,\n page: number,\n _filterId?: string,\n ): Promise<LinkEntitySearchPage> => {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'name',\n sortDir: 'asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n if (options.excludeLinkedCompanyId) {\n params.set('excludeLinkedCompanyId', options.excludeLinkedCompanyId)\n }\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/people?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const exclude = new Set(options.excludeIds ?? [])\n const items = rawItems\n .map((candidate) =>\n candidate && typeof candidate === 'object'\n ? normalizePersonRecord(candidate as Record<string, unknown>)\n : null,\n )\n .filter((entry): entry is LinkEntityOption => entry !== null && !exclude.has(entry.id))\n const totalPages = typeof payload.totalPages === 'number' ? payload.totalPages : 1\n const total = typeof payload.total === 'number' ? payload.total : undefined\n return { items, totalPages, total }\n }\n\n const fetchByIds = async (ids: string[]): Promise<LinkEntityOption[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n try {\n const payload = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/customers/people?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, LinkEntityOption>()\n rawItems.forEach((record) => {\n if (!record || typeof record !== 'object') return\n const option = normalizePersonRecord(record as Record<string, unknown>)\n if (option) byId.set(option.id, option)\n })\n return uniqueIds.map((id) => byId.get(id) ?? { id, label: id, subtitle: null })\n } catch {\n return uniqueIds.map((id) => ({ id, label: id, subtitle: null }))\n }\n }\n\n const renderRow = (option: LinkEntityOption, ctx: LinkEntityRowContext): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n role?: string | null\n jobTitle?: string | null\n primaryEmail?: string | null\n }\n const rolePill = meta.role ?? meta.jobTitle ?? null\n return (\n <>\n <Avatar label={option.label} variant=\"monochrome\" size=\"md\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {rolePill ? (\n <span className=\"inline-flex items-center rounded-sm bg-muted px-1.5 py-0.5 text-xs font-semibold text-muted-foreground\">\n {rolePill}\n </span>\n ) : null}\n </div>\n {option.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {option.subtitle}\n </div>\n ) : null}\n </div>\n <span\n role=\"checkbox\"\n aria-checked={ctx.selected}\n aria-label={`Select ${option.label}`}\n className={cn(\n 'inline-flex size-5 shrink-0 items-center justify-center rounded-full border',\n ctx.selected\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n )}\n >\n {ctx.selected ? (\n <svg viewBox=\"0 0 12 12\" className=\"size-3\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.5 6.5l2.5 2.5 4.5-5\" />\n </svg>\n ) : null}\n </span>\n </>\n )\n }\n\n const renderPreview = (\n option: LinkEntityOption,\n details?: PersonDetails,\n ): React.ReactNode => {\n const meta = (option.meta ?? {}) as { jobTitle?: string | null; primaryPhone?: string | null; primaryEmail?: string | null }\n const email = details?.contactEmails?.[0] ?? meta.primaryEmail ?? null\n const phone = details?.contactPhones?.[0] ?? meta.primaryPhone ?? null\n const companies = details?.linkedCompanies ?? []\n const activity = details?.recentActivity ?? null\n const subtitle = option.subtitle ?? meta.jobTitle ?? null\n return (\n <div className=\"flex flex-col gap-3.5 rounded-xl border border-border/70 bg-card p-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar label={option.label} variant=\"monochrome\" size=\"lg\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-bold text-foreground\">{option.label}</div>\n {subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">{subtitle}</div>\n ) : null}\n </div>\n </div>\n\n {email || phone ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Contact\n </div>\n {email ? (\n <div className=\"flex items-center gap-2.5 text-xs text-foreground\">\n <Mail className=\"size-3.5 text-muted-foreground\" />\n <span className=\"truncate\">{email}</span>\n </div>\n ) : null}\n {phone ? (\n <div className=\"flex items-center gap-2.5 text-xs text-foreground\">\n <Phone className=\"size-3.5 text-muted-foreground\" />\n <span className=\"truncate\">{phone}</span>\n </div>\n ) : null}\n </>\n ) : null}\n\n {companies.length > 0 ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Linked companies ({companies.length})\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {companies.map((company) => (\n <div\n key={company.id}\n className=\"flex items-center gap-2 rounded-md bg-muted/70 px-2.5 py-1.5 text-xs font-semibold text-foreground\"\n >\n <Building2 className=\"size-3 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{company.name}</span>\n {company.isPrimary ? (\n <span className=\"inline-flex items-center rounded-full bg-primary px-2 py-0.5 text-xs font-bold text-primary-foreground\">\n PRIMARY\n </span>\n ) : null}\n </div>\n ))}\n </div>\n </>\n ) : null}\n\n {activity ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Recent activity\n </div>\n <div className=\"flex items-start gap-2\">\n <CalendarDays className=\"mt-0.5 size-3 text-muted-foreground\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-xs font-semibold text-foreground\">\n {activity.title}\n {activity.occurredAt ? (\n <span className=\"text-muted-foreground\"> \u00B7 {formatRelative(activity.occurredAt)}</span>\n ) : null}\n </div>\n {activity.summary ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {activity.summary}\n </div>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n </div>\n )\n }\n\n const renderLinkSettings = options.showLinkSettings\n ? (\n settings: PersonLinkSettings,\n onChange: (next: PersonLinkSettings) => void,\n ): React.ReactNode => {\n const currentRole = settings.role ?? ''\n return (\n <div className=\"flex flex-col gap-3\">\n {roleOptions.length > 0 ? (\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-semibold text-muted-foreground\">Role at company</span>\n <select\n value={currentRole}\n onChange={(event) => onChange({ ...settings, role: event.target.value || null })}\n className=\"h-9 rounded-md border border-border bg-card px-3 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring/40\"\n >\n <option value=\"\">\u2014</option>\n {roleOptions.map((role) => (\n <option key={role.id} value={role.id}>\n {role.label}\n </option>\n ))}\n </select>\n </label>\n ) : null}\n <label className=\"flex cursor-pointer items-start gap-2\">\n <input\n type=\"checkbox\"\n checked={Boolean(settings.isPrimary)}\n onChange={(event) => onChange({ ...settings, isPrimary: event.target.checked })}\n className=\"mt-0.5 size-4 shrink-0 rounded-sm border border-border accent-foreground\"\n />\n <span className=\"min-w-0\">\n <span className=\"block text-xs font-semibold text-foreground\">\n Set as PRIMARY contact\n </span>\n <span className=\"mt-0.5 block text-xs text-muted-foreground\">\n Will appear at the top of company contacts\n </span>\n </span>\n </label>\n </div>\n )\n }\n : undefined\n\n return {\n kind: 'person',\n dialogTitle: options.dialogTitle,\n dialogSubtitle: options.dialogSubtitle,\n sectionLabel: options.sectionLabel ?? 'MATCHING CONTACTS',\n searchPlaceholder: options.searchPlaceholder,\n searchEmptyHint: options.searchEmptyHint,\n selectedEmptyHint: options.selectedEmptyHint,\n confirmButtonLabel: options.confirmButtonLabel,\n defaultAvatarIcon: options.defaultAvatarIcon,\n headerIcon: options.headerIcon ?? <Link2 className=\"size-5\" />,\n filters,\n renderRow,\n renderPreview,\n renderLinkSettings,\n initialLinkSettings: options.showLinkSettings ? { role: null, isPrimary: false } : undefined,\n fetchDetails: fetchPersonDetails,\n searchPage,\n fetchByIds,\n addNew: options.addNew,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,16 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ import { declareQueryIndexReindex } from "@open-mercato/shared/lib/query/migration-reindex";
3
+ const queryIndexReindexEntityTypes = declareQueryIndexReindex([
4
+ "customers:customer_dictionary_entry"
5
+ ]);
6
+ class Migration20260901120000_reindex_pipeline_stage_colors extends Migration {
7
+ up() {
8
+ }
9
+ down() {
10
+ }
11
+ }
12
+ export {
13
+ Migration20260901120000_reindex_pipeline_stage_colors,
14
+ queryIndexReindexEntityTypes
15
+ };
16
+ //# sourceMappingURL=Migration20260901120000_reindex_pipeline_stage_colors.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/migrations/Migration20260901120000_reindex_pipeline_stage_colors.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\nimport { declareQueryIndexReindex } from '@open-mercato/shared/lib/query/migration-reindex';\n\n/**\n * Catch-up reindex for `Migration20260519120000_pipeline_stage_color_tones`, which rewrote\n * `customer_dictionary_entries.color` in raw SQL and never notified the query index. On every\n * install that already applied it, `entity_indexes.doc` for `customers:customer_dictionary_entry`\n * still holds the legacy hex chip (`#facc15`, `#a855f7`, \u2026) instead of the semantic tone, and so\n * do the `search_tokens` rows derived from that document. Both migrations are forward-only, so a\n * follow-up migration is the only route to repair existing installs.\n *\n * This migration executes no SQL \u2014 the declaration below is its entire payload.\n */\nexport const queryIndexReindexEntityTypes = declareQueryIndexReindex([\n 'customers:customer_dictionary_entry',\n]);\n\nexport class Migration20260901120000_reindex_pipeline_stage_colors extends Migration {\n override up(): void | Promise<void> {}\n\n override down(): void | Promise<void> {}\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,gCAAgC;AAYlC,MAAM,+BAA+B,yBAAyB;AAAA,EACnE;AACF,CAAC;AAEM,MAAM,8DAA8D,UAAU;AAAA,EAC1E,KAA2B;AAAA,EAAC;AAAA,EAE5B,OAA6B;AAAA,EAAC;AACzC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ import { declareQueryIndexReindex } from "@open-mercato/shared/lib/query/migration-reindex";
3
+ const queryIndexReindexEntityTypes = declareQueryIndexReindex([
4
+ "dictionaries:dictionary_entry"
5
+ ]);
6
+ class Migration20260901120000_reindex_dictionary_entries extends Migration {
7
+ up() {
8
+ }
9
+ down() {
10
+ }
11
+ }
12
+ export {
13
+ Migration20260901120000_reindex_dictionary_entries,
14
+ queryIndexReindexEntityTypes
15
+ };
16
+ //# sourceMappingURL=Migration20260901120000_reindex_dictionary_entries.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/dictionaries/migrations/Migration20260901120000_reindex_dictionary_entries.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\nimport { declareQueryIndexReindex } from '@open-mercato/shared/lib/query/migration-reindex';\n\n/**\n * Catch-up reindex for `Migration20260410171544`, which added `position` and `is_default` to\n * `dictionary_entries` and backfilled them in raw SQL. Documents written before that migration\n * were never rebuilt, so `entity_indexes.doc` for `dictionaries:dictionary_entry` is missing both\n * keys entirely rather than holding a stale value \u2014 the same absent emit, a different symptom.\n *\n * This migration executes no SQL \u2014 the declaration below is its entire payload.\n */\nexport const queryIndexReindexEntityTypes = declareQueryIndexReindex([\n 'dictionaries:dictionary_entry',\n]);\n\nexport class Migration20260901120000_reindex_dictionary_entries extends Migration {\n override up(): void | Promise<void> {}\n\n override down(): void | Promise<void> {}\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,gCAAgC;AAUlC,MAAM,+BAA+B,yBAAyB;AAAA,EACnE;AACF,CAAC;AAEM,MAAM,2DAA2D,UAAU;AAAA,EACvE,KAA2B;AAAA,EAAC;AAAA,EAE5B,OAA6B;AAAA,EAAC;AACzC;",
6
+ "names": []
7
+ }