@open-mercato/core 0.6.5-develop.5337.1.534b781eac → 0.6.5
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/AGENTS.md +1 -1
- package/dist/bootstrap.js +46 -6
- package/dist/bootstrap.js.map +2 -2
- package/dist/generated/entities/organization/index.js +2 -0
- package/dist/generated/entities/organization/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +1 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/crmFixtures.js +4 -0
- package/dist/helpers/integration/crmFixtures.js.map +2 -2
- package/dist/modules/attachments/api/library/route.js +2 -2
- package/dist/modules/attachments/api/library/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +2 -0
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js +9 -5
- package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
- package/dist/modules/attachments/lib/access.js +18 -0
- package/dist/modules/attachments/lib/access.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +3 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
- package/dist/modules/audit_logs/data/entities.js +2 -1
- package/dist/modules/audit_logs/data/entities.js.map +2 -2
- package/dist/modules/audit_logs/migrations/Migration20260611104500.js +13 -0
- package/dist/modules/audit_logs/migrations/Migration20260611104500.js.map +7 -0
- package/dist/modules/audit_logs/services/accessLogService.js +10 -0
- package/dist/modules/audit_logs/services/accessLogService.js.map +2 -2
- package/dist/modules/auth/api/admin/nav.js +9 -0
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/login.js +4 -13
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/commands/users.js +20 -14
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/entities.js +4 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +35 -2
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/auth/lib/consentIntegrity.js +3 -3
- package/dist/modules/auth/lib/consentIntegrity.js.map +2 -2
- package/dist/modules/auth/migrations/Migration20260610120000.js +30 -0
- package/dist/modules/auth/migrations/Migration20260610120000.js.map +7 -0
- package/dist/modules/auth/migrations/Migration20260611103000.js +15 -0
- package/dist/modules/auth/migrations/Migration20260611103000.js.map +7 -0
- package/dist/modules/auth/services/authService.js +5 -3
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/rbacService.js +3 -2
- package/dist/modules/auth/services/rbacService.js.map +2 -2
- package/dist/modules/catalog/ai-tools/configuration-pack.js.map +1 -1
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +1 -1
- package/dist/modules/catalog/ai-tools/products-pack.js.map +1 -1
- package/dist/modules/catalog/ai-tools/variants-pack.js.map +1 -1
- package/dist/modules/communication_channels/data/entities.js.map +1 -1
- package/dist/modules/communication_channels/encryption.js.map +1 -1
- package/dist/modules/communication_channels/lib/thread-matcher.js.map +1 -1
- package/dist/modules/communication_channels/lib/thread-token.js.map +1 -1
- package/dist/modules/currencies/api/currencies/route.js +4 -3
- package/dist/modules/currencies/api/currencies/route.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles.js +2 -1
- package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js +0 -3
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js.map +2 -2
- package/dist/modules/customer_accounts/events.js +1 -1
- package/dist/modules/customer_accounts/events.js.map +1 -1
- package/dist/modules/customer_accounts/lib/resolveTenantContext.js.map +1 -1
- package/dist/modules/customers/acl.js +1 -1
- package/dist/modules/customers/acl.js.map +1 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +1 -1
- package/dist/modules/customers/ai-tools/deals-pack.js.map +1 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +1 -1
- package/dist/modules/customers/api/companies/route.js +4 -4
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +43 -2
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/deals/summary/route.js +402 -0
- package/dist/modules/customers/api/deals/summary/route.js.map +7 -0
- package/dist/modules/customers/api/people/route.js +4 -4
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +16 -5
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js +22 -5
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +221 -56
- package/dist/modules/customers/backend/customers/deals/page.js.map +3 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +1 -1
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +18 -0
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/cli.js +15 -9
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +5 -5
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/comments.js +5 -5
- package/dist/modules/customers/commands/comments.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +2 -2
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/entity-roles.js +2 -1
- package/dist/modules/customers/commands/entity-roles.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +8 -5
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +21 -6
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/commands/tags.js +3 -3
- package/dist/modules/customers/commands/tags.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +282 -0
- package/dist/modules/customers/components/DealsKpiStrip.js.map +7 -0
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +0 -1
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +100 -17
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +11 -3
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +1 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/assignableStaff.js +21 -8
- package/dist/modules/customers/components/detail/assignableStaff.js.map +2 -2
- package/dist/modules/customers/components/kpi/PipelineStageBar.js +63 -0
- package/dist/modules/customers/components/kpi/PipelineStageBar.js.map +7 -0
- package/dist/modules/customers/lib/dealsMetrics.js +82 -0
- package/dist/modules/customers/lib/dealsMetrics.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260519120000_pipeline_stage_color_tones.js.map +1 -1
- package/dist/modules/data_sync/api/run.js +1 -1
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +214 -0
- package/dist/modules/directory/api/organization-branding/route.js.map +7 -0
- package/dist/modules/directory/api/organizations/route.js +7 -0
- package/dist/modules/directory/api/organizations/route.js.map +3 -3
- package/dist/modules/directory/backend/directory/branding/page.js +214 -0
- package/dist/modules/directory/backend/directory/branding/page.js.map +7 -0
- package/dist/modules/directory/backend/directory/branding/page.meta.js +26 -0
- package/dist/modules/directory/backend/directory/branding/page.meta.js.map +7 -0
- package/dist/modules/directory/commands/organizations.js +8 -1
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/data/entities.js +3 -0
- package/dist/modules/directory/data/entities.js.map +2 -2
- package/dist/modules/directory/data/validators.js +9 -0
- package/dist/modules/directory/data/validators.js.map +2 -2
- package/dist/modules/directory/migrations/Migration20260607222259_directory.js +13 -0
- package/dist/modules/directory/migrations/Migration20260607222259_directory.js.map +7 -0
- package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js +2 -1
- package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +59 -27
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/definitions.batch.js +2 -1
- package/dist/modules/entities/api/definitions.batch.js.map +2 -2
- package/dist/modules/entities/api/entities.js +7 -0
- package/dist/modules/entities/api/entities.js.map +2 -2
- package/dist/modules/entities/api/records.js +26 -15
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +14 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/create/page.js +14 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/create/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +12 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/components/useRecordsEntityGuard.js +30 -0
- package/dist/modules/entities/components/useRecordsEntityGuard.js.map +7 -0
- package/dist/modules/payment_gateways/api/transactions/route.js +2 -4
- package/dist/modules/payment_gateways/api/transactions/route.js.map +2 -2
- package/dist/modules/progress/api/jobs/[id]/route.js +7 -2
- package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
- package/dist/modules/progress/api/jobs/route.js +1 -1
- package/dist/modules/progress/api/jobs/route.js.map +2 -2
- package/dist/modules/progress/lib/progressServiceImpl.js +8 -2
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/query_index/data/entities.js +2 -1
- package/dist/modules/query_index/data/entities.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +4 -2
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/migrations/Migration20260611103000_query_index.js +16 -0
- package/dist/modules/query_index/migrations/Migration20260611103000_query_index.js.map +7 -0
- package/dist/modules/resources/api/resources.js +2 -3
- package/dist/modules/resources/api/resources.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +2 -2
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +7 -5
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -1
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/salesDocumentsColumns.js +10 -0
- package/dist/modules/sales/components/documents/salesDocumentsColumns.js.map +7 -0
- package/dist/modules/staff/api/team-members.js +9 -2
- package/dist/modules/staff/api/team-members.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +24 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +11 -6
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/commands/team-members.js +1 -1
- package/dist/modules/staff/commands/team-members.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -1
- package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
- package/dist/modules/staff/lib/scheduleSwitch.js +23 -0
- package/dist/modules/staff/lib/scheduleSwitch.js.map +7 -0
- package/dist/modules/sync_excel/api/import/route.js +1 -1
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +3 -2
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.js +1 -2
- package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +1 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +4 -13
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js +4 -13
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +1 -4
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +2 -5
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +2 -2
- package/generated/entities/organization/index.ts +1 -0
- package/generated/entity-fields-registry.ts +1 -0
- package/package.json +11 -12
- package/src/bootstrap.ts +65 -7
- package/src/helpers/integration/crmFixtures.ts +21 -1
- package/src/modules/attachments/AGENTS.md +79 -0
- package/src/modules/attachments/api/library/route.ts +2 -2
- package/src/modules/attachments/api/route.ts +2 -0
- package/src/modules/attachments/components/AttachmentContentPreview.tsx +6 -6
- package/src/modules/attachments/lib/access.ts +36 -0
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +14 -2
- package/src/modules/audit_logs/data/entities.ts +1 -0
- package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +10 -0
- package/src/modules/audit_logs/migrations/Migration20260611104500.ts +13 -0
- package/src/modules/audit_logs/services/accessLogService.ts +15 -0
- package/src/modules/auth/api/admin/nav.ts +9 -0
- package/src/modules/auth/api/login.ts +13 -13
- package/src/modules/auth/commands/users.ts +32 -15
- package/src/modules/auth/data/entities.ts +13 -1
- package/src/modules/auth/i18n/de.json +0 -1
- package/src/modules/auth/i18n/en.json +0 -1
- package/src/modules/auth/i18n/es.json +0 -1
- package/src/modules/auth/i18n/pl.json +0 -1
- package/src/modules/auth/lib/backendChrome.tsx +37 -1
- package/src/modules/auth/lib/consentIntegrity.ts +6 -3
- package/src/modules/auth/migrations/.snapshot-open-mercato.json +20 -10
- package/src/modules/auth/migrations/Migration20260610120000.ts +53 -0
- package/src/modules/auth/migrations/Migration20260611103000.ts +21 -0
- package/src/modules/auth/services/authService.ts +24 -4
- package/src/modules/auth/services/rbacService.ts +11 -2
- package/src/modules/catalog/ai-tools/configuration-pack.ts +1 -1
- package/src/modules/catalog/ai-tools/prices-offers-pack.ts +1 -1
- package/src/modules/catalog/ai-tools/products-pack.ts +1 -1
- package/src/modules/catalog/ai-tools/variants-pack.ts +1 -1
- package/src/modules/communication_channels/data/entities.ts +2 -2
- package/src/modules/communication_channels/encryption.ts +1 -1
- package/src/modules/communication_channels/lib/adapter.ts +1 -1
- package/src/modules/communication_channels/lib/thread-matcher.ts +1 -1
- package/src/modules/communication_channels/lib/thread-token.ts +1 -1
- package/src/modules/currencies/api/currencies/route.ts +4 -3
- package/src/modules/customer_accounts/api/admin/roles.ts +2 -1
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx +0 -3
- package/src/modules/customer_accounts/events.ts +1 -1
- package/src/modules/customer_accounts/lib/resolveTenantContext.ts +2 -2
- package/src/modules/customers/acl.ts +1 -1
- package/src/modules/customers/ai-tools/companies-pack.ts +1 -1
- package/src/modules/customers/ai-tools/deals-pack.ts +1 -1
- package/src/modules/customers/ai-tools/people-pack.ts +1 -1
- package/src/modules/customers/api/companies/route.ts +4 -4
- package/src/modules/customers/api/deals/route.ts +51 -2
- package/src/modules/customers/api/deals/summary/route.ts +496 -0
- package/src/modules/customers/api/people/route.ts +4 -4
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +28 -6
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealData.ts +33 -6
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +17 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +254 -66
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +1 -2
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -0
- package/src/modules/customers/cli.ts +15 -15
- package/src/modules/customers/commands/addresses.ts +5 -5
- package/src/modules/customers/commands/comments.ts +5 -5
- package/src/modules/customers/commands/deals.ts +2 -2
- package/src/modules/customers/commands/entity-roles.ts +2 -1
- package/src/modules/customers/commands/interactions.ts +8 -5
- package/src/modules/customers/commands/shared.ts +26 -4
- package/src/modules/customers/commands/tags.ts +3 -3
- package/src/modules/customers/components/DealsKpiStrip.tsx +389 -0
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +0 -1
- package/src/modules/customers/components/detail/DealForm.tsx +121 -19
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +12 -2
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +1 -2
- package/src/modules/customers/components/detail/assignableStaff.ts +32 -8
- package/src/modules/customers/components/kpi/PipelineStageBar.tsx +77 -0
- package/src/modules/customers/i18n/de.json +43 -0
- package/src/modules/customers/i18n/en.json +43 -0
- package/src/modules/customers/i18n/es.json +43 -0
- package/src/modules/customers/i18n/pl.json +43 -0
- package/src/modules/customers/lib/dealsMetrics.ts +159 -0
- package/src/modules/customers/migrations/Migration20260519120000_pipeline_stage_color_tones.ts +1 -1
- package/src/modules/data_sync/api/run.ts +1 -1
- package/src/modules/directory/api/organization-branding/route.ts +238 -0
- package/src/modules/directory/api/organizations/route.ts +7 -0
- package/src/modules/directory/backend/directory/branding/page.meta.ts +24 -0
- package/src/modules/directory/backend/directory/branding/page.tsx +248 -0
- package/src/modules/directory/commands/organizations.ts +9 -1
- package/src/modules/directory/data/entities.ts +3 -0
- package/src/modules/directory/data/validators.ts +12 -0
- package/src/modules/directory/i18n/de.json +21 -0
- package/src/modules/directory/i18n/en.json +21 -0
- package/src/modules/directory/i18n/es.json +21 -0
- package/src/modules/directory/i18n/pl.json +21 -0
- package/src/modules/directory/migrations/.snapshot-open-mercato.json +40 -0
- package/src/modules/directory/migrations/Migration20260607222259_directory.ts +13 -0
- package/src/modules/directory/subscribers/invalidateOrgScopeCache.ts +3 -1
- package/src/modules/directory/utils/organizationScope.ts +85 -30
- package/src/modules/entities/api/definitions.batch.ts +11 -7
- package/src/modules/entities/api/entities.ts +11 -0
- package/src/modules/entities/api/records.ts +46 -25
- package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +15 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/create/page.tsx +15 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +23 -0
- package/src/modules/entities/components/useRecordsEntityGuard.ts +41 -0
- package/src/modules/entities/i18n/de.json +1 -0
- package/src/modules/entities/i18n/en.json +1 -0
- package/src/modules/entities/i18n/es.json +1 -0
- package/src/modules/entities/i18n/pl.json +1 -0
- package/src/modules/payment_gateways/api/transactions/route.ts +2 -5
- package/src/modules/progress/api/jobs/[id]/route.ts +6 -1
- package/src/modules/progress/api/jobs/route.ts +1 -1
- package/src/modules/progress/lib/progressServiceImpl.ts +7 -1
- package/src/modules/query_index/data/entities.ts +1 -0
- package/src/modules/query_index/lib/engine.ts +11 -5
- package/src/modules/query_index/migrations/.snapshot-open-mercato.json +11 -0
- package/src/modules/query_index/migrations/Migration20260611103000_query_index.ts +29 -0
- package/src/modules/resources/api/resources.ts +2 -3
- package/src/modules/sales/api/documents/factory.ts +2 -2
- package/src/modules/sales/commands/documents.ts +7 -5
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -1
- package/src/modules/sales/components/documents/salesDocumentsColumns.ts +6 -0
- package/src/modules/staff/AGENTS.md +1 -1
- package/src/modules/staff/api/team-members.ts +9 -2
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +31 -1
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +18 -8
- package/src/modules/staff/commands/team-members.ts +5 -2
- package/src/modules/staff/components/TeamMemberForm.tsx +4 -1
- package/src/modules/staff/i18n/de.json +1 -0
- package/src/modules/staff/i18n/en.json +1 -0
- package/src/modules/staff/i18n/es.json +1 -0
- package/src/modules/staff/i18n/pl.json +1 -0
- package/src/modules/staff/lib/scheduleSwitch.ts +46 -0
- package/src/modules/sync_excel/api/import/route.ts +1 -1
- package/src/modules/workflows/api/definitions/route.ts +3 -2
- package/src/modules/workflows/backend/definitions/create/page.tsx +1 -2
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +1 -2
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -2
- package/src/modules/workflows/components/NodeEditDialog.tsx +1 -4
- package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +4 -7
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +1 -2
- package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +2 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/commands/tags.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerTag, CustomerTagAssignment } from '../data/entities'\nimport {\n tagCreateSchema,\n tagUpdateSchema,\n tagAssignmentSchema,\n type TagCreateInput,\n type TagUpdateInput,\n type TagAssignmentInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireCustomerEntity,\n ensureSameScope,\n loadEntityTagIds,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitCustomersEvent } from '../events'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\n\nconst tagCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'tag',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype TagSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n slug: string\n label: string\n color: string | null\n description: string | null\n}\n\ntype TagUndoPayload = {\n before?: TagSnapshot | null\n after?: TagSnapshot | null\n}\n\ntype TagAssignmentSnapshot = {\n tagId: string\n entityId: string\n organizationId: string\n tenantId: string\n}\n\ntype TagAssignmentUndoPayload = {\n before?: TagAssignmentSnapshot | null\n}\n\nasync function loadTagSnapshot(em: EntityManager, id: string): Promise<TagSnapshot | null> {\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) return null\n return {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n slug: tag.slug,\n label: tag.label,\n color: tag.color ?? null,\n description: tag.description ?? null,\n }\n}\n\nconst createTagCommand: CommandHandler<TagCreateInput, { tagId: string }> = {\n id: 'customers.tags.create',\n async execute(rawInput, ctx) {\n const parsed = tagCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n\n const tag = em.create(CustomerTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug: parsed.slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n })\n em.persist(tag)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadTagSnapshot(em, result.tagId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTagSnapshot(em, result.tagId)\n return {\n actionLabel: translate('customers.audit.tags.create', 'Create tag'),\n resourceKind: 'customers.tag',\n resourceId: result.tagId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const tagId = logEntry?.resourceId ?? null\n if (!tagId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: tagId })\n if (tag) {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n await em.flush()\n }\n },\n redo: makeCreateRedo<CustomerTag, TagSnapshot, TagCreateInput, { tagId: string }>({\n entityClass: CustomerTag,\n buildResult: (entity) => ({ tagId: entity.id }),\n events: tagCrudEvents,\n }),\n}\n\nconst updateTagCommand: CommandHandler<TagUpdateInput, { tagId: string }> = {\n id: 'customers.tags.update',\n async prepare(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n\n if (parsed.slug !== undefined && parsed.slug !== tag.slug) {\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n id: { $ne: tag.id },\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadTagSnapshot(em, before.id)\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['slug', 'label', 'color', 'description']\n )\n : {}\n return {\n actionLabel: translate('customers.audit.tags.update', 'Update tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { tagId: string }> = {\n id: 'customers.tags.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await withAtomicFlush(em, [\n async () => {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.tags.delete', 'Delete tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n const restoredTag = tag\n await withAtomicFlush(em, [\n () => {\n em.persist(restoredTag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string }> = {\n id: 'customers.tags.assign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, parsed.organizationId, parsed.tenantId)\n const tagIds = await loadEntityTagIds(em, entity)\n if (tagIds.includes(parsed.tagId)) {\n throw new CrudHttpError(409, { error: 'Tag already assigned' })\n }\n\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await findOneWithDecryption(\n em,\n CustomerTagAssignment,\n { id: result.assignmentId },\n { populate: ['tag', 'entity'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null },\n )\n if (!assignment) return null\n const tagId = typeof assignment.tag === 'string' ? assignment.tag : assignment.tag.id\n const entityId = typeof assignment.entity === 'string' ? assignment.entity : assignment.entity.id\n return {\n actionLabel: translate('customers.audit.tags.assign', 'Assign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: result.assignmentId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n payload: {\n undo: {\n before: {\n tagId,\n entityId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await em.nativeDelete(CustomerTagAssignment, {\n tag: before.tagId,\n entity: before.entityId,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n },\n redo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for tag assign' })\n }\n const assignmentId = logEntry?.resourceId ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n\n let assignment = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!assignment) {\n assignment = em.create(CustomerTagAssignment, {\n ...(assignmentId ? { id: assignmentId } : {}),\n tag,\n entity,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: before.tagId,\n entityId: before.entityId,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n}\n\nconst unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string | null }> = {\n id: 'customers.tags.unassign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await em.findOne(CustomerTagAssignment, {\n tag: parsed.tagId,\n entity: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n })\n if (!existing) throw new CrudHttpError(404, { error: 'Tag assignment not found' })\n await em.remove(existing).flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: existing,\n identifiers: {\n id: String(existing.id),\n organizationId: existing.organizationId,\n tenantId: existing.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.removed', {\n id: String(existing.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: existing.id ?? null }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const parsed = tagAssignmentSchema.parse(input)\n return {\n actionLabel: translate('customers.audit.tags.unassign', 'Unassign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: parsed.tagId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: {\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const existing = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!existing) {\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n em.persist(assignment)\n await em.flush()\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\nregisterCommand(assignTagCommand)\nregisterCommand(unassignTagCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerTag, CustomerTagAssignment } from '../data/entities'\nimport {\n tagCreateSchema,\n tagUpdateSchema,\n tagAssignmentSchema,\n type TagCreateInput,\n type TagUpdateInput,\n type TagAssignmentInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireCustomerEntity,\n ensureSameScope,\n loadEntityTagIds,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitCustomersEvent } from '../events'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\n\nconst tagCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'tag',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype TagSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n slug: string\n label: string\n color: string | null\n description: string | null\n}\n\ntype TagUndoPayload = {\n before?: TagSnapshot | null\n after?: TagSnapshot | null\n}\n\ntype TagAssignmentSnapshot = {\n tagId: string\n entityId: string\n organizationId: string\n tenantId: string\n}\n\ntype TagAssignmentUndoPayload = {\n before?: TagAssignmentSnapshot | null\n}\n\nasync function loadTagSnapshot(em: EntityManager, id: string): Promise<TagSnapshot | null> {\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) return null\n return {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n slug: tag.slug,\n label: tag.label,\n color: tag.color ?? null,\n description: tag.description ?? null,\n }\n}\n\nconst createTagCommand: CommandHandler<TagCreateInput, { tagId: string }> = {\n id: 'customers.tags.create',\n async execute(rawInput, ctx) {\n const parsed = tagCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n\n const tag = em.create(CustomerTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug: parsed.slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n })\n em.persist(tag)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadTagSnapshot(em, result.tagId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTagSnapshot(em, result.tagId)\n return {\n actionLabel: translate('customers.audit.tags.create', 'Create tag'),\n resourceKind: 'customers.tag',\n resourceId: result.tagId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const tagId = logEntry?.resourceId ?? null\n if (!tagId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: tagId })\n if (tag) {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n await em.flush()\n }\n },\n redo: makeCreateRedo<CustomerTag, TagSnapshot, TagCreateInput, { tagId: string }>({\n entityClass: CustomerTag,\n buildResult: (entity) => ({ tagId: entity.id }),\n events: tagCrudEvents,\n }),\n}\n\nconst updateTagCommand: CommandHandler<TagUpdateInput, { tagId: string }> = {\n id: 'customers.tags.update',\n async prepare(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = tagUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n\n if (parsed.slug !== undefined && parsed.slug !== tag.slug) {\n const duplicate = await em.findOne(CustomerTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n id: { $ne: tag.id },\n })\n if (duplicate) throw new CrudHttpError(409, { error: 'Tag slug already exists' })\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadTagSnapshot(em, before.id)\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['slug', 'label', 'color', 'description']\n )\n : {}\n return {\n actionLabel: translate('customers.audit.tags.update', 'Update tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { tagId: string }> = {\n id: 'customers.tags.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTagSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Tag id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await withAtomicFlush(em, [\n async () => {\n await em.nativeDelete(CustomerTagAssignment, { tag })\n em.remove(tag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n return { tagId: tag.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TagSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.tags.delete', 'Delete tag'),\n resourceKind: 'customers.tag',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TagUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let tag = await em.findOne(CustomerTag, { id: before.id })\n if (!tag) {\n tag = em.create(CustomerTag, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n slug: before.slug,\n label: before.label,\n color: before.color,\n description: before.description,\n })\n em.persist(tag)\n } else {\n tag.slug = before.slug\n tag.label = before.label\n tag.color = before.color\n tag.description = before.description\n }\n const restoredTag = tag\n await withAtomicFlush(em, [\n () => {\n em.persist(restoredTag)\n },\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: tag,\n identifiers: {\n id: tag.id,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n },\n events: tagCrudEvents,\n })\n },\n}\n\nconst assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string }> = {\n id: 'customers.tags.assign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, undefined, 'Customer not found')\n ensureSameScope(entity, parsed.organizationId, parsed.tenantId)\n const tagIds = await loadEntityTagIds(em, entity)\n if (tagIds.includes(parsed.tagId)) {\n throw new CrudHttpError(409, { error: 'Tag already assigned' })\n }\n\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const assignment = await findOneWithDecryption(\n em,\n CustomerTagAssignment,\n { id: result.assignmentId },\n { populate: ['tag', 'entity'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null },\n )\n if (!assignment) return null\n const tagId = typeof assignment.tag === 'string' ? assignment.tag : assignment.tag.id\n const entityId = typeof assignment.entity === 'string' ? assignment.entity : assignment.entity.id\n return {\n actionLabel: translate('customers.audit.tags.assign', 'Assign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: result.assignmentId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n payload: {\n undo: {\n before: {\n tagId,\n entityId,\n tenantId: assignment.tenantId,\n organizationId: assignment.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n await em.nativeDelete(CustomerTagAssignment, {\n tag: before.tagId,\n entity: before.entityId,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n },\n redo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for tag assign' })\n }\n const assignmentId = logEntry?.resourceId ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n\n let assignment = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!assignment) {\n assignment = em.create(CustomerTagAssignment, {\n ...(assignmentId ? { id: assignmentId } : {}),\n tag,\n entity,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n })\n em.persist(assignment)\n await em.flush()\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: assignment,\n identifiers: {\n id: String(assignment.id),\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.assigned', {\n id: String(assignment.id),\n tagId: before.tagId,\n entityId: before.entityId,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n }, { persistent: true })\n\n return { assignmentId: assignment.id }\n },\n}\n\nconst unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: string | null }> = {\n id: 'customers.tags.unassign',\n async execute(rawInput, ctx) {\n const parsed = tagAssignmentSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await em.findOne(CustomerTagAssignment, {\n tag: parsed.tagId,\n entity: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n })\n if (!existing) throw new CrudHttpError(404, { error: 'Tag assignment not found' })\n await em.remove(existing).flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: existing,\n identifiers: {\n id: String(existing.id),\n organizationId: existing.organizationId,\n tenantId: existing.tenantId,\n },\n })\n\n await emitCustomersEvent('customers.tag.removed', {\n id: String(existing.id),\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n }, { persistent: true })\n\n return { assignmentId: existing.id ?? null }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const parsed = tagAssignmentSchema.parse(input)\n return {\n actionLabel: translate('customers.audit.tags.unassign', 'Unassign tag'),\n resourceKind: 'customers.tagAssignment',\n resourceId: parsed.tagId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: {\n tagId: parsed.tagId,\n entityId: parsed.entityId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n } satisfies TagAssignmentSnapshot,\n } satisfies TagAssignmentUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TagAssignmentUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(CustomerTag, { id: before.tagId })\n const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')\n ensureSameScope(entity, before.organizationId, before.tenantId)\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n const existing = await em.findOne(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n if (!existing) {\n const assignment = em.create(CustomerTagAssignment, {\n tag,\n entity,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\n em.persist(assignment)\n await em.flush()\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\nregisterCommand(assignTagCommand)\nregisterCommand(unassignTagCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { CheckCircle } from "lucide-react";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
+
import { KpiCard, DeltaBadge, Sparkline } from "@open-mercato/ui/backend/charts";
|
|
9
|
+
import { Avatar, AvatarStack } from "@open-mercato/ui/primitives/avatar";
|
|
10
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
11
|
+
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
12
|
+
import { PipelineStageBar } from "./kpi/PipelineStageBar.js";
|
|
13
|
+
const compactNumberFormatter = new Intl.NumberFormat(void 0, {
|
|
14
|
+
notation: "compact",
|
|
15
|
+
maximumFractionDigits: 1
|
|
16
|
+
});
|
|
17
|
+
function formatCompact(value) {
|
|
18
|
+
return compactNumberFormatter.format(value);
|
|
19
|
+
}
|
|
20
|
+
function buildCurrencySuffix(code, convertedAll) {
|
|
21
|
+
if (!code) return convertedAll ? "" : "\u2248";
|
|
22
|
+
return convertedAll ? code : `\u2248 ${code}`;
|
|
23
|
+
}
|
|
24
|
+
const KPI_TITLE_CLASS = "text-xs font-semibold uppercase tracking-wide text-muted-foreground";
|
|
25
|
+
function DealKpiCard(props) {
|
|
26
|
+
return /* @__PURE__ */ jsx(KpiCard, { titleClassName: KPI_TITLE_CLASS, ...props });
|
|
27
|
+
}
|
|
28
|
+
function KpiDeltaBadge({
|
|
29
|
+
direction,
|
|
30
|
+
value,
|
|
31
|
+
unit,
|
|
32
|
+
title
|
|
33
|
+
}) {
|
|
34
|
+
if (direction === "unchanged" && value === 0) {
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"span",
|
|
37
|
+
{
|
|
38
|
+
className: "inline-flex items-center rounded-md bg-status-neutral-bg px-2 py-0.5 text-xs font-medium text-status-neutral-text",
|
|
39
|
+
title,
|
|
40
|
+
children: "--"
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ jsx(DeltaBadge, { direction, value, unit, title });
|
|
45
|
+
}
|
|
46
|
+
function isObject(value) {
|
|
47
|
+
return typeof value === "object" && value !== null;
|
|
48
|
+
}
|
|
49
|
+
function isDealsSummaryResponse(value) {
|
|
50
|
+
if (!isObject(value)) return false;
|
|
51
|
+
const { pipelineValue, activeDeals, wonThisQuarter, winRate } = value;
|
|
52
|
+
return isObject(pipelineValue) && Array.isArray(pipelineValue.stages) && isObject(activeDeals) && Array.isArray(activeDeals.owners) && isObject(wonThisQuarter) && isObject(winRate) && Array.isArray(winRate.series);
|
|
53
|
+
}
|
|
54
|
+
function DealsKpiStrip({
|
|
55
|
+
ownerNames,
|
|
56
|
+
stageDictionary,
|
|
57
|
+
pipelineCount,
|
|
58
|
+
className,
|
|
59
|
+
scopeVersion,
|
|
60
|
+
reloadToken,
|
|
61
|
+
onNeedsAttentionClick
|
|
62
|
+
}) {
|
|
63
|
+
const t = useT();
|
|
64
|
+
const locale = useLocale();
|
|
65
|
+
const pluralCat = React.useCallback((count) => {
|
|
66
|
+
try {
|
|
67
|
+
return new Intl.PluralRules(locale).select(count);
|
|
68
|
+
} catch {
|
|
69
|
+
return count === 1 ? "one" : "other";
|
|
70
|
+
}
|
|
71
|
+
}, [locale]);
|
|
72
|
+
const pf = React.useCallback((base, count) => {
|
|
73
|
+
const cat = pluralCat(count);
|
|
74
|
+
const key = `${base}.${cat}`;
|
|
75
|
+
const out = t(key, { count });
|
|
76
|
+
return out === key ? t(`${base}.other`, { count }) : out;
|
|
77
|
+
}, [t, pluralCat]);
|
|
78
|
+
const [data, setData] = React.useState(null);
|
|
79
|
+
const [loading, setLoading] = React.useState(true);
|
|
80
|
+
const [error, setError] = React.useState(null);
|
|
81
|
+
const [retryToken, setRetryToken] = React.useState(0);
|
|
82
|
+
const previousScopeVersionRef = React.useRef(scopeVersion);
|
|
83
|
+
const retry = React.useCallback(() => {
|
|
84
|
+
setRetryToken((token) => token + 1);
|
|
85
|
+
}, []);
|
|
86
|
+
React.useEffect(() => {
|
|
87
|
+
let cancelled = false;
|
|
88
|
+
const scopeChanged = previousScopeVersionRef.current !== scopeVersion;
|
|
89
|
+
previousScopeVersionRef.current = scopeVersion;
|
|
90
|
+
if (scopeChanged) setData(null);
|
|
91
|
+
setLoading(true);
|
|
92
|
+
setError(null);
|
|
93
|
+
apiCall("/api/customers/deals/summary").then((call) => {
|
|
94
|
+
if (cancelled) return;
|
|
95
|
+
if (!call.ok || !isDealsSummaryResponse(call.result)) {
|
|
96
|
+
setError(t("customers.deals.list.kpi.error"));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setData(call.result);
|
|
100
|
+
}).catch(() => {
|
|
101
|
+
if (cancelled) return;
|
|
102
|
+
setError(t("customers.deals.list.kpi.error"));
|
|
103
|
+
}).finally(() => {
|
|
104
|
+
if (!cancelled) setLoading(false);
|
|
105
|
+
});
|
|
106
|
+
return () => {
|
|
107
|
+
cancelled = true;
|
|
108
|
+
};
|
|
109
|
+
}, [t, scopeVersion, reloadToken, retryToken]);
|
|
110
|
+
const wrapperClassName = cn("space-y-2", className);
|
|
111
|
+
const gridClassName = "grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4";
|
|
112
|
+
if (loading && !data) {
|
|
113
|
+
return /* @__PURE__ */ jsx("div", { className: wrapperClassName, children: /* @__PURE__ */ jsxs("div", { className: gridClassName, children: [
|
|
114
|
+
/* @__PURE__ */ jsx(DealKpiCard, { loading: true, title: t("customers.deals.list.kpi.pipelineValue"), value: null }),
|
|
115
|
+
/* @__PURE__ */ jsx(DealKpiCard, { loading: true, title: t("customers.deals.list.kpi.activeDeals"), value: null }),
|
|
116
|
+
/* @__PURE__ */ jsx(DealKpiCard, { loading: true, title: t("customers.deals.list.kpi.wonThisQuarter"), value: null }),
|
|
117
|
+
/* @__PURE__ */ jsx(DealKpiCard, { loading: true, title: t("customers.deals.list.kpi.winRate"), value: null })
|
|
118
|
+
] }) });
|
|
119
|
+
}
|
|
120
|
+
if (!data) {
|
|
121
|
+
const errorMessage = error ?? t("customers.deals.list.kpi.error");
|
|
122
|
+
return /* @__PURE__ */ jsx("div", { className: wrapperClassName, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4", children: [
|
|
123
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errorMessage }),
|
|
124
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive-outline", size: "sm", onClick: retry, children: t("customers.deals.list.kpi.retry") })
|
|
125
|
+
] }) });
|
|
126
|
+
}
|
|
127
|
+
const currencySuffix = buildCurrencySuffix(data.baseCurrencyCode, data.convertedAll);
|
|
128
|
+
const unassignedLabel = t("customers.deals.list.kpi.unassignedStage");
|
|
129
|
+
const deltaTooltip = t("customers.deals.list.kpi.deltaTooltip");
|
|
130
|
+
const deltaUnavailableTooltip = t("customers.deals.list.kpi.deltaUnavailable");
|
|
131
|
+
const scopeLabel = t("customers.deals.list.kpi.scopeAllPipelinesThisQuarter");
|
|
132
|
+
const unknownOwner = t("customers.deals.list.unknownOwner");
|
|
133
|
+
const currencyHint = !data.convertedAll ? data.baseCurrencyCode ? t("customers.deals.list.kpi.currencyApproxMissing", {
|
|
134
|
+
currencies: data.missingRateCurrencies.length ? data.missingRateCurrencies.join(", ") : currencySuffix
|
|
135
|
+
}) : t("customers.deals.list.kpi.currencyApproxNoBase") : null;
|
|
136
|
+
const attentionLabel = pf("customers.deals.list.kpi.frag.needAttention", data.activeDeals.needAttention);
|
|
137
|
+
return /* @__PURE__ */ jsxs("div", { className: wrapperClassName, children: [
|
|
138
|
+
error ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2", children: [
|
|
139
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error }),
|
|
140
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive-outline", size: "2xs", onClick: retry, children: t("customers.deals.list.kpi.retry") })
|
|
141
|
+
] }) : null,
|
|
142
|
+
loading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 text-xs text-muted-foreground", children: [
|
|
143
|
+
/* @__PURE__ */ jsx(Spinner, { className: "h-3 w-3" }),
|
|
144
|
+
/* @__PURE__ */ jsx("span", { children: t("customers.deals.list.kpi.updating") })
|
|
145
|
+
] }) : null,
|
|
146
|
+
/* @__PURE__ */ jsxs("div", { className: gridClassName, children: [
|
|
147
|
+
/* @__PURE__ */ jsx(
|
|
148
|
+
DealKpiCard,
|
|
149
|
+
{
|
|
150
|
+
title: t("customers.deals.list.kpi.pipelineValue"),
|
|
151
|
+
value: data.pipelineValue.value,
|
|
152
|
+
formatValue: formatCompact,
|
|
153
|
+
suffix: currencySuffix,
|
|
154
|
+
headerAction: /* @__PURE__ */ jsx(
|
|
155
|
+
KpiDeltaBadge,
|
|
156
|
+
{
|
|
157
|
+
direction: data.pipelineValue.delta.direction,
|
|
158
|
+
value: data.pipelineValue.delta.value,
|
|
159
|
+
title: data.pipelineValue.delta.direction === "unchanged" && data.pipelineValue.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
footer: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
163
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: scopeLabel }),
|
|
164
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("customers.deals.list.kpi.activeAcrossPipelines", {
|
|
165
|
+
deals: pf("customers.deals.list.kpi.frag.activeDeals", data.activeDeals.value),
|
|
166
|
+
pipelines: pf("customers.deals.list.kpi.frag.pipelines", pipelineCount)
|
|
167
|
+
}) }),
|
|
168
|
+
currencyHint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: currencyHint }) : null,
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
PipelineStageBar,
|
|
171
|
+
{
|
|
172
|
+
stages: data.pipelineValue.stages,
|
|
173
|
+
stageDictionary,
|
|
174
|
+
unassignedLabel
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
] })
|
|
178
|
+
}
|
|
179
|
+
),
|
|
180
|
+
/* @__PURE__ */ jsx(
|
|
181
|
+
DealKpiCard,
|
|
182
|
+
{
|
|
183
|
+
title: t("customers.deals.list.kpi.activeDeals"),
|
|
184
|
+
value: data.activeDeals.value,
|
|
185
|
+
formatValue: formatCompact,
|
|
186
|
+
headerAction: /* @__PURE__ */ jsx(
|
|
187
|
+
KpiDeltaBadge,
|
|
188
|
+
{
|
|
189
|
+
direction: data.activeDeals.delta.direction,
|
|
190
|
+
value: data.activeDeals.delta.value,
|
|
191
|
+
title: data.activeDeals.delta.direction === "unchanged" && data.activeDeals.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
footer: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
195
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: scopeLabel }),
|
|
196
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-1.5 gap-y-1 text-xs text-muted-foreground", children: [
|
|
197
|
+
/* @__PURE__ */ jsx("span", { children: pf("customers.deals.list.kpi.frag.owners", data.activeDeals.ownersCount) }),
|
|
198
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
199
|
+
onNeedsAttentionClick && data.activeDeals.needAttention > 0 ? /* @__PURE__ */ jsx(
|
|
200
|
+
Button,
|
|
201
|
+
{
|
|
202
|
+
type: "button",
|
|
203
|
+
variant: "link",
|
|
204
|
+
size: "2xs",
|
|
205
|
+
className: "h-auto p-0 text-xs",
|
|
206
|
+
onClick: onNeedsAttentionClick,
|
|
207
|
+
children: attentionLabel
|
|
208
|
+
}
|
|
209
|
+
) : /* @__PURE__ */ jsx("span", { children: attentionLabel })
|
|
210
|
+
] }),
|
|
211
|
+
data.activeDeals.owners.length > 0 ? /* @__PURE__ */ jsx(AvatarStack, { max: 4, size: "sm", overflowCount: data.activeDeals.ownersOverflow, children: data.activeDeals.owners.map((owner) => {
|
|
212
|
+
const ownerLabel = ownerNames[owner.id]?.trim() || unknownOwner;
|
|
213
|
+
return /* @__PURE__ */ jsx(Avatar, { label: ownerLabel, size: "sm" }, owner.id);
|
|
214
|
+
}) }) : null
|
|
215
|
+
] })
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
/* @__PURE__ */ jsx(
|
|
219
|
+
DealKpiCard,
|
|
220
|
+
{
|
|
221
|
+
title: t("customers.deals.list.kpi.wonThisQuarter"),
|
|
222
|
+
value: data.wonThisQuarter.value,
|
|
223
|
+
formatValue: formatCompact,
|
|
224
|
+
suffix: currencySuffix,
|
|
225
|
+
headerAction: /* @__PURE__ */ jsx(
|
|
226
|
+
KpiDeltaBadge,
|
|
227
|
+
{
|
|
228
|
+
direction: data.wonThisQuarter.delta.direction,
|
|
229
|
+
value: data.wonThisQuarter.delta.value,
|
|
230
|
+
title: data.wonThisQuarter.delta.direction === "unchanged" && data.wonThisQuarter.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
footer: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
234
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: scopeLabel }),
|
|
235
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
236
|
+
/* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-status-success-text", "aria-hidden": true }),
|
|
237
|
+
/* @__PURE__ */ jsx("span", { children: pf("customers.deals.list.kpi.frag.dealsClosed", data.wonThisQuarter.dealsClosed) })
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("customers.deals.list.kpi.avgDeal", {
|
|
240
|
+
value: `${formatCompact(data.wonThisQuarter.avgDeal)}${currencySuffix ? ` ${currencySuffix}` : ""}`
|
|
241
|
+
}) }),
|
|
242
|
+
currencyHint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: currencyHint }) : null
|
|
243
|
+
] })
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ jsx(
|
|
247
|
+
DealKpiCard,
|
|
248
|
+
{
|
|
249
|
+
title: t("customers.deals.list.kpi.winRate"),
|
|
250
|
+
value: data.winRate.value,
|
|
251
|
+
suffix: "%",
|
|
252
|
+
headerAction: /* @__PURE__ */ jsx(
|
|
253
|
+
KpiDeltaBadge,
|
|
254
|
+
{
|
|
255
|
+
direction: data.winRate.direction,
|
|
256
|
+
value: Math.abs(data.winRate.deltaPp),
|
|
257
|
+
unit: "pp",
|
|
258
|
+
title: data.winRate.previousValue === 0 ? deltaUnavailableTooltip : deltaTooltip
|
|
259
|
+
}
|
|
260
|
+
),
|
|
261
|
+
footer: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
262
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: scopeLabel }),
|
|
263
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("customers.deals.list.kpi.fromLastQuarter", { value: data.winRate.previousValue }) }),
|
|
264
|
+
/* @__PURE__ */ jsx("div", { className: "text-primary", children: /* @__PURE__ */ jsx(
|
|
265
|
+
Sparkline,
|
|
266
|
+
{
|
|
267
|
+
values: data.winRate.series.map((point) => point.rate),
|
|
268
|
+
ariaLabel: t("customers.deals.list.kpi.winRate")
|
|
269
|
+
}
|
|
270
|
+
) })
|
|
271
|
+
] })
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
] })
|
|
275
|
+
] });
|
|
276
|
+
}
|
|
277
|
+
var DealsKpiStrip_default = DealsKpiStrip;
|
|
278
|
+
export {
|
|
279
|
+
DealsKpiStrip,
|
|
280
|
+
DealsKpiStrip_default as default
|
|
281
|
+
};
|
|
282
|
+
//# sourceMappingURL=DealsKpiStrip.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/components/DealsKpiStrip.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CheckCircle } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { KpiCard, DeltaBadge, Sparkline } from '@open-mercato/ui/backend/charts'\nimport { Avatar, AvatarStack } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport type { DictionaryMap } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { PipelineStageBar } from './kpi/PipelineStageBar'\n\ntype DeltaDirection = 'up' | 'down' | 'unchanged'\n\ntype SummaryDelta = {\n value: number\n direction: DeltaDirection\n}\n\ntype DealsSummaryResponse = {\n baseCurrencyCode: string | null\n convertedAll: boolean\n missingRateCurrencies: string[]\n pipelineValue: {\n value: number\n delta: SummaryDelta\n stages: { stage: string | null; count: number; value: number }[]\n }\n activeDeals: {\n value: number\n delta: SummaryDelta\n ownersCount: number\n needAttention: number\n owners: { id: string; count: number }[]\n ownersOverflow: number\n }\n wonThisQuarter: {\n value: number\n delta: SummaryDelta\n dealsClosed: number\n avgDeal: number\n }\n winRate: {\n value: number\n deltaPp: number\n direction: DeltaDirection\n previousValue: number\n series: { period: string; rate: number }[]\n }\n}\n\nexport type DealsKpiStripProps = {\n ownerNames: Record<string, string>\n stageDictionary: DictionaryMap\n pipelineCount: number\n className?: string\n /** Bumped by the host when the active org scope changes \u2014 forces a KPI refetch so the cards never show another org's data. */\n scopeVersion?: number\n /** Bumped by the host on manual refresh / after mutations \u2014 forces a KPI refetch so totals stay in sync with the table. */\n reloadToken?: number\n onNeedsAttentionClick?: () => void\n}\n\nconst compactNumberFormatter = new Intl.NumberFormat(undefined, {\n notation: 'compact',\n maximumFractionDigits: 1,\n})\n\nfunction formatCompact(value: number): string {\n return compactNumberFormatter.format(value)\n}\n\nfunction buildCurrencySuffix(code: string | null, convertedAll: boolean): string {\n if (!code) return convertedAll ? '' : '\u2248'\n return convertedAll ? code : `\u2248 ${code}`\n}\n\nconst KPI_TITLE_CLASS = 'text-xs font-semibold uppercase tracking-wide text-muted-foreground'\n\nfunction DealKpiCard(props: React.ComponentProps<typeof KpiCard>) {\n return <KpiCard titleClassName={KPI_TITLE_CLASS} {...props} />\n}\n\nfunction KpiDeltaBadge({\n direction,\n value,\n unit,\n title,\n}: {\n direction: DeltaDirection\n value: number\n unit?: string\n title: string\n}) {\n if (direction === 'unchanged' && value === 0) {\n return (\n <span\n className=\"inline-flex items-center rounded-md bg-status-neutral-bg px-2 py-0.5 text-xs font-medium text-status-neutral-text\"\n title={title}\n >\n --\n </span>\n )\n }\n return <DeltaBadge direction={direction} value={value} unit={unit} title={title} />\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\n// Guard the summary payload before rendering: a non-conforming response (an unrelated\n// endpoint mock, an error body, or a future contract drift) must surface the error card,\n// never crash the whole deals page by dereferencing missing sections/arrays.\nfunction isDealsSummaryResponse(value: unknown): value is DealsSummaryResponse {\n if (!isObject(value)) return false\n const { pipelineValue, activeDeals, wonThisQuarter, winRate } = value\n return (\n isObject(pipelineValue) && Array.isArray(pipelineValue.stages) &&\n isObject(activeDeals) && Array.isArray(activeDeals.owners) &&\n isObject(wonThisQuarter) &&\n isObject(winRate) && Array.isArray(winRate.series)\n )\n}\n\nexport function DealsKpiStrip({\n ownerNames,\n stageDictionary,\n pipelineCount,\n className,\n scopeVersion,\n reloadToken,\n onNeedsAttentionClick,\n}: DealsKpiStripProps) {\n const t = useT()\n const locale = useLocale()\n const pluralCat = React.useCallback((count: number): string => {\n try {\n return new Intl.PluralRules(locale).select(count)\n } catch {\n return count === 1 ? 'one' : 'other'\n }\n }, [locale])\n const pf = React.useCallback((base: string, count: number): string => {\n const cat = pluralCat(count)\n const key = `${base}.${cat}`\n const out = t(key, { count })\n return out === key ? t(`${base}.other`, { count }) : out\n }, [t, pluralCat])\n const [data, setData] = React.useState<DealsSummaryResponse | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [retryToken, setRetryToken] = React.useState(0)\n const previousScopeVersionRef = React.useRef(scopeVersion)\n\n const retry = React.useCallback(() => {\n setRetryToken((token) => token + 1)\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n const scopeChanged = previousScopeVersionRef.current !== scopeVersion\n previousScopeVersionRef.current = scopeVersion\n if (scopeChanged) setData(null)\n setLoading(true)\n setError(null)\n apiCall<DealsSummaryResponse>('/api/customers/deals/summary')\n .then((call) => {\n if (cancelled) return\n if (!call.ok || !isDealsSummaryResponse(call.result)) {\n setError(t('customers.deals.list.kpi.error'))\n return\n }\n setData(call.result)\n })\n .catch(() => {\n if (cancelled) return\n setError(t('customers.deals.list.kpi.error'))\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [t, scopeVersion, reloadToken, retryToken])\n\n const wrapperClassName = cn('space-y-2', className)\n const gridClassName = 'grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4'\n\n if (loading && !data) {\n return (\n <div className={wrapperClassName}>\n <div className={gridClassName}>\n <DealKpiCard loading title={t('customers.deals.list.kpi.pipelineValue')} value={null} />\n <DealKpiCard loading title={t('customers.deals.list.kpi.activeDeals')} value={null} />\n <DealKpiCard loading title={t('customers.deals.list.kpi.wonThisQuarter')} value={null} />\n <DealKpiCard loading title={t('customers.deals.list.kpi.winRate')} value={null} />\n </div>\n </div>\n )\n }\n\n if (!data) {\n const errorMessage = error ?? t('customers.deals.list.kpi.error')\n return (\n <div className={wrapperClassName}>\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4\">\n <p className=\"text-sm text-destructive\">{errorMessage}</p>\n <Button type=\"button\" variant=\"destructive-outline\" size=\"sm\" onClick={retry}>\n {t('customers.deals.list.kpi.retry')}\n </Button>\n </div>\n </div>\n )\n }\n\n const currencySuffix = buildCurrencySuffix(data.baseCurrencyCode, data.convertedAll)\n const unassignedLabel = t('customers.deals.list.kpi.unassignedStage')\n const deltaTooltip = t('customers.deals.list.kpi.deltaTooltip')\n const deltaUnavailableTooltip = t('customers.deals.list.kpi.deltaUnavailable')\n const scopeLabel = t('customers.deals.list.kpi.scopeAllPipelinesThisQuarter')\n const unknownOwner = t('customers.deals.list.unknownOwner')\n const currencyHint = !data.convertedAll\n ? data.baseCurrencyCode\n ? t('customers.deals.list.kpi.currencyApproxMissing', {\n currencies: data.missingRateCurrencies.length ? data.missingRateCurrencies.join(', ') : currencySuffix,\n })\n : t('customers.deals.list.kpi.currencyApproxNoBase')\n : null\n const attentionLabel = pf('customers.deals.list.kpi.frag.needAttention', data.activeDeals.needAttention)\n\n return (\n <div className={wrapperClassName}>\n {error ? (\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2\">\n <p className=\"text-xs text-destructive\">{error}</p>\n <Button type=\"button\" variant=\"destructive-outline\" size=\"2xs\" onClick={retry}>\n {t('customers.deals.list.kpi.retry')}\n </Button>\n </div>\n ) : null}\n {loading ? (\n <div className=\"flex items-center justify-end gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n <span>{t('customers.deals.list.kpi.updating')}</span>\n </div>\n ) : null}\n <div className={gridClassName}>\n <DealKpiCard\n title={t('customers.deals.list.kpi.pipelineValue')}\n value={data.pipelineValue.value}\n formatValue={formatCompact}\n suffix={currencySuffix}\n headerAction={\n <KpiDeltaBadge\n direction={data.pipelineValue.delta.direction}\n value={data.pipelineValue.delta.value}\n title={data.pipelineValue.delta.direction === 'unchanged' && data.pipelineValue.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip}\n />\n }\n footer={\n <div className=\"space-y-2\">\n <p className=\"text-xs text-muted-foreground\">{scopeLabel}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.deals.list.kpi.activeAcrossPipelines', {\n deals: pf('customers.deals.list.kpi.frag.activeDeals', data.activeDeals.value),\n pipelines: pf('customers.deals.list.kpi.frag.pipelines', pipelineCount),\n })}\n </p>\n {currencyHint ? <p className=\"text-xs text-muted-foreground\">{currencyHint}</p> : null}\n <PipelineStageBar\n stages={data.pipelineValue.stages}\n stageDictionary={stageDictionary}\n unassignedLabel={unassignedLabel}\n />\n </div>\n }\n />\n\n <DealKpiCard\n title={t('customers.deals.list.kpi.activeDeals')}\n value={data.activeDeals.value}\n formatValue={formatCompact}\n headerAction={\n <KpiDeltaBadge\n direction={data.activeDeals.delta.direction}\n value={data.activeDeals.delta.value}\n title={data.activeDeals.delta.direction === 'unchanged' && data.activeDeals.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip}\n />\n }\n footer={\n <div className=\"space-y-2\">\n <p className=\"text-xs text-muted-foreground\">{scopeLabel}</p>\n <div className=\"flex flex-wrap items-center gap-x-1.5 gap-y-1 text-xs text-muted-foreground\">\n <span>{pf('customers.deals.list.kpi.frag.owners', data.activeDeals.ownersCount)}</span>\n <span aria-hidden=\"true\">\u00B7</span>\n {onNeedsAttentionClick && data.activeDeals.needAttention > 0 ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"2xs\"\n className=\"h-auto p-0 text-xs\"\n onClick={onNeedsAttentionClick}\n >\n {attentionLabel}\n </Button>\n ) : (\n <span>{attentionLabel}</span>\n )}\n </div>\n {data.activeDeals.owners.length > 0 ? (\n <AvatarStack max={4} size=\"sm\" overflowCount={data.activeDeals.ownersOverflow}>\n {data.activeDeals.owners.map((owner) => {\n const ownerLabel = ownerNames[owner.id]?.trim() || unknownOwner\n return <Avatar key={owner.id} label={ownerLabel} size=\"sm\" />\n })}\n </AvatarStack>\n ) : null}\n </div>\n }\n />\n\n <DealKpiCard\n title={t('customers.deals.list.kpi.wonThisQuarter')}\n value={data.wonThisQuarter.value}\n formatValue={formatCompact}\n suffix={currencySuffix}\n headerAction={\n <KpiDeltaBadge\n direction={data.wonThisQuarter.delta.direction}\n value={data.wonThisQuarter.delta.value}\n title={data.wonThisQuarter.delta.direction === 'unchanged' && data.wonThisQuarter.delta.value === 0 ? deltaUnavailableTooltip : deltaTooltip}\n />\n }\n footer={\n <div className=\"space-y-1\">\n <p className=\"text-xs text-muted-foreground\">{scopeLabel}</p>\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <CheckCircle className=\"h-4 w-4 text-status-success-text\" aria-hidden />\n <span>\n {pf('customers.deals.list.kpi.frag.dealsClosed', data.wonThisQuarter.dealsClosed)}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.deals.list.kpi.avgDeal', {\n value: `${formatCompact(data.wonThisQuarter.avgDeal)}${currencySuffix ? ` ${currencySuffix}` : ''}`,\n })}\n </p>\n {currencyHint ? <p className=\"text-xs text-muted-foreground\">{currencyHint}</p> : null}\n </div>\n }\n />\n\n <DealKpiCard\n title={t('customers.deals.list.kpi.winRate')}\n value={data.winRate.value}\n suffix=\"%\"\n headerAction={\n <KpiDeltaBadge\n direction={data.winRate.direction}\n value={Math.abs(data.winRate.deltaPp)}\n unit=\"pp\"\n title={data.winRate.previousValue === 0 ? deltaUnavailableTooltip : deltaTooltip}\n />\n }\n footer={\n <div className=\"space-y-2\">\n <p className=\"text-xs text-muted-foreground\">{scopeLabel}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.deals.list.kpi.fromLastQuarter', { value: data.winRate.previousValue })}\n </p>\n <div className=\"text-primary\">\n <Sparkline\n values={data.winRate.series.map((point) => point.rate)}\n ariaLabel={t('customers.deals.list.kpi.winRate')}\n />\n </div>\n </div>\n }\n />\n </div>\n </div>\n )\n}\n\nexport default DealsKpiStrip\n"],
|
|
5
|
+
"mappings": ";AAkFS,cAiHD,YAjHC;AAhFT,YAAY,WAAW;AACvB,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AACnB,SAAS,MAAM,iBAAiB;AAChC,SAAS,eAAe;AACxB,SAAS,SAAS,YAAY,iBAAiB;AAC/C,SAAS,QAAQ,mBAAmB;AACpC,SAAS,cAAc;AACvB,SAAS,eAAe;AAExB,SAAS,wBAAwB;AAqDjC,MAAM,yBAAyB,IAAI,KAAK,aAAa,QAAW;AAAA,EAC9D,UAAU;AAAA,EACV,uBAAuB;AACzB,CAAC;AAED,SAAS,cAAc,OAAuB;AAC5C,SAAO,uBAAuB,OAAO,KAAK;AAC5C;AAEA,SAAS,oBAAoB,MAAqB,cAA+B;AAC/E,MAAI,CAAC,KAAM,QAAO,eAAe,KAAK;AACtC,SAAO,eAAe,OAAO,UAAK,IAAI;AACxC;AAEA,MAAM,kBAAkB;AAExB,SAAS,YAAY,OAA6C;AAChE,SAAO,oBAAC,WAAQ,gBAAgB,iBAAkB,GAAG,OAAO;AAC9D;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,cAAc,eAAe,UAAU,GAAG;AAC5C,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV;AAAA,QACD;AAAA;AAAA,IAED;AAAA,EAEJ;AACA,SAAO,oBAAC,cAAW,WAAsB,OAAc,MAAY,OAAc;AACnF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAKA,SAAS,uBAAuB,OAA+C;AAC7E,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,EAAE,eAAe,aAAa,gBAAgB,QAAQ,IAAI;AAChE,SACE,SAAS,aAAa,KAAK,MAAM,QAAQ,cAAc,MAAM,KAC7D,SAAS,WAAW,KAAK,MAAM,QAAQ,YAAY,MAAM,KACzD,SAAS,cAAc,KACvB,SAAS,OAAO,KAAK,MAAM,QAAQ,QAAQ,MAAM;AAErD;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,YAAY,MAAM,YAAY,CAAC,UAA0B;AAC7D,QAAI;AACF,aAAO,IAAI,KAAK,YAAY,MAAM,EAAE,OAAO,KAAK;AAAA,IAClD,QAAQ;AACN,aAAO,UAAU,IAAI,QAAQ;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AACX,QAAM,KAAK,MAAM,YAAY,CAAC,MAAc,UAA0B;AACpE,UAAM,MAAM,UAAU,KAAK;AAC3B,UAAM,MAAM,GAAG,IAAI,IAAI,GAAG;AAC1B,UAAM,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC;AAC5B,WAAO,QAAQ,MAAM,EAAE,GAAG,IAAI,UAAU,EAAE,MAAM,CAAC,IAAI;AAAA,EACvD,GAAG,CAAC,GAAG,SAAS,CAAC;AACjB,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAsC,IAAI;AACxE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,CAAC;AACpD,QAAM,0BAA0B,MAAM,OAAO,YAAY;AAEzD,QAAM,QAAQ,MAAM,YAAY,MAAM;AACpC,kBAAc,CAAC,UAAU,QAAQ,CAAC;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,UAAM,eAAe,wBAAwB,YAAY;AACzD,4BAAwB,UAAU;AAClC,QAAI,aAAc,SAAQ,IAAI;AAC9B,eAAW,IAAI;AACf,aAAS,IAAI;AACb,YAA8B,8BAA8B,EACzD,KAAK,CAAC,SAAS;AACd,UAAI,UAAW;AACf,UAAI,CAAC,KAAK,MAAM,CAAC,uBAAuB,KAAK,MAAM,GAAG;AACpD,iBAAS,EAAE,gCAAgC,CAAC;AAC5C;AAAA,MACF;AACA,cAAQ,KAAK,MAAM;AAAA,IACrB,CAAC,EACA,MAAM,MAAM;AACX,UAAI,UAAW;AACf,eAAS,EAAE,gCAAgC,CAAC;AAAA,IAC9C,CAAC,EACA,QAAQ,MAAM;AACb,UAAI,CAAC,UAAW,YAAW,KAAK;AAAA,IAClC,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,GAAG,cAAc,aAAa,UAAU,CAAC;AAE7C,QAAM,mBAAmB,GAAG,aAAa,SAAS;AAClD,QAAM,gBAAgB;AAEtB,MAAI,WAAW,CAAC,MAAM;AACpB,WACE,oBAAC,SAAI,WAAW,kBACd,+BAAC,SAAI,WAAW,eACd;AAAA,0BAAC,eAAY,SAAO,MAAC,OAAO,EAAE,wCAAwC,GAAG,OAAO,MAAM;AAAA,MACtF,oBAAC,eAAY,SAAO,MAAC,OAAO,EAAE,sCAAsC,GAAG,OAAO,MAAM;AAAA,MACpF,oBAAC,eAAY,SAAO,MAAC,OAAO,EAAE,yCAAyC,GAAG,OAAO,MAAM;AAAA,MACvF,oBAAC,eAAY,SAAO,MAAC,OAAO,EAAE,kCAAkC,GAAG,OAAO,MAAM;AAAA,OAClF,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,MAAM;AACT,UAAM,eAAe,SAAS,EAAE,gCAAgC;AAChE,WACE,oBAAC,SAAI,WAAW,kBACd,+BAAC,SAAI,WAAU,wGACb;AAAA,0BAAC,OAAE,WAAU,4BAA4B,wBAAa;AAAA,MACtD,oBAAC,UAAO,MAAK,UAAS,SAAQ,uBAAsB,MAAK,MAAK,SAAS,OACpE,YAAE,gCAAgC,GACrC;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,QAAM,iBAAiB,oBAAoB,KAAK,kBAAkB,KAAK,YAAY;AACnF,QAAM,kBAAkB,EAAE,0CAA0C;AACpE,QAAM,eAAe,EAAE,uCAAuC;AAC9D,QAAM,0BAA0B,EAAE,2CAA2C;AAC7E,QAAM,aAAa,EAAE,uDAAuD;AAC5E,QAAM,eAAe,EAAE,mCAAmC;AAC1D,QAAM,eAAe,CAAC,KAAK,eACvB,KAAK,mBACH,EAAE,kDAAkD;AAAA,IAClD,YAAY,KAAK,sBAAsB,SAAS,KAAK,sBAAsB,KAAK,IAAI,IAAI;AAAA,EAC1F,CAAC,IACD,EAAE,+CAA+C,IACnD;AACJ,QAAM,iBAAiB,GAAG,+CAA+C,KAAK,YAAY,aAAa;AAEvG,SACE,qBAAC,SAAI,WAAW,kBACb;AAAA,YACC,qBAAC,SAAI,WAAU,8GACb;AAAA,0BAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MAC/C,oBAAC,UAAO,MAAK,UAAS,SAAQ,uBAAsB,MAAK,OAAM,SAAS,OACrE,YAAE,gCAAgC,GACrC;AAAA,OACF,IACE;AAAA,IACH,UACC,qBAAC,SAAI,WAAU,qEACb;AAAA,0BAAC,WAAQ,WAAU,WAAU;AAAA,MAC7B,oBAAC,UAAM,YAAE,mCAAmC,GAAE;AAAA,OAChD,IACE;AAAA,IACJ,qBAAC,SAAI,WAAW,eACd;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,wCAAwC;AAAA,UACjD,OAAO,KAAK,cAAc;AAAA,UAC1B,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,cACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,KAAK,cAAc,MAAM;AAAA,cACpC,OAAO,KAAK,cAAc,MAAM;AAAA,cAChC,OAAO,KAAK,cAAc,MAAM,cAAc,eAAe,KAAK,cAAc,MAAM,UAAU,IAAI,0BAA0B;AAAA;AAAA,UAChI;AAAA,UAEF,QACE,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,OAAE,WAAU,iCAAiC,sBAAW;AAAA,YACzD,oBAAC,OAAE,WAAU,iCACV,YAAE,kDAAkD;AAAA,cACnD,OAAO,GAAG,6CAA6C,KAAK,YAAY,KAAK;AAAA,cAC7E,WAAW,GAAG,2CAA2C,aAAa;AAAA,YACxE,CAAC,GACH;AAAA,YACC,eAAe,oBAAC,OAAE,WAAU,iCAAiC,wBAAa,IAAO;AAAA,YAClF;AAAA,cAAC;AAAA;AAAA,gBACC,QAAQ,KAAK,cAAc;AAAA,gBAC3B;AAAA,gBACA;AAAA;AAAA,YACF;AAAA,aACF;AAAA;AAAA,MAEJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,sCAAsC;AAAA,UAC/C,OAAO,KAAK,YAAY;AAAA,UACxB,aAAa;AAAA,UACb,cACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,KAAK,YAAY,MAAM;AAAA,cAClC,OAAO,KAAK,YAAY,MAAM;AAAA,cAC9B,OAAO,KAAK,YAAY,MAAM,cAAc,eAAe,KAAK,YAAY,MAAM,UAAU,IAAI,0BAA0B;AAAA;AAAA,UAC5H;AAAA,UAEF,QACE,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,OAAE,WAAU,iCAAiC,sBAAW;AAAA,YACzD,qBAAC,SAAI,WAAU,+EACb;AAAA,kCAAC,UAAM,aAAG,wCAAwC,KAAK,YAAY,WAAW,GAAE;AAAA,cAChF,oBAAC,UAAK,eAAY,QAAO,kBAAC;AAAA,cACzB,yBAAyB,KAAK,YAAY,gBAAgB,IACzD;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAAS;AAAA,kBAER;AAAA;AAAA,cACH,IAEA,oBAAC,UAAM,0BAAe;AAAA,eAE1B;AAAA,YACC,KAAK,YAAY,OAAO,SAAS,IAChC,oBAAC,eAAY,KAAK,GAAG,MAAK,MAAK,eAAe,KAAK,YAAY,gBAC5D,eAAK,YAAY,OAAO,IAAI,CAAC,UAAU;AACtC,oBAAM,aAAa,WAAW,MAAM,EAAE,GAAG,KAAK,KAAK;AACnD,qBAAO,oBAAC,UAAsB,OAAO,YAAY,MAAK,QAAlC,MAAM,EAAiC;AAAA,YAC7D,CAAC,GACH,IACE;AAAA,aACN;AAAA;AAAA,MAEJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,yCAAyC;AAAA,UAClD,OAAO,KAAK,eAAe;AAAA,UAC3B,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,cACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,KAAK,eAAe,MAAM;AAAA,cACrC,OAAO,KAAK,eAAe,MAAM;AAAA,cACjC,OAAO,KAAK,eAAe,MAAM,cAAc,eAAe,KAAK,eAAe,MAAM,UAAU,IAAI,0BAA0B;AAAA;AAAA,UAClI;AAAA,UAEF,QACE,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,OAAE,WAAU,iCAAiC,sBAAW;AAAA,YACzD,qBAAC,SAAI,WAAU,2DACb;AAAA,kCAAC,eAAY,WAAU,oCAAmC,eAAW,MAAC;AAAA,cACtE,oBAAC,UACE,aAAG,6CAA6C,KAAK,eAAe,WAAW,GAClF;AAAA,eACF;AAAA,YACA,oBAAC,OAAE,WAAU,iCACV,YAAE,oCAAoC;AAAA,cACrC,OAAO,GAAG,cAAc,KAAK,eAAe,OAAO,CAAC,GAAG,iBAAiB,IAAI,cAAc,KAAK,EAAE;AAAA,YACnG,CAAC,GACH;AAAA,YACC,eAAe,oBAAC,OAAE,WAAU,iCAAiC,wBAAa,IAAO;AAAA,aACpF;AAAA;AAAA,MAEJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,kCAAkC;AAAA,UAC3C,OAAO,KAAK,QAAQ;AAAA,UACpB,QAAO;AAAA,UACP,cACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,KAAK,QAAQ;AAAA,cACxB,OAAO,KAAK,IAAI,KAAK,QAAQ,OAAO;AAAA,cACpC,MAAK;AAAA,cACL,OAAO,KAAK,QAAQ,kBAAkB,IAAI,0BAA0B;AAAA;AAAA,UACtE;AAAA,UAEF,QACE,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,OAAE,WAAU,iCAAiC,sBAAW;AAAA,YACzD,oBAAC,OAAE,WAAU,iCACV,YAAE,4CAA4C,EAAE,OAAO,KAAK,QAAQ,cAAc,CAAC,GACtF;AAAA,YACA,oBAAC,SAAI,WAAU,gBACb;AAAA,cAAC;AAAA;AAAA,gBACC,QAAQ,KAAK,QAAQ,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,gBACrD,WAAW,EAAE,kCAAkC;AAAA;AAAA,YACjD,GACF;AAAA,aACF;AAAA;AAAA,MAEJ;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,IAAO,wBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -83,7 +83,6 @@ function ConfirmDealLostDialog({
|
|
|
83
83
|
] }) }),
|
|
84
84
|
/* @__PURE__ */ jsxs("div", { className: "space-y-6 px-7 py-6", children: [
|
|
85
85
|
/* @__PURE__ */ jsxs(Alert, { variant: "warning", className: "rounded-md", children: [
|
|
86
|
-
/* @__PURE__ */ jsx(AlertTriangle, { className: "size-4" }),
|
|
87
86
|
/* @__PURE__ */ jsx(AlertTitle, { children: t("customers.deals.detail.lost.warningTitle", "This action closes the deal") }),
|
|
88
87
|
/* @__PURE__ */ jsx(AlertDescription, { children: t("customers.deals.detail.lost.warning", "This action sets the stage to 'Lost' and cannot be undone without 'sales.reopen' permission") })
|
|
89
88
|
] }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ConfirmDealLostDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertTriangle, Check, ChevronDown } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { loadDictionaryEntriesByKey } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\n\ntype LossReasonOption = {\n id: string\n value: string\n label: string\n description?: string | null\n}\n\ntype ConfirmDealLostDialogProps = {\n open: boolean\n dealTitle: string\n dealValue?: string | null\n companyName?: string | null\n onClose: () => void\n onConfirm: (input: { lossReasonId: string; lossNotes?: string }) => void | Promise<void>\n}\n\nexport function ConfirmDealLostDialog({\n open,\n dealTitle,\n dealValue,\n companyName,\n onClose,\n onConfirm,\n}: ConfirmDealLostDialogProps) {\n const t = useT()\n const [lossReasonId, setLossReasonId] = React.useState('')\n const [lossNotes, setLossNotes] = React.useState('')\n const [lossReasons, setLossReasons] = React.useState<LossReasonOption[]>([])\n const [reasonListOpen, setReasonListOpen] = React.useState(false)\n const [error, setError] = React.useState('')\n const [isConfirming, setIsConfirming] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n loadDictionaryEntriesByKey('sales.deal_loss_reason')\n .then((items) => {\n if (!cancelled) setLossReasons(items)\n })\n .catch((loadError) => {\n console.error('customers.deals.detail.lossReasons failed', loadError)\n if (!cancelled) setLossReasons([])\n })\n return () => {\n cancelled = true\n }\n }, [open])\n\n React.useEffect(() => {\n if (!open) return\n setLossReasonId('')\n setLossNotes('')\n setReasonListOpen(false)\n setError('')\n }, [open])\n\n const selectedLossReason = React.useMemo(\n () => lossReasons.find((reason) => reason.id === lossReasonId) ?? null,\n [lossReasonId, lossReasons],\n )\n\n const handleConfirm = React.useCallback(async () => {\n if (!lossReasonId) {\n setError(t('customers.deals.detail.lost.reasonRequired', 'Please select a loss reason'))\n return\n }\n setIsConfirming(true)\n try {\n await onConfirm({\n lossReasonId,\n lossNotes: lossNotes.trim() || undefined,\n })\n } finally {\n setIsConfirming(false)\n }\n }, [lossNotes, lossReasonId, onConfirm, t])\n\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: () => void handleConfirm(),\n disabled: isConfirming,\n })\n\n return (\n <Dialog open={open} onOpenChange={(nextOpen) => { if (!nextOpen) onClose() }}>\n <DialogContent className=\"overflow-hidden p-0 sm:max-w-[560px]\" onKeyDown={handleKeyDown}>\n <div className=\"overflow-hidden rounded-lg bg-card\">\n <DialogHeader className=\"border-b border-border/70 px-7 py-5\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-md bg-destructive/10 text-destructive\">\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"min-w-0\">\n <DialogTitle className=\"text-lg font-bold leading-none tracking-tight text-foreground\">\n {t('customers.deals.detail.lost.title', 'Mark deal as Lost?')}\n </DialogTitle>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {dealTitle}\n {dealValue ? ` \u00B7 ${dealValue}` : ''}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n </div>\n </div>\n </DialogHeader>\n\n <div className=\"space-y-6 px-7 py-6\">\n <Alert variant=\"warning\" className=\"rounded-md\">\n <
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertTriangle, Check, ChevronDown } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { loadDictionaryEntriesByKey } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\n\ntype LossReasonOption = {\n id: string\n value: string\n label: string\n description?: string | null\n}\n\ntype ConfirmDealLostDialogProps = {\n open: boolean\n dealTitle: string\n dealValue?: string | null\n companyName?: string | null\n onClose: () => void\n onConfirm: (input: { lossReasonId: string; lossNotes?: string }) => void | Promise<void>\n}\n\nexport function ConfirmDealLostDialog({\n open,\n dealTitle,\n dealValue,\n companyName,\n onClose,\n onConfirm,\n}: ConfirmDealLostDialogProps) {\n const t = useT()\n const [lossReasonId, setLossReasonId] = React.useState('')\n const [lossNotes, setLossNotes] = React.useState('')\n const [lossReasons, setLossReasons] = React.useState<LossReasonOption[]>([])\n const [reasonListOpen, setReasonListOpen] = React.useState(false)\n const [error, setError] = React.useState('')\n const [isConfirming, setIsConfirming] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n loadDictionaryEntriesByKey('sales.deal_loss_reason')\n .then((items) => {\n if (!cancelled) setLossReasons(items)\n })\n .catch((loadError) => {\n console.error('customers.deals.detail.lossReasons failed', loadError)\n if (!cancelled) setLossReasons([])\n })\n return () => {\n cancelled = true\n }\n }, [open])\n\n React.useEffect(() => {\n if (!open) return\n setLossReasonId('')\n setLossNotes('')\n setReasonListOpen(false)\n setError('')\n }, [open])\n\n const selectedLossReason = React.useMemo(\n () => lossReasons.find((reason) => reason.id === lossReasonId) ?? null,\n [lossReasonId, lossReasons],\n )\n\n const handleConfirm = React.useCallback(async () => {\n if (!lossReasonId) {\n setError(t('customers.deals.detail.lost.reasonRequired', 'Please select a loss reason'))\n return\n }\n setIsConfirming(true)\n try {\n await onConfirm({\n lossReasonId,\n lossNotes: lossNotes.trim() || undefined,\n })\n } finally {\n setIsConfirming(false)\n }\n }, [lossNotes, lossReasonId, onConfirm, t])\n\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: () => void handleConfirm(),\n disabled: isConfirming,\n })\n\n return (\n <Dialog open={open} onOpenChange={(nextOpen) => { if (!nextOpen) onClose() }}>\n <DialogContent className=\"overflow-hidden p-0 sm:max-w-[560px]\" onKeyDown={handleKeyDown}>\n <div className=\"overflow-hidden rounded-lg bg-card\">\n <DialogHeader className=\"border-b border-border/70 px-7 py-5\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-md bg-destructive/10 text-destructive\">\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"min-w-0\">\n <DialogTitle className=\"text-lg font-bold leading-none tracking-tight text-foreground\">\n {t('customers.deals.detail.lost.title', 'Mark deal as Lost?')}\n </DialogTitle>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {dealTitle}\n {dealValue ? ` \u00B7 ${dealValue}` : ''}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n </div>\n </div>\n </DialogHeader>\n\n <div className=\"space-y-6 px-7 py-6\">\n <Alert variant=\"warning\" className=\"rounded-md\">\n <AlertTitle>\n {t('customers.deals.detail.lost.warningTitle', 'This action closes the deal')}\n </AlertTitle>\n <AlertDescription>\n {t('customers.deals.detail.lost.warning', \"This action sets the stage to 'Lost' and cannot be undone without 'sales.reopen' permission\")}\n </AlertDescription>\n </Alert>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.lost.reasonLabel', 'Loss reason')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <div className=\"space-y-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setReasonListOpen((current) => !current)}\n className=\"h-auto flex w-full items-center justify-between rounded-md border-2 border-foreground bg-background px-4 py-3 text-left\"\n >\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-semibold text-foreground\">\n {selectedLossReason?.label ?? t('customers.deals.detail.lost.reasonPlaceholder', 'Select loss reason')}\n </div>\n <div className=\"truncate text-sm text-muted-foreground\">\n {selectedLossReason?.description ?? t('customers.deals.detail.lost.reasonHelp', 'Choose the closest reason from the dictionary.')}\n </div>\n </div>\n <ChevronDown className=\"ml-3 size-4 shrink-0 text-muted-foreground\" />\n </Button>\n\n {reasonListOpen ? (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-background\">\n {lossReasons.map((reason, index) => {\n const isSelected = reason.id === lossReasonId\n return (\n <Button\n key={reason.id}\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n setLossReasonId(reason.id)\n setReasonListOpen(false)\n setError('')\n }}\n className={`h-auto flex w-full items-center justify-between rounded-none px-4 py-3 text-left ${\n index < lossReasons.length - 1 ? 'border-b border-border/60' : ''\n } ${isSelected ? 'bg-muted/60' : 'hover:bg-accent/50'}`}\n >\n <div className=\"min-w-0\">\n <div className=\"text-base font-semibold text-foreground\">{reason.label}</div>\n <div className=\"text-sm text-muted-foreground\">\n {reason.description ?? t('customers.deals.detail.lost.reasonFallbackDescription', 'No description available.')}\n </div>\n </div>\n {isSelected ? (\n <span className=\"ml-3 flex size-6 shrink-0 items-center justify-center rounded-full bg-foreground text-background\">\n <Check className=\"size-3.5\" />\n </span>\n ) : null}\n </Button>\n )\n })}\n </div>\n ) : null}\n </div>\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.lost.notesLabel', 'Loss notes (optional)')}\n </label>\n <Textarea\n value={lossNotes}\n onChange={(event) => setLossNotes(event.target.value)}\n placeholder={t('customers.deals.detail.lost.notesPlaceholder', 'Additional context about the loss...')}\n rows={4}\n className=\"min-h-[88px] rounded-md border-border/80 px-4 py-3 shadow-none\"\n />\n </div>\n </div>\n\n <DialogFooter className=\"border-t border-border/70 px-7 py-4 sm:justify-end\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose}>\n {t('customers.deals.detail.lost.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={() => { void handleConfirm() }}>\n {t('customers.deals.detail.lost.confirm', 'Mark as Lost')}\n </Button>\n </DialogFooter>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|