@open-mercato/core 0.7.1-develop.7113.1.9d83dca10c → 0.7.1-develop.7121.1.734c263bda

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 (95) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/crmFixtures.js.map +1 -1
  3. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -2
  4. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
  5. package/dist/modules/communication_channels/lib/outbound-recipient.js +5 -1
  6. package/dist/modules/communication_channels/lib/outbound-recipient.js.map +2 -2
  7. package/dist/modules/communication_channels/lib/test-seed.js +5 -0
  8. package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
  9. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +1 -1
  10. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +1 -1
  11. package/dist/modules/customers/backend/customers/deals/page.js +4 -3
  12. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  13. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js +2 -2
  14. package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js.map +2 -2
  15. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +1 -1
  16. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +1 -1
  17. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +1 -1
  18. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  19. package/dist/modules/customers/cli.js +5 -5
  20. package/dist/modules/customers/cli.js.map +2 -2
  21. package/dist/modules/customers/commands/deals.js.map +2 -2
  22. package/dist/modules/customers/components/detail/pipelineStageUtils.js +1 -0
  23. package/dist/modules/customers/components/detail/pipelineStageUtils.js.map +2 -2
  24. package/dist/modules/customers/components/linking/adapters/dealAdapter.js +2 -2
  25. package/dist/modules/customers/components/linking/adapters/dealAdapter.js.map +2 -2
  26. package/dist/modules/customers/lib/closureStage.js.map +2 -2
  27. package/dist/modules/customers/lib/dealStatus.js +6 -4
  28. package/dist/modules/customers/lib/dealStatus.js.map +2 -2
  29. package/dist/modules/customers/lib/dealsSummaryQueries.js +3 -3
  30. package/dist/modules/customers/lib/dealsSummaryQueries.js.map +1 -1
  31. package/dist/modules/customers/migrations/Migration20260824180000_deal_status_lost.js +30 -0
  32. package/dist/modules/customers/migrations/Migration20260824180000_deal_status_lost.js.map +7 -0
  33. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/config.js.map +1 -1
  34. package/dist/modules/eudr/notifications.js +5 -0
  35. package/dist/modules/eudr/notifications.js.map +2 -2
  36. package/dist/modules/query_index/lib/search-tokens.js +59 -28
  37. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  38. package/dist/modules/sales/commands/documents.js +146 -99
  39. package/dist/modules/sales/commands/documents.js.map +2 -2
  40. package/dist/modules/sales/commands/returns.js +1 -30
  41. package/dist/modules/sales/commands/returns.js.map +2 -2
  42. package/dist/modules/sales/commands/shared.js +1 -4
  43. package/dist/modules/sales/commands/shared.js.map +2 -2
  44. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +2 -1
  45. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
  46. package/dist/modules/sales/data/validators.js +3 -0
  47. package/dist/modules/sales/data/validators.js.map +2 -2
  48. package/dist/modules/sales/lib/calculations.js +14 -2
  49. package/dist/modules/sales/lib/calculations.js.map +2 -2
  50. package/dist/modules/sales/lib/json.js +8 -0
  51. package/dist/modules/sales/lib/json.js.map +7 -0
  52. package/dist/modules/sales/lib/lineSnapshots.js +66 -0
  53. package/dist/modules/sales/lib/lineSnapshots.js.map +7 -0
  54. package/dist/modules/warranty_claims/notifications.js +5 -0
  55. package/dist/modules/warranty_claims/notifications.js.map +2 -2
  56. package/dist/modules/wms/notifications.js +2 -0
  57. package/dist/modules/wms/notifications.js.map +2 -2
  58. package/package.json +7 -7
  59. package/src/helpers/integration/crmFixtures.ts +1 -1
  60. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +21 -9
  61. package/src/modules/communication_channels/lib/adapter.ts +11 -0
  62. package/src/modules/communication_channels/lib/outbound-recipient.ts +14 -1
  63. package/src/modules/communication_channels/lib/test-seed.ts +19 -0
  64. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +1 -1
  65. package/src/modules/customers/backend/customers/deals/page.tsx +4 -3
  66. package/src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx +5 -5
  67. package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +3 -3
  68. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +2 -2
  69. package/src/modules/customers/cli.ts +5 -5
  70. package/src/modules/customers/commands/deals.ts +4 -3
  71. package/src/modules/customers/components/detail/pipelineStageUtils.ts +1 -0
  72. package/src/modules/customers/components/linking/adapters/dealAdapter.tsx +2 -2
  73. package/src/modules/customers/i18n/de.json +1 -1
  74. package/src/modules/customers/i18n/en.json +1 -1
  75. package/src/modules/customers/i18n/es.json +1 -1
  76. package/src/modules/customers/i18n/ko.json +1 -1
  77. package/src/modules/customers/i18n/pl.json +1 -1
  78. package/src/modules/customers/lib/closureStage.ts +2 -1
  79. package/src/modules/customers/lib/dealStatus.ts +23 -12
  80. package/src/modules/customers/lib/dealsSummaryQueries.ts +3 -3
  81. package/src/modules/customers/migrations/Migration20260824180000_deal_status_lost.ts +55 -0
  82. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/config.ts +1 -1
  83. package/src/modules/eudr/notifications.ts +5 -0
  84. package/src/modules/query_index/lib/search-tokens.ts +100 -43
  85. package/src/modules/sales/commands/documents.ts +185 -105
  86. package/src/modules/sales/commands/returns.ts +1 -31
  87. package/src/modules/sales/commands/shared.ts +1 -4
  88. package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +12 -1
  89. package/src/modules/sales/data/validators.ts +3 -0
  90. package/src/modules/sales/lib/calculations.ts +33 -7
  91. package/src/modules/sales/lib/json.ts +4 -0
  92. package/src/modules/sales/lib/lineSnapshots.ts +98 -0
  93. package/src/modules/sales/lib/types.ts +20 -0
  94. package/src/modules/warranty_claims/notifications.ts +5 -0
  95. package/src/modules/wms/notifications.ts +2 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/backend/customers/deals/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'\nimport Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { AdvancedFilterTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'\nimport { createEmptyTree, makeRuleTree, makeMultiRuleTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'\nimport { deserializeTree, deserializeAdvancedFilter, flatToTree, mapDictionaryColorToTone, serializeTree, type FilterFieldDef, type FilterOption as AdvancedFilterOption } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { groupBulkDeleteFailures, runBulkDelete } from '@open-mercato/ui/backend/utils/bulkDelete'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { coalesceLastOperations } from '@open-mercato/ui/backend/operations/store'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { StatusBadge, type StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'\nimport { Avatar, AvatarStack } from '@open-mercato/ui/primitives/avatar'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'\nimport { Briefcase, AlertTriangle, X } from 'lucide-react'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport { ViewTabsRow } from './pipeline/components/ViewTabsRow'\nimport { DealsKpiStrip } from '../../../components/DealsKpiStrip'\nimport { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n type CustomerDictionaryKind,\n type CustomerDictionaryMap,\n} from '../../../lib/dictionaries'\nimport {\n ensureCustomerDictionary,\n invalidateCustomerDictionary,\n} from '../../../components/detail/hooks/useCustomerDictionary'\nimport {\n useCustomFieldDefs,\n} from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n mapCustomFieldKindToFilterType,\n normalizeCustomFieldFilterOptions,\n supportsCustomFieldColumn,\n} from '@open-mercato/ui/backend/utils/customFieldColumns'\nimport { CollectionPreviewCell, normalizeCollectionLabels } from '../../../components/list/CollectionPreviewCell'\nimport { useAutoDiscoveredFields } from '@open-mercato/ui/backend/utils/useAutoDiscoveredFields'\nimport { useAdvancedFilterTree } from '@open-mercato/ui/backend/hooks/useAdvancedFilter'\nimport { AdvancedFilterPanel } from '@open-mercato/ui/backend/filters/AdvancedFilterPanel'\nimport { ActiveFilterChips } from '@open-mercato/ui/backend/filters/ActiveFilterChips'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\nimport type { FilterPreset } from '@open-mercato/ui/backend/filters/QuickFilters'\nimport {\n ensureCurrentUserFilterOption,\n fetchAssignableStaffMembers,\n mapAssignableStaffToFilterOptions,\n} from '../../../components/detail/assignableStaff'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nfunction makeDealsPresets(): FilterPreset[] {\n return [\n {\n id: 'my-deals',\n labelKey: 'customers.deals.presets.myDeals',\n requiresUser: true,\n build: ({ userId }) => makeRuleTree({ field: 'owner_user_id', operator: 'is', value: userId }),\n },\n {\n id: 'closing-month',\n labelKey: 'customers.deals.presets.closingMonth',\n iconName: 'clock',\n build: ({ now }) => {\n const start = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10)\n const end = new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString().slice(0, 10)\n return makeRuleTree({ field: 'expected_close_at', operator: 'between', value: [start, end] })\n },\n },\n // The Deal entity has no dedicated \"at risk\" or health-score field \u2014 `customer_deals`\n // exposes only `status` (open/win/loose/closed/in_progress, dictionary-driven) and\n // `closure_outcome`. Rather than fabricate a mapping, the \"At risk\" preset is omitted\n // until the data model exposes a first-class signal.\n {\n id: 'won-quarter',\n labelKey: 'customers.deals.presets.wonQuarter',\n build: ({ now }) => {\n const quarter = Math.floor(now.getMonth() / 3)\n const start = new Date(now.getFullYear(), quarter * 3, 1).toISOString().slice(0, 10)\n return makeMultiRuleTree([\n { field: 'status', operator: 'is', value: 'win' },\n { field: 'expected_close_at', operator: 'is_after', value: start },\n ], 'and')\n },\n },\n ]\n}\n\ntype DealRow = {\n id: string\n title: string\n status?: string | null\n pipelineStage?: string | null\n pipelineStageId?: string | null\n pipelineId?: string | null\n valueAmount?: number | null\n valueCurrency?: string | null\n probability?: number | null\n expectedCloseAt?: string | null\n updatedAt?: string | null\n ownerUserId?: string | null\n companies: { id: string; label: string }[]\n people: { id: string; label: string }[]\n} & Record<string, unknown>\n\ntype DealsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\ntype FilterOption = { value: string; label: string }\ntype DictionaryOptionWithTone = AdvancedFilterOption & FilterOption\n\ntype DictionaryKey = Extract<CustomerDictionaryKind, 'deal-statuses' | 'pipeline-stages'>\n\nconst PAGE_SIZE = 20\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction isUuid(value: string | null | undefined): value is string {\n if (!value) return false\n return UUID_REGEX.test(value.trim())\n}\n\nfunction normalizeIdCandidates(raw: Array<string>): string[] {\n const set = new Set<string>()\n raw.forEach((candidate) => {\n candidate\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0)\n .forEach((part) => {\n if (isUuid(part)) set.add(part)\n })\n })\n return Array.from(set)\n}\n\nfunction extractIdsFromParams(params: URLSearchParams | null | undefined, key: string): string[] {\n if (!params) return []\n const values = params.getAll(key)\n return normalizeIdCandidates(values)\n}\n\nfunction formatDateValue(value: string | null | undefined, fallback: string): string {\n if (!value) return fallback\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return fallback\n return date.toLocaleDateString()\n}\n\nconst STATUS_BADGE_VARIANTS: ReadonlySet<StatusBadgeVariant> = new Set([\n 'success',\n 'warning',\n 'error',\n 'info',\n 'neutral',\n])\n\nfunction coerceStatusBadgeVariant(\n tone: ReturnType<typeof mapDictionaryColorToTone>,\n): StatusBadgeVariant {\n if (tone && STATUS_BADGE_VARIANTS.has(tone as StatusBadgeVariant)) {\n return tone as StatusBadgeVariant\n }\n return 'neutral'\n}\n\nconst groupedAmountFormatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 0 })\n\nfunction formatGroupedAmount(amount: number | null | undefined): string | null {\n if (typeof amount !== 'number' || Number.isNaN(amount)) return null\n return groupedAmountFormatter.format(amount)\n}\n\nexport default function CustomersDealsPage() {\n const t = useT()\n const locale = useLocale()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n\n const [rows, setRows] = React.useState<DealRow[]>([])\n const [page, setPage] = React.useState(() => {\n const raw = Number(searchParams?.get('page') ?? '1')\n return Number.isFinite(raw) && raw > 0 ? raw : 1\n })\n const [pageSize, setPageSize] = React.useState(PAGE_SIZE)\n const [sorting, setSorting] = React.useState<import('@tanstack/react-table').SortingState>([])\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [search, setSearch] = React.useState(() => searchParams?.get('search')?.trim() ?? '')\n const [isLoading, setIsLoading] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [pendingDeleteId, setPendingDeleteId] = React.useState<string | null>(null)\n const [needsAttentionOnly, setNeedsAttentionOnly] = React.useState(() => searchParams?.get('needsAttention') === 'true')\n // One-shot URL hydration used as the hook's initial value. The hook is the\n // single source of truth from this point on \u2014 the page MUST NOT keep a\n // parallel `useState<AdvancedFilterTree>` (see spec \"Migration & Backward\n // Compatibility\" \u2192 state ownership).\n const initialFilterTree = React.useMemo<AdvancedFilterTree>(() => {\n if (!searchParams) return createEmptyTree()\n const record: Record<string, string> = {}\n searchParams.forEach((value, key) => {\n if (key.startsWith('filter[')) record[key] = value\n })\n const v2 = deserializeTree(record)\n if (v2) return v2\n const flat = deserializeAdvancedFilter(record)\n if (flat) return flatToTree(flat)\n return createEmptyTree()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n // `filterPanel` lives at the top of the component so derived state below\n // (URL params, data fetch, export config) can read `filterPanel.appliedTree`\n // directly. Real `FilterFieldDef[]` arrives later from `useAutoDiscoveredFields`\n // (it depends on columns) and is synced into the hook via a small effect at\n // the bottom of the component. The hook reads fields through a ref at\n // validation time only \u2014 first validation cannot fire before user input, by\n // which point fields have settled, so the empty initial value is safe.\n const [panelFields, setPanelFields] = React.useState<FilterFieldDef[]>([])\n const [filtersOpen, setFiltersOpen] = React.useState(false)\n const filtersTriggerRef = React.useRef<HTMLButtonElement | null>(null)\n const filterPanel = useAdvancedFilterTree({\n initial: initialFilterTree,\n fields: panelFields,\n onApply: () => setPage(1),\n })\n const advancedFilterState = filterPanel.appliedTree\n const handleAdvancedFilterClear = React.useCallback(() => {\n filterPanel.clear()\n setPage(1)\n }, [filterPanel])\n const [cacheStatus, setCacheStatus] = React.useState<'hit' | 'miss' | null>(null)\n\n const initialPersonIds = React.useMemo(\n () => extractIdsFromParams(searchParams, 'personId'),\n [searchParams],\n )\n const initialCompanyIds = React.useMemo(\n () => extractIdsFromParams(searchParams, 'companyId'),\n [searchParams],\n )\n\n const [selectedPersonIds, setSelectedPersonIds] = React.useState<string[]>(initialPersonIds)\n const [selectedCompanyIds, setSelectedCompanyIds] = React.useState<string[]>(initialCompanyIds)\n\n const [dictionaryMaps, setDictionaryMaps] = React.useState<Record<DictionaryKey, CustomerDictionaryMap>>({\n 'deal-statuses': {},\n 'pipeline-stages': {},\n })\n\n const [pipelineNames, setPipelineNames] = React.useState<Record<string, string>>({})\n\n const fetchDictionaryEntries = React.useCallback(\n async (kind: DictionaryKey) => {\n try {\n const data = await ensureCustomerDictionary(queryClient, kind, scopeVersion)\n setDictionaryMaps((prev) => ({ ...prev, [kind]: data.map }))\n } catch {\n setDictionaryMaps((prev) => ({ ...prev, [kind]: {} }))\n }\n },\n [queryClient, scopeVersion],\n )\n\n React.useEffect(() => {\n let cancelled = false\n async function loadDictionaries() {\n if (cancelled) return\n await Promise.all([fetchDictionaryEntries('deal-statuses'), fetchDictionaryEntries('pipeline-stages')])\n }\n loadDictionaries().catch(() => {})\n return () => { cancelled = true }\n }, [fetchDictionaryEntries, reloadToken])\n const dictionaryOptions = React.useMemo(() => {\n const toOptions = (map?: CustomerDictionaryMap | null): DictionaryOptionWithTone[] =>\n Object.values(map ?? {})\n .map((entry) => {\n const tone = mapDictionaryColorToTone(entry.color)\n const option: DictionaryOptionWithTone = { value: entry.value, label: entry.label }\n if (tone) option.tone = tone\n return option\n })\n .sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))\n return {\n dealStatuses: toOptions(dictionaryMaps['deal-statuses']),\n pipelineStages: toOptions(dictionaryMaps['pipeline-stages']),\n }\n }, [dictionaryMaps])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadPipelines() {\n try {\n const call = await apiCall<{ items?: Array<{ id: string; name: string }> }>('/api/customers/pipelines')\n if (cancelled || !call.ok) return\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const map: Record<string, string> = {}\n items.forEach((p) => { if (p.id && p.name) map[p.id] = p.name })\n setPipelineNames(map)\n } catch (err) {\n logger.warn('failed to load pipelines', { component: 'deals.list', err })\n }\n }\n loadPipelines().catch((err) => {\n logger.warn('loadPipelines threw', { component: 'deals.list', err })\n })\n return () => { cancelled = true }\n }, [reloadToken, scopeVersion])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value.trim())\n setPage(1)\n }, [])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (sorting.length > 0) {\n params.set('sort', sorting[0].id)\n params.set('order', sorting[0].desc ? 'desc' : 'asc')\n }\n if (search.trim().length) params.set('search', search.trim())\n if (selectedPersonIds.length) params.set('personId', selectedPersonIds.join(','))\n if (selectedCompanyIds.length) params.set('companyId', selectedCompanyIds.join(','))\n if (needsAttentionOnly) params.set('needsAttention', 'true')\n const advancedParams = serializeTree(advancedFilterState)\n for (const [key, val] of Object.entries(advancedParams)) {\n params.set(key, val)\n }\n return params.toString()\n }, [advancedFilterState, needsAttentionOnly, page, pageSize, search, selectedCompanyIds, selectedPersonIds, sorting])\n\n const currentParams = React.useMemo(\n () => Object.fromEntries(new URLSearchParams(queryParams)),\n [queryParams],\n )\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl('customers/deals', { ...currentParams, exportScope: 'view' }, format),\n },\n full: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl('customers/deals', { ...currentParams, exportScope: 'full', all: 'true' }, format),\n },\n }), [currentParams])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setCacheStatus(null)\n try {\n const fallback: DealsResponse = { items: [], total: 0, totalPages: 1 }\n const call = await apiCall<DealsResponse>(`/api/customers/deals?${queryParams}`, undefined, { fallback })\n if (!call.ok) {\n const message =\n typeof (call.result as { error?: string } | undefined)?.error === 'string'\n ? (call.result as { error?: string }).error!\n : t('customers.deals.list.error.load')\n flash(message, 'error')\n if (!cancelled) setCacheStatus(null)\n return\n }\n const payload = call.result ?? fallback\n if (cancelled) return\n setCacheStatus(call.cacheStatus ?? null)\n const items = Array.isArray(payload.items) ? payload.items : []\n const mapped = items\n .map((item) => mapDeal(item as Record<string, unknown>))\n .filter((row): row is DealRow => !!row)\n setRows(mapped)\n setTotal(typeof payload.total === 'number' ? payload.total : mapped.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)\n setTotalIsCapped(payload.totalIsCapped === true)\n } catch (err) {\n if (!cancelled) {\n setCacheStatus(null)\n const message = err instanceof Error ? err.message : t('customers.deals.list.error.load')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [queryParams, reloadToken, scopeVersion, t])\n\n React.useEffect(() => {\n // A capped totalPages is a floor \u2014 pages past it hold reachable rows, so\n // clamping would bounce a deep-linked user off data that exists.\n if (!totalIsCapped && totalPages > 0 && page > totalPages) {\n setPage(totalPages)\n }\n }, [page, totalPages, totalIsCapped])\n\n const queryRef = React.useRef(searchParams?.toString() ?? '')\n React.useEffect(() => {\n if (!pathname) return\n const params = new URLSearchParams()\n if (search.trim().length) params.set('search', search.trim())\n if (selectedPersonIds.length) selectedPersonIds.forEach((id) => params.append('personId', id))\n if (selectedCompanyIds.length) selectedCompanyIds.forEach((id) => params.append('companyId', id))\n if (needsAttentionOnly) params.set('needsAttention', 'true')\n if (page > 1) params.set('page', String(page))\n const advancedParams = serializeTree(advancedFilterState)\n for (const [key, val] of Object.entries(advancedParams)) {\n params.set(key, val)\n }\n const next = params.toString()\n if (queryRef.current === next) return\n queryRef.current = next\n router.replace(next ? `${pathname}?${next}` : pathname, { scroll: false })\n }, [pathname, router, page, search, selectedPersonIds, selectedCompanyIds, needsAttentionOnly, advancedFilterState])\n\n const handleRefresh = React.useCallback(() => {\n void Promise.all([\n invalidateCustomerDictionary(queryClient, 'deal-statuses'),\n invalidateCustomerDictionary(queryClient, 'pipeline-stages'),\n ])\n setReloadToken((token) => token + 1)\n }, [queryClient])\n\n const bulkMutationContextId = 'customers-deals-list:bulk-delete'\n const { runMutation: runBulkMutation, retryLastMutation: retryBulkMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: bulkMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const singleMutationContextId = 'customers-deals-list:single-delete'\n const { runMutation: runSingleMutation, retryLastMutation: retrySingleMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: singleMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const handleDeleteDeal = React.useCallback(\n async (dealId: string) => {\n if (pendingDeleteId) return\n const confirmed = await confirm({\n title: t(\n 'customers.deals.list.deleteConfirm',\n 'Delete this deal? This action cannot be undone.',\n ),\n variant: 'destructive',\n })\n if (!confirmed) return\n const lockVersion = rows.find((row) => row.id === dealId)?.updatedAt ?? null\n setPendingDeleteId(dealId)\n try {\n await runSingleMutation({\n operation: async () => {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(lockVersion),\n () => deleteCrud('customers/deals', {\n body: { id: dealId },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n }),\n )\n },\n context: {\n formId: singleMutationContextId,\n resourceKind: 'customers.deal',\n resourceId: dealId,\n retryLastMutation: retrySingleMutation,\n },\n })\n flash(t('customers.deals.list.deleteSuccess', 'Deal deleted.'), 'success')\n setRows((prev) => prev.filter((row) => row.id !== dealId))\n setTotal((prev) => Math.max(0, prev - 1))\n handleRefresh()\n } catch (err) {\n // A stale delete surfaces the unified conflict bar (via the guarded\n // mutation) \u2014 skip the generic error flash to avoid a double message (#2332).\n if (surfaceRecordConflict(err, t)) {\n handleRefresh()\n return\n }\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.list.deleteError', 'Failed to delete deal.')\n flash(message, 'error')\n } finally {\n setPendingDeleteId(null)\n }\n },\n [confirm, handleRefresh, pendingDeleteId, retrySingleMutation, rows, runSingleMutation, singleMutationContextId, t],\n )\n\n const handlePageSizeChange = React.useCallback((newSize: number) => {\n setPageSize(newSize)\n setPage(1)\n }, [])\n\n const handleNeedsAttentionFilter = React.useCallback(() => {\n setNeedsAttentionOnly(true)\n setPage(1)\n }, [])\n\n const handleNeedsAttentionClear = React.useCallback(() => {\n setNeedsAttentionOnly(false)\n setPage(1)\n }, [])\n\n const handleBulkDelete = React.useCallback(async (selectedRows: DealRow[]) => {\n const confirmed = await confirm({\n title: t('customers.deals.list.bulkDelete.title', 'Delete {count} deals?', { count: selectedRows.length }),\n description: t('customers.deals.list.bulkDelete.description', 'This action cannot be undone.'),\n variant: 'destructive',\n })\n if (!confirmed) return false\n\n const { succeeded, failures } = await runBulkMutation({\n operation: async () =>\n runBulkDelete(\n selectedRows,\n async (row) => {\n await deleteCrud('customers/deals', {\n body: { id: row.id },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n })\n },\n {\n fallbackErrorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n logTag: 'customers.deals.list',\n progress: {\n jobType: 'customers.deals.bulk_delete',\n name: t('customers.deals.list.bulkDelete.progressName', 'Delete selected deals'),\n description: t(\n 'customers.deals.list.bulkDelete.progressDescription',\n '{count} deals selected for deletion',\n { count: selectedRows.length },\n ),\n meta: { source: 'customers.deals.list' },\n },\n },\n ),\n context: {\n formId: bulkMutationContextId,\n resourceKind: 'customers.deal',\n retryLastMutation: retryBulkMutation,\n },\n })\n\n if (succeeded.length > 0) {\n const succeededIds = new Set(succeeded.map((r) => r.id))\n setRows((prev) => prev.filter((r) => !succeededIds.has(r.id)))\n setTotal((prev) => Math.max(0, prev - succeeded.length))\n setReloadToken((prev) => prev + 1)\n if (succeeded.length > 1) {\n coalesceLastOperations(succeeded.length, {\n commandId: 'customers.deals.delete',\n actionLabel: t('customers.deals.list.bulkDelete.operationLabel', 'Delete {count} deals', { count: succeeded.length }),\n resourceKind: 'customers.deal',\n })\n }\n if (failures.length === 0) {\n flash(\n t('customers.deals.list.bulkDelete.success', '{count} deals deleted', { count: succeeded.length }),\n 'success',\n )\n } else {\n flash(\n t('customers.deals.list.bulkDelete.partial', '{deleted} of {total} deals deleted; {failed} failed', {\n deleted: succeeded.length,\n total: selectedRows.length,\n failed: failures.length,\n }),\n 'warning',\n )\n }\n }\n\n for (const group of groupBulkDeleteFailures(failures)) {\n const message = group.count === 1\n ? group.sampleMessage\n : t(\n 'customers.deals.list.bulkDelete.failedGroup',\n '{count} deals could not be deleted: {message}',\n { count: group.count, message: group.sampleMessage },\n )\n flash(message, 'error')\n }\n\n return succeeded.length > 0\n }, [bulkMutationContextId, confirm, retryBulkMutation, runBulkMutation, t])\n\n const { data: customFieldDefs = [] } = useCustomFieldDefs([E.customers.customer_deal], {\n keyExtras: [scopeVersion, reloadToken],\n })\n const currentUserId = useCurrentUserId()\n const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])\n // Single staff load drives both the owner FILTER options and the owner-name\n // map shared with the OWNER cell + the KPI strip (userId \u2192 display name).\n // No per-row fetch \u2014 see spec audit \"Owner names\" resolution.\n const [ownerNames, setOwnerNames] = React.useState<Record<string, string>>({})\n React.useEffect(() => {\n const controller = new AbortController()\n let cancelled = false\n void fetchAssignableStaffMembers('', { pageSize: 100, signal: controller.signal })\n .then((items) => {\n if (cancelled) return\n setOwnerFilterOptions(mapAssignableStaffToFilterOptions(items))\n const names: Record<string, string> = {}\n for (const item of items) {\n if (item.userId) names[item.userId] = item.displayName\n }\n setOwnerNames(names)\n })\n .catch(() => {\n if (cancelled) return\n setOwnerFilterOptions([])\n setOwnerNames({})\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [scopeVersion])\n const resolvedOwnerFilterOptions = React.useMemo(\n () => ensureCurrentUserFilterOption(\n ownerFilterOptions,\n currentUserId,\n t('customers.filters.currentUser', 'Current user'),\n ),\n [currentUserId, ownerFilterOptions, t],\n )\n const loadOwnerFilterOptions = React.useCallback(async (query?: string): Promise<AdvancedFilterOption[]> => {\n const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })\n return mapAssignableStaffToFilterOptions(items)\n }, [])\n\n const startOfToday = React.useMemo(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n return today\n }, [])\n const isDealOverdue = React.useCallback(\n (row: DealRow): boolean =>\n !!row.expectedCloseAt && new Date(row.expectedCloseAt) < startOfToday && row.status === 'open',\n [startOfToday],\n )\n\n const columns = React.useMemo<ColumnDef<DealRow>[]>(() => {\n const noValue = <span className=\"text-muted-foreground text-sm\">{t('customers.deals.list.noValue')}</span>\n const unknownOwner = t('customers.deals.list.unknownOwner')\n\n const customColumns = customFieldDefs\n .filter((def) => supportsCustomFieldColumn(def))\n .map<ColumnDef<DealRow>>((def) => ({\n accessorKey: `cf_${def.key}`,\n header: def.label || def.key,\n meta: {\n columnChooserGroup: def.group?.title ?? t('ui.columnChooser.customFieldsGroup', 'Custom Fields'),\n filterGroup: def.group?.title ?? t('ui.columnChooser.customFieldsGroup', 'Custom Fields'),\n filterType: mapCustomFieldKindToFilterType(def.kind),\n filterOptions: normalizeCustomFieldFilterOptions(def.options),\n hidden: def.listVisible === false,\n maxWidth: '220px',\n },\n cell: ({ getValue }) => {\n const value = getValue()\n if (value == null) return noValue\n if (Array.isArray(value)) {\n const normalized = normalizeCollectionLabels(\n value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item\n return String(item)\n }),\n )\n if (!normalized.length) return noValue\n return <CollectionPreviewCell labels={normalized} maxVisible={2} />\n }\n if (typeof value === 'boolean') {\n return (\n <span className=\"text-sm\">\n {value\n ? t('customers.deals.list.booleanYes', 'Yes')\n : t('customers.deals.list.booleanNo', 'No')}\n </span>\n )\n }\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (!stringValue) return noValue\n return <span className=\"text-sm\">{stringValue}</span>\n },\n }))\n\n return [\n {\n accessorKey: 'title',\n header: t('customers.deals.list.columns.title'),\n meta: {\n alwaysVisible: true,\n columnChooserGroup: 'Basic Info',\n filterKey: 'title',\n filterGroup: 'Deal',\n maxWidth: '280px',\n },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\">\n <Briefcase className=\"h-4 w-4\" />\n </span>\n <span className=\"font-medium text-foreground truncate\">{row.original.title}</span>\n {isDealOverdue(row.original) ? (\n <AlertTriangle\n className=\"h-4 w-4 shrink-0 text-status-warning-text\"\n aria-label={t('customers.deals.list.close.overdue')}\n />\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('customers.deals.list.columns.status'),\n meta: {\n filterType: 'select' as const,\n filterOptions: dictionaryOptions.dealStatuses,\n columnChooserGroup: 'Basic Info',\n filterKey: 'status',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const status = row.original.status\n if (!status) return noValue\n const entry = dictionaryMaps['deal-statuses']?.[status]\n const label = entry?.label ?? status\n const variant = coerceStatusBadgeVariant(mapDictionaryColorToTone(entry?.color))\n return <StatusBadge variant={variant} dot>{label}</StatusBadge>\n },\n },\n {\n accessorKey: 'pipelineStage',\n header: t('customers.deals.list.columns.pipelineStage'),\n meta: {\n filterType: 'select' as const,\n filterOptions: dictionaryOptions.pipelineStages,\n columnChooserGroup: 'Pipeline',\n filterKey: 'pipeline_stage',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const stage = row.original.pipelineStage\n if (!stage) return noValue\n const label = dictionaryMaps['pipeline-stages']?.[stage]?.label ?? stage\n return <span className=\"text-foreground\">{label}</span>\n },\n },\n {\n accessorKey: 'pipelineId',\n header: t('customers.deals.list.columns.pipeline', 'Pipeline'),\n meta: {\n columnChooserGroup: 'Pipeline',\n filterKey: 'pipeline_id',\n filterGroup: 'Deal',\n maxWidth: '220px',\n },\n cell: ({ row }) => {\n const name = row.original.pipelineId ? pipelineNames[row.original.pipelineId] : null\n return name ? <span className=\"text-sm\">{name}</span> : noValue\n },\n },\n {\n accessorKey: 'valueAmount',\n header: t('customers.deals.list.columns.value'),\n meta: {\n filterType: 'number' as const,\n columnChooserGroup: 'Financial',\n filterKey: 'value_amount',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const amount = formatGroupedAmount(row.original.valueAmount ?? null)\n if (amount === null) return noValue\n const currency = row.original.valueCurrency\n return (\n <div className=\"flex flex-col\">\n <span className=\"font-medium text-foreground\">{amount}</span>\n {currency ? <span className=\"text-xs text-muted-foreground\">{currency}</span> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'probability',\n header: t('customers.deals.list.columns.probability'),\n meta: {\n filterType: 'number' as const,\n columnChooserGroup: 'Financial',\n filterKey: 'probability',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const value = row.original.probability\n if (typeof value === 'number' && Number.isFinite(value)) {\n return <span className=\"font-medium text-foreground\">{`${Math.min(Math.max(value, 0), 100)}%`}</span>\n }\n return noValue\n },\n },\n {\n accessorKey: 'expectedCloseAt',\n header: t('customers.deals.list.columns.expectedClose'),\n meta: {\n columnChooserGroup: 'Dates',\n filterKey: 'expected_close_at',\n filterGroup: 'Activity',\n filterIconName: 'calendar',\n },\n cell: ({ row }) => {\n const expectedCloseAt = row.original.expectedCloseAt\n if (!expectedCloseAt) return noValue\n let subtitle: React.ReactNode = null\n if (isDealOverdue(row.original)) {\n subtitle = (\n <span className=\"text-xs text-status-error-text\">{t('customers.deals.list.close.overdue')}</span>\n )\n } else if (row.original.status === 'win') {\n subtitle = (\n <span className=\"text-xs text-muted-foreground\">{t('customers.deals.list.close.won')}</span>\n )\n } else if (row.original.status === 'loose') {\n subtitle = (\n <span className=\"text-xs text-muted-foreground\">{t('customers.deals.list.close.lost')}</span>\n )\n } else {\n const relative = formatRelativeTime(expectedCloseAt, { locale, translate: t })\n if (relative) {\n subtitle = <span className=\"text-xs text-muted-foreground\">{relative}</span>\n }\n }\n return (\n <div className=\"flex flex-col\">\n <span className=\"text-foreground\">\n {formatDateValue(expectedCloseAt, t('customers.deals.list.noValue'))}\n </span>\n {subtitle}\n </div>\n )\n },\n },\n {\n accessorKey: 'ownerUserId',\n header: t('customers.deals.list.columns.owner', 'Owner'),\n meta: {\n columnChooserGroup: 'CRM',\n filterType: 'select',\n filterOptions: resolvedOwnerFilterOptions,\n filterLoadOptions: loadOwnerFilterOptions,\n filterGroup: 'CRM',\n filterIconName: 'user-round',\n filterKey: 'owner_user_id',\n },\n cell: ({ row }) => {\n const ownerUserId = row.original.ownerUserId\n if (!ownerUserId) return noValue\n const label = ownerNames[ownerUserId]?.trim() || unknownOwner\n return (\n <div className=\"flex items-center gap-2 min-w-0\">\n <Avatar label={label} size=\"sm\" />\n <span className=\"text-foreground truncate\">{label}</span>\n </div>\n )\n },\n },\n {\n accessorKey: 'companies',\n header: t('customers.deals.list.columns.companies'),\n meta: {\n columnChooserGroup: 'Associations',\n filterable: false,\n filterGroup: 'CRM',\n filterIconName: 'building-2',\n maxWidth: '220px',\n tooltipContent: (row: DealRow) =>\n normalizeCollectionLabels(\n row.companies.map((entry) => (entry.label && entry.label.trim().length ? entry.label : t('customers.deals.list.unnamedCompany'))),\n ).join(', '),\n },\n cell: ({ row }) => {\n const companies = row.original.companies\n if (!companies.length) return noValue\n const first = companies[0]\n const firstLabel =\n first.label && first.label.trim().length ? first.label : t('customers.deals.list.unnamedCompany')\n const overflow = companies.length - 1\n return (\n <div className=\"flex items-center gap-1.5 min-w-0\">\n <Tag variant=\"neutral\" className=\"max-w-36\">\n <span className=\"truncate\">{firstLabel}</span>\n </Tag>\n {overflow > 0 ? <Tag variant=\"neutral\">{`+${overflow}`}</Tag> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'people',\n header: t('customers.deals.list.columns.people'),\n meta: {\n columnChooserGroup: 'Associations',\n filterable: false,\n filterGroup: 'CRM',\n filterIconName: 'user-round',\n maxWidth: '220px',\n tooltipContent: (row: DealRow) =>\n normalizeCollectionLabels(\n row.people.map((entry) => (entry.label && entry.label.trim().length ? entry.label : t('customers.deals.list.unnamedPerson'))),\n ).join(', '),\n },\n cell: ({ row }) => {\n const people = row.original.people\n if (!people.length) return noValue\n const labels = normalizeCollectionLabels(\n people.map((person) =>\n person.label && person.label.trim().length ? person.label : t('customers.deals.list.unnamedPerson')),\n )\n const tooltip = labels.join(', ')\n return (\n <SimpleTooltip content={tooltip} side=\"top\">\n <span className=\"inline-flex\">\n <AvatarStack max={4} size=\"sm\">\n {people.map((person) => (\n <Avatar\n key={person.id}\n label={person.label || t('customers.deals.list.unnamedPerson')}\n size=\"sm\"\n />\n ))}\n </AvatarStack>\n </span>\n </SimpleTooltip>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: t('customers.deals.list.columns.updatedAt'),\n meta: {\n columnChooserGroup: 'Dates',\n filterKey: 'updated_at',\n filterGroup: 'Activity',\n filterIconName: 'calendar',\n },\n cell: ({ row }) => (\n <span className=\"text-sm\">\n {formatDateValue(row.original.updatedAt ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n ...customColumns,\n ]\n }, [customFieldDefs, dictionaryMaps, dictionaryOptions, isDealOverdue, loadOwnerFilterOptions, locale, ownerNames, pipelineNames, resolvedOwnerFilterOptions, t])\n\n const { advancedFilterFields } = useAutoDiscoveredFields({ columns, customFieldDefs })\n\n // Sync auto-discovered fields into the `filterPanel` declared at the top of\n // the component. See the comment on the `panelFields` state for why this\n // late-binding is safe. Bail out by content (field-key list) \u2014 every render\n // of `useAutoDiscoveredFields` produces fresh `FilterFieldDef` object refs\n // even when the set of fields hasn't actually changed, so a naive reference\n // setState would loop (\"Maximum update depth exceeded\").\n React.useEffect(() => {\n setPanelFields((prev) => {\n if (prev === advancedFilterFields) return prev\n if (prev.length === advancedFilterFields.length) {\n let same = true\n for (let i = 0; i < prev.length; i++) {\n if (prev[i].key !== advancedFilterFields[i].key) { same = false; break }\n }\n if (same) return prev\n }\n return advancedFilterFields\n })\n }, [advancedFilterFields])\n\n const associationFilterFields = React.useMemo<FilterFieldDef[]>(() => {\n const personLabels = new Map<string, string>()\n const companyLabels = new Map<string, string>()\n for (const row of rows) {\n for (const person of row.people) {\n if (selectedPersonIds.includes(person.id) && person.label.trim().length > 0) {\n personLabels.set(person.id, person.label)\n }\n }\n for (const company of row.companies) {\n if (selectedCompanyIds.includes(company.id) && company.label.trim().length > 0) {\n companyLabels.set(company.id, company.label)\n }\n }\n }\n return [\n {\n key: 'people',\n label: t('customers.deals.list.columns.people', 'People'),\n type: 'select',\n options: selectedPersonIds.map((id) => ({ value: id, label: personLabels.get(id) ?? id })),\n },\n {\n key: 'companies',\n label: t('customers.deals.list.columns.companies', 'Companies'),\n type: 'select',\n options: selectedCompanyIds.map((id) => ({ value: id, label: companyLabels.get(id) ?? id })),\n },\n ]\n }, [rows, selectedCompanyIds, selectedPersonIds, t])\n const associationFilterTree = React.useMemo<AdvancedFilterTree>(() => {\n const rules: Array<{ field: string; operator: 'is_any_of'; value: string[] }> = []\n if (selectedPersonIds.length) rules.push({ field: 'people', operator: 'is_any_of', value: selectedPersonIds })\n if (selectedCompanyIds.length) rules.push({ field: 'companies', operator: 'is_any_of', value: selectedCompanyIds })\n return rules.length ? makeMultiRuleTree(rules) : createEmptyTree()\n }, [selectedCompanyIds, selectedPersonIds])\n const handleAssociationFilterRemove = React.useCallback((nodeId: string) => {\n const node = associationFilterTree.root.children.find((child) => child.id === nodeId)\n if (!node || node.type !== 'rule') return\n if (node.field === 'people') setSelectedPersonIds([])\n if (node.field === 'companies') setSelectedCompanyIds([])\n setPage(1)\n }, [associationFilterTree.root.children])\n\n const dealsPresets = React.useMemo<FilterPreset[]>(() => makeDealsPresets(), [])\n\n return (\n <Page>\n <PageBody>\n <ViewTabsRow active=\"list\" className=\"mb-4\" />\n <DealsKpiStrip\n ownerNames={ownerNames}\n stageDictionary={dictionaryMaps['pipeline-stages'] ?? {}}\n pipelineCount={Object.keys(pipelineNames).length}\n scopeVersion={scopeVersion}\n reloadToken={reloadToken}\n onNeedsAttentionClick={handleNeedsAttentionFilter}\n className=\"mb-4\"\n />\n <DataTable<DealRow>\n stickyFirstColumn\n stickyActionsColumn\n actionsColumnAlign=\"center\"\n title={t('customers.deals.list.title')}\n actions={(\n <Button asChild>\n <Link href=\"/backend/customers/deals/create\">\n {t('customers.deals.list.actions.new', 'New deal')}\n </Link>\n </Button>\n )}\n columns={columns}\n columnChooser={{ auto: true }}\n data={rows}\n onRowClick={(row) => {\n router.push(`/backend/customers/deals/${row.id}`)\n }}\n rowActions={(row) => {\n const isDeleting = pendingDeleteId === row.id\n return (\n <RowActions\n items={[\n {\n id: 'edit',\n label: t('customers.deals.list.actions.edit', 'Edit'),\n onSelect: () => { router.push(`/backend/customers/deals/${row.id}`) },\n },\n {\n id: 'open-new-tab',\n label: t('customers.deals.list.actions.openInNewTab', 'Open in new tab'),\n onSelect: () => {\n if (typeof window !== 'undefined') {\n window.open(`/backend/customers/deals/${row.id}`, '_blank', 'noopener')\n }\n },\n },\n {\n id: 'delete',\n label: isDeleting\n ? t('customers.deals.list.actions.deleting', 'Deleting\u2026')\n : t('customers.deals.list.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => handleDeleteDeal(row.id),\n },\n ]}\n />\n )\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n bulkActions={[\n {\n id: 'delete',\n label: t('customers.deals.list.actions.delete', 'Delete'),\n destructive: true,\n onExecute: handleBulkDelete,\n },\n ]}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={t('customers.deals.list.searchPlaceholder')}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n totalIsCapped,\n onPageChange: (nextPage) => setPage(nextPage),\n pageSizeOptions: [10, 25, 50, 100],\n onPageSizeChange: handlePageSizeChange,\n cacheStatus,\n }}\n isLoading={isLoading}\n refreshButton={{\n label: t('customers.deals.list.refresh'),\n onRefresh: handleRefresh,\n }}\n exporter={exportConfig}\n entityId={E.customers.customer_deal}\n perspective={{ tableId: extensionPoints.hosts.dealsTable.tableId }}\n advancedFilter={{\n auto: true,\n value: filterPanel.tree,\n onChange: filterPanel.setTree,\n onApply: () => filterPanel.flush(),\n onClear: handleAdvancedFilterClear,\n triggerRef: filtersTriggerRef,\n externalPopover: true,\n onTriggerClick: () => setFiltersOpen((prev) => !prev),\n onApplyTree: (tree) => {\n filterPanel.replaceTree(tree)\n setPage(1)\n },\n }}\n activeFilterChips={(\n <>\n {needsAttentionOnly ? (\n <div\n className=\"flex items-center gap-2 overflow-x-auto border-b border-border bg-background px-4 py-2\"\n data-testid=\"active-filter-chips\"\n >\n <div\n className=\"inline-flex items-center gap-1\"\n data-testid=\"active-filter-chip\"\n aria-label={t('customers.deals.list.filters.needsAttention')}\n >\n <Tag variant=\"warning\" dot>{t('customers.deals.list.filters.needsAttention')}</Tag>\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n aria-label={t('customers.deals.list.filters.needsAttentionRemove')}\n onClick={handleNeedsAttentionClear}\n >\n <X className=\"size-3\" />\n </IconButton>\n </div>\n </div>\n ) : null}\n <ActiveFilterChips\n tree={associationFilterTree}\n fields={associationFilterFields}\n popoverOpen={filtersOpen}\n onRemoveNode={handleAssociationFilterRemove}\n onOpen={() => setFiltersOpen(true)}\n />\n <ActiveFilterChips\n tree={filterPanel.appliedTree}\n fields={advancedFilterFields}\n popoverOpen={filtersOpen}\n onRemoveNode={(id) => filterPanel.dispatch({ type: 'removeNode', nodeId: id })}\n onOpen={() => setFiltersOpen(true)}\n />\n </>\n )}\n filterAwareEmptyState={{\n active: needsAttentionOnly || associationFilterTree.root.children.length > 0 || advancedFilterState.root.children.length > 0,\n entityNamePlural: t('customers.deals.entityPlural', 'deals'),\n canRemoveLast: needsAttentionOnly || associationFilterTree.root.children.length > 0 || filterPanel.tree.root.children.length > 0,\n onClearAll: () => {\n handleAdvancedFilterClear()\n setSelectedPersonIds([])\n setSelectedCompanyIds([])\n setNeedsAttentionOnly(false)\n },\n onRemoveLast: () => {\n if (needsAttentionOnly) {\n handleNeedsAttentionClear()\n return\n }\n if (selectedCompanyIds.length > 0) {\n setSelectedCompanyIds([])\n setPage(1)\n return\n }\n if (selectedPersonIds.length > 0) {\n setSelectedPersonIds([])\n setPage(1)\n return\n }\n filterPanel.dispatch({ type: 'removeLast' })\n },\n }}\n emptyState={(\n <ListEmptyState\n entityName={t('customers.deals.entityPlural', 'deals')}\n createHref=\"/backend/customers/deals/create\"\n createLabel={t('customers.deals.list.actions.new', 'New deal')}\n />\n )}\n virtualized\n />\n <AdvancedFilterPanel\n fields={advancedFilterFields}\n value={filterPanel.tree}\n onChange={filterPanel.setTree}\n onApply={filterPanel.flush}\n onClear={handleAdvancedFilterClear}\n onFlush={filterPanel.flush}\n pendingErrors={filterPanel.pendingErrors}\n userId={currentUserId}\n presets={dealsPresets}\n open={filtersOpen}\n onOpenChange={setFiltersOpen}\n triggerRef={filtersTriggerRef}\n savedFilterStorageKey=\"customers.deals.list\"\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nfunction mapDeal(item: Record<string, unknown>): DealRow | null {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const title = typeof item.title === 'string' ? item.title : ''\n const status = typeof item.status === 'string' ? item.status : null\n const pipelineStage = typeof item.pipeline_stage === 'string' ? item.pipeline_stage : null\n const pipelineStageId = typeof item.pipeline_stage_id === 'string' ? item.pipeline_stage_id : null\n const pipelineId = typeof item.pipeline_id === 'string' ? item.pipeline_id : null\n const valueAmountRaw = item.value_amount\n const valueAmount =\n typeof valueAmountRaw === 'number'\n ? valueAmountRaw\n : typeof valueAmountRaw === 'string' && valueAmountRaw.trim()\n ? Number(valueAmountRaw)\n : null\n const valueCurrency =\n typeof item.value_currency === 'string' && item.value_currency.trim().length\n ? item.value_currency.trim().toUpperCase()\n : null\n const probabilityRaw = item.probability\n const probability =\n typeof probabilityRaw === 'number'\n ? probabilityRaw\n : typeof probabilityRaw === 'string' && probabilityRaw.trim().length\n ? Number(probabilityRaw)\n : null\n const expectedCloseAt = typeof item.expected_close_at === 'string' ? item.expected_close_at : null\n const updatedAt = typeof item.updated_at === 'string' ? item.updated_at : null\n const ownerUserId = typeof item.owner_user_id === 'string' ? item.owner_user_id : null\n const peopleRaw = Array.isArray(item.people) ? item.people : []\n const companiesRaw = Array.isArray(item.companies) ? item.companies : []\n const people = peopleRaw\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const data = entry as Record<string, unknown>\n const pid = typeof data.id === 'string' ? data.id : null\n if (!pid) return null\n const label = typeof data.label === 'string' ? data.label : ''\n return { id: pid, label }\n })\n .filter((entry): entry is { id: string; label: string } => !!entry)\n const companies = companiesRaw\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const data = entry as Record<string, unknown>\n const cid = typeof data.id === 'string' ? data.id : null\n if (!cid) return null\n const label = typeof data.label === 'string' ? data.label : ''\n return { id: cid, label }\n })\n .filter((entry): entry is { id: string; label: string } => !!entry)\n const customFields: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(item)) {\n if (key.startsWith('cf_')) customFields[key] = value\n }\n return withDataTableNamespaces({\n id,\n title,\n status,\n pipelineStage,\n pipelineStageId,\n pipelineId,\n valueAmount,\n valueCurrency,\n probability,\n expectedCloseAt,\n updatedAt,\n ownerUserId,\n people,\n companies,\n ...customFields,\n }, item)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'\nimport Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { AdvancedFilterTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'\nimport { createEmptyTree, makeRuleTree, makeMultiRuleTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'\nimport { deserializeTree, deserializeAdvancedFilter, flatToTree, mapDictionaryColorToTone, serializeTree, type FilterFieldDef, type FilterOption as AdvancedFilterOption } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { groupBulkDeleteFailures, runBulkDelete } from '@open-mercato/ui/backend/utils/bulkDelete'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { coalesceLastOperations } from '@open-mercato/ui/backend/operations/store'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { StatusBadge, type StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'\nimport { Avatar, AvatarStack } from '@open-mercato/ui/primitives/avatar'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'\nimport { Briefcase, AlertTriangle, X } from 'lucide-react'\nimport { isLostDealStatus, isWonDealStatus } from '../../../lib/dealStatus'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport { ViewTabsRow } from './pipeline/components/ViewTabsRow'\nimport { DealsKpiStrip } from '../../../components/DealsKpiStrip'\nimport { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n type CustomerDictionaryKind,\n type CustomerDictionaryMap,\n} from '../../../lib/dictionaries'\nimport {\n ensureCustomerDictionary,\n invalidateCustomerDictionary,\n} from '../../../components/detail/hooks/useCustomerDictionary'\nimport {\n useCustomFieldDefs,\n} from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n mapCustomFieldKindToFilterType,\n normalizeCustomFieldFilterOptions,\n supportsCustomFieldColumn,\n} from '@open-mercato/ui/backend/utils/customFieldColumns'\nimport { CollectionPreviewCell, normalizeCollectionLabels } from '../../../components/list/CollectionPreviewCell'\nimport { useAutoDiscoveredFields } from '@open-mercato/ui/backend/utils/useAutoDiscoveredFields'\nimport { useAdvancedFilterTree } from '@open-mercato/ui/backend/hooks/useAdvancedFilter'\nimport { AdvancedFilterPanel } from '@open-mercato/ui/backend/filters/AdvancedFilterPanel'\nimport { ActiveFilterChips } from '@open-mercato/ui/backend/filters/ActiveFilterChips'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\nimport type { FilterPreset } from '@open-mercato/ui/backend/filters/QuickFilters'\nimport {\n ensureCurrentUserFilterOption,\n fetchAssignableStaffMembers,\n mapAssignableStaffToFilterOptions,\n} from '../../../components/detail/assignableStaff'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nfunction makeDealsPresets(): FilterPreset[] {\n return [\n {\n id: 'my-deals',\n labelKey: 'customers.deals.presets.myDeals',\n requiresUser: true,\n build: ({ userId }) => makeRuleTree({ field: 'owner_user_id', operator: 'is', value: userId }),\n },\n {\n id: 'closing-month',\n labelKey: 'customers.deals.presets.closingMonth',\n iconName: 'clock',\n build: ({ now }) => {\n const start = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10)\n const end = new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString().slice(0, 10)\n return makeRuleTree({ field: 'expected_close_at', operator: 'between', value: [start, end] })\n },\n },\n // The Deal entity has no dedicated \"at risk\" or health-score field \u2014 `customer_deals`\n // exposes only `status` (open/win/lost/closed/in_progress, dictionary-driven) and\n // `closure_outcome`. Rather than fabricate a mapping, the \"At risk\" preset is omitted\n // until the data model exposes a first-class signal.\n {\n id: 'won-quarter',\n labelKey: 'customers.deals.presets.wonQuarter',\n build: ({ now }) => {\n const quarter = Math.floor(now.getMonth() / 3)\n const start = new Date(now.getFullYear(), quarter * 3, 1).toISOString().slice(0, 10)\n return makeMultiRuleTree([\n { field: 'status', operator: 'is', value: 'win' },\n { field: 'expected_close_at', operator: 'is_after', value: start },\n ], 'and')\n },\n },\n ]\n}\n\ntype DealRow = {\n id: string\n title: string\n status?: string | null\n pipelineStage?: string | null\n pipelineStageId?: string | null\n pipelineId?: string | null\n valueAmount?: number | null\n valueCurrency?: string | null\n probability?: number | null\n expectedCloseAt?: string | null\n updatedAt?: string | null\n ownerUserId?: string | null\n companies: { id: string; label: string }[]\n people: { id: string; label: string }[]\n} & Record<string, unknown>\n\ntype DealsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\ntype FilterOption = { value: string; label: string }\ntype DictionaryOptionWithTone = AdvancedFilterOption & FilterOption\n\ntype DictionaryKey = Extract<CustomerDictionaryKind, 'deal-statuses' | 'pipeline-stages'>\n\nconst PAGE_SIZE = 20\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction isUuid(value: string | null | undefined): value is string {\n if (!value) return false\n return UUID_REGEX.test(value.trim())\n}\n\nfunction normalizeIdCandidates(raw: Array<string>): string[] {\n const set = new Set<string>()\n raw.forEach((candidate) => {\n candidate\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0)\n .forEach((part) => {\n if (isUuid(part)) set.add(part)\n })\n })\n return Array.from(set)\n}\n\nfunction extractIdsFromParams(params: URLSearchParams | null | undefined, key: string): string[] {\n if (!params) return []\n const values = params.getAll(key)\n return normalizeIdCandidates(values)\n}\n\nfunction formatDateValue(value: string | null | undefined, fallback: string): string {\n if (!value) return fallback\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return fallback\n return date.toLocaleDateString()\n}\n\nconst STATUS_BADGE_VARIANTS: ReadonlySet<StatusBadgeVariant> = new Set([\n 'success',\n 'warning',\n 'error',\n 'info',\n 'neutral',\n])\n\nfunction coerceStatusBadgeVariant(\n tone: ReturnType<typeof mapDictionaryColorToTone>,\n): StatusBadgeVariant {\n if (tone && STATUS_BADGE_VARIANTS.has(tone as StatusBadgeVariant)) {\n return tone as StatusBadgeVariant\n }\n return 'neutral'\n}\n\nconst groupedAmountFormatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 0 })\n\nfunction formatGroupedAmount(amount: number | null | undefined): string | null {\n if (typeof amount !== 'number' || Number.isNaN(amount)) return null\n return groupedAmountFormatter.format(amount)\n}\n\nexport default function CustomersDealsPage() {\n const t = useT()\n const locale = useLocale()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n\n const [rows, setRows] = React.useState<DealRow[]>([])\n const [page, setPage] = React.useState(() => {\n const raw = Number(searchParams?.get('page') ?? '1')\n return Number.isFinite(raw) && raw > 0 ? raw : 1\n })\n const [pageSize, setPageSize] = React.useState(PAGE_SIZE)\n const [sorting, setSorting] = React.useState<import('@tanstack/react-table').SortingState>([])\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [search, setSearch] = React.useState(() => searchParams?.get('search')?.trim() ?? '')\n const [isLoading, setIsLoading] = React.useState(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [pendingDeleteId, setPendingDeleteId] = React.useState<string | null>(null)\n const [needsAttentionOnly, setNeedsAttentionOnly] = React.useState(() => searchParams?.get('needsAttention') === 'true')\n // One-shot URL hydration used as the hook's initial value. The hook is the\n // single source of truth from this point on \u2014 the page MUST NOT keep a\n // parallel `useState<AdvancedFilterTree>` (see spec \"Migration & Backward\n // Compatibility\" \u2192 state ownership).\n const initialFilterTree = React.useMemo<AdvancedFilterTree>(() => {\n if (!searchParams) return createEmptyTree()\n const record: Record<string, string> = {}\n searchParams.forEach((value, key) => {\n if (key.startsWith('filter[')) record[key] = value\n })\n const v2 = deserializeTree(record)\n if (v2) return v2\n const flat = deserializeAdvancedFilter(record)\n if (flat) return flatToTree(flat)\n return createEmptyTree()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n // `filterPanel` lives at the top of the component so derived state below\n // (URL params, data fetch, export config) can read `filterPanel.appliedTree`\n // directly. Real `FilterFieldDef[]` arrives later from `useAutoDiscoveredFields`\n // (it depends on columns) and is synced into the hook via a small effect at\n // the bottom of the component. The hook reads fields through a ref at\n // validation time only \u2014 first validation cannot fire before user input, by\n // which point fields have settled, so the empty initial value is safe.\n const [panelFields, setPanelFields] = React.useState<FilterFieldDef[]>([])\n const [filtersOpen, setFiltersOpen] = React.useState(false)\n const filtersTriggerRef = React.useRef<HTMLButtonElement | null>(null)\n const filterPanel = useAdvancedFilterTree({\n initial: initialFilterTree,\n fields: panelFields,\n onApply: () => setPage(1),\n })\n const advancedFilterState = filterPanel.appliedTree\n const handleAdvancedFilterClear = React.useCallback(() => {\n filterPanel.clear()\n setPage(1)\n }, [filterPanel])\n const [cacheStatus, setCacheStatus] = React.useState<'hit' | 'miss' | null>(null)\n\n const initialPersonIds = React.useMemo(\n () => extractIdsFromParams(searchParams, 'personId'),\n [searchParams],\n )\n const initialCompanyIds = React.useMemo(\n () => extractIdsFromParams(searchParams, 'companyId'),\n [searchParams],\n )\n\n const [selectedPersonIds, setSelectedPersonIds] = React.useState<string[]>(initialPersonIds)\n const [selectedCompanyIds, setSelectedCompanyIds] = React.useState<string[]>(initialCompanyIds)\n\n const [dictionaryMaps, setDictionaryMaps] = React.useState<Record<DictionaryKey, CustomerDictionaryMap>>({\n 'deal-statuses': {},\n 'pipeline-stages': {},\n })\n\n const [pipelineNames, setPipelineNames] = React.useState<Record<string, string>>({})\n\n const fetchDictionaryEntries = React.useCallback(\n async (kind: DictionaryKey) => {\n try {\n const data = await ensureCustomerDictionary(queryClient, kind, scopeVersion)\n setDictionaryMaps((prev) => ({ ...prev, [kind]: data.map }))\n } catch {\n setDictionaryMaps((prev) => ({ ...prev, [kind]: {} }))\n }\n },\n [queryClient, scopeVersion],\n )\n\n React.useEffect(() => {\n let cancelled = false\n async function loadDictionaries() {\n if (cancelled) return\n await Promise.all([fetchDictionaryEntries('deal-statuses'), fetchDictionaryEntries('pipeline-stages')])\n }\n loadDictionaries().catch(() => {})\n return () => { cancelled = true }\n }, [fetchDictionaryEntries, reloadToken])\n const dictionaryOptions = React.useMemo(() => {\n const toOptions = (map?: CustomerDictionaryMap | null): DictionaryOptionWithTone[] =>\n Object.values(map ?? {})\n .map((entry) => {\n const tone = mapDictionaryColorToTone(entry.color)\n const option: DictionaryOptionWithTone = { value: entry.value, label: entry.label }\n if (tone) option.tone = tone\n return option\n })\n .sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))\n return {\n dealStatuses: toOptions(dictionaryMaps['deal-statuses']),\n pipelineStages: toOptions(dictionaryMaps['pipeline-stages']),\n }\n }, [dictionaryMaps])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadPipelines() {\n try {\n const call = await apiCall<{ items?: Array<{ id: string; name: string }> }>('/api/customers/pipelines')\n if (cancelled || !call.ok) return\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const map: Record<string, string> = {}\n items.forEach((p) => { if (p.id && p.name) map[p.id] = p.name })\n setPipelineNames(map)\n } catch (err) {\n logger.warn('failed to load pipelines', { component: 'deals.list', err })\n }\n }\n loadPipelines().catch((err) => {\n logger.warn('loadPipelines threw', { component: 'deals.list', err })\n })\n return () => { cancelled = true }\n }, [reloadToken, scopeVersion])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value.trim())\n setPage(1)\n }, [])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (sorting.length > 0) {\n params.set('sort', sorting[0].id)\n params.set('order', sorting[0].desc ? 'desc' : 'asc')\n }\n if (search.trim().length) params.set('search', search.trim())\n if (selectedPersonIds.length) params.set('personId', selectedPersonIds.join(','))\n if (selectedCompanyIds.length) params.set('companyId', selectedCompanyIds.join(','))\n if (needsAttentionOnly) params.set('needsAttention', 'true')\n const advancedParams = serializeTree(advancedFilterState)\n for (const [key, val] of Object.entries(advancedParams)) {\n params.set(key, val)\n }\n return params.toString()\n }, [advancedFilterState, needsAttentionOnly, page, pageSize, search, selectedCompanyIds, selectedPersonIds, sorting])\n\n const currentParams = React.useMemo(\n () => Object.fromEntries(new URLSearchParams(queryParams)),\n [queryParams],\n )\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl('customers/deals', { ...currentParams, exportScope: 'view' }, format),\n },\n full: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl('customers/deals', { ...currentParams, exportScope: 'full', all: 'true' }, format),\n },\n }), [currentParams])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setCacheStatus(null)\n try {\n const fallback: DealsResponse = { items: [], total: 0, totalPages: 1 }\n const call = await apiCall<DealsResponse>(`/api/customers/deals?${queryParams}`, undefined, { fallback })\n if (!call.ok) {\n const message =\n typeof (call.result as { error?: string } | undefined)?.error === 'string'\n ? (call.result as { error?: string }).error!\n : t('customers.deals.list.error.load')\n flash(message, 'error')\n if (!cancelled) setCacheStatus(null)\n return\n }\n const payload = call.result ?? fallback\n if (cancelled) return\n setCacheStatus(call.cacheStatus ?? null)\n const items = Array.isArray(payload.items) ? payload.items : []\n const mapped = items\n .map((item) => mapDeal(item as Record<string, unknown>))\n .filter((row): row is DealRow => !!row)\n setRows(mapped)\n setTotal(typeof payload.total === 'number' ? payload.total : mapped.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)\n setTotalIsCapped(payload.totalIsCapped === true)\n } catch (err) {\n if (!cancelled) {\n setCacheStatus(null)\n const message = err instanceof Error ? err.message : t('customers.deals.list.error.load')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [queryParams, reloadToken, scopeVersion, t])\n\n React.useEffect(() => {\n // A capped totalPages is a floor \u2014 pages past it hold reachable rows, so\n // clamping would bounce a deep-linked user off data that exists.\n if (!totalIsCapped && totalPages > 0 && page > totalPages) {\n setPage(totalPages)\n }\n }, [page, totalPages, totalIsCapped])\n\n const queryRef = React.useRef(searchParams?.toString() ?? '')\n React.useEffect(() => {\n if (!pathname) return\n const params = new URLSearchParams()\n if (search.trim().length) params.set('search', search.trim())\n if (selectedPersonIds.length) selectedPersonIds.forEach((id) => params.append('personId', id))\n if (selectedCompanyIds.length) selectedCompanyIds.forEach((id) => params.append('companyId', id))\n if (needsAttentionOnly) params.set('needsAttention', 'true')\n if (page > 1) params.set('page', String(page))\n const advancedParams = serializeTree(advancedFilterState)\n for (const [key, val] of Object.entries(advancedParams)) {\n params.set(key, val)\n }\n const next = params.toString()\n if (queryRef.current === next) return\n queryRef.current = next\n router.replace(next ? `${pathname}?${next}` : pathname, { scroll: false })\n }, [pathname, router, page, search, selectedPersonIds, selectedCompanyIds, needsAttentionOnly, advancedFilterState])\n\n const handleRefresh = React.useCallback(() => {\n void Promise.all([\n invalidateCustomerDictionary(queryClient, 'deal-statuses'),\n invalidateCustomerDictionary(queryClient, 'pipeline-stages'),\n ])\n setReloadToken((token) => token + 1)\n }, [queryClient])\n\n const bulkMutationContextId = 'customers-deals-list:bulk-delete'\n const { runMutation: runBulkMutation, retryLastMutation: retryBulkMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: bulkMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const singleMutationContextId = 'customers-deals-list:single-delete'\n const { runMutation: runSingleMutation, retryLastMutation: retrySingleMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: singleMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const handleDeleteDeal = React.useCallback(\n async (dealId: string) => {\n if (pendingDeleteId) return\n const confirmed = await confirm({\n title: t(\n 'customers.deals.list.deleteConfirm',\n 'Delete this deal? This action cannot be undone.',\n ),\n variant: 'destructive',\n })\n if (!confirmed) return\n const lockVersion = rows.find((row) => row.id === dealId)?.updatedAt ?? null\n setPendingDeleteId(dealId)\n try {\n await runSingleMutation({\n operation: async () => {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(lockVersion),\n () => deleteCrud('customers/deals', {\n body: { id: dealId },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n }),\n )\n },\n context: {\n formId: singleMutationContextId,\n resourceKind: 'customers.deal',\n resourceId: dealId,\n retryLastMutation: retrySingleMutation,\n },\n })\n flash(t('customers.deals.list.deleteSuccess', 'Deal deleted.'), 'success')\n setRows((prev) => prev.filter((row) => row.id !== dealId))\n setTotal((prev) => Math.max(0, prev - 1))\n handleRefresh()\n } catch (err) {\n // A stale delete surfaces the unified conflict bar (via the guarded\n // mutation) \u2014 skip the generic error flash to avoid a double message (#2332).\n if (surfaceRecordConflict(err, t)) {\n handleRefresh()\n return\n }\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.deals.list.deleteError', 'Failed to delete deal.')\n flash(message, 'error')\n } finally {\n setPendingDeleteId(null)\n }\n },\n [confirm, handleRefresh, pendingDeleteId, retrySingleMutation, rows, runSingleMutation, singleMutationContextId, t],\n )\n\n const handlePageSizeChange = React.useCallback((newSize: number) => {\n setPageSize(newSize)\n setPage(1)\n }, [])\n\n const handleNeedsAttentionFilter = React.useCallback(() => {\n setNeedsAttentionOnly(true)\n setPage(1)\n }, [])\n\n const handleNeedsAttentionClear = React.useCallback(() => {\n setNeedsAttentionOnly(false)\n setPage(1)\n }, [])\n\n const handleBulkDelete = React.useCallback(async (selectedRows: DealRow[]) => {\n const confirmed = await confirm({\n title: t('customers.deals.list.bulkDelete.title', 'Delete {count} deals?', { count: selectedRows.length }),\n description: t('customers.deals.list.bulkDelete.description', 'This action cannot be undone.'),\n variant: 'destructive',\n })\n if (!confirmed) return false\n\n const { succeeded, failures } = await runBulkMutation({\n operation: async () =>\n runBulkDelete(\n selectedRows,\n async (row) => {\n await deleteCrud('customers/deals', {\n body: { id: row.id },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n })\n },\n {\n fallbackErrorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n logTag: 'customers.deals.list',\n progress: {\n jobType: 'customers.deals.bulk_delete',\n name: t('customers.deals.list.bulkDelete.progressName', 'Delete selected deals'),\n description: t(\n 'customers.deals.list.bulkDelete.progressDescription',\n '{count} deals selected for deletion',\n { count: selectedRows.length },\n ),\n meta: { source: 'customers.deals.list' },\n },\n },\n ),\n context: {\n formId: bulkMutationContextId,\n resourceKind: 'customers.deal',\n retryLastMutation: retryBulkMutation,\n },\n })\n\n if (succeeded.length > 0) {\n const succeededIds = new Set(succeeded.map((r) => r.id))\n setRows((prev) => prev.filter((r) => !succeededIds.has(r.id)))\n setTotal((prev) => Math.max(0, prev - succeeded.length))\n setReloadToken((prev) => prev + 1)\n if (succeeded.length > 1) {\n coalesceLastOperations(succeeded.length, {\n commandId: 'customers.deals.delete',\n actionLabel: t('customers.deals.list.bulkDelete.operationLabel', 'Delete {count} deals', { count: succeeded.length }),\n resourceKind: 'customers.deal',\n })\n }\n if (failures.length === 0) {\n flash(\n t('customers.deals.list.bulkDelete.success', '{count} deals deleted', { count: succeeded.length }),\n 'success',\n )\n } else {\n flash(\n t('customers.deals.list.bulkDelete.partial', '{deleted} of {total} deals deleted; {failed} failed', {\n deleted: succeeded.length,\n total: selectedRows.length,\n failed: failures.length,\n }),\n 'warning',\n )\n }\n }\n\n for (const group of groupBulkDeleteFailures(failures)) {\n const message = group.count === 1\n ? group.sampleMessage\n : t(\n 'customers.deals.list.bulkDelete.failedGroup',\n '{count} deals could not be deleted: {message}',\n { count: group.count, message: group.sampleMessage },\n )\n flash(message, 'error')\n }\n\n return succeeded.length > 0\n }, [bulkMutationContextId, confirm, retryBulkMutation, runBulkMutation, t])\n\n const { data: customFieldDefs = [] } = useCustomFieldDefs([E.customers.customer_deal], {\n keyExtras: [scopeVersion, reloadToken],\n })\n const currentUserId = useCurrentUserId()\n const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])\n // Single staff load drives both the owner FILTER options and the owner-name\n // map shared with the OWNER cell + the KPI strip (userId \u2192 display name).\n // No per-row fetch \u2014 see spec audit \"Owner names\" resolution.\n const [ownerNames, setOwnerNames] = React.useState<Record<string, string>>({})\n React.useEffect(() => {\n const controller = new AbortController()\n let cancelled = false\n void fetchAssignableStaffMembers('', { pageSize: 100, signal: controller.signal })\n .then((items) => {\n if (cancelled) return\n setOwnerFilterOptions(mapAssignableStaffToFilterOptions(items))\n const names: Record<string, string> = {}\n for (const item of items) {\n if (item.userId) names[item.userId] = item.displayName\n }\n setOwnerNames(names)\n })\n .catch(() => {\n if (cancelled) return\n setOwnerFilterOptions([])\n setOwnerNames({})\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [scopeVersion])\n const resolvedOwnerFilterOptions = React.useMemo(\n () => ensureCurrentUserFilterOption(\n ownerFilterOptions,\n currentUserId,\n t('customers.filters.currentUser', 'Current user'),\n ),\n [currentUserId, ownerFilterOptions, t],\n )\n const loadOwnerFilterOptions = React.useCallback(async (query?: string): Promise<AdvancedFilterOption[]> => {\n const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })\n return mapAssignableStaffToFilterOptions(items)\n }, [])\n\n const startOfToday = React.useMemo(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n return today\n }, [])\n const isDealOverdue = React.useCallback(\n (row: DealRow): boolean =>\n !!row.expectedCloseAt && new Date(row.expectedCloseAt) < startOfToday && row.status === 'open',\n [startOfToday],\n )\n\n const columns = React.useMemo<ColumnDef<DealRow>[]>(() => {\n const noValue = <span className=\"text-muted-foreground text-sm\">{t('customers.deals.list.noValue')}</span>\n const unknownOwner = t('customers.deals.list.unknownOwner')\n\n const customColumns = customFieldDefs\n .filter((def) => supportsCustomFieldColumn(def))\n .map<ColumnDef<DealRow>>((def) => ({\n accessorKey: `cf_${def.key}`,\n header: def.label || def.key,\n meta: {\n columnChooserGroup: def.group?.title ?? t('ui.columnChooser.customFieldsGroup', 'Custom Fields'),\n filterGroup: def.group?.title ?? t('ui.columnChooser.customFieldsGroup', 'Custom Fields'),\n filterType: mapCustomFieldKindToFilterType(def.kind),\n filterOptions: normalizeCustomFieldFilterOptions(def.options),\n hidden: def.listVisible === false,\n maxWidth: '220px',\n },\n cell: ({ getValue }) => {\n const value = getValue()\n if (value == null) return noValue\n if (Array.isArray(value)) {\n const normalized = normalizeCollectionLabels(\n value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item\n return String(item)\n }),\n )\n if (!normalized.length) return noValue\n return <CollectionPreviewCell labels={normalized} maxVisible={2} />\n }\n if (typeof value === 'boolean') {\n return (\n <span className=\"text-sm\">\n {value\n ? t('customers.deals.list.booleanYes', 'Yes')\n : t('customers.deals.list.booleanNo', 'No')}\n </span>\n )\n }\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (!stringValue) return noValue\n return <span className=\"text-sm\">{stringValue}</span>\n },\n }))\n\n return [\n {\n accessorKey: 'title',\n header: t('customers.deals.list.columns.title'),\n meta: {\n alwaysVisible: true,\n columnChooserGroup: 'Basic Info',\n filterKey: 'title',\n filterGroup: 'Deal',\n maxWidth: '280px',\n },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\">\n <Briefcase className=\"h-4 w-4\" />\n </span>\n <span className=\"font-medium text-foreground truncate\">{row.original.title}</span>\n {isDealOverdue(row.original) ? (\n <AlertTriangle\n className=\"h-4 w-4 shrink-0 text-status-warning-text\"\n aria-label={t('customers.deals.list.close.overdue')}\n />\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('customers.deals.list.columns.status'),\n meta: {\n filterType: 'select' as const,\n filterOptions: dictionaryOptions.dealStatuses,\n columnChooserGroup: 'Basic Info',\n filterKey: 'status',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const status = row.original.status\n if (!status) return noValue\n const entry = dictionaryMaps['deal-statuses']?.[status]\n const label = entry?.label ?? status\n const variant = coerceStatusBadgeVariant(mapDictionaryColorToTone(entry?.color))\n return <StatusBadge variant={variant} dot>{label}</StatusBadge>\n },\n },\n {\n accessorKey: 'pipelineStage',\n header: t('customers.deals.list.columns.pipelineStage'),\n meta: {\n filterType: 'select' as const,\n filterOptions: dictionaryOptions.pipelineStages,\n columnChooserGroup: 'Pipeline',\n filterKey: 'pipeline_stage',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const stage = row.original.pipelineStage\n if (!stage) return noValue\n const label = dictionaryMaps['pipeline-stages']?.[stage]?.label ?? stage\n return <span className=\"text-foreground\">{label}</span>\n },\n },\n {\n accessorKey: 'pipelineId',\n header: t('customers.deals.list.columns.pipeline', 'Pipeline'),\n meta: {\n columnChooserGroup: 'Pipeline',\n filterKey: 'pipeline_id',\n filterGroup: 'Deal',\n maxWidth: '220px',\n },\n cell: ({ row }) => {\n const name = row.original.pipelineId ? pipelineNames[row.original.pipelineId] : null\n return name ? <span className=\"text-sm\">{name}</span> : noValue\n },\n },\n {\n accessorKey: 'valueAmount',\n header: t('customers.deals.list.columns.value'),\n meta: {\n filterType: 'number' as const,\n columnChooserGroup: 'Financial',\n filterKey: 'value_amount',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const amount = formatGroupedAmount(row.original.valueAmount ?? null)\n if (amount === null) return noValue\n const currency = row.original.valueCurrency\n return (\n <div className=\"flex flex-col\">\n <span className=\"font-medium text-foreground\">{amount}</span>\n {currency ? <span className=\"text-xs text-muted-foreground\">{currency}</span> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'probability',\n header: t('customers.deals.list.columns.probability'),\n meta: {\n filterType: 'number' as const,\n columnChooserGroup: 'Financial',\n filterKey: 'probability',\n filterGroup: 'Deal',\n },\n cell: ({ row }) => {\n const value = row.original.probability\n if (typeof value === 'number' && Number.isFinite(value)) {\n return <span className=\"font-medium text-foreground\">{`${Math.min(Math.max(value, 0), 100)}%`}</span>\n }\n return noValue\n },\n },\n {\n accessorKey: 'expectedCloseAt',\n header: t('customers.deals.list.columns.expectedClose'),\n meta: {\n columnChooserGroup: 'Dates',\n filterKey: 'expected_close_at',\n filterGroup: 'Activity',\n filterIconName: 'calendar',\n },\n cell: ({ row }) => {\n const expectedCloseAt = row.original.expectedCloseAt\n if (!expectedCloseAt) return noValue\n let subtitle: React.ReactNode = null\n if (isDealOverdue(row.original)) {\n subtitle = (\n <span className=\"text-xs text-status-error-text\">{t('customers.deals.list.close.overdue')}</span>\n )\n } else if (isWonDealStatus(row.original.status)) {\n subtitle = (\n <span className=\"text-xs text-muted-foreground\">{t('customers.deals.list.close.won')}</span>\n )\n } else if (isLostDealStatus(row.original.status)) {\n subtitle = (\n <span className=\"text-xs text-muted-foreground\">{t('customers.deals.list.close.lost')}</span>\n )\n } else {\n const relative = formatRelativeTime(expectedCloseAt, { locale, translate: t })\n if (relative) {\n subtitle = <span className=\"text-xs text-muted-foreground\">{relative}</span>\n }\n }\n return (\n <div className=\"flex flex-col\">\n <span className=\"text-foreground\">\n {formatDateValue(expectedCloseAt, t('customers.deals.list.noValue'))}\n </span>\n {subtitle}\n </div>\n )\n },\n },\n {\n accessorKey: 'ownerUserId',\n header: t('customers.deals.list.columns.owner', 'Owner'),\n meta: {\n columnChooserGroup: 'CRM',\n filterType: 'select',\n filterOptions: resolvedOwnerFilterOptions,\n filterLoadOptions: loadOwnerFilterOptions,\n filterGroup: 'CRM',\n filterIconName: 'user-round',\n filterKey: 'owner_user_id',\n },\n cell: ({ row }) => {\n const ownerUserId = row.original.ownerUserId\n if (!ownerUserId) return noValue\n const label = ownerNames[ownerUserId]?.trim() || unknownOwner\n return (\n <div className=\"flex items-center gap-2 min-w-0\">\n <Avatar label={label} size=\"sm\" />\n <span className=\"text-foreground truncate\">{label}</span>\n </div>\n )\n },\n },\n {\n accessorKey: 'companies',\n header: t('customers.deals.list.columns.companies'),\n meta: {\n columnChooserGroup: 'Associations',\n filterable: false,\n filterGroup: 'CRM',\n filterIconName: 'building-2',\n maxWidth: '220px',\n tooltipContent: (row: DealRow) =>\n normalizeCollectionLabels(\n row.companies.map((entry) => (entry.label && entry.label.trim().length ? entry.label : t('customers.deals.list.unnamedCompany'))),\n ).join(', '),\n },\n cell: ({ row }) => {\n const companies = row.original.companies\n if (!companies.length) return noValue\n const first = companies[0]\n const firstLabel =\n first.label && first.label.trim().length ? first.label : t('customers.deals.list.unnamedCompany')\n const overflow = companies.length - 1\n return (\n <div className=\"flex items-center gap-1.5 min-w-0\">\n <Tag variant=\"neutral\" className=\"max-w-36\">\n <span className=\"truncate\">{firstLabel}</span>\n </Tag>\n {overflow > 0 ? <Tag variant=\"neutral\">{`+${overflow}`}</Tag> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'people',\n header: t('customers.deals.list.columns.people'),\n meta: {\n columnChooserGroup: 'Associations',\n filterable: false,\n filterGroup: 'CRM',\n filterIconName: 'user-round',\n maxWidth: '220px',\n tooltipContent: (row: DealRow) =>\n normalizeCollectionLabels(\n row.people.map((entry) => (entry.label && entry.label.trim().length ? entry.label : t('customers.deals.list.unnamedPerson'))),\n ).join(', '),\n },\n cell: ({ row }) => {\n const people = row.original.people\n if (!people.length) return noValue\n const labels = normalizeCollectionLabels(\n people.map((person) =>\n person.label && person.label.trim().length ? person.label : t('customers.deals.list.unnamedPerson')),\n )\n const tooltip = labels.join(', ')\n return (\n <SimpleTooltip content={tooltip} side=\"top\">\n <span className=\"inline-flex\">\n <AvatarStack max={4} size=\"sm\">\n {people.map((person) => (\n <Avatar\n key={person.id}\n label={person.label || t('customers.deals.list.unnamedPerson')}\n size=\"sm\"\n />\n ))}\n </AvatarStack>\n </span>\n </SimpleTooltip>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: t('customers.deals.list.columns.updatedAt'),\n meta: {\n columnChooserGroup: 'Dates',\n filterKey: 'updated_at',\n filterGroup: 'Activity',\n filterIconName: 'calendar',\n },\n cell: ({ row }) => (\n <span className=\"text-sm\">\n {formatDateValue(row.original.updatedAt ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n ...customColumns,\n ]\n }, [customFieldDefs, dictionaryMaps, dictionaryOptions, isDealOverdue, loadOwnerFilterOptions, locale, ownerNames, pipelineNames, resolvedOwnerFilterOptions, t])\n\n const { advancedFilterFields } = useAutoDiscoveredFields({ columns, customFieldDefs })\n\n // Sync auto-discovered fields into the `filterPanel` declared at the top of\n // the component. See the comment on the `panelFields` state for why this\n // late-binding is safe. Bail out by content (field-key list) \u2014 every render\n // of `useAutoDiscoveredFields` produces fresh `FilterFieldDef` object refs\n // even when the set of fields hasn't actually changed, so a naive reference\n // setState would loop (\"Maximum update depth exceeded\").\n React.useEffect(() => {\n setPanelFields((prev) => {\n if (prev === advancedFilterFields) return prev\n if (prev.length === advancedFilterFields.length) {\n let same = true\n for (let i = 0; i < prev.length; i++) {\n if (prev[i].key !== advancedFilterFields[i].key) { same = false; break }\n }\n if (same) return prev\n }\n return advancedFilterFields\n })\n }, [advancedFilterFields])\n\n const associationFilterFields = React.useMemo<FilterFieldDef[]>(() => {\n const personLabels = new Map<string, string>()\n const companyLabels = new Map<string, string>()\n for (const row of rows) {\n for (const person of row.people) {\n if (selectedPersonIds.includes(person.id) && person.label.trim().length > 0) {\n personLabels.set(person.id, person.label)\n }\n }\n for (const company of row.companies) {\n if (selectedCompanyIds.includes(company.id) && company.label.trim().length > 0) {\n companyLabels.set(company.id, company.label)\n }\n }\n }\n return [\n {\n key: 'people',\n label: t('customers.deals.list.columns.people', 'People'),\n type: 'select',\n options: selectedPersonIds.map((id) => ({ value: id, label: personLabels.get(id) ?? id })),\n },\n {\n key: 'companies',\n label: t('customers.deals.list.columns.companies', 'Companies'),\n type: 'select',\n options: selectedCompanyIds.map((id) => ({ value: id, label: companyLabels.get(id) ?? id })),\n },\n ]\n }, [rows, selectedCompanyIds, selectedPersonIds, t])\n const associationFilterTree = React.useMemo<AdvancedFilterTree>(() => {\n const rules: Array<{ field: string; operator: 'is_any_of'; value: string[] }> = []\n if (selectedPersonIds.length) rules.push({ field: 'people', operator: 'is_any_of', value: selectedPersonIds })\n if (selectedCompanyIds.length) rules.push({ field: 'companies', operator: 'is_any_of', value: selectedCompanyIds })\n return rules.length ? makeMultiRuleTree(rules) : createEmptyTree()\n }, [selectedCompanyIds, selectedPersonIds])\n const handleAssociationFilterRemove = React.useCallback((nodeId: string) => {\n const node = associationFilterTree.root.children.find((child) => child.id === nodeId)\n if (!node || node.type !== 'rule') return\n if (node.field === 'people') setSelectedPersonIds([])\n if (node.field === 'companies') setSelectedCompanyIds([])\n setPage(1)\n }, [associationFilterTree.root.children])\n\n const dealsPresets = React.useMemo<FilterPreset[]>(() => makeDealsPresets(), [])\n\n return (\n <Page>\n <PageBody>\n <ViewTabsRow active=\"list\" className=\"mb-4\" />\n <DealsKpiStrip\n ownerNames={ownerNames}\n stageDictionary={dictionaryMaps['pipeline-stages'] ?? {}}\n pipelineCount={Object.keys(pipelineNames).length}\n scopeVersion={scopeVersion}\n reloadToken={reloadToken}\n onNeedsAttentionClick={handleNeedsAttentionFilter}\n className=\"mb-4\"\n />\n <DataTable<DealRow>\n stickyFirstColumn\n stickyActionsColumn\n actionsColumnAlign=\"center\"\n title={t('customers.deals.list.title')}\n actions={(\n <Button asChild>\n <Link href=\"/backend/customers/deals/create\">\n {t('customers.deals.list.actions.new', 'New deal')}\n </Link>\n </Button>\n )}\n columns={columns}\n columnChooser={{ auto: true }}\n data={rows}\n onRowClick={(row) => {\n router.push(`/backend/customers/deals/${row.id}`)\n }}\n rowActions={(row) => {\n const isDeleting = pendingDeleteId === row.id\n return (\n <RowActions\n items={[\n {\n id: 'edit',\n label: t('customers.deals.list.actions.edit', 'Edit'),\n onSelect: () => { router.push(`/backend/customers/deals/${row.id}`) },\n },\n {\n id: 'open-new-tab',\n label: t('customers.deals.list.actions.openInNewTab', 'Open in new tab'),\n onSelect: () => {\n if (typeof window !== 'undefined') {\n window.open(`/backend/customers/deals/${row.id}`, '_blank', 'noopener')\n }\n },\n },\n {\n id: 'delete',\n label: isDeleting\n ? t('customers.deals.list.actions.deleting', 'Deleting\u2026')\n : t('customers.deals.list.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => handleDeleteDeal(row.id),\n },\n ]}\n />\n )\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n bulkActions={[\n {\n id: 'delete',\n label: t('customers.deals.list.actions.delete', 'Delete'),\n destructive: true,\n onExecute: handleBulkDelete,\n },\n ]}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={t('customers.deals.list.searchPlaceholder')}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n totalIsCapped,\n onPageChange: (nextPage) => setPage(nextPage),\n pageSizeOptions: [10, 25, 50, 100],\n onPageSizeChange: handlePageSizeChange,\n cacheStatus,\n }}\n isLoading={isLoading}\n refreshButton={{\n label: t('customers.deals.list.refresh'),\n onRefresh: handleRefresh,\n }}\n exporter={exportConfig}\n entityId={E.customers.customer_deal}\n perspective={{ tableId: extensionPoints.hosts.dealsTable.tableId }}\n advancedFilter={{\n auto: true,\n value: filterPanel.tree,\n onChange: filterPanel.setTree,\n onApply: () => filterPanel.flush(),\n onClear: handleAdvancedFilterClear,\n triggerRef: filtersTriggerRef,\n externalPopover: true,\n onTriggerClick: () => setFiltersOpen((prev) => !prev),\n onApplyTree: (tree) => {\n filterPanel.replaceTree(tree)\n setPage(1)\n },\n }}\n activeFilterChips={(\n <>\n {needsAttentionOnly ? (\n <div\n className=\"flex items-center gap-2 overflow-x-auto border-b border-border bg-background px-4 py-2\"\n data-testid=\"active-filter-chips\"\n >\n <div\n className=\"inline-flex items-center gap-1\"\n data-testid=\"active-filter-chip\"\n aria-label={t('customers.deals.list.filters.needsAttention')}\n >\n <Tag variant=\"warning\" dot>{t('customers.deals.list.filters.needsAttention')}</Tag>\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n aria-label={t('customers.deals.list.filters.needsAttentionRemove')}\n onClick={handleNeedsAttentionClear}\n >\n <X className=\"size-3\" />\n </IconButton>\n </div>\n </div>\n ) : null}\n <ActiveFilterChips\n tree={associationFilterTree}\n fields={associationFilterFields}\n popoverOpen={filtersOpen}\n onRemoveNode={handleAssociationFilterRemove}\n onOpen={() => setFiltersOpen(true)}\n />\n <ActiveFilterChips\n tree={filterPanel.appliedTree}\n fields={advancedFilterFields}\n popoverOpen={filtersOpen}\n onRemoveNode={(id) => filterPanel.dispatch({ type: 'removeNode', nodeId: id })}\n onOpen={() => setFiltersOpen(true)}\n />\n </>\n )}\n filterAwareEmptyState={{\n active: needsAttentionOnly || associationFilterTree.root.children.length > 0 || advancedFilterState.root.children.length > 0,\n entityNamePlural: t('customers.deals.entityPlural', 'deals'),\n canRemoveLast: needsAttentionOnly || associationFilterTree.root.children.length > 0 || filterPanel.tree.root.children.length > 0,\n onClearAll: () => {\n handleAdvancedFilterClear()\n setSelectedPersonIds([])\n setSelectedCompanyIds([])\n setNeedsAttentionOnly(false)\n },\n onRemoveLast: () => {\n if (needsAttentionOnly) {\n handleNeedsAttentionClear()\n return\n }\n if (selectedCompanyIds.length > 0) {\n setSelectedCompanyIds([])\n setPage(1)\n return\n }\n if (selectedPersonIds.length > 0) {\n setSelectedPersonIds([])\n setPage(1)\n return\n }\n filterPanel.dispatch({ type: 'removeLast' })\n },\n }}\n emptyState={(\n <ListEmptyState\n entityName={t('customers.deals.entityPlural', 'deals')}\n createHref=\"/backend/customers/deals/create\"\n createLabel={t('customers.deals.list.actions.new', 'New deal')}\n />\n )}\n virtualized\n />\n <AdvancedFilterPanel\n fields={advancedFilterFields}\n value={filterPanel.tree}\n onChange={filterPanel.setTree}\n onApply={filterPanel.flush}\n onClear={handleAdvancedFilterClear}\n onFlush={filterPanel.flush}\n pendingErrors={filterPanel.pendingErrors}\n userId={currentUserId}\n presets={dealsPresets}\n open={filtersOpen}\n onOpenChange={setFiltersOpen}\n triggerRef={filtersTriggerRef}\n savedFilterStorageKey=\"customers.deals.list\"\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nfunction mapDeal(item: Record<string, unknown>): DealRow | null {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const title = typeof item.title === 'string' ? item.title : ''\n const status = typeof item.status === 'string' ? item.status : null\n const pipelineStage = typeof item.pipeline_stage === 'string' ? item.pipeline_stage : null\n const pipelineStageId = typeof item.pipeline_stage_id === 'string' ? item.pipeline_stage_id : null\n const pipelineId = typeof item.pipeline_id === 'string' ? item.pipeline_id : null\n const valueAmountRaw = item.value_amount\n const valueAmount =\n typeof valueAmountRaw === 'number'\n ? valueAmountRaw\n : typeof valueAmountRaw === 'string' && valueAmountRaw.trim()\n ? Number(valueAmountRaw)\n : null\n const valueCurrency =\n typeof item.value_currency === 'string' && item.value_currency.trim().length\n ? item.value_currency.trim().toUpperCase()\n : null\n const probabilityRaw = item.probability\n const probability =\n typeof probabilityRaw === 'number'\n ? probabilityRaw\n : typeof probabilityRaw === 'string' && probabilityRaw.trim().length\n ? Number(probabilityRaw)\n : null\n const expectedCloseAt = typeof item.expected_close_at === 'string' ? item.expected_close_at : null\n const updatedAt = typeof item.updated_at === 'string' ? item.updated_at : null\n const ownerUserId = typeof item.owner_user_id === 'string' ? item.owner_user_id : null\n const peopleRaw = Array.isArray(item.people) ? item.people : []\n const companiesRaw = Array.isArray(item.companies) ? item.companies : []\n const people = peopleRaw\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const data = entry as Record<string, unknown>\n const pid = typeof data.id === 'string' ? data.id : null\n if (!pid) return null\n const label = typeof data.label === 'string' ? data.label : ''\n return { id: pid, label }\n })\n .filter((entry): entry is { id: string; label: string } => !!entry)\n const companies = companiesRaw\n .map((entry) => {\n if (!entry || typeof entry !== 'object') return null\n const data = entry as Record<string, unknown>\n const cid = typeof data.id === 'string' ? data.id : null\n if (!cid) return null\n const label = typeof data.label === 'string' ? data.label : ''\n return { id: cid, label }\n })\n .filter((entry): entry is { id: string; label: string } => !!entry)\n const customFields: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(item)) {\n if (key.startsWith('cf_')) customFields[key] = value\n }\n return withDataTableNamespaces({\n id,\n title,\n status,\n pipelineStage,\n pipelineStageId,\n pipelineId,\n valueAmount,\n valueCurrency,\n probability,\n expectedCloseAt,\n updatedAt,\n ownerUserId,\n people,\n companies,\n ...customFields,\n }, item)\n}\n"],
5
+ "mappings": ";AAyqBoB,SA4eR,UA5eQ,KA0DV,YA1DU;AAvqBpB,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAChC,OAAO,UAAU;AACjB,SAAS,aAAa,WAAW,uBAAuB;AACxD,SAAS,sBAAsB;AAE/B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,WAAuC,+BAA+B;AAE/E,SAAS,iBAAiB,cAAc,yBAAyB;AACjE,SAAS,iBAAiB,2BAA2B,YAAY,0BAA0B,qBAAqF;AAChL,SAAS,wBAAwB;AACjC,SAAS,SAAS,mCAAmC;AACrD,SAAS,iCAAiC;AAC1C,SAAS,6BAA6B;AACtC,SAAS,oBAAoB,kBAAkB;AAC/C,SAAS,yBAAyB,qBAAqB;AACvD,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,mBAA4C;AACrD,SAAS,QAAQ,mBAAmB;AACpC,SAAS,WAAW;AACpB,SAAS,qBAAqB;AAC9B,SAAS,WAAW,eAAe,SAAS;AAC5C,SAAS,kBAAkB,uBAAuB;AAClD,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAClB,SAAS,mCAAmC;AAC5C,SAAS,WAAW,YAAY;AAChC,SAAS,wBAAwB;AAKjC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB,iCAAiC;AACjE,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAE/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,WAAW;AAEvC,SAAS,mBAAmC;AAC1C,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,EAAE,OAAO,MAAM,aAAa,EAAE,OAAO,iBAAiB,UAAU,MAAM,OAAO,OAAO,CAAC;AAAA,IAC/F;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO,CAAC,EAAE,IAAI,MAAM;AAClB,cAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACtF,cAAM,MAAM,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACxF,eAAO,aAAa,EAAE,OAAO,qBAAqB,UAAU,WAAW,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC;AAAA,MAC9F;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,OAAO,CAAC,EAAE,IAAI,MAAM;AAClB,cAAM,UAAU,KAAK,MAAM,IAAI,SAAS,IAAI,CAAC;AAC7C,cAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,UAAU,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACnF,eAAO,kBAAkB;AAAA,UACvB,EAAE,OAAO,UAAU,UAAU,MAAM,OAAO,MAAM;AAAA,UAChD,EAAE,OAAO,qBAAqB,UAAU,YAAY,OAAO,MAAM;AAAA,QACnE,GAAG,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;AA+BA,MAAM,YAAY;AAClB,MAAM,aAAa;AAEnB,SAAS,OAAO,OAAmD;AACjE,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,WAAW,KAAK,MAAM,KAAK,CAAC;AACrC;AAEA,SAAS,sBAAsB,KAA8B;AAC3D,QAAM,MAAM,oBAAI,IAAY;AAC5B,MAAI,QAAQ,CAAC,cAAc;AACzB,cACG,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAChC,QAAQ,CAAC,SAAS;AACjB,UAAI,OAAO,IAAI,EAAG,KAAI,IAAI,IAAI;AAAA,IAChC,CAAC;AAAA,EACL,CAAC;AACD,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAS,qBAAqB,QAA4C,KAAuB;AAC/F,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,QAAM,SAAS,OAAO,OAAO,GAAG;AAChC,SAAO,sBAAsB,MAAM;AACrC;AAEA,SAAS,gBAAgB,OAAkC,UAA0B;AACnF,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,KAAK,mBAAmB;AACjC;AAEA,MAAM,wBAAyD,oBAAI,IAAI;AAAA,EACrE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,yBACP,MACoB;AACpB,MAAI,QAAQ,sBAAsB,IAAI,IAA0B,GAAG;AACjE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,yBAAyB,IAAI,KAAK,aAAa,QAAW,EAAE,uBAAuB,EAAE,CAAC;AAE5F,SAAS,oBAAoB,QAAkD;AAC7E,MAAI,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,EAAG,QAAO;AAC/D,SAAO,uBAAuB,OAAO,MAAM;AAC7C;AAEe,SAAR,qBAAsC;AAC3C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,eAAe,4BAA4B;AACjD,QAAM,cAAc,eAAe;AAEnC,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAoB,CAAC,CAAC;AACpD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,MAAM;AAC3C,UAAM,MAAM,OAAO,cAAc,IAAI,MAAM,KAAK,GAAG;AACnD,WAAO,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;AAAA,EACjD,CAAC;AACD,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,SAAS;AACxD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAuD,CAAC,CAAC;AAC7F,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAS,CAAC;AAC1C,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,CAAC;AACpD,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,KAAK;AAC9D,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,MAAM,cAAc,IAAI,QAAQ,GAAG,KAAK,KAAK,EAAE;AAC1F,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,CAAC;AACtD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAwB,IAAI;AAChF,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAS,MAAM,cAAc,IAAI,gBAAgB,MAAM,MAAM;AAKvH,QAAM,oBAAoB,MAAM,QAA4B,MAAM;AAChE,QAAI,CAAC,aAAc,QAAO,gBAAgB;AAC1C,UAAM,SAAiC,CAAC;AACxC,iBAAa,QAAQ,CAAC,OAAO,QAAQ;AACnC,UAAI,IAAI,WAAW,SAAS,EAAG,QAAO,GAAG,IAAI;AAAA,IAC/C,CAAC;AACD,UAAM,KAAK,gBAAgB,MAAM;AACjC,QAAI,GAAI,QAAO;AACf,UAAM,OAAO,0BAA0B,MAAM;AAC7C,QAAI,KAAM,QAAO,WAAW,IAAI;AAChC,WAAO,gBAAgB;AAAA,EAEzB,GAAG,CAAC,CAAC;AAQL,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAA2B,CAAC,CAAC;AACzE,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,KAAK;AAC1D,QAAM,oBAAoB,MAAM,OAAiC,IAAI;AACrE,QAAM,cAAc,sBAAsB;AAAA,IACxC,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,MAAM,QAAQ,CAAC;AAAA,EAC1B,CAAC;AACD,QAAM,sBAAsB,YAAY;AACxC,QAAM,4BAA4B,MAAM,YAAY,MAAM;AACxD,gBAAY,MAAM;AAClB,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAgC,IAAI;AAEhF,QAAM,mBAAmB,MAAM;AAAA,IAC7B,MAAM,qBAAqB,cAAc,UAAU;AAAA,IACnD,CAAC,YAAY;AAAA,EACf;AACA,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,qBAAqB,cAAc,WAAW;AAAA,IACpD,CAAC,YAAY;AAAA,EACf;AAEA,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAmB,gBAAgB;AAC3F,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAmB,iBAAiB;AAE9F,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAuD;AAAA,IACvG,iBAAiB,CAAC;AAAA,IAClB,mBAAmB,CAAC;AAAA,EACtB,CAAC;AAED,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAiC,CAAC,CAAC;AAEnF,QAAM,yBAAyB,MAAM;AAAA,IACnC,OAAO,SAAwB;AAC7B,UAAI;AACF,cAAM,OAAO,MAAM,yBAAyB,aAAa,MAAM,YAAY;AAC3E,0BAAkB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,GAAG,KAAK,IAAI,EAAE;AAAA,MAC7D,QAAQ;AACN,0BAAkB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE;AAAA,MACvD;AAAA,IACF;AAAA,IACA,CAAC,aAAa,YAAY;AAAA,EAC5B;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,mBAAe,mBAAmB;AAChC,UAAI,UAAW;AACf,YAAM,QAAQ,IAAI,CAAC,uBAAuB,eAAe,GAAG,uBAAuB,iBAAiB,CAAC,CAAC;AAAA,IACxG;AACA,qBAAiB,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACjC,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,wBAAwB,WAAW,CAAC;AACxC,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAC5C,UAAM,YAAY,CAAC,QACjB,OAAO,OAAO,OAAO,CAAC,CAAC,EACpB,IAAI,CAAC,UAAU;AACd,YAAM,OAAO,yBAAyB,MAAM,KAAK;AACjD,YAAM,SAAmC,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,MAAM;AAClF,UAAI,KAAM,QAAO,OAAO;AACxB,aAAO;AAAA,IACT,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,OAAO,QAAW,EAAE,aAAa,OAAO,CAAC,CAAC;AACtF,WAAO;AAAA,MACL,cAAc,UAAU,eAAe,eAAe,CAAC;AAAA,MACvD,gBAAgB,UAAU,eAAe,iBAAiB,CAAC;AAAA,IAC7D;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,mBAAe,gBAAgB;AAC7B,UAAI;AACF,cAAM,OAAO,MAAM,QAAyD,0BAA0B;AACtG,YAAI,aAAa,CAAC,KAAK,GAAI;AAC3B,cAAM,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,KAAK,OAAO,QAAQ,CAAC;AACvE,cAAM,MAA8B,CAAC;AACrC,cAAM,QAAQ,CAAC,MAAM;AAAE,cAAI,EAAE,MAAM,EAAE,KAAM,KAAI,EAAE,EAAE,IAAI,EAAE;AAAA,QAAK,CAAC;AAC/D,yBAAiB,GAAG;AAAA,MACtB,SAAS,KAAK;AACZ,eAAO,KAAK,4BAA4B,EAAE,WAAW,cAAc,IAAI,CAAC;AAAA,MAC1E;AAAA,IACF;AACA,kBAAc,EAAE,MAAM,CAAC,QAAQ;AAC7B,aAAO,KAAK,uBAAuB,EAAE,WAAW,cAAc,IAAI,CAAC;AAAA,IACrE,CAAC;AACD,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,aAAa,YAAY,CAAC;AAE9B,QAAM,qBAAqB,MAAM,YAAY,CAAC,UAAkB;AAC9D,cAAU,MAAM,KAAK,CAAC;AACtB,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AAC/B,WAAO,IAAI,YAAY,OAAO,QAAQ,CAAC;AACvC,QAAI,QAAQ,SAAS,GAAG;AACtB,aAAO,IAAI,QAAQ,QAAQ,CAAC,EAAE,EAAE;AAChC,aAAO,IAAI,SAAS,QAAQ,CAAC,EAAE,OAAO,SAAS,KAAK;AAAA,IACtD;AACA,QAAI,OAAO,KAAK,EAAE,OAAQ,QAAO,IAAI,UAAU,OAAO,KAAK,CAAC;AAC5D,QAAI,kBAAkB,OAAQ,QAAO,IAAI,YAAY,kBAAkB,KAAK,GAAG,CAAC;AAChF,QAAI,mBAAmB,OAAQ,QAAO,IAAI,aAAa,mBAAmB,KAAK,GAAG,CAAC;AACnF,QAAI,mBAAoB,QAAO,IAAI,kBAAkB,MAAM;AAC3D,UAAM,iBAAiB,cAAc,mBAAmB;AACxD,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,cAAc,GAAG;AACvD,aAAO,IAAI,KAAK,GAAG;AAAA,IACrB;AACA,WAAO,OAAO,SAAS;AAAA,EACzB,GAAG,CAAC,qBAAqB,oBAAoB,MAAM,UAAU,QAAQ,oBAAoB,mBAAmB,OAAO,CAAC;AAEpH,QAAM,gBAAgB,MAAM;AAAA,IAC1B,MAAM,OAAO,YAAY,IAAI,gBAAgB,WAAW,CAAC;AAAA,IACzD,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,eAAe,MAAM,QAAQ,OAAO;AAAA,IACxC,MAAM;AAAA,MACJ,QAAQ,CAAC,WACP,mBAAmB,mBAAmB,EAAE,GAAG,eAAe,aAAa,OAAO,GAAG,MAAM;AAAA,IAC3F;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ,CAAC,WACP,mBAAmB,mBAAmB,EAAE,GAAG,eAAe,aAAa,QAAQ,KAAK,OAAO,GAAG,MAAM;AAAA,IACxG;AAAA,EACF,IAAI,CAAC,aAAa,CAAC;AAEnB,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,mBAAe,OAAO;AACpB,mBAAa,IAAI;AACjB,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,WAA0B,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,YAAY,EAAE;AACrE,cAAM,OAAO,MAAM,QAAuB,wBAAwB,WAAW,IAAI,QAAW,EAAE,SAAS,CAAC;AACxG,YAAI,CAAC,KAAK,IAAI;AACZ,gBAAM,UACJ,OAAQ,KAAK,QAA2C,UAAU,WAC7D,KAAK,OAA8B,QACpC,EAAE,iCAAiC;AACzC,gBAAM,SAAS,OAAO;AACtB,cAAI,CAAC,UAAW,gBAAe,IAAI;AACnC;AAAA,QACF;AACA,cAAM,UAAU,KAAK,UAAU;AAC/B,YAAI,UAAW;AACf,uBAAe,KAAK,eAAe,IAAI;AACvC,cAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,cAAM,SAAS,MACZ,IAAI,CAAC,SAAS,QAAQ,IAA+B,CAAC,EACtD,OAAO,CAAC,QAAwB,CAAC,CAAC,GAAG;AACxC,gBAAQ,MAAM;AACd,iBAAS,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,OAAO,MAAM;AAC1E,sBAAc,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa,CAAC;AAC7E,yBAAiB,QAAQ,kBAAkB,IAAI;AAAA,MACjD,SAAS,KAAK;AACZ,YAAI,CAAC,WAAW;AACd,yBAAe,IAAI;AACnB,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,EAAE,iCAAiC;AACxF,gBAAM,SAAS,OAAO;AAAA,QACxB;AAAA,MACF,UAAE;AACA,YAAI,CAAC,UAAW,cAAa,KAAK;AAAA,MACpC;AAAA,IACF;AACA,SAAK;AACL,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,aAAa,aAAa,cAAc,CAAC,CAAC;AAE9C,QAAM,UAAU,MAAM;AAGpB,QAAI,CAAC,iBAAiB,aAAa,KAAK,OAAO,YAAY;AACzD,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,MAAM,YAAY,aAAa,CAAC;AAEpC,QAAM,WAAW,MAAM,OAAO,cAAc,SAAS,KAAK,EAAE;AAC5D,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,KAAK,EAAE,OAAQ,QAAO,IAAI,UAAU,OAAO,KAAK,CAAC;AAC5D,QAAI,kBAAkB,OAAQ,mBAAkB,QAAQ,CAAC,OAAO,OAAO,OAAO,YAAY,EAAE,CAAC;AAC7F,QAAI,mBAAmB,OAAQ,oBAAmB,QAAQ,CAAC,OAAO,OAAO,OAAO,aAAa,EAAE,CAAC;AAChG,QAAI,mBAAoB,QAAO,IAAI,kBAAkB,MAAM;AAC3D,QAAI,OAAO,EAAG,QAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AAC7C,UAAM,iBAAiB,cAAc,mBAAmB;AACxD,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,cAAc,GAAG;AACvD,aAAO,IAAI,KAAK,GAAG;AAAA,IACrB;AACA,UAAM,OAAO,OAAO,SAAS;AAC7B,QAAI,SAAS,YAAY,KAAM;AAC/B,aAAS,UAAU;AACnB,WAAO,QAAQ,OAAO,GAAG,QAAQ,IAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC;AAAA,EAC3E,GAAG,CAAC,UAAU,QAAQ,MAAM,QAAQ,mBAAmB,oBAAoB,oBAAoB,mBAAmB,CAAC;AAEnH,QAAM,gBAAgB,MAAM,YAAY,MAAM;AAC5C,SAAK,QAAQ,IAAI;AAAA,MACf,6BAA6B,aAAa,eAAe;AAAA,MACzD,6BAA6B,aAAa,iBAAiB;AAAA,IAC7D,CAAC;AACD,mBAAe,CAAC,UAAU,QAAQ,CAAC;AAAA,EACrC,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,wBAAwB;AAC9B,QAAM,EAAE,aAAa,iBAAiB,mBAAmB,kBAAkB,IAAI,mBAI5E;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AACD,QAAM,0BAA0B;AAChC,QAAM,EAAE,aAAa,mBAAmB,mBAAmB,oBAAoB,IAAI,mBAKhF;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AAED,QAAM,mBAAmB,MAAM;AAAA,IAC7B,OAAO,WAAmB;AACxB,UAAI,gBAAiB;AACrB,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AACD,UAAI,CAAC,UAAW;AAChB,YAAM,cAAc,KAAK,KAAK,CAAC,QAAQ,IAAI,OAAO,MAAM,GAAG,aAAa;AACxE,yBAAmB,MAAM;AACzB,UAAI;AACF,cAAM,kBAAkB;AAAA,UACtB,WAAW,YAAY;AACrB,kBAAM;AAAA,cACJ,0BAA0B,WAAW;AAAA,cACrC,MAAM,WAAW,mBAAmB;AAAA,gBAClC,MAAM,EAAE,IAAI,OAAO;AAAA,gBACnB,cAAc,EAAE,oCAAoC,wBAAwB;AAAA,cAC9E,CAAC;AAAA,YACH;AAAA,UACF;AAAA,UACA,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,mBAAmB;AAAA,UACrB;AAAA,QACF,CAAC;AACD,cAAM,EAAE,sCAAsC,eAAe,GAAG,SAAS;AACzE,gBAAQ,CAAC,SAAS,KAAK,OAAO,CAAC,QAAQ,IAAI,OAAO,MAAM,CAAC;AACzD,iBAAS,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AACxC,sBAAc;AAAA,MAChB,SAAS,KAAK;AAGZ,YAAI,sBAAsB,KAAK,CAAC,GAAG;AACjC,wBAAc;AACd;AAAA,QACF;AACA,cAAM,UACJ,eAAe,SAAS,IAAI,UACxB,IAAI,UACJ,EAAE,oCAAoC,wBAAwB;AACpE,cAAM,SAAS,OAAO;AAAA,MACxB,UAAE;AACA,2BAAmB,IAAI;AAAA,MACzB;AAAA,IACF;AAAA,IACA,CAAC,SAAS,eAAe,iBAAiB,qBAAqB,MAAM,mBAAmB,yBAAyB,CAAC;AAAA,EACpH;AAEA,QAAM,uBAAuB,MAAM,YAAY,CAAC,YAAoB;AAClE,gBAAY,OAAO;AACnB,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,6BAA6B,MAAM,YAAY,MAAM;AACzD,0BAAsB,IAAI;AAC1B,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,4BAA4B,MAAM,YAAY,MAAM;AACxD,0BAAsB,KAAK;AAC3B,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,OAAO,iBAA4B;AAC5E,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,yCAAyC,yBAAyB,EAAE,OAAO,aAAa,OAAO,CAAC;AAAA,MACzG,aAAa,EAAE,+CAA+C,+BAA+B;AAAA,MAC7F,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW,QAAO;AAEvB,UAAM,EAAE,WAAW,SAAS,IAAI,MAAM,gBAAgB;AAAA,MACpD,WAAW,YACT;AAAA,QACE;AAAA,QACA,OAAO,QAAQ;AACb,gBAAM,WAAW,mBAAmB;AAAA,YAClC,MAAM,EAAE,IAAI,IAAI,GAAG;AAAA,YACnB,cAAc,EAAE,oCAAoC,wBAAwB;AAAA,UAC9E,CAAC;AAAA,QACH;AAAA,QACA;AAAA,UACE,sBAAsB,EAAE,oCAAoC,wBAAwB;AAAA,UACpF,QAAQ;AAAA,UACR,UAAU;AAAA,YACR,SAAS;AAAA,YACT,MAAM,EAAE,gDAAgD,uBAAuB;AAAA,YAC/E,aAAa;AAAA,cACX;AAAA,cACA;AAAA,cACA,EAAE,OAAO,aAAa,OAAO;AAAA,YAC/B;AAAA,YACA,MAAM,EAAE,QAAQ,uBAAuB;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,MACF,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,mBAAmB;AAAA,MACrB;AAAA,IACF,CAAC;AAED,QAAI,UAAU,SAAS,GAAG;AACxB,YAAM,eAAe,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACvD,cAAQ,CAAC,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC,CAAC;AAC7D,eAAS,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,UAAU,MAAM,CAAC;AACvD,qBAAe,CAAC,SAAS,OAAO,CAAC;AACjC,UAAI,UAAU,SAAS,GAAG;AACxB,+BAAuB,UAAU,QAAQ;AAAA,UACvC,WAAW;AAAA,UACX,aAAa,EAAE,kDAAkD,wBAAwB,EAAE,OAAO,UAAU,OAAO,CAAC;AAAA,UACpH,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AACA,UAAI,SAAS,WAAW,GAAG;AACzB;AAAA,UACE,EAAE,2CAA2C,yBAAyB,EAAE,OAAO,UAAU,OAAO,CAAC;AAAA,UACjG;AAAA,QACF;AAAA,MACF,OAAO;AACL;AAAA,UACE,EAAE,2CAA2C,uDAAuD;AAAA,YAClG,SAAS,UAAU;AAAA,YACnB,OAAO,aAAa;AAAA,YACpB,QAAQ,SAAS;AAAA,UACnB,CAAC;AAAA,UACD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,eAAW,SAAS,wBAAwB,QAAQ,GAAG;AACrD,YAAM,UAAU,MAAM,UAAU,IAC5B,MAAM,gBACN;AAAA,QACE;AAAA,QACA;AAAA,QACA,EAAE,OAAO,MAAM,OAAO,SAAS,MAAM,cAAc;AAAA,MACrD;AACJ,YAAM,SAAS,OAAO;AAAA,IACxB;AAEA,WAAO,UAAU,SAAS;AAAA,EAC5B,GAAG,CAAC,uBAAuB,SAAS,mBAAmB,iBAAiB,CAAC,CAAC;AAE1E,QAAM,EAAE,MAAM,kBAAkB,CAAC,EAAE,IAAI,mBAAmB,CAAC,EAAE,UAAU,aAAa,GAAG;AAAA,IACrF,WAAW,CAAC,cAAc,WAAW;AAAA,EACvC,CAAC;AACD,QAAM,gBAAgB,iBAAiB;AACvC,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAiC,CAAC,CAAC;AAI7F,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAiC,CAAC,CAAC;AAC7E,QAAM,UAAU,MAAM;AACpB,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,YAAY;AAChB,SAAK,4BAA4B,IAAI,EAAE,UAAU,KAAK,QAAQ,WAAW,OAAO,CAAC,EAC9E,KAAK,CAAC,UAAU;AACf,UAAI,UAAW;AACf,4BAAsB,kCAAkC,KAAK,CAAC;AAC9D,YAAM,QAAgC,CAAC;AACvC,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,OAAQ,OAAM,KAAK,MAAM,IAAI,KAAK;AAAA,MAC7C;AACA,oBAAc,KAAK;AAAA,IACrB,CAAC,EACA,MAAM,MAAM;AACX,UAAI,UAAW;AACf,4BAAsB,CAAC,CAAC;AACxB,oBAAc,CAAC,CAAC;AAAA,IAClB,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AACjB,QAAM,6BAA6B,MAAM;AAAA,IACvC,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,EAAE,iCAAiC,cAAc;AAAA,IACnD;AAAA,IACA,CAAC,eAAe,oBAAoB,CAAC;AAAA,EACvC;AACA,QAAM,yBAAyB,MAAM,YAAY,OAAO,UAAoD;AAC1G,UAAM,QAAQ,MAAM,4BAA4B,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;AAC9E,WAAO,kCAAkC,KAAK;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AACzB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AACL,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,QACC,CAAC,CAAC,IAAI,mBAAmB,IAAI,KAAK,IAAI,eAAe,IAAI,gBAAgB,IAAI,WAAW;AAAA,IAC1F,CAAC,YAAY;AAAA,EACf;AAEA,QAAM,UAAU,MAAM,QAA8B,MAAM;AACxD,UAAM,UAAU,oBAAC,UAAK,WAAU,iCAAiC,YAAE,8BAA8B,GAAE;AACnG,UAAM,eAAe,EAAE,mCAAmC;AAE1D,UAAM,gBAAgB,gBACnB,OAAO,CAAC,QAAQ,0BAA0B,GAAG,CAAC,EAC9C,IAAwB,CAAC,SAAS;AAAA,MACjC,aAAa,MAAM,IAAI,GAAG;AAAA,MAC1B,QAAQ,IAAI,SAAS,IAAI;AAAA,MACzB,MAAM;AAAA,QACJ,oBAAoB,IAAI,OAAO,SAAS,EAAE,sCAAsC,eAAe;AAAA,QAC/F,aAAa,IAAI,OAAO,SAAS,EAAE,sCAAsC,eAAe;AAAA,QACxF,YAAY,+BAA+B,IAAI,IAAI;AAAA,QACnD,eAAe,kCAAkC,IAAI,OAAO;AAAA,QAC5D,QAAQ,IAAI,gBAAgB;AAAA,QAC5B,UAAU;AAAA,MACZ;AAAA,MACA,MAAM,CAAC,EAAE,SAAS,MAAM;AACtB,cAAM,QAAQ,SAAS;AACvB,YAAI,SAAS,KAAM,QAAO;AAC1B,YAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,gBAAM,aAAa;AAAA,YACjB,MACG,IAAI,CAAC,SAAS;AACb,kBAAI,QAAQ,KAAM,QAAO;AACzB,kBAAI,OAAO,SAAS,SAAU,QAAO;AACrC,qBAAO,OAAO,IAAI;AAAA,YACpB,CAAC;AAAA,UACL;AACA,cAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,iBAAO,oBAAC,yBAAsB,QAAQ,YAAY,YAAY,GAAG;AAAA,QACnE;AACA,YAAI,OAAO,UAAU,WAAW;AAC9B,iBACE,oBAAC,UAAK,WAAU,WACb,kBACG,EAAE,mCAAmC,KAAK,IAC1C,EAAE,kCAAkC,IAAI,GAC9C;AAAA,QAEJ;AACA,cAAM,cAAc,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI,OAAO,KAAK;AAC3E,YAAI,CAAC,YAAa,QAAO;AACzB,eAAO,oBAAC,UAAK,WAAU,WAAW,uBAAY;AAAA,MAChD;AAAA,IACF,EAAE;AAEJ,WAAO;AAAA,MACL;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,oCAAoC;AAAA,QAC9C,MAAM;AAAA,UACJ,eAAe;AAAA,UACf,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,UACb,UAAU;AAAA,QACZ;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MACX,qBAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,UAAK,WAAU,+FACd,8BAAC,aAAU,WAAU,WAAU,GACjC;AAAA,UACA,oBAAC,UAAK,WAAU,wCAAwC,cAAI,SAAS,OAAM;AAAA,UAC1E,cAAc,IAAI,QAAQ,IACzB;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,cAAY,EAAE,oCAAoC;AAAA;AAAA,UACpD,IACE;AAAA,WACN;AAAA,MAEJ;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,qCAAqC;AAAA,QAC/C,MAAM;AAAA,UACJ,YAAY;AAAA,UACZ,eAAe,kBAAkB;AAAA,UACjC,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,SAAS,IAAI,SAAS;AAC5B,cAAI,CAAC,OAAQ,QAAO;AACpB,gBAAM,QAAQ,eAAe,eAAe,IAAI,MAAM;AACtD,gBAAM,QAAQ,OAAO,SAAS;AAC9B,gBAAM,UAAU,yBAAyB,yBAAyB,OAAO,KAAK,CAAC;AAC/E,iBAAO,oBAAC,eAAY,SAAkB,KAAG,MAAE,iBAAM;AAAA,QACnD;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,4CAA4C;AAAA,QACtD,MAAM;AAAA,UACJ,YAAY;AAAA,UACZ,eAAe,kBAAkB;AAAA,UACjC,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,QAAQ,IAAI,SAAS;AAC3B,cAAI,CAAC,MAAO,QAAO;AACnB,gBAAM,QAAQ,eAAe,iBAAiB,IAAI,KAAK,GAAG,SAAS;AACnE,iBAAO,oBAAC,UAAK,WAAU,mBAAmB,iBAAM;AAAA,QAClD;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,yCAAyC,UAAU;AAAA,QAC7D,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,UACb,UAAU;AAAA,QACZ;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,OAAO,IAAI,SAAS,aAAa,cAAc,IAAI,SAAS,UAAU,IAAI;AAChF,iBAAO,OAAO,oBAAC,UAAK,WAAU,WAAW,gBAAK,IAAU;AAAA,QAC1D;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,oCAAoC;AAAA,QAC9C,MAAM;AAAA,UACJ,YAAY;AAAA,UACZ,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,SAAS,oBAAoB,IAAI,SAAS,eAAe,IAAI;AACnE,cAAI,WAAW,KAAM,QAAO;AAC5B,gBAAM,WAAW,IAAI,SAAS;AAC9B,iBACE,qBAAC,SAAI,WAAU,iBACb;AAAA,gCAAC,UAAK,WAAU,+BAA+B,kBAAO;AAAA,YACrD,WAAW,oBAAC,UAAK,WAAU,iCAAiC,oBAAS,IAAU;AAAA,aAClF;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,0CAA0C;AAAA,QACpD,MAAM;AAAA,UACJ,YAAY;AAAA,UACZ,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,QAAQ,IAAI,SAAS;AAC3B,cAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AACvD,mBAAO,oBAAC,UAAK,WAAU,+BAA+B,aAAG,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,KAAI;AAAA,UAChG;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,4CAA4C;AAAA,QACtD,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,UACb,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,kBAAkB,IAAI,SAAS;AACrC,cAAI,CAAC,gBAAiB,QAAO;AAC7B,cAAI,WAA4B;AAChC,cAAI,cAAc,IAAI,QAAQ,GAAG;AAC/B,uBACE,oBAAC,UAAK,WAAU,kCAAkC,YAAE,oCAAoC,GAAE;AAAA,UAE9F,WAAW,gBAAgB,IAAI,SAAS,MAAM,GAAG;AAC/C,uBACE,oBAAC,UAAK,WAAU,iCAAiC,YAAE,gCAAgC,GAAE;AAAA,UAEzF,WAAW,iBAAiB,IAAI,SAAS,MAAM,GAAG;AAChD,uBACE,oBAAC,UAAK,WAAU,iCAAiC,YAAE,iCAAiC,GAAE;AAAA,UAE1F,OAAO;AACL,kBAAM,WAAW,mBAAmB,iBAAiB,EAAE,QAAQ,WAAW,EAAE,CAAC;AAC7E,gBAAI,UAAU;AACZ,yBAAW,oBAAC,UAAK,WAAU,iCAAiC,oBAAS;AAAA,YACvE;AAAA,UACF;AACA,iBACE,qBAAC,SAAI,WAAU,iBACb;AAAA,gCAAC,UAAK,WAAU,mBACb,0BAAgB,iBAAiB,EAAE,8BAA8B,CAAC,GACrE;AAAA,YACC;AAAA,aACH;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,sCAAsC,OAAO;AAAA,QACvD,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,YAAY;AAAA,UACZ,eAAe;AAAA,UACf,mBAAmB;AAAA,UACnB,aAAa;AAAA,UACb,gBAAgB;AAAA,UAChB,WAAW;AAAA,QACb;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,cAAc,IAAI,SAAS;AACjC,cAAI,CAAC,YAAa,QAAO;AACzB,gBAAM,QAAQ,WAAW,WAAW,GAAG,KAAK,KAAK;AACjD,iBACE,qBAAC,SAAI,WAAU,mCACb;AAAA,gCAAC,UAAO,OAAc,MAAK,MAAK;AAAA,YAChC,oBAAC,UAAK,WAAU,4BAA4B,iBAAM;AAAA,aACpD;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,wCAAwC;AAAA,QAClD,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,YAAY;AAAA,UACZ,aAAa;AAAA,UACb,gBAAgB;AAAA,UAChB,UAAU;AAAA,UACV,gBAAgB,CAAC,QACf;AAAA,YACE,IAAI,UAAU,IAAI,CAAC,UAAW,MAAM,SAAS,MAAM,MAAM,KAAK,EAAE,SAAS,MAAM,QAAQ,EAAE,qCAAqC,CAAE;AAAA,UAClI,EAAE,KAAK,IAAI;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,YAAY,IAAI,SAAS;AAC/B,cAAI,CAAC,UAAU,OAAQ,QAAO;AAC9B,gBAAM,QAAQ,UAAU,CAAC;AACzB,gBAAM,aACJ,MAAM,SAAS,MAAM,MAAM,KAAK,EAAE,SAAS,MAAM,QAAQ,EAAE,qCAAqC;AAClG,gBAAM,WAAW,UAAU,SAAS;AACpC,iBACE,qBAAC,SAAI,WAAU,qCACb;AAAA,gCAAC,OAAI,SAAQ,WAAU,WAAU,YAC/B,8BAAC,UAAK,WAAU,YAAY,sBAAW,GACzC;AAAA,YACC,WAAW,IAAI,oBAAC,OAAI,SAAQ,WAAW,cAAI,QAAQ,IAAG,IAAS;AAAA,aAClE;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,qCAAqC;AAAA,QAC/C,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,YAAY;AAAA,UACZ,aAAa;AAAA,UACb,gBAAgB;AAAA,UAChB,UAAU;AAAA,UACV,gBAAgB,CAAC,QACf;AAAA,YACE,IAAI,OAAO,IAAI,CAAC,UAAW,MAAM,SAAS,MAAM,MAAM,KAAK,EAAE,SAAS,MAAM,QAAQ,EAAE,oCAAoC,CAAE;AAAA,UAC9H,EAAE,KAAK,IAAI;AAAA,QACf;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,SAAS,IAAI,SAAS;AAC5B,cAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,gBAAM,SAAS;AAAA,YACb,OAAO,IAAI,CAAC,WACV,OAAO,SAAS,OAAO,MAAM,KAAK,EAAE,SAAS,OAAO,QAAQ,EAAE,oCAAoC,CAAC;AAAA,UACvG;AACA,gBAAM,UAAU,OAAO,KAAK,IAAI;AAChC,iBACE,oBAAC,iBAAc,SAAS,SAAS,MAAK,OACpC,8BAAC,UAAK,WAAU,eACd,8BAAC,eAAY,KAAK,GAAG,MAAK,MACvB,iBAAO,IAAI,CAAC,WACX;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,OAAO,SAAS,EAAE,oCAAoC;AAAA,cAC7D,MAAK;AAAA;AAAA,YAFA,OAAO;AAAA,UAGd,CACD,GACH,GACF,GACF;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,wCAAwC;AAAA,QAClD,MAAM;AAAA,UACJ,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,aAAa;AAAA,UACb,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,CAAC,EAAE,IAAI,MACX,oBAAC,UAAK,WAAU,WACb,0BAAgB,IAAI,SAAS,aAAa,MAAM,EAAE,8BAA8B,CAAC,GACpF;AAAA,MAEJ;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF,GAAG,CAAC,iBAAiB,gBAAgB,mBAAmB,eAAe,wBAAwB,QAAQ,YAAY,eAAe,4BAA4B,CAAC,CAAC;AAEhK,QAAM,EAAE,qBAAqB,IAAI,wBAAwB,EAAE,SAAS,gBAAgB,CAAC;AAQrF,QAAM,UAAU,MAAM;AACpB,mBAAe,CAAC,SAAS;AACvB,UAAI,SAAS,qBAAsB,QAAO;AAC1C,UAAI,KAAK,WAAW,qBAAqB,QAAQ;AAC/C,YAAI,OAAO;AACX,iBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAI,KAAK,CAAC,EAAE,QAAQ,qBAAqB,CAAC,EAAE,KAAK;AAAE,mBAAO;AAAO;AAAA,UAAM;AAAA,QACzE;AACA,YAAI,KAAM,QAAO;AAAA,MACnB;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,oBAAoB,CAAC;AAEzB,QAAM,0BAA0B,MAAM,QAA0B,MAAM;AACpE,UAAM,eAAe,oBAAI,IAAoB;AAC7C,UAAM,gBAAgB,oBAAI,IAAoB;AAC9C,eAAW,OAAO,MAAM;AACtB,iBAAW,UAAU,IAAI,QAAQ;AAC/B,YAAI,kBAAkB,SAAS,OAAO,EAAE,KAAK,OAAO,MAAM,KAAK,EAAE,SAAS,GAAG;AAC3E,uBAAa,IAAI,OAAO,IAAI,OAAO,KAAK;AAAA,QAC1C;AAAA,MACF;AACA,iBAAW,WAAW,IAAI,WAAW;AACnC,YAAI,mBAAmB,SAAS,QAAQ,EAAE,KAAK,QAAQ,MAAM,KAAK,EAAE,SAAS,GAAG;AAC9E,wBAAc,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,QACE,KAAK;AAAA,QACL,OAAO,EAAE,uCAAuC,QAAQ;AAAA,QACxD,MAAM;AAAA,QACN,SAAS,kBAAkB,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,OAAO,aAAa,IAAI,EAAE,KAAK,GAAG,EAAE;AAAA,MAC3F;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO,EAAE,0CAA0C,WAAW;AAAA,QAC9D,MAAM;AAAA,QACN,SAAS,mBAAmB,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,OAAO,cAAc,IAAI,EAAE,KAAK,GAAG,EAAE;AAAA,MAC7F;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,oBAAoB,mBAAmB,CAAC,CAAC;AACnD,QAAM,wBAAwB,MAAM,QAA4B,MAAM;AACpE,UAAM,QAA0E,CAAC;AACjF,QAAI,kBAAkB,OAAQ,OAAM,KAAK,EAAE,OAAO,UAAU,UAAU,aAAa,OAAO,kBAAkB,CAAC;AAC7G,QAAI,mBAAmB,OAAQ,OAAM,KAAK,EAAE,OAAO,aAAa,UAAU,aAAa,OAAO,mBAAmB,CAAC;AAClH,WAAO,MAAM,SAAS,kBAAkB,KAAK,IAAI,gBAAgB;AAAA,EACnE,GAAG,CAAC,oBAAoB,iBAAiB,CAAC;AAC1C,QAAM,gCAAgC,MAAM,YAAY,CAAC,WAAmB;AAC1E,UAAM,OAAO,sBAAsB,KAAK,SAAS,KAAK,CAAC,UAAU,MAAM,OAAO,MAAM;AACpF,QAAI,CAAC,QAAQ,KAAK,SAAS,OAAQ;AACnC,QAAI,KAAK,UAAU,SAAU,sBAAqB,CAAC,CAAC;AACpD,QAAI,KAAK,UAAU,YAAa,uBAAsB,CAAC,CAAC;AACxD,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,sBAAsB,KAAK,QAAQ,CAAC;AAExC,QAAM,eAAe,MAAM,QAAwB,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE/E,SACE,qBAAC,QACC;AAAA,yBAAC,YACC;AAAA,0BAAC,eAAY,QAAO,QAAO,WAAU,QAAO;AAAA,MAC5C;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,iBAAiB,eAAe,iBAAiB,KAAK,CAAC;AAAA,UACvD,eAAe,OAAO,KAAK,aAAa,EAAE;AAAA,UAC1C;AAAA,UACA;AAAA,UACA,uBAAuB;AAAA,UACvB,WAAU;AAAA;AAAA,MACZ;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,mBAAiB;AAAA,UACjB,qBAAmB;AAAA,UACnB,oBAAmB;AAAA,UACnB,OAAO,EAAE,4BAA4B;AAAA,UACrC,SACE,oBAAC,UAAO,SAAO,MACb,8BAAC,QAAK,MAAK,mCACR,YAAE,oCAAoC,UAAU,GACnD,GACF;AAAA,UAEF;AAAA,UACA,eAAe,EAAE,MAAM,KAAK;AAAA,UAC5B,MAAM;AAAA,UACN,YAAY,CAAC,QAAQ;AACnB,mBAAO,KAAK,4BAA4B,IAAI,EAAE,EAAE;AAAA,UAClD;AAAA,UACA,YAAY,CAAC,QAAQ;AACnB,kBAAM,aAAa,oBAAoB,IAAI;AAC3C,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL;AAAA,oBACE,IAAI;AAAA,oBACJ,OAAO,EAAE,qCAAqC,MAAM;AAAA,oBACpD,UAAU,MAAM;AAAE,6BAAO,KAAK,4BAA4B,IAAI,EAAE,EAAE;AAAA,oBAAE;AAAA,kBACtE;AAAA,kBACA;AAAA,oBACE,IAAI;AAAA,oBACJ,OAAO,EAAE,6CAA6C,iBAAiB;AAAA,oBACvE,UAAU,MAAM;AACd,0BAAI,OAAO,WAAW,aAAa;AACjC,+BAAO,KAAK,4BAA4B,IAAI,EAAE,IAAI,UAAU,UAAU;AAAA,sBACxE;AAAA,oBACF;AAAA,kBACF;AAAA,kBACA;AAAA,oBACE,IAAI;AAAA,oBACJ,OAAO,aACH,EAAE,yCAAyC,gBAAW,IACtD,EAAE,uCAAuC,QAAQ;AAAA,oBACrD,aAAa;AAAA,oBACb,UAAU,MAAM,iBAAiB,IAAI,EAAE;AAAA,kBACzC;AAAA,gBACF;AAAA;AAAA,YACF;AAAA,UAEJ;AAAA,UACA,UAAQ;AAAA,UACR;AAAA,UACA,iBAAiB;AAAA,UACjB,aAAa;AAAA,YACX;AAAA,cACE,IAAI;AAAA,cACJ,OAAO,EAAE,uCAAuC,QAAQ;AAAA,cACxD,aAAa;AAAA,cACb,WAAW;AAAA,YACb;AAAA,UACF;AAAA,UACA,aAAa;AAAA,UACb,gBAAgB;AAAA,UAChB,mBAAmB,EAAE,wCAAwC;AAAA,UAC7D,YAAY;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc,CAAC,aAAa,QAAQ,QAAQ;AAAA,YAC5C,iBAAiB,CAAC,IAAI,IAAI,IAAI,GAAG;AAAA,YACjC,kBAAkB;AAAA,YAClB;AAAA,UACF;AAAA,UACA;AAAA,UACA,eAAe;AAAA,YACb,OAAO,EAAE,8BAA8B;AAAA,YACvC,WAAW;AAAA,UACb;AAAA,UACA,UAAU;AAAA,UACV,UAAU,EAAE,UAAU;AAAA,UACtB,aAAa,EAAE,SAAS,gBAAgB,MAAM,WAAW,QAAQ;AAAA,UACjE,gBAAgB;AAAA,YACd,MAAM;AAAA,YACN,OAAO,YAAY;AAAA,YACnB,UAAU,YAAY;AAAA,YACtB,SAAS,MAAM,YAAY,MAAM;AAAA,YACjC,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,iBAAiB;AAAA,YACjB,gBAAgB,MAAM,eAAe,CAAC,SAAS,CAAC,IAAI;AAAA,YACpD,aAAa,CAAC,SAAS;AACrB,0BAAY,YAAY,IAAI;AAC5B,sBAAQ,CAAC;AAAA,YACX;AAAA,UACF;AAAA,UACA,mBACE,iCACG;AAAA,iCACC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,eAAY;AAAA,gBAEZ;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,eAAY;AAAA,oBACZ,cAAY,EAAE,6CAA6C;AAAA,oBAE3D;AAAA,0CAAC,OAAI,SAAQ,WAAU,KAAG,MAAE,YAAE,6CAA6C,GAAE;AAAA,sBAC7E;AAAA,wBAAC;AAAA;AAAA,0BACC,MAAK;AAAA,0BACL,SAAQ;AAAA,0BACR,MAAK;AAAA,0BACL,cAAY,EAAE,mDAAmD;AAAA,0BACjE,SAAS;AAAA,0BAET,8BAAC,KAAE,WAAU,UAAS;AAAA;AAAA,sBACxB;AAAA;AAAA;AAAA,gBACF;AAAA;AAAA,YACF,IACE;AAAA,YACJ;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,QAAQ;AAAA,gBACR,aAAa;AAAA,gBACb,cAAc;AAAA,gBACd,QAAQ,MAAM,eAAe,IAAI;AAAA;AAAA,YACnC;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,YAAY;AAAA,gBAClB,QAAQ;AAAA,gBACR,aAAa;AAAA,gBACb,cAAc,CAAC,OAAO,YAAY,SAAS,EAAE,MAAM,cAAc,QAAQ,GAAG,CAAC;AAAA,gBAC7E,QAAQ,MAAM,eAAe,IAAI;AAAA;AAAA,YACnC;AAAA,aACF;AAAA,UAEF,uBAAuB;AAAA,YACrB,QAAQ,sBAAsB,sBAAsB,KAAK,SAAS,SAAS,KAAK,oBAAoB,KAAK,SAAS,SAAS;AAAA,YAC3H,kBAAkB,EAAE,gCAAgC,OAAO;AAAA,YAC3D,eAAe,sBAAsB,sBAAsB,KAAK,SAAS,SAAS,KAAK,YAAY,KAAK,KAAK,SAAS,SAAS;AAAA,YAC/H,YAAY,MAAM;AAChB,wCAA0B;AAC1B,mCAAqB,CAAC,CAAC;AACvB,oCAAsB,CAAC,CAAC;AACxB,oCAAsB,KAAK;AAAA,YAC7B;AAAA,YACA,cAAc,MAAM;AAClB,kBAAI,oBAAoB;AACtB,0CAA0B;AAC1B;AAAA,cACF;AACA,kBAAI,mBAAmB,SAAS,GAAG;AACjC,sCAAsB,CAAC,CAAC;AACxB,wBAAQ,CAAC;AACT;AAAA,cACF;AACA,kBAAI,kBAAkB,SAAS,GAAG;AAChC,qCAAqB,CAAC,CAAC;AACvB,wBAAQ,CAAC;AACT;AAAA,cACF;AACA,0BAAY,SAAS,EAAE,MAAM,aAAa,CAAC;AAAA,YAC7C;AAAA,UACF;AAAA,UACA,YACE;AAAA,YAAC;AAAA;AAAA,cACC,YAAY,EAAE,gCAAgC,OAAO;AAAA,cACrD,YAAW;AAAA,cACX,aAAa,EAAE,oCAAoC,UAAU;AAAA;AAAA,UAC/D;AAAA,UAEF,aAAW;AAAA;AAAA,MACb;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,QAAQ;AAAA,UACR,OAAO,YAAY;AAAA,UACnB,UAAU,YAAY;AAAA,UACtB,SAAS,YAAY;AAAA,UACrB,SAAS;AAAA,UACT,SAAS,YAAY;AAAA,UACrB,eAAe,YAAY;AAAA,UAC3B,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,MAAM;AAAA,UACN,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,uBAAsB;AAAA;AAAA,MACxB;AAAA,OACF;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,SAAS,QAAQ,MAA+C;AAC9D,QAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACnD,MAAI,CAAC,GAAI,QAAO;AAChB,QAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAC5D,QAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAC/D,QAAM,gBAAgB,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AACtF,QAAM,kBAAkB,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB;AAC9F,QAAM,aAAa,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAC7E,QAAM,iBAAiB,KAAK;AAC5B,QAAM,cACJ,OAAO,mBAAmB,WACtB,iBACA,OAAO,mBAAmB,YAAY,eAAe,KAAK,IACxD,OAAO,cAAc,IACrB;AACR,QAAM,gBACJ,OAAO,KAAK,mBAAmB,YAAY,KAAK,eAAe,KAAK,EAAE,SAClE,KAAK,eAAe,KAAK,EAAE,YAAY,IACvC;AACN,QAAM,iBAAiB,KAAK;AAC5B,QAAM,cACJ,OAAO,mBAAmB,WACtB,iBACA,OAAO,mBAAmB,YAAY,eAAe,KAAK,EAAE,SAC1D,OAAO,cAAc,IACrB;AACR,QAAM,kBAAkB,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB;AAC9F,QAAM,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC1E,QAAM,cAAc,OAAO,KAAK,kBAAkB,WAAW,KAAK,gBAAgB;AAClF,QAAM,YAAY,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAC9D,QAAM,eAAe,MAAM,QAAQ,KAAK,SAAS,IAAI,KAAK,YAAY,CAAC;AACvE,QAAM,SAAS,UACZ,IAAI,CAAC,UAAU;AACd,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,UAAM,OAAO;AACb,UAAM,MAAM,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACpD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAC5D,WAAO,EAAE,IAAI,KAAK,MAAM;AAAA,EAC1B,CAAC,EACA,OAAO,CAAC,UAAkD,CAAC,CAAC,KAAK;AACpE,QAAM,YAAY,aACf,IAAI,CAAC,UAAU;AACd,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,UAAM,OAAO;AACb,UAAM,MAAM,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACpD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAC5D,WAAO,EAAE,IAAI,KAAK,MAAM;AAAA,EAC1B,CAAC,EACA,OAAO,CAAC,UAAkD,CAAC,CAAC,KAAK;AACpE,QAAM,eAAwC,CAAC;AAC/C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,QAAI,IAAI,WAAW,KAAK,EAAG,cAAa,GAAG,IAAI;AAAA,EACjD;AACA,SAAO,wBAAwB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GAAG,IAAI;AACT;",
6
6
  "names": []
7
7
  }
