@open-mercato/core 0.6.1-develop.3256.1.fe3dec2464 → 0.6.1-develop.3276.1.1fcd145078

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 (120) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/authFixtures.js.map +1 -1
  3. package/dist/helpers/integration/authUi.js +10 -2
  4. package/dist/helpers/integration/authUi.js.map +2 -2
  5. package/dist/helpers/integration/salesUi.js +3 -1
  6. package/dist/helpers/integration/salesUi.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
  8. package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
  9. package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
  10. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  11. package/dist/modules/auth/api/users/route.js +21 -3
  12. package/dist/modules/auth/api/users/route.js.map +2 -2
  13. package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
  14. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  15. package/dist/modules/auth/backend/users/create/page.js +4 -1
  16. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  17. package/dist/modules/auth/backend/users/page.js +56 -2
  18. package/dist/modules/auth/backend/users/page.js.map +3 -3
  19. package/dist/modules/auth/commands/users.js +14 -0
  20. package/dist/modules/auth/commands/users.js.map +2 -2
  21. package/dist/modules/auth/data/validators.js +8 -0
  22. package/dist/modules/auth/data/validators.js.map +2 -2
  23. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
  24. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  25. package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
  26. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  27. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
  28. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  29. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
  30. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  31. package/dist/modules/customers/components/PipelineSettings.js +108 -99
  32. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  33. package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
  34. package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
  35. package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
  36. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  37. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
  38. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  39. package/dist/modules/customers/components/detail/RolesSection.js +35 -22
  40. package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
  41. package/dist/modules/customers/components/detail/TasksSection.js +2 -2
  42. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  43. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
  44. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  45. package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
  46. package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
  47. package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
  48. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  49. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
  50. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  51. package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
  52. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  53. package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
  54. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  55. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
  56. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  57. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
  58. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
  59. package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
  60. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  61. package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
  62. package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
  63. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
  64. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  65. package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
  66. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  67. package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
  68. package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
  69. package/dist/modules/staff/components/TeamForm.js +1 -1
  70. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  71. package/dist/modules/staff/components/TeamMemberForm.js +1 -1
  72. package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
  73. package/dist/modules/staff/components/TeamRoleForm.js +1 -1
  74. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  75. package/package.json +5 -5
  76. package/src/helpers/integration/authFixtures.ts +1 -1
  77. package/src/helpers/integration/authUi.ts +11 -2
  78. package/src/helpers/integration/salesUi.ts +10 -1
  79. package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
  80. package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
  81. package/src/modules/auth/api/users/route.ts +22 -3
  82. package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
  83. package/src/modules/auth/backend/users/create/page.tsx +6 -2
  84. package/src/modules/auth/backend/users/page.tsx +60 -3
  85. package/src/modules/auth/commands/users.ts +15 -0
  86. package/src/modules/auth/data/validators.ts +8 -0
  87. package/src/modules/auth/i18n/de.json +4 -0
  88. package/src/modules/auth/i18n/en.json +4 -0
  89. package/src/modules/auth/i18n/es.json +4 -0
  90. package/src/modules/auth/i18n/pl.json +4 -0
  91. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
  92. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
  93. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
  94. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
  95. package/src/modules/customers/components/PipelineSettings.tsx +95 -95
  96. package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
  97. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
  98. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
  99. package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
  100. package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
  101. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
  102. package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
  103. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
  104. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
  105. package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
  106. package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
  107. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
  108. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
  109. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
  110. package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
  111. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
  112. package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
  113. package/src/modules/sales/i18n/de.json +2 -0
  114. package/src/modules/sales/i18n/en.json +2 -0
  115. package/src/modules/sales/i18n/es.json +2 -0
  116. package/src/modules/sales/i18n/pl.json +2 -0
  117. package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
  118. package/src/modules/staff/components/TeamForm.tsx +1 -1
  119. package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
  120. package/src/modules/staff/components/TeamRoleForm.tsx +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/detail/schedule/DateTimeFields.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Calendar, Clock, ChevronDown, Globe, Repeat } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport type { ActivityType, ScheduleFieldId } from './fieldConfig'\nimport { isVisible, getFieldLabel } from './fieldConfig'\n\nconst DURATION_OPTIONS = [15, 30, 45, 60, 90, 120]\nconst DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\ninterface DateTimeFieldsProps {\n visible: Set<ScheduleFieldId>\n activityType: ActivityType\n date: string\n setDate: (value: string) => void\n startTime: string\n setStartTime: (value: string) => void\n duration: number\n setDuration: (value: number) => void\n allDay: boolean\n setAllDay: (value: boolean) => void\n recurrenceEnabled: boolean\n setRecurrenceEnabled: (value: boolean) => void\n recurrenceDays: boolean[]\n toggleRecurrenceDay: (index: number) => void\n recurrenceEndType: 'never' | 'count' | 'date'\n setRecurrenceEndType: (value: 'never' | 'count' | 'date') => void\n recurrenceCount: number\n setRecurrenceCount: (value: number) => void\n recurrenceEndDate: string\n setRecurrenceEndDate: (value: string) => void\n}\n\nexport function DateTimeFields({\n visible,\n activityType,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n toggleRecurrenceDay,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n}: DateTimeFieldsProps) {\n const t = useT()\n\n if (!visible.has('date')) return null\n\n const showStartTime = isVisible(activityType, 'startTime')\n const showDuration = isVisible(activityType, 'duration')\n const showAllDay = isVisible(activityType, 'allDay')\n const showRecurrence = isVisible(activityType, 'recurrence')\n\n const dateMissing = !date.trim()\n const timeMissing = showStartTime && !allDay && !startTime.trim()\n const dateErrorId = 'schedule-date-error'\n const timeErrorId = 'schedule-time-error'\n\n return (\n <>\n {/* Date / Time / Duration */}\n <div className=\"flex gap-3\">\n <div className=\"flex flex-[2] flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'date', t, 'customers.schedule.date', 'Date')}\n <span aria-hidden=\"true\" className=\"ml-1 text-status-error-foreground\">*</span>\n </label>\n <div\n className={cn(\n 'flex items-center gap-2 rounded-md border bg-background px-3 py-2.5',\n dateMissing ? 'border-status-error-border' : 'border-border',\n )}\n >\n <Calendar className=\"size-3.5 text-muted-foreground\" />\n <input\n type=\"date\"\n value={date}\n onChange={(e) => setDate(e.target.value)}\n required\n aria-required=\"true\"\n aria-invalid={dateMissing ? true : undefined}\n aria-describedby={dateMissing ? dateErrorId : undefined}\n className=\"flex-1 bg-transparent text-sm text-foreground focus:outline-none\"\n />\n </div>\n {dateMissing ? (\n <p id={dateErrorId} className=\"text-xs text-status-error-foreground\">\n {t('customers.activities.errors.dateRequired', 'Date is required')}\n </p>\n ) : null}\n </div>\n {showStartTime && (\n <div className=\"flex flex-1 flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'startTime', t, 'customers.schedule.start', 'Start')}\n <span aria-hidden=\"true\" className=\"ml-1 text-status-error-foreground\">*</span>\n </label>\n <div\n className={cn(\n 'flex items-center gap-2 rounded-md border bg-background px-3 py-2.5',\n timeMissing ? 'border-status-error-border' : 'border-border',\n )}\n >\n <Clock className=\"size-3.5 text-muted-foreground\" />\n <input\n type=\"time\"\n value={startTime}\n onChange={(e) => setStartTime(e.target.value)}\n disabled={allDay}\n required={!allDay}\n aria-required={!allDay}\n aria-invalid={timeMissing ? true : undefined}\n aria-describedby={timeMissing ? timeErrorId : undefined}\n className=\"flex-1 bg-transparent text-sm text-foreground focus:outline-none disabled:opacity-50\"\n />\n </div>\n {timeMissing ? (\n <p id={timeErrorId} className=\"text-xs text-status-error-foreground\">\n {t('customers.activities.errors.timeRequired', 'Time is required')}\n </p>\n ) : null}\n </div>\n )}\n {showDuration && (\n <div className=\"flex flex-1 flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'duration', t, 'customers.schedule.duration', 'Duration')}\n </label>\n <div className=\"flex items-center gap-2 rounded-md border border-border bg-background px-3 py-2.5\">\n <select\n value={duration}\n onChange={(e) => setDuration(Number(e.target.value))}\n disabled={allDay}\n className=\"flex-1 appearance-none bg-transparent text-sm text-foreground focus:outline-none disabled:opacity-50\"\n >\n {DURATION_OPTIONS.map((m) => (\n <option key={m} value={m}>{m} min</option>\n ))}\n </select>\n <ChevronDown className=\"size-3.5 text-muted-foreground\" />\n </div>\n </div>\n )}\n </div>\n\n {/* All day + timezone + recurrence */}\n {showAllDay && (\n <div className=\"flex flex-wrap items-center gap-3.5 text-xs text-muted-foreground\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input type=\"checkbox\" checked={allDay} onChange={(e) => setAllDay(e.target.checked)} className=\"rounded\" />\n {t('customers.schedule.allDay', 'All day')}\n </label>\n <span className=\"text-muted-foreground\">&middot;</span>\n <span className=\"flex items-center gap-1.5\">\n <Globe className=\"size-3.5\" />\n {Intl.DateTimeFormat().resolvedOptions().timeZone} (GMT{new Date().getTimezoneOffset() <= 0 ? '+' : '-'}{String(Math.abs(Math.floor(new Date().getTimezoneOffset() / 60))).padStart(1, '0')})\n </span>\n {showRecurrence && (\n <>\n <span className=\"text-muted-foreground\">&middot;</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setRecurrenceEnabled(!recurrenceEnabled)}\n className={cn('h-auto flex items-center gap-1.5', recurrenceEnabled && 'font-medium text-foreground')}\n >\n <Repeat className=\"size-3.5\" />\n {recurrenceEnabled\n ? t('customers.schedule.recurrence.active', 'Repeats')\n : t('customers.schedule.recurrence.none', 'No repeat')}\n </Button>\n </>\n )}\n </div>\n )}\n\n {/* Recurrence config */}\n {showRecurrence && recurrenceEnabled && (\n <div className=\"rounded-lg border border-status-warning-border bg-status-warning-bg p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Repeat className=\"size-3.5\" />\n {t('customers.schedule.recurrence.title', 'Recurrence')}\n </span>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"h-auto text-xs font-medium text-foreground\">\n {t('customers.schedule.recurrence.edit', 'Edit')}\n </Button>\n </div>\n <div className=\"flex gap-2\">\n {DAYS_OF_WEEK.map((day, i) => (\n <Button\n key={day}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => toggleRecurrenceDay(i)}\n className={cn(\n 'h-auto flex size-8 items-center justify-center rounded-full text-xs font-medium transition-colors p-0',\n recurrenceDays[i] ? 'bg-primary text-primary-foreground' : 'border border-border bg-background text-muted-foreground hover:bg-muted',\n )}\n >\n {day.slice(0, 2)}\n </Button>\n ))}\n </div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{t('customers.schedule.recurrence.ends', 'Ends')}:</span>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('never')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'never' ? 'bg-background border border-border text-foreground' : 'text-muted-foreground')}>\n {t('customers.schedule.recurrence.never', 'Never')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('count')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'count' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground')}>\n {t('customers.schedule.recurrence.afterCount', 'After {{count}} occurrences', { count: recurrenceCount })}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('date')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'date' ? 'bg-background border border-border text-foreground' : 'text-muted-foreground')}>\n {recurrenceEndDate || t('customers.schedule.recurrence.onDate', 'On date')}\n </Button>\n </div>\n </div>\n )}\n </>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Globe, Repeat } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DatePicker } from '@open-mercato/ui/primitives/date-picker'\nimport { TimePicker } from '@open-mercato/ui/backend/inputs/TimePicker'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport type { ActivityType, ScheduleFieldId } from './fieldConfig'\nimport { isVisible, getFieldLabel } from './fieldConfig'\n\nfunction parseIsoDate(value: string): Date | null {\n if (!value) return null\n const parts = value.split('-')\n if (parts.length !== 3) return null\n const [y, m, d] = parts.map((p) => parseInt(p, 10))\n if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) return null\n const date = new Date(y, m - 1, d)\n return Number.isNaN(date.getTime()) ? null : date\n}\n\nfunction formatIsoDate(date: Date | null): string {\n if (!date) return ''\n const y = date.getFullYear()\n const m = String(date.getMonth() + 1).padStart(2, '0')\n const d = String(date.getDate()).padStart(2, '0')\n return `${y}-${m}-${d}`\n}\n\nconst DURATION_OPTIONS: Array<{ value: number; key: string; fallback: string }> = [\n { value: 15, key: 'customers.schedule.duration.option.15min', fallback: '15 min' },\n { value: 30, key: 'customers.schedule.duration.option.30min', fallback: '30 min' },\n { value: 45, key: 'customers.schedule.duration.option.45min', fallback: '45 min' },\n { value: 60, key: 'customers.schedule.duration.option.1hour', fallback: '1 hour' },\n { value: 90, key: 'customers.schedule.duration.option.1h30m', fallback: '1h 30m' },\n { value: 120, key: 'customers.schedule.duration.option.2hours', fallback: '2 hours' },\n]\nconst DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\ninterface DateTimeFieldsProps {\n visible: Set<ScheduleFieldId>\n activityType: ActivityType\n date: string\n setDate: (value: string) => void\n startTime: string\n setStartTime: (value: string) => void\n duration: number\n setDuration: (value: number) => void\n allDay: boolean\n setAllDay: (value: boolean) => void\n recurrenceEnabled: boolean\n setRecurrenceEnabled: (value: boolean) => void\n recurrenceDays: boolean[]\n toggleRecurrenceDay: (index: number) => void\n recurrenceEndType: 'never' | 'count' | 'date'\n setRecurrenceEndType: (value: 'never' | 'count' | 'date') => void\n recurrenceCount: number\n setRecurrenceCount: (value: number) => void\n recurrenceEndDate: string\n setRecurrenceEndDate: (value: string) => void\n}\n\nexport function DateTimeFields({\n visible,\n activityType,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n toggleRecurrenceDay,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n}: DateTimeFieldsProps) {\n const t = useT()\n\n if (!visible.has('date')) return null\n\n const showStartTime = isVisible(activityType, 'startTime')\n const showDuration = isVisible(activityType, 'duration')\n const showAllDay = isVisible(activityType, 'allDay')\n const showRecurrence = isVisible(activityType, 'recurrence')\n\n const dateMissing = !date.trim()\n const timeMissing = showStartTime && !allDay && !startTime.trim()\n const dateErrorId = 'schedule-date-error'\n const timeErrorId = 'schedule-time-error'\n\n return (\n <>\n {/* Date / Time / Duration */}\n <div className=\"flex flex-wrap gap-3\">\n <div className=\"flex min-w-0 flex-[1.5] flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'date', t, 'customers.schedule.date', 'Date')}\n <span aria-hidden=\"true\" className=\"ml-1 text-status-error-foreground\">*</span>\n </label>\n <DatePicker\n value={parseIsoDate(date)}\n onChange={(next) => setDate(formatIsoDate(next))}\n placeholder={t('customers.schedule.date.placeholder', 'Pick a date')}\n required\n aria-describedby={dateMissing ? dateErrorId : undefined}\n className={cn(\n 'h-10',\n dateMissing && 'border-status-error-border',\n )}\n />\n {dateMissing ? (\n <p id={dateErrorId} className=\"text-xs text-status-error-foreground\">\n {t('customers.activities.errors.dateRequired', 'Date is required')}\n </p>\n ) : null}\n </div>\n {showStartTime && (\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'startTime', t, 'customers.schedule.start', 'Start')}\n <span aria-hidden=\"true\" className=\"ml-1 text-status-error-foreground\">*</span>\n </label>\n <TimePicker\n value={startTime || null}\n onChange={(next) => setStartTime(next ?? '')}\n disabled={allDay}\n placeholder={t('customers.schedule.start.placeholder', 'Pick a time')}\n className={cn(\n 'py-2.5',\n timeMissing ? 'border-status-error-border' : undefined,\n )}\n showNowButton\n showClearButton={false}\n />\n {timeMissing ? (\n <p id={timeErrorId} className=\"text-xs text-status-error-foreground\">\n {t('customers.activities.errors.timeRequired', 'Time is required')}\n </p>\n ) : null}\n </div>\n )}\n {showDuration && (\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(activityType, 'duration', t, 'customers.schedule.duration', 'Duration')}\n </label>\n <Select\n value={String(duration)}\n onValueChange={(next) => {\n const parsed = Number(next)\n if (Number.isFinite(parsed)) setDuration(parsed)\n }}\n disabled={allDay}\n >\n <SelectTrigger className=\"h-10\">\n <SelectValue placeholder={t('customers.schedule.duration.placeholder', 'Pick duration')} />\n </SelectTrigger>\n <SelectContent>\n {DURATION_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={String(option.value)}>\n {t(option.key, option.fallback)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n </div>\n\n {/* All day + timezone + recurrence */}\n {showAllDay && (\n <div className=\"flex flex-wrap items-center gap-3.5 text-xs text-muted-foreground\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input type=\"checkbox\" checked={allDay} onChange={(e) => setAllDay(e.target.checked)} className=\"rounded\" />\n {t('customers.schedule.allDay', 'All day')}\n </label>\n <span className=\"text-muted-foreground\">&middot;</span>\n <span className=\"flex items-center gap-1.5\">\n <Globe className=\"size-3.5\" />\n {Intl.DateTimeFormat().resolvedOptions().timeZone} (GMT{new Date().getTimezoneOffset() <= 0 ? '+' : '-'}{String(Math.abs(Math.floor(new Date().getTimezoneOffset() / 60))).padStart(1, '0')})\n </span>\n {showRecurrence && (\n <>\n <span className=\"text-muted-foreground\">&middot;</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setRecurrenceEnabled(!recurrenceEnabled)}\n className={cn('h-auto flex items-center gap-1.5', recurrenceEnabled && 'font-medium text-foreground')}\n >\n <Repeat className=\"size-3.5\" />\n {recurrenceEnabled\n ? t('customers.schedule.recurrence.active', 'Repeats')\n : t('customers.schedule.recurrence.none', 'No repeat')}\n </Button>\n </>\n )}\n </div>\n )}\n\n {/* Recurrence config */}\n {showRecurrence && recurrenceEnabled && (\n <div className=\"rounded-lg border border-status-warning-border bg-status-warning-bg p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Repeat className=\"size-3.5\" />\n {t('customers.schedule.recurrence.title', 'Recurrence')}\n </span>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"h-auto text-xs font-medium text-foreground\">\n {t('customers.schedule.recurrence.edit', 'Edit')}\n </Button>\n </div>\n <div className=\"flex gap-2\">\n {DAYS_OF_WEEK.map((day, i) => (\n <Button\n key={day}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => toggleRecurrenceDay(i)}\n className={cn(\n 'h-auto flex size-8 items-center justify-center rounded-full text-xs font-medium transition-colors p-0',\n recurrenceDays[i] ? 'bg-primary text-primary-foreground' : 'border border-border bg-background text-muted-foreground hover:bg-muted',\n )}\n >\n {day.slice(0, 2)}\n </Button>\n ))}\n </div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{t('customers.schedule.recurrence.ends', 'Ends')}:</span>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('never')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'never' ? 'bg-background border border-border text-foreground' : 'text-muted-foreground')}>\n {t('customers.schedule.recurrence.never', 'Never')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('count')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'count' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground')}>\n {t('customers.schedule.recurrence.afterCount', 'After {{count}} occurrences', { count: recurrenceCount })}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setRecurrenceEndType('date')} className={cn('h-auto rounded-full px-3 py-1 text-xs font-medium', recurrenceEndType === 'date' ? 'bg-background border border-border text-foreground' : 'text-muted-foreground')}>\n {recurrenceEndDate || t('customers.schedule.recurrence.onDate', 'On date')}\n </Button>\n </div>\n </div>\n )}\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -6,8 +6,10 @@ import {
6
6
  Link2,
7
7
  Loader2,
8
8
  Plus,
9
- Search
9
+ Search,
10
+ SearchX
10
11
  } from "lucide-react";
12
+ import { EmptyState } from "@open-mercato/ui/primitives/empty-state";
11
13
  import { cn } from "@open-mercato/shared/lib/utils";
12
14
  import { useT } from "@open-mercato/shared/lib/i18n/context";
13
15
  import { Avatar } from "@open-mercato/ui/primitives/avatar";
@@ -432,7 +434,14 @@ function LinkEntityDialog({
432
434
  searchLoading && displayedResults.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground", children: [
433
435
  /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }),
434
436
  t("customers.linking.searching", "Searching\u2026")
435
- ] }) : displayedResults.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground", children: adapter.searchEmptyHint }) : displayedResults.map((result) => {
437
+ ] }) : displayedResults.length === 0 ? /* @__PURE__ */ jsx(
438
+ EmptyState,
439
+ {
440
+ size: "sm",
441
+ icon: /* @__PURE__ */ jsx(SearchX, { className: "h-8 w-8", "aria-hidden": "true" }),
442
+ title: adapter.searchEmptyHint
443
+ }
444
+ ) : displayedResults.map((result) => {
436
445
  const checked = draftSet.has(result.id);
437
446
  const focused = focusedId === result.id;
438
447
  const ctx = { selected: checked, focused };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/linking/LinkEntityDialog.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport {\n Check,\n Link2,\n Loader2,\n Plus,\n Search,\n X,\n} from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\n\nexport type LinkEntityKind = 'company' | 'person' | 'deal'\n\nexport type LinkEntityOption = {\n id: string\n label: string\n subtitle?: string | null\n avatarSeed?: string | null\n icon?: React.ReactNode\n meta?: Record<string, unknown>\n}\n\nexport type LinkEntitySearchPage = {\n items: LinkEntityOption[]\n totalPages: number\n total?: number\n}\n\nexport type LinkEntityFilterOption = {\n id: string\n label: string\n count?: number\n dotColor?: string\n}\n\nexport type LinkEntityRowContext = {\n selected: boolean\n focused: boolean\n disabled?: boolean\n}\n\nexport type LinkEntityAdapter<TDetails = unknown, TLinkSettings = Record<string, unknown>> = {\n kind: LinkEntityKind\n searchPage: (\n query: string,\n page: number,\n filterId?: string,\n ) => Promise<LinkEntitySearchPage>\n fetchByIds: (ids: string[]) => Promise<LinkEntityOption[]>\n fetchDetails?: (id: string) => Promise<TDetails>\n\n dialogTitle: string\n dialogSubtitle?: string\n headerIcon?: React.ReactNode\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n defaultAvatarIcon?: React.ReactNode\n\n filters?: {\n options: LinkEntityFilterOption[]\n defaultId?: string\n /**\n * Optional client-side predicate applied AFTER the server response.\n * Return true to keep the option when the given filter id is active.\n * When not provided, all items pass regardless of filter (filter effectively\n * only applies server-side via searchPage's third argument).\n */\n clientFilter?: (option: LinkEntityOption, filterId: string) => boolean\n }\n\n renderRow?: (\n option: LinkEntityOption,\n ctx: LinkEntityRowContext,\n ) => React.ReactNode\n renderPreview?: (option: LinkEntityOption, details?: TDetails) => React.ReactNode\n renderLinkSettings?: (\n settings: TLinkSettings,\n onChange: (next: TLinkSettings) => void,\n focusedOption: LinkEntityOption | null,\n ) => React.ReactNode\n initialLinkSettings?: TLinkSettings\n\n computeOrphanWarning?: (option: LinkEntityOption) => Promise<string | null>\n\n addNew?: {\n title: string\n subtitle?: string\n render: (ctx: {\n onCreated: (created: LinkEntityOption) => void\n onCancel: () => void\n }) => React.ReactNode\n }\n}\n\nexport type LinkEntityConfirmInput<TLinkSettings = Record<string, unknown>> = {\n addedIds: string[]\n removedIds: string[]\n nextSelectedIds: string[]\n primaryId?: string | null\n optionsById: Record<string, LinkEntityOption>\n linkSettings?: TLinkSettings\n}\n\ntype GuardedMutationRunner = <T,>(\n operation: () => Promise<T>,\n mutationPayload?: Record<string, unknown>,\n) => Promise<T>\n\nexport type LinkEntityDialogProps<TDetails = unknown, TLinkSettings = Record<string, unknown>> = {\n open: boolean\n onOpenChange: (open: boolean) => void\n adapter: LinkEntityAdapter<TDetails, TLinkSettings>\n initialSelectedIds: string[]\n initialPrimaryId?: string | null\n primarySupported?: boolean\n onConfirm: (next: LinkEntityConfirmInput<TLinkSettings>) => Promise<void>\n runGuardedMutation?: GuardedMutationRunner\n avatarVariant?: 'default' | 'monochrome'\n}\n\nconst SEARCH_DEBOUNCE_MS = 200\n\nfunction diffSelection(initial: string[], next: string[]): { addedIds: string[]; removedIds: string[] } {\n const initialSet = new Set(initial)\n const nextSet = new Set(next)\n const addedIds: string[] = []\n const removedIds: string[] = []\n next.forEach((id) => {\n if (!initialSet.has(id)) addedIds.push(id)\n })\n initial.forEach((id) => {\n if (!nextSet.has(id)) removedIds.push(id)\n })\n return { addedIds, removedIds }\n}\n\nfunction sameIds(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false\n const rightSet = new Set(right)\n return left.every((value) => rightSet.has(value))\n}\n\nfunction mergeOptionMaps(\n existing: Map<string, LinkEntityOption>,\n entries: LinkEntityOption[],\n): Map<string, LinkEntityOption> {\n const next = new Map(existing)\n entries.forEach((entry) => next.set(entry.id, entry))\n return next\n}\n\ntype SelectionIndicatorProps = {\n checked: boolean\n disabled?: boolean\n label: string\n}\n\nfunction SelectionIndicator({ checked, disabled, label }: SelectionIndicatorProps) {\n return (\n <span\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled || undefined}\n aria-label={label}\n className={cn(\n 'inline-flex size-6 shrink-0 items-center justify-center rounded-full border transition-colors',\n checked\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n disabled && 'opacity-50',\n )}\n >\n {checked ? <Check className=\"size-3\" strokeWidth={2.5} /> : null}\n </span>\n )\n}\n\ntype DefaultRowProps = {\n option: LinkEntityOption\n ctx: LinkEntityRowContext\n avatarVariant: 'default' | 'monochrome'\n defaultAvatarIcon?: React.ReactNode\n selectLabel: string\n}\n\nfunction DefaultRow({\n option,\n ctx,\n avatarVariant,\n defaultAvatarIcon,\n selectLabel,\n}: DefaultRowProps) {\n return (\n <>\n <Avatar\n label={option.label}\n variant={avatarVariant}\n size=\"md\"\n icon={option.icon ?? defaultAvatarIcon}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-semibold text-foreground\">{option.label}</div>\n {option.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">{option.subtitle}</div>\n ) : null}\n </div>\n <SelectionIndicator checked={ctx.selected} label={selectLabel} />\n </>\n )\n}\n\nexport function LinkEntityDialog<TDetails = unknown, TLinkSettings = Record<string, unknown>>({\n open,\n onOpenChange,\n adapter,\n initialSelectedIds,\n initialPrimaryId,\n primarySupported = false,\n onConfirm,\n avatarVariant = 'monochrome',\n}: LinkEntityDialogProps<TDetails, TLinkSettings>) {\n const t = useT()\n const [query, setQuery] = React.useState('')\n const [activeFilter, setActiveFilter] = React.useState<string | undefined>(\n adapter.filters?.defaultId,\n )\n const [searchPage, setSearchPage] = React.useState(1)\n const [searchTotalPages, setSearchTotalPages] = React.useState(1)\n const [searchTotal, setSearchTotal] = React.useState<number | null>(null)\n const [searchResults, setSearchResults] = React.useState<LinkEntityOption[]>([])\n const [searchLoading, setSearchLoading] = React.useState(false)\n const [draftIds, setDraftIds] = React.useState<string[]>(initialSelectedIds)\n const [draftPrimaryId, setDraftPrimaryId] = React.useState<string | null>(\n initialPrimaryId ?? null,\n )\n const [focusedId, setFocusedId] = React.useState<string | null>(null)\n const [optionCache, setOptionCache] = React.useState<Map<string, LinkEntityOption>>(\n () => new Map(),\n )\n const [details, setDetails] = React.useState<Record<string, TDetails>>({})\n const [detailsLoadingId, setDetailsLoadingId] = React.useState<string | null>(null)\n const [linkSettings, setLinkSettings] = React.useState<TLinkSettings>(\n adapter.initialLinkSettings ?? ({} as TLinkSettings),\n )\n const [saving, setSaving] = React.useState(false)\n const [nestedOpen, setNestedOpen] = React.useState(false)\n const requestIdRef = React.useRef(0)\n\n const initialIdsKey = React.useMemo(() => initialSelectedIds.join('|'), [initialSelectedIds])\n\n React.useEffect(() => {\n if (!open) return\n setDraftIds(initialSelectedIds)\n setDraftPrimaryId(initialPrimaryId ?? null)\n setQuery('')\n setActiveFilter(adapter.filters?.defaultId)\n setSearchPage(1)\n setSearchTotalPages(1)\n setSearchTotal(null)\n setSearchResults([])\n setFocusedId(null)\n setDetails({})\n setDetailsLoadingId(null)\n setLinkSettings(adapter.initialLinkSettings ?? ({} as TLinkSettings))\n setNestedOpen(false)\n }, [open, initialIdsKey, initialPrimaryId, adapter])\n\n React.useEffect(() => {\n if (!open) return\n setSearchPage(1)\n }, [open, query, activeFilter])\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n const current = ++requestIdRef.current\n setSearchLoading(true)\n const timeout = window.setTimeout(async () => {\n try {\n const result = await adapter.searchPage(query, searchPage, activeFilter)\n if (cancelled || current !== requestIdRef.current) return\n setSearchResults(result.items)\n setSearchTotalPages(Math.max(1, result.totalPages))\n setSearchTotal(typeof result.total === 'number' ? result.total : null)\n setOptionCache((prev) => mergeOptionMaps(prev, result.items))\n } catch {\n if (cancelled || current !== requestIdRef.current) return\n setSearchResults([])\n setSearchTotalPages(1)\n setSearchTotal(0)\n } finally {\n if (!cancelled && current === requestIdRef.current) {\n setSearchLoading(false)\n }\n }\n }, SEARCH_DEBOUNCE_MS)\n return () => {\n cancelled = true\n window.clearTimeout(timeout)\n }\n }, [adapter, activeFilter, open, query, searchPage])\n\n React.useEffect(() => {\n if (!open) return\n const missingIds = draftIds.filter((id) => !optionCache.has(id))\n if (!missingIds.length) return\n let cancelled = false\n void adapter\n .fetchByIds(missingIds)\n .then((entries) => {\n if (cancelled) return\n setOptionCache((prev) => mergeOptionMaps(prev, entries))\n })\n .catch((error) => console.warn('[LinkEntityDialog] fetchByIds failed', error))\n return () => {\n cancelled = true\n }\n }, [adapter, draftIds, open, optionCache])\n\n const focusedOption: LinkEntityOption | null = React.useMemo(\n () => (focusedId ? optionCache.get(focusedId) ?? null : null),\n [focusedId, optionCache],\n )\n\n const fetchDetails = adapter.fetchDetails\n React.useEffect(() => {\n if (!open || !focusedId || !fetchDetails) return\n if (details[focusedId] !== undefined) return\n let cancelled = false\n setDetailsLoadingId(focusedId)\n void fetchDetails(focusedId)\n .then((result) => {\n if (cancelled) return\n setDetails((prev) => ({ ...prev, [focusedId]: result }))\n })\n .catch((error) => console.warn('[LinkEntityDialog] fetchDetails failed', error))\n .finally(() => {\n if (!cancelled) setDetailsLoadingId(null)\n })\n return () => {\n cancelled = true\n }\n }, [details, fetchDetails, focusedId, open])\n\n const draftSet = React.useMemo(() => new Set(draftIds), [draftIds])\n\n const displayedResults = React.useMemo(() => {\n const predicate = adapter.filters?.clientFilter\n const effectiveFilter = activeFilter ?? adapter.filters?.defaultId\n if (!predicate || !effectiveFilter) return searchResults\n return searchResults.filter((option) => predicate(option, effectiveFilter))\n }, [adapter.filters, activeFilter, searchResults])\n\n const selectedOptions = React.useMemo(\n () =>\n draftIds.map((id) => optionCache.get(id) ?? { id, label: id }).filter((entry): entry is LinkEntityOption => Boolean(entry)),\n [draftIds, optionCache],\n )\n\n React.useEffect(() => {\n if (!primarySupported) return\n setDraftPrimaryId((current) => {\n const normalizedCurrent = current ?? null\n if (draftIds.length === 0) return null\n if (normalizedCurrent && draftIds.includes(normalizedCurrent)) return normalizedCurrent\n return draftIds[0]\n })\n }, [draftIds, primarySupported])\n\n const toggleDraftId = React.useCallback((id: string, checked: boolean) => {\n setDraftIds((current) => {\n if (checked) {\n if (current.includes(id)) return current\n return [...current, id]\n }\n return current.filter((candidate) => candidate !== id)\n })\n }, [])\n\n const handleRowClick = React.useCallback(\n (option: LinkEntityOption) => {\n setFocusedId(option.id)\n const isSelected = draftSet.has(option.id)\n toggleDraftId(option.id, !isSelected)\n },\n [draftSet, toggleDraftId],\n )\n\n const handleAddNewCreated = React.useCallback(\n (option: LinkEntityOption) => {\n setOptionCache((prev) => mergeOptionMaps(prev, [option]))\n setDraftIds((current) => (current.includes(option.id) ? current : [...current, option.id]))\n setFocusedId(option.id)\n setNestedOpen(false)\n },\n [],\n )\n\n const handleDialogOpenChange = React.useCallback(\n (next: boolean) => {\n if (nestedOpen && !next) return\n onOpenChange(next)\n },\n [nestedOpen, onOpenChange],\n )\n\n const handleSetPrimary = React.useCallback(\n (id: string) => {\n if (!primarySupported || !draftSet.has(id)) return\n setDraftPrimaryId(id)\n setFocusedId(id)\n },\n [draftSet, primarySupported],\n )\n\n const hasChanges = React.useMemo(() => {\n if (!sameIds(initialSelectedIds, draftIds)) return true\n if (primarySupported && (draftPrimaryId ?? null) !== (initialPrimaryId ?? null)) return true\n return false\n }, [draftIds, draftPrimaryId, initialPrimaryId, initialSelectedIds, primarySupported])\n\n const handleSave = React.useCallback(async () => {\n if (saving) return\n const { addedIds, removedIds } = diffSelection(initialSelectedIds, draftIds)\n const primaryChanged = primarySupported\n ? (draftPrimaryId ?? null) !== (initialPrimaryId ?? null)\n : false\n if (!addedIds.length && !removedIds.length && !primaryChanged) {\n onOpenChange(false)\n return\n }\n setSaving(true)\n try {\n const optionsById: Record<string, LinkEntityOption> = {}\n optionCache.forEach((value, key) => {\n optionsById[key] = value\n })\n await onConfirm({\n addedIds,\n removedIds,\n nextSelectedIds: draftIds,\n primaryId: primarySupported ? draftPrimaryId : undefined,\n optionsById,\n linkSettings,\n })\n onOpenChange(false)\n } finally {\n setSaving(false)\n }\n }, [\n draftIds,\n draftPrimaryId,\n initialPrimaryId,\n initialSelectedIds,\n linkSettings,\n onConfirm,\n onOpenChange,\n optionCache,\n primarySupported,\n saving,\n ])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (nestedOpen) return\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSave()\n return\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n handleDialogOpenChange(false)\n }\n },\n [handleDialogOpenChange, handleSave, nestedOpen],\n )\n\n const selectedCountLabel = React.useMemo(() => {\n const kindLabels: Record<LinkEntityKind, [string, string, string, string]> = {\n person: [\n 'customers.linking.footer.personSingular',\n '{{count}} person selected',\n 'customers.linking.footer.personPlural',\n '{{count}} people selected',\n ],\n company: [\n 'customers.linking.footer.companySingular',\n '{{count}} company selected',\n 'customers.linking.footer.companyPlural',\n '{{count}} companies selected',\n ],\n deal: [\n 'customers.linking.footer.dealSingular',\n '{{count}} deal selected',\n 'customers.linking.footer.dealPlural',\n '{{count}} deals selected',\n ],\n }\n const [singularKey, singularDefault, pluralKey, pluralDefault] = kindLabels[adapter.kind]\n if (draftIds.length === 1) {\n return t(singularKey, singularDefault, { count: String(draftIds.length) })\n }\n return t(pluralKey, pluralDefault, { count: String(draftIds.length) })\n }, [adapter.kind, draftIds.length, t])\n\n const filterOptions = adapter.filters?.options ?? []\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleDialogOpenChange}>\n <DialogContent\n className=\"flex flex-col gap-0 overflow-hidden p-0\"\n style={{\n width: 'min(calc(100vw - 2rem), 920px)',\n maxWidth: 'min(calc(100vw - 2rem), 920px)',\n maxHeight: 'min(640px, calc(100vh - 4rem))',\n }}\n onKeyDown={handleKeyDown}\n aria-hidden={nestedOpen ? 'true' : undefined}\n >\n <DialogHeader className=\"flex flex-row items-center gap-3 space-y-0 border-b border-border/70 bg-card px-6 py-5\">\n {adapter.headerIcon ? (\n <div className=\"flex size-6 shrink-0 items-center justify-center text-foreground\">\n {adapter.headerIcon}\n </div>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <DialogTitle className=\"text-lg font-bold text-foreground\">\n {adapter.dialogTitle}\n </DialogTitle>\n {adapter.dialogSubtitle ? (\n <DialogDescription className=\"mt-0.5 text-sm text-muted-foreground\">\n {adapter.dialogSubtitle}\n </DialogDescription>\n ) : null}\n </div>\n </DialogHeader>\n\n <div className=\"flex min-h-0 flex-1 flex-col lg:flex-row\">\n <div className=\"flex min-h-0 flex-col gap-3 border-b border-border/70 bg-card p-4 lg:w-[480px] lg:shrink-0 lg:border-b-0 lg:border-r\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={adapter.searchPlaceholder}\n className=\"h-10 rounded-md pl-9 pr-20 text-sm\"\n autoFocus\n aria-label={adapter.searchPlaceholder}\n />\n {searchTotal !== null && !searchLoading ? (\n <span className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground\">\n {t('customers.linking.resultsCount', '{{count}} results', {\n count: String(searchTotal),\n })}\n </span>\n ) : null}\n </div>\n\n {filterOptions.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filterOptions.map((filter) => {\n const isActive = (activeFilter ?? adapter.filters?.defaultId) === filter.id\n return (\n <button\n key={filter.id}\n type=\"button\"\n onClick={() => setActiveFilter(filter.id)}\n className={cn(\n 'inline-flex h-6 items-center gap-1.5 rounded-full px-2.5 text-xs font-semibold transition-colors',\n isActive\n ? 'bg-foreground text-background'\n : 'bg-muted/70 text-muted-foreground hover:bg-muted',\n )}\n >\n {filter.dotColor ? (\n <span\n aria-hidden=\"true\"\n className=\"inline-block size-1.5 rounded-full\"\n style={{ backgroundColor: filter.dotColor }}\n />\n ) : null}\n <span>{filter.label}</span>\n {typeof filter.count === 'number' ? (\n <span\n className={cn(\n 'inline-flex min-w-[14px] items-center justify-center rounded-full px-1 text-xs',\n isActive\n ? 'bg-background/20 text-background'\n : 'bg-background text-muted-foreground',\n )}\n >\n {filter.count}\n </span>\n ) : null}\n </button>\n )\n })}\n </div>\n ) : null}\n\n {adapter.sectionLabel ? (\n <div className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {adapter.sectionLabel}\n </div>\n ) : null}\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n {searchLoading && displayedResults.length === 0 ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"size-4 animate-spin\" />\n {t('customers.linking.searching', 'Searching\u2026')}\n </div>\n ) : displayedResults.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground\">\n {adapter.searchEmptyHint}\n </div>\n ) : (\n displayedResults.map((result) => {\n const checked = draftSet.has(result.id)\n const focused = focusedId === result.id\n const ctx: LinkEntityRowContext = { selected: checked, focused }\n const selectLabel = t('customers.linking.selectEntity', 'Select {{name}}', {\n name: result.label,\n })\n return (\n <div\n key={result.id}\n role=\"button\"\n tabIndex={0}\n aria-pressed={checked}\n onClick={() => handleRowClick(result)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleRowClick(result)\n }\n }}\n className={cn(\n 'group flex cursor-pointer items-center gap-3 rounded-lg border px-3.5 py-3 transition-colors focus:outline-none focus:ring-2 focus:ring-ring/40',\n checked\n ? 'border-border bg-muted/50'\n : 'border-border/70 bg-card hover:bg-muted/30',\n )}\n >\n {adapter.renderRow ? (\n adapter.renderRow(result, ctx)\n ) : (\n <DefaultRow\n option={result}\n ctx={ctx}\n avatarVariant={avatarVariant}\n defaultAvatarIcon={adapter.defaultAvatarIcon}\n selectLabel={selectLabel}\n />\n )}\n </div>\n )\n })\n )}\n\n {adapter.addNew ? (\n <button\n type=\"button\"\n onClick={() => setNestedOpen(true)}\n className=\"mt-2 flex items-center gap-3 rounded-lg border border-dashed border-border px-4 py-3.5 text-left transition-colors hover:bg-muted/30 focus:outline-none focus:ring-2 focus:ring-ring/40\"\n >\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground\">\n <Plus className=\"size-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-foreground\">\n {adapter.addNew.title}\n </span>\n {adapter.addNew.subtitle ? (\n <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n {adapter.addNew.subtitle}\n </span>\n ) : null}\n </span>\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-foreground text-background\">\n <Plus className=\"size-3.5\" />\n </span>\n </button>\n ) : null}\n\n {searchTotalPages > 1 ? (\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n <span aria-live=\"polite\">\n {t('customers.linking.pagination.pageOf', 'Page {{page}} of {{total}}', {\n page: String(Math.min(searchPage, searchTotalPages)),\n total: String(searchTotalPages),\n })}\n </span>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8 rounded-md px-2.5 text-xs\"\n disabled={searchLoading || searchPage <= 1}\n onClick={() => setSearchPage((current) => Math.max(1, current - 1))}\n >\n {t('customers.linking.pagination.previousShort', 'Previous')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8 rounded-md px-2.5 text-xs\"\n disabled={searchLoading || searchPage >= searchTotalPages}\n onClick={() =>\n setSearchPage((current) => Math.min(searchTotalPages, current + 1))\n }\n >\n {t('customers.linking.pagination.nextShort', 'Next')}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-auto bg-muted/20 p-5\">\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"mb-3 text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.selected.label', 'Selected')}\n </div>\n {selectedOptions.length > 0 ? (\n <div className=\"space-y-2\">\n {selectedOptions.map((option) => {\n const isPrimary = primarySupported && draftPrimaryId === option.id\n return (\n <div\n key={option.id}\n className={cn(\n 'flex items-center gap-3 rounded-lg border px-3 py-2.5 transition-colors',\n focusedId === option.id\n ? 'border-border bg-muted/50'\n : 'border-border/70 bg-card',\n )}\n >\n <button\n type=\"button\"\n onClick={() => setFocusedId(option.id)}\n className=\"flex min-w-0 flex-1 items-center gap-3 text-left\"\n >\n <Avatar\n label={option.label}\n variant={avatarVariant}\n size=\"sm\"\n icon={option.icon ?? adapter.defaultAvatarIcon}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {option.subtitle ? (\n <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n {option.subtitle}\n </span>\n ) : null}\n </span>\n </button>\n {primarySupported ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant={isPrimary ? 'default' : 'outline'}\n className=\"h-7 rounded-full px-3 text-xs\"\n onClick={() => handleSetPrimary(option.id)}\n disabled={isPrimary}\n >\n {isPrimary\n ? t('customers.linking.primary.current', 'Primary')\n : t('customers.linking.primary.set', 'Set primary')}\n </Button>\n ) : null}\n </div>\n )\n })}\n </div>\n ) : (\n <div className=\"rounded-lg border border-dashed border-border/70 px-4 py-4 text-sm text-muted-foreground\">\n {adapter.selectedEmptyHint}\n </div>\n )}\n {primarySupported && selectedOptions.length > 0 ? (\n <div className=\"mt-3 text-xs text-muted-foreground\">\n {t(\n 'customers.linking.primary.help',\n 'Choose which linked company should remain primary.',\n )}\n </div>\n ) : null}\n </div>\n\n <div className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.preview.label', 'Preview')}\n </div>\n\n {focusedOption ? (\n <>\n {adapter.renderPreview ? (\n adapter.renderPreview(focusedOption, details[focusedOption.id])\n ) : (\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar\n label={focusedOption.label}\n variant={avatarVariant}\n size=\"lg\"\n icon={focusedOption.icon ?? adapter.defaultAvatarIcon}\n />\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-bold text-foreground\">\n {focusedOption.label}\n </div>\n {focusedOption.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {focusedOption.subtitle}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n )}\n {detailsLoadingId === focusedOption.id && adapter.fetchDetails ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" />\n {t('customers.linking.preview.loading', 'Loading details\u2026')}\n </div>\n ) : null}\n\n {adapter.renderLinkSettings ? (\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"mb-3 text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.settings.label', 'Link settings')}\n </div>\n {adapter.renderLinkSettings(linkSettings, setLinkSettings, focusedOption)}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-lg border border-dashed border-border/70 bg-card/40 p-6 text-center text-sm text-muted-foreground\">\n <Link2 className=\"mb-2 size-5 opacity-60\" />\n {t(\n 'customers.linking.preview.empty',\n 'Select an entry on the left to see details here.',\n )}\n </div>\n )}\n </div>\n </div>\n\n <DialogFooter className=\"flex flex-row items-center justify-between border-t border-border/70 bg-muted/30 px-6 py-4 sm:flex-row sm:justify-between\">\n <div className=\"text-xs text-muted-foreground\">{selectedCountLabel}</div>\n <div className=\"flex items-center gap-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => handleDialogOpenChange(false)}\n disabled={saving}\n className=\"h-9 rounded-md px-4\"\n >\n {t('customers.linking.actions.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n void handleSave()\n }}\n disabled={saving || !hasChanges}\n className=\"h-9 rounded-md bg-foreground px-5 text-background hover:bg-foreground/90\"\n >\n {saving ? (\n <>\n <Loader2 className=\"mr-2 size-4 animate-spin\" />\n {t('customers.linking.actions.saving', 'Saving\u2026')}\n </>\n ) : (\n <>\n <Link2 className=\"mr-2 size-4\" />\n {adapter.confirmButtonLabel}\n </>\n )}\n </Button>\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {adapter.addNew && nestedOpen\n ? adapter.addNew.render({\n onCreated: handleAddNewCreated,\n onCancel: () => setNestedOpen(false),\n })\n : null}\n </>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport {\n Check,\n Link2,\n Loader2,\n Plus,\n Search,\n SearchX,\n X,\n} from 'lucide-react'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\n\nexport type LinkEntityKind = 'company' | 'person' | 'deal'\n\nexport type LinkEntityOption = {\n id: string\n label: string\n subtitle?: string | null\n avatarSeed?: string | null\n icon?: React.ReactNode\n meta?: Record<string, unknown>\n}\n\nexport type LinkEntitySearchPage = {\n items: LinkEntityOption[]\n totalPages: number\n total?: number\n}\n\nexport type LinkEntityFilterOption = {\n id: string\n label: string\n count?: number\n dotColor?: string\n}\n\nexport type LinkEntityRowContext = {\n selected: boolean\n focused: boolean\n disabled?: boolean\n}\n\nexport type LinkEntityAdapter<TDetails = unknown, TLinkSettings = Record<string, unknown>> = {\n kind: LinkEntityKind\n searchPage: (\n query: string,\n page: number,\n filterId?: string,\n ) => Promise<LinkEntitySearchPage>\n fetchByIds: (ids: string[]) => Promise<LinkEntityOption[]>\n fetchDetails?: (id: string) => Promise<TDetails>\n\n dialogTitle: string\n dialogSubtitle?: string\n headerIcon?: React.ReactNode\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n defaultAvatarIcon?: React.ReactNode\n\n filters?: {\n options: LinkEntityFilterOption[]\n defaultId?: string\n /**\n * Optional client-side predicate applied AFTER the server response.\n * Return true to keep the option when the given filter id is active.\n * When not provided, all items pass regardless of filter (filter effectively\n * only applies server-side via searchPage's third argument).\n */\n clientFilter?: (option: LinkEntityOption, filterId: string) => boolean\n }\n\n renderRow?: (\n option: LinkEntityOption,\n ctx: LinkEntityRowContext,\n ) => React.ReactNode\n renderPreview?: (option: LinkEntityOption, details?: TDetails) => React.ReactNode\n renderLinkSettings?: (\n settings: TLinkSettings,\n onChange: (next: TLinkSettings) => void,\n focusedOption: LinkEntityOption | null,\n ) => React.ReactNode\n initialLinkSettings?: TLinkSettings\n\n computeOrphanWarning?: (option: LinkEntityOption) => Promise<string | null>\n\n addNew?: {\n title: string\n subtitle?: string\n render: (ctx: {\n onCreated: (created: LinkEntityOption) => void\n onCancel: () => void\n }) => React.ReactNode\n }\n}\n\nexport type LinkEntityConfirmInput<TLinkSettings = Record<string, unknown>> = {\n addedIds: string[]\n removedIds: string[]\n nextSelectedIds: string[]\n primaryId?: string | null\n optionsById: Record<string, LinkEntityOption>\n linkSettings?: TLinkSettings\n}\n\ntype GuardedMutationRunner = <T,>(\n operation: () => Promise<T>,\n mutationPayload?: Record<string, unknown>,\n) => Promise<T>\n\nexport type LinkEntityDialogProps<TDetails = unknown, TLinkSettings = Record<string, unknown>> = {\n open: boolean\n onOpenChange: (open: boolean) => void\n adapter: LinkEntityAdapter<TDetails, TLinkSettings>\n initialSelectedIds: string[]\n initialPrimaryId?: string | null\n primarySupported?: boolean\n onConfirm: (next: LinkEntityConfirmInput<TLinkSettings>) => Promise<void>\n runGuardedMutation?: GuardedMutationRunner\n avatarVariant?: 'default' | 'monochrome'\n}\n\nconst SEARCH_DEBOUNCE_MS = 200\n\nfunction diffSelection(initial: string[], next: string[]): { addedIds: string[]; removedIds: string[] } {\n const initialSet = new Set(initial)\n const nextSet = new Set(next)\n const addedIds: string[] = []\n const removedIds: string[] = []\n next.forEach((id) => {\n if (!initialSet.has(id)) addedIds.push(id)\n })\n initial.forEach((id) => {\n if (!nextSet.has(id)) removedIds.push(id)\n })\n return { addedIds, removedIds }\n}\n\nfunction sameIds(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false\n const rightSet = new Set(right)\n return left.every((value) => rightSet.has(value))\n}\n\nfunction mergeOptionMaps(\n existing: Map<string, LinkEntityOption>,\n entries: LinkEntityOption[],\n): Map<string, LinkEntityOption> {\n const next = new Map(existing)\n entries.forEach((entry) => next.set(entry.id, entry))\n return next\n}\n\ntype SelectionIndicatorProps = {\n checked: boolean\n disabled?: boolean\n label: string\n}\n\nfunction SelectionIndicator({ checked, disabled, label }: SelectionIndicatorProps) {\n return (\n <span\n role=\"checkbox\"\n aria-checked={checked}\n aria-disabled={disabled || undefined}\n aria-label={label}\n className={cn(\n 'inline-flex size-6 shrink-0 items-center justify-center rounded-full border transition-colors',\n checked\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n disabled && 'opacity-50',\n )}\n >\n {checked ? <Check className=\"size-3\" strokeWidth={2.5} /> : null}\n </span>\n )\n}\n\ntype DefaultRowProps = {\n option: LinkEntityOption\n ctx: LinkEntityRowContext\n avatarVariant: 'default' | 'monochrome'\n defaultAvatarIcon?: React.ReactNode\n selectLabel: string\n}\n\nfunction DefaultRow({\n option,\n ctx,\n avatarVariant,\n defaultAvatarIcon,\n selectLabel,\n}: DefaultRowProps) {\n return (\n <>\n <Avatar\n label={option.label}\n variant={avatarVariant}\n size=\"md\"\n icon={option.icon ?? defaultAvatarIcon}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-semibold text-foreground\">{option.label}</div>\n {option.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">{option.subtitle}</div>\n ) : null}\n </div>\n <SelectionIndicator checked={ctx.selected} label={selectLabel} />\n </>\n )\n}\n\nexport function LinkEntityDialog<TDetails = unknown, TLinkSettings = Record<string, unknown>>({\n open,\n onOpenChange,\n adapter,\n initialSelectedIds,\n initialPrimaryId,\n primarySupported = false,\n onConfirm,\n avatarVariant = 'monochrome',\n}: LinkEntityDialogProps<TDetails, TLinkSettings>) {\n const t = useT()\n const [query, setQuery] = React.useState('')\n const [activeFilter, setActiveFilter] = React.useState<string | undefined>(\n adapter.filters?.defaultId,\n )\n const [searchPage, setSearchPage] = React.useState(1)\n const [searchTotalPages, setSearchTotalPages] = React.useState(1)\n const [searchTotal, setSearchTotal] = React.useState<number | null>(null)\n const [searchResults, setSearchResults] = React.useState<LinkEntityOption[]>([])\n const [searchLoading, setSearchLoading] = React.useState(false)\n const [draftIds, setDraftIds] = React.useState<string[]>(initialSelectedIds)\n const [draftPrimaryId, setDraftPrimaryId] = React.useState<string | null>(\n initialPrimaryId ?? null,\n )\n const [focusedId, setFocusedId] = React.useState<string | null>(null)\n const [optionCache, setOptionCache] = React.useState<Map<string, LinkEntityOption>>(\n () => new Map(),\n )\n const [details, setDetails] = React.useState<Record<string, TDetails>>({})\n const [detailsLoadingId, setDetailsLoadingId] = React.useState<string | null>(null)\n const [linkSettings, setLinkSettings] = React.useState<TLinkSettings>(\n adapter.initialLinkSettings ?? ({} as TLinkSettings),\n )\n const [saving, setSaving] = React.useState(false)\n const [nestedOpen, setNestedOpen] = React.useState(false)\n const requestIdRef = React.useRef(0)\n\n const initialIdsKey = React.useMemo(() => initialSelectedIds.join('|'), [initialSelectedIds])\n\n React.useEffect(() => {\n if (!open) return\n setDraftIds(initialSelectedIds)\n setDraftPrimaryId(initialPrimaryId ?? null)\n setQuery('')\n setActiveFilter(adapter.filters?.defaultId)\n setSearchPage(1)\n setSearchTotalPages(1)\n setSearchTotal(null)\n setSearchResults([])\n setFocusedId(null)\n setDetails({})\n setDetailsLoadingId(null)\n setLinkSettings(adapter.initialLinkSettings ?? ({} as TLinkSettings))\n setNestedOpen(false)\n }, [open, initialIdsKey, initialPrimaryId, adapter])\n\n React.useEffect(() => {\n if (!open) return\n setSearchPage(1)\n }, [open, query, activeFilter])\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n const current = ++requestIdRef.current\n setSearchLoading(true)\n const timeout = window.setTimeout(async () => {\n try {\n const result = await adapter.searchPage(query, searchPage, activeFilter)\n if (cancelled || current !== requestIdRef.current) return\n setSearchResults(result.items)\n setSearchTotalPages(Math.max(1, result.totalPages))\n setSearchTotal(typeof result.total === 'number' ? result.total : null)\n setOptionCache((prev) => mergeOptionMaps(prev, result.items))\n } catch {\n if (cancelled || current !== requestIdRef.current) return\n setSearchResults([])\n setSearchTotalPages(1)\n setSearchTotal(0)\n } finally {\n if (!cancelled && current === requestIdRef.current) {\n setSearchLoading(false)\n }\n }\n }, SEARCH_DEBOUNCE_MS)\n return () => {\n cancelled = true\n window.clearTimeout(timeout)\n }\n }, [adapter, activeFilter, open, query, searchPage])\n\n React.useEffect(() => {\n if (!open) return\n const missingIds = draftIds.filter((id) => !optionCache.has(id))\n if (!missingIds.length) return\n let cancelled = false\n void adapter\n .fetchByIds(missingIds)\n .then((entries) => {\n if (cancelled) return\n setOptionCache((prev) => mergeOptionMaps(prev, entries))\n })\n .catch((error) => console.warn('[LinkEntityDialog] fetchByIds failed', error))\n return () => {\n cancelled = true\n }\n }, [adapter, draftIds, open, optionCache])\n\n const focusedOption: LinkEntityOption | null = React.useMemo(\n () => (focusedId ? optionCache.get(focusedId) ?? null : null),\n [focusedId, optionCache],\n )\n\n const fetchDetails = adapter.fetchDetails\n React.useEffect(() => {\n if (!open || !focusedId || !fetchDetails) return\n if (details[focusedId] !== undefined) return\n let cancelled = false\n setDetailsLoadingId(focusedId)\n void fetchDetails(focusedId)\n .then((result) => {\n if (cancelled) return\n setDetails((prev) => ({ ...prev, [focusedId]: result }))\n })\n .catch((error) => console.warn('[LinkEntityDialog] fetchDetails failed', error))\n .finally(() => {\n if (!cancelled) setDetailsLoadingId(null)\n })\n return () => {\n cancelled = true\n }\n }, [details, fetchDetails, focusedId, open])\n\n const draftSet = React.useMemo(() => new Set(draftIds), [draftIds])\n\n const displayedResults = React.useMemo(() => {\n const predicate = adapter.filters?.clientFilter\n const effectiveFilter = activeFilter ?? adapter.filters?.defaultId\n if (!predicate || !effectiveFilter) return searchResults\n return searchResults.filter((option) => predicate(option, effectiveFilter))\n }, [adapter.filters, activeFilter, searchResults])\n\n const selectedOptions = React.useMemo(\n () =>\n draftIds.map((id) => optionCache.get(id) ?? { id, label: id }).filter((entry): entry is LinkEntityOption => Boolean(entry)),\n [draftIds, optionCache],\n )\n\n React.useEffect(() => {\n if (!primarySupported) return\n setDraftPrimaryId((current) => {\n const normalizedCurrent = current ?? null\n if (draftIds.length === 0) return null\n if (normalizedCurrent && draftIds.includes(normalizedCurrent)) return normalizedCurrent\n return draftIds[0]\n })\n }, [draftIds, primarySupported])\n\n const toggleDraftId = React.useCallback((id: string, checked: boolean) => {\n setDraftIds((current) => {\n if (checked) {\n if (current.includes(id)) return current\n return [...current, id]\n }\n return current.filter((candidate) => candidate !== id)\n })\n }, [])\n\n const handleRowClick = React.useCallback(\n (option: LinkEntityOption) => {\n setFocusedId(option.id)\n const isSelected = draftSet.has(option.id)\n toggleDraftId(option.id, !isSelected)\n },\n [draftSet, toggleDraftId],\n )\n\n const handleAddNewCreated = React.useCallback(\n (option: LinkEntityOption) => {\n setOptionCache((prev) => mergeOptionMaps(prev, [option]))\n setDraftIds((current) => (current.includes(option.id) ? current : [...current, option.id]))\n setFocusedId(option.id)\n setNestedOpen(false)\n },\n [],\n )\n\n const handleDialogOpenChange = React.useCallback(\n (next: boolean) => {\n if (nestedOpen && !next) return\n onOpenChange(next)\n },\n [nestedOpen, onOpenChange],\n )\n\n const handleSetPrimary = React.useCallback(\n (id: string) => {\n if (!primarySupported || !draftSet.has(id)) return\n setDraftPrimaryId(id)\n setFocusedId(id)\n },\n [draftSet, primarySupported],\n )\n\n const hasChanges = React.useMemo(() => {\n if (!sameIds(initialSelectedIds, draftIds)) return true\n if (primarySupported && (draftPrimaryId ?? null) !== (initialPrimaryId ?? null)) return true\n return false\n }, [draftIds, draftPrimaryId, initialPrimaryId, initialSelectedIds, primarySupported])\n\n const handleSave = React.useCallback(async () => {\n if (saving) return\n const { addedIds, removedIds } = diffSelection(initialSelectedIds, draftIds)\n const primaryChanged = primarySupported\n ? (draftPrimaryId ?? null) !== (initialPrimaryId ?? null)\n : false\n if (!addedIds.length && !removedIds.length && !primaryChanged) {\n onOpenChange(false)\n return\n }\n setSaving(true)\n try {\n const optionsById: Record<string, LinkEntityOption> = {}\n optionCache.forEach((value, key) => {\n optionsById[key] = value\n })\n await onConfirm({\n addedIds,\n removedIds,\n nextSelectedIds: draftIds,\n primaryId: primarySupported ? draftPrimaryId : undefined,\n optionsById,\n linkSettings,\n })\n onOpenChange(false)\n } finally {\n setSaving(false)\n }\n }, [\n draftIds,\n draftPrimaryId,\n initialPrimaryId,\n initialSelectedIds,\n linkSettings,\n onConfirm,\n onOpenChange,\n optionCache,\n primarySupported,\n saving,\n ])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (nestedOpen) return\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSave()\n return\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n handleDialogOpenChange(false)\n }\n },\n [handleDialogOpenChange, handleSave, nestedOpen],\n )\n\n const selectedCountLabel = React.useMemo(() => {\n const kindLabels: Record<LinkEntityKind, [string, string, string, string]> = {\n person: [\n 'customers.linking.footer.personSingular',\n '{{count}} person selected',\n 'customers.linking.footer.personPlural',\n '{{count}} people selected',\n ],\n company: [\n 'customers.linking.footer.companySingular',\n '{{count}} company selected',\n 'customers.linking.footer.companyPlural',\n '{{count}} companies selected',\n ],\n deal: [\n 'customers.linking.footer.dealSingular',\n '{{count}} deal selected',\n 'customers.linking.footer.dealPlural',\n '{{count}} deals selected',\n ],\n }\n const [singularKey, singularDefault, pluralKey, pluralDefault] = kindLabels[adapter.kind]\n if (draftIds.length === 1) {\n return t(singularKey, singularDefault, { count: String(draftIds.length) })\n }\n return t(pluralKey, pluralDefault, { count: String(draftIds.length) })\n }, [adapter.kind, draftIds.length, t])\n\n const filterOptions = adapter.filters?.options ?? []\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleDialogOpenChange}>\n <DialogContent\n className=\"flex flex-col gap-0 overflow-hidden p-0\"\n style={{\n width: 'min(calc(100vw - 2rem), 920px)',\n maxWidth: 'min(calc(100vw - 2rem), 920px)',\n maxHeight: 'min(640px, calc(100vh - 4rem))',\n }}\n onKeyDown={handleKeyDown}\n aria-hidden={nestedOpen ? 'true' : undefined}\n >\n <DialogHeader className=\"flex flex-row items-center gap-3 space-y-0 border-b border-border/70 bg-card px-6 py-5\">\n {adapter.headerIcon ? (\n <div className=\"flex size-6 shrink-0 items-center justify-center text-foreground\">\n {adapter.headerIcon}\n </div>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <DialogTitle className=\"text-lg font-bold text-foreground\">\n {adapter.dialogTitle}\n </DialogTitle>\n {adapter.dialogSubtitle ? (\n <DialogDescription className=\"mt-0.5 text-sm text-muted-foreground\">\n {adapter.dialogSubtitle}\n </DialogDescription>\n ) : null}\n </div>\n </DialogHeader>\n\n <div className=\"flex min-h-0 flex-1 flex-col lg:flex-row\">\n <div className=\"flex min-h-0 flex-col gap-3 border-b border-border/70 bg-card p-4 lg:w-[480px] lg:shrink-0 lg:border-b-0 lg:border-r\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={adapter.searchPlaceholder}\n className=\"h-10 rounded-md pl-9 pr-20 text-sm\"\n autoFocus\n aria-label={adapter.searchPlaceholder}\n />\n {searchTotal !== null && !searchLoading ? (\n <span className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground\">\n {t('customers.linking.resultsCount', '{{count}} results', {\n count: String(searchTotal),\n })}\n </span>\n ) : null}\n </div>\n\n {filterOptions.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filterOptions.map((filter) => {\n const isActive = (activeFilter ?? adapter.filters?.defaultId) === filter.id\n return (\n <button\n key={filter.id}\n type=\"button\"\n onClick={() => setActiveFilter(filter.id)}\n className={cn(\n 'inline-flex h-6 items-center gap-1.5 rounded-full px-2.5 text-xs font-semibold transition-colors',\n isActive\n ? 'bg-foreground text-background'\n : 'bg-muted/70 text-muted-foreground hover:bg-muted',\n )}\n >\n {filter.dotColor ? (\n <span\n aria-hidden=\"true\"\n className=\"inline-block size-1.5 rounded-full\"\n style={{ backgroundColor: filter.dotColor }}\n />\n ) : null}\n <span>{filter.label}</span>\n {typeof filter.count === 'number' ? (\n <span\n className={cn(\n 'inline-flex min-w-[14px] items-center justify-center rounded-full px-1 text-xs',\n isActive\n ? 'bg-background/20 text-background'\n : 'bg-background text-muted-foreground',\n )}\n >\n {filter.count}\n </span>\n ) : null}\n </button>\n )\n })}\n </div>\n ) : null}\n\n {adapter.sectionLabel ? (\n <div className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {adapter.sectionLabel}\n </div>\n ) : null}\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n {searchLoading && displayedResults.length === 0 ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"size-4 animate-spin\" />\n {t('customers.linking.searching', 'Searching\u2026')}\n </div>\n ) : displayedResults.length === 0 ? (\n <EmptyState\n size=\"sm\"\n icon={<SearchX className=\"h-8 w-8\" aria-hidden=\"true\" />}\n title={adapter.searchEmptyHint}\n />\n ) : (\n displayedResults.map((result) => {\n const checked = draftSet.has(result.id)\n const focused = focusedId === result.id\n const ctx: LinkEntityRowContext = { selected: checked, focused }\n const selectLabel = t('customers.linking.selectEntity', 'Select {{name}}', {\n name: result.label,\n })\n return (\n <div\n key={result.id}\n role=\"button\"\n tabIndex={0}\n aria-pressed={checked}\n onClick={() => handleRowClick(result)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleRowClick(result)\n }\n }}\n className={cn(\n 'group flex cursor-pointer items-center gap-3 rounded-lg border px-3.5 py-3 transition-colors focus:outline-none focus:ring-2 focus:ring-ring/40',\n checked\n ? 'border-border bg-muted/50'\n : 'border-border/70 bg-card hover:bg-muted/30',\n )}\n >\n {adapter.renderRow ? (\n adapter.renderRow(result, ctx)\n ) : (\n <DefaultRow\n option={result}\n ctx={ctx}\n avatarVariant={avatarVariant}\n defaultAvatarIcon={adapter.defaultAvatarIcon}\n selectLabel={selectLabel}\n />\n )}\n </div>\n )\n })\n )}\n\n {adapter.addNew ? (\n <button\n type=\"button\"\n onClick={() => setNestedOpen(true)}\n className=\"mt-2 flex items-center gap-3 rounded-lg border border-dashed border-border px-4 py-3.5 text-left transition-colors hover:bg-muted/30 focus:outline-none focus:ring-2 focus:ring-ring/40\"\n >\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground\">\n <Plus className=\"size-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-foreground\">\n {adapter.addNew.title}\n </span>\n {adapter.addNew.subtitle ? (\n <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n {adapter.addNew.subtitle}\n </span>\n ) : null}\n </span>\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-foreground text-background\">\n <Plus className=\"size-3.5\" />\n </span>\n </button>\n ) : null}\n\n {searchTotalPages > 1 ? (\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n <span aria-live=\"polite\">\n {t('customers.linking.pagination.pageOf', 'Page {{page}} of {{total}}', {\n page: String(Math.min(searchPage, searchTotalPages)),\n total: String(searchTotalPages),\n })}\n </span>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8 rounded-md px-2.5 text-xs\"\n disabled={searchLoading || searchPage <= 1}\n onClick={() => setSearchPage((current) => Math.max(1, current - 1))}\n >\n {t('customers.linking.pagination.previousShort', 'Previous')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8 rounded-md px-2.5 text-xs\"\n disabled={searchLoading || searchPage >= searchTotalPages}\n onClick={() =>\n setSearchPage((current) => Math.min(searchTotalPages, current + 1))\n }\n >\n {t('customers.linking.pagination.nextShort', 'Next')}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-auto bg-muted/20 p-5\">\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"mb-3 text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.selected.label', 'Selected')}\n </div>\n {selectedOptions.length > 0 ? (\n <div className=\"space-y-2\">\n {selectedOptions.map((option) => {\n const isPrimary = primarySupported && draftPrimaryId === option.id\n return (\n <div\n key={option.id}\n className={cn(\n 'flex items-center gap-3 rounded-lg border px-3 py-2.5 transition-colors',\n focusedId === option.id\n ? 'border-border bg-muted/50'\n : 'border-border/70 bg-card',\n )}\n >\n <button\n type=\"button\"\n onClick={() => setFocusedId(option.id)}\n className=\"flex min-w-0 flex-1 items-center gap-3 text-left\"\n >\n <Avatar\n label={option.label}\n variant={avatarVariant}\n size=\"sm\"\n icon={option.icon ?? adapter.defaultAvatarIcon}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {option.subtitle ? (\n <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n {option.subtitle}\n </span>\n ) : null}\n </span>\n </button>\n {primarySupported ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant={isPrimary ? 'default' : 'outline'}\n className=\"h-7 rounded-full px-3 text-xs\"\n onClick={() => handleSetPrimary(option.id)}\n disabled={isPrimary}\n >\n {isPrimary\n ? t('customers.linking.primary.current', 'Primary')\n : t('customers.linking.primary.set', 'Set primary')}\n </Button>\n ) : null}\n </div>\n )\n })}\n </div>\n ) : (\n <div className=\"rounded-lg border border-dashed border-border/70 px-4 py-4 text-sm text-muted-foreground\">\n {adapter.selectedEmptyHint}\n </div>\n )}\n {primarySupported && selectedOptions.length > 0 ? (\n <div className=\"mt-3 text-xs text-muted-foreground\">\n {t(\n 'customers.linking.primary.help',\n 'Choose which linked company should remain primary.',\n )}\n </div>\n ) : null}\n </div>\n\n <div className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.preview.label', 'Preview')}\n </div>\n\n {focusedOption ? (\n <>\n {adapter.renderPreview ? (\n adapter.renderPreview(focusedOption, details[focusedOption.id])\n ) : (\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar\n label={focusedOption.label}\n variant={avatarVariant}\n size=\"lg\"\n icon={focusedOption.icon ?? adapter.defaultAvatarIcon}\n />\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-bold text-foreground\">\n {focusedOption.label}\n </div>\n {focusedOption.subtitle ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {focusedOption.subtitle}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n )}\n {detailsLoadingId === focusedOption.id && adapter.fetchDetails ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" />\n {t('customers.linking.preview.loading', 'Loading details\u2026')}\n </div>\n ) : null}\n\n {adapter.renderLinkSettings ? (\n <div className=\"rounded-lg border border-border/70 bg-card p-4\">\n <div className=\"mb-3 text-overline font-semibold uppercase tracking-wider text-muted-foreground\">\n {t('customers.linking.settings.label', 'Link settings')}\n </div>\n {adapter.renderLinkSettings(linkSettings, setLinkSettings, focusedOption)}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"flex flex-1 flex-col items-center justify-center rounded-lg border border-dashed border-border/70 bg-card/40 p-6 text-center text-sm text-muted-foreground\">\n <Link2 className=\"mb-2 size-5 opacity-60\" />\n {t(\n 'customers.linking.preview.empty',\n 'Select an entry on the left to see details here.',\n )}\n </div>\n )}\n </div>\n </div>\n\n <DialogFooter className=\"flex flex-row items-center justify-between border-t border-border/70 bg-muted/30 px-6 py-4 sm:flex-row sm:justify-between\">\n <div className=\"text-xs text-muted-foreground\">{selectedCountLabel}</div>\n <div className=\"flex items-center gap-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => handleDialogOpenChange(false)}\n disabled={saving}\n className=\"h-9 rounded-md px-4\"\n >\n {t('customers.linking.actions.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n void handleSave()\n }}\n disabled={saving || !hasChanges}\n className=\"h-9 rounded-md bg-foreground px-5 text-background hover:bg-foreground/90\"\n >\n {saving ? (\n <>\n <Loader2 className=\"mr-2 size-4 animate-spin\" />\n {t('customers.linking.actions.saving', 'Saving\u2026')}\n </>\n ) : (\n <>\n <Link2 className=\"mr-2 size-4\" />\n {adapter.confirmButtonLabel}\n </>\n )}\n </Button>\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {adapter.addNew && nestedOpen\n ? adapter.addNew.render({\n onCreated: handleAddNewCreated,\n onCancel: () => setNestedOpen(false),\n })\n : null}\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -30,7 +30,6 @@ import {
30
30
  ArrowRightLeft,
31
31
  Boxes,
32
32
  CalendarClock,
33
- CircleAlert,
34
33
  Clock3,
35
34
  Gauge,
36
35
  Play,
@@ -777,14 +776,8 @@ function SyncRunsDashboardPage() {
777
776
  ] })
778
777
  ] })
