@open-mercato/core 0.6.6-develop.6390.1.210bbbc703 → 0.6.6-develop.6392.1.ed38e087fe

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.
@@ -211,11 +211,11 @@ function DealsMapView({ search }) {
211
211
  "deals",
212
212
  `scope:${scopeVersion}`,
213
213
  `search:${debouncedSearch}`,
214
- `status:${statusFilters.slice().sort().join(",")}`,
214
+ `status:${statusFilters.slice().sort((a, b) => a.localeCompare(b)).join(",")}`,
215
215
  `pipeline:${selectedPipelineId ?? ""}`,
216
- `owners:${ownerFilters.slice().sort().join(",")}`,
217
- `people:${peopleFilters.slice().sort().join(",")}`,
218
- `companies:${companyFilters.slice().sort().join(",")}`,
216
+ `owners:${ownerFilters.slice().sort((a, b) => a.localeCompare(b)).join(",")}`,
217
+ `people:${peopleFilters.slice().sort((a, b) => a.localeCompare(b)).join(",")}`,
218
+ `companies:${companyFilters.slice().sort((a, b) => a.localeCompare(b)).join(",")}`,
219
219
  `close:${closeDateFilter.from ?? ""}-${closeDateFilter.to ?? ""}`,
220
220
  `sort:${apiSort.sortField}:${apiSort.sortDir}`
221
221
  ],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/backend/customers/deals/map/components/DealsMapView.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport {\n apiCall,\n readApiResultOrThrow,\n withScopedApiRequestHeaders,\n} from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { FilterBarRow, type KanbanFilterChip } from '../../pipeline/components/FilterBarRow'\nimport { StatusFilterPopover } from '../../pipeline/components/StatusFilterPopover'\nimport {\n PipelineFilterPopover,\n type PipelineFilterOption,\n} from '../../pipeline/components/PipelineFilterPopover'\nimport {\n EntityFilterPopover,\n type EntityFilterOption,\n} from '../../pipeline/components/EntityFilterPopover'\nimport {\n CloseDateFilterPopover,\n type CloseDateRange,\n} from '../../pipeline/components/CloseDateFilterPopover'\nimport { SortByPopover, type SortOption } from '../../pipeline/components/SortByPopover'\nimport { fetchAssignableStaffMembers } from '../../../../../components/detail/assignableStaff'\nimport { DealsLocationPanel } from './DealsLocationPanel'\nimport {\n DealsMapCanvas,\n type DealsMapCanvasDeal,\n type DealsMapLegendStage,\n type DealsMapPreview,\n type MapCenter,\n} from './DealsMapCanvas'\n\nconst DEFAULT_SORT: SortOption = 'updated_desc'\nconst PAGE_SIZE = 100\nconst MAX_DEALS = 500\nconst FALLBACK_TONES: FilterOptionTone[] = ['success', 'warning', 'error', 'info', 'neutral', 'brand']\nconst KNOWN_STAGE_TONES: ReadonlySet<string> = new Set([\n 'success',\n 'warning',\n 'info',\n 'error',\n 'neutral',\n 'brand',\n 'pink',\n])\nconst SUPPRESS_AUTH_REDIRECT_HEADERS = {\n 'x-om-forbidden-redirect': '0',\n 'x-om-unauthorized-redirect': '0',\n} as const\n// The map has no quick-filter chips (filters live in the leading popovers), but FilterBarRow\n// requires the props \u2014 keep stable module-level references instead of per-render allocations.\nconst NO_FILTER_CHIPS: KanbanFilterChip[] = []\nconst noopChipClick = (_chipId: KanbanFilterChip['id']) => {}\n\ntype PipelineRecord = { id: string; name: string; isDefault: boolean }\n\ntype PipelineStageRecord = {\n id: string\n pipelineId: string\n label: string\n order: number\n color?: string | null\n}\n\nexport type StageMeta = { label: string; tone: FilterOptionTone }\n\ntype DealMapApiLocation = {\n latitude?: number | string | null\n longitude?: number | string | null\n city?: string | null\n region?: string | null\n country?: string | null\n source?: string | null\n}\n\ntype DealMapApiItem = {\n id?: string\n title?: string | null\n status?: string | null\n pipelineId?: string | null\n pipelineStageId?: string | null\n pipelineStage?: string | null\n valueAmount?: number | string | null\n valueCurrency?: string | null\n probability?: number | string | null\n expectedCloseAt?: string | null\n ownerUserId?: string | null\n updatedAt?: string | null\n companies?: Array<{ id?: string; label?: string } | null> | null\n people?: Array<{ id?: string; label?: string } | null> | null\n location?: DealMapApiLocation | null\n}\n\ntype DealsMapApiResponse = {\n items?: DealMapApiItem[]\n total?: number\n page?: number\n pageSize?: number\n totalPages?: number\n}\n\nexport type MapDealLocation = {\n latitude: number\n longitude: number\n city: string | null\n region: string | null\n country: string | null\n}\n\nexport type MapDeal = {\n id: string\n title: string\n status: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: number | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n ownerUserId: string | null\n companyLabel: string | null\n location: MapDealLocation | null\n}\n\ntype DealsMapQueryResult = {\n deals: MapDeal[]\n total: number\n truncated: boolean\n}\n\nfunction normalizeNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction normalizeText(value: unknown): string | null {\n return typeof value === 'string' && value.trim().length ? value.trim() : null\n}\n\nfunction normalizeLocation(location: DealMapApiLocation | null | undefined): MapDealLocation | null {\n if (!location) return null\n const latitude = normalizeNumber(location.latitude)\n const longitude = normalizeNumber(location.longitude)\n if (latitude === null || longitude === null) return null\n return {\n latitude,\n longitude,\n city: normalizeText(location.city),\n region: normalizeText(location.region),\n country: normalizeText(location.country),\n }\n}\n\nfunction mapApiItem(item: DealMapApiItem, fallbackTitle: string): MapDeal | null {\n const id = normalizeText(item.id)\n if (!id) return null\n const firstCompany = Array.isArray(item.companies)\n ? item.companies.find((entry) => entry && normalizeText(entry.label))\n : null\n return {\n id,\n title: normalizeText(item.title) ?? fallbackTitle,\n status: normalizeText(item.status),\n pipelineId: normalizeText(item.pipelineId),\n pipelineStageId: normalizeText(item.pipelineStageId),\n valueAmount: normalizeNumber(item.valueAmount),\n valueCurrency: normalizeText(item.valueCurrency)?.toUpperCase() ?? null,\n probability: normalizeNumber(item.probability),\n expectedCloseAt: normalizeText(item.expectedCloseAt),\n ownerUserId: normalizeText(item.ownerUserId),\n companyLabel: firstCompany ? normalizeText(firstCompany.label) : null,\n location: normalizeLocation(item.location),\n }\n}\n\nfunction mapSortOptionToApi(option: SortOption): { sortField: string; sortDir: 'asc' | 'desc' } | null {\n switch (option) {\n case 'updated_desc':\n return { sortField: 'updatedAt', sortDir: 'desc' }\n case 'updated_asc':\n return { sortField: 'updatedAt', sortDir: 'asc' }\n case 'created_desc':\n return { sortField: 'createdAt', sortDir: 'desc' }\n case 'value_desc':\n return { sortField: 'value', sortDir: 'desc' }\n case 'value_asc':\n return { sortField: 'value', sortDir: 'asc' }\n case 'probability_desc':\n return { sortField: 'probability', sortDir: 'desc' }\n case 'close_asc':\n return { sortField: 'expectedCloseAt', sortDir: 'asc' }\n case 'owner_asc':\n default:\n return null\n }\n}\n\nfunction buildStageMetaById(stages: PipelineStageRecord[]): Map<string, StageMeta> {\n const byPipeline = new Map<string, PipelineStageRecord[]>()\n for (const stage of stages) {\n const key = stage.pipelineId ?? ''\n const bucket = byPipeline.get(key) ?? []\n bucket.push(stage)\n byPipeline.set(key, bucket)\n }\n const meta = new Map<string, StageMeta>()\n for (const bucket of byPipeline.values()) {\n const sorted = bucket.slice().sort((a, b) => a.order - b.order)\n sorted.forEach((stage, index) => {\n const tone =\n stage.color && KNOWN_STAGE_TONES.has(stage.color)\n ? (stage.color as FilterOptionTone)\n : FALLBACK_TONES[index % FALLBACK_TONES.length]\n meta.set(stage.id, { label: stage.label, tone })\n })\n }\n return meta\n}\n\ntype DealsMapViewProps = {\n search: string\n}\n\nexport function DealsMapView({ search }: DealsMapViewProps): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [statusFilters, setStatusFilters] = React.useState<string[]>([])\n const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)\n const [ownerFilters, setOwnerFilters] = React.useState<string[]>([])\n const [peopleFilters, setPeopleFilters] = React.useState<string[]>([])\n const [companyFilters, setCompanyFilters] = React.useState<string[]>([])\n const [closeDateFilter, setCloseDateFilter] = React.useState<CloseDateRange>({ from: null, to: null })\n const [sortBy, setSortBy] = React.useState<SortOption>(DEFAULT_SORT)\n const [ownerLabels, setOwnerLabels] = React.useState<Record<string, string>>({})\n const [peopleLabels, setPeopleLabels] = React.useState<Record<string, string>>({})\n const [companyLabels, setCompanyLabels] = React.useState<Record<string, string>>({})\n const [selectedDealId, setSelectedDealId] = React.useState<string | null>(null)\n const [mapCenter, setMapCenter] = React.useState<MapCenter | null>(null)\n\n const [debouncedSearch, setDebouncedSearch] = React.useState(search)\n React.useEffect(() => {\n const handle = window.setTimeout(() => setDebouncedSearch(search.trim()), 300)\n return () => window.clearTimeout(handle)\n }, [search])\n\n const fallbackTitle = translateWithFallback(t, 'customers.deals.pipeline.untitled', 'Untitled deal')\n const loadErrorLabel = translateWithFallback(\n t,\n 'customers.deals.map.loadError',\n 'Failed to load deals for the map.',\n )\n\n const apiSort = React.useMemo(() => {\n const mapped = mapSortOptionToApi(sortBy)\n return mapped ?? { sortField: 'updatedAt' as const, sortDir: 'desc' as const }\n }, [sortBy])\n\n const pipelinesQuery = useQuery<PipelineRecord[]>({\n queryKey: ['customers', 'deals', 'map', 'pipelines', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const call = await apiCall<{ items?: PipelineRecord[] }>('/api/customers/pipelines', {\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n return Array.isArray(call.result?.items) ? call.result.items : []\n },\n })\n\n const stagesQuery = useQuery<PipelineStageRecord[]>({\n queryKey: ['customers', 'deals', 'map', 'stages', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const call = await apiCall<{ items?: PipelineStageRecord[] }>('/api/customers/pipeline-stages', {\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n return Array.isArray(call.result?.items) ? call.result.items : []\n },\n })\n\n const staffQuery = useQuery<Map<string, string>>({\n queryKey: ['customers', 'deals', 'map', 'staff', `scope:${scopeVersion}`],\n staleTime: 300_000,\n queryFn: async () => {\n try {\n const members = await withScopedApiRequestHeaders(\n { ...SUPPRESS_AUTH_REDIRECT_HEADERS },\n () => fetchAssignableStaffMembers('', { pageSize: 100 }),\n )\n const names = new Map<string, string>()\n for (const member of members) {\n if (member.userId && member.displayName) names.set(member.userId, member.displayName)\n }\n return names\n } catch {\n return new Map<string, string>()\n }\n },\n })\n\n const ownerNamesById = staffQuery.data ?? null\n\n const dealsQuery = useQuery<DealsMapQueryResult>({\n queryKey: [\n 'customers',\n 'deals',\n 'map',\n 'deals',\n `scope:${scopeVersion}`,\n `search:${debouncedSearch}`,\n `status:${statusFilters.slice().sort().join(',')}`,\n `pipeline:${selectedPipelineId ?? ''}`,\n `owners:${ownerFilters.slice().sort().join(',')}`,\n `people:${peopleFilters.slice().sort().join(',')}`,\n `companies:${companyFilters.slice().sort().join(',')}`,\n `close:${closeDateFilter.from ?? ''}-${closeDateFilter.to ?? ''}`,\n `sort:${apiSort.sortField}:${apiSort.sortDir}`,\n ],\n staleTime: 30_000,\n queryFn: async () => {\n const buildParams = (page: number) => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n params.set('sortField', apiSort.sortField)\n params.set('sortDir', apiSort.sortDir)\n if (debouncedSearch.length) params.set('search', debouncedSearch)\n for (const status of statusFilters) params.append('status', status)\n if (selectedPipelineId) params.set('pipelineId', selectedPipelineId)\n for (const ownerId of ownerFilters) params.append('ownerUserId', ownerId)\n for (const personId of peopleFilters) params.append('personId', personId)\n for (const companyId of companyFilters) params.append('companyId', companyId)\n if (closeDateFilter.from) params.set('expectedCloseAtFrom', closeDateFilter.from)\n if (closeDateFilter.to) params.set('expectedCloseAtTo', closeDateFilter.to)\n return params\n }\n const fetchPage = (page: number) =>\n readApiResultOrThrow<DealsMapApiResponse>(\n `/api/customers/deals/map?${buildParams(page).toString()}`,\n undefined,\n { errorMessage: loadErrorLabel },\n )\n\n const collected: MapDeal[] = []\n const collectFrom = (payload: DealsMapApiResponse | null | undefined) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n for (const item of items) {\n const mapped = mapApiItem(item, fallbackTitle)\n if (mapped) collected.push(mapped)\n }\n }\n\n // Fetch the first page to learn totalPages, then pull the remaining pages concurrently \u2014\n // the pages are independent, so awaiting them sequentially only stacked round-trip latency.\n const firstPage = await fetchPage(1)\n collectFrom(firstPage)\n const total = typeof firstPage?.total === 'number' ? firstPage.total : collected.length\n const reportedTotalPages = typeof firstPage?.totalPages === 'number' ? firstPage.totalPages : 1\n // Bound the fan-out: the client renders at most MAX_DEALS pins regardless of the located total.\n const maxPages = Math.max(1, Math.ceil(MAX_DEALS / PAGE_SIZE))\n const lastPage = Math.min(reportedTotalPages, maxPages)\n if (lastPage > 1) {\n const rest = await Promise.all(\n Array.from({ length: lastPage - 1 }, (_unused, index) => fetchPage(index + 2)),\n )\n for (const payload of rest) collectFrom(payload)\n }\n\n const deals = collected.slice(0, MAX_DEALS)\n return { deals, total, truncated: total > deals.length }\n },\n })\n\n const stageMetaById = React.useMemo(\n () => buildStageMetaById(stagesQuery.data ?? []),\n [stagesQuery.data],\n )\n\n const deals = React.useMemo(() => {\n const fetched = dealsQuery.data?.deals ?? []\n if (sortBy !== 'owner_asc' || !ownerNamesById) return fetched\n return fetched.slice().sort((a, b) => {\n const aLabel = (a.ownerUserId ? ownerNamesById.get(a.ownerUserId) : null) ?? a.ownerUserId ?? ''\n const bLabel = (b.ownerUserId ? ownerNamesById.get(b.ownerUserId) : null) ?? b.ownerUserId ?? ''\n return aLabel.localeCompare(bLabel)\n })\n }, [dealsQuery.data, sortBy, ownerNamesById])\n\n const locatedDeals = React.useMemo(\n () => deals.filter((deal): deal is MapDeal & { location: MapDealLocation } => deal.location !== null),\n [deals],\n )\n\n const canvasDeals = React.useMemo<DealsMapCanvasDeal[]>(\n () =>\n locatedDeals.map((deal) => ({\n id: deal.id,\n latitude: deal.location.latitude,\n longitude: deal.location.longitude,\n tone: deal.pipelineStageId ? stageMetaById.get(deal.pipelineStageId)?.tone ?? null : null,\n })),\n [locatedDeals, stageMetaById],\n )\n\n const legendStages = React.useMemo<DealsMapLegendStage[]>(() => {\n if (stageMetaById.size === 0) return []\n const presentStageIds = new Set<string>()\n for (const deal of locatedDeals) {\n if (deal.pipelineStageId) presentStageIds.add(deal.pipelineStageId)\n }\n const stages: DealsMapLegendStage[] = []\n for (const stage of stagesQuery.data ?? []) {\n if (!presentStageIds.has(stage.id)) continue\n const meta = stageMetaById.get(stage.id)\n if (!meta) continue\n stages.push({ id: stage.id, label: meta.label, tone: meta.tone })\n }\n return stages\n }, [locatedDeals, stageMetaById, stagesQuery.data])\n\n const selectedDeal = React.useMemo(\n () => (selectedDealId ? deals.find((deal) => deal.id === selectedDealId) ?? null : null),\n [deals, selectedDealId],\n )\n\n const preview = React.useMemo<DealsMapPreview | null>(() => {\n if (!selectedDeal) return null\n const stageMeta = selectedDeal.pipelineStageId\n ? stageMetaById.get(selectedDeal.pipelineStageId) ?? null\n : null\n const locationLine = selectedDeal.location\n ? [selectedDeal.location.city, selectedDeal.location.region].filter(Boolean).join(', ') ||\n selectedDeal.location.country\n : null\n return {\n id: selectedDeal.id,\n title: selectedDeal.title,\n companyLabel: selectedDeal.companyLabel,\n locationLine: locationLine || null,\n valueAmount: selectedDeal.valueAmount,\n valueCurrency: selectedDeal.valueCurrency,\n probability: selectedDeal.probability,\n expectedCloseAt: selectedDeal.expectedCloseAt,\n stageLabel: stageMeta?.label ?? null,\n stageTone: stageMeta?.tone ?? null,\n ownerName:\n selectedDeal.ownerUserId && ownerNamesById\n ? ownerNamesById.get(selectedDeal.ownerUserId) ?? null\n : null,\n }\n }, [selectedDeal, stageMetaById, ownerNamesById])\n\n const handleSelect = React.useCallback((dealId: string | null) => {\n setSelectedDealId(dealId)\n }, [])\n\n const handleCenterChange = React.useCallback((center: MapCenter) => {\n setMapCenter(center)\n }, [])\n\n const pipelineFilterOptions = React.useMemo<PipelineFilterOption[]>(\n () => (pipelinesQuery.data ?? []).map((pipeline) => ({ id: pipeline.id, name: pipeline.name })),\n [pipelinesQuery.data],\n )\n\n const loadOwnerOptions = React.useCallback(\n async (query: string, _signal: AbortSignal): Promise<EntityFilterOption[]> => {\n try {\n const members = await withScopedApiRequestHeaders(\n { ...SUPPRESS_AUTH_REDIRECT_HEADERS },\n () => fetchAssignableStaffMembers(query ?? '', { pageSize: 100 }),\n )\n const options: EntityFilterOption[] = members\n .filter((member) => !!member.userId && !!member.displayName)\n .map((member) => ({ value: member.userId, label: member.displayName }))\n setOwnerLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n } catch {\n return []\n }\n },\n [],\n )\n\n const loadPeopleOptions = React.useCallback(\n async (query: string, signal: AbortSignal): Promise<EntityFilterOption[]> => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '50')\n if (query) params.set('search', query)\n params.set('sortField', 'displayName')\n params.set('sortDir', 'asc')\n const call = await apiCall<{\n items?: Array<{ id?: string; display_name?: string; first_name?: string; last_name?: string }>\n }>(`/api/customers/people?${params.toString()}`, {\n signal,\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n const items = call.result?.items ?? []\n const options: EntityFilterOption[] = []\n for (const item of items) {\n if (!item.id) continue\n const label =\n item.display_name && item.display_name.trim().length\n ? item.display_name.trim()\n : [item.first_name, item.last_name].filter(Boolean).join(' ').trim() || item.id.slice(0, 8)\n options.push({ value: item.id, label })\n }\n setPeopleLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n },\n [],\n )\n\n const loadCompanyOptions = React.useCallback(\n async (query: string, signal: AbortSignal): Promise<EntityFilterOption[]> => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '50')\n if (query) params.set('search', query)\n params.set('sortField', 'display_name')\n params.set('sortDir', 'asc')\n const call = await apiCall<{ items?: Array<{ id?: string; display_name?: string }> }>(\n `/api/customers/companies?${params.toString()}`,\n { signal, headers: SUPPRESS_AUTH_REDIRECT_HEADERS },\n )\n if (!call.ok) return []\n const items = call.result?.items ?? []\n const options: EntityFilterOption[] = []\n for (const item of items) {\n if (!item.id || !item.display_name) continue\n options.push({ value: item.id, label: item.display_name })\n }\n setCompanyLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n },\n [],\n )\n\n const leadingChipsNode = (\n <>\n <StatusFilterPopover values={statusFilters} onApply={setStatusFilters} />\n <PipelineFilterPopover\n pipelines={pipelineFilterOptions}\n selectedPipelineId={selectedPipelineId}\n onApply={setSelectedPipelineId}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.owner', 'Owner')}\n anyLabel={translateWithFallback(t, 'customers.deals.kanban.filter.all', 'All')}\n values={ownerFilters}\n onApply={setOwnerFilters}\n loadOptions={loadOwnerOptions}\n labelById={ownerLabels}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.people', 'People')}\n values={peopleFilters}\n onApply={setPeopleFilters}\n loadOptions={loadPeopleOptions}\n labelById={peopleLabels}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.companies', 'Companies')}\n values={companyFilters}\n onApply={setCompanyFilters}\n loadOptions={loadCompanyOptions}\n labelById={companyLabels}\n />\n <CloseDateFilterPopover value={closeDateFilter} onApply={setCloseDateFilter} />\n </>\n )\n\n const sortNode = <SortByPopover value={sortBy} onApply={setSortBy} />\n\n return (\n <div className=\"flex flex-col gap-4\">\n <FilterBarRow\n leadingChips={leadingChipsNode}\n chips={NO_FILTER_CHIPS}\n sortNode={sortNode}\n onChipClick={noopChipClick}\n />\n\n {dealsQuery.isLoading ? (\n <LoadingMessage\n label={translateWithFallback(t, 'customers.deals.map.canvas.loading', 'Loading map\u2026')}\n />\n ) : dealsQuery.isError ? (\n <ErrorMessage\n label={dealsQuery.error instanceof Error ? dealsQuery.error.message : loadErrorLabel}\n action={\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void dealsQuery.refetch()}\n >\n {translateWithFallback(t, 'customers.deals.map.retry', 'Retry')}\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-2\">\n {dealsQuery.data?.truncated ? (\n <p className=\"text-sm text-muted-foreground\">\n {translateWithFallback(\n t,\n 'customers.deals.map.truncated',\n 'Showing first {count} of {total} located deals \u2014 refine filters to narrow the map.',\n { count: deals.length, total: dealsQuery.data?.total ?? deals.length },\n )}\n </p>\n ) : null}\n <div className=\"flex min-h-[480px] flex-col gap-4 lg:h-[calc(100vh-360px)] lg:flex-row\">\n <DealsLocationPanel\n deals={deals}\n locatedCount={dealsQuery.data?.total ?? deals.length}\n stageMetaById={stageMetaById}\n mapCenter={mapCenter}\n selectedDealId={selectedDealId}\n onSelect={handleSelect}\n />\n <DealsMapCanvas\n className=\"min-h-[480px] flex-1 overflow-hidden rounded-xl border border-border lg:min-h-0\"\n deals={canvasDeals}\n legendStages={legendStages}\n preview={preview}\n selectedDealId={selectedDealId}\n onSelect={handleSelect}\n onCenterChange={handleCenterChange}\n />\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default DealsMapView\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport {\n apiCall,\n readApiResultOrThrow,\n withScopedApiRequestHeaders,\n} from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { FilterBarRow, type KanbanFilterChip } from '../../pipeline/components/FilterBarRow'\nimport { StatusFilterPopover } from '../../pipeline/components/StatusFilterPopover'\nimport {\n PipelineFilterPopover,\n type PipelineFilterOption,\n} from '../../pipeline/components/PipelineFilterPopover'\nimport {\n EntityFilterPopover,\n type EntityFilterOption,\n} from '../../pipeline/components/EntityFilterPopover'\nimport {\n CloseDateFilterPopover,\n type CloseDateRange,\n} from '../../pipeline/components/CloseDateFilterPopover'\nimport { SortByPopover, type SortOption } from '../../pipeline/components/SortByPopover'\nimport { fetchAssignableStaffMembers } from '../../../../../components/detail/assignableStaff'\nimport { DealsLocationPanel } from './DealsLocationPanel'\nimport {\n DealsMapCanvas,\n type DealsMapCanvasDeal,\n type DealsMapLegendStage,\n type DealsMapPreview,\n type MapCenter,\n} from './DealsMapCanvas'\n\nconst DEFAULT_SORT: SortOption = 'updated_desc'\nconst PAGE_SIZE = 100\nconst MAX_DEALS = 500\nconst FALLBACK_TONES: FilterOptionTone[] = ['success', 'warning', 'error', 'info', 'neutral', 'brand']\nconst KNOWN_STAGE_TONES: ReadonlySet<string> = new Set([\n 'success',\n 'warning',\n 'info',\n 'error',\n 'neutral',\n 'brand',\n 'pink',\n])\nconst SUPPRESS_AUTH_REDIRECT_HEADERS = {\n 'x-om-forbidden-redirect': '0',\n 'x-om-unauthorized-redirect': '0',\n} as const\n// The map has no quick-filter chips (filters live in the leading popovers), but FilterBarRow\n// requires the props \u2014 keep stable module-level references instead of per-render allocations.\nconst NO_FILTER_CHIPS: KanbanFilterChip[] = []\nconst noopChipClick = (_chipId: KanbanFilterChip['id']) => {}\n\ntype PipelineRecord = { id: string; name: string; isDefault: boolean }\n\ntype PipelineStageRecord = {\n id: string\n pipelineId: string\n label: string\n order: number\n color?: string | null\n}\n\nexport type StageMeta = { label: string; tone: FilterOptionTone }\n\ntype DealMapApiLocation = {\n latitude?: number | string | null\n longitude?: number | string | null\n city?: string | null\n region?: string | null\n country?: string | null\n source?: string | null\n}\n\ntype DealMapApiItem = {\n id?: string\n title?: string | null\n status?: string | null\n pipelineId?: string | null\n pipelineStageId?: string | null\n pipelineStage?: string | null\n valueAmount?: number | string | null\n valueCurrency?: string | null\n probability?: number | string | null\n expectedCloseAt?: string | null\n ownerUserId?: string | null\n updatedAt?: string | null\n companies?: Array<{ id?: string; label?: string } | null> | null\n people?: Array<{ id?: string; label?: string } | null> | null\n location?: DealMapApiLocation | null\n}\n\ntype DealsMapApiResponse = {\n items?: DealMapApiItem[]\n total?: number\n page?: number\n pageSize?: number\n totalPages?: number\n}\n\nexport type MapDealLocation = {\n latitude: number\n longitude: number\n city: string | null\n region: string | null\n country: string | null\n}\n\nexport type MapDeal = {\n id: string\n title: string\n status: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: number | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: string | null\n ownerUserId: string | null\n companyLabel: string | null\n location: MapDealLocation | null\n}\n\ntype DealsMapQueryResult = {\n deals: MapDeal[]\n total: number\n truncated: boolean\n}\n\nfunction normalizeNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n return null\n}\n\nfunction normalizeText(value: unknown): string | null {\n return typeof value === 'string' && value.trim().length ? value.trim() : null\n}\n\nfunction normalizeLocation(location: DealMapApiLocation | null | undefined): MapDealLocation | null {\n if (!location) return null\n const latitude = normalizeNumber(location.latitude)\n const longitude = normalizeNumber(location.longitude)\n if (latitude === null || longitude === null) return null\n return {\n latitude,\n longitude,\n city: normalizeText(location.city),\n region: normalizeText(location.region),\n country: normalizeText(location.country),\n }\n}\n\nfunction mapApiItem(item: DealMapApiItem, fallbackTitle: string): MapDeal | null {\n const id = normalizeText(item.id)\n if (!id) return null\n const firstCompany = Array.isArray(item.companies)\n ? item.companies.find((entry) => entry && normalizeText(entry.label))\n : null\n return {\n id,\n title: normalizeText(item.title) ?? fallbackTitle,\n status: normalizeText(item.status),\n pipelineId: normalizeText(item.pipelineId),\n pipelineStageId: normalizeText(item.pipelineStageId),\n valueAmount: normalizeNumber(item.valueAmount),\n valueCurrency: normalizeText(item.valueCurrency)?.toUpperCase() ?? null,\n probability: normalizeNumber(item.probability),\n expectedCloseAt: normalizeText(item.expectedCloseAt),\n ownerUserId: normalizeText(item.ownerUserId),\n companyLabel: firstCompany ? normalizeText(firstCompany.label) : null,\n location: normalizeLocation(item.location),\n }\n}\n\nfunction mapSortOptionToApi(option: SortOption): { sortField: string; sortDir: 'asc' | 'desc' } | null {\n switch (option) {\n case 'updated_desc':\n return { sortField: 'updatedAt', sortDir: 'desc' }\n case 'updated_asc':\n return { sortField: 'updatedAt', sortDir: 'asc' }\n case 'created_desc':\n return { sortField: 'createdAt', sortDir: 'desc' }\n case 'value_desc':\n return { sortField: 'value', sortDir: 'desc' }\n case 'value_asc':\n return { sortField: 'value', sortDir: 'asc' }\n case 'probability_desc':\n return { sortField: 'probability', sortDir: 'desc' }\n case 'close_asc':\n return { sortField: 'expectedCloseAt', sortDir: 'asc' }\n case 'owner_asc':\n default:\n return null\n }\n}\n\nfunction buildStageMetaById(stages: PipelineStageRecord[]): Map<string, StageMeta> {\n const byPipeline = new Map<string, PipelineStageRecord[]>()\n for (const stage of stages) {\n const key = stage.pipelineId ?? ''\n const bucket = byPipeline.get(key) ?? []\n bucket.push(stage)\n byPipeline.set(key, bucket)\n }\n const meta = new Map<string, StageMeta>()\n for (const bucket of byPipeline.values()) {\n const sorted = bucket.slice().sort((a, b) => a.order - b.order)\n sorted.forEach((stage, index) => {\n const tone =\n stage.color && KNOWN_STAGE_TONES.has(stage.color)\n ? (stage.color as FilterOptionTone)\n : FALLBACK_TONES[index % FALLBACK_TONES.length]\n meta.set(stage.id, { label: stage.label, tone })\n })\n }\n return meta\n}\n\ntype DealsMapViewProps = {\n search: string\n}\n\nexport function DealsMapView({ search }: DealsMapViewProps): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n\n const [statusFilters, setStatusFilters] = React.useState<string[]>([])\n const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)\n const [ownerFilters, setOwnerFilters] = React.useState<string[]>([])\n const [peopleFilters, setPeopleFilters] = React.useState<string[]>([])\n const [companyFilters, setCompanyFilters] = React.useState<string[]>([])\n const [closeDateFilter, setCloseDateFilter] = React.useState<CloseDateRange>({ from: null, to: null })\n const [sortBy, setSortBy] = React.useState<SortOption>(DEFAULT_SORT)\n const [ownerLabels, setOwnerLabels] = React.useState<Record<string, string>>({})\n const [peopleLabels, setPeopleLabels] = React.useState<Record<string, string>>({})\n const [companyLabels, setCompanyLabels] = React.useState<Record<string, string>>({})\n const [selectedDealId, setSelectedDealId] = React.useState<string | null>(null)\n const [mapCenter, setMapCenter] = React.useState<MapCenter | null>(null)\n\n const [debouncedSearch, setDebouncedSearch] = React.useState(search)\n React.useEffect(() => {\n const handle = window.setTimeout(() => setDebouncedSearch(search.trim()), 300)\n return () => window.clearTimeout(handle)\n }, [search])\n\n const fallbackTitle = translateWithFallback(t, 'customers.deals.pipeline.untitled', 'Untitled deal')\n const loadErrorLabel = translateWithFallback(\n t,\n 'customers.deals.map.loadError',\n 'Failed to load deals for the map.',\n )\n\n const apiSort = React.useMemo(() => {\n const mapped = mapSortOptionToApi(sortBy)\n return mapped ?? { sortField: 'updatedAt' as const, sortDir: 'desc' as const }\n }, [sortBy])\n\n const pipelinesQuery = useQuery<PipelineRecord[]>({\n queryKey: ['customers', 'deals', 'map', 'pipelines', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const call = await apiCall<{ items?: PipelineRecord[] }>('/api/customers/pipelines', {\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n return Array.isArray(call.result?.items) ? call.result.items : []\n },\n })\n\n const stagesQuery = useQuery<PipelineStageRecord[]>({\n queryKey: ['customers', 'deals', 'map', 'stages', `scope:${scopeVersion}`],\n staleTime: 60_000,\n queryFn: async () => {\n const call = await apiCall<{ items?: PipelineStageRecord[] }>('/api/customers/pipeline-stages', {\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n return Array.isArray(call.result?.items) ? call.result.items : []\n },\n })\n\n const staffQuery = useQuery<Map<string, string>>({\n queryKey: ['customers', 'deals', 'map', 'staff', `scope:${scopeVersion}`],\n staleTime: 300_000,\n queryFn: async () => {\n try {\n const members = await withScopedApiRequestHeaders(\n { ...SUPPRESS_AUTH_REDIRECT_HEADERS },\n () => fetchAssignableStaffMembers('', { pageSize: 100 }),\n )\n const names = new Map<string, string>()\n for (const member of members) {\n if (member.userId && member.displayName) names.set(member.userId, member.displayName)\n }\n return names\n } catch {\n return new Map<string, string>()\n }\n },\n })\n\n const ownerNamesById = staffQuery.data ?? null\n\n const dealsQuery = useQuery<DealsMapQueryResult>({\n queryKey: [\n 'customers',\n 'deals',\n 'map',\n 'deals',\n `scope:${scopeVersion}`,\n `search:${debouncedSearch}`,\n `status:${statusFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,\n `pipeline:${selectedPipelineId ?? ''}`,\n `owners:${ownerFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,\n `people:${peopleFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,\n `companies:${companyFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,\n `close:${closeDateFilter.from ?? ''}-${closeDateFilter.to ?? ''}`,\n `sort:${apiSort.sortField}:${apiSort.sortDir}`,\n ],\n staleTime: 30_000,\n queryFn: async () => {\n const buildParams = (page: number) => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n params.set('sortField', apiSort.sortField)\n params.set('sortDir', apiSort.sortDir)\n if (debouncedSearch.length) params.set('search', debouncedSearch)\n for (const status of statusFilters) params.append('status', status)\n if (selectedPipelineId) params.set('pipelineId', selectedPipelineId)\n for (const ownerId of ownerFilters) params.append('ownerUserId', ownerId)\n for (const personId of peopleFilters) params.append('personId', personId)\n for (const companyId of companyFilters) params.append('companyId', companyId)\n if (closeDateFilter.from) params.set('expectedCloseAtFrom', closeDateFilter.from)\n if (closeDateFilter.to) params.set('expectedCloseAtTo', closeDateFilter.to)\n return params\n }\n const fetchPage = (page: number) =>\n readApiResultOrThrow<DealsMapApiResponse>(\n `/api/customers/deals/map?${buildParams(page).toString()}`,\n undefined,\n { errorMessage: loadErrorLabel },\n )\n\n const collected: MapDeal[] = []\n const collectFrom = (payload: DealsMapApiResponse | null | undefined) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n for (const item of items) {\n const mapped = mapApiItem(item, fallbackTitle)\n if (mapped) collected.push(mapped)\n }\n }\n\n // Fetch the first page to learn totalPages, then pull the remaining pages concurrently \u2014\n // the pages are independent, so awaiting them sequentially only stacked round-trip latency.\n const firstPage = await fetchPage(1)\n collectFrom(firstPage)\n const total = typeof firstPage?.total === 'number' ? firstPage.total : collected.length\n const reportedTotalPages = typeof firstPage?.totalPages === 'number' ? firstPage.totalPages : 1\n // Bound the fan-out: the client renders at most MAX_DEALS pins regardless of the located total.\n const maxPages = Math.max(1, Math.ceil(MAX_DEALS / PAGE_SIZE))\n const lastPage = Math.min(reportedTotalPages, maxPages)\n if (lastPage > 1) {\n const rest = await Promise.all(\n Array.from({ length: lastPage - 1 }, (_unused, index) => fetchPage(index + 2)),\n )\n for (const payload of rest) collectFrom(payload)\n }\n\n const deals = collected.slice(0, MAX_DEALS)\n return { deals, total, truncated: total > deals.length }\n },\n })\n\n const stageMetaById = React.useMemo(\n () => buildStageMetaById(stagesQuery.data ?? []),\n [stagesQuery.data],\n )\n\n const deals = React.useMemo(() => {\n const fetched = dealsQuery.data?.deals ?? []\n if (sortBy !== 'owner_asc' || !ownerNamesById) return fetched\n return fetched.slice().sort((a, b) => {\n const aLabel = (a.ownerUserId ? ownerNamesById.get(a.ownerUserId) : null) ?? a.ownerUserId ?? ''\n const bLabel = (b.ownerUserId ? ownerNamesById.get(b.ownerUserId) : null) ?? b.ownerUserId ?? ''\n return aLabel.localeCompare(bLabel)\n })\n }, [dealsQuery.data, sortBy, ownerNamesById])\n\n const locatedDeals = React.useMemo(\n () => deals.filter((deal): deal is MapDeal & { location: MapDealLocation } => deal.location !== null),\n [deals],\n )\n\n const canvasDeals = React.useMemo<DealsMapCanvasDeal[]>(\n () =>\n locatedDeals.map((deal) => ({\n id: deal.id,\n latitude: deal.location.latitude,\n longitude: deal.location.longitude,\n tone: deal.pipelineStageId ? stageMetaById.get(deal.pipelineStageId)?.tone ?? null : null,\n })),\n [locatedDeals, stageMetaById],\n )\n\n const legendStages = React.useMemo<DealsMapLegendStage[]>(() => {\n if (stageMetaById.size === 0) return []\n const presentStageIds = new Set<string>()\n for (const deal of locatedDeals) {\n if (deal.pipelineStageId) presentStageIds.add(deal.pipelineStageId)\n }\n const stages: DealsMapLegendStage[] = []\n for (const stage of stagesQuery.data ?? []) {\n if (!presentStageIds.has(stage.id)) continue\n const meta = stageMetaById.get(stage.id)\n if (!meta) continue\n stages.push({ id: stage.id, label: meta.label, tone: meta.tone })\n }\n return stages\n }, [locatedDeals, stageMetaById, stagesQuery.data])\n\n const selectedDeal = React.useMemo(\n () => (selectedDealId ? deals.find((deal) => deal.id === selectedDealId) ?? null : null),\n [deals, selectedDealId],\n )\n\n const preview = React.useMemo<DealsMapPreview | null>(() => {\n if (!selectedDeal) return null\n const stageMeta = selectedDeal.pipelineStageId\n ? stageMetaById.get(selectedDeal.pipelineStageId) ?? null\n : null\n const locationLine = selectedDeal.location\n ? [selectedDeal.location.city, selectedDeal.location.region].filter(Boolean).join(', ') ||\n selectedDeal.location.country\n : null\n return {\n id: selectedDeal.id,\n title: selectedDeal.title,\n companyLabel: selectedDeal.companyLabel,\n locationLine: locationLine || null,\n valueAmount: selectedDeal.valueAmount,\n valueCurrency: selectedDeal.valueCurrency,\n probability: selectedDeal.probability,\n expectedCloseAt: selectedDeal.expectedCloseAt,\n stageLabel: stageMeta?.label ?? null,\n stageTone: stageMeta?.tone ?? null,\n ownerName:\n selectedDeal.ownerUserId && ownerNamesById\n ? ownerNamesById.get(selectedDeal.ownerUserId) ?? null\n : null,\n }\n }, [selectedDeal, stageMetaById, ownerNamesById])\n\n const handleSelect = React.useCallback((dealId: string | null) => {\n setSelectedDealId(dealId)\n }, [])\n\n const handleCenterChange = React.useCallback((center: MapCenter) => {\n setMapCenter(center)\n }, [])\n\n const pipelineFilterOptions = React.useMemo<PipelineFilterOption[]>(\n () => (pipelinesQuery.data ?? []).map((pipeline) => ({ id: pipeline.id, name: pipeline.name })),\n [pipelinesQuery.data],\n )\n\n const loadOwnerOptions = React.useCallback(\n async (query: string, _signal: AbortSignal): Promise<EntityFilterOption[]> => {\n try {\n const members = await withScopedApiRequestHeaders(\n { ...SUPPRESS_AUTH_REDIRECT_HEADERS },\n () => fetchAssignableStaffMembers(query ?? '', { pageSize: 100 }),\n )\n const options: EntityFilterOption[] = members\n .filter((member) => !!member.userId && !!member.displayName)\n .map((member) => ({ value: member.userId, label: member.displayName }))\n setOwnerLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n } catch {\n return []\n }\n },\n [],\n )\n\n const loadPeopleOptions = React.useCallback(\n async (query: string, signal: AbortSignal): Promise<EntityFilterOption[]> => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '50')\n if (query) params.set('search', query)\n params.set('sortField', 'displayName')\n params.set('sortDir', 'asc')\n const call = await apiCall<{\n items?: Array<{ id?: string; display_name?: string; first_name?: string; last_name?: string }>\n }>(`/api/customers/people?${params.toString()}`, {\n signal,\n headers: SUPPRESS_AUTH_REDIRECT_HEADERS,\n })\n if (!call.ok) return []\n const items = call.result?.items ?? []\n const options: EntityFilterOption[] = []\n for (const item of items) {\n if (!item.id) continue\n const label =\n item.display_name && item.display_name.trim().length\n ? item.display_name.trim()\n : [item.first_name, item.last_name].filter(Boolean).join(' ').trim() || item.id.slice(0, 8)\n options.push({ value: item.id, label })\n }\n setPeopleLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n },\n [],\n )\n\n const loadCompanyOptions = React.useCallback(\n async (query: string, signal: AbortSignal): Promise<EntityFilterOption[]> => {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '50')\n if (query) params.set('search', query)\n params.set('sortField', 'display_name')\n params.set('sortDir', 'asc')\n const call = await apiCall<{ items?: Array<{ id?: string; display_name?: string }> }>(\n `/api/customers/companies?${params.toString()}`,\n { signal, headers: SUPPRESS_AUTH_REDIRECT_HEADERS },\n )\n if (!call.ok) return []\n const items = call.result?.items ?? []\n const options: EntityFilterOption[] = []\n for (const item of items) {\n if (!item.id || !item.display_name) continue\n options.push({ value: item.id, label: item.display_name })\n }\n setCompanyLabels((prev) => {\n const next: Record<string, string> = { ...prev }\n for (const option of options) next[option.value] = option.label\n return next\n })\n return options\n },\n [],\n )\n\n const leadingChipsNode = (\n <>\n <StatusFilterPopover values={statusFilters} onApply={setStatusFilters} />\n <PipelineFilterPopover\n pipelines={pipelineFilterOptions}\n selectedPipelineId={selectedPipelineId}\n onApply={setSelectedPipelineId}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.owner', 'Owner')}\n anyLabel={translateWithFallback(t, 'customers.deals.kanban.filter.all', 'All')}\n values={ownerFilters}\n onApply={setOwnerFilters}\n loadOptions={loadOwnerOptions}\n labelById={ownerLabels}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.people', 'People')}\n values={peopleFilters}\n onApply={setPeopleFilters}\n loadOptions={loadPeopleOptions}\n labelById={peopleLabels}\n />\n <EntityFilterPopover\n label={translateWithFallback(t, 'customers.deals.kanban.filter.companies', 'Companies')}\n values={companyFilters}\n onApply={setCompanyFilters}\n loadOptions={loadCompanyOptions}\n labelById={companyLabels}\n />\n <CloseDateFilterPopover value={closeDateFilter} onApply={setCloseDateFilter} />\n </>\n )\n\n const sortNode = <SortByPopover value={sortBy} onApply={setSortBy} />\n\n return (\n <div className=\"flex flex-col gap-4\">\n <FilterBarRow\n leadingChips={leadingChipsNode}\n chips={NO_FILTER_CHIPS}\n sortNode={sortNode}\n onChipClick={noopChipClick}\n />\n\n {dealsQuery.isLoading ? (\n <LoadingMessage\n label={translateWithFallback(t, 'customers.deals.map.canvas.loading', 'Loading map\u2026')}\n />\n ) : dealsQuery.isError ? (\n <ErrorMessage\n label={dealsQuery.error instanceof Error ? dealsQuery.error.message : loadErrorLabel}\n action={\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void dealsQuery.refetch()}\n >\n {translateWithFallback(t, 'customers.deals.map.retry', 'Retry')}\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-2\">\n {dealsQuery.data?.truncated ? (\n <p className=\"text-sm text-muted-foreground\">\n {translateWithFallback(\n t,\n 'customers.deals.map.truncated',\n 'Showing first {count} of {total} located deals \u2014 refine filters to narrow the map.',\n { count: deals.length, total: dealsQuery.data?.total ?? deals.length },\n )}\n </p>\n ) : null}\n <div className=\"flex min-h-[480px] flex-col gap-4 lg:h-[calc(100vh-360px)] lg:flex-row\">\n <DealsLocationPanel\n deals={deals}\n locatedCount={dealsQuery.data?.total ?? deals.length}\n stageMetaById={stageMetaById}\n mapCenter={mapCenter}\n selectedDealId={selectedDealId}\n onSelect={handleSelect}\n />\n <DealsMapCanvas\n className=\"min-h-[480px] flex-1 overflow-hidden rounded-xl border border-border lg:min-h-0\"\n deals={canvasDeals}\n legendStages={legendStages}\n preview={preview}\n selectedDealId={selectedDealId}\n onSelect={handleSelect}\n onCenterChange={handleCenterChange}\n />\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default DealsMapView\n"],