@@ -19,7 +19,7 @@ import { flash } from "@open-mercato/ui/backend/FlashMessages";
19
19
  import { useT } from "@open-mercato/shared/lib/i18n/context";
20
20
  import { translateWithFallback } from "@open-mercato/shared/lib/i18n/translate";
21
21
  import { registerComponent } from "@open-mercato/shared/modules/widgets/component-registry";
22
- const STATUS_OPTIONS = ["open", "in_progress", "win", "loose"];
22
+ const STATUS_OPTIONS = ["open", "in_progress", "win", "lost"];
23
23
  const FALLBACK_CURRENCIES = [
24
24
  { code: "USD", isBase: true },
25
25
  { code: "EUR" },
@@ -166,7 +166,7 @@ function QuickDealDialog({
166
166
  id: "status",
167
167
  label: translateWithFallback(t, "customers.deals.kanban.quickDeal.status", "Status"),
168
168
  type: "select",
169
- // Storage value is preserved (`loose` etc.) only the displayed label is
169
+ // Storage value is preserved (`lost` etc.), only the displayed label is
170
170
  // translated, so we never write a localised string back to the DB.
171
171
  options: STATUS_OPTIONS.map((statusValue) => ({
172
172
  value: statusValue,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { ComboboxInput } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { registerComponent } from '@open-mercato/shared/modules/widgets/component-registry'\n\n// Deal status values written by the kanban flow. These intentionally do NOT include 'closed'\n// because the rest of the app only persists 'loose' for lost deals (see StatusFilterPopover\n// notes). 'in_progress' is kept for backwards compatibility with quick-deals created from\n// the previous version of this dialog. The labels are looked up via i18n at render time so\n// the historic typo 'loose' doesn't leak to operators \u2014 the storage value stays unchanged.\nconst STATUS_OPTIONS = ['open', 'in_progress', 'win', 'loose'] as const\n\n/**\n * Tenant currency option. The page resolves these from the currencies module (see\n * `useCurrencyDictionary`) and passes them in; we no longer hardcode the 4-currency\n * list that previously locked tenants on CZK/SEK/HUF/etc. out of quick-add.\n */\nexport type QuickDealCurrencyOption = {\n code: string\n label?: string\n isBase?: boolean\n}\n\nconst FALLBACK_CURRENCIES: QuickDealCurrencyOption[] = [\n { code: 'USD', isBase: true },\n { code: 'EUR' },\n { code: 'GBP' },\n { code: 'PLN' },\n]\n\nexport type QuickDealContext = {\n pipelineId: string\n pipelineName: string\n pipelineStageId: string\n pipelineStageLabel: string\n}\n\nexport type QuickDealCompanyOption = {\n id: string\n label: string\n}\n\n/**\n * Registered component id for the kanban quick-add dialog. Downstream apps can\n * target it from `widgets/components.ts` to replace/wrap the dialog or to\n * transform its props \u2014 e.g. `defaultProbability: null` so quick-create stops\n * seeding a probability that overrides pipeline automation (#4329).\n */\nexport const QUICK_DEAL_DIALOG_COMPONENT_ID = 'dialog:customers.deals.quickDeal'\n\n/** Probability seeded into the quick-add form when the host passes no override. */\nexport const DEFAULT_QUICK_DEAL_PROBABILITY = 25\n\nexport type QuickDealDialogProps = {\n open: boolean\n context: QuickDealContext | null\n onClose: () => void\n onCreated: () => void\n currentUserId?: string\n currentUserLabel?: string\n companies?: QuickDealCompanyOption[]\n /**\n * Probability pre-filled in the collapsed \"More details\" group. `null` leaves\n * the field empty, so quick-create sends no `probability` at all and whatever\n * the pipeline/automation derives for the target stage stands. Defaults to\n * `DEFAULT_QUICK_DEAL_PROBABILITY` to preserve the historic behavior.\n */\n defaultProbability?: number | null\n /**\n * Tenant currency list. When omitted (e.g. dictionary not yet loaded), we render a\n * conservative fallback so the dialog still works end-to-end. The default selection is\n * always the entry with `isBase: true`, falling back to the first item.\n */\n currencies?: QuickDealCurrencyOption[]\n}\n\ntype QuickDealFormValues = {\n title: string\n valueAmount: number | null\n valueCurrency: string\n companyId: string\n status: (typeof STATUS_OPTIONS)[number]\n probability: number | null\n expectedCloseAt: string\n description: string\n}\n\nconst QUICK_DEAL_CONTEXT_ID = 'customers-deals-kanban:quick-deal'\n\nexport function QuickDealDialog({\n open,\n context,\n onClose,\n onCreated,\n currentUserId,\n currentUserLabel,\n companies = [],\n currencies,\n defaultProbability = DEFAULT_QUICK_DEAL_PROBABILITY,\n}: QuickDealDialogProps): React.ReactElement | null {\n const t = useT()\n // Re-mount CrudForm whenever the dialog opens so cleared state is consistently fresh.\n // We also key on `context?.pipelineStageId` so reopening from a different stage doesn't\n // reuse stale field values (the page passes a fresh stage in `context` each time).\n const [formInstanceKey, setFormInstanceKey] = React.useState(0)\n React.useEffect(() => {\n if (open) setFormInstanceKey((current) => current + 1)\n }, [open])\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: QUICK_DEAL_CONTEXT_ID,\n blockedMessage: translateWithFallback(t, 'ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const titleRequiredMessage = translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.title.required',\n 'Title is required.',\n )\n\n // Default currency selection: tenant base currency, else first available, else 'USD' as\n // a last-resort literal that satisfies the form validator (which now accepts any 3-char\n // code rather than a hardcoded enum).\n const resolvedCurrencies = React.useMemo(\n () => (currencies && currencies.length > 0 ? currencies : FALLBACK_CURRENCIES),\n [currencies],\n )\n const defaultCurrencyCode = React.useMemo(() => {\n const base = resolvedCurrencies.find((currency) => currency.isBase)\n return base?.code ?? resolvedCurrencies[0]?.code ?? 'USD'\n }, [resolvedCurrencies])\n\n const formSchema = React.useMemo(\n () =>\n z.object({\n title: z.string().trim().min(1, titleRequiredMessage),\n valueAmount: z.number().min(0).nullable().optional(),\n // The set of valid currencies is tenant-defined and resolved at runtime; we accept\n // any non-empty string here and let the server (which knows the canonical list)\n // reject anything bogus.\n valueCurrency: z.string().min(1),\n companyId: z.string().optional(),\n status: z.enum(STATUS_OPTIONS),\n probability: z.number().min(0).max(100).nullable().optional(),\n expectedCloseAt: z.string().optional(),\n description: z.string().optional(),\n }),\n // Cast widens to QuickDealFormValues so CrudForm's TValues generic stays exact.\n [titleRequiredMessage],\n ) as unknown as z.ZodType<QuickDealFormValues>\n\n const initialValues = React.useMemo<Partial<QuickDealFormValues>>(\n () => ({\n title: '',\n valueAmount: null,\n valueCurrency: defaultCurrencyCode,\n companyId: '',\n status: 'open',\n probability: defaultProbability,\n expectedCloseAt: '',\n description: '',\n }),\n [defaultCurrencyCode, defaultProbability],\n )\n\n const fields = React.useMemo<CrudField[]>(\n () => {\n const list: CrudField[] = [\n {\n // CrudForm auto-focuses the first field of the first group on mount; we don't\n // need (and CrudField doesn't accept) an explicit `autoFocus` prop here.\n id: 'title',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.title.label', 'Deal title'),\n type: 'text',\n required: true,\n placeholder: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.title.placeholder',\n 'e.g. Q3 Expansion \u2014 Lighting Package',\n ),\n },\n {\n id: 'valueAmount',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.value', 'Value'),\n type: 'number',\n layout: 'half',\n placeholder: '0',\n },\n {\n id: 'valueCurrency',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.currency', 'Currency'),\n type: 'select',\n layout: 'half',\n options: resolvedCurrencies.map((currency) => ({\n value: currency.code,\n label: currency.label && currency.label !== currency.code\n ? `${currency.code} \u2014 ${currency.label}`\n : currency.code,\n })),\n },\n {\n // Company is a typeahead (ComboboxInput) rather than a plain <select>: tenants\n // with hundreds of companies get an unusable dropdown otherwise. The `seedOptions`\n // carry the most-recent companies the page already loaded; an async loader could\n // be added later to hit the companies search endpoint for full coverage.\n id: 'companyId',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.company', 'Company'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <ComboboxInput\n value={typeof value === 'string' ? value : ''}\n onChange={(next) => setValue(next)}\n seedOptions={companies.map((company) => ({ value: company.id, label: company.label }))}\n placeholder={translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.companyPh',\n 'Pick a company or add new\u2026',\n )}\n allowCustomValues={false}\n />\n ),\n },\n ]\n // Owner is read-only display of the current user (mirrors original UX). Hidden when\n // we don't know the user \u2014 avoids confusing empty avatar cell.\n if (currentUserLabel) {\n list.push({\n id: 'owner',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.owner', 'Owner'),\n type: 'custom',\n readOnly: true,\n component: () => (\n <div className=\"flex h-9 items-center gap-2 rounded-md border border-input bg-card px-3 text-sm\">\n <Avatar label={currentUserLabel} size=\"sm\" />\n <span>{currentUserLabel}</span>\n </div>\n ),\n })\n }\n // Progressive disclosure: status + probability + close date + description live in\n // a separate \"More details\" group with `defaultExpanded: false` (configured via\n // collapsibleGroups on the host CrudForm).\n list.push(\n {\n id: 'status',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.status', 'Status'),\n type: 'select',\n // Storage value is preserved (`loose` etc.) \u2014 only the displayed label is\n // translated, so we never write a localised string back to the DB.\n options: STATUS_OPTIONS.map((statusValue) => ({\n value: statusValue,\n label: translateWithFallback(\n t,\n `customers.deals.kanban.quickDeal.status.${statusValue}`,\n statusValue,\n ),\n })),\n },\n {\n id: 'probability',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.probability', 'Probability'),\n type: 'number',\n layout: 'half',\n placeholder: '25',\n },\n {\n id: 'expectedCloseAt',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.expectedClose', 'Expected close'),\n type: 'date',\n layout: 'half',\n },\n {\n id: 'description',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.description', 'Description'),\n type: 'textarea',\n rows: 3,\n placeholder: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.description.placeholder',\n 'Short context, decision makers or next steps. Markdown supported.',\n ),\n },\n )\n return list\n },\n [companies, currentUserLabel, resolvedCurrencies, t],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'basic',\n // No title \u2014 keep the basic section flush with the dialog header.\n fields: ['title', 'valueAmount', 'valueCurrency', 'companyId', ...(currentUserLabel ? ['owner'] : [])],\n },\n {\n id: 'more',\n title: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.more',\n 'More details (probability, close date, description)',\n ),\n fields: ['status', 'probability', 'expectedCloseAt', 'description'],\n },\n ],\n [currentUserLabel, t],\n )\n\n const handleSubmit = React.useCallback(\n async (values: QuickDealFormValues) => {\n if (!context) return\n const trimmedTitle = values.title.trim()\n if (!trimmedTitle.length) {\n throw createCrudFormError(titleRequiredMessage, { title: titleRequiredMessage })\n }\n const payload: Record<string, unknown> = {\n title: trimmedTitle,\n pipelineId: context.pipelineId,\n pipelineStageId: context.pipelineStageId,\n valueCurrency: values.valueCurrency,\n }\n if (typeof values.valueAmount === 'number' && Number.isFinite(values.valueAmount)) {\n payload.valueAmount = values.valueAmount\n }\n if (currentUserId) payload.ownerUserId = currentUserId\n if (values.companyId) payload.companyIds = [values.companyId]\n if (values.status) payload.status = values.status\n if (typeof values.probability === 'number' && Number.isFinite(values.probability)) {\n payload.probability = values.probability\n }\n if (values.expectedCloseAt && values.expectedCloseAt.trim().length) {\n payload.expectedCloseAt = values.expectedCloseAt\n }\n if (values.description && values.description.trim().length) {\n payload.description = values.description\n }\n const operation = () =>\n createCrud('customers/deals', payload, {\n errorMessage: translateWithFallback(t, 'customers.deals.create.error', 'Failed to create deal.'),\n })\n await runMutation({\n operation,\n context: {\n formId: QUICK_DEAL_CONTEXT_ID,\n resourceKind: 'customers.deal',\n retryLastMutation,\n },\n })\n flash(\n translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.success',\n 'Deal added to {stage}.',\n { stage: context.pipelineStageLabel },\n ),\n 'success',\n )\n onCreated()\n onClose()\n },\n [context, currentUserId, onClose, onCreated, retryLastMutation, runMutation, t, titleRequiredMessage],\n )\n\n if (!context) return null\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) onClose()\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {translateWithFallback(t, 'customers.deals.kanban.quickDeal.title', 'Quick deal')}\n </DialogTitle>\n <DialogDescription>\n {translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.context',\n 'Pipeline: {pipeline} \u00B7 Stage: {stage}',\n { pipeline: context.pipelineName, stage: context.pipelineStageLabel },\n )}\n </DialogDescription>\n </DialogHeader>\n\n <CrudForm<QuickDealFormValues>\n key={`${context.pipelineStageId}:${formInstanceKey}`}\n embedded\n fields={fields}\n groups={groups}\n // The \"More details\" group starts collapsed; users can expand to set\n // status / probability / close date / description. Mirrors the previous\n // \"+ More details\" toggle.\n collapsibleGroups={{ pageType: 'customers.deals.kanban.quickDeal' }}\n initialValues={initialValues}\n schema={formSchema}\n submitLabel={translateWithFallback(t, 'customers.deals.kanban.quickDeal.submit', 'Add deal')}\n onSubmit={handleSubmit}\n />\n </DialogContent>\n </Dialog>\n )\n}\n\n// Register so downstream apps can reach the dialog from `widgets/components.ts`\n// (replace / wrap / propsTransform) instead of forking the whole kanban page\n// just to change a default (#4329).\nregisterComponent<QuickDealDialogProps>({\n id: QUICK_DEAL_DIALOG_COMPONENT_ID,\n component: QuickDealDialog,\n metadata: {\n module: 'customers',\n description: 'Kanban quick-add deal dialog (pipeline board \"+ deal\").',\n },\n})\n\nexport default QuickDealDialog\n"],
5
- "mappings": ";AAsOY,cAuBA,YAvBA;AApOZ,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,gBAAoD;AAC7D,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AACpC,SAAS,0BAA0B;AACnC,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,yBAAyB;AAOlC,MAAM,iBAAiB,CAAC,QAAQ,eAAe,OAAO,OAAO;AAa7D,MAAM,sBAAiD;AAAA,EACrD,EAAE,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC5B,EAAE,MAAM,MAAM;AAAA,EACd,EAAE,MAAM,MAAM;AAAA,EACd,EAAE,MAAM,MAAM;AAChB;AAoBO,MAAM,iCAAiC;AAGvC,MAAM,iCAAiC;AAoC9C,MAAM,wBAAwB;AAEvB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,CAAC;AAAA,EACb;AAAA,EACA,qBAAqB;AACvB,GAAoD;AAClD,QAAM,IAAI,KAAK;AAIf,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,CAAC;AAC9D,QAAM,UAAU,MAAM;AACpB,QAAI,KAAM,oBAAmB,CAAC,YAAY,UAAU,CAAC;AAAA,EACvD,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAIxC;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,sBAAsB,GAAG,8BAA8B,4BAA4B;AAAA,EACrG,CAAC;AAED,QAAM,uBAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAKA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,MAAO,cAAc,WAAW,SAAS,IAAI,aAAa;AAAA,IAC1D,CAAC,UAAU;AAAA,EACb;AACA,QAAM,sBAAsB,MAAM,QAAQ,MAAM;AAC9C,UAAM,OAAO,mBAAmB,KAAK,CAAC,aAAa,SAAS,MAAM;AAClE,WAAO,MAAM,QAAQ,mBAAmB,CAAC,GAAG,QAAQ;AAAA,EACtD,GAAG,CAAC,kBAAkB,CAAC;AAEvB,QAAM,aAAa,MAAM;AAAA,IACvB,MACE,EAAE,OAAO;AAAA,MACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,oBAAoB;AAAA,MACpD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA,MAInD,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,MAC/B,QAAQ,EAAE,KAAK,cAAc;AAAA,MAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5D,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,MACrC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACnC,CAAC;AAAA;AAAA,IAEH,CAAC,oBAAoB;AAAA,EACvB;AAEA,QAAM,gBAAgB,MAAM;AAAA,IAC1B,OAAO;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,CAAC,qBAAqB,kBAAkB;AAAA,EAC1C;AAEA,QAAM,SAAS,MAAM;AAAA,IACnB,MAAM;AACJ,YAAM,OAAoB;AAAA,QACxB;AAAA;AAAA;AAAA,UAGE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,gDAAgD,YAAY;AAAA,UAC5F,MAAM;AAAA,UACN,UAAU;AAAA,UACV,aAAa;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,0CAA0C,OAAO;AAAA,UACjF,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,aAAa;AAAA,QACf;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,6CAA6C,UAAU;AAAA,UACvF,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,SAAS,mBAAmB,IAAI,CAAC,cAAc;AAAA,YAC7C,OAAO,SAAS;AAAA,YAChB,OAAO,SAAS,SAAS,SAAS,UAAU,SAAS,OACjD,GAAG,SAAS,IAAI,WAAM,SAAS,KAAK,KACpC,SAAS;AAAA,UACf,EAAE;AAAA,QACJ;AAAA,QACA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,4CAA4C,SAAS;AAAA,UACrF,MAAM;AAAA,UACN,WAAW,CAAC,EAAE,OAAO,SAAS,MAC5B;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,cAC3C,UAAU,CAAC,SAAS,SAAS,IAAI;AAAA,cACjC,aAAa,UAAU,IAAI,CAAC,aAAa,EAAE,OAAO,QAAQ,IAAI,OAAO,QAAQ,MAAM,EAAE;AAAA,cACrF,aAAa;AAAA,gBACX;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,cACA,mBAAmB;AAAA;AAAA,UACrB;AAAA,QAEJ;AAAA,MACF;AAGA,UAAI,kBAAkB;AACpB,aAAK,KAAK;AAAA,UACR,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,0CAA0C,OAAO;AAAA,UACjF,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAW,MACT,qBAAC,SAAI,WAAU,mFACb;AAAA,gCAAC,UAAO,OAAO,kBAAkB,MAAK,MAAK;AAAA,YAC3C,oBAAC,UAAM,4BAAiB;AAAA,aAC1B;AAAA,QAEJ,CAAC;AAAA,MACH;AAIA,WAAK;AAAA,QACH;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,2CAA2C,QAAQ;AAAA,UACnF,MAAM;AAAA;AAAA;AAAA,UAGN,SAAS,eAAe,IAAI,CAAC,iBAAiB;AAAA,YAC5C,OAAO;AAAA,YACP,OAAO;AAAA,cACL;AAAA,cACA,2CAA2C,WAAW;AAAA,cACtD;AAAA,YACF;AAAA,UACF,EAAE;AAAA,QACJ;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,gDAAgD,aAAa;AAAA,UAC7F,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,aAAa;AAAA,QACf;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,kDAAkD,gBAAgB;AAAA,UAClG,MAAM;AAAA,UACN,QAAQ;AAAA,QACV;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,sBAAsB,GAAG,gDAAgD,aAAa;AAAA,UAC7F,MAAM;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,WAAW,kBAAkB,oBAAoB,CAAC;AAAA,EACrD;AAEA,QAAM,SAAS,MAAM;AAAA,IACnB,MAAM;AAAA,MACJ;AAAA,QACE,IAAI;AAAA;AAAA,QAEJ,QAAQ,CAAC,SAAS,eAAe,iBAAiB,aAAa,GAAI,mBAAmB,CAAC,OAAO,IAAI,CAAC,CAAE;AAAA,MACvG;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,QAAQ,CAAC,UAAU,eAAe,mBAAmB,aAAa;AAAA,MACpE;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,CAAC;AAAA,EACtB;AAEA,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,WAAgC;AACrC,UAAI,CAAC,QAAS;AACd,YAAM,eAAe,OAAO,MAAM,KAAK;AACvC,UAAI,CAAC,aAAa,QAAQ;AACxB,cAAM,oBAAoB,sBAAsB,EAAE,OAAO,qBAAqB,CAAC;AAAA,MACjF;AACA,YAAM,UAAmC;AAAA,QACvC,OAAO;AAAA,QACP,YAAY,QAAQ;AAAA,QACpB,iBAAiB,QAAQ;AAAA,QACzB,eAAe,OAAO;AAAA,MACxB;AACA,UAAI,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,OAAO,WAAW,GAAG;AACjF,gBAAQ,cAAc,OAAO;AAAA,MAC/B;AACA,UAAI,cAAe,SAAQ,cAAc;AACzC,UAAI,OAAO,UAAW,SAAQ,aAAa,CAAC,OAAO,SAAS;AAC5D,UAAI,OAAO,OAAQ,SAAQ,SAAS,OAAO;AAC3C,UAAI,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,OAAO,WAAW,GAAG;AACjF,gBAAQ,cAAc,OAAO;AAAA,MAC/B;AACA,UAAI,OAAO,mBAAmB,OAAO,gBAAgB,KAAK,EAAE,QAAQ;AAClE,gBAAQ,kBAAkB,OAAO;AAAA,MACnC;AACA,UAAI,OAAO,eAAe,OAAO,YAAY,KAAK,EAAE,QAAQ;AAC1D,gBAAQ,cAAc,OAAO;AAAA,MAC/B;AACA,YAAM,YAAY,MAChB,WAAW,mBAAmB,SAAS;AAAA,QACrC,cAAc,sBAAsB,GAAG,gCAAgC,wBAAwB;AAAA,MACjG,CAAC;AACH,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF,CAAC;AACD;AAAA,QACE;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA,EAAE,OAAO,QAAQ,mBAAmB;AAAA,QACtC;AAAA,QACA;AAAA,MACF;AACA,gBAAU;AACV,cAAQ;AAAA,IACV;AAAA,IACA,CAAC,SAAS,eAAe,SAAS,WAAW,mBAAmB,aAAa,GAAG,oBAAoB;AAAA,EACtG;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAc,CAAC,SAAS;AACtB,YAAI,CAAC,KAAM,SAAQ;AAAA,MACrB;AAAA,MAEA,+BAAC,iBACC;AAAA,6BAAC,gBACC;AAAA,8BAAC,eACE,gCAAsB,GAAG,0CAA0C,YAAY,GAClF;AAAA,UACA,oBAAC,qBACE;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,EAAE,UAAU,QAAQ,cAAc,OAAO,QAAQ,mBAAmB;AAAA,UACtE,GACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YAEC,UAAQ;AAAA,YACR;AAAA,YACA;AAAA,YAIA,mBAAmB,EAAE,UAAU,mCAAmC;AAAA,YAClE;AAAA,YACA,QAAQ;AAAA,YACR,aAAa,sBAAsB,GAAG,2CAA2C,UAAU;AAAA,YAC3F,UAAU;AAAA;AAAA,UAXL,GAAG,QAAQ,eAAe,IAAI,eAAe;AAAA,QAYpD;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAKA,kBAAwC;AAAA,EACtC,IAAI;AAAA,EACJ,WAAW;AAAA,EACX,UAAU;AAAA,IACR,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AACF,CAAC;AAED,IAAO,0BAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { ComboboxInput } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { registerComponent } from '@open-mercato/shared/modules/widgets/component-registry'\n\n// Deal status values written by the kanban flow. These intentionally do NOT include 'closed'\n// because the rest of the app only persists 'lost' for lost deals (see StatusFilterPopover\n// notes). 'in_progress' is kept for backwards compatibility with quick-deals created from\n// the previous version of this dialog. Deals written before 0.7.1 carry the misspelled\n// 'loose'; readers still match it through `lib/dealStatus.ts`, but no writer produces it.\nconst STATUS_OPTIONS = ['open', 'in_progress', 'win', 'lost'] as const\n\n/**\n * Tenant currency option. The page resolves these from the currencies module (see\n * `useCurrencyDictionary`) and passes them in; we no longer hardcode the 4-currency\n * list that previously locked tenants on CZK/SEK/HUF/etc. out of quick-add.\n */\nexport type QuickDealCurrencyOption = {\n code: string\n label?: string\n isBase?: boolean\n}\n\nconst FALLBACK_CURRENCIES: QuickDealCurrencyOption[] = [\n { code: 'USD', isBase: true },\n { code: 'EUR' },\n { code: 'GBP' },\n { code: 'PLN' },\n]\n\nexport type QuickDealContext = {\n pipelineId: string\n pipelineName: string\n pipelineStageId: string\n pipelineStageLabel: string\n}\n\nexport type QuickDealCompanyOption = {\n id: string\n label: string\n}\n\n/**\n * Registered component id for the kanban quick-add dialog. Downstream apps can\n * target it from `widgets/components.ts` to replace/wrap the dialog or to\n * transform its props \u2014 e.g. `defaultProbability: null` so quick-create stops\n * seeding a probability that overrides pipeline automation (#4329).\n */\nexport const QUICK_DEAL_DIALOG_COMPONENT_ID = 'dialog:customers.deals.quickDeal'\n\n/** Probability seeded into the quick-add form when the host passes no override. */\nexport const DEFAULT_QUICK_DEAL_PROBABILITY = 25\n\nexport type QuickDealDialogProps = {\n open: boolean\n context: QuickDealContext | null\n onClose: () => void\n onCreated: () => void\n currentUserId?: string\n currentUserLabel?: string\n companies?: QuickDealCompanyOption[]\n /**\n * Probability pre-filled in the collapsed \"More details\" group. `null` leaves\n * the field empty, so quick-create sends no `probability` at all and whatever\n * the pipeline/automation derives for the target stage stands. Defaults to\n * `DEFAULT_QUICK_DEAL_PROBABILITY` to preserve the historic behavior.\n */\n defaultProbability?: number | null\n /**\n * Tenant currency list. When omitted (e.g. dictionary not yet loaded), we render a\n * conservative fallback so the dialog still works end-to-end. The default selection is\n * always the entry with `isBase: true`, falling back to the first item.\n */\n currencies?: QuickDealCurrencyOption[]\n}\n\ntype QuickDealFormValues = {\n title: string\n valueAmount: number | null\n valueCurrency: string\n companyId: string\n status: (typeof STATUS_OPTIONS)[number]\n probability: number | null\n expectedCloseAt: string\n description: string\n}\n\nconst QUICK_DEAL_CONTEXT_ID = 'customers-deals-kanban:quick-deal'\n\nexport function QuickDealDialog({\n open,\n context,\n onClose,\n onCreated,\n currentUserId,\n currentUserLabel,\n companies = [],\n currencies,\n defaultProbability = DEFAULT_QUICK_DEAL_PROBABILITY,\n}: QuickDealDialogProps): React.ReactElement | null {\n const t = useT()\n // Re-mount CrudForm whenever the dialog opens so cleared state is consistently fresh.\n // We also key on `context?.pipelineStageId` so reopening from a different stage doesn't\n // reuse stale field values (the page passes a fresh stage in `context` each time).\n const [formInstanceKey, setFormInstanceKey] = React.useState(0)\n React.useEffect(() => {\n if (open) setFormInstanceKey((current) => current + 1)\n }, [open])\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: QUICK_DEAL_CONTEXT_ID,\n blockedMessage: translateWithFallback(t, 'ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const titleRequiredMessage = translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.title.required',\n 'Title is required.',\n )\n\n // Default currency selection: tenant base currency, else first available, else 'USD' as\n // a last-resort literal that satisfies the form validator (which now accepts any 3-char\n // code rather than a hardcoded enum).\n const resolvedCurrencies = React.useMemo(\n () => (currencies && currencies.length > 0 ? currencies : FALLBACK_CURRENCIES),\n [currencies],\n )\n const defaultCurrencyCode = React.useMemo(() => {\n const base = resolvedCurrencies.find((currency) => currency.isBase)\n return base?.code ?? resolvedCurrencies[0]?.code ?? 'USD'\n }, [resolvedCurrencies])\n\n const formSchema = React.useMemo(\n () =>\n z.object({\n title: z.string().trim().min(1, titleRequiredMessage),\n valueAmount: z.number().min(0).nullable().optional(),\n // The set of valid currencies is tenant-defined and resolved at runtime; we accept\n // any non-empty string here and let the server (which knows the canonical list)\n // reject anything bogus.\n valueCurrency: z.string().min(1),\n companyId: z.string().optional(),\n status: z.enum(STATUS_OPTIONS),\n probability: z.number().min(0).max(100).nullable().optional(),\n expectedCloseAt: z.string().optional(),\n description: z.string().optional(),\n }),\n // Cast widens to QuickDealFormValues so CrudForm's TValues generic stays exact.\n [titleRequiredMessage],\n ) as unknown as z.ZodType<QuickDealFormValues>\n\n const initialValues = React.useMemo<Partial<QuickDealFormValues>>(\n () => ({\n title: '',\n valueAmount: null,\n valueCurrency: defaultCurrencyCode,\n companyId: '',\n status: 'open',\n probability: defaultProbability,\n expectedCloseAt: '',\n description: '',\n }),\n [defaultCurrencyCode, defaultProbability],\n )\n\n const fields = React.useMemo<CrudField[]>(\n () => {\n const list: CrudField[] = [\n {\n // CrudForm auto-focuses the first field of the first group on mount; we don't\n // need (and CrudField doesn't accept) an explicit `autoFocus` prop here.\n id: 'title',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.title.label', 'Deal title'),\n type: 'text',\n required: true,\n placeholder: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.title.placeholder',\n 'e.g. Q3 Expansion \u2014 Lighting Package',\n ),\n },\n {\n id: 'valueAmount',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.value', 'Value'),\n type: 'number',\n layout: 'half',\n placeholder: '0',\n },\n {\n id: 'valueCurrency',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.currency', 'Currency'),\n type: 'select',\n layout: 'half',\n options: resolvedCurrencies.map((currency) => ({\n value: currency.code,\n label: currency.label && currency.label !== currency.code\n ? `${currency.code} \u2014 ${currency.label}`\n : currency.code,\n })),\n },\n {\n // Company is a typeahead (ComboboxInput) rather than a plain <select>: tenants\n // with hundreds of companies get an unusable dropdown otherwise. The `seedOptions`\n // carry the most-recent companies the page already loaded; an async loader could\n // be added later to hit the companies search endpoint for full coverage.\n id: 'companyId',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.company', 'Company'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <ComboboxInput\n value={typeof value === 'string' ? value : ''}\n onChange={(next) => setValue(next)}\n seedOptions={companies.map((company) => ({ value: company.id, label: company.label }))}\n placeholder={translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.companyPh',\n 'Pick a company or add new\u2026',\n )}\n allowCustomValues={false}\n />\n ),\n },\n ]\n // Owner is read-only display of the current user (mirrors original UX). Hidden when\n // we don't know the user \u2014 avoids confusing empty avatar cell.\n if (currentUserLabel) {\n list.push({\n id: 'owner',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.owner', 'Owner'),\n type: 'custom',\n readOnly: true,\n component: () => (\n <div className=\"flex h-9 items-center gap-2 rounded-md border border-input bg-card px-3 text-sm\">\n <Avatar label={currentUserLabel} size=\"sm\" />\n <span>{currentUserLabel}</span>\n </div>\n ),\n })\n }\n // Progressive disclosure: status + probability + close date + description live in\n // a separate \"More details\" group with `defaultExpanded: false` (configured via\n // collapsibleGroups on the host CrudForm).\n list.push(\n {\n id: 'status',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.status', 'Status'),\n type: 'select',\n // Storage value is preserved (`lost` etc.), only the displayed label is\n // translated, so we never write a localised string back to the DB.\n options: STATUS_OPTIONS.map((statusValue) => ({\n value: statusValue,\n label: translateWithFallback(\n t,\n `customers.deals.kanban.quickDeal.status.${statusValue}`,\n statusValue,\n ),\n })),\n },\n {\n id: 'probability',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.probability', 'Probability'),\n type: 'number',\n layout: 'half',\n placeholder: '25',\n },\n {\n id: 'expectedCloseAt',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.expectedClose', 'Expected close'),\n type: 'date',\n layout: 'half',\n },\n {\n id: 'description',\n label: translateWithFallback(t, 'customers.deals.kanban.quickDeal.description', 'Description'),\n type: 'textarea',\n rows: 3,\n placeholder: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.description.placeholder',\n 'Short context, decision makers or next steps. Markdown supported.',\n ),\n },\n )\n return list\n },\n [companies, currentUserLabel, resolvedCurrencies, t],\n )\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'basic',\n // No title \u2014 keep the basic section flush with the dialog header.\n fields: ['title', 'valueAmount', 'valueCurrency', 'companyId', ...(currentUserLabel ? ['owner'] : [])],\n },\n {\n id: 'more',\n title: translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.more',\n 'More details (probability, close date, description)',\n ),\n fields: ['status', 'probability', 'expectedCloseAt', 'description'],\n },\n ],\n [currentUserLabel, t],\n )\n\n const handleSubmit = React.useCallback(\n async (values: QuickDealFormValues) => {\n if (!context) return\n const trimmedTitle = values.title.trim()\n if (!trimmedTitle.length) {\n throw createCrudFormError(titleRequiredMessage, { title: titleRequiredMessage })\n }\n const payload: Record<string, unknown> = {\n title: trimmedTitle,\n pipelineId: context.pipelineId,\n pipelineStageId: context.pipelineStageId,\n valueCurrency: values.valueCurrency,\n }\n if (typeof values.valueAmount === 'number' && Number.isFinite(values.valueAmount)) {\n payload.valueAmount = values.valueAmount\n }\n if (currentUserId) payload.ownerUserId = currentUserId\n if (values.companyId) payload.companyIds = [values.companyId]\n if (values.status) payload.status = values.status\n if (typeof values.probability === 'number' && Number.isFinite(values.probability)) {\n payload.probability = values.probability\n }\n if (values.expectedCloseAt && values.expectedCloseAt.trim().length) {\n payload.expectedCloseAt = values.expectedCloseAt\n }\n if (values.description && values.description.trim().length) {\n payload.description = values.description\n }\n const operation = () =>\n createCrud('customers/deals', payload, {\n errorMessage: translateWithFallback(t, 'customers.deals.create.error', 'Failed to create deal.'),\n })\n await runMutation({\n operation,\n context: {\n formId: QUICK_DEAL_CONTEXT_ID,\n resourceKind: 'customers.deal',\n retryLastMutation,\n },\n })\n flash(\n translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.success',\n 'Deal added to {stage}.',\n { stage: context.pipelineStageLabel },\n ),\n 'success',\n )\n onCreated()\n onClose()\n },\n [context, currentUserId, onClose, onCreated, retryLastMutation, runMutation, t, titleRequiredMessage],\n )\n\n if (!context) return null\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) onClose()\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {translateWithFallback(t, 'customers.deals.kanban.quickDeal.title', 'Quick deal')}\n </DialogTitle>\n <DialogDescription>\n {translateWithFallback(\n t,\n 'customers.deals.kanban.quickDeal.context',\n 'Pipeline: {pipeline} \u00B7 Stage: {stage}',\n { pipeline: context.pipelineName, stage: context.pipelineStageLabel },\n )}\n </DialogDescription>\n </DialogHeader>\n\n <CrudForm<QuickDealFormValues>\n key={`${context.pipelineStageId}:${formInstanceKey}`}\n embedded\n fields={fields}\n groups={groups}\n // The \"More details\" group starts collapsed; users can expand to set\n // status / probability / close date / description. Mirrors the previous\n // \"+ More details\" toggle.\n collapsibleGroups={{ pageType: 'customers.deals.kanban.quickDeal' }}\n initialValues={initialValues}\n schema={formSchema}\n submitLabel={translateWithFallback(t, 'customers.deals.kanban.quickDeal.submit', 'Add deal')}\n onSubmit={handleSubmit}\n />\n </DialogContent>\n </Dialog>\n )\n}\n\n// Register so downstream apps can reach the dialog from `widgets/components.ts`\n// (replace / wrap / propsTransform) instead of forking the whole kanban page\n// just to change a default (#4329).\nregisterComponent<QuickDealDialogProps>({\n id: QUICK_DEAL_DIALOG_COMPONENT_ID,\n component: QuickDealDialog,\n metadata: {\n module: 'customers',\n description: 'Kanban quick-add deal dialog (pipeline board \"+ deal\").',\n },\n})\n\nexport default QuickDealDialog\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -35,7 +35,7 @@ const FALLBACK_STATUS_OPTIONS = [
35
35
  dotClass: "bg-status-success-icon"
36
36
  },
37
37
  {
38
- value: "loose",
38
+ value: "lost",
39
39
  labelKey: "customers.deals.kanban.filter.status.lost",
40
40
  labelFallback: "Lost",
41
41
  dotClass: "bg-status-error-icon"