779
778
  ] }),
780
- selectedIntegration && !selectedIntegration.isEnabled ? /* @__PURE__ */ jsx(Alert, { variant: "warning", children: /* @__PURE__ */ jsxs(AlertDescription, { className: "inline-flex items-center gap-2", children: [
781
- /* @__PURE__ */ jsx(CircleAlert, { className: "size-4" }),
782
- /* @__PURE__ */ jsx("span", { children: t("integrations.detail.state.disabled", "This integration is disabled. Enable it on the integration settings page before starting a sync.") })
783
- ] }) }) : null,
784
- selectedIntegration && !selectedIntegration.hasCredentials ? /* @__PURE__ */ jsx(Alert, { variant: "warning", children: /* @__PURE__ */ jsxs(AlertDescription, { className: "inline-flex items-center gap-2", children: [
785
- /* @__PURE__ */ jsx(CircleAlert, { className: "size-4" }),
786
- /* @__PURE__ */ jsx("span", { children: t("integrations.detail.credentials.notConfigured", "Credentials are not configured yet. Save the integration credentials before starting a sync.") })
787
- ] }) }) : null
779
+ selectedIntegration && !selectedIntegration.isEnabled ? /* @__PURE__ */ jsx(Alert, { variant: "warning", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("integrations.detail.state.disabled", "This integration is disabled. Enable it on the integration settings page before starting a sync.") }) }) : null,
780
+ selectedIntegration && !selectedIntegration.hasCredentials ? /* @__PURE__ */ jsx(Alert, { variant: "warning", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("integrations.detail.credentials.notConfigured", "Credentials are not configured yet. Save the integration credentials before starting a sync.") }) }) : null
788
781
  ] })
789
782
  ] }),
790
783
  /* @__PURE__ */ jsx(