5
+ "mappings": "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",
6
6
  "names": ["deals"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6390.1.210bbbc703",
3
+ "version": "0.6.6-develop.6392.1.ed38e087fe",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -248,16 +248,16 @@
248
248
  "zod": "^4.4.3"
249
249
  },
250
250
  "peerDependencies": {
251
- "@open-mercato/ai-assistant": "0.6.6-develop.6390.1.210bbbc703",
252
- "@open-mercato/shared": "0.6.6-develop.6390.1.210bbbc703",
253
- "@open-mercato/ui": "0.6.6-develop.6390.1.210bbbc703",
251
+ "@open-mercato/ai-assistant": "0.6.6-develop.6392.1.ed38e087fe",
252
+ "@open-mercato/shared": "0.6.6-develop.6392.1.ed38e087fe",
253
+ "@open-mercato/ui": "0.6.6-develop.6392.1.ed38e087fe",
254
254
  "react": "^19.0.0",
255
255
  "react-dom": "^19.0.0"
256
256
  },
257
257
  "devDependencies": {
258
- "@open-mercato/ai-assistant": "0.6.6-develop.6390.1.210bbbc703",
259
- "@open-mercato/shared": "0.6.6-develop.6390.1.210bbbc703",
260
- "@open-mercato/ui": "0.6.6-develop.6390.1.210bbbc703",
258
+ "@open-mercato/ai-assistant": "0.6.6-develop.6392.1.ed38e087fe",
259
+ "@open-mercato/shared": "0.6.6-develop.6392.1.ed38e087fe",
260
+ "@open-mercato/ui": "0.6.6-develop.6392.1.ed38e087fe",
261
261
  "@testing-library/dom": "^10.4.1",
262
262
  "@testing-library/jest-dom": "^6.9.1",
263
263
  "@testing-library/react": "^16.3.1",
@@ -322,11 +322,11 @@ export function DealsMapView({ search }: DealsMapViewProps): React.ReactElement
322
322
  'deals',
323
323
  `scope:${scopeVersion}`,
324
324
  `search:${debouncedSearch}`,
325
- `status:${statusFilters.slice().sort().join(',')}`,
325
+ `status:${statusFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,
326
326
  `pipeline:${selectedPipelineId ?? ''}`,
327
- `owners:${ownerFilters.slice().sort().join(',')}`,
328
- `people:${peopleFilters.slice().sort().join(',')}`,
329
- `companies:${companyFilters.slice().sort().join(',')}`,
327
+ `owners:${ownerFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,
328
+ `people:${peopleFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,
329
+ `companies:${companyFilters.slice().sort((a, b) => a.localeCompare(b)).join(',')}`,
330
330
  `close:${closeDateFilter.from ?? ''}-${closeDateFilter.to ?? ''}`,
331
331
  `sort:${apiSort.sortField}:${apiSort.sortDir}`,
332
332
  ],