@open-mercato/core 0.4.11-develop.1354.54d40d164a → 0.4.11-develop.1362.574a071900
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.
- package/dist/modules/customers/api/companies/route.js +141 -3
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +52 -3
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +145 -3
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +195 -0
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +171 -6
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +100 -7
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +180 -7
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +7 -0
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +1 -0
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +81 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/package.json +3 -3
- package/src/modules/customers/api/companies/route.ts +151 -3
- package/src/modules/customers/api/deals/route.ts +54 -3
- package/src/modules/customers/api/people/route.ts +160 -3
- package/src/modules/customers/api/utils.ts +286 -0
- package/src/modules/customers/backend/customers/companies/page.tsx +184 -9
- package/src/modules/customers/backend/customers/deals/page.tsx +127 -35
- package/src/modules/customers/backend/customers/people/page.tsx +191 -10
- package/src/modules/customers/commands/interactions.ts +7 -0
- package/src/modules/customers/components/detail/DealForm.tsx +1 -0
- package/src/modules/customers/i18n/de.json +12 -0
- package/src/modules/customers/i18n/en.json +15 -3
- package/src/modules/customers/i18n/es.json +12 -0
- package/src/modules/customers/i18n/pl.json +12 -0
- package/src/modules/query_index/lib/engine.ts +95 -1
|
@@ -6,6 +6,7 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
|
6
6
|
import { useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
8
8
|
import { DataTable, withDataTableNamespaces } from "@open-mercato/ui/backend/DataTable";
|
|
9
|
+
import { serializeAdvancedFilter } from "@open-mercato/shared/lib/query/advanced-filter";
|
|
9
10
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
10
11
|
import { buildCrudExportUrl, deleteCrud } from "@open-mercato/ui/backend/utils/crud";
|
|
11
12
|
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
@@ -23,9 +24,13 @@ import {
|
|
|
23
24
|
invalidateCustomerDictionary
|
|
24
25
|
} from "../../../components/detail/hooks/useCustomerDictionary.js";
|
|
25
26
|
import {
|
|
26
|
-
useCustomFieldDefs
|
|
27
|
-
filterCustomFieldDefs
|
|
27
|
+
useCustomFieldDefs
|
|
28
28
|
} from "@open-mercato/ui/backend/utils/customFieldDefs";
|
|
29
|
+
import {
|
|
30
|
+
mapCustomFieldKindToFilterType,
|
|
31
|
+
normalizeCustomFieldFilterOptions,
|
|
32
|
+
supportsCustomFieldColumn
|
|
33
|
+
} from "@open-mercato/ui/backend/utils/customFieldColumns";
|
|
29
34
|
function parsePersonLookupRecord(item) {
|
|
30
35
|
if (typeof item !== "object" || item === null) return null;
|
|
31
36
|
const record = item;
|
|
@@ -197,6 +202,8 @@ function CustomersDealsPage() {
|
|
|
197
202
|
const raw = Number(searchParams?.get("page") ?? "1");
|
|
198
203
|
return Number.isFinite(raw) && raw > 0 ? raw : 1;
|
|
199
204
|
});
|
|
205
|
+
const [pageSize, setPageSize] = React.useState(PAGE_SIZE);
|
|
206
|
+
const [sorting, setSorting] = React.useState([]);
|
|
200
207
|
const [total, setTotal] = React.useState(0);
|
|
201
208
|
const [totalPages, setTotalPages] = React.useState(1);
|
|
202
209
|
const [search, setSearch] = React.useState(() => searchParams?.get("search")?.trim() ?? "");
|
|
@@ -204,6 +211,7 @@ function CustomersDealsPage() {
|
|
|
204
211
|
const [reloadToken, setReloadToken] = React.useState(0);
|
|
205
212
|
const [pendingDeleteId, setPendingDeleteId] = React.useState(null);
|
|
206
213
|
const [filterValues, setFilterValues] = React.useState({});
|
|
214
|
+
const [advancedFilterState, setAdvancedFilterState] = React.useState({ logic: "and", conditions: [] });
|
|
207
215
|
const [cacheStatus, setCacheStatus] = React.useState(null);
|
|
208
216
|
const initialPersonIds = React.useMemo(
|
|
209
217
|
() => extractIdsFromParams(searchParams, "personId"),
|
|
@@ -483,7 +491,11 @@ function CustomersDealsPage() {
|
|
|
483
491
|
const queryParams = React.useMemo(() => {
|
|
484
492
|
const params = new URLSearchParams();
|
|
485
493
|
params.set("page", String(page));
|
|
486
|
-
params.set("pageSize", String(
|
|
494
|
+
params.set("pageSize", String(pageSize));
|
|
495
|
+
if (sorting.length > 0) {
|
|
496
|
+
params.set("sort", sorting[0].id);
|
|
497
|
+
params.set("order", sorting[0].desc ? "desc" : "asc");
|
|
498
|
+
}
|
|
487
499
|
if (search.trim().length) params.set("search", search.trim());
|
|
488
500
|
if (selectedPersonIds.length) params.set("personId", selectedPersonIds.join(","));
|
|
489
501
|
if (selectedCompanyIds.length) params.set("companyId", selectedCompanyIds.join(","));
|
|
@@ -508,8 +520,12 @@ function CustomersDealsPage() {
|
|
|
508
520
|
if (stringValue) params.set(key, stringValue);
|
|
509
521
|
}
|
|
510
522
|
});
|
|
523
|
+
const advancedParams = serializeAdvancedFilter(advancedFilterState);
|
|
524
|
+
for (const [key, val] of Object.entries(advancedParams)) {
|
|
525
|
+
params.set(key, val);
|
|
526
|
+
}
|
|
511
527
|
return params.toString();
|
|
512
|
-
}, [filterValues, page, search, selectedCompanyIds, selectedPersonIds]);
|
|
528
|
+
}, [advancedFilterState, filterValues, page, pageSize, search, selectedCompanyIds, selectedPersonIds, sorting]);
|
|
513
529
|
const currentParams = React.useMemo(
|
|
514
530
|
() => Object.fromEntries(new URLSearchParams(queryParams)),
|
|
515
531
|
[queryParams]
|
|
@@ -616,6 +632,38 @@ function CustomersDealsPage() {
|
|
|
616
632
|
},
|
|
617
633
|
[confirm, handleRefresh, pendingDeleteId, t]
|
|
618
634
|
);
|
|
635
|
+
const handlePageSizeChange = React.useCallback((newSize) => {
|
|
636
|
+
setPageSize(newSize);
|
|
637
|
+
setPage(1);
|
|
638
|
+
}, []);
|
|
639
|
+
const handleBulkDelete = React.useCallback(async (selectedRows) => {
|
|
640
|
+
const confirmed = await confirm({
|
|
641
|
+
title: t("customers.deals.list.bulkDelete.title", "Delete {count} deals?", { count: selectedRows.length }),
|
|
642
|
+
description: t("customers.deals.list.bulkDelete.description", "This action cannot be undone."),
|
|
643
|
+
variant: "destructive"
|
|
644
|
+
});
|
|
645
|
+
if (!confirmed) return false;
|
|
646
|
+
let deletedCount = 0;
|
|
647
|
+
for (const row of selectedRows) {
|
|
648
|
+
try {
|
|
649
|
+
await deleteCrud("customers/deals", {
|
|
650
|
+
body: { id: row.id },
|
|
651
|
+
errorMessage: t("customers.deals.list.deleteError", "Failed to delete deal.")
|
|
652
|
+
});
|
|
653
|
+
deletedCount++;
|
|
654
|
+
} catch {
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (deletedCount > 0) {
|
|
658
|
+
setRows((prev) => {
|
|
659
|
+
const deletedIds = new Set(selectedRows.map((r) => r.id));
|
|
660
|
+
return prev.filter((r) => !deletedIds.has(r.id));
|
|
661
|
+
});
|
|
662
|
+
setTotal((prev) => Math.max(0, prev - deletedCount));
|
|
663
|
+
flash(t("customers.deals.list.bulkDelete.success", "{count} deals deleted", { count: deletedCount }), "success");
|
|
664
|
+
}
|
|
665
|
+
return deletedCount > 0;
|
|
666
|
+
}, [confirm, t]);
|
|
619
667
|
const personOptions = peopleState.options;
|
|
620
668
|
const companyOptions = companiesState.options;
|
|
621
669
|
const filters = React.useMemo(() => [
|
|
@@ -657,9 +705,16 @@ function CustomersDealsPage() {
|
|
|
657
705
|
if (!items.length) return noValue;
|
|
658
706
|
return /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-1 text-sm", children: items.map((entry) => /* @__PURE__ */ jsx("li", { className: "rounded border px-2 py-0.5 text-xs bg-muted", children: entry.label && entry.label.trim().length ? entry.label : fallbackLabel }, entry.id)) });
|
|
659
707
|
};
|
|
660
|
-
const customColumns =
|
|
708
|
+
const customColumns = customFieldDefs.filter((def) => supportsCustomFieldColumn(def)).map((def) => ({
|
|
661
709
|
accessorKey: `cf_${def.key}`,
|
|
662
710
|
header: def.label || def.key,
|
|
711
|
+
meta: {
|
|
712
|
+
columnChooserGroup: def.group?.title ?? "Custom Fields",
|
|
713
|
+
filterGroup: def.group?.title ?? "Custom Fields",
|
|
714
|
+
filterType: mapCustomFieldKindToFilterType(def.kind),
|
|
715
|
+
filterOptions: normalizeCustomFieldFilterOptions(def.options),
|
|
716
|
+
hidden: def.listVisible === false
|
|
717
|
+
},
|
|
663
718
|
cell: ({ getValue }) => {
|
|
664
719
|
const value = getValue();
|
|
665
720
|
if (value == null) return noValue;
|
|
@@ -684,21 +739,25 @@ function CustomersDealsPage() {
|
|
|
684
739
|
{
|
|
685
740
|
accessorKey: "title",
|
|
686
741
|
header: t("customers.deals.list.columns.title"),
|
|
742
|
+
meta: { alwaysVisible: true, columnChooserGroup: "Basic Info", filterKey: "title" },
|
|
687
743
|
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: row.original.title })
|
|
688
744
|
},
|
|
689
745
|
{
|
|
690
746
|
accessorKey: "status",
|
|
691
747
|
header: t("customers.deals.list.columns.status"),
|
|
748
|
+
meta: { filterType: "select", columnChooserGroup: "Basic Info", filterKey: "status" },
|
|
692
749
|
cell: ({ row }) => renderDictionaryCell("deal-statuses", row.original.status)
|
|
693
750
|
},
|
|
694
751
|
{
|
|
695
752
|
accessorKey: "pipelineStage",
|
|
696
753
|
header: t("customers.deals.list.columns.pipelineStage"),
|
|
754
|
+
meta: { columnChooserGroup: "Pipeline", filterKey: "pipeline_stage" },
|
|
697
755
|
cell: ({ row }) => renderDictionaryCell("pipeline-stages", row.original.pipelineStage)
|
|
698
756
|
},
|
|
699
757
|
{
|
|
700
758
|
accessorKey: "pipelineId",
|
|
701
759
|
header: t("customers.deals.list.columns.pipeline", "Pipeline"),
|
|
760
|
+
meta: { columnChooserGroup: "Pipeline", filterKey: "pipeline_id" },
|
|
702
761
|
cell: ({ row }) => {
|
|
703
762
|
const name = row.original.pipelineId ? pipelineNames[row.original.pipelineId] : null;
|
|
704
763
|
return name ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: name }) : noValue;
|
|
@@ -707,11 +766,13 @@ function CustomersDealsPage() {
|
|
|
707
766
|
{
|
|
708
767
|
accessorKey: "valueAmount",
|
|
709
768
|
header: t("customers.deals.list.columns.value"),
|
|
769
|
+
meta: { filterType: "number", columnChooserGroup: "Financial", filterKey: "value_amount" },
|
|
710
770
|
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: formatCurrency(row.original.valueAmount ?? null, row.original.valueCurrency ?? null, t("customers.deals.list.noValue")) })
|
|
711
771
|
},
|
|
712
772
|
{
|
|
713
773
|
accessorKey: "probability",
|
|
714
774
|
header: t("customers.deals.list.columns.probability"),
|
|
775
|
+
meta: { filterType: "number", columnChooserGroup: "Financial", filterKey: "probability" },
|
|
715
776
|
cell: ({ row }) => {
|
|
716
777
|
const value = row.original.probability;
|
|
717
778
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -723,21 +784,25 @@ function CustomersDealsPage() {
|
|
|
723
784
|
{
|
|
724
785
|
accessorKey: "expectedCloseAt",
|
|
725
786
|
header: t("customers.deals.list.columns.expectedClose"),
|
|
787
|
+
meta: { columnChooserGroup: "Dates", filterKey: "expected_close_at" },
|
|
726
788
|
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm", children: formatDateValue(row.original.expectedCloseAt ?? null, t("customers.deals.list.noValue")) })
|
|
727
789
|
},
|
|
728
790
|
{
|
|
729
791
|
accessorKey: "companies",
|
|
730
792
|
header: t("customers.deals.list.columns.companies"),
|
|
793
|
+
meta: { columnChooserGroup: "Associations", filterable: false },
|
|
731
794
|
cell: ({ row }) => renderAssociationList(row.original.companies, t("customers.deals.list.unnamedCompany"))
|
|
732
795
|
},
|
|
733
796
|
{
|
|
734
797
|
accessorKey: "people",
|
|
735
798
|
header: t("customers.deals.list.columns.people"),
|
|
799
|
+
meta: { columnChooserGroup: "Associations", filterable: false },
|
|
736
800
|
cell: ({ row }) => renderAssociationList(row.original.people, t("customers.deals.list.unnamedPerson"))
|
|
737
801
|
},
|
|
738
802
|
{
|
|
739
803
|
accessorKey: "updatedAt",
|
|
740
804
|
header: t("customers.deals.list.columns.updatedAt"),
|
|
805
|
+
meta: { columnChooserGroup: "Dates", filterKey: "updated_at" },
|
|
741
806
|
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm", children: formatDateValue(row.original.updatedAt ?? null, t("customers.deals.list.noValue")) })
|
|
742
807
|
},
|
|
743
808
|
...customColumns
|
|
@@ -747,9 +812,11 @@ function CustomersDealsPage() {
|
|
|
747
812
|
/* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
748
813
|
DataTable,
|
|
749
814
|
{
|
|
815
|
+
stickyFirstColumn: true,
|
|
750
816
|
title: t("customers.deals.list.title"),
|
|
751
817
|
actions: /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx(Link, { href: "/backend/customers/deals/create", children: t("customers.deals.list.actions.new", "New deal") }) }),
|
|
752
818
|
columns,
|
|
819
|
+
columnChooser: { auto: true },
|
|
753
820
|
data: rows,
|
|
754
821
|
onRowClick: (row) => {
|
|
755
822
|
router.push(`/backend/customers/deals/${row.id}`);
|
|
@@ -786,6 +853,17 @@ function CustomersDealsPage() {
|
|
|
786
853
|
}
|
|
787
854
|
);
|
|
788
855
|
},
|
|
856
|
+
sortable: true,
|
|
857
|
+
sorting,
|
|
858
|
+
onSortingChange: setSorting,
|
|
859
|
+
bulkActions: [
|
|
860
|
+
{
|
|
861
|
+
id: "delete",
|
|
862
|
+
label: t("customers.deals.list.actions.delete", "Delete"),
|
|
863
|
+
destructive: true,
|
|
864
|
+
onExecute: handleBulkDelete
|
|
865
|
+
}
|
|
866
|
+
],
|
|
789
867
|
searchValue: search,
|
|
790
868
|
onSearchChange: handleSearchChange,
|
|
791
869
|
searchPlaceholder: t("customers.deals.list.searchPlaceholder"),
|
|
@@ -795,10 +873,12 @@ function CustomersDealsPage() {
|
|
|
795
873
|
onFiltersClear: handleFiltersClear,
|
|
796
874
|
pagination: {
|
|
797
875
|
page,
|
|
798
|
-
pageSize
|
|
876
|
+
pageSize,
|
|
799
877
|
total,
|
|
800
878
|
totalPages,
|
|
801
879
|
onPageChange: (nextPage) => setPage(nextPage),
|
|
880
|
+
pageSizeOptions: [10, 25, 50, 100],
|
|
881
|
+
onPageSizeChange: handlePageSizeChange,
|
|
802
882
|
cacheStatus
|
|
803
883
|
},
|
|
804
884
|
isLoading,
|
|
@@ -808,7 +888,20 @@ function CustomersDealsPage() {
|
|
|
808
888
|
},
|
|
809
889
|
exporter: exportConfig,
|
|
810
890
|
entityId: E.customers.customer_deal,
|
|
811
|
-
perspective: { tableId: "customers.deals.list" }
|
|
891
|
+
perspective: { tableId: "customers.deals.list" },
|
|
892
|
+
advancedFilter: {
|
|
893
|
+
auto: true,
|
|
894
|
+
value: advancedFilterState,
|
|
895
|
+
onChange: setAdvancedFilterState,
|
|
896
|
+
onApply: () => {
|
|
897
|
+
setPage(1);
|
|
898
|
+
},
|
|
899
|
+
onClear: () => {
|
|
900
|
+
setAdvancedFilterState({ logic: "and", conditions: [] });
|
|
901
|
+
setPage(1);
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
virtualized: true
|
|
812
905
|
}
|
|
813
906
|
) }),
|
|
814
907
|
ConfirmDialogElement
|
|
@@ -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 Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\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 { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n DictionaryValue,\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 filterCustomFieldDefs,\n} from '@open-mercato/ui/backend/utils/customFieldDefs'\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 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}\n\ntype FilterOption = { value: string; label: string }\n\ntype DictionaryKey = Extract<CustomerDictionaryKind, 'deal-statuses' | 'pipeline-stages'>\n\ntype PersonLookupRecord = {\n id: string\n name: string | null\n email: string | null\n phone: string | null\n}\n\ntype CompanyLookupRecord = {\n id: string\n name: string | null\n domain: string | null\n email: string | null\n}\n\nfunction parsePersonLookupRecord(item: unknown): PersonLookupRecord | null {\n if (typeof item !== 'object' || item === null) return null\n const record = item as Record<string, unknown>\n const id = typeof record.id === 'string' ? record.id : null\n if (!id || !isUuid(id)) return null\n const name = typeof record.display_name === 'string' ? record.display_name : null\n const email = typeof record.primary_email === 'string' ? record.primary_email : null\n const phone = typeof record.primary_phone === 'string' ? record.primary_phone : null\n return { id, name, email, phone }\n}\n\nfunction parseCompanyLookupRecord(item: unknown): CompanyLookupRecord | null {\n if (typeof item !== 'object' || item === null) return null\n const record = item as Record<string, unknown>\n const id = typeof record.id === 'string' ? record.id : null\n if (!id || !isUuid(id)) return null\n const name = typeof record.display_name === 'string' ? record.display_name : null\n const domain = typeof record.primary_domain === 'string' ? record.primary_domain : null\n const email = typeof record.primary_email === 'string' ? record.primary_email : null\n return { id, name, domain, email }\n}\n\ntype OptionsState = {\n options: FilterOption[]\n idToLabel: Record<string, string>\n labelToId: Record<string, string>\n}\n\nconst EMPTY_OPTIONS_STATE: OptionsState = {\n options: [],\n idToLabel: {},\n labelToId: {},\n}\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 ensureUniqueLabel(base: string, occupied: Set<string>): string {\n const trimmed = base.trim() || 'Unnamed'\n if (!occupied.has(trimmed)) {\n occupied.add(trimmed)\n return trimmed\n }\n let counter = 2\n let candidate = `${trimmed} \u2022 ${counter}`\n while (occupied.has(candidate)) {\n counter += 1\n candidate = `${trimmed} \u2022 ${counter}`\n }\n occupied.add(candidate)\n return candidate\n}\n\nasync function fetchPeopleLookup(query?: string): Promise<PersonLookupRecord[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '20')\n if (query && query.trim().length) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/people?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n return items\n .map((item) => parsePersonLookupRecord(item))\n .filter((record): record is PersonLookupRecord => record !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchPeopleLookupByIds(ids: string[]): Promise<PersonLookupRecord[]> {\n const unique = Array.from(new Set(ids.filter((id) => isUuid(id))))\n if (!unique.length) return []\n const results = await Promise.all(\n unique.map(async (id) => {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/people?${search.toString()}`)\n if (!call.ok) return null\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const match = items\n .map((item) => parsePersonLookupRecord(item))\n .find((record) => record?.id === id)\n return match ?? null\n } catch {\n return null\n }\n }),\n )\n return results.filter((record): record is PersonLookupRecord => !!record)\n}\n\nasync function fetchCompaniesLookup(query?: string): Promise<CompanyLookupRecord[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '20')\n if (query && query.trim().length) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/companies?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n return items\n .map((item) => parseCompanyLookupRecord(item))\n .filter((record): record is CompanyLookupRecord => record !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchCompaniesLookupByIds(ids: string[]): Promise<CompanyLookupRecord[]> {\n const unique = Array.from(new Set(ids.filter((id) => isUuid(id))))\n if (!unique.length) return []\n const results = await Promise.all(\n unique.map(async (id) => {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/companies?${search.toString()}`)\n if (!call.ok) return null\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const match = items\n .map((item) => parseCompanyLookupRecord(item))\n .find((record) => record?.id === id)\n return match ?? null\n } catch {\n return null\n }\n }),\n )\n return results.filter((record): record is CompanyLookupRecord => !!record)\n}\n\nfunction formatCurrency(amount: number | null | undefined, currency: string | null | undefined, fallback: string): string {\n if (typeof amount !== 'number' || Number.isNaN(amount)) return fallback\n try {\n if (currency && currency.trim().length) {\n const formatter = new Intl.NumberFormat(undefined, { style: 'currency', currency })\n return formatter.format(amount)\n }\n const formatter = new Intl.NumberFormat(undefined, { style: 'decimal', maximumFractionDigits: 2 })\n return formatter.format(amount)\n } catch {\n return currency ? `${amount} ${currency}` : String(amount)\n }\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\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n\nexport default function CustomersDealsPage() {\n const t = useT()\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 [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\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 [filterValues, setFilterValues] = React.useState<FilterValues>({})\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 [peopleState, setPeopleState] = React.useState<OptionsState>(EMPTY_OPTIONS_STATE)\n const [companiesState, setCompaniesState] = React.useState<OptionsState>(EMPTY_OPTIONS_STATE)\n const peopleCacheRef = React.useRef<Map<string, FilterOption[]>>(new Map())\n const companiesCacheRef = React.useRef<Map<string, FilterOption[]>>(new Map())\n\n const buildPersonLabel = React.useCallback((record: PersonLookupRecord): string => {\n const parts: string[] = []\n const name = record.name?.trim()\n if (name) parts.push(name)\n const email = record.email?.trim()\n if (email && !parts.includes(email)) parts.push(email)\n const phone = record.phone?.trim()\n if (!parts.length && phone) parts.push(phone)\n if (!parts.length) parts.push(t('customers.deals.list.unnamedPerson', 'Unnamed person'))\n return parts.join(' \u2022 ')\n }, [t])\n\n const buildCompanyLabel = React.useCallback((record: CompanyLookupRecord): string => {\n const parts: string[] = []\n const name = record.name?.trim()\n if (name) parts.push(name)\n const domain = record.domain?.trim()\n if (domain && !parts.includes(domain)) parts.push(domain)\n const email = record.email?.trim()\n if (!parts.length && email) parts.push(email)\n if (!parts.length) parts.push(t('customers.deals.list.unnamedCompany', 'Unnamed company'))\n return parts.join(' \u2022 ')\n }, [t])\n\n const ingestPeopleRecords = React.useCallback((records: PersonLookupRecord[]) => {\n if (!records.length) return [] as FilterOption[]\n const queryMap = new Map<string, FilterOption>()\n setPeopleState((prev) => {\n const idToLabel = { ...prev.idToLabel }\n const labelToId: Record<string, string> = {}\n const merged = new Map(prev.options.map((opt) => [opt.value, opt]))\n const occupied = new Set<string>()\n Object.entries(prev.labelToId).forEach(([label, id]) => {\n occupied.add(label)\n labelToId[label] = id\n })\n records.forEach((record) => {\n if (!isUuid(record.id)) return\n const base = buildPersonLabel(record)\n let previousLabel = idToLabel[record.id]\n if (previousLabel) {\n // remove previous label before reassigning\n delete labelToId[previousLabel]\n occupied.delete(previousLabel)\n }\n const label = ensureUniqueLabel(base, occupied)\n idToLabel[record.id] = label\n labelToId[label] = record.id\n const option = { value: record.id, label }\n merged.set(record.id, option)\n queryMap.set(record.id, option)\n })\n const nextOptions = Array.from(merged.values()).sort((a, b) => a.label.localeCompare(b.label))\n return { options: nextOptions, idToLabel, labelToId }\n })\n return Array.from(queryMap.values()).sort((a, b) => a.label.localeCompare(b.label))\n }, [buildPersonLabel])\n\n const ingestCompanyRecords = React.useCallback((records: CompanyLookupRecord[]) => {\n if (!records.length) return [] as FilterOption[]\n const queryMap = new Map<string, FilterOption>()\n setCompaniesState((prev) => {\n const idToLabel = { ...prev.idToLabel }\n const labelToId: Record<string, string> = {}\n const merged = new Map(prev.options.map((opt) => [opt.value, opt]))\n const occupied = new Set<string>()\n Object.entries(prev.labelToId).forEach(([label, id]) => {\n occupied.add(label)\n labelToId[label] = id\n })\n records.forEach((record) => {\n if (!isUuid(record.id)) return\n const base = buildCompanyLabel(record)\n let previousLabel = idToLabel[record.id]\n if (previousLabel) {\n delete labelToId[previousLabel]\n occupied.delete(previousLabel)\n }\n const label = ensureUniqueLabel(base, occupied)\n idToLabel[record.id] = label\n labelToId[label] = record.id\n const option = { value: record.id, label }\n merged.set(record.id, option)\n queryMap.set(record.id, option)\n })\n const nextOptions = Array.from(merged.values()).sort((a, b) => a.label.localeCompare(b.label))\n return { options: nextOptions, idToLabel, labelToId }\n })\n return Array.from(queryMap.values()).sort((a, b) => a.label.localeCompare(b.label))\n }, [buildCompanyLabel])\n\n const loadPeopleOptions = React.useCallback(async (query?: string) => {\n const normalizedQuery = (query || '').trim().toLowerCase()\n const cacheKey = `${scopeVersion}|${normalizedQuery}`\n const cached = peopleCacheRef.current.get(cacheKey)\n if (cached) return cached\n const records = await fetchPeopleLookup(query)\n const options = ingestPeopleRecords(records)\n peopleCacheRef.current.set(cacheKey, options)\n return options\n }, [scopeVersion, ingestPeopleRecords])\n\n const loadCompanyOptions = React.useCallback(async (query?: string) => {\n const normalizedQuery = (query || '').trim().toLowerCase()\n const cacheKey = `${scopeVersion}|${normalizedQuery}`\n const cached = companiesCacheRef.current.get(cacheKey)\n if (cached) return cached\n const records = await fetchCompaniesLookup(query)\n const options = ingestCompanyRecords(records)\n companiesCacheRef.current.set(cacheKey, options)\n return options\n }, [scopeVersion, ingestCompanyRecords])\n\n React.useEffect(() => {\n let cancelled = false\n if (!selectedPersonIds.length) return\n const missing = selectedPersonIds.filter((id) => !peopleState.idToLabel[id])\n if (!missing.length) return\n fetchPeopleLookupByIds(missing).then((records) => {\n if (cancelled) return\n ingestPeopleRecords(records)\n })\n return () => { cancelled = true }\n }, [selectedPersonIds, peopleState.idToLabel, ingestPeopleRecords])\n\n React.useEffect(() => {\n let cancelled = false\n if (!selectedCompanyIds.length) return\n const missing = selectedCompanyIds.filter((id) => !companiesState.idToLabel[id])\n if (!missing.length) return\n fetchCompaniesLookupByIds(missing).then((records) => {\n if (cancelled) return\n ingestCompanyRecords(records)\n })\n return () => { cancelled = true }\n }, [selectedCompanyIds, companiesState.idToLabel, ingestCompanyRecords])\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\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 {}\n }\n loadPipelines().catch(() => {})\n return () => { cancelled = true }\n }, [reloadToken, scopeVersion])\n\n React.useEffect(() => {\n peopleCacheRef.current.clear()\n companiesCacheRef.current.clear()\n setPeopleState((prev) => {\n if (!prev.options.length && !Object.keys(prev.idToLabel).length) return prev\n return { ...EMPTY_OPTIONS_STATE }\n })\n setCompaniesState((prev) => {\n if (!prev.options.length && !Object.keys(prev.idToLabel).length) return prev\n return { ...EMPTY_OPTIONS_STATE }\n })\n }, [scopeVersion, reloadToken])\n\n const syncFilterLabels = React.useCallback((\n key: 'people' | 'companies',\n ids: string[],\n idToLabel: Record<string, string>,\n ) => {\n setFilterValues((prev) => {\n const current = Array.isArray(prev[key]) ? (prev[key] as string[]) : []\n if (!ids.length) {\n if (!current.length) return prev\n const next = { ...prev }\n delete next[key]\n return next\n }\n const labels: string[] = []\n ids.forEach((id) => {\n const label = idToLabel[id]\n if (label && !labels.includes(label)) labels.push(label)\n })\n if (labels.length < ids.length) return prev\n if (arraysEqual(current, labels)) return prev\n return { ...prev, [key]: labels }\n })\n }, [])\n\n React.useEffect(() => {\n syncFilterLabels('people', selectedPersonIds, peopleState.idToLabel)\n }, [selectedPersonIds, peopleState.idToLabel, syncFilterLabels])\n\n React.useEffect(() => {\n syncFilterLabels('companies', selectedCompanyIds, companiesState.idToLabel)\n }, [selectedCompanyIds, companiesState.idToLabel, syncFilterLabels])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value.trim())\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = { ...values }\n const rawPeople = Array.isArray(values.people) ? (values.people as string[]) : []\n const nextPersonIds: string[] = []\n rawPeople.forEach((value) => {\n const trimmed = typeof value === 'string' ? value.trim() : ''\n if (!trimmed) return\n const mapped = peopleState.labelToId[trimmed]\n if (mapped && !nextPersonIds.includes(mapped)) nextPersonIds.push(mapped)\n })\n setSelectedPersonIds(nextPersonIds)\n if (nextPersonIds.length) {\n next.people = Array.from(new Set(rawPeople.map((value) => (typeof value === 'string' ? value.trim() : '')).filter((value) => value.length > 0)))\n } else {\n delete next.people\n }\n\n const rawCompanies = Array.isArray(values.companies) ? (values.companies as string[]) : []\n const nextCompanyIds: string[] = []\n rawCompanies.forEach((value) => {\n const trimmed = typeof value === 'string' ? value.trim() : ''\n if (!trimmed) return\n const mapped = companiesState.labelToId[trimmed]\n if (mapped && !nextCompanyIds.includes(mapped)) nextCompanyIds.push(mapped)\n })\n setSelectedCompanyIds(nextCompanyIds)\n if (nextCompanyIds.length) {\n next.companies = Array.from(new Set(rawCompanies.map((value) => (typeof value === 'string' ? value.trim() : '')).filter((value) => value.length > 0)))\n } else {\n delete next.companies\n }\n\n setFilterValues(next)\n setPage(1)\n }, [peopleState.labelToId, companiesState.labelToId])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setSelectedPersonIds([])\n setSelectedCompanyIds([])\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(PAGE_SIZE))\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 Object.entries(filterValues).forEach(([key, value]) => {\n if (key === 'people' || key === 'companies') return\n if (value == null) return\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (normalized.length) params.set(key, normalized.join(','))\n } else if (typeof value === 'object') {\n const obj = value as Record<string, unknown>\n const from = typeof obj.from === 'string' ? obj.from.trim() : ''\n const to = typeof obj.to === 'string' ? obj.to.trim() : ''\n if (from) params.set(`${key}[from]`, from)\n if (to) params.set(`${key}[to]`, to)\n } else {\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (stringValue) params.set(key, stringValue)\n }\n })\n return params.toString()\n }, [filterValues, page, search, selectedCompanyIds, selectedPersonIds])\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 } 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 if (totalPages > 0 && page > totalPages) {\n setPage(totalPages)\n }\n }, [page, totalPages])\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 (page > 1) params.set('page', String(page))\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])\n\n const handleRefresh = React.useCallback(() => {\n peopleCacheRef.current.clear()\n companiesCacheRef.current.clear()\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 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 setPendingDeleteId(dealId)\n try {\n await deleteCrud('customers/deals', {\n body: { id: dealId },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\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 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, t],\n )\n\n const personOptions = peopleState.options\n const companyOptions = companiesState.options\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'people',\n label: t('customers.deals.list.filters.people'),\n type: 'tags',\n options: personOptions,\n loadOptions: loadPeopleOptions,\n placeholder: t('customers.deals.list.filters.peoplePlaceholder'),\n },\n {\n id: 'companies',\n label: t('customers.deals.list.filters.companies'),\n type: 'tags',\n options: companyOptions,\n loadOptions: loadCompanyOptions,\n placeholder: t('customers.deals.list.filters.companiesPlaceholder'),\n },\n ], [companyOptions, loadCompanyOptions, loadPeopleOptions, personOptions, t])\n\n const { data: customFieldDefs = [] } = useCustomFieldDefs([E.customers.customer_deal], {\n keyExtras: [scopeVersion, reloadToken],\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 renderDictionaryCell = (kind: DictionaryKey, value: string | null | undefined) => (\n <DictionaryValue\n value={value}\n map={dictionaryMaps[kind]}\n fallback={value ? <span className=\"text-sm\">{value}</span> : noValue}\n className=\"text-sm\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n const renderAssociationList = (\n items: { id: string; label: string }[],\n fallbackLabel: string,\n ) => {\n if (!items.length) return noValue\n return (\n <ul className=\"flex flex-wrap gap-1 text-sm\">\n {items.map((entry) => (\n <li key={entry.id} className=\"rounded border px-2 py-0.5 text-xs bg-muted\">\n {entry.label && entry.label.trim().length ? entry.label : fallbackLabel}\n </li>\n ))}\n </ul>\n )\n }\n\n const customColumns = filterCustomFieldDefs(customFieldDefs, 'list').map<ColumnDef<DealRow>>((def) => ({\n accessorKey: `cf_${def.key}`,\n header: def.label || def.key,\n cell: ({ getValue }) => {\n const value = getValue()\n if (value == null) return noValue\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (!normalized.length) return noValue\n return <span className=\"text-sm\">{normalized.join(', ')}</span>\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 cell: ({ row }) => <span className=\"font-medium text-sm\">{row.original.title}</span>,\n },\n {\n accessorKey: 'status',\n header: t('customers.deals.list.columns.status'),\n cell: ({ row }) => renderDictionaryCell('deal-statuses', row.original.status),\n },\n {\n accessorKey: 'pipelineStage',\n header: t('customers.deals.list.columns.pipelineStage'),\n cell: ({ row }) => renderDictionaryCell('pipeline-stages', row.original.pipelineStage),\n },\n {\n accessorKey: 'pipelineId',\n header: t('customers.deals.list.columns.pipeline', 'Pipeline'),\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 cell: ({ row }) => (\n <span className=\"text-sm font-medium\">\n {formatCurrency(row.original.valueAmount ?? null, row.original.valueCurrency ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n {\n accessorKey: 'probability',\n header: t('customers.deals.list.columns.probability'),\n cell: ({ row }) => {\n const value = row.original.probability\n if (typeof value === 'number' && Number.isFinite(value)) {\n return <span className=\"text-sm\">{`${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 cell: ({ row }) => (\n <span className=\"text-sm\">\n {formatDateValue(row.original.expectedCloseAt ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n {\n accessorKey: 'companies',\n header: t('customers.deals.list.columns.companies'),\n cell: ({ row }) => renderAssociationList(row.original.companies, t('customers.deals.list.unnamedCompany')),\n },\n {\n accessorKey: 'people',\n header: t('customers.deals.list.columns.people'),\n cell: ({ row }) => renderAssociationList(row.original.people, t('customers.deals.list.unnamedPerson')),\n },\n {\n accessorKey: 'updatedAt',\n header: t('customers.deals.list.columns.updatedAt'),\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, pipelineNames, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable<DealRow>\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 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 searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={t('customers.deals.list.searchPlaceholder')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: (nextPage) => setPage(nextPage),\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: '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 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 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 Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport type { AdvancedFilterState } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { serializeAdvancedFilter } from '@open-mercato/shared/lib/query/advanced-filter'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\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 { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n DictionaryValue,\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'\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 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}\n\ntype FilterOption = { value: string; label: string }\n\ntype DictionaryKey = Extract<CustomerDictionaryKind, 'deal-statuses' | 'pipeline-stages'>\n\ntype PersonLookupRecord = {\n id: string\n name: string | null\n email: string | null\n phone: string | null\n}\n\ntype CompanyLookupRecord = {\n id: string\n name: string | null\n domain: string | null\n email: string | null\n}\n\nfunction parsePersonLookupRecord(item: unknown): PersonLookupRecord | null {\n if (typeof item !== 'object' || item === null) return null\n const record = item as Record<string, unknown>\n const id = typeof record.id === 'string' ? record.id : null\n if (!id || !isUuid(id)) return null\n const name = typeof record.display_name === 'string' ? record.display_name : null\n const email = typeof record.primary_email === 'string' ? record.primary_email : null\n const phone = typeof record.primary_phone === 'string' ? record.primary_phone : null\n return { id, name, email, phone }\n}\n\nfunction parseCompanyLookupRecord(item: unknown): CompanyLookupRecord | null {\n if (typeof item !== 'object' || item === null) return null\n const record = item as Record<string, unknown>\n const id = typeof record.id === 'string' ? record.id : null\n if (!id || !isUuid(id)) return null\n const name = typeof record.display_name === 'string' ? record.display_name : null\n const domain = typeof record.primary_domain === 'string' ? record.primary_domain : null\n const email = typeof record.primary_email === 'string' ? record.primary_email : null\n return { id, name, domain, email }\n}\n\ntype OptionsState = {\n options: FilterOption[]\n idToLabel: Record<string, string>\n labelToId: Record<string, string>\n}\n\nconst EMPTY_OPTIONS_STATE: OptionsState = {\n options: [],\n idToLabel: {},\n labelToId: {},\n}\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 ensureUniqueLabel(base: string, occupied: Set<string>): string {\n const trimmed = base.trim() || 'Unnamed'\n if (!occupied.has(trimmed)) {\n occupied.add(trimmed)\n return trimmed\n }\n let counter = 2\n let candidate = `${trimmed} \u2022 ${counter}`\n while (occupied.has(candidate)) {\n counter += 1\n candidate = `${trimmed} \u2022 ${counter}`\n }\n occupied.add(candidate)\n return candidate\n}\n\nasync function fetchPeopleLookup(query?: string): Promise<PersonLookupRecord[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '20')\n if (query && query.trim().length) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/people?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n return items\n .map((item) => parsePersonLookupRecord(item))\n .filter((record): record is PersonLookupRecord => record !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchPeopleLookupByIds(ids: string[]): Promise<PersonLookupRecord[]> {\n const unique = Array.from(new Set(ids.filter((id) => isUuid(id))))\n if (!unique.length) return []\n const results = await Promise.all(\n unique.map(async (id) => {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/people?${search.toString()}`)\n if (!call.ok) return null\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const match = items\n .map((item) => parsePersonLookupRecord(item))\n .find((record) => record?.id === id)\n return match ?? null\n } catch {\n return null\n }\n }),\n )\n return results.filter((record): record is PersonLookupRecord => !!record)\n}\n\nasync function fetchCompaniesLookup(query?: string): Promise<CompanyLookupRecord[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '20')\n if (query && query.trim().length) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/companies?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n return items\n .map((item) => parseCompanyLookupRecord(item))\n .filter((record): record is CompanyLookupRecord => record !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchCompaniesLookupByIds(ids: string[]): Promise<CompanyLookupRecord[]> {\n const unique = Array.from(new Set(ids.filter((id) => isUuid(id))))\n if (!unique.length) return []\n const results = await Promise.all(\n unique.map(async (id) => {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/customers/companies?${search.toString()}`)\n if (!call.ok) return null\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const match = items\n .map((item) => parseCompanyLookupRecord(item))\n .find((record) => record?.id === id)\n return match ?? null\n } catch {\n return null\n }\n }),\n )\n return results.filter((record): record is CompanyLookupRecord => !!record)\n}\n\nfunction formatCurrency(amount: number | null | undefined, currency: string | null | undefined, fallback: string): string {\n if (typeof amount !== 'number' || Number.isNaN(amount)) return fallback\n try {\n if (currency && currency.trim().length) {\n const formatter = new Intl.NumberFormat(undefined, { style: 'currency', currency })\n return formatter.format(amount)\n }\n const formatter = new Intl.NumberFormat(undefined, { style: 'decimal', maximumFractionDigits: 2 })\n return formatter.format(amount)\n } catch {\n return currency ? `${amount} ${currency}` : String(amount)\n }\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\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n\nexport default function CustomersDealsPage() {\n const t = useT()\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 [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 [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [advancedFilterState, setAdvancedFilterState] = React.useState<AdvancedFilterState>({ logic: 'and', conditions: [] })\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 [peopleState, setPeopleState] = React.useState<OptionsState>(EMPTY_OPTIONS_STATE)\n const [companiesState, setCompaniesState] = React.useState<OptionsState>(EMPTY_OPTIONS_STATE)\n const peopleCacheRef = React.useRef<Map<string, FilterOption[]>>(new Map())\n const companiesCacheRef = React.useRef<Map<string, FilterOption[]>>(new Map())\n\n const buildPersonLabel = React.useCallback((record: PersonLookupRecord): string => {\n const parts: string[] = []\n const name = record.name?.trim()\n if (name) parts.push(name)\n const email = record.email?.trim()\n if (email && !parts.includes(email)) parts.push(email)\n const phone = record.phone?.trim()\n if (!parts.length && phone) parts.push(phone)\n if (!parts.length) parts.push(t('customers.deals.list.unnamedPerson', 'Unnamed person'))\n return parts.join(' \u2022 ')\n }, [t])\n\n const buildCompanyLabel = React.useCallback((record: CompanyLookupRecord): string => {\n const parts: string[] = []\n const name = record.name?.trim()\n if (name) parts.push(name)\n const domain = record.domain?.trim()\n if (domain && !parts.includes(domain)) parts.push(domain)\n const email = record.email?.trim()\n if (!parts.length && email) parts.push(email)\n if (!parts.length) parts.push(t('customers.deals.list.unnamedCompany', 'Unnamed company'))\n return parts.join(' \u2022 ')\n }, [t])\n\n const ingestPeopleRecords = React.useCallback((records: PersonLookupRecord[]) => {\n if (!records.length) return [] as FilterOption[]\n const queryMap = new Map<string, FilterOption>()\n setPeopleState((prev) => {\n const idToLabel = { ...prev.idToLabel }\n const labelToId: Record<string, string> = {}\n const merged = new Map(prev.options.map((opt) => [opt.value, opt]))\n const occupied = new Set<string>()\n Object.entries(prev.labelToId).forEach(([label, id]) => {\n occupied.add(label)\n labelToId[label] = id\n })\n records.forEach((record) => {\n if (!isUuid(record.id)) return\n const base = buildPersonLabel(record)\n let previousLabel = idToLabel[record.id]\n if (previousLabel) {\n // remove previous label before reassigning\n delete labelToId[previousLabel]\n occupied.delete(previousLabel)\n }\n const label = ensureUniqueLabel(base, occupied)\n idToLabel[record.id] = label\n labelToId[label] = record.id\n const option = { value: record.id, label }\n merged.set(record.id, option)\n queryMap.set(record.id, option)\n })\n const nextOptions = Array.from(merged.values()).sort((a, b) => a.label.localeCompare(b.label))\n return { options: nextOptions, idToLabel, labelToId }\n })\n return Array.from(queryMap.values()).sort((a, b) => a.label.localeCompare(b.label))\n }, [buildPersonLabel])\n\n const ingestCompanyRecords = React.useCallback((records: CompanyLookupRecord[]) => {\n if (!records.length) return [] as FilterOption[]\n const queryMap = new Map<string, FilterOption>()\n setCompaniesState((prev) => {\n const idToLabel = { ...prev.idToLabel }\n const labelToId: Record<string, string> = {}\n const merged = new Map(prev.options.map((opt) => [opt.value, opt]))\n const occupied = new Set<string>()\n Object.entries(prev.labelToId).forEach(([label, id]) => {\n occupied.add(label)\n labelToId[label] = id\n })\n records.forEach((record) => {\n if (!isUuid(record.id)) return\n const base = buildCompanyLabel(record)\n let previousLabel = idToLabel[record.id]\n if (previousLabel) {\n delete labelToId[previousLabel]\n occupied.delete(previousLabel)\n }\n const label = ensureUniqueLabel(base, occupied)\n idToLabel[record.id] = label\n labelToId[label] = record.id\n const option = { value: record.id, label }\n merged.set(record.id, option)\n queryMap.set(record.id, option)\n })\n const nextOptions = Array.from(merged.values()).sort((a, b) => a.label.localeCompare(b.label))\n return { options: nextOptions, idToLabel, labelToId }\n })\n return Array.from(queryMap.values()).sort((a, b) => a.label.localeCompare(b.label))\n }, [buildCompanyLabel])\n\n const loadPeopleOptions = React.useCallback(async (query?: string) => {\n const normalizedQuery = (query || '').trim().toLowerCase()\n const cacheKey = `${scopeVersion}|${normalizedQuery}`\n const cached = peopleCacheRef.current.get(cacheKey)\n if (cached) return cached\n const records = await fetchPeopleLookup(query)\n const options = ingestPeopleRecords(records)\n peopleCacheRef.current.set(cacheKey, options)\n return options\n }, [scopeVersion, ingestPeopleRecords])\n\n const loadCompanyOptions = React.useCallback(async (query?: string) => {\n const normalizedQuery = (query || '').trim().toLowerCase()\n const cacheKey = `${scopeVersion}|${normalizedQuery}`\n const cached = companiesCacheRef.current.get(cacheKey)\n if (cached) return cached\n const records = await fetchCompaniesLookup(query)\n const options = ingestCompanyRecords(records)\n companiesCacheRef.current.set(cacheKey, options)\n return options\n }, [scopeVersion, ingestCompanyRecords])\n\n React.useEffect(() => {\n let cancelled = false\n if (!selectedPersonIds.length) return\n const missing = selectedPersonIds.filter((id) => !peopleState.idToLabel[id])\n if (!missing.length) return\n fetchPeopleLookupByIds(missing).then((records) => {\n if (cancelled) return\n ingestPeopleRecords(records)\n })\n return () => { cancelled = true }\n }, [selectedPersonIds, peopleState.idToLabel, ingestPeopleRecords])\n\n React.useEffect(() => {\n let cancelled = false\n if (!selectedCompanyIds.length) return\n const missing = selectedCompanyIds.filter((id) => !companiesState.idToLabel[id])\n if (!missing.length) return\n fetchCompaniesLookupByIds(missing).then((records) => {\n if (cancelled) return\n ingestCompanyRecords(records)\n })\n return () => { cancelled = true }\n }, [selectedCompanyIds, companiesState.idToLabel, ingestCompanyRecords])\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\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 {}\n }\n loadPipelines().catch(() => {})\n return () => { cancelled = true }\n }, [reloadToken, scopeVersion])\n\n React.useEffect(() => {\n peopleCacheRef.current.clear()\n companiesCacheRef.current.clear()\n setPeopleState((prev) => {\n if (!prev.options.length && !Object.keys(prev.idToLabel).length) return prev\n return { ...EMPTY_OPTIONS_STATE }\n })\n setCompaniesState((prev) => {\n if (!prev.options.length && !Object.keys(prev.idToLabel).length) return prev\n return { ...EMPTY_OPTIONS_STATE }\n })\n }, [scopeVersion, reloadToken])\n\n const syncFilterLabels = React.useCallback((\n key: 'people' | 'companies',\n ids: string[],\n idToLabel: Record<string, string>,\n ) => {\n setFilterValues((prev) => {\n const current = Array.isArray(prev[key]) ? (prev[key] as string[]) : []\n if (!ids.length) {\n if (!current.length) return prev\n const next = { ...prev }\n delete next[key]\n return next\n }\n const labels: string[] = []\n ids.forEach((id) => {\n const label = idToLabel[id]\n if (label && !labels.includes(label)) labels.push(label)\n })\n if (labels.length < ids.length) return prev\n if (arraysEqual(current, labels)) return prev\n return { ...prev, [key]: labels }\n })\n }, [])\n\n React.useEffect(() => {\n syncFilterLabels('people', selectedPersonIds, peopleState.idToLabel)\n }, [selectedPersonIds, peopleState.idToLabel, syncFilterLabels])\n\n React.useEffect(() => {\n syncFilterLabels('companies', selectedCompanyIds, companiesState.idToLabel)\n }, [selectedCompanyIds, companiesState.idToLabel, syncFilterLabels])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value.trim())\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = { ...values }\n const rawPeople = Array.isArray(values.people) ? (values.people as string[]) : []\n const nextPersonIds: string[] = []\n rawPeople.forEach((value) => {\n const trimmed = typeof value === 'string' ? value.trim() : ''\n if (!trimmed) return\n const mapped = peopleState.labelToId[trimmed]\n if (mapped && !nextPersonIds.includes(mapped)) nextPersonIds.push(mapped)\n })\n setSelectedPersonIds(nextPersonIds)\n if (nextPersonIds.length) {\n next.people = Array.from(new Set(rawPeople.map((value) => (typeof value === 'string' ? value.trim() : '')).filter((value) => value.length > 0)))\n } else {\n delete next.people\n }\n\n const rawCompanies = Array.isArray(values.companies) ? (values.companies as string[]) : []\n const nextCompanyIds: string[] = []\n rawCompanies.forEach((value) => {\n const trimmed = typeof value === 'string' ? value.trim() : ''\n if (!trimmed) return\n const mapped = companiesState.labelToId[trimmed]\n if (mapped && !nextCompanyIds.includes(mapped)) nextCompanyIds.push(mapped)\n })\n setSelectedCompanyIds(nextCompanyIds)\n if (nextCompanyIds.length) {\n next.companies = Array.from(new Set(rawCompanies.map((value) => (typeof value === 'string' ? value.trim() : '')).filter((value) => value.length > 0)))\n } else {\n delete next.companies\n }\n\n setFilterValues(next)\n setPage(1)\n }, [peopleState.labelToId, companiesState.labelToId])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setSelectedPersonIds([])\n setSelectedCompanyIds([])\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 Object.entries(filterValues).forEach(([key, value]) => {\n if (key === 'people' || key === 'companies') return\n if (value == null) return\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (normalized.length) params.set(key, normalized.join(','))\n } else if (typeof value === 'object') {\n const obj = value as Record<string, unknown>\n const from = typeof obj.from === 'string' ? obj.from.trim() : ''\n const to = typeof obj.to === 'string' ? obj.to.trim() : ''\n if (from) params.set(`${key}[from]`, from)\n if (to) params.set(`${key}[to]`, to)\n } else {\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (stringValue) params.set(key, stringValue)\n }\n })\n const advancedParams = serializeAdvancedFilter(advancedFilterState)\n for (const [key, val] of Object.entries(advancedParams)) {\n params.set(key, val)\n }\n return params.toString()\n }, [advancedFilterState, filterValues, 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 } 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 if (totalPages > 0 && page > totalPages) {\n setPage(totalPages)\n }\n }, [page, totalPages])\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 (page > 1) params.set('page', String(page))\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])\n\n const handleRefresh = React.useCallback(() => {\n peopleCacheRef.current.clear()\n companiesCacheRef.current.clear()\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 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 setPendingDeleteId(dealId)\n try {\n await deleteCrud('customers/deals', {\n body: { id: dealId },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\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 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, t],\n )\n\n const handlePageSizeChange = React.useCallback((newSize: number) => {\n setPageSize(newSize)\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 let deletedCount = 0\n for (const row of selectedRows) {\n try {\n await deleteCrud('customers/deals', {\n body: { id: row.id },\n errorMessage: t('customers.deals.list.deleteError', 'Failed to delete deal.'),\n })\n deletedCount++\n } catch {}\n }\n if (deletedCount > 0) {\n setRows((prev) => {\n const deletedIds = new Set(selectedRows.map((r) => r.id))\n return prev.filter((r) => !deletedIds.has(r.id))\n })\n setTotal((prev) => Math.max(0, prev - deletedCount))\n flash(t('customers.deals.list.bulkDelete.success', '{count} deals deleted', { count: deletedCount }), 'success')\n }\n return deletedCount > 0\n }, [confirm, t])\n\n const personOptions = peopleState.options\n const companyOptions = companiesState.options\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'people',\n label: t('customers.deals.list.filters.people'),\n type: 'tags',\n options: personOptions,\n loadOptions: loadPeopleOptions,\n placeholder: t('customers.deals.list.filters.peoplePlaceholder'),\n },\n {\n id: 'companies',\n label: t('customers.deals.list.filters.companies'),\n type: 'tags',\n options: companyOptions,\n loadOptions: loadCompanyOptions,\n placeholder: t('customers.deals.list.filters.companiesPlaceholder'),\n },\n ], [companyOptions, loadCompanyOptions, loadPeopleOptions, personOptions, t])\n\n const { data: customFieldDefs = [] } = useCustomFieldDefs([E.customers.customer_deal], {\n keyExtras: [scopeVersion, reloadToken],\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 renderDictionaryCell = (kind: DictionaryKey, value: string | null | undefined) => (\n <DictionaryValue\n value={value}\n map={dictionaryMaps[kind]}\n fallback={value ? <span className=\"text-sm\">{value}</span> : noValue}\n className=\"text-sm\"\n iconWrapperClassName=\"inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-card\"\n iconClassName=\"h-4 w-4\"\n colorClassName=\"h-3 w-3 rounded-full\"\n />\n )\n const renderAssociationList = (\n items: { id: string; label: string }[],\n fallbackLabel: string,\n ) => {\n if (!items.length) return noValue\n return (\n <ul className=\"flex flex-wrap gap-1 text-sm\">\n {items.map((entry) => (\n <li key={entry.id} className=\"rounded border px-2 py-0.5 text-xs bg-muted\">\n {entry.label && entry.label.trim().length ? entry.label : fallbackLabel}\n </li>\n ))}\n </ul>\n )\n }\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 ?? 'Custom Fields',\n filterGroup: def.group?.title ?? 'Custom Fields',\n filterType: mapCustomFieldKindToFilterType(def.kind),\n filterOptions: normalizeCustomFieldFilterOptions(def.options),\n hidden: def.listVisible === false,\n },\n cell: ({ getValue }) => {\n const value = getValue()\n if (value == null) return noValue\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (!normalized.length) return noValue\n return <span className=\"text-sm\">{normalized.join(', ')}</span>\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: { alwaysVisible: true, columnChooserGroup: 'Basic Info', filterKey: 'title' },\n cell: ({ row }) => <span className=\"font-medium text-sm\">{row.original.title}</span>,\n },\n {\n accessorKey: 'status',\n header: t('customers.deals.list.columns.status'),\n meta: { filterType: 'select' as const, columnChooserGroup: 'Basic Info', filterKey: 'status' },\n cell: ({ row }) => renderDictionaryCell('deal-statuses', row.original.status),\n },\n {\n accessorKey: 'pipelineStage',\n header: t('customers.deals.list.columns.pipelineStage'),\n meta: { columnChooserGroup: 'Pipeline', filterKey: 'pipeline_stage' },\n cell: ({ row }) => renderDictionaryCell('pipeline-stages', row.original.pipelineStage),\n },\n {\n accessorKey: 'pipelineId',\n header: t('customers.deals.list.columns.pipeline', 'Pipeline'),\n meta: { columnChooserGroup: 'Pipeline', filterKey: 'pipeline_id' },\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: { filterType: 'number' as const, columnChooserGroup: 'Financial', filterKey: 'value_amount' },\n cell: ({ row }) => (\n <span className=\"text-sm font-medium\">\n {formatCurrency(row.original.valueAmount ?? null, row.original.valueCurrency ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n {\n accessorKey: 'probability',\n header: t('customers.deals.list.columns.probability'),\n meta: { filterType: 'number' as const, columnChooserGroup: 'Financial', filterKey: 'probability' },\n cell: ({ row }) => {\n const value = row.original.probability\n if (typeof value === 'number' && Number.isFinite(value)) {\n return <span className=\"text-sm\">{`${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: { columnChooserGroup: 'Dates', filterKey: 'expected_close_at' },\n cell: ({ row }) => (\n <span className=\"text-sm\">\n {formatDateValue(row.original.expectedCloseAt ?? null, t('customers.deals.list.noValue'))}\n </span>\n ),\n },\n {\n accessorKey: 'companies',\n header: t('customers.deals.list.columns.companies'),\n meta: { columnChooserGroup: 'Associations', filterable: false },\n cell: ({ row }) => renderAssociationList(row.original.companies, t('customers.deals.list.unnamedCompany')),\n },\n {\n accessorKey: 'people',\n header: t('customers.deals.list.columns.people'),\n meta: { columnChooserGroup: 'Associations', filterable: false },\n cell: ({ row }) => renderAssociationList(row.original.people, t('customers.deals.list.unnamedPerson')),\n },\n {\n accessorKey: 'updatedAt',\n header: t('customers.deals.list.columns.updatedAt'),\n meta: { columnChooserGroup: 'Dates', filterKey: 'updated_at' },\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, pipelineNames, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable<DealRow>\n stickyFirstColumn\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 filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\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: 'customers.deals.list' }}\n advancedFilter={{\n auto: true,\n value: advancedFilterState,\n onChange: setAdvancedFilterState,\n onApply: () => { setPage(1) },\n onClear: () => { setAdvancedFilterState({ logic: 'and', conditions: [] }); setPage(1) },\n }}\n virtualized\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 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 people,\n companies,\n ...customFields,\n }, item)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["formatter"]
|
|
7
7
|
}
|