@open-mercato/core 0.9.0 → 0.9.1-develop.7459.1.99e3accd30
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/generated/entities/customer_dictionary_entry/index.js +2 -0
- package/dist/generated/entities/customer_dictionary_entry/index.js.map +2 -2
- package/dist/generated/entities/customer_interaction/index.js +2 -0
- package/dist/generated/entities/customer_interaction/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +1 -1
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/productDeleteChildren.js +389 -0
- package/dist/modules/catalog/commands/productDeleteChildren.js.map +7 -0
- package/dist/modules/catalog/commands/products.js +52 -17
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +4 -6
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js +4 -6
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js +47 -11
- package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js.map +3 -3
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js +5 -1
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
- package/dist/modules/communication_channels/lib/inbound-message-origin.js +1 -1
- package/dist/modules/communication_channels/lib/inbound-message-origin.js.map +2 -2
- package/dist/modules/communication_channels/lib/oauth-state.js +4 -1
- package/dist/modules/communication_channels/lib/oauth-state.js.map +2 -2
- package/dist/modules/communication_channels/lib/use-connect-channel.js +10 -0
- package/dist/modules/communication_channels/lib/use-connect-channel.js.map +2 -2
- package/dist/modules/customers/api/activity-types/route.js +151 -0
- package/dist/modules/customers/api/activity-types/route.js.map +7 -0
- package/dist/modules/customers/api/deals/[id]/people/route.js +58 -5
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +13 -5
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -5
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -0
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +1 -0
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +18 -0
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +0 -23
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -17
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/calendar-event-types.js +548 -0
- package/dist/modules/customers/calendar-event-types.js.map +7 -0
- package/dist/modules/customers/commands/dictionaries.js +70 -10
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +187 -22
- package/dist/modules/customers/commands/interactions.js.map +3 -3
- package/dist/modules/customers/components/ActivityTypeEditor.js +288 -0
- package/dist/modules/customers/components/ActivityTypeEditor.js.map +7 -0
- package/dist/modules/customers/components/DictionarySettings.js +3 -1
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -297
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +3 -3
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +9 -74
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/TimeGrid.js +20 -16
- package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/EventTypePanel.js +218 -0
- package/dist/modules/customers/components/calendar/editor/EventTypePanel.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/LocationField.js +7 -3
- package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PriorityField.js +3 -1
- package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/RepeatField.js +9 -1
- package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js +4 -1
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +15 -7
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +3 -1
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +28 -13
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +3 -3
- package/dist/modules/customers/components/calendar/editor/inputs.js +14 -6
- package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js +54 -0
- package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js +82 -0
- package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js.map +7 -0
- package/dist/modules/customers/components/calendar/types.js +1 -0
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +78 -343
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CreatePersonDialog.js +12 -11
- package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +7 -3
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealPeopleSection.js +206 -0
- package/dist/modules/customers/components/detail/DealPeopleSection.js.map +7 -0
- package/dist/modules/customers/components/detail/LinkedPeopleSection.js +342 -0
- package/dist/modules/customers/components/detail/LinkedPeopleSection.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonCard.js +5 -2
- package/dist/modules/customers/components/detail/PersonCard.js.map +2 -2
- package/dist/modules/customers/components/linking/adapters/personAdapter.js +3 -0
- package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +2 -2
- package/dist/modules/customers/data/entities.js +6 -0
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +39 -10
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/di.js +20 -1
- package/dist/modules/customers/di.js.map +2 -2
- package/dist/modules/customers/extension-points.js +13 -0
- package/dist/modules/customers/extension-points.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +59 -16
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +34 -16
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/eventTypeResolver.js +197 -0
- package/dist/modules/customers/lib/calendar/eventTypeResolver.js.map +7 -0
- package/dist/modules/customers/lib/calendar/interactionApplicability.js +67 -0
- package/dist/modules/customers/lib/calendar/interactionApplicability.js.map +7 -0
- package/dist/modules/customers/lib/calendar/mapItem.js +5 -2
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/recurrence.js +62 -1
- package/dist/modules/customers/lib/calendar/recurrence.js.map +2 -2
- package/dist/modules/customers/lib/calendar/timezone.js +111 -0
- package/dist/modules/customers/lib/calendar/timezone.js.map +7 -0
- package/dist/modules/customers/lib/interactionReadModel.js +1 -0
- package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +1 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260928175058_customers.js +17 -0
- package/dist/modules/customers/migrations/Migration20260928175058_customers.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260930110235_customers.js +17 -0
- package/dist/modules/customers/migrations/Migration20260930110235_customers.js.map +7 -0
- package/dist/modules/dictionaries/components/DictionaryTable.js +60 -51
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/messages/subscribers/message-notification.js +13 -1
- package/dist/modules/messages/subscribers/message-notification.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +201 -53
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +37 -11
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/planner/lib/availabilityMerge.js +101 -38
- package/dist/modules/planner/lib/availabilityMerge.js.map +3 -3
- package/dist/modules/planner/services/plannerAvailabilityService.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +159 -81
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +12 -7
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +28 -25
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/generated/entities/customer_dictionary_entry/index.ts +1 -0
- package/generated/entities/customer_interaction/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +9 -8
- package/src/modules/auth/i18n/de.json +3 -0
- package/src/modules/auth/i18n/en.json +3 -0
- package/src/modules/auth/i18n/es.json +3 -0
- package/src/modules/auth/i18n/ko.json +3 -0
- package/src/modules/auth/i18n/pl.json +3 -0
- package/src/modules/catalog/commands/categories.ts +1 -1
- package/src/modules/catalog/commands/productDeleteChildren.ts +557 -0
- package/src/modules/catalog/commands/products.ts +58 -17
- package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +4 -6
- package/src/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.ts +4 -6
- package/src/modules/communication_channels/api/post/oauth/[provider]/initiate/route.ts +46 -10
- package/src/modules/communication_channels/commands/deliver-outbound-message.ts +6 -1
- package/src/modules/communication_channels/i18n/de.json +4 -0
- package/src/modules/communication_channels/i18n/en.json +4 -0
- package/src/modules/communication_channels/i18n/es.json +4 -0
- package/src/modules/communication_channels/i18n/ko.json +4 -0
- package/src/modules/communication_channels/i18n/pl.json +4 -0
- package/src/modules/communication_channels/lib/inbound-message-origin.ts +2 -6
- package/src/modules/communication_channels/lib/oauth-state.ts +4 -1
- package/src/modules/communication_channels/lib/use-connect-channel.ts +10 -0
- package/src/modules/customers/api/activity-types/route.ts +154 -0
- package/src/modules/customers/api/deals/[id]/people/route.ts +82 -3
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -1
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +18 -2
- package/src/modules/customers/api/interactions/route.ts +4 -0
- package/src/modules/customers/api/interactions/tasks/route.ts +1 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +20 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +0 -29
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +15 -17
- package/src/modules/customers/calendar-event-types.ts +674 -0
- package/src/modules/customers/commands/dictionaries.ts +84 -8
- package/src/modules/customers/commands/interactions.ts +244 -21
- package/src/modules/customers/components/ActivityTypeEditor.tsx +239 -0
- package/src/modules/customers/components/DictionarySettings.tsx +5 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +347 -218
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +18 -96
- package/src/modules/customers/components/calendar/TimeGrid.tsx +20 -18
- package/src/modules/customers/components/calendar/editor/EventTypePanel.tsx +230 -0
- package/src/modules/customers/components/calendar/editor/LocationField.tsx +7 -1
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +4 -0
- package/src/modules/customers/components/calendar/editor/PriorityField.tsx +3 -0
- package/src/modules/customers/components/calendar/editor/RepeatField.tsx +10 -0
- package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +4 -0
- package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +16 -4
- package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +3 -0
- package/src/modules/customers/components/calendar/editor/hooks.ts +29 -13
- package/src/modules/customers/components/calendar/editor/inputs.tsx +17 -5
- package/src/modules/customers/components/calendar/editor/useCalendarCustomFields.ts +49 -0
- package/src/modules/customers/components/calendar/editor/useEventTypeCatalog.ts +100 -0
- package/src/modules/customers/components/calendar/types.ts +1 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +94 -388
- package/src/modules/customers/components/detail/CreatePersonDialog.tsx +39 -19
- package/src/modules/customers/components/detail/DealForm.tsx +7 -3
- package/src/modules/customers/components/detail/DealPeopleSection.tsx +256 -0
- package/src/modules/customers/components/detail/LinkedPeopleSection.tsx +474 -0
- package/src/modules/customers/components/detail/PersonCard.tsx +12 -4
- package/src/modules/customers/components/detail/types.ts +1 -0
- package/src/modules/customers/components/linking/adapters/personAdapter.tsx +4 -0
- package/src/modules/customers/data/entities.ts +8 -1
- package/src/modules/customers/data/validators.ts +42 -7
- package/src/modules/customers/di.ts +21 -0
- package/src/modules/customers/extension-points.ts +13 -0
- package/src/modules/customers/i18n/de.json +104 -8
- package/src/modules/customers/i18n/en.json +104 -8
- package/src/modules/customers/i18n/es.json +104 -8
- package/src/modules/customers/i18n/ko.json +104 -8
- package/src/modules/customers/i18n/pl.json +104 -8
- package/src/modules/customers/lib/calendar/conflicts.ts +106 -27
- package/src/modules/customers/lib/calendar/editorPayload.ts +39 -19
- package/src/modules/customers/lib/calendar/eventTypeResolver.ts +258 -0
- package/src/modules/customers/lib/calendar/interactionApplicability.ts +99 -0
- package/src/modules/customers/lib/calendar/mapItem.ts +6 -2
- package/src/modules/customers/lib/calendar/recurrence.ts +65 -1
- package/src/modules/customers/lib/calendar/timezone.ts +117 -0
- package/src/modules/customers/lib/interactionReadModel.ts +1 -0
- package/src/modules/customers/lib/todoCompatibility.ts +2 -0
- package/src/modules/customers/migrations/.snapshot-open-mercato.json +34 -0
- package/src/modules/customers/migrations/Migration20260928175058_customers.ts +15 -0
- package/src/modules/customers/migrations/Migration20260930110235_customers.ts +15 -0
- package/src/modules/dictionaries/components/DictionaryTable.tsx +63 -56
- package/src/modules/messages/subscribers/message-notification.ts +13 -3
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +243 -62
- package/src/modules/payment_gateways/lib/gateway-service.ts +39 -12
- package/src/modules/planner/lib/availabilityMerge.ts +106 -41
- package/src/modules/planner/services/plannerAvailabilityService.ts +4 -0
- package/src/modules/sales/components/documents/LineItemDialog.tsx +194 -111
- package/src/modules/sales/components/documents/lineItemUtils.ts +18 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +25 -13
- package/src/modules/sync_excel/lib/adapters/customers.ts +33 -27
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { Users, Link2, Plus, Filter } from 'lucide-react'
|
|
5
|
-
import { EmptyState } from '@open-mercato/ui/backend/EmptyState'
|
|
6
|
-
import { Button } from '@open-mercato/ui/primitives/button'
|
|
7
|
-
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
8
4
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
9
5
|
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
10
|
-
import {
|
|
11
|
-
readVersionedIdSet,
|
|
12
|
-
writeVersionedIdSet,
|
|
13
|
-
} from '@open-mercato/shared/lib/browser/versionedPreference'
|
|
14
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
15
7
|
import { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
16
8
|
import { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'
|
|
17
9
|
import type { AppEventPayload } from '@open-mercato/shared/modules/widgets/injection'
|
|
18
10
|
import type { SectionAction, TabEmptyStateConfig, Translator } from './types'
|
|
19
11
|
import { CreatePersonDialog } from './CreatePersonDialog'
|
|
20
|
-
import { PersonCard } from './PersonCard'
|
|
21
12
|
import { coerceDisplayName } from '../../lib/displayName'
|
|
22
13
|
import { DecisionMakersFooter } from './DecisionMakersFooter'
|
|
23
14
|
import { RolesSection } from './RolesSection'
|
|
24
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
LinkedPeopleSection,
|
|
17
|
+
type LinkedPeoplePage,
|
|
18
|
+
type LinkedPeopleSortMode,
|
|
19
|
+
type LinkedPersonSummary,
|
|
20
|
+
} from './LinkedPeopleSection'
|
|
21
|
+
import type { LinkEntityOption } from '../linking/LinkEntityDialog'
|
|
25
22
|
import { createPersonLinkAdapter } from '../linking/adapters/personAdapter'
|
|
26
23
|
|
|
27
24
|
type GuardedMutationRunner = <T>(
|
|
@@ -29,21 +26,7 @@ type GuardedMutationRunner = <T>(
|
|
|
29
26
|
mutationPayload?: Record<string, unknown>,
|
|
30
27
|
) => Promise<T>
|
|
31
28
|
|
|
32
|
-
export type CompanyPersonSummary =
|
|
33
|
-
id: string
|
|
34
|
-
displayName: string
|
|
35
|
-
primaryEmail?: string | null
|
|
36
|
-
primaryPhone?: string | null
|
|
37
|
-
status?: string | null
|
|
38
|
-
lifecycleStage?: string | null
|
|
39
|
-
jobTitle?: string | null
|
|
40
|
-
department?: string | null
|
|
41
|
-
createdAt?: string | null
|
|
42
|
-
organizationId?: string | null
|
|
43
|
-
temperature?: string | null
|
|
44
|
-
source?: string | null
|
|
45
|
-
linkedAt?: string | null
|
|
46
|
-
}
|
|
29
|
+
export type CompanyPersonSummary = LinkedPersonSummary
|
|
47
30
|
|
|
48
31
|
export type CompanyPeopleSectionProps = {
|
|
49
32
|
companyId: string
|
|
@@ -60,9 +43,6 @@ export type CompanyPeopleSectionProps = {
|
|
|
60
43
|
runGuardedMutation?: GuardedMutationRunner
|
|
61
44
|
}
|
|
62
45
|
|
|
63
|
-
const COMPANY_PEOPLE_PAGE_SIZE = 20
|
|
64
|
-
const STARRED_PEOPLE_STORAGE_VERSION = 1
|
|
65
|
-
|
|
66
46
|
function normalizeCompanyPerson(record: Record<string, unknown>): CompanyPersonSummary | null {
|
|
67
47
|
const id = typeof record.id === 'string' ? record.id : null
|
|
68
48
|
if (!id) return null
|
|
@@ -160,7 +140,7 @@ function matchesCompanyPersonSearch(person: CompanyPersonSummary, query: string)
|
|
|
160
140
|
|
|
161
141
|
function sortCompanyPeople(
|
|
162
142
|
items: CompanyPersonSummary[],
|
|
163
|
-
sortMode:
|
|
143
|
+
sortMode: LinkedPeopleSortMode,
|
|
164
144
|
): CompanyPersonSummary[] {
|
|
165
145
|
return [...items].sort((left, right) => {
|
|
166
146
|
if (sortMode === 'recent') {
|
|
@@ -196,22 +176,15 @@ export function CompanyPeopleSection({
|
|
|
196
176
|
)
|
|
197
177
|
const translate: Translator = translator ?? fallbackTranslator
|
|
198
178
|
const [people, setPeople] = React.useState<CompanyPersonSummary[]>(initialPeople)
|
|
199
|
-
const [removingId, setRemovingId] = React.useState<string | null>(null)
|
|
200
|
-
const [linkDialogOpen, setLinkDialogOpen] = React.useState(false)
|
|
201
179
|
const [createDialogOpen, setCreateDialogOpen] = React.useState(false)
|
|
202
|
-
const [
|
|
203
|
-
const [
|
|
204
|
-
const [filtersOpen, setFiltersOpen] = React.useState(true)
|
|
205
|
-
const [visiblePeople, setVisiblePeople] = React.useState<CompanyPersonSummary[]>([])
|
|
206
|
-
const [listPage, setListPage] = React.useState(1)
|
|
207
|
-
const [listTotalPages, setListTotalPages] = React.useState(1)
|
|
208
|
-
const [listTotalCount, setListTotalCount] = React.useState(initialPeople.length)
|
|
209
|
-
const [listLoading, setListLoading] = React.useState(true)
|
|
210
|
-
const [starredIds, setStarredIds] = React.useState<Set<string>>(
|
|
211
|
-
() => readVersionedIdSet(`om:starred-people:${companyId}`, STARRED_PEOPLE_STORAGE_VERSION),
|
|
212
|
-
)
|
|
180
|
+
const [linkDialogOpen, setLinkDialogOpen] = React.useState(false)
|
|
181
|
+
const [refreshKey, setRefreshKey] = React.useState(0)
|
|
213
182
|
const pendingPeopleChangeRef = React.useRef(false)
|
|
214
183
|
|
|
184
|
+
const requestRefresh = React.useCallback(() => {
|
|
185
|
+
setRefreshKey((current) => current + 1)
|
|
186
|
+
}, [])
|
|
187
|
+
|
|
215
188
|
const runWriteMutation = React.useCallback(
|
|
216
189
|
async <T,>(
|
|
217
190
|
operation: () => Promise<T>,
|
|
@@ -225,32 +198,6 @@ export function CompanyPeopleSection({
|
|
|
225
198
|
[runGuardedMutation],
|
|
226
199
|
)
|
|
227
200
|
|
|
228
|
-
const toggleStar = React.useCallback(
|
|
229
|
-
(personId: string) => {
|
|
230
|
-
setStarredIds((prev) => {
|
|
231
|
-
const next = new Set(prev)
|
|
232
|
-
if (next.has(personId)) next.delete(personId)
|
|
233
|
-
else next.add(personId)
|
|
234
|
-
writeVersionedIdSet(`om:starred-people:${companyId}`, STARRED_PEOPLE_STORAGE_VERSION, next)
|
|
235
|
-
return next
|
|
236
|
-
})
|
|
237
|
-
},
|
|
238
|
-
[companyId],
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
const displayedPeople = React.useMemo(
|
|
242
|
-
() => (visiblePeople.length > 0 ? visiblePeople : people),
|
|
243
|
-
[people, visiblePeople],
|
|
244
|
-
)
|
|
245
|
-
const totalLinkedPeople = listTotalCount > 0 ? listTotalCount : displayedPeople.length
|
|
246
|
-
const decisionMakerNames = React.useMemo(
|
|
247
|
-
() =>
|
|
248
|
-
displayedPeople
|
|
249
|
-
.filter((person) => starredIds.has(person.id))
|
|
250
|
-
.map((person) => person.displayName),
|
|
251
|
-
[displayedPeople, starredIds],
|
|
252
|
-
)
|
|
253
|
-
|
|
254
201
|
React.useEffect(() => {
|
|
255
202
|
onActionChange?.(null)
|
|
256
203
|
return () => onActionChange?.(null)
|
|
@@ -267,23 +214,27 @@ export function CompanyPeopleSection({
|
|
|
267
214
|
onPeopleChange?.(people)
|
|
268
215
|
}, [onPeopleChange, people])
|
|
269
216
|
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
217
|
+
const loadPage = React.useCallback(
|
|
218
|
+
async ({
|
|
219
|
+
page,
|
|
220
|
+
pageSize,
|
|
221
|
+
sort,
|
|
222
|
+
search,
|
|
223
|
+
}: {
|
|
224
|
+
page: number
|
|
225
|
+
pageSize: number
|
|
226
|
+
sort: LinkedPeopleSortMode
|
|
227
|
+
search: string
|
|
228
|
+
}): Promise<LinkedPeoplePage> => {
|
|
273
229
|
const params = new URLSearchParams({
|
|
274
|
-
page: String(
|
|
275
|
-
pageSize: String(
|
|
276
|
-
sort
|
|
230
|
+
page: String(page),
|
|
231
|
+
pageSize: String(pageSize),
|
|
232
|
+
sort,
|
|
277
233
|
})
|
|
278
|
-
if (
|
|
279
|
-
params.set('search',
|
|
234
|
+
if (search.length > 0) {
|
|
235
|
+
params.set('search', search)
|
|
280
236
|
}
|
|
281
|
-
|
|
282
|
-
items?: CompanyPersonSummary[]
|
|
283
|
-
page?: number
|
|
284
|
-
total?: number
|
|
285
|
-
totalPages?: number
|
|
286
|
-
}>(
|
|
237
|
+
return readApiResultOrThrow<LinkedPeoplePage>(
|
|
287
238
|
`/api/customers/companies/${encodeURIComponent(companyId)}/people?${params.toString()}`,
|
|
288
239
|
undefined,
|
|
289
240
|
{
|
|
@@ -293,34 +244,16 @@ export function CompanyPeopleSection({
|
|
|
293
244
|
),
|
|
294
245
|
},
|
|
295
246
|
)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
setListTotalCount((current) =>
|
|
300
|
-
searchQuery.trim().length > 0 ? Math.max(current, nextTotalCount) : nextTotalCount,
|
|
301
|
-
)
|
|
302
|
-
setListTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)
|
|
303
|
-
} catch {
|
|
304
|
-
setVisiblePeople([])
|
|
305
|
-
if (searchQuery.trim().length === 0) {
|
|
306
|
-
setListTotalCount(0)
|
|
307
|
-
}
|
|
308
|
-
setListTotalPages(1)
|
|
309
|
-
} finally {
|
|
310
|
-
setListLoading(false)
|
|
311
|
-
}
|
|
312
|
-
}, [companyId, listPage, searchQuery, sortMode, translate])
|
|
313
|
-
|
|
314
|
-
React.useEffect(() => {
|
|
315
|
-
void loadVisiblePeople()
|
|
316
|
-
}, [loadVisiblePeople])
|
|
247
|
+
},
|
|
248
|
+
[companyId, translate],
|
|
249
|
+
)
|
|
317
250
|
|
|
318
251
|
const reloadOnCompanyDetach = React.useCallback((event: AppEventPayload) => {
|
|
319
252
|
const payload = event.payload as { companyEntityId?: string | null } | null | undefined
|
|
320
253
|
if (payload && payload.companyEntityId === companyId) {
|
|
321
|
-
|
|
254
|
+
requestRefresh()
|
|
322
255
|
}
|
|
323
|
-
}, [companyId,
|
|
256
|
+
}, [companyId, requestRefresh])
|
|
324
257
|
|
|
325
258
|
useAppEvent('customers.person_company_link.deleted', reloadOnCompanyDetach, [reloadOnCompanyDetach])
|
|
326
259
|
// Legacy profile-only assignments have no link row, so their detach broadcasts this sibling
|
|
@@ -328,10 +261,6 @@ export function CompanyPeopleSection({
|
|
|
328
261
|
// of the same company keep listing a person who is already gone.
|
|
329
262
|
useAppEvent('customers.person.company_assignment.detached', reloadOnCompanyDetach, [reloadOnCompanyDetach])
|
|
330
263
|
|
|
331
|
-
React.useEffect(() => {
|
|
332
|
-
setListPage(1)
|
|
333
|
-
}, [searchQuery, sortMode])
|
|
334
|
-
|
|
335
264
|
const applyPeopleChange = React.useCallback(
|
|
336
265
|
(updater: (current: CompanyPersonSummary[]) => CompanyPersonSummary[]) => {
|
|
337
266
|
setPeople((current) => {
|
|
@@ -351,11 +280,9 @@ export function CompanyPeopleSection({
|
|
|
351
280
|
optionsById,
|
|
352
281
|
}: {
|
|
353
282
|
addedIds: string[]
|
|
354
|
-
removedIds: string[]
|
|
355
283
|
optionsById: Record<string, LinkEntityOption>
|
|
356
284
|
}) => {
|
|
357
285
|
if (!addedIds.length) return
|
|
358
|
-
onLoadingChange?.(true)
|
|
359
286
|
try {
|
|
360
287
|
for (const personId of addedIds) {
|
|
361
288
|
await runWriteMutation(
|
|
@@ -396,9 +323,7 @@ export function CompanyPeopleSection({
|
|
|
396
323
|
.filter((entry): entry is CompanyPersonSummary => entry !== null)
|
|
397
324
|
if (optimisticPeople.length > 0) {
|
|
398
325
|
applyPeopleChange((current) => mergeCompanyPeople([...current, ...optimisticPeople]))
|
|
399
|
-
setListTotalCount((current) => current + optimisticPeople.length)
|
|
400
326
|
}
|
|
401
|
-
await loadVisiblePeople()
|
|
402
327
|
flash(
|
|
403
328
|
addedIds.length === 1
|
|
404
329
|
? translate(
|
|
@@ -427,19 +352,9 @@ export function CompanyPeopleSection({
|
|
|
427
352
|
)
|
|
428
353
|
flash(message, 'error')
|
|
429
354
|
throw err
|
|
430
|
-
} finally {
|
|
431
|
-
onLoadingChange?.(false)
|
|
432
355
|
}
|
|
433
356
|
},
|
|
434
|
-
[
|
|
435
|
-
applyPeopleChange,
|
|
436
|
-
companyId,
|
|
437
|
-
loadVisiblePeople,
|
|
438
|
-
onDataRefresh,
|
|
439
|
-
onLoadingChange,
|
|
440
|
-
runWriteMutation,
|
|
441
|
-
translate,
|
|
442
|
-
],
|
|
357
|
+
[applyPeopleChange, companyId, onDataRefresh, runWriteMutation, translate],
|
|
443
358
|
)
|
|
444
359
|
|
|
445
360
|
const personLinkAdapter = React.useMemo(
|
|
@@ -508,7 +423,7 @@ export function CompanyPeopleSection({
|
|
|
508
423
|
// CreatePersonDialog already created and linked the person to this company
|
|
509
424
|
// via the companyEntityId payload field. Refresh the on-page list and close
|
|
510
425
|
// both the nested and outer dialogs so the user can see the new entry.
|
|
511
|
-
|
|
426
|
+
requestRefresh()
|
|
512
427
|
void onDataRefresh?.()
|
|
513
428
|
setLinkDialogOpen(false)
|
|
514
429
|
onCancel()
|
|
@@ -517,14 +432,11 @@ export function CompanyPeopleSection({
|
|
|
517
432
|
),
|
|
518
433
|
},
|
|
519
434
|
}),
|
|
520
|
-
[companyId, companyName,
|
|
435
|
+
[companyId, companyName, onDataRefresh, requestRefresh, runWriteMutation, translate],
|
|
521
436
|
)
|
|
522
437
|
|
|
523
438
|
const handleRemove = React.useCallback(
|
|
524
439
|
async (personId: string) => {
|
|
525
|
-
if (!personId || removingId) return
|
|
526
|
-
setRemovingId(personId)
|
|
527
|
-
onLoadingChange?.(true)
|
|
528
440
|
try {
|
|
529
441
|
await runWriteMutation(
|
|
530
442
|
() =>
|
|
@@ -544,7 +456,6 @@ export function CompanyPeopleSection({
|
|
|
544
456
|
companyId,
|
|
545
457
|
},
|
|
546
458
|
)
|
|
547
|
-
await loadVisiblePeople()
|
|
548
459
|
flash(
|
|
549
460
|
translate(
|
|
550
461
|
'customers.companies.detail.people.removeSuccess',
|
|
@@ -561,270 +472,65 @@ export function CompanyPeopleSection({
|
|
|
561
472
|
'Failed to unlink person from company.',
|
|
562
473
|
)
|
|
563
474
|
flash(message, 'error')
|
|
564
|
-
} finally {
|
|
565
|
-
setRemovingId(null)
|
|
566
|
-
onLoadingChange?.(false)
|
|
567
475
|
}
|
|
568
476
|
},
|
|
569
|
-
[
|
|
570
|
-
companyId,
|
|
571
|
-
loadVisiblePeople,
|
|
572
|
-
onLoadingChange,
|
|
573
|
-
removingId,
|
|
574
|
-
runWriteMutation,
|
|
575
|
-
translate,
|
|
576
|
-
],
|
|
577
|
-
)
|
|
578
|
-
|
|
579
|
-
const linkAction = (
|
|
580
|
-
<Button
|
|
581
|
-
type="button"
|
|
582
|
-
variant="outline"
|
|
583
|
-
size="sm"
|
|
584
|
-
onClick={() => setLinkDialogOpen(true)}
|
|
585
|
-
>
|
|
586
|
-
<Link2 className="mr-1.5 h-4 w-4" />
|
|
587
|
-
{translate(
|
|
588
|
-
'customers.companies.detail.people.linkAction',
|
|
589
|
-
'Link existing person',
|
|
590
|
-
)}
|
|
591
|
-
</Button>
|
|
477
|
+
[companyId, runWriteMutation, translate],
|
|
592
478
|
)
|
|
593
|
-
const addPersonAction = (
|
|
594
|
-
<Button type="button" size="sm" onClick={() => setCreateDialogOpen(true)}>
|
|
595
|
-
<Plus className="mr-1.5 h-4 w-4" />
|
|
596
|
-
{addActionLabel}
|
|
597
|
-
</Button>
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
if (!listLoading && totalLinkedPeople === 0) {
|
|
601
|
-
return (
|
|
602
|
-
<>
|
|
603
|
-
<EmptyState
|
|
604
|
-
icon={<Users className="h-10 w-10 text-muted-foreground" />}
|
|
605
|
-
title={emptyState.title}
|
|
606
|
-
actionLabel={emptyState.actionLabel}
|
|
607
|
-
onAction={() => setCreateDialogOpen(true)}
|
|
608
|
-
>
|
|
609
|
-
<p className="text-sm text-muted-foreground">{emptyLabel}</p>
|
|
610
|
-
<div className="mt-4">{linkAction}</div>
|
|
611
|
-
</EmptyState>
|
|
612
|
-
<LinkEntityDialog
|
|
613
|
-
open={linkDialogOpen}
|
|
614
|
-
onOpenChange={setLinkDialogOpen}
|
|
615
|
-
adapter={personLinkAdapter}
|
|
616
|
-
initialSelectedIds={[]}
|
|
617
|
-
onConfirm={handleLinkConfirm}
|
|
618
|
-
runGuardedMutation={runWriteMutation}
|
|
619
|
-
/>
|
|
620
|
-
<CreatePersonDialog
|
|
621
|
-
open={createDialogOpen}
|
|
622
|
-
onClose={() => setCreateDialogOpen(false)}
|
|
623
|
-
companyId={companyId}
|
|
624
|
-
companyName={companyName ?? companyId}
|
|
625
|
-
runGuardedMutation={runWriteMutation}
|
|
626
|
-
onPersonCreated={() => {
|
|
627
|
-
setCreateDialogOpen(false)
|
|
628
|
-
void loadVisiblePeople()
|
|
629
|
-
void onDataRefresh?.()
|
|
630
|
-
}}
|
|
631
|
-
/>
|
|
632
|
-
</>
|
|
633
|
-
)
|
|
634
|
-
}
|
|
635
479
|
|
|
636
480
|
return (
|
|
637
481
|
<>
|
|
638
|
-
<
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
'Employees and decision makers on the client side',
|
|
667
|
-
)}
|
|
668
|
-
</p>
|
|
669
|
-
</div>
|
|
670
|
-
<div className="flex flex-wrap items-center gap-2 xl:justify-end">
|
|
671
|
-
{linkAction}
|
|
672
|
-
{addPersonAction}
|
|
673
|
-
</div>
|
|
674
|
-
</div>
|
|
675
|
-
|
|
676
|
-
{totalLinkedPeople > 0 ? (
|
|
677
|
-
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
|
|
678
|
-
{filtersOpen ? (
|
|
679
|
-
<div className="min-w-0 flex-1">
|
|
680
|
-
<input
|
|
681
|
-
type="text"
|
|
682
|
-
value={searchQuery}
|
|
683
|
-
onChange={(event) => setSearchQuery(event.target.value)}
|
|
684
|
-
placeholder={translate(
|
|
685
|
-
'customers.companies.detail.people.searchPlaceholder',
|
|
686
|
-
'Search by name, role, email...',
|
|
687
|
-
)}
|
|
688
|
-
className="h-10 w-full rounded-md border bg-background px-3 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring"
|
|
689
|
-
/>
|
|
690
|
-
</div>
|
|
691
|
-
) : null}
|
|
692
|
-
<div className="flex flex-wrap items-center gap-2 lg:justify-end">
|
|
693
|
-
<Button
|
|
694
|
-
type="button"
|
|
695
|
-
variant="outline"
|
|
696
|
-
size="sm"
|
|
697
|
-
onClick={() => setFiltersOpen((current) => !current)}
|
|
698
|
-
className="h-10"
|
|
699
|
-
>
|
|
700
|
-
<Filter className="mr-1.5 h-4 w-4" />
|
|
701
|
-
{translate(
|
|
702
|
-
'customers.companies.detail.people.filter',
|
|
703
|
-
'Filters',
|
|
704
|
-
)}
|
|
705
|
-
</Button>
|
|
706
|
-
{filtersOpen ? (
|
|
707
|
-
<select
|
|
708
|
-
value={sortMode}
|
|
709
|
-
onChange={(event) =>
|
|
710
|
-
setSortMode(event.target.value as 'name-asc' | 'name-desc' | 'recent')
|
|
711
|
-
}
|
|
712
|
-
className="h-10 min-w-[11rem] rounded-md border bg-background px-3 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
|
713
|
-
>
|
|
714
|
-
<option value="name-asc">
|
|
715
|
-
{translate(
|
|
716
|
-
'customers.companies.detail.people.sortNameAsc',
|
|
717
|
-
'Sort: Name A-Z',
|
|
718
|
-
)}
|
|
719
|
-
</option>
|
|
720
|
-
<option value="name-desc">
|
|
721
|
-
{translate(
|
|
722
|
-
'customers.companies.detail.people.sortNameDesc',
|
|
723
|
-
'Sort: Name Z-A',
|
|
724
|
-
)}
|
|
725
|
-
</option>
|
|
726
|
-
<option value="recent">
|
|
727
|
-
{translate(
|
|
728
|
-
'customers.companies.detail.people.sortRecent',
|
|
729
|
-
'Sort: Recently linked',
|
|
730
|
-
)}
|
|
731
|
-
</option>
|
|
732
|
-
</select>
|
|
733
|
-
) : null}
|
|
734
|
-
</div>
|
|
735
|
-
</div>
|
|
736
|
-
) : null}
|
|
737
|
-
|
|
738
|
-
{listLoading ? (
|
|
739
|
-
<p className="py-6 text-center text-sm text-muted-foreground">
|
|
740
|
-
{translate('customers.companies.detail.people.loading', 'Loading people…')}
|
|
741
|
-
</p>
|
|
742
|
-
) : visiblePeople.length > 0 ? (
|
|
743
|
-
<>
|
|
744
|
-
<div
|
|
745
|
-
className="grid items-start gap-4"
|
|
746
|
-
style={{
|
|
747
|
-
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 19.5rem), 1fr))',
|
|
748
|
-
}}
|
|
749
|
-
>
|
|
750
|
-
{visiblePeople.map((person) => (
|
|
751
|
-
<PersonCard
|
|
752
|
-
key={person.id}
|
|
753
|
-
person={person}
|
|
754
|
-
isStarred={starredIds.has(person.id)}
|
|
755
|
-
onToggleStar={toggleStar}
|
|
756
|
-
onUnlink={handleRemove}
|
|
757
|
-
/>
|
|
758
|
-
))}
|
|
759
|
-
</div>
|
|
760
|
-
{listTotalPages > 1 ? (
|
|
761
|
-
<div className="flex items-center justify-between border-t border-border/60 pt-3 text-sm text-muted-foreground">
|
|
762
|
-
<span>
|
|
763
|
-
{translate(
|
|
764
|
-
'customers.companies.detail.people.pageSummary',
|
|
765
|
-
'Page {{page}} of {{total}}',
|
|
766
|
-
{
|
|
767
|
-
page: listPage,
|
|
768
|
-
total: listTotalPages,
|
|
769
|
-
},
|
|
770
|
-
)}
|
|
771
|
-
</span>
|
|
772
|
-
<div className="flex items-center gap-2">
|
|
773
|
-
<Button
|
|
774
|
-
type="button"
|
|
775
|
-
variant="outline"
|
|
776
|
-
size="sm"
|
|
777
|
-
onClick={() => setListPage((current) => Math.max(1, current - 1))}
|
|
778
|
-
disabled={listPage <= 1}
|
|
779
|
-
>
|
|
780
|
-
{translate('customers.companies.detail.people.previous', 'Previous')}
|
|
781
|
-
</Button>
|
|
782
|
-
<Button
|
|
783
|
-
type="button"
|
|
784
|
-
variant="outline"
|
|
785
|
-
size="sm"
|
|
786
|
-
onClick={() =>
|
|
787
|
-
setListPage((current) => Math.min(listTotalPages, current + 1))
|
|
788
|
-
}
|
|
789
|
-
disabled={listPage >= listTotalPages}
|
|
790
|
-
>
|
|
791
|
-
{translate('customers.companies.detail.people.next', 'Next')}
|
|
792
|
-
</Button>
|
|
793
|
-
</div>
|
|
794
|
-
</div>
|
|
795
|
-
) : null}
|
|
796
|
-
</>
|
|
797
|
-
) : totalLinkedPeople > 0 ? (
|
|
798
|
-
<p className="py-6 text-center text-sm text-muted-foreground">
|
|
799
|
-
{translate(
|
|
800
|
-
'customers.companies.detail.people.noSearchResults',
|
|
801
|
-
'No people match your search.',
|
|
802
|
-
)}
|
|
803
|
-
</p>
|
|
804
|
-
) : null}
|
|
805
|
-
</div>
|
|
806
|
-
</section>
|
|
807
|
-
|
|
808
|
-
<DecisionMakersFooter
|
|
809
|
-
names={decisionMakerNames}
|
|
810
|
-
onSendInvitation={() => {
|
|
811
|
-
const starredEmails = displayedPeople
|
|
812
|
-
.filter((person) => starredIds.has(person.id) && person.primaryEmail)
|
|
813
|
-
.map((person) => person.primaryEmail!)
|
|
814
|
-
if (starredEmails.length > 0) {
|
|
815
|
-
window.open(`mailto:${starredEmails.join(',')}`, '_blank')
|
|
816
|
-
}
|
|
817
|
-
}}
|
|
818
|
-
/>
|
|
819
|
-
</div>
|
|
820
|
-
|
|
821
|
-
<LinkEntityDialog
|
|
822
|
-
open={linkDialogOpen}
|
|
823
|
-
onOpenChange={setLinkDialogOpen}
|
|
824
|
-
adapter={personLinkAdapter}
|
|
825
|
-
initialSelectedIds={[]}
|
|
826
|
-
onConfirm={handleLinkConfirm}
|
|
482
|
+
<LinkedPeopleSection
|
|
483
|
+
scopeId={companyId}
|
|
484
|
+
fallbackPeople={people}
|
|
485
|
+
loadPage={loadPage}
|
|
486
|
+
onUnlink={handleRemove}
|
|
487
|
+
linkAdapter={personLinkAdapter}
|
|
488
|
+
linkDialogOpen={linkDialogOpen}
|
|
489
|
+
onLinkDialogOpenChange={setLinkDialogOpen}
|
|
490
|
+
onLinkConfirm={handleLinkConfirm}
|
|
491
|
+
sectionTitle={translate('customers.companies.detail.people.sectionTitle', 'People')}
|
|
492
|
+
sectionSubtitle={translate(
|
|
493
|
+
'customers.companies.detail.people.sectionSubtitle',
|
|
494
|
+
'Employees and decision makers on the client side',
|
|
495
|
+
)}
|
|
496
|
+
searchPlaceholder={translate(
|
|
497
|
+
'customers.companies.detail.people.searchPlaceholder',
|
|
498
|
+
'Search by name, role, email...',
|
|
499
|
+
)}
|
|
500
|
+
linkActionLabel={translate(
|
|
501
|
+
'customers.companies.detail.people.linkAction',
|
|
502
|
+
'Link existing person',
|
|
503
|
+
)}
|
|
504
|
+
addActionLabel={addActionLabel}
|
|
505
|
+
onAddPerson={() => setCreateDialogOpen(true)}
|
|
506
|
+
emptyLabel={emptyLabel}
|
|
507
|
+
emptyState={emptyState}
|
|
508
|
+
refreshKey={refreshKey}
|
|
509
|
+
translator={translate}
|
|
827
510
|
runGuardedMutation={runWriteMutation}
|
|
511
|
+
onLoadingChange={onLoadingChange}
|
|
512
|
+
header={
|
|
513
|
+
<RolesSection
|
|
514
|
+
entityType="company"
|
|
515
|
+
entityId={companyId}
|
|
516
|
+
entityName={companyName ?? null}
|
|
517
|
+
/>
|
|
518
|
+
}
|
|
519
|
+
renderFooter={({ people: visible, starredIds }) => (
|
|
520
|
+
<DecisionMakersFooter
|
|
521
|
+
names={visible
|
|
522
|
+
.filter((person) => starredIds.has(person.id))
|
|
523
|
+
.map((person) => person.displayName)}
|
|
524
|
+
onSendInvitation={() => {
|
|
525
|
+
const starredEmails = visible
|
|
526
|
+
.filter((person) => starredIds.has(person.id) && person.primaryEmail)
|
|
527
|
+
.map((person) => person.primaryEmail!)
|
|
528
|
+
if (starredEmails.length > 0) {
|
|
529
|
+
window.open(`mailto:${starredEmails.join(',')}`, '_blank')
|
|
530
|
+
}
|
|
531
|
+
}}
|
|
532
|
+
/>
|
|
533
|
+
)}
|
|
828
534
|
/>
|
|
829
535
|
|
|
830
536
|
<CreatePersonDialog
|
|
@@ -835,7 +541,7 @@ export function CompanyPeopleSection({
|
|
|
835
541
|
runGuardedMutation={runWriteMutation}
|
|
836
542
|
onPersonCreated={() => {
|
|
837
543
|
setCreateDialogOpen(false)
|
|
838
|
-
|
|
544
|
+
requestRefresh()
|
|
839
545
|
void onDataRefresh?.()
|
|
840
546
|
}}
|
|
841
547
|
/>
|