@open-mercato/core 0.10.1-develop.7761.1.9dfaf470ed → 0.10.1-develop.7762.1.657bb7236b
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/.turbo/turbo-build.log +1 -1
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +1 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +3 -2
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +11 -12
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +3 -2
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/create/page.js +6 -0
- package/dist/modules/customers/backend/customers/companies/create/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +25 -25
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js +8 -27
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +175 -171
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js +25 -24
- package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/create/page.js +9 -0
- package/dist/modules/customers/backend/customers/people/create/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +140 -144
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js +2 -0
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +13 -4
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/CreatePersonDialog.js +13 -3
- package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/CustomerDetailSidebar.js +29 -0
- package/dist/modules/customers/components/detail/CustomerDetailSidebar.js.map +7 -0
- package/dist/modules/customers/components/detail/DealDetailHeader.js +4 -2
- package/dist/modules/customers/components/detail/DealDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailTabs.js +9 -1
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +5 -0
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailHeader.js +2 -0
- package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +9 -1
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/create/CreateDealForm.js +160 -176
- package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/useCustomerInjectedTabs.js +47 -0
- package/dist/modules/customers/components/detail/useCustomerInjectedTabs.js.map +7 -0
- package/dist/modules/customers/components/formConfig.js +3 -0
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/extension-points.js +14 -4
- package/dist/modules/customers/extension-points.js.map +2 -2
- package/dist/modules/customers/lib/detailResponseEnrichment.js +38 -0
- package/dist/modules/customers/lib/detailResponseEnrichment.js.map +7 -0
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +4 -4
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -0
- package/src/modules/customers/api/companies/[id]/route.ts +3 -2
- package/src/modules/customers/api/deals/[id]/route.ts +12 -12
- package/src/modules/customers/api/people/[id]/route.ts +3 -2
- package/src/modules/customers/backend/customers/companies/create/page.tsx +6 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -30
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx +9 -44
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -3
- package/src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx +25 -27
- package/src/modules/customers/backend/customers/people/create/page.tsx +9 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +21 -33
- package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +3 -0
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +15 -4
- package/src/modules/customers/components/detail/CreatePersonDialog.tsx +15 -4
- package/src/modules/customers/components/detail/CustomerDetailSidebar.tsx +41 -0
- package/src/modules/customers/components/detail/DealDetailHeader.tsx +4 -1
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +11 -1
- package/src/modules/customers/components/detail/DealForm.tsx +5 -0
- package/src/modules/customers/components/detail/PersonDetailHeader.tsx +3 -0
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +11 -1
- package/src/modules/customers/components/detail/create/CreateDealForm.tsx +126 -209
- package/src/modules/customers/components/detail/useCustomerInjectedTabs.tsx +64 -0
- package/src/modules/customers/components/formConfig.tsx +3 -0
- package/src/modules/customers/extension-points.ts +14 -4
- package/src/modules/customers/lib/detailResponseEnrichment.ts +53 -0
- package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +4 -4
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
defineModuleExtensionPoints,
|
|
6
6
|
injectionExtensionHost
|
|
7
7
|
} from "@open-mercato/shared/modules/widgets/extension-points";
|
|
8
|
-
const detailHost = (spotId, source) => injectionExtensionHost({
|
|
8
|
+
const detailHost = (spotId, source, dataContract) => injectionExtensionHost({
|
|
9
9
|
family: "detail",
|
|
10
10
|
spotId,
|
|
11
11
|
supported: ["render-widget"],
|
|
12
12
|
contextContract: "customers.detail.v1",
|
|
13
|
+
dataContract,
|
|
13
14
|
source
|
|
14
15
|
});
|
|
15
16
|
const extensionPoints = defineModuleExtensionPoints({
|
|
@@ -19,9 +20,9 @@ const extensionPoints = defineModuleExtensionPoints({
|
|
|
19
20
|
dealsTable: dataTableExtensionHost({ tableId: "customers.deals.list", source: "backend/customers/deals/page.tsx" }),
|
|
20
21
|
peopleTable: dataTableExtensionHost({ tableId: "customers.people.list", source: "backend/customers/people/page.tsx" }),
|
|
21
22
|
todosTable: dataTableExtensionHost({ tableId: "customers.todos.list", source: "components/CustomerTodosTable.tsx" }),
|
|
22
|
-
companyForm: crudFormExtensionHost({ entityId: "customers.company", spotId: "crud-form:customers.company", source: "backend/customers/companies-v2/[id]/page.tsx" }),
|
|
23
|
-
dealForm: crudFormExtensionHost({ entityId: "customers.deal", spotId: "crud-form:customers.deal", source: "backend/customers/deals/[id]/page.tsx" }),
|
|
24
|
-
personForm: crudFormExtensionHost({ entityId: "customers.person", spotId: "crud-form:customers.person", source: "backend/customers/people-v2/[id]/page.tsx" }),
|
|
23
|
+
companyForm: crudFormExtensionHost({ entityId: "customers.company", spotId: "crud-form:customers.company", source: ["backend/customers/companies-v2/[id]/page.tsx", "backend/customers/companies/create/page.tsx"] }),
|
|
24
|
+
dealForm: crudFormExtensionHost({ entityId: "customers.deal", spotId: "crud-form:customers.deal", source: ["backend/customers/deals/[id]/page.tsx", "components/detail/create/CreateDealForm.tsx", "backend/customers/deals/pipeline/components/QuickDealDialog.tsx"] }),
|
|
25
|
+
personForm: crudFormExtensionHost({ entityId: "customers.person", spotId: "crud-form:customers.person", source: ["backend/customers/people-v2/[id]/page.tsx", "backend/customers/people/create/page.tsx", "components/detail/CreatePersonDialog.tsx"] }),
|
|
25
26
|
calendarEventTypes: injectionExtensionHost({
|
|
26
27
|
family: "generic",
|
|
27
28
|
spotId: "calendar:customers.event-types",
|
|
@@ -34,13 +35,22 @@ const extensionPoints = defineModuleExtensionPoints({
|
|
|
34
35
|
propsContract: "customers.calendar.event-type-panel.v1",
|
|
35
36
|
source: "components/calendar/editor/EventTypePanel.tsx"
|
|
36
37
|
}),
|
|
38
|
+
companyHeaderActions: detailHost("detail:customers.company:header-actions", "backend/customers/companies-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
39
|
+
companySidebar: detailHost("detail:customers.company:sidebar", "backend/customers/companies-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
40
|
+
companyTabs: detailHost("detail:customers.company:tabs", "backend/customers/companies-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
37
41
|
companyHeader: detailHost("detail:customers.company:header", "backend/customers/companies-v2/[id]/page.tsx"),
|
|
38
42
|
companyStatusBadges: detailHost("detail:customers.company:status-badges", "backend/customers/companies-v2/[id]/page.tsx"),
|
|
39
43
|
companyFooter: detailHost("detail:customers.company:footer", "backend/customers/companies-v2/[id]/page.tsx"),
|
|
40
44
|
companyLegacyDetails: detailHost("customers.company.detail:details", "backend/customers/companies/[id]/page.tsx"),
|
|
45
|
+
dealHeaderActions: detailHost("detail:customers.deal:header-actions", "backend/customers/deals/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
46
|
+
dealSidebar: detailHost("detail:customers.deal:sidebar", "backend/customers/deals/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
47
|
+
dealTabs: detailHost("detail:customers.deal:tabs", "backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx", "customers.detail.overview.v1"),
|
|
41
48
|
dealHeader: detailHost("detail:customers.deal:header", "backend/customers/deals/[id]/page.tsx"),
|
|
42
49
|
dealStatusBadges: detailHost("detail:customers.deal:status-badges", "backend/customers/deals/[id]/page.tsx"),
|
|
43
50
|
dealFooter: detailHost("detail:customers.deal:footer", "backend/customers/deals/[id]/page.tsx"),
|
|
51
|
+
personHeaderActions: detailHost("detail:customers.person:header-actions", "backend/customers/people-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
52
|
+
personSidebar: detailHost("detail:customers.person:sidebar", "backend/customers/people-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
53
|
+
personTabs: detailHost("detail:customers.person:tabs", "backend/customers/people-v2/[id]/page.tsx", "customers.detail.overview.v1"),
|
|
44
54
|
personHeader: detailHost("detail:customers.person:header", "backend/customers/people-v2/[id]/page.tsx"),
|
|
45
55
|
personStatusBadges: detailHost("detail:customers.person:status-badges", "backend/customers/people-v2/[id]/page.tsx"),
|
|
46
56
|
personFooter: detailHost("detail:customers.person:footer", "backend/customers/people-v2/[id]/page.tsx"),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/customers/extension-points.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n componentExtensionHost,\n crudFormExtensionHost,\n dataTableExtensionHost,\n defineModuleExtensionPoints,\n injectionExtensionHost,\n} from '@open-mercato/shared/modules/widgets/extension-points'\n\nconst detailHost = (spotId: string, source: string) => injectionExtensionHost({\n family: 'detail',\n spotId,\n supported: ['render-widget'],\n contextContract: 'customers.detail.v1',\n source,\n})\n\nexport const extensionPoints = defineModuleExtensionPoints({\n moduleId: 'customers',\n hosts: {\n companiesTable: dataTableExtensionHost({ tableId: 'customers.companies.list', source: 'backend/customers/companies/page.tsx' }),\n dealsTable: dataTableExtensionHost({ tableId: 'customers.deals.list', source: 'backend/customers/deals/page.tsx' }),\n peopleTable: dataTableExtensionHost({ tableId: 'customers.people.list', source: 'backend/customers/people/page.tsx' }),\n todosTable: dataTableExtensionHost({ tableId: 'customers.todos.list', source: 'components/CustomerTodosTable.tsx' }),\n companyForm: crudFormExtensionHost({ entityId: 'customers.company', spotId: 'crud-form:customers.company', source: 'backend/customers/companies-v2/[id]/page.tsx' }),\n dealForm: crudFormExtensionHost({ entityId: 'customers.deal', spotId: 'crud-form:customers.deal', source: 'backend/customers/deals/[id]/page.tsx' }),\n personForm: crudFormExtensionHost({ entityId: 'customers.person', spotId: 'crud-form:customers.person', source: 'backend/customers/people-v2/[id]/page.tsx' }),\n calendarEventTypes: injectionExtensionHost({\n family: 'generic',\n spotId: 'calendar:customers.event-types',\n supported: ['headless-widget', 'registry-contribution'],\n dataContract: 'customers.calendar.event-types.v1',\n source: 'lib/calendar/eventTypeResolver.ts',\n }),\n calendarEventTypePanel: componentExtensionHost({\n componentId: 'section:customers.calendar-event-editor.type-panel',\n propsContract: 'customers.calendar.event-type-panel.v1',\n source: 'components/calendar/editor/EventTypePanel.tsx',\n }),\n companyHeader: detailHost('detail:customers.company:header', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyStatusBadges: detailHost('detail:customers.company:status-badges', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyFooter: detailHost('detail:customers.company:footer', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyLegacyDetails: detailHost('customers.company.detail:details', 'backend/customers/companies/[id]/page.tsx'),\n dealHeader: detailHost('detail:customers.deal:header', 'backend/customers/deals/[id]/page.tsx'),\n dealStatusBadges: detailHost('detail:customers.deal:status-badges', 'backend/customers/deals/[id]/page.tsx'),\n dealFooter: detailHost('detail:customers.deal:footer', 'backend/customers/deals/[id]/page.tsx'),\n personHeader: detailHost('detail:customers.person:header', 'backend/customers/people-v2/[id]/page.tsx'),\n personStatusBadges: detailHost('detail:customers.person:status-badges', 'backend/customers/people-v2/[id]/page.tsx'),\n personFooter: detailHost('detail:customers.person:footer', 'backend/customers/people-v2/[id]/page.tsx'),\n personLegacyDetails: detailHost('customers.person.detail:details', 'backend/customers/people/[id]/page.tsx'),\n },\n})\n\nexport default extensionPoints\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,aAAa,CAAC,QAAgB,
|
|
4
|
+
"sourcesContent": ["import {\n componentExtensionHost,\n crudFormExtensionHost,\n dataTableExtensionHost,\n defineModuleExtensionPoints,\n injectionExtensionHost,\n} from '@open-mercato/shared/modules/widgets/extension-points'\n\nconst detailHost = (spotId: string, source: string, dataContract?: string) => injectionExtensionHost({\n family: 'detail',\n spotId,\n supported: ['render-widget'],\n contextContract: 'customers.detail.v1',\n dataContract,\n source,\n})\n\nexport const extensionPoints = defineModuleExtensionPoints({\n moduleId: 'customers',\n hosts: {\n companiesTable: dataTableExtensionHost({ tableId: 'customers.companies.list', source: 'backend/customers/companies/page.tsx' }),\n dealsTable: dataTableExtensionHost({ tableId: 'customers.deals.list', source: 'backend/customers/deals/page.tsx' }),\n peopleTable: dataTableExtensionHost({ tableId: 'customers.people.list', source: 'backend/customers/people/page.tsx' }),\n todosTable: dataTableExtensionHost({ tableId: 'customers.todos.list', source: 'components/CustomerTodosTable.tsx' }),\n companyForm: crudFormExtensionHost({ entityId: 'customers.company', spotId: 'crud-form:customers.company', source: ['backend/customers/companies-v2/[id]/page.tsx', 'backend/customers/companies/create/page.tsx'] }),\n dealForm: crudFormExtensionHost({ entityId: 'customers.deal', spotId: 'crud-form:customers.deal', source: ['backend/customers/deals/[id]/page.tsx', 'components/detail/create/CreateDealForm.tsx', 'backend/customers/deals/pipeline/components/QuickDealDialog.tsx'] }),\n personForm: crudFormExtensionHost({ entityId: 'customers.person', spotId: 'crud-form:customers.person', source: ['backend/customers/people-v2/[id]/page.tsx', 'backend/customers/people/create/page.tsx', 'components/detail/CreatePersonDialog.tsx'] }),\n calendarEventTypes: injectionExtensionHost({\n family: 'generic',\n spotId: 'calendar:customers.event-types',\n supported: ['headless-widget', 'registry-contribution'],\n dataContract: 'customers.calendar.event-types.v1',\n source: 'lib/calendar/eventTypeResolver.ts',\n }),\n calendarEventTypePanel: componentExtensionHost({\n componentId: 'section:customers.calendar-event-editor.type-panel',\n propsContract: 'customers.calendar.event-type-panel.v1',\n source: 'components/calendar/editor/EventTypePanel.tsx',\n }),\n companyHeaderActions: detailHost('detail:customers.company:header-actions', 'backend/customers/companies-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n companySidebar: detailHost('detail:customers.company:sidebar', 'backend/customers/companies-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n companyTabs: detailHost('detail:customers.company:tabs', 'backend/customers/companies-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n companyHeader: detailHost('detail:customers.company:header', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyStatusBadges: detailHost('detail:customers.company:status-badges', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyFooter: detailHost('detail:customers.company:footer', 'backend/customers/companies-v2/[id]/page.tsx'),\n companyLegacyDetails: detailHost('customers.company.detail:details', 'backend/customers/companies/[id]/page.tsx'),\n dealHeaderActions: detailHost('detail:customers.deal:header-actions', 'backend/customers/deals/[id]/page.tsx', 'customers.detail.overview.v1'),\n dealSidebar: detailHost('detail:customers.deal:sidebar', 'backend/customers/deals/[id]/page.tsx', 'customers.detail.overview.v1'),\n dealTabs: detailHost('detail:customers.deal:tabs', 'backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx', 'customers.detail.overview.v1'),\n dealHeader: detailHost('detail:customers.deal:header', 'backend/customers/deals/[id]/page.tsx'),\n dealStatusBadges: detailHost('detail:customers.deal:status-badges', 'backend/customers/deals/[id]/page.tsx'),\n dealFooter: detailHost('detail:customers.deal:footer', 'backend/customers/deals/[id]/page.tsx'),\n personHeaderActions: detailHost('detail:customers.person:header-actions', 'backend/customers/people-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n personSidebar: detailHost('detail:customers.person:sidebar', 'backend/customers/people-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n personTabs: detailHost('detail:customers.person:tabs', 'backend/customers/people-v2/[id]/page.tsx', 'customers.detail.overview.v1'),\n personHeader: detailHost('detail:customers.person:header', 'backend/customers/people-v2/[id]/page.tsx'),\n personStatusBadges: detailHost('detail:customers.person:status-badges', 'backend/customers/people-v2/[id]/page.tsx'),\n personFooter: detailHost('detail:customers.person:footer', 'backend/customers/people-v2/[id]/page.tsx'),\n personLegacyDetails: detailHost('customers.person.detail:details', 'backend/customers/people/[id]/page.tsx'),\n },\n})\n\nexport default extensionPoints\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,aAAa,CAAC,QAAgB,QAAgB,iBAA0B,uBAAuB;AAAA,EACnG,QAAQ;AAAA,EACR;AAAA,EACA,WAAW,CAAC,eAAe;AAAA,EAC3B,iBAAiB;AAAA,EACjB;AAAA,EACA;AACF,CAAC;AAEM,MAAM,kBAAkB,4BAA4B;AAAA,EACzD,UAAU;AAAA,EACV,OAAO;AAAA,IACL,gBAAgB,uBAAuB,EAAE,SAAS,4BAA4B,QAAQ,uCAAuC,CAAC;AAAA,IAC9H,YAAY,uBAAuB,EAAE,SAAS,wBAAwB,QAAQ,mCAAmC,CAAC;AAAA,IAClH,aAAa,uBAAuB,EAAE,SAAS,yBAAyB,QAAQ,oCAAoC,CAAC;AAAA,IACrH,YAAY,uBAAuB,EAAE,SAAS,wBAAwB,QAAQ,oCAAoC,CAAC;AAAA,IACnH,aAAa,sBAAsB,EAAE,UAAU,qBAAqB,QAAQ,+BAA+B,QAAQ,CAAC,gDAAgD,6CAA6C,EAAE,CAAC;AAAA,IACpN,UAAU,sBAAsB,EAAE,UAAU,kBAAkB,QAAQ,4BAA4B,QAAQ,CAAC,yCAAyC,+CAA+C,iEAAiE,EAAE,CAAC;AAAA,IACvQ,YAAY,sBAAsB,EAAE,UAAU,oBAAoB,QAAQ,8BAA8B,QAAQ,CAAC,6CAA6C,4CAA4C,0CAA0C,EAAE,CAAC;AAAA,IACvP,oBAAoB,uBAAuB;AAAA,MACzC,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW,CAAC,mBAAmB,uBAAuB;AAAA,MACtD,cAAc;AAAA,MACd,QAAQ;AAAA,IACV,CAAC;AAAA,IACD,wBAAwB,uBAAuB;AAAA,MAC7C,aAAa;AAAA,MACb,eAAe;AAAA,MACf,QAAQ;AAAA,IACV,CAAC;AAAA,IACD,sBAAsB,WAAW,2CAA2C,gDAAgD,8BAA8B;AAAA,IAC1J,gBAAgB,WAAW,oCAAoC,gDAAgD,8BAA8B;AAAA,IAC7I,aAAa,WAAW,iCAAiC,gDAAgD,8BAA8B;AAAA,IACvI,eAAe,WAAW,mCAAmC,8CAA8C;AAAA,IAC3G,qBAAqB,WAAW,0CAA0C,8CAA8C;AAAA,IACxH,eAAe,WAAW,mCAAmC,8CAA8C;AAAA,IAC3G,sBAAsB,WAAW,oCAAoC,2CAA2C;AAAA,IAChH,mBAAmB,WAAW,wCAAwC,yCAAyC,8BAA8B;AAAA,IAC7I,aAAa,WAAW,iCAAiC,yCAAyC,8BAA8B;AAAA,IAChI,UAAU,WAAW,8BAA8B,8DAA8D,8BAA8B;AAAA,IAC/I,YAAY,WAAW,gCAAgC,uCAAuC;AAAA,IAC9F,kBAAkB,WAAW,uCAAuC,uCAAuC;AAAA,IAC3G,YAAY,WAAW,gCAAgC,uCAAuC;AAAA,IAC9F,qBAAqB,WAAW,0CAA0C,6CAA6C,8BAA8B;AAAA,IACrJ,eAAe,WAAW,mCAAmC,6CAA6C,8BAA8B;AAAA,IACxI,YAAY,WAAW,gCAAgC,6CAA6C,8BAA8B;AAAA,IAClI,cAAc,WAAW,kCAAkC,2CAA2C;AAAA,IACtG,oBAAoB,WAAW,yCAAyC,2CAA2C;AAAA,IACnH,cAAc,WAAW,kCAAkC,2CAA2C;AAAA,IACtG,qBAAqB,WAAW,mCAAmC,wCAAwC;AAAA,EAC7G;AACF,CAAC;AAED,IAAO,2BAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getEnrichersForEntity } from "@open-mercato/shared/lib/crud/enricher-registry";
|
|
2
|
+
import { applyResponseEnricherToRecord } from "@open-mercato/shared/lib/crud/enricher-runner";
|
|
3
|
+
import { extractResponseEnricherNamespaces } from "@open-mercato/shared/lib/crud/response-enricher-namespaces";
|
|
4
|
+
async function enrichCustomerDetailResponse(payload, recordKey, context) {
|
|
5
|
+
if (getEnrichersForEntity(`customers.${recordKey}`).length === 0) return payload;
|
|
6
|
+
const clonedPayload = structuredClone(payload);
|
|
7
|
+
const mainRecord = clonedPayload[recordKey];
|
|
8
|
+
if (!context.tenantId || !context.organizationId || !mainRecord || typeof mainRecord !== "object" || Array.isArray(mainRecord)) {
|
|
9
|
+
return clonedPayload;
|
|
10
|
+
}
|
|
11
|
+
let userFeatures;
|
|
12
|
+
try {
|
|
13
|
+
const rbac = context.container.resolve("rbacService");
|
|
14
|
+
if (rbac?.getGrantedFeatures) {
|
|
15
|
+
userFeatures = await rbac.getGrantedFeatures(context.auth.sub, {
|
|
16
|
+
tenantId: context.tenantId,
|
|
17
|
+
organizationId: context.organizationId
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
} catch {
|
|
21
|
+
userFeatures = void 0;
|
|
22
|
+
}
|
|
23
|
+
const record = mainRecord;
|
|
24
|
+
const result = await applyResponseEnricherToRecord(structuredClone(record), `customers.${recordKey}`, {
|
|
25
|
+
tenantId: context.tenantId,
|
|
26
|
+
organizationId: context.organizationId,
|
|
27
|
+
userId: context.auth.sub,
|
|
28
|
+
em: context.em,
|
|
29
|
+
container: context.container,
|
|
30
|
+
userFeatures
|
|
31
|
+
});
|
|
32
|
+
const namespaces = extractResponseEnricherNamespaces(result.record);
|
|
33
|
+
return { ...clonedPayload, ...namespaces, [recordKey]: { ...record, ...namespaces } };
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
enrichCustomerDetailResponse
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=detailResponseEnrichment.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/detailResponseEnrichment.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { getEnrichersForEntity } from '@open-mercato/shared/lib/crud/enricher-registry'\nimport { applyResponseEnricherToRecord } from '@open-mercato/shared/lib/crud/enricher-runner'\nimport { extractResponseEnricherNamespaces } from '@open-mercato/shared/lib/crud/response-enricher-namespaces'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\n\ntype DetailRecordKey = 'person' | 'company' | 'deal'\n\ntype DetailEnrichmentContext = {\n auth: NonNullable<AuthContext>\n container: AppContainer\n em: EntityManager\n tenantId: string | null\n organizationId: string | null\n}\n\nexport async function enrichCustomerDetailResponse<T extends Record<string, unknown>>(\n payload: T,\n recordKey: DetailRecordKey,\n context: DetailEnrichmentContext,\n): Promise<T> {\n if (getEnrichersForEntity(`customers.${recordKey}`).length === 0) return payload\n const clonedPayload = structuredClone(payload)\n const mainRecord = clonedPayload[recordKey]\n if (!context.tenantId || !context.organizationId || !mainRecord || typeof mainRecord !== 'object' || Array.isArray(mainRecord)) {\n return clonedPayload\n }\n let userFeatures: string[] | undefined\n try {\n const rbac = context.container.resolve<RbacService>('rbacService')\n if (rbac?.getGrantedFeatures) {\n userFeatures = await rbac.getGrantedFeatures(context.auth.sub, {\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n })\n }\n } catch {\n userFeatures = undefined\n }\n const record = mainRecord as Record<string, unknown>\n const result = await applyResponseEnricherToRecord(structuredClone(record), `customers.${recordKey}`, {\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n userId: context.auth.sub,\n em: context.em,\n container: context.container,\n userFeatures,\n })\n const namespaces = extractResponseEnricherNamespaces(result.record)\n return { ...clonedPayload, ...namespaces, [recordKey]: { ...record, ...namespaces } }\n}\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,6BAA6B;AACtC,SAAS,qCAAqC;AAC9C,SAAS,yCAAyC;AAalD,eAAsB,6BACpB,SACA,WACA,SACY;AACZ,MAAI,sBAAsB,aAAa,SAAS,EAAE,EAAE,WAAW,EAAG,QAAO;AACzE,QAAM,gBAAgB,gBAAgB,OAAO;AAC7C,QAAM,aAAa,cAAc,SAAS;AAC1C,MAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,kBAAkB,CAAC,cAAc,OAAO,eAAe,YAAY,MAAM,QAAQ,UAAU,GAAG;AAC9H,WAAO;AAAA,EACT;AACA,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,QAAQ,UAAU,QAAqB,aAAa;AACjE,QAAI,MAAM,oBAAoB;AAC5B,qBAAe,MAAM,KAAK,mBAAmB,QAAQ,KAAK,KAAK;AAAA,QAC7D,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF,QAAQ;AACN,mBAAe;AAAA,EACjB;AACA,QAAM,SAAS;AACf,QAAM,SAAS,MAAM,8BAA8B,gBAAgB,MAAM,GAAG,aAAa,SAAS,IAAI;AAAA,IACpG,UAAU,QAAQ;AAAA,IAClB,gBAAgB,QAAQ;AAAA,IACxB,QAAQ,QAAQ,KAAK;AAAA,IACrB,IAAI,QAAQ;AAAA,IACZ,WAAW,QAAQ;AAAA,IACnB;AAAA,EACF,CAAC;AACD,QAAM,aAAa,kCAAkC,OAAO,MAAM;AAClE,SAAO,EAAE,GAAG,eAAe,GAAG,YAAY,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,GAAG,WAAW,EAAE;AACtF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -13,7 +13,7 @@ function SyncStatusBadge({ status, lastSynced }) {
|
|
|
13
13
|
const t = useT();
|
|
14
14
|
const config = SYNC_STATUS_STYLES[status];
|
|
15
15
|
const label = t(config.label, status);
|
|
16
|
-
return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
16
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
17
17
|
/* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", config.dot), "aria-hidden": "true" }),
|
|
18
18
|
/* @__PURE__ */ jsx("span", { children: label }),
|
|
19
19
|
lastSynced && /* @__PURE__ */ jsx("span", { title: lastSynced, children: new Date(lastSynced).toLocaleDateString() })
|
|
@@ -36,16 +36,16 @@ function ExternalIdsWidget({ data }) {
|
|
|
36
36
|
{
|
|
37
37
|
className: "flex items-center justify-between gap-2 rounded-md bg-muted/50 px-3 py-2",
|
|
38
38
|
children: [
|
|
39
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2
|
|
39
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-2", children: [
|
|
40
40
|
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: getIntegrationTitle(integrationId) }),
|
|
41
|
-
/* @__PURE__ */ jsx("code", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-mono text-muted-foreground", children: mapping.externalId }),
|
|
41
|
+
/* @__PURE__ */ jsx("code", { className: "min-w-0 max-w-full break-all rounded bg-muted px-1.5 py-0.5 text-xs font-mono text-muted-foreground", children: mapping.externalId }),
|
|
42
42
|
mapping.externalUrl && /* @__PURE__ */ jsx(
|
|
43
43
|
"a",
|
|
44
44
|
{
|
|
45
45
|
href: mapping.externalUrl,
|
|
46
46
|
target: "_blank",
|
|
47
47
|
rel: "noopener noreferrer",
|
|
48
|
-
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
48
|
+
className: "shrink-0 text-muted-foreground hover:text-foreground transition-colors",
|
|
49
49
|
"aria-label": t("integrations.externalIds.openExternal", "Open in external system"),
|
|
50
50
|
children: /* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
51
51
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/integrations/widgets/injection/external-ids/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport type { ExternalIdMapping } from '@open-mercato/shared/modules/integrations/types'\nimport { getIntegrationTitle } from '@open-mercato/shared/modules/integrations/types'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype IntegrationsData = Record<string, ExternalIdMapping>\n\nconst SYNC_STATUS_STYLES: Record<ExternalIdMapping['syncStatus'], { dot: string; label: string }> = {\n synced: { dot: 'bg-status-success-icon', label: 'integrations.syncStatus.synced' },\n pending: { dot: 'bg-status-warning-icon', label: 'integrations.syncStatus.pending' },\n error: { dot: 'bg-status-error-icon', label: 'integrations.syncStatus.error' },\n not_synced: { dot: 'bg-status-neutral-icon', label: 'integrations.syncStatus.notSynced' },\n}\n\nfunction SyncStatusBadge({ status, lastSynced }: { status: ExternalIdMapping['syncStatus']; lastSynced?: string }) {\n const t = useT()\n const config = SYNC_STATUS_STYLES[status]\n const label = t(config.label, status)\n\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\">\n <span className={cn('inline-block size-1.5 rounded-full', config.dot)} aria-hidden=\"true\" />\n <span>{label}</span>\n {lastSynced && (\n <span title={lastSynced}>\n {new Date(lastSynced).toLocaleDateString()}\n </span>\n )}\n </span>\n )\n}\n\nfunction ExternalLinkIcon() {\n return (\n <svg className=\"size-3.5\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <path d=\"M6.5 3.5H3a1 1 0 0 0-1 1V13a1 1 0 0 0 1 1h8.5a1 1 0 0 0 1-1V9.5\" />\n <path d=\"M9.5 2h4.5v4.5M14 2 7.5 8.5\" />\n </svg>\n )\n}\n\nexport default function ExternalIdsWidget({ data }: InjectionWidgetComponentProps) {\n const t = useT()\n const integrations = (data as Record<string, unknown>)?._integrations as IntegrationsData | undefined\n\n if (!integrations || Object.keys(integrations).length === 0) return null\n\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <h3 className=\"mb-3 text-sm font-medium\">\n {t('integrations.externalIds.title', 'External IDs')}\n </h3>\n <div className=\"space-y-2\">\n {Object.entries(integrations).map(([integrationId, mapping]) => (\n <div\n key={integrationId}\n className=\"flex items-center justify-between gap-2 rounded-md bg-muted/50 px-3 py-2\"\n >\n <div className=\"flex items-center gap-2
|
|
5
|
-
"mappings": ";AAwBI,SACE,KADF;AAnBJ,SAAS,2BAA2B;AACpC,SAAS,YAAY;AACrB,SAAS,UAAU;AAInB,MAAM,qBAA8F;AAAA,EAClG,QAAQ,EAAE,KAAK,0BAA0B,OAAO,iCAAiC;AAAA,EACjF,SAAS,EAAE,KAAK,0BAA0B,OAAO,kCAAkC;AAAA,EACnF,OAAO,EAAE,KAAK,wBAAwB,OAAO,gCAAgC;AAAA,EAC7E,YAAY,EAAE,KAAK,0BAA0B,OAAO,oCAAoC;AAC1F;AAEA,SAAS,gBAAgB,EAAE,QAAQ,WAAW,GAAqE;AACjH,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,mBAAmB,MAAM;AACxC,QAAM,QAAQ,EAAE,OAAO,OAAO,MAAM;AAEpC,SACE,qBAAC,UAAK,WAAU,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport type { ExternalIdMapping } from '@open-mercato/shared/modules/integrations/types'\nimport { getIntegrationTitle } from '@open-mercato/shared/modules/integrations/types'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype IntegrationsData = Record<string, ExternalIdMapping>\n\nconst SYNC_STATUS_STYLES: Record<ExternalIdMapping['syncStatus'], { dot: string; label: string }> = {\n synced: { dot: 'bg-status-success-icon', label: 'integrations.syncStatus.synced' },\n pending: { dot: 'bg-status-warning-icon', label: 'integrations.syncStatus.pending' },\n error: { dot: 'bg-status-error-icon', label: 'integrations.syncStatus.error' },\n not_synced: { dot: 'bg-status-neutral-icon', label: 'integrations.syncStatus.notSynced' },\n}\n\nfunction SyncStatusBadge({ status, lastSynced }: { status: ExternalIdMapping['syncStatus']; lastSynced?: string }) {\n const t = useT()\n const config = SYNC_STATUS_STYLES[status]\n const label = t(config.label, status)\n\n return (\n <span className=\"inline-flex shrink-0 items-center gap-1 text-xs text-muted-foreground\">\n <span className={cn('inline-block size-1.5 rounded-full', config.dot)} aria-hidden=\"true\" />\n <span>{label}</span>\n {lastSynced && (\n <span title={lastSynced}>\n {new Date(lastSynced).toLocaleDateString()}\n </span>\n )}\n </span>\n )\n}\n\nfunction ExternalLinkIcon() {\n return (\n <svg className=\"size-3.5\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <path d=\"M6.5 3.5H3a1 1 0 0 0-1 1V13a1 1 0 0 0 1 1h8.5a1 1 0 0 0 1-1V9.5\" />\n <path d=\"M9.5 2h4.5v4.5M14 2 7.5 8.5\" />\n </svg>\n )\n}\n\nexport default function ExternalIdsWidget({ data }: InjectionWidgetComponentProps) {\n const t = useT()\n const integrations = (data as Record<string, unknown>)?._integrations as IntegrationsData | undefined\n\n if (!integrations || Object.keys(integrations).length === 0) return null\n\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <h3 className=\"mb-3 text-sm font-medium\">\n {t('integrations.externalIds.title', 'External IDs')}\n </h3>\n <div className=\"space-y-2\">\n {Object.entries(integrations).map(([integrationId, mapping]) => (\n <div\n key={integrationId}\n className=\"flex items-center justify-between gap-2 rounded-md bg-muted/50 px-3 py-2\"\n >\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">\n {getIntegrationTitle(integrationId)}\n </span>\n <code className=\"min-w-0 max-w-full break-all rounded bg-muted px-1.5 py-0.5 text-xs font-mono text-muted-foreground\">\n {mapping.externalId}\n </code>\n {mapping.externalUrl && (\n <a\n href={mapping.externalUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"shrink-0 text-muted-foreground hover:text-foreground transition-colors\"\n aria-label={t('integrations.externalIds.openExternal', 'Open in external system')}\n >\n <ExternalLinkIcon />\n </a>\n )}\n </div>\n <SyncStatusBadge status={mapping.syncStatus} lastSynced={mapping.lastSyncedAt} />\n </div>\n ))}\n </div>\n </div>\n )\n}\n\n"],
|
|
5
|
+
"mappings": ";AAwBI,SACE,KADF;AAnBJ,SAAS,2BAA2B;AACpC,SAAS,YAAY;AACrB,SAAS,UAAU;AAInB,MAAM,qBAA8F;AAAA,EAClG,QAAQ,EAAE,KAAK,0BAA0B,OAAO,iCAAiC;AAAA,EACjF,SAAS,EAAE,KAAK,0BAA0B,OAAO,kCAAkC;AAAA,EACnF,OAAO,EAAE,KAAK,wBAAwB,OAAO,gCAAgC;AAAA,EAC7E,YAAY,EAAE,KAAK,0BAA0B,OAAO,oCAAoC;AAC1F;AAEA,SAAS,gBAAgB,EAAE,QAAQ,WAAW,GAAqE;AACjH,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,mBAAmB,MAAM;AACxC,QAAM,QAAQ,EAAE,OAAO,OAAO,MAAM;AAEpC,SACE,qBAAC,UAAK,WAAU,yEACd;AAAA,wBAAC,UAAK,WAAW,GAAG,sCAAsC,OAAO,GAAG,GAAG,eAAY,QAAO;AAAA,IAC1F,oBAAC,UAAM,iBAAM;AAAA,IACZ,cACC,oBAAC,UAAK,OAAO,YACV,cAAI,KAAK,UAAU,EAAE,mBAAmB,GAC3C;AAAA,KAEJ;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,qBAAC,SAAI,WAAU,YAAW,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAC1F;AAAA,wBAAC,UAAK,GAAE,mEAAkE;AAAA,IAC1E,oBAAC,UAAK,GAAE,+BAA8B;AAAA,KACxC;AAEJ;AAEe,SAAR,kBAAmC,EAAE,KAAK,GAAkC;AACjF,QAAM,IAAI,KAAK;AACf,QAAM,eAAgB,MAAkC;AAExD,MAAI,CAAC,gBAAgB,OAAO,KAAK,YAAY,EAAE,WAAW,EAAG,QAAO;AAEpE,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,wBAAC,QAAG,WAAU,4BACX,YAAE,kCAAkC,cAAc,GACrD;AAAA,IACA,oBAAC,SAAI,WAAU,aACZ,iBAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,eAAe,OAAO,MACxD;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SAAI,WAAU,oDACb;AAAA,gCAAC,UAAK,WAAU,gCACb,8BAAoB,aAAa,GACpC;AAAA,YACA,oBAAC,UAAK,WAAU,uGACb,kBAAQ,YACX;AAAA,YACC,QAAQ,eACP;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,QAAQ;AAAA,gBACd,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,WAAU;AAAA,gBACV,cAAY,EAAE,yCAAyC,yBAAyB;AAAA,gBAEhF,8BAAC,oBAAiB;AAAA;AAAA,YACpB;AAAA,aAEJ;AAAA,UACA,oBAAC,mBAAgB,QAAQ,QAAQ,YAAY,YAAY,QAAQ,cAAc;AAAA;AAAA;AAAA,MAtB1E;AAAA,IAuBP,CACD,GACH;AAAA,KACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.10.1-develop.
|
|
3
|
+
"version": "0.10.1-develop.7762.1.657bb7236b",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -266,16 +266,16 @@
|
|
|
266
266
|
"zod": "^4.4.3"
|
|
267
267
|
},
|
|
268
268
|
"peerDependencies": {
|
|
269
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
270
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
271
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
269
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7762.1.657bb7236b",
|
|
270
|
+
"@open-mercato/shared": "0.10.1-develop.7762.1.657bb7236b",
|
|
271
|
+
"@open-mercato/ui": "0.10.1-develop.7762.1.657bb7236b",
|
|
272
272
|
"react": "^19.0.0",
|
|
273
273
|
"react-dom": "^19.0.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
277
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
278
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
276
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7762.1.657bb7236b",
|
|
277
|
+
"@open-mercato/shared": "0.10.1-develop.7762.1.657bb7236b",
|
|
278
|
+
"@open-mercato/ui": "0.10.1-develop.7762.1.657bb7236b",
|
|
279
279
|
"@testing-library/dom": "^10.4.1",
|
|
280
280
|
"@testing-library/jest-dom": "^7.0.1",
|
|
281
281
|
"@testing-library/react": "^16.3.3",
|
|
@@ -325,6 +325,8 @@ export default function AccountStatusWidget({ context }: AccountStatusProps) {
|
|
|
325
325
|
queryClient.invalidateQueries({ queryKey: ['customer-account-pending-invitation', personEntityId] })
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
if (!personEntityId) return null
|
|
329
|
+
|
|
328
330
|
if (isLoading) {
|
|
329
331
|
return <div className="text-sm text-muted-foreground">{t('common.loading', 'Loading...')}</div>
|
|
330
332
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { enrichCustomerDetailResponse } from '../../../lib/detailResponseEnrichment'
|
|
1
2
|
import { NextResponse } from 'next/server'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
@@ -524,7 +525,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
|
|
|
524
525
|
: null
|
|
525
526
|
if (cache && cacheKey) {
|
|
526
527
|
const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey))
|
|
527
|
-
if (cached) return NextResponse.json(cached)
|
|
528
|
+
if (cached) return NextResponse.json(await enrichCustomerDetailResponse(cached as Record<string, unknown>, 'company', { auth, container, em, tenantId: companyScope.tenantId, organizationId: companyScope.organizationId }))
|
|
528
529
|
}
|
|
529
530
|
|
|
530
531
|
const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos
|
|
@@ -1211,7 +1212,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
|
|
|
1211
1212
|
}
|
|
1212
1213
|
}
|
|
1213
1214
|
|
|
1214
|
-
return NextResponse.json(payload)
|
|
1215
|
+
return NextResponse.json(await enrichCustomerDetailResponse(payload, 'company', { auth, container, em, tenantId: companyScope.tenantId, organizationId: companyScope.organizationId }))
|
|
1215
1216
|
}
|
|
1216
1217
|
|
|
1217
1218
|
const companyDetailQuerySchema = z.object({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { enrichCustomerDetailResponse } from '../../../lib/detailResponseEnrichment'
|
|
1
2
|
import { NextResponse } from 'next/server'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
@@ -491,20 +492,11 @@ export async function GET(request: Request, context: { params?: Record<string, u
|
|
|
491
492
|
})
|
|
492
493
|
: null
|
|
493
494
|
|
|
495
|
+
let cachedBody: Record<string, unknown> | null = null
|
|
494
496
|
if (detailCache && detailCacheKey) {
|
|
495
497
|
try {
|
|
496
498
|
const cached = await runWithCacheTenant(cacheTenantId, () => detailCache.get(detailCacheKey))
|
|
497
|
-
if (cached && typeof cached === 'object')
|
|
498
|
-
const viewerInfo = await resolveViewer()
|
|
499
|
-
return NextResponse.json({
|
|
500
|
-
...(cached as Record<string, unknown>),
|
|
501
|
-
viewer: {
|
|
502
|
-
userId: viewerUserId,
|
|
503
|
-
name: viewerInfo.name,
|
|
504
|
-
email: viewerInfo.email,
|
|
505
|
-
},
|
|
506
|
-
})
|
|
507
|
-
}
|
|
499
|
+
if (cached && typeof cached === 'object') cachedBody = cached as Record<string, unknown>
|
|
508
500
|
} catch (err) {
|
|
509
501
|
// A cache-backend read error must degrade to a fresh DB read, never a 500.
|
|
510
502
|
debugCrudCache('get', {
|
|
@@ -514,6 +506,14 @@ export async function GET(request: Request, context: { params?: Record<string, u
|
|
|
514
506
|
})
|
|
515
507
|
}
|
|
516
508
|
}
|
|
509
|
+
if (cachedBody) {
|
|
510
|
+
const viewerInfo = await resolveViewer()
|
|
511
|
+
return NextResponse.json(await enrichCustomerDetailResponse({
|
|
512
|
+
...cachedBody,
|
|
513
|
+
viewer: { userId: viewerUserId, name: viewerInfo.name, email: viewerInfo.email },
|
|
514
|
+
}, 'deal', { auth, container, em, tenantId: cacheTenantId, organizationId: cacheOrganizationId }))
|
|
515
|
+
}
|
|
516
|
+
|
|
517
517
|
// Issue #3175: the reads below only depend on the already-resolved deal +
|
|
518
518
|
// organization scope + decryption scope, so they are grouped into Promise.all
|
|
519
519
|
// batches instead of being awaited one after another. True dependencies stay
|
|
@@ -872,7 +872,7 @@ export async function GET(request: Request, context: { params?: Record<string, u
|
|
|
872
872
|
}
|
|
873
873
|
}
|
|
874
874
|
|
|
875
|
-
return NextResponse.json({ ...cacheableBody, viewer })
|
|
875
|
+
return NextResponse.json(await enrichCustomerDetailResponse({ ...cacheableBody, viewer }, 'deal', { auth, container, em, tenantId: cacheTenantId, organizationId: cacheOrganizationId }))
|
|
876
876
|
}
|
|
877
877
|
|
|
878
878
|
const dealDetailQuerySchema = z.object({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { enrichCustomerDetailResponse } from '../../../lib/detailResponseEnrichment'
|
|
1
2
|
import { NextResponse } from 'next/server'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
@@ -579,7 +580,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
|
|
|
579
580
|
statusCode = 200
|
|
580
581
|
profileMeta = { cacheHit: true, include: Array.from(includeTokens), interactionMode }
|
|
581
582
|
profiler.mark('cache_hit')
|
|
582
|
-
return NextResponse.json(cached)
|
|
583
|
+
return NextResponse.json(await enrichCustomerDetailResponse(cached as Record<string, unknown>, 'person', { auth, container, em, tenantId: personDetailTenantId, organizationId: personDetailOrganizationId }))
|
|
583
584
|
}
|
|
584
585
|
}
|
|
585
586
|
|
|
@@ -1134,7 +1135,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
|
|
|
1134
1135
|
} catch {}
|
|
1135
1136
|
}
|
|
1136
1137
|
|
|
1137
|
-
const response = NextResponse.json(payload)
|
|
1138
|
+
const response = NextResponse.json(await enrichCustomerDetailResponse(payload, 'person', { auth, container, em, tenantId: personDetailTenantId, organizationId: personDetailOrganizationId }))
|
|
1138
1139
|
statusCode = 200
|
|
1139
1140
|
profileMeta = {
|
|
1140
1141
|
include: Array.from(includeTokens),
|
|
@@ -45,6 +45,8 @@ export default function CreateCompanyPage() {
|
|
|
45
45
|
initialValues={{ addresses: [] as CompanyFormValues['addresses'] }}
|
|
46
46
|
injectionSpotId={extensionPoints.hosts.companyForm.spotId}
|
|
47
47
|
legacyInjectionSpotId={COMPANY_CREATE_LEGACY_INJECTION_SPOT_ID}
|
|
48
|
+
entityId="customers.company"
|
|
49
|
+
resourceKind="customers.company"
|
|
48
50
|
entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}
|
|
49
51
|
submitLabel={t('customers.companies.form.submit')}
|
|
50
52
|
cancelHref={returnTo ?? '/backend/customers/companies'}
|
|
@@ -125,6 +127,10 @@ export default function CreateCompanyPage() {
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
flash(t('customers.companies.form.success'), 'success')
|
|
130
|
+
return newId ? { resourceId: newId } : undefined
|
|
131
|
+
}}
|
|
132
|
+
onSubmitSuccess={async (_values, result) => {
|
|
133
|
+
const newId = result?.resourceId
|
|
128
134
|
if (returnTo) router.push(returnTo)
|
|
129
135
|
else if (newId) router.push(`/backend/customers/companies-v2/${newId}`)
|
|
130
136
|
else router.push('/backend/customers/companies')
|
|
@@ -15,7 +15,9 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
15
15
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
16
16
|
import { AttachmentsSection, ErrorMessage, LoadingMessage, RecordNotFoundState, type SectionAction } from '@open-mercato/ui/backend/detail'
|
|
17
17
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
18
|
-
import { InjectionSpot
|
|
18
|
+
import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
|
|
19
|
+
import { useCustomerInjectedTabs } from '../../../../components/detail/useCustomerInjectedTabs'
|
|
20
|
+
import { CustomerDetailSidebar } from '../../../../components/detail/CustomerDetailSidebar'
|
|
19
21
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
20
22
|
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
21
23
|
import { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
@@ -32,7 +34,7 @@ import type { TagsSectionController } from '@open-mercato/ui/backend/detail'
|
|
|
32
34
|
import { coerceDisplayName } from '../../../../lib/displayName'
|
|
33
35
|
import { isDetailNotFoundStatus } from '@open-mercato/core/modules/customers/lib/detailHelpers'
|
|
34
36
|
import { CompanyDetailHeader } from '../../../../components/detail/CompanyDetailHeader'
|
|
35
|
-
import { CompanyDetailTabs, resolveLegacyTab, type CompanyTabId } from '../../../../components/detail/CompanyDetailTabs'
|
|
37
|
+
import { CompanyDetailTabs, COMPANY_DETAIL_TAB_IDS, resolveLegacyTab, type CompanyTabId } from '../../../../components/detail/CompanyDetailTabs'
|
|
36
38
|
import { useDealsAccess } from '../../../../components/detail/useDealsAccess'
|
|
37
39
|
import { CompanyKpiBar } from '../../../../components/detail/CompanyKpiBar'
|
|
38
40
|
import { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'
|
|
@@ -192,9 +194,11 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
192
194
|
resourceKind: 'customers.company',
|
|
193
195
|
resourceId: currentCompanyId ?? (id ?? undefined),
|
|
194
196
|
data,
|
|
197
|
+
isDirty,
|
|
198
|
+
isSaving,
|
|
195
199
|
retryLastMutation,
|
|
196
200
|
}),
|
|
197
|
-
[currentCompanyId, data, id, mutationContextId, retryLastMutation],
|
|
201
|
+
[currentCompanyId, data, isDirty, isSaving, id, mutationContextId, retryLastMutation],
|
|
198
202
|
)
|
|
199
203
|
const runMutationWithContext = React.useCallback(
|
|
200
204
|
async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {
|
|
@@ -295,36 +299,19 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
295
299
|
setScheduleDialogOpen(true)
|
|
296
300
|
}, [])
|
|
297
301
|
|
|
298
|
-
|
|
299
|
-
|
|
302
|
+
const { injectedTabs, injectedTabMap, loading: injectedTabsLoading } = useCustomerInjectedTabs({
|
|
303
|
+
spotId: extensionPoints.hosts.companyTabs.spotId,
|
|
300
304
|
context: injectionContext,
|
|
301
|
-
|
|
305
|
+
data,
|
|
306
|
+
onDataChange: setData,
|
|
307
|
+
nativeTabIds: COMPANY_DETAIL_TAB_IDS,
|
|
302
308
|
})
|
|
303
309
|
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const tabId = widget.placement?.groupId ?? widget.widgetId
|
|
310
|
-
const label = widget.placement?.groupLabel
|
|
311
|
-
? t(widget.placement.groupLabel, widget.placement.groupLabel)
|
|
312
|
-
: widget.module.metadata.title ?? tabId
|
|
313
|
-
const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0
|
|
314
|
-
const render = () => (
|
|
315
|
-
<widget.module.Widget
|
|
316
|
-
context={injectionContext}
|
|
317
|
-
data={data}
|
|
318
|
-
onDataChange={(next: unknown) => setData(next as CompanyOverview)}
|
|
319
|
-
/>
|
|
320
|
-
)
|
|
321
|
-
return { id: tabId, label, priority, render }
|
|
322
|
-
})
|
|
323
|
-
.sort((a, b) => b.priority - a.priority),
|
|
324
|
-
[data, injectedTabWidgets, injectionContext, t],
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])
|
|
310
|
+
const injectedTabIds = React.useMemo(() => injectedTabs.map((tab) => tab.id), [injectedTabs])
|
|
311
|
+
React.useEffect(() => {
|
|
312
|
+
const requested = resolveLegacyTab(searchParams?.get('tab'), injectedTabIds)
|
|
313
|
+
setActiveTab(requested === 'deals' && isDealsAccessReady && !canViewDeals ? 'people' : requested)
|
|
314
|
+
}, [searchParams, injectedTabIds, isDealsAccessReady, canViewDeals])
|
|
328
315
|
|
|
329
316
|
// Tags
|
|
330
317
|
const handleTagsChange = React.useCallback((nextTags: TagSummary[]) => {
|
|
@@ -492,6 +479,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
492
479
|
|
|
493
480
|
{/* Persistent company header */}
|
|
494
481
|
<CompanyDetailHeader
|
|
482
|
+
actions={<InjectionSpot spotId={extensionPoints.hosts.companyHeaderActions.spotId} context={injectionContext} data={data} disabled={isSaving} />}
|
|
495
483
|
data={data}
|
|
496
484
|
onTagsChange={handleTagsChange}
|
|
497
485
|
tagsSectionControllerRef={tagsSectionControllerRef}
|
|
@@ -506,6 +494,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
506
494
|
<CompanyKpiBar data={data} />
|
|
507
495
|
|
|
508
496
|
{/* Two-zone layout: zone1 = form, zone2 = tabs */}
|
|
497
|
+
<CustomerDetailSidebar spotId={extensionPoints.hosts.companySidebar.spotId} context={injectionContext} data={data} onDataChange={setData} disabled={isSaving}>
|
|
509
498
|
<CollapsibleZoneLayout
|
|
510
499
|
pageType="company-v2"
|
|
511
500
|
entityName={companyName}
|
|
@@ -517,6 +506,10 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
517
506
|
embedded
|
|
518
507
|
trackDirtyWhenEmbedded
|
|
519
508
|
injectionSpotId={extensionPoints.hosts.companyForm.spotId}
|
|
509
|
+
entityId="customers.company"
|
|
510
|
+
resourceKind="customers.company"
|
|
511
|
+
resourceId={companyId}
|
|
512
|
+
injectionGroupAliases={{ details: 'identity', profile: 'businessProfile' }}
|
|
520
513
|
entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}
|
|
521
514
|
schema={formSchema}
|
|
522
515
|
fields={formFields}
|
|
@@ -536,6 +529,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
536
529
|
<CompanyDetailTabs
|
|
537
530
|
activeTab={activeTab}
|
|
538
531
|
onTabChange={handleTabChange}
|
|
532
|
+
isLoadingInjectedTabs={injectedTabsLoading}
|
|
539
533
|
injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}
|
|
540
534
|
peopleCount={data.counts?.people ?? 0}
|
|
541
535
|
dealsCount={dealCount}
|
|
@@ -621,7 +615,10 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
621
615
|
}
|
|
622
616
|
/>
|
|
623
617
|
|
|
618
|
+
</CustomerDetailSidebar>
|
|
619
|
+
|
|
624
620
|
{/* UMES footer injection */}
|
|
621
|
+
|
|
625
622
|
<InjectionSpot spotId={extensionPoints.hosts.companyFooter.spotId} context={injectionContext} data={data} />
|
|
626
623
|
|
|
627
624
|
{/* Schedule Activity Dialog */}
|
|
@@ -1,60 +1,25 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { useCustomerInjectedTabs } from '../../../../../components/detail/useCustomerInjectedTabs'
|
|
3
|
+
import { DEAL_DETAIL_TAB_IDS } from '../../../../../components/detail/DealDetailTabs'
|
|
4
|
+
import { extensionPoints } from '../../../../../extension-points'
|
|
3
5
|
import type { DealDetailPayload } from './types'
|
|
4
6
|
|
|
5
|
-
type InjectedTab = {
|
|
6
|
-
id: string
|
|
7
|
-
label: string
|
|
8
|
-
priority: number
|
|
9
|
-
render: () => React.ReactNode
|
|
10
|
-
}
|
|
11
|
-
|
|
12
7
|
type UseDealInjectedTabsOptions = {
|
|
13
8
|
injectionContext: unknown
|
|
14
9
|
data: DealDetailPayload | null
|
|
15
10
|
setData: React.Dispatch<React.SetStateAction<DealDetailPayload | null>>
|
|
16
11
|
}
|
|
17
12
|
|
|
18
|
-
type UseDealInjectedTabsResult = {
|
|
19
|
-
injectedTabs: InjectedTab[]
|
|
20
|
-
injectedTabMap: Map<string, () => React.ReactNode>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
13
|
export function useDealInjectedTabs({
|
|
24
14
|
injectionContext,
|
|
25
15
|
data,
|
|
26
16
|
setData,
|
|
27
|
-
}: UseDealInjectedTabsOptions)
|
|
28
|
-
|
|
17
|
+
}: UseDealInjectedTabsOptions) {
|
|
18
|
+
return useCustomerInjectedTabs({
|
|
19
|
+
spotId: extensionPoints.hosts.dealTabs.spotId,
|
|
29
20
|
context: injectionContext,
|
|
30
|
-
|
|
21
|
+
data,
|
|
22
|
+
onDataChange: setData,
|
|
23
|
+
nativeTabIds: DEAL_DETAIL_TAB_IDS,
|
|
31
24
|
})
|
|
32
|
-
|
|
33
|
-
const injectedTabs = React.useMemo<InjectedTab[]>(
|
|
34
|
-
() =>
|
|
35
|
-
(injectedTabWidgets ?? [])
|
|
36
|
-
.filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')
|
|
37
|
-
.map((widget) => {
|
|
38
|
-
const tabId = widget.placement?.groupId ?? widget.widgetId
|
|
39
|
-
const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? tabId
|
|
40
|
-
const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0
|
|
41
|
-
const render = () => (
|
|
42
|
-
<widget.module.Widget
|
|
43
|
-
context={injectionContext}
|
|
44
|
-
data={data}
|
|
45
|
-
onDataChange={(next: unknown) => setData(next as DealDetailPayload)}
|
|
46
|
-
/>
|
|
47
|
-
)
|
|
48
|
-
return { id: tabId, label, priority, render }
|
|
49
|
-
})
|
|
50
|
-
.sort((left, right) => right.priority - left.priority),
|
|
51
|
-
[data, injectedTabWidgets, injectionContext, setData],
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
const injectedTabMap = React.useMemo(
|
|
55
|
-
() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])),
|
|
56
|
-
[injectedTabs],
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
return { injectedTabs, injectedTabMap }
|
|
60
25
|
}
|
|
@@ -10,6 +10,7 @@ import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
|
10
10
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
11
11
|
import { AttachmentsSection, ErrorMessage, LoadingMessage, NotesSection, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
|
|
12
12
|
import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
|
|
13
|
+
import { CustomerDetailSidebar } from '../../../../components/detail/CustomerDetailSidebar'
|
|
13
14
|
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
14
15
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
15
16
|
import { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'
|
|
@@ -100,7 +101,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
100
101
|
[detailTranslator, runMutationWithContext],
|
|
101
102
|
)
|
|
102
103
|
|
|
103
|
-
const { injectedTabs, injectedTabMap } = useDealInjectedTabs({
|
|
104
|
+
const { injectedTabs, injectedTabMap, loading: injectedTabsLoading } = useDealInjectedTabs({
|
|
104
105
|
injectionContext,
|
|
105
106
|
data,
|
|
106
107
|
setData,
|
|
@@ -428,8 +429,6 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
428
429
|
const zone2Content = (
|
|
429
430
|
<div className="rounded-[10px] border border-border bg-card px-5 py-5">
|
|
430
431
|
{(() => {
|
|
431
|
-
const injected = injectedTabMap.get(activeTab)
|
|
432
|
-
if (injected) return injected()
|
|
433
432
|
|
|
434
433
|
if (activeTab === 'activities') {
|
|
435
434
|
const activityEntitySelection = activityEntities.length > 1 ? (
|
|
@@ -618,6 +617,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
618
617
|
|
|
619
618
|
return null
|
|
620
619
|
})()}
|
|
620
|
+
{injectedTabMap.get(activeTab)?.()}
|
|
621
621
|
</div>
|
|
622
622
|
)
|
|
623
623
|
|
|
@@ -628,6 +628,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
628
628
|
<InjectionSpot spotId={extensionPoints.hosts.dealHeader.spotId} context={injectionContext} data={data} />
|
|
629
629
|
|
|
630
630
|
<DealDetailHeader
|
|
631
|
+
actions={<InjectionSpot spotId={extensionPoints.hosts.dealHeaderActions.spotId} context={{ ...injectionContext, isDirty, isSaving }} data={data} disabled={isSaving} />}
|
|
631
632
|
deal={data.deal}
|
|
632
633
|
owner={data.owner}
|
|
633
634
|
people={data.people}
|
|
@@ -661,7 +662,9 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
661
662
|
)}
|
|
662
663
|
/>
|
|
663
664
|
|
|
665
|
+
<CustomerDetailSidebar spotId={extensionPoints.hosts.dealSidebar.spotId} context={injectionContext} data={data} onDataChange={setData} disabled={isSaving}>
|
|
664
666
|
<DealDetailTabs
|
|
667
|
+
isLoadingInjectedTabs={injectedTabsLoading}
|
|
665
668
|
activeTab={activeTab}
|
|
666
669
|
onTabChange={handleTabChange}
|
|
667
670
|
injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}
|
|
@@ -678,6 +681,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
678
681
|
zone2={zone2Content}
|
|
679
682
|
/>
|
|
680
683
|
</DealDetailTabs>
|
|
684
|
+
</CustomerDetailSidebar>
|
|
681
685
|
|
|
682
686
|
<InjectionSpot spotId={extensionPoints.hosts.dealFooter.spotId} context={injectionContext} data={data} />
|
|
683
687
|
</div>
|