@open-mercato/core 0.6.5-develop.4534.1.b459babe6d → 0.6.5-develop.4544.1.71c003c861
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 +5 -0
- package/dist/generated/entities/role/index.js +3 -1
- package/dist/generated/entities/role/index.js.map +2 -2
- package/dist/generated/entities/user/index.js +3 -1
- package/dist/generated/entities/user/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/optimisticLockUi.js +104 -0
- package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
- package/dist/helpers/integration/salesFixtures.js +17 -0
- package/dist/helpers/integration/salesFixtures.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +32 -13
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +3 -1
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +42 -19
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +3 -1
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +8 -4
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +6 -2
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +3 -1
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js +6 -0
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
- package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +28 -0
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +28 -0
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
- package/dist/modules/business_rules/backend/rules/page.js +20 -11
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +20 -11
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/catalog/api/categories/route.js +2 -0
- package/dist/modules/catalog/api/categories/route.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +2 -1
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +32 -31
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/variantForm.js +2 -1
- package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +18 -11
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +7 -5
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
- package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users.js +2 -0
- package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +13 -2
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +2 -0
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +11 -2
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +1 -0
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +16 -6
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +16 -14
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +1 -1
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +41 -4
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/people.js +1 -1
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +13 -11
- package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
- package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +20 -13
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +38 -23
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
- package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +36 -24
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
- package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
- package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/data/guards.js +66 -0
- package/dist/modules/customers/data/guards.js.map +7 -0
- package/dist/modules/customers/di.js +37 -0
- package/dist/modules/customers/di.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +11 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +4 -4
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +9 -1
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
- package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/directory/api/organizations/route.js +3 -0
- package/dist/modules/directory/api/organizations/route.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +7 -2
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/entities/api/records.js +66 -0
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -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/page.js +8 -4
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/lib/helpers.js +17 -0
- package/dist/modules/entities/lib/helpers.js.map +2 -2
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/formConfig.js +2 -1
- package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
- package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
- package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
- package/dist/modules/feature_toggles/data/validators.js +7 -4
- package/dist/modules/feature_toggles/data/validators.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +17 -2
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.js +12 -8
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +13 -10
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
- package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +7 -0
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
- package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +19 -0
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +8 -4
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
- package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +7 -2
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +16 -4
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +181 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +29 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +12 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +15 -0
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +4 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/StatusSettings.js +18 -11
- package/dist/modules/sales/components/StatusSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
- package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
- package/dist/modules/sales/di.js +18 -0
- package/dist/modules/sales/di.js.map +2 -2
- package/dist/modules/staff/api/job-histories.js +11 -2
- package/dist/modules/staff/api/job-histories.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +5 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +12 -3
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/commands/job-histories.js +40 -3
- package/dist/modules/staff/commands/job-histories.js.map +2 -2
- package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
- package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -0
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -0
- package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +1 -0
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
- package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
- package/dist/modules/staff/data/validators.js +7 -1
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
- package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +12 -8
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +19 -8
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/components/formConfig.js +4 -1
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/di.js +12 -0
- package/dist/modules/workflows/di.js.map +2 -2
- package/generated/entities/role/index.ts +1 -0
- package/generated/entities/user/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/jest.setup.ts +17 -0
- package/package.json +8 -7
- package/src/helpers/integration/optimisticLockUi.ts +172 -0
- package/src/helpers/integration/salesFixtures.ts +29 -0
- package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
- package/src/modules/auth/api/roles/acl/route.ts +37 -11
- package/src/modules/auth/api/roles/route.ts +2 -0
- package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
- package/src/modules/auth/api/users/acl/route.ts +46 -18
- package/src/modules/auth/api/users/route.ts +2 -0
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
- package/src/modules/auth/backend/roles/page.tsx +9 -4
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
- package/src/modules/auth/backend/users/page.tsx +7 -2
- package/src/modules/auth/components/AclEditor.tsx +10 -1
- package/src/modules/auth/data/entities.ts +7 -1
- package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
- package/src/modules/business_rules/api/rules/route.ts +30 -0
- package/src/modules/business_rules/api/sets/route.ts +30 -0
- package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/rules/page.tsx +20 -11
- package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/sets/page.tsx +20 -11
- package/src/modules/catalog/api/categories/route.ts +3 -0
- package/src/modules/catalog/api/products/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
- package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
- package/src/modules/catalog/commands/variants.ts +32 -32
- package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
- package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
- package/src/modules/catalog/components/products/productForm.ts +3 -0
- package/src/modules/catalog/components/products/variantForm.ts +9 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
- package/src/modules/currencies/backend/currencies/page.tsx +18 -11
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
- package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
- package/src/modules/currencies/commands/currencies.ts +10 -5
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
- package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
- package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
- package/src/modules/customer_accounts/api/admin/users.ts +2 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
- package/src/modules/customers/AGENTS.md +2 -2
- package/src/modules/customers/api/companies/route.ts +14 -1
- package/src/modules/customers/api/deals/route.ts +3 -0
- package/src/modules/customers/api/people/route.ts +12 -1
- package/src/modules/customers/api/todos/route.ts +1 -0
- package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
- package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
- package/src/modules/customers/backend/customers/people/page.tsx +2 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
- package/src/modules/customers/commands/addresses.ts +16 -14
- package/src/modules/customers/commands/companies.ts +3 -1
- package/src/modules/customers/commands/interactions.ts +50 -4
- package/src/modules/customers/commands/people.ts +2 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
- package/src/modules/customers/commands/pipeline-stages.ts +16 -16
- package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
- package/src/modules/customers/components/DictionarySettings.tsx +18 -13
- package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
- package/src/modules/customers/components/PipelineSettings.tsx +42 -21
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
- package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
- package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
- package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
- package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
- package/src/modules/customers/components/detail/types.ts +1 -0
- package/src/modules/customers/components/formConfig.tsx +2 -0
- package/src/modules/customers/data/guards.ts +67 -0
- package/src/modules/customers/di.ts +66 -0
- package/src/modules/customers/i18n/de.json +2 -0
- package/src/modules/customers/i18n/en.json +2 -0
- package/src/modules/customers/i18n/es.json +2 -0
- package/src/modules/customers/i18n/pl.json +2 -0
- package/src/modules/customers/lib/todoCompatibility.ts +14 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
- package/src/modules/data_sync/api/options.ts +7 -4
- package/src/modules/data_sync/api/schedules/route.ts +9 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
- package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
- package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
- package/src/modules/dictionaries/i18n/de.json +1 -0
- package/src/modules/dictionaries/i18n/en.json +1 -0
- package/src/modules/dictionaries/i18n/es.json +1 -0
- package/src/modules/dictionaries/i18n/pl.json +1 -0
- package/src/modules/directory/api/organizations/route.ts +3 -0
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
- package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
- package/src/modules/directory/commands/organizations.ts +7 -4
- package/src/modules/entities/api/records.ts +99 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
- package/src/modules/entities/lib/helpers.ts +17 -0
- package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
- package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
- package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
- package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
- package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
- package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
- package/src/modules/feature_toggles/data/validators.ts +11 -3
- package/src/modules/inbox_ops/api/settings/route.ts +18 -0
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
- package/src/modules/integrations/backend/integrations/page.tsx +13 -8
- package/src/modules/messages/commands/messages.ts +27 -15
- package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
- package/src/modules/perspectives/services/perspectiveService.ts +13 -1
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
- package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
- package/src/modules/query_index/lib/engine.ts +34 -0
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
- package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
- package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
- package/src/modules/sales/api/documents/factory.ts +13 -1
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
- package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
- package/src/modules/sales/commands/documentAddresses.ts +226 -4
- package/src/modules/sales/commands/documents.ts +28 -0
- package/src/modules/sales/commands/returns.ts +12 -3
- package/src/modules/sales/commands/shared.ts +36 -0
- package/src/modules/sales/commands/shipments.ts +17 -1
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
- package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
- package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/StatusSettings.tsx +20 -11
- package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
- package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
- package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
- package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
- package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
- package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
- package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
- package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
- package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
- package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
- package/src/modules/sales/di.ts +35 -0
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/pl.json +3 -0
- package/src/modules/staff/api/job-histories.ts +12 -2
- package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
- package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
- package/src/modules/staff/commands/job-histories.ts +42 -3
- package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
- package/src/modules/staff/components/TeamForm.tsx +2 -0
- package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
- package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
- package/src/modules/staff/data/validators.ts +6 -0
- 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/leaveRequestHelpers.ts +4 -0
- package/src/modules/translations/components/TranslationManager.tsx +13 -8
- package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
- package/src/modules/workflows/backend/definitions/page.tsx +20 -9
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
- package/src/modules/workflows/components/formConfig.tsx +5 -0
- package/src/modules/workflows/di.ts +20 -0
- package/src/modules/workflows/i18n/de.json +1 -0
- package/src/modules/workflows/i18n/en.json +1 -0
- package/src/modules/workflows/i18n/es.json +1 -0
- package/src/modules/workflows/i18n/pl.json +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/components/DictionarySortSettings.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_DICTIONARY_ENTRY_SORT_MODE,\n dictionaryEntrySortModes,\n type DictionaryEntrySortMode,\n} from '@open-mercato/core/modules/dictionaries/lib/entrySort'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\n\nconst SAVE_CONTEXT_ID = 'customers-dictionary-sort-modes'\n\ntype SortModeMap = Partial<Record<CustomerDictionaryKind, DictionaryEntrySortMode>>\n\ntype DictionarySortSection = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\nfunction isDictionaryEntrySortMode(value: string): value is DictionaryEntrySortMode {\n return dictionaryEntrySortModes.includes(value as DictionaryEntrySortMode)\n}\n\nexport function DictionarySortSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [sortModes, setSortModes] = React.useState<SortModeMap>({})\n const [loading, setLoading] = React.useState(true)\n const [savingKind, setSavingKind] = React.useState<CustomerDictionaryKind | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n\n const sections = React.useMemo<DictionarySortSection[]>(() => [\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'pipeline-stages',\n title: t('customers.config.dictionaries.sections.pipelineStages.title', 'Pipeline stages'),\n description: t('customers.config.dictionaries.sections.pipelineStages.description', 'Define the stages used in your deal pipeline.'),\n },\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n const sortOptions = React.useMemo(\n () => dictionaryEntrySortModes.map((mode) => ({\n value: mode,\n label:\n mode === 'label_asc'\n ? t('dictionaries.config.sortModes.labelAsc', 'A to Z')\n : mode === 'label_desc'\n ? t('dictionaries.config.sortModes.labelDesc', 'Z to A')\n : mode === 'value_asc'\n ? t('dictionaries.config.sortModes.valueAsc', 'Value A to Z')\n : mode === 'value_desc'\n ? t('dictionaries.config.sortModes.valueDesc', 'Value Z to A')\n : mode === 'created_at_asc'\n ? t('dictionaries.config.sortModes.createdAtAsc', 'Oldest first')\n : t('dictionaries.config.sortModes.createdAtDesc', 'Newest first'),\n })),\n [t],\n )\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: SAVE_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const data = await readApiResultOrThrow<{ dictionarySortModes?: Record<string, string> }>(\n '/api/customers/settings/dictionary-sort-modes',\n undefined,\n { errorMessage: t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.') },\n )\n const next: SortModeMap = {}\n for (const section of sections) {\n const value = data?.dictionarySortModes?.[section.kind]\n next[section.kind] = value && isDictionaryEntrySortMode(value)\n ? value\n : DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n }\n if (!cancelled) setSortModes(next)\n } catch (err) {\n console.error('customers.dictionarySorting.load failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, sections, t])\n\n const handleChange = React.useCallback(async (kind: CustomerDictionaryKind, mode: DictionaryEntrySortMode) => {\n const previous = sortModes\n const next = { ...sortModes, [kind]: mode }\n setSortModes(next)\n setSavingKind(kind)\n setError(null)\n try {\n await runMutation({\n operation: async () => {\n await apiCallOrThrow(\n '/api/customers/settings/dictionary-sort-modes',\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ dictionarySortModes: next }),\n },\n { errorMessage: t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.') },\n )\n },\n context: {\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'customers.settings',\n retryLastMutation,\n },\n })\n flash(t('customers.config.dictionarySorting.success', 'Dictionary sorting settings saved.'), 'success')\n } catch (err) {\n setSortModes(previous)\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n } finally {\n setSavingKind(null)\n }\n }, [retryLastMutation, runMutation, sortModes, t])\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-background p-4\">\n <header className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold\">\n {t('customers.config.dictionarySorting.title', 'Dictionary sorting')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionarySorting.description', 'Choose how customer dictionary values are ordered in dropdowns and settings.')}\n </p>\n </header>\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.config.dictionarySorting.loading', 'Loading dictionary sorting settings\u2026')}\n </div>\n ) : (\n <div className=\"grid gap-3 lg:grid-cols-2\">\n {sections.map((section) => {\n const value = sortModes[section.kind] ?? DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n const saving = savingKind === section.kind\n return (\n <div key={section.kind} className=\"rounded border p-3\">\n <div className=\"mb-3 space-y-1\">\n <div className=\"text-sm font-medium\">{section.title}</div>\n <div className=\"text-xs text-muted-foreground\">{section.description}</div>\n </div>\n <Select\n value={value}\n onValueChange={(next) => {\n if (!isDictionaryEntrySortMode(next) || next === value) return\n handleChange(section.kind, next).catch(() => {})\n }}\n disabled={savingKind !== null}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {sortOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {saving ? (\n <div className=\"mt-2 inline-flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.config.dictionarySorting.updating', 'Saving\u2026')}\n </div>\n ) : null}\n </div>\n )\n })}\n </div>\n )}\n {error ? <p className=\"text-sm text-status-error-text\">{error}</p> : null}\n </section>\n )\n}\n\nexport default DictionarySortSettings\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_DICTIONARY_ENTRY_SORT_MODE,\n dictionaryEntrySortModes,\n type DictionaryEntrySortMode,\n} from '@open-mercato/core/modules/dictionaries/lib/entrySort'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\n\nconst SAVE_CONTEXT_ID = 'customers-dictionary-sort-modes'\n\ntype SortModeMap = Partial<Record<CustomerDictionaryKind, DictionaryEntrySortMode>>\n\ntype DictionarySortSection = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\nfunction isDictionaryEntrySortMode(value: string): value is DictionaryEntrySortMode {\n return dictionaryEntrySortModes.includes(value as DictionaryEntrySortMode)\n}\n\nexport function DictionarySortSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [sortModes, setSortModes] = React.useState<SortModeMap>({})\n const [loading, setLoading] = React.useState(true)\n const [savingKind, setSavingKind] = React.useState<CustomerDictionaryKind | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n\n const sections = React.useMemo<DictionarySortSection[]>(() => [\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'pipeline-stages',\n title: t('customers.config.dictionaries.sections.pipelineStages.title', 'Pipeline stages'),\n description: t('customers.config.dictionaries.sections.pipelineStages.description', 'Define the stages used in your deal pipeline.'),\n },\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n const sortOptions = React.useMemo(\n () => dictionaryEntrySortModes.map((mode) => ({\n value: mode,\n label:\n mode === 'label_asc'\n ? t('dictionaries.config.sortModes.labelAsc', 'A to Z')\n : mode === 'label_desc'\n ? t('dictionaries.config.sortModes.labelDesc', 'Z to A')\n : mode === 'value_asc'\n ? t('dictionaries.config.sortModes.valueAsc', 'Value A to Z')\n : mode === 'value_desc'\n ? t('dictionaries.config.sortModes.valueDesc', 'Value Z to A')\n : mode === 'created_at_asc'\n ? t('dictionaries.config.sortModes.createdAtAsc', 'Oldest first')\n : t('dictionaries.config.sortModes.createdAtDesc', 'Newest first'),\n })),\n [t],\n )\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: SAVE_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const data = await readApiResultOrThrow<{ dictionarySortModes?: Record<string, string> }>(\n '/api/customers/settings/dictionary-sort-modes',\n undefined,\n { errorMessage: t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.') },\n )\n const next: SortModeMap = {}\n for (const section of sections) {\n const value = data?.dictionarySortModes?.[section.kind]\n next[section.kind] = value && isDictionaryEntrySortMode(value)\n ? value\n : DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n }\n if (!cancelled) setSortModes(next)\n } catch (err) {\n console.error('customers.dictionarySorting.load failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, sections, t])\n\n const handleChange = React.useCallback(async (kind: CustomerDictionaryKind, mode: DictionaryEntrySortMode) => {\n const previous = sortModes\n const next = { ...sortModes, [kind]: mode }\n setSortModes(next)\n setSavingKind(kind)\n setError(null)\n try {\n await runMutation({\n // optimistic-lock-exempt: tenant-scoped settings blob (dictionary sort\n // modes), not a versioned per-record entity \u2014 there is no `updatedAt`\n // round-trip to lock against, and concurrent writes converge on the\n // last-selected preference. Mirrors other singleton settings PATCHes.\n operation: async () => {\n await apiCallOrThrow(\n '/api/customers/settings/dictionary-sort-modes',\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ dictionarySortModes: next }),\n },\n { errorMessage: t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.') },\n )\n },\n context: {\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'customers.settings',\n retryLastMutation,\n },\n })\n flash(t('customers.config.dictionarySorting.success', 'Dictionary sorting settings saved.'), 'success')\n } catch (err) {\n setSortModes(previous)\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n } finally {\n setSavingKind(null)\n }\n }, [retryLastMutation, runMutation, sortModes, t])\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-background p-4\">\n <header className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold\">\n {t('customers.config.dictionarySorting.title', 'Dictionary sorting')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionarySorting.description', 'Choose how customer dictionary values are ordered in dropdowns and settings.')}\n </p>\n </header>\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.config.dictionarySorting.loading', 'Loading dictionary sorting settings\u2026')}\n </div>\n ) : (\n <div className=\"grid gap-3 lg:grid-cols-2\">\n {sections.map((section) => {\n const value = sortModes[section.kind] ?? DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n const saving = savingKind === section.kind\n return (\n <div key={section.kind} className=\"rounded border p-3\">\n <div className=\"mb-3 space-y-1\">\n <div className=\"text-sm font-medium\">{section.title}</div>\n <div className=\"text-xs text-muted-foreground\">{section.description}</div>\n </div>\n <Select\n value={value}\n onValueChange={(next) => {\n if (!isDictionaryEntrySortMode(next) || next === value) return\n handleChange(section.kind, next).catch(() => {})\n }}\n disabled={savingKind !== null}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {sortOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {saving ? (\n <div className=\"mt-2 inline-flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.config.dictionarySorting.updating', 'Saving\u2026')}\n </div>\n ) : null}\n </div>\n )\n })}\n </div>\n )}\n {error ? <p className=\"text-sm text-status-error-text\">{error}</p> : null}\n </section>\n )\n}\n\nexport default DictionarySortSettings\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
DialogTitle
|
|
14
14
|
} from "@open-mercato/ui/primitives/dialog";
|
|
15
15
|
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
16
|
-
import { apiCall, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
16
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
|
|
17
|
+
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
17
18
|
import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
18
19
|
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
19
20
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -38,7 +39,8 @@ function normalizePipeline(raw) {
|
|
|
38
39
|
name: typeof raw.name === "string" ? raw.name : "",
|
|
39
40
|
isDefault: raw.isDefault === true || raw.is_default === true,
|
|
40
41
|
organizationId: typeof raw.organizationId === "string" ? raw.organizationId : typeof raw.organization_id === "string" ? raw.organization_id : "",
|
|
41
|
-
tenantId: typeof raw.tenantId === "string" ? raw.tenantId : typeof raw.tenant_id === "string" ? raw.tenant_id : ""
|
|
42
|
+
tenantId: typeof raw.tenantId === "string" ? raw.tenantId : typeof raw.tenant_id === "string" ? raw.tenant_id : "",
|
|
43
|
+
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : typeof raw.updated_at === "string" ? raw.updated_at : null
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
function normalizeStage(raw) {
|
|
@@ -48,7 +50,8 @@ function normalizeStage(raw) {
|
|
|
48
50
|
label: typeof raw.label === "string" ? raw.label : "",
|
|
49
51
|
order: typeof raw.order === "number" ? raw.order : 0,
|
|
50
52
|
color: typeof raw.color === "string" && raw.color.trim().length ? raw.color.trim() : null,
|
|
51
|
-
icon: typeof raw.icon === "string" && raw.icon.trim().length ? raw.icon.trim() : null
|
|
53
|
+
icon: typeof raw.icon === "string" && raw.icon.trim().length ? raw.icon.trim() : null,
|
|
54
|
+
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : typeof raw.updated_at === "string" ? raw.updated_at : null
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
function PipelineSettings() {
|
|
@@ -132,11 +135,14 @@ function PipelineSettings() {
|
|
|
132
135
|
}
|
|
133
136
|
flash(t("customers.pipelines.flash.created", "Pipeline created"), "success");
|
|
134
137
|
} else if (pipelineDialog?.mode === "edit") {
|
|
135
|
-
const res = await
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
const res = await withScopedApiRequestHeaders(
|
|
139
|
+
buildOptimisticLockHeader(pipelineDialog.entry.updatedAt),
|
|
140
|
+
() => apiCall("/api/customers/pipelines", {
|
|
141
|
+
method: "PUT",
|
|
142
|
+
headers: { "content-type": "application/json" },
|
|
143
|
+
body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault })
|
|
144
|
+
})
|
|
145
|
+
);
|
|
140
146
|
if (!res.ok) {
|
|
141
147
|
await raiseCrudError(res.response, t("customers.pipelines.errors.updateFailed", "Failed to update pipeline"));
|
|
142
148
|
return;
|
|
@@ -157,11 +163,14 @@ function PipelineSettings() {
|
|
|
157
163
|
variant: "destructive"
|
|
158
164
|
});
|
|
159
165
|
if (!confirmed) return;
|
|
160
|
-
const res = await
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
const res = await withScopedApiRequestHeaders(
|
|
167
|
+
buildOptimisticLockHeader(pipeline.updatedAt),
|
|
168
|
+
() => apiCall("/api/customers/pipelines", {
|
|
169
|
+
method: "DELETE",
|
|
170
|
+
headers: { "content-type": "application/json" },
|
|
171
|
+
body: JSON.stringify({ id: pipeline.id })
|
|
172
|
+
})
|
|
173
|
+
);
|
|
165
174
|
if (!res.ok) {
|
|
166
175
|
const body = res.result ?? {};
|
|
167
176
|
const msg = typeof body.error === "string" ? body.error : t("customers.pipelines.errors.deleteFailed", "Failed to delete pipeline");
|
|
@@ -203,11 +212,14 @@ function PipelineSettings() {
|
|
|
203
212
|
flash(t("customers.pipelines.flash.stageCreated", "Stage created"), "success");
|
|
204
213
|
await loadStages(stageDialog.pipelineId);
|
|
205
214
|
} else if (stageDialog?.mode === "edit") {
|
|
206
|
-
const res = await
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
const res = await withScopedApiRequestHeaders(
|
|
216
|
+
buildOptimisticLockHeader(stageDialog.entry.updatedAt),
|
|
217
|
+
() => apiCall("/api/customers/pipeline-stages", {
|
|
218
|
+
method: "PUT",
|
|
219
|
+
headers: { "content-type": "application/json" },
|
|
220
|
+
body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance })
|
|
221
|
+
})
|
|
222
|
+
);
|
|
211
223
|
if (!res.ok) {
|
|
212
224
|
await raiseCrudError(res.response, t("customers.pipelines.errors.stageUpdateFailed", "Failed to update stage"));
|
|
213
225
|
return;
|
|
@@ -228,11 +240,14 @@ function PipelineSettings() {
|
|
|
228
240
|
variant: "destructive"
|
|
229
241
|
});
|
|
230
242
|
if (!confirmed) return;
|
|
231
|
-
const res = await
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
243
|
+
const res = await withScopedApiRequestHeaders(
|
|
244
|
+
buildOptimisticLockHeader(stage.updatedAt),
|
|
245
|
+
() => apiCall("/api/customers/pipeline-stages", {
|
|
246
|
+
method: "DELETE",
|
|
247
|
+
headers: { "content-type": "application/json" },
|
|
248
|
+
body: JSON.stringify({ id: stage.id })
|
|
249
|
+
})
|
|
250
|
+
);
|
|
236
251
|
if (!res.ok) {
|
|
237
252
|
const body = res.result ?? {};
|
|
238
253
|
const msg = typeof body.error === "string" ? body.error : t("customers.pipelines.errors.stageDeleteFailed", "Failed to delete stage");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/components/PipelineSettings.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport {\n AppearanceSelector,\n type AppearanceSelectorLabels,\n} from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport {\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\ntype Pipeline = {\n id: string\n name: string\n isDefault: boolean\n organizationId: string\n tenantId: string\n}\n\ntype PipelineStage = {\n id: string\n pipelineId: string\n label: string\n order: number\n color: string | null\n icon: string | null\n}\n\ntype PipelineDialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: Pipeline }\n\ntype StageDialogState =\n | { mode: 'create'; pipelineId: string }\n | { mode: 'edit'; entry: PipelineStage }\n\nfunction normalizePipeline(raw: Record<string, unknown>): Pipeline {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n name: typeof raw.name === 'string' ? raw.name : '',\n isDefault: raw.isDefault === true || raw.is_default === true,\n organizationId: typeof raw.organizationId === 'string' ? raw.organizationId : (typeof raw.organization_id === 'string' ? raw.organization_id : ''),\n tenantId: typeof raw.tenantId === 'string' ? raw.tenantId : (typeof raw.tenant_id === 'string' ? raw.tenant_id : ''),\n }\n}\n\nfunction normalizeStage(raw: Record<string, unknown>): PipelineStage {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n pipelineId: typeof raw.pipelineId === 'string' ? raw.pipelineId : (typeof raw.pipeline_id === 'string' ? raw.pipeline_id : ''),\n label: typeof raw.label === 'string' ? raw.label : '',\n order: typeof raw.order === 'number' ? raw.order : 0,\n color: typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null,\n icon: typeof raw.icon === 'string' && raw.icon.trim().length ? raw.icon.trim() : null,\n }\n}\n\nexport default function PipelineSettings(): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [pipelines, setPipelines] = React.useState<Pipeline[]>([])\n const [loadingPipelines, setLoadingPipelines] = React.useState(false)\n const [pipelineDialog, setPipelineDialog] = React.useState<PipelineDialogState | null>(null)\n const [pipelineForm, setPipelineForm] = React.useState({ name: '', isDefault: false })\n const [submittingPipeline, setSubmittingPipeline] = React.useState(false)\n\n const [expandedPipelineId, setExpandedPipelineId] = React.useState<string | null>(null)\n const [stages, setStages] = React.useState<Record<string, PipelineStage[]>>({})\n const [loadingStages, setLoadingStages] = React.useState<Record<string, boolean>>({})\n const [stageDialog, setStageDialog] = React.useState<StageDialogState | null>(null)\n const [stageForm, setStageForm] = React.useState({ label: '', color: null as string | null, icon: null as string | null })\n const [submittingStage, setSubmittingStage] = React.useState(false)\n\n const loadPipelines = React.useCallback(async () => {\n setLoadingPipelines(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: t('customers.pipelines.errors.loadFailed', 'Failed to load pipelines'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setPipelines(items.map((item) => normalizePipeline(item as Record<string, unknown>)))\n } finally {\n setLoadingPipelines(false)\n }\n }, [t])\n\n const loadStages = React.useCallback(async (pipelineId: string) => {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: true }))\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(pipelineId)}`,\n undefined,\n { errorMessage: t('customers.pipelines.errors.stagesLoadFailed', 'Failed to load stages'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setStages((prev) => ({\n ...prev,\n [pipelineId]: items.map((item) => normalizeStage(item as Record<string, unknown>)),\n }))\n } finally {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: false }))\n }\n }, [t])\n\n React.useEffect(() => {\n void loadPipelines()\n }, [loadPipelines, scopeVersion])\n\n React.useEffect(() => {\n if (expandedPipelineId) {\n void loadStages(expandedPipelineId)\n }\n }, [expandedPipelineId, loadStages])\n\n const openCreatePipeline = React.useCallback(() => {\n setPipelineForm({ name: '', isDefault: false })\n setPipelineDialog({ mode: 'create' })\n }, [])\n\n const openEditPipeline = React.useCallback((pipeline: Pipeline) => {\n setPipelineForm({ name: pipeline.name, isDefault: pipeline.isDefault })\n setPipelineDialog({ mode: 'edit', entry: pipeline })\n }, [])\n\n const closePipelineDialog = React.useCallback(() => {\n setPipelineDialog(null)\n }, [])\n\n const handlePipelineSubmit = React.useCallback(async () => {\n if (!pipelineForm.name.trim()) return\n setSubmittingPipeline(true)\n try {\n if (pipelineDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.createFailed', 'Failed to create pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.created', 'Pipeline created'), 'success')\n } else if (pipelineDialog?.mode === 'edit') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.updateFailed', 'Failed to update pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.updated', 'Pipeline updated'), 'success')\n }\n setPipelineDialog(null)\n await loadPipelines()\n } finally {\n setSubmittingPipeline(false)\n }\n }, [pipelineDialog, pipelineForm, loadPipelines, t])\n\n const handleDeletePipeline = React.useCallback(async (pipeline: Pipeline) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.deleteTitle', 'Delete pipeline'),\n text: t('customers.pipelines.confirm.deleteDesc', 'Are you sure you want to delete this pipeline? This cannot be undone.'),\n confirmText: t('customers.pipelines.confirm.deleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await apiCall('/api/customers/pipelines', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipeline.id }),\n })\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.deleteFailed', 'Failed to delete pipeline')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.deleted', 'Pipeline deleted'), 'success')\n if (expandedPipelineId === pipeline.id) setExpandedPipelineId(null)\n await loadPipelines()\n }, [confirm, expandedPipelineId, loadPipelines, t])\n\n const openCreateStage = React.useCallback((pipelineId: string) => {\n setStageForm({ label: '', color: null, icon: null })\n setStageDialog({ mode: 'create', pipelineId })\n }, [])\n\n const openEditStage = React.useCallback((stage: PipelineStage) => {\n setStageForm({ label: stage.label, color: stage.color, icon: stage.icon })\n setStageDialog({ mode: 'edit', entry: stage })\n }, [])\n\n const closeStageDialog = React.useCallback(() => {\n setStageDialog(null)\n }, [])\n\n const handleStageSubmit = React.useCallback(async () => {\n if (!stageForm.label.trim()) return\n setSubmittingStage(true)\n try {\n const appearance: Record<string, unknown> = {}\n if (stageForm.color) appearance.color = stageForm.color\n if (stageForm.icon) appearance.icon = stageForm.icon\n\n if (stageDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ pipelineId: stageDialog.pipelineId, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageCreateFailed', 'Failed to create stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageCreated', 'Stage created'), 'success')\n await loadStages(stageDialog.pipelineId)\n } else if (stageDialog?.mode === 'edit') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageUpdateFailed', 'Failed to update stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageUpdated', 'Stage updated'), 'success')\n await loadStages(stageDialog.entry.pipelineId)\n }\n setStageDialog(null)\n } finally {\n setSubmittingStage(false)\n }\n }, [stageDialog, stageForm, loadStages, t])\n\n const handleDeleteStage = React.useCallback(async (stage: PipelineStage) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.stageDeleteTitle', 'Delete stage'),\n text: t('customers.pipelines.confirm.stageDeleteDesc', 'Are you sure you want to delete this stage?'),\n confirmText: t('customers.pipelines.confirm.stageDeleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stage.id }),\n })\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.stageDeleteFailed', 'Failed to delete stage')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.stageDeleted', 'Stage deleted'), 'success')\n await loadStages(stage.pipelineId)\n }, [confirm, loadStages, t])\n\n const handleMoveStage = React.useCallback(async (stage: PipelineStage, direction: 'up' | 'down') => {\n const pipelineStages = stages[stage.pipelineId] ?? []\n const idx = pipelineStages.findIndex((s) => s.id === stage.id)\n if (idx < 0) return\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n if (swapIdx < 0 || swapIdx >= pipelineStages.length) return\n\n const reordered = [...pipelineStages]\n const temp = reordered[idx]\n reordered[idx] = reordered[swapIdx]\n reordered[swapIdx] = temp\n\n const orderedStages = reordered.map((s, i) => ({ id: s.id, order: i }))\n const res = await apiCall('/api/customers/pipeline-stages/reorder', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ stages: orderedStages }),\n })\n if (!res.ok) {\n flash(t('customers.pipelines.errors.reorderFailed', 'Failed to reorder stages'), 'error')\n return\n }\n await loadStages(stage.pipelineId)\n }, [stages, loadStages, t])\n\n const handleKeyDown = React.useCallback(\n (handler: () => void) => (e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handler()\n }\n },\n [],\n )\n\n const appearanceLabels = React.useMemo<AppearanceSelectorLabels>(() => ({\n colorLabel: t('customers.pipelines.stageForm.color', 'Color'),\n colorClearLabel: t('customers.pipelines.stageForm.colorClear', 'Remove color'),\n iconLabel: t('customers.pipelines.stageForm.icon', 'Icon'),\n iconPlaceholder: t('customers.pipelines.stageForm.iconPlaceholder', 'e.g. lucide:star'),\n iconPickerTriggerLabel: t('customers.pipelines.stageForm.iconPicker', 'Pick icon'),\n iconSearchPlaceholder: t('customers.pipelines.stageForm.iconSearch', 'Search icons\u2026'),\n iconSearchEmptyLabel: t('customers.pipelines.stageForm.iconSearchEmpty', 'No icons found'),\n iconSuggestionsLabel: t('customers.pipelines.stageForm.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.pipelines.stageForm.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.pipelines.stageForm.previewEmpty', 'No appearance set'),\n }), [t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold\">{t('customers.pipelines.title', 'Sales Pipelines')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.description', 'Manage sales pipelines and their stages.')}\n </p>\n </div>\n <Button size=\"sm\" onClick={openCreatePipeline}>\n {t('customers.pipelines.actions.create', 'Add pipeline')}\n </Button>\n </div>\n\n {loadingPipelines ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.pipelines.loading', 'Loading pipelines\u2026')}\n </div>\n ) : pipelines.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.empty', 'No pipelines yet. Create one to get started.')}\n </p>\n ) : (\n <Accordion\n type=\"single\"\n collapsible\n value={expandedPipelineId ?? ''}\n onValueChange={(next) => setExpandedPipelineId(next || null)}\n className=\"space-y-2\"\n >\n {pipelines.map((pipeline) => {\n const pipelineStages = stages[pipeline.id] ?? []\n const isLoadingStages = loadingStages[pipeline.id] ?? false\n\n return (\n <AccordionItem key={pipeline.id} value={pipeline.id}>\n <AccordionTrigger triggerIcon=\"chevron\">\n <span className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{pipeline.name}</span>\n {pipeline.isDefault ? (\n <span className=\"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary\">\n {t('customers.pipelines.defaultBadge', 'Default')}\n </span>\n ) : null}\n </span>\n </AccordionTrigger>\n <AccordionContent>\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n {t('customers.pipelines.stages.title', 'Stages')}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={() => openCreateStage(pipeline.id)}>\n {t('customers.pipelines.stages.add', 'Add stage')}\n </Button>\n </div>\n\n {isLoadingStages ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.pipelines.stages.loading', 'Loading\u2026')}\n </div>\n ) : pipelineStages.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.stages.empty', 'No stages yet.')}\n </p>\n ) : (\n <div className=\"divide-y divide-border rounded-md border bg-background\">\n {pipelineStages.map((stage, idx) => (\n <div key={stage.id} className=\"flex items-center justify-between gap-3 px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-5 text-center text-xs text-muted-foreground\">{idx + 1}</span>\n {stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}\n {stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}\n <span className=\"text-sm\">{stage.label}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === 0}\n onClick={() => void handleMoveStage(stage, 'up')}\n title={t('customers.pipelines.stages.moveUp', 'Move up')}\n >\n \u2191\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === pipelineStages.length - 1}\n onClick={() => void handleMoveStage(stage, 'down')}\n title={t('customers.pipelines.stages.moveDown', 'Move down')}\n >\n \u2193\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditStage(stage)}\n >\n {t('customers.pipelines.stages.edit', 'Edit')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeleteStage(stage)}\n >\n {t('customers.pipelines.stages.delete', 'Delete')}\n </Button>\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-end gap-2 border-t pt-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditPipeline(pipeline)}\n >\n {t('customers.pipelines.actions.edit', 'Edit pipeline')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeletePipeline(pipeline)}\n >\n {t('customers.pipelines.actions.delete', 'Delete pipeline')}\n </Button>\n </div>\n </AccordionContent>\n </AccordionItem>\n )\n })}\n </Accordion>\n )}\n\n {/* Pipeline Dialog */}\n <Dialog open={pipelineDialog !== null} onOpenChange={(open) => { if (!open) closePipelineDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handlePipelineSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {pipelineDialog?.mode === 'create'\n ? t('customers.pipelines.dialog.createTitle', 'Create pipeline')\n : t('customers.pipelines.dialog.editTitle', 'Edit pipeline')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"pipeline-name\">{t('customers.pipelines.form.name', 'Name')}</Label>\n <Input\n id=\"pipeline-name\"\n value={pipelineForm.name}\n onChange={(e) => setPipelineForm((prev) => ({ ...prev, name: e.target.value }))}\n placeholder={t('customers.pipelines.form.namePlaceholder', 'e.g. New Business')}\n autoFocus\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"pipeline-default\"\n checked={pipelineForm.isDefault}\n onCheckedChange={(checked) => setPipelineForm((prev) => ({ ...prev, isDefault: checked === true }))}\n />\n <Label htmlFor=\"pipeline-default\" className=\"cursor-pointer\">\n {t('customers.pipelines.form.isDefault', 'Set as default pipeline')}\n </Label>\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closePipelineDialog} disabled={submittingPipeline}>\n {t('customers.pipelines.dialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handlePipelineSubmit()} disabled={submittingPipeline || !pipelineForm.name.trim()}>\n {submittingPipeline ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {ConfirmDialogElement}\n\n {/* Stage Dialog */}\n <Dialog open={stageDialog !== null} onOpenChange={(open) => { if (!open) closeStageDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handleStageSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {stageDialog?.mode === 'create'\n ? t('customers.pipelines.stageDialog.createTitle', 'Add stage')\n : t('customers.pipelines.stageDialog.editTitle', 'Edit stage')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"stage-label\">{t('customers.pipelines.stageForm.label', 'Label')}</Label>\n <Input\n id=\"stage-label\"\n value={stageForm.label}\n onChange={(e) => setStageForm((prev) => ({ ...prev, label: e.target.value }))}\n placeholder={t('customers.pipelines.stageForm.labelPlaceholder', 'e.g. Discovery')}\n autoFocus\n />\n </div>\n <AppearanceSelector\n color={stageForm.color}\n icon={stageForm.icon}\n onColorChange={(next) => setStageForm((prev) => ({ ...prev, color: next }))}\n onIconChange={(next) => setStageForm((prev) => ({ ...prev, icon: next }))}\n labels={appearanceLabels}\n />\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closeStageDialog} disabled={submittingStage}>\n {t('customers.pipelines.stageDialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleStageSubmit()} disabled={submittingStage || !stageForm.label.trim()}>\n {submittingStage ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.stageDialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport {\n AppearanceSelector,\n type AppearanceSelectorLabels,\n} from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport {\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\ntype Pipeline = {\n id: string\n name: string\n isDefault: boolean\n organizationId: string\n tenantId: string\n updatedAt?: string | null\n}\n\ntype PipelineStage = {\n id: string\n pipelineId: string\n label: string\n order: number\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\ntype PipelineDialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: Pipeline }\n\ntype StageDialogState =\n | { mode: 'create'; pipelineId: string }\n | { mode: 'edit'; entry: PipelineStage }\n\nfunction normalizePipeline(raw: Record<string, unknown>): Pipeline {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n name: typeof raw.name === 'string' ? raw.name : '',\n isDefault: raw.isDefault === true || raw.is_default === true,\n organizationId: typeof raw.organizationId === 'string' ? raw.organizationId : (typeof raw.organization_id === 'string' ? raw.organization_id : ''),\n tenantId: typeof raw.tenantId === 'string' ? raw.tenantId : (typeof raw.tenant_id === 'string' ? raw.tenant_id : ''),\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),\n }\n}\n\nfunction normalizeStage(raw: Record<string, unknown>): PipelineStage {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n pipelineId: typeof raw.pipelineId === 'string' ? raw.pipelineId : (typeof raw.pipeline_id === 'string' ? raw.pipeline_id : ''),\n label: typeof raw.label === 'string' ? raw.label : '',\n order: typeof raw.order === 'number' ? raw.order : 0,\n color: typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null,\n icon: typeof raw.icon === 'string' && raw.icon.trim().length ? raw.icon.trim() : null,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),\n }\n}\n\nexport default function PipelineSettings(): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [pipelines, setPipelines] = React.useState<Pipeline[]>([])\n const [loadingPipelines, setLoadingPipelines] = React.useState(false)\n const [pipelineDialog, setPipelineDialog] = React.useState<PipelineDialogState | null>(null)\n const [pipelineForm, setPipelineForm] = React.useState({ name: '', isDefault: false })\n const [submittingPipeline, setSubmittingPipeline] = React.useState(false)\n\n const [expandedPipelineId, setExpandedPipelineId] = React.useState<string | null>(null)\n const [stages, setStages] = React.useState<Record<string, PipelineStage[]>>({})\n const [loadingStages, setLoadingStages] = React.useState<Record<string, boolean>>({})\n const [stageDialog, setStageDialog] = React.useState<StageDialogState | null>(null)\n const [stageForm, setStageForm] = React.useState({ label: '', color: null as string | null, icon: null as string | null })\n const [submittingStage, setSubmittingStage] = React.useState(false)\n\n const loadPipelines = React.useCallback(async () => {\n setLoadingPipelines(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: t('customers.pipelines.errors.loadFailed', 'Failed to load pipelines'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setPipelines(items.map((item) => normalizePipeline(item as Record<string, unknown>)))\n } finally {\n setLoadingPipelines(false)\n }\n }, [t])\n\n const loadStages = React.useCallback(async (pipelineId: string) => {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: true }))\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(pipelineId)}`,\n undefined,\n { errorMessage: t('customers.pipelines.errors.stagesLoadFailed', 'Failed to load stages'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setStages((prev) => ({\n ...prev,\n [pipelineId]: items.map((item) => normalizeStage(item as Record<string, unknown>)),\n }))\n } finally {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: false }))\n }\n }, [t])\n\n React.useEffect(() => {\n void loadPipelines()\n }, [loadPipelines, scopeVersion])\n\n React.useEffect(() => {\n if (expandedPipelineId) {\n void loadStages(expandedPipelineId)\n }\n }, [expandedPipelineId, loadStages])\n\n const openCreatePipeline = React.useCallback(() => {\n setPipelineForm({ name: '', isDefault: false })\n setPipelineDialog({ mode: 'create' })\n }, [])\n\n const openEditPipeline = React.useCallback((pipeline: Pipeline) => {\n setPipelineForm({ name: pipeline.name, isDefault: pipeline.isDefault })\n setPipelineDialog({ mode: 'edit', entry: pipeline })\n }, [])\n\n const closePipelineDialog = React.useCallback(() => {\n setPipelineDialog(null)\n }, [])\n\n const handlePipelineSubmit = React.useCallback(async () => {\n if (!pipelineForm.name.trim()) return\n setSubmittingPipeline(true)\n try {\n if (pipelineDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.createFailed', 'Failed to create pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.created', 'Pipeline created'), 'success')\n } else if (pipelineDialog?.mode === 'edit') {\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(pipelineDialog.entry.updatedAt),\n () =>\n apiCall('/api/customers/pipelines', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n }),\n )\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.updateFailed', 'Failed to update pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.updated', 'Pipeline updated'), 'success')\n }\n setPipelineDialog(null)\n await loadPipelines()\n } finally {\n setSubmittingPipeline(false)\n }\n }, [pipelineDialog, pipelineForm, loadPipelines, t])\n\n const handleDeletePipeline = React.useCallback(async (pipeline: Pipeline) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.deleteTitle', 'Delete pipeline'),\n text: t('customers.pipelines.confirm.deleteDesc', 'Are you sure you want to delete this pipeline? This cannot be undone.'),\n confirmText: t('customers.pipelines.confirm.deleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(pipeline.updatedAt),\n () =>\n apiCall('/api/customers/pipelines', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipeline.id }),\n }),\n )\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.deleteFailed', 'Failed to delete pipeline')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.deleted', 'Pipeline deleted'), 'success')\n if (expandedPipelineId === pipeline.id) setExpandedPipelineId(null)\n await loadPipelines()\n }, [confirm, expandedPipelineId, loadPipelines, t])\n\n const openCreateStage = React.useCallback((pipelineId: string) => {\n setStageForm({ label: '', color: null, icon: null })\n setStageDialog({ mode: 'create', pipelineId })\n }, [])\n\n const openEditStage = React.useCallback((stage: PipelineStage) => {\n setStageForm({ label: stage.label, color: stage.color, icon: stage.icon })\n setStageDialog({ mode: 'edit', entry: stage })\n }, [])\n\n const closeStageDialog = React.useCallback(() => {\n setStageDialog(null)\n }, [])\n\n const handleStageSubmit = React.useCallback(async () => {\n if (!stageForm.label.trim()) return\n setSubmittingStage(true)\n try {\n const appearance: Record<string, unknown> = {}\n if (stageForm.color) appearance.color = stageForm.color\n if (stageForm.icon) appearance.icon = stageForm.icon\n\n if (stageDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ pipelineId: stageDialog.pipelineId, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageCreateFailed', 'Failed to create stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageCreated', 'Stage created'), 'success')\n await loadStages(stageDialog.pipelineId)\n } else if (stageDialog?.mode === 'edit') {\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(stageDialog.entry.updatedAt),\n () =>\n apiCall('/api/customers/pipeline-stages', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance }),\n }),\n )\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageUpdateFailed', 'Failed to update stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageUpdated', 'Stage updated'), 'success')\n await loadStages(stageDialog.entry.pipelineId)\n }\n setStageDialog(null)\n } finally {\n setSubmittingStage(false)\n }\n }, [stageDialog, stageForm, loadStages, t])\n\n const handleDeleteStage = React.useCallback(async (stage: PipelineStage) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.stageDeleteTitle', 'Delete stage'),\n text: t('customers.pipelines.confirm.stageDeleteDesc', 'Are you sure you want to delete this stage?'),\n confirmText: t('customers.pipelines.confirm.stageDeleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(stage.updatedAt),\n () =>\n apiCall('/api/customers/pipeline-stages', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stage.id }),\n }),\n )\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.stageDeleteFailed', 'Failed to delete stage')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.stageDeleted', 'Stage deleted'), 'success')\n await loadStages(stage.pipelineId)\n }, [confirm, loadStages, t])\n\n const handleMoveStage = React.useCallback(async (stage: PipelineStage, direction: 'up' | 'down') => {\n const pipelineStages = stages[stage.pipelineId] ?? []\n const idx = pipelineStages.findIndex((s) => s.id === stage.id)\n if (idx < 0) return\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n if (swapIdx < 0 || swapIdx >= pipelineStages.length) return\n\n const reordered = [...pipelineStages]\n const temp = reordered[idx]\n reordered[idx] = reordered[swapIdx]\n reordered[swapIdx] = temp\n\n const orderedStages = reordered.map((s, i) => ({ id: s.id, order: i }))\n const res = await apiCall('/api/customers/pipeline-stages/reorder', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ stages: orderedStages }),\n })\n if (!res.ok) {\n flash(t('customers.pipelines.errors.reorderFailed', 'Failed to reorder stages'), 'error')\n return\n }\n await loadStages(stage.pipelineId)\n }, [stages, loadStages, t])\n\n const handleKeyDown = React.useCallback(\n (handler: () => void) => (e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handler()\n }\n },\n [],\n )\n\n const appearanceLabels = React.useMemo<AppearanceSelectorLabels>(() => ({\n colorLabel: t('customers.pipelines.stageForm.color', 'Color'),\n colorClearLabel: t('customers.pipelines.stageForm.colorClear', 'Remove color'),\n iconLabel: t('customers.pipelines.stageForm.icon', 'Icon'),\n iconPlaceholder: t('customers.pipelines.stageForm.iconPlaceholder', 'e.g. lucide:star'),\n iconPickerTriggerLabel: t('customers.pipelines.stageForm.iconPicker', 'Pick icon'),\n iconSearchPlaceholder: t('customers.pipelines.stageForm.iconSearch', 'Search icons\u2026'),\n iconSearchEmptyLabel: t('customers.pipelines.stageForm.iconSearchEmpty', 'No icons found'),\n iconSuggestionsLabel: t('customers.pipelines.stageForm.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.pipelines.stageForm.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.pipelines.stageForm.previewEmpty', 'No appearance set'),\n }), [t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold\">{t('customers.pipelines.title', 'Sales Pipelines')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.description', 'Manage sales pipelines and their stages.')}\n </p>\n </div>\n <Button size=\"sm\" onClick={openCreatePipeline}>\n {t('customers.pipelines.actions.create', 'Add pipeline')}\n </Button>\n </div>\n\n {loadingPipelines ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.pipelines.loading', 'Loading pipelines\u2026')}\n </div>\n ) : pipelines.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.empty', 'No pipelines yet. Create one to get started.')}\n </p>\n ) : (\n <Accordion\n type=\"single\"\n collapsible\n value={expandedPipelineId ?? ''}\n onValueChange={(next) => setExpandedPipelineId(next || null)}\n className=\"space-y-2\"\n >\n {pipelines.map((pipeline) => {\n const pipelineStages = stages[pipeline.id] ?? []\n const isLoadingStages = loadingStages[pipeline.id] ?? false\n\n return (\n <AccordionItem key={pipeline.id} value={pipeline.id}>\n <AccordionTrigger triggerIcon=\"chevron\">\n <span className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{pipeline.name}</span>\n {pipeline.isDefault ? (\n <span className=\"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary\">\n {t('customers.pipelines.defaultBadge', 'Default')}\n </span>\n ) : null}\n </span>\n </AccordionTrigger>\n <AccordionContent>\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n {t('customers.pipelines.stages.title', 'Stages')}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={() => openCreateStage(pipeline.id)}>\n {t('customers.pipelines.stages.add', 'Add stage')}\n </Button>\n </div>\n\n {isLoadingStages ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.pipelines.stages.loading', 'Loading\u2026')}\n </div>\n ) : pipelineStages.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.stages.empty', 'No stages yet.')}\n </p>\n ) : (\n <div className=\"divide-y divide-border rounded-md border bg-background\">\n {pipelineStages.map((stage, idx) => (\n <div key={stage.id} className=\"flex items-center justify-between gap-3 px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-5 text-center text-xs text-muted-foreground\">{idx + 1}</span>\n {stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}\n {stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}\n <span className=\"text-sm\">{stage.label}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === 0}\n onClick={() => void handleMoveStage(stage, 'up')}\n title={t('customers.pipelines.stages.moveUp', 'Move up')}\n >\n \u2191\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === pipelineStages.length - 1}\n onClick={() => void handleMoveStage(stage, 'down')}\n title={t('customers.pipelines.stages.moveDown', 'Move down')}\n >\n \u2193\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditStage(stage)}\n >\n {t('customers.pipelines.stages.edit', 'Edit')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeleteStage(stage)}\n >\n {t('customers.pipelines.stages.delete', 'Delete')}\n </Button>\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-end gap-2 border-t pt-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditPipeline(pipeline)}\n >\n {t('customers.pipelines.actions.edit', 'Edit pipeline')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeletePipeline(pipeline)}\n >\n {t('customers.pipelines.actions.delete', 'Delete pipeline')}\n </Button>\n </div>\n </AccordionContent>\n </AccordionItem>\n )\n })}\n </Accordion>\n )}\n\n {/* Pipeline Dialog */}\n <Dialog open={pipelineDialog !== null} onOpenChange={(open) => { if (!open) closePipelineDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handlePipelineSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {pipelineDialog?.mode === 'create'\n ? t('customers.pipelines.dialog.createTitle', 'Create pipeline')\n : t('customers.pipelines.dialog.editTitle', 'Edit pipeline')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"pipeline-name\">{t('customers.pipelines.form.name', 'Name')}</Label>\n <Input\n id=\"pipeline-name\"\n value={pipelineForm.name}\n onChange={(e) => setPipelineForm((prev) => ({ ...prev, name: e.target.value }))}\n placeholder={t('customers.pipelines.form.namePlaceholder', 'e.g. New Business')}\n autoFocus\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"pipeline-default\"\n checked={pipelineForm.isDefault}\n onCheckedChange={(checked) => setPipelineForm((prev) => ({ ...prev, isDefault: checked === true }))}\n />\n <Label htmlFor=\"pipeline-default\" className=\"cursor-pointer\">\n {t('customers.pipelines.form.isDefault', 'Set as default pipeline')}\n </Label>\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closePipelineDialog} disabled={submittingPipeline}>\n {t('customers.pipelines.dialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handlePipelineSubmit()} disabled={submittingPipeline || !pipelineForm.name.trim()}>\n {submittingPipeline ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {ConfirmDialogElement}\n\n {/* Stage Dialog */}\n <Dialog open={stageDialog !== null} onOpenChange={(open) => { if (!open) closeStageDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handleStageSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {stageDialog?.mode === 'create'\n ? t('customers.pipelines.stageDialog.createTitle', 'Add stage')\n : t('customers.pipelines.stageDialog.editTitle', 'Edit stage')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"stage-label\">{t('customers.pipelines.stageForm.label', 'Label')}</Label>\n <Input\n id=\"stage-label\"\n value={stageForm.label}\n onChange={(e) => setStageForm((prev) => ({ ...prev, label: e.target.value }))}\n placeholder={t('customers.pipelines.stageForm.labelPlaceholder', 'e.g. Discovery')}\n autoFocus\n />\n </div>\n <AppearanceSelector\n color={stageForm.color}\n icon={stageForm.icon}\n onColorChange={(next) => setStageForm((prev) => ({ ...prev, color: next }))}\n onIconChange={(next) => setStageForm((prev) => ({ ...prev, icon: next }))}\n labels={appearanceLabels}\n />\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closeStageDialog} disabled={submittingStage}>\n {t('customers.pipelines.stageDialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleStageSubmit()} disabled={submittingStage || !stageForm.label.trim()}>\n {submittingStage ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.stageDialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AA2WQ,SACE,KADF;AAzWR,YAAY,WAAW;AACvB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,SAAS,sBAAsB,mCAAmC;AAC3E,SAAS,iCAAiC;AAC1C,SAAS,sBAAsB;AAC/B,SAAS,mCAAmC;AAC5C,SAAS,YAAY;AACrB,SAAS,wBAAwB;AACjC,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AA6BP,SAAS,kBAAkB,KAAwC;AACjE,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK;AAAA,IAC1C,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAAA,IAChD,WAAW,IAAI,cAAc,QAAQ,IAAI,eAAe;AAAA,IACxD,gBAAgB,OAAO,IAAI,mBAAmB,WAAW,IAAI,iBAAkB,OAAO,IAAI,oBAAoB,WAAW,IAAI,kBAAkB;AAAA,IAC/I,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,WAAY,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY;AAAA,IACjH,WAAW,OAAO,IAAI,cAAc,WAAW,IAAI,YAAa,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACxH;AACF;AAEA,SAAS,eAAe,KAA6C;AACnE,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK;AAAA,IAC1C,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAc,OAAO,IAAI,gBAAgB,WAAW,IAAI,cAAc;AAAA,IAC3H,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAAA,IACnD,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAAA,IACnD,OAAO,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI;AAAA,IACrF,MAAM,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,KAAK,EAAE,SAAS,IAAI,KAAK,KAAK,IAAI;AAAA,IACjF,WAAW,OAAO,IAAI,cAAc,WAAW,IAAI,YAAa,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACxH;AACF;AAEe,SAAR,mBAAwD;AAC7D,QAAM,IAAI,KAAK;AACf,QAAM,eAAe,4BAA4B;AACjD,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAE3D,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAqB,CAAC,CAAC;AAC/D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAS,KAAK;AACpE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAqC,IAAI;AAC3F,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,EAAE,MAAM,IAAI,WAAW,MAAM,CAAC;AACrF,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAS,KAAK;AAExE,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAwB,IAAI;AACtF,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAA0C,CAAC,CAAC;AAC9E,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAkC,CAAC,CAAC;AACpF,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAkC,IAAI;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,EAAE,OAAO,IAAI,OAAO,MAAuB,MAAM,KAAsB,CAAC;AACzH,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,KAAK;AAElE,QAAM,gBAAgB,MAAM,YAAY,YAAY;AAClD,wBAAoB,IAAI;AACxB,QAAI;AACF,YAAM,OAAO,MAAM;AAAA,QACjB;AAAA,QACA;AAAA,QACA,EAAE,cAAc,EAAE,yCAAyC,0BAA0B,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MAClH;AACA,YAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AACzD,mBAAa,MAAM,IAAI,CAAC,SAAS,kBAAkB,IAA+B,CAAC,CAAC;AAAA,IACtF,UAAE;AACA,0BAAoB,KAAK;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,aAAa,MAAM,YAAY,OAAO,eAAuB;AACjE,qBAAiB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,KAAK,EAAE;AAC5D,QAAI;AACF,YAAM,OAAO,MAAM;AAAA,QACjB,6CAA6C,mBAAmB,UAAU,CAAC;AAAA,QAC3E;AAAA,QACA,EAAE,cAAc,EAAE,+CAA+C,uBAAuB,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MACrH;AACA,YAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AACzD,gBAAU,CAAC,UAAU;AAAA,QACnB,GAAG;AAAA,QACH,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,eAAe,IAA+B,CAAC;AAAA,MACnF,EAAE;AAAA,IACJ,UAAE;AACA,uBAAiB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,MAAM,EAAE;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,SAAK,cAAc;AAAA,EACrB,GAAG,CAAC,eAAe,YAAY,CAAC;AAEhC,QAAM,UAAU,MAAM;AACpB,QAAI,oBAAoB;AACtB,WAAK,WAAW,kBAAkB;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,oBAAoB,UAAU,CAAC;AAEnC,QAAM,qBAAqB,MAAM,YAAY,MAAM;AACjD,oBAAgB,EAAE,MAAM,IAAI,WAAW,MAAM,CAAC;AAC9C,sBAAkB,EAAE,MAAM,SAAS,CAAC;AAAA,EACtC,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,CAAC,aAAuB;AACjE,oBAAgB,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,UAAU,CAAC;AACtE,sBAAkB,EAAE,MAAM,QAAQ,OAAO,SAAS,CAAC;AAAA,EACrD,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAsB,MAAM,YAAY,MAAM;AAClD,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,MAAM,YAAY,YAAY;AACzD,QAAI,CAAC,aAAa,KAAK,KAAK,EAAG;AAC/B,0BAAsB,IAAI;AAC1B,QAAI;AACF,UAAI,gBAAgB,SAAS,UAAU;AACrC,cAAM,MAAM,MAAM,QAAQ,4BAA4B;AAAA,UACpD,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,aAAa,KAAK,KAAK,GAAG,WAAW,aAAa,UAAU,CAAC;AAAA,QAC5F,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,2CAA2C,2BAA2B,CAAC;AAC5G;AAAA,QACF;AACA,cAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAAA,MAC7E,WAAW,gBAAgB,SAAS,QAAQ;AAC1C,cAAM,MAAM,MAAM;AAAA,UAChB,0BAA0B,eAAe,MAAM,SAAS;AAAA,UACxD,MACE,QAAQ,4BAA4B;AAAA,YAClC,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,eAAe,MAAM,IAAI,MAAM,aAAa,KAAK,KAAK,GAAG,WAAW,aAAa,UAAU,CAAC;AAAA,UACzH,CAAC;AAAA,QACL;AACA,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,2CAA2C,2BAA2B,CAAC;AAC5G;AAAA,QACF;AACA,cAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAAA,MAC7E;AACA,wBAAkB,IAAI;AACtB,YAAM,cAAc;AAAA,IACtB,UAAE;AACA,4BAAsB,KAAK;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,gBAAgB,cAAc,eAAe,CAAC,CAAC;AAEnD,QAAM,uBAAuB,MAAM,YAAY,OAAO,aAAuB;AAC3E,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,2CAA2C,iBAAiB;AAAA,MACrE,MAAM,EAAE,0CAA0C,uEAAuE;AAAA,MACzH,aAAa,EAAE,6CAA6C,QAAQ;AAAA,MACpE,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,UAAM,MAAM,MAAM;AAAA,MAChB,0BAA0B,SAAS,SAAS;AAAA,MAC5C,MACE,QAAQ,4BAA4B;AAAA,QAClC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAAA,MAC1C,CAAC;AAAA,IACL;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,IAAI,UAAU,CAAC;AAC7B,YAAM,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE,2CAA2C,2BAA2B;AAClI,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AACA,UAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAC3E,QAAI,uBAAuB,SAAS,GAAI,uBAAsB,IAAI;AAClE,UAAM,cAAc;AAAA,EACtB,GAAG,CAAC,SAAS,oBAAoB,eAAe,CAAC,CAAC;AAElD,QAAM,kBAAkB,MAAM,YAAY,CAAC,eAAuB;AAChE,iBAAa,EAAE,OAAO,IAAI,OAAO,MAAM,MAAM,KAAK,CAAC;AACnD,mBAAe,EAAE,MAAM,UAAU,WAAW,CAAC;AAAA,EAC/C,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,MAAM,YAAY,CAAC,UAAyB;AAChE,iBAAa,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC;AACzE,mBAAe,EAAE,MAAM,QAAQ,OAAO,MAAM,CAAC;AAAA,EAC/C,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,MAAM;AAC/C,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,oBAAoB,MAAM,YAAY,YAAY;AACtD,QAAI,CAAC,UAAU,MAAM,KAAK,EAAG;AAC7B,uBAAmB,IAAI;AACvB,QAAI;AACF,YAAM,aAAsC,CAAC;AAC7C,UAAI,UAAU,MAAO,YAAW,QAAQ,UAAU;AAClD,UAAI,UAAU,KAAM,YAAW,OAAO,UAAU;AAEhD,UAAI,aAAa,SAAS,UAAU;AAClC,cAAM,MAAM,MAAM,QAAQ,kCAAkC;AAAA,UAC1D,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,YAAY,YAAY,YAAY,OAAO,UAAU,MAAM,KAAK,GAAG,GAAG,WAAW,CAAC;AAAA,QAC3G,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,gDAAgD,wBAAwB,CAAC;AAC9G;AAAA,QACF;AACA,cAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,cAAM,WAAW,YAAY,UAAU;AAAA,MACzC,WAAW,aAAa,SAAS,QAAQ;AACvC,cAAM,MAAM,MAAM;AAAA,UAChB,0BAA0B,YAAY,MAAM,SAAS;AAAA,UACrD,MACE,QAAQ,kCAAkC;AAAA,YACxC,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,YAAY,MAAM,IAAI,OAAO,UAAU,MAAM,KAAK,GAAG,GAAG,WAAW,CAAC;AAAA,UACjG,CAAC;AAAA,QACL;AACA,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,gDAAgD,wBAAwB,CAAC;AAC9G;AAAA,QACF;AACA,cAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,cAAM,WAAW,YAAY,MAAM,UAAU;AAAA,MAC/C;AACA,qBAAe,IAAI;AAAA,IACrB,UAAE;AACA,yBAAmB,KAAK;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,aAAa,WAAW,YAAY,CAAC,CAAC;AAE1C,QAAM,oBAAoB,MAAM,YAAY,OAAO,UAAyB;AAC1E,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,gDAAgD,cAAc;AAAA,MACvE,MAAM,EAAE,+CAA+C,6CAA6C;AAAA,MACpG,aAAa,EAAE,kDAAkD,QAAQ;AAAA,MACzE,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,UAAM,MAAM,MAAM;AAAA,MAChB,0BAA0B,MAAM,SAAS;AAAA,MACzC,MACE,QAAQ,kCAAkC;AAAA,QACxC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,MAAM,GAAG,CAAC;AAAA,MACvC,CAAC;AAAA,IACL;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,IAAI,UAAU,CAAC;AAC7B,YAAM,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE,gDAAgD,wBAAwB;AACpI,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AACA,UAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,UAAM,WAAW,MAAM,UAAU;AAAA,EACnC,GAAG,CAAC,SAAS,YAAY,CAAC,CAAC;AAE3B,QAAM,kBAAkB,MAAM,YAAY,OAAO,OAAsB,cAA6B;AAClG,UAAM,iBAAiB,OAAO,MAAM,UAAU,KAAK,CAAC;AACpD,UAAM,MAAM,eAAe,UAAU,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AAC7D,QAAI,MAAM,EAAG;AACb,UAAM,UAAU,cAAc,OAAO,MAAM,IAAI,MAAM;AACrD,QAAI,UAAU,KAAK,WAAW,eAAe,OAAQ;AAErD,UAAM,YAAY,CAAC,GAAG,cAAc;AACpC,UAAM,OAAO,UAAU,GAAG;AAC1B,cAAU,GAAG,IAAI,UAAU,OAAO;AAClC,cAAU,OAAO,IAAI;AAErB,UAAM,gBAAgB,UAAU,IAAI,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,EAAE;AACtE,UAAM,MAAM,MAAM,QAAQ,0CAA0C;AAAA,MAClE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,QAAQ,cAAc,CAAC;AAAA,IAChD,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,EAAE,4CAA4C,0BAA0B,GAAG,OAAO;AACxF;AAAA,IACF;AACA,UAAM,WAAW,MAAM,UAAU;AAAA,EACnC,GAAG,CAAC,QAAQ,YAAY,CAAC,CAAC;AAE1B,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,YAAwB,CAAC,MAA2B;AACnD,WAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,SAAS;AACjD,UAAE,eAAe;AACjB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,MAAM,QAAkC,OAAO;AAAA,IACtE,YAAY,EAAE,uCAAuC,OAAO;AAAA,IAC5D,iBAAiB,EAAE,4CAA4C,cAAc;AAAA,IAC7E,WAAW,EAAE,sCAAsC,MAAM;AAAA,IACzD,iBAAiB,EAAE,iDAAiD,kBAAkB;AAAA,IACtF,wBAAwB,EAAE,4CAA4C,WAAW;AAAA,IACjF,uBAAuB,EAAE,4CAA4C,oBAAe;AAAA,IACpF,sBAAsB,EAAE,iDAAiD,gBAAgB;AAAA,IACzF,sBAAsB,EAAE,iDAAiD,aAAa;AAAA,IACtF,gBAAgB,EAAE,2CAA2C,aAAa;AAAA,IAC1E,mBAAmB,EAAE,8CAA8C,mBAAmB;AAAA,EACxF,IAAI,CAAC,CAAC,CAAC;AAEP,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,2BAA2B,YAAE,6BAA6B,iBAAiB,GAAE;AAAA,QAC3F,oBAAC,OAAE,WAAU,iCACV,YAAE,mCAAmC,0CAA0C,GAClF;AAAA,SACF;AAAA,MACA,oBAAC,UAAO,MAAK,MAAK,SAAS,oBACxB,YAAE,sCAAsC,cAAc,GACzD;AAAA,OACF;AAAA,IAEC,mBACC,qBAAC,SAAI,WAAU,yDACb;AAAA,0BAAC,WAAQ,WAAU,WAAU;AAAA,MAC5B,EAAE,+BAA+B,yBAAoB;AAAA,OACxD,IACE,UAAU,WAAW,IACvB,oBAAC,OAAE,WAAU,iCACV,YAAE,6BAA6B,8CAA8C,GAChF,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,aAAW;AAAA,QACX,OAAO,sBAAsB;AAAA,QAC7B,eAAe,CAAC,SAAS,sBAAsB,QAAQ,IAAI;AAAA,QAC3D,WAAU;AAAA,QAET,oBAAU,IAAI,CAAC,aAAa;AAC3B,gBAAM,iBAAiB,OAAO,SAAS,EAAE,KAAK,CAAC;AAC/C,gBAAM,kBAAkB,cAAc,SAAS,EAAE,KAAK;AAEtD,iBACE,qBAAC,iBAAgC,OAAO,SAAS,IAC/C;AAAA,gCAAC,oBAAiB,aAAY,WAC5B,+BAAC,UAAK,WAAU,2BACd;AAAA,kCAAC,UAAK,WAAU,uBAAuB,mBAAS,MAAK;AAAA,cACpD,SAAS,YACR,oBAAC,UAAK,WAAU,+DACb,YAAE,oCAAoC,SAAS,GAClD,IACE;AAAA,eACN,GACF;AAAA,YACA,qBAAC,oBACC;AAAA,mCAAC,SAAI,WAAU,0CACb;AAAA,oCAAC,UAAK,WAAU,qEACb,YAAE,oCAAoC,QAAQ,GACjD;AAAA,gBACA,oBAAC,UAAO,MAAK,MAAK,SAAQ,WAAU,SAAS,MAAM,gBAAgB,SAAS,EAAE,GAC3E,YAAE,kCAAkC,WAAW,GAClD;AAAA,iBACF;AAAA,cAEC,kBACC,qBAAC,SAAI,WAAU,yDACb;AAAA,oCAAC,WAAQ,WAAU,WAAU;AAAA,gBAC5B,EAAE,sCAAsC,eAAU;AAAA,iBACrD,IACE,eAAe,WAAW,IAC5B,oBAAC,OAAE,WAAU,iCACV,YAAE,oCAAoC,gBAAgB,GACzD,IAEA,oBAAC,SAAI,WAAU,0DACZ,yBAAe,IAAI,CAAC,OAAO,QAC1B,qBAAC,SAAmB,WAAU,qDAC5B;AAAA,qCAAC,SAAI,WAAU,2BACb;AAAA,sCAAC,UAAK,WAAU,iDAAiD,gBAAM,GAAE;AAAA,kBACxE,MAAM,QAAQ,sBAAsB,MAAM,OAAO,sBAAsB,IAAI;AAAA,kBAC3E,MAAM,OAAO,qBAAqB,MAAM,MAAM,SAAS,IAAI;AAAA,kBAC5D,oBAAC,UAAK,WAAU,WAAW,gBAAM,OAAM;AAAA,mBACzC;AAAA,gBACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,UAAU,QAAQ;AAAA,sBAClB,SAAS,MAAM,KAAK,gBAAgB,OAAO,IAAI;AAAA,sBAC/C,OAAO,EAAE,qCAAqC,SAAS;AAAA,sBACxD;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,UAAU,QAAQ,eAAe,SAAS;AAAA,sBAC1C,SAAS,MAAM,KAAK,gBAAgB,OAAO,MAAM;AAAA,sBACjD,OAAO,EAAE,uCAAuC,WAAW;AAAA,sBAC5D;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,SAAS,MAAM,cAAc,KAAK;AAAA,sBAEjC,YAAE,mCAAmC,MAAM;AAAA;AAAA,kBAC9C;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS,MAAM,KAAK,kBAAkB,KAAK;AAAA,sBAE1C,YAAE,qCAAqC,QAAQ;AAAA;AAAA,kBAClD;AAAA,mBACF;AAAA,mBA3CQ,MAAM,EA4ChB,CACD,GACH;AAAA,cAGF,qBAAC,SAAI,WAAU,0DACb;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,SAAS,MAAM,iBAAiB,QAAQ;AAAA,oBAEvC,YAAE,oCAAoC,eAAe;AAAA;AAAA,gBACxD;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS,MAAM,KAAK,qBAAqB,QAAQ;AAAA,oBAEhD,YAAE,sCAAsC,iBAAiB;AAAA;AAAA,gBAC5D;AAAA,iBACF;AAAA,eACF;AAAA,eAnGkB,SAAS,EAoG7B;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,IAIF,oBAAC,UAAO,MAAM,mBAAmB,MAAM,cAAc,CAAC,SAAS;AAAE,UAAI,CAAC,KAAM,qBAAoB;AAAA,IAAE,GAChG,+BAAC,iBAAc,WAAW,cAAc,oBAAoB,GAC1D;AAAA,0BAAC,gBACC,8BAAC,eACE,0BAAgB,SAAS,WACtB,EAAE,0CAA0C,iBAAiB,IAC7D,EAAE,wCAAwC,eAAe,GAC/D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,kBACb;AAAA,6BAAC,SAAI,WAAU,aACb;AAAA,8BAAC,SAAM,SAAQ,iBAAiB,YAAE,iCAAiC,MAAM,GAAE;AAAA,UAC3E;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO,aAAa;AAAA,cACpB,UAAU,CAAC,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE;AAAA,cAC9E,aAAa,EAAE,4CAA4C,mBAAmB;AAAA,cAC9E,WAAS;AAAA;AAAA,UACX;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,SAAS,aAAa;AAAA,cACtB,iBAAiB,CAAC,YAAY,gBAAgB,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW,YAAY,KAAK,EAAE;AAAA;AAAA,UACpG;AAAA,UACA,oBAAC,SAAM,SAAQ,oBAAmB,WAAU,kBACzC,YAAE,sCAAsC,yBAAyB,GACpE;AAAA,WACF;AAAA,SACF;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,qBAAqB,UAAU,oBAC/D,YAAE,qCAAqC,QAAQ,GAClD;AAAA,QACA,qBAAC,UAAO,SAAS,MAAM,KAAK,qBAAqB,GAAG,UAAU,sBAAsB,CAAC,aAAa,KAAK,KAAK,GACzG;AAAA,+BAAqB,oBAAC,WAAQ,WAAU,gBAAe,IAAK;AAAA,UAC5D,EAAE,mCAAmC,MAAM;AAAA,WAC9C;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAEC;AAAA,IAGD,oBAAC,UAAO,MAAM,gBAAgB,MAAM,cAAc,CAAC,SAAS;AAAE,UAAI,CAAC,KAAM,kBAAiB;AAAA,IAAE,GAC1F,+BAAC,iBAAc,WAAW,cAAc,iBAAiB,GACvD;AAAA,0BAAC,gBACC,8BAAC,eACE,uBAAa,SAAS,WACnB,EAAE,+CAA+C,WAAW,IAC5D,EAAE,6CAA6C,YAAY,GACjE,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,kBACb;AAAA,6BAAC,SAAI,WAAU,aACb;AAAA,8BAAC,SAAM,SAAQ,eAAe,YAAE,uCAAuC,OAAO,GAAE;AAAA,UAChF;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO,UAAU;AAAA,cACjB,UAAU,CAAC,MAAM,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,cAC5E,aAAa,EAAE,kDAAkD,gBAAgB;AAAA,cACjF,WAAS;AAAA;AAAA,UACX;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,UAAU;AAAA,YACjB,MAAM,UAAU;AAAA,YAChB,eAAe,CAAC,SAAS,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,EAAE;AAAA,YAC1E,cAAc,CAAC,SAAS,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,KAAK,EAAE;AAAA,YACxE,QAAQ;AAAA;AAAA,QACV;AAAA,SACF;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,kBAAkB,UAAU,iBAC5D,YAAE,0CAA0C,QAAQ,GACvD;AAAA,QACA,qBAAC,UAAO,SAAS,MAAM,KAAK,kBAAkB,GAAG,UAAU,mBAAmB,CAAC,UAAU,MAAM,KAAK,GACjG;AAAA,4BAAkB,oBAAC,WAAQ,WAAU,gBAAe,IAAK;AAAA,UACzD,EAAE,wCAAwC,MAAM;AAAA,WACnD;AAAA,SACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ActivityTimeline.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Check, ListTodo, Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n task: ListTodo,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string) => void | Promise<void>\n}\n\nexport function ActivityTimeline({ activities, onEdit, onMarkDone }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n onMarkDone={onMarkDone}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n onMarkDone,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string) => void | Promise<void>\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n const isPlanned = activity.status === 'planned'\n const [markingDone, setMarkingDone] = React.useState(false)\n\n const handleMarkDone = React.useCallback(async (event: React.MouseEvent | React.KeyboardEvent) => {\n event.stopPropagation()\n if (!onMarkDone || markingDone) return\n setMarkingDone(true)\n try {\n await onMarkDone(activity.id)\n } finally {\n setMarkingDone(false)\n }\n }, [activity.id, markingDone, onMarkDone])\n\n return (\n <div\n className={`py-2.5 ${withBorder ? 'border-b border-border/60' : ''} ${onEdit ? 'cursor-pointer hover:bg-accent/40 transition-colors' : ''}`}\n onClick={() => onEdit?.(activity)}\n role={onEdit ? 'button' : undefined}\n tabIndex={onEdit ? 0 : undefined}\n onKeyDown={onEdit ? (e) => { if (e.key === 'Enter') onEdit(activity) } : undefined}\n >\n <div className=\"grid items-start gap-3\" style={{ gridTemplateColumns: '75px 32px 1fr' }}>\n {/* Column 1: Date */}\n <div className=\"shrink-0\">\n <span className=\"block text-[11px] font-semibold leading-tight text-foreground\">\n {formatRelativeDate(dateStr, t)}\n </span>\n <span className=\"block text-[10px] leading-tight text-muted-foreground\">\n {formatTime(dateStr)}\n </span>\n </div>\n\n {/* Column 2: Type icon */}\n <div className=\"flex size-8 items-center justify-center rounded-md bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-3.5 text-muted-foreground\" /> : null}\n </div>\n\n {/* Column 3: Content */}\n <div className=\"min-w-0 space-y-1.5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"block text-[12px] font-semibold leading-tight text-foreground\">\n {title}{duration}\n </span>\n {isPlanned && onMarkDone ? (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={markingDone}\n onClick={handleMarkDone}\n className=\"shrink-0\"\n >\n <Check className=\"size-3.5\" />\n {t('customers.activities.actions.markDone', 'Mark done')}\n </Button>\n ) : null}\n </div>\n\n {activity.body && activity.title && (\n <p className=\"text-[11px] leading-snug text-muted-foreground\">\n {activity.body}\n </p>\n )}\n\n {activity.authorName && (\n <div className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <User className=\"size-2.5 shrink-0\" />\n <span>{t('customers.timeline.author', 'by {{name}}', { name: activity.authorName })}</span>\n </div>\n )}\n\n <AiActionChips activityType={activity.interactionType} />\n </div>\n </div>\n </div>\n )\n}\n\nfunction formatRelativeDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n // Compare calendar dates (not time-based diff) to correctly handle same-day future times\n const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const diffDays = Math.round((nowDay.getTime() - dateDay.getTime()) / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return t('customers.timeline.date.today', 'today')\n if (diffDays === 1) return t('customers.timeline.date.yesterday', 'yesterday')\n return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n } catch {\n return ''\n }\n}\n\nfunction formatTime(isoString: string): string {\n try {\n return new Date(isoString).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n } catch {\n return ''\n }\n}\n"],
|
|
5
|
-
"mappings": ";AA4BM,cAkBQ,YAlBR;AA3BN,YAAY,WAAW;AACvB,SAAS,OAAO,UAAU,OAAO,MAAM,OAAO,YAAY,YAAY;AACtE,SAAS,YAAY;AAErB,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAG9B,MAAM,aAA0E;AAAA,EAC9E,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AACR;AAQO,SAAS,iBAAiB,EAAE,YAAY,QAAQ,WAAW,GAA0B;AAC1F,QAAM,IAAI,KAAK;AAEf,MAAI,WAAW,WAAW,GAAG;AAC3B,WACE,oBAAC,SAAI,WAAU,kDACZ,YAAE,4BAA4B,0CAA0C,GAC3E;AAAA,EAEJ;AAEA,SACE,oBAAC,SACE,qBAAW,IAAI,CAAC,UAAU,UAAU;AACnC,UAAM,UAAU,SAAS,eAAe,SAAS,cAAc,SAAS;AACxE,UAAM,eAAe,UAAU,IAAI,KAAK,OAAO,EAAE,YAAY,IAAI;AACjE,UAAM,cAAc,QAAQ,IAAK,WAAW,QAAQ,CAAC,EAAE,eAAe,WAAW,QAAQ,CAAC,EAAE,cAAc,WAAW,QAAQ,CAAC,EAAE,YAAa;AAC7I,UAAM,WAAW,cAAc,IAAI,KAAK,WAAW,EAAE,YAAY,IAAI;AACrE,UAAM,oBAAoB,iBAAiB,QAAQ,aAAa,QAAQ,iBAAiB;AAEzF,WACE,qBAAC,MAAM,UAAN,EACE;AAAA,2BACC,qBAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,SAAI,WAAU,yBAAwB;AAAA,QACvC,oBAAC,UAAK,WAAU,+CACb,YAAE,sCAAsC,UAAU,EAAE,MAAM,aAAa,CAAC,GAC3E;AAAA,QACA,oBAAC,SAAI,WAAU,yBAAwB;AAAA,SACzC;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,YAAY,QAAQ,WAAW,SAAS;AAAA,UACxC;AAAA,UACA;AAAA;AAAA,MACF;AAAA,SAhBmB,SAAS,EAiB9B;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,UAAU,SAAS,eAAe,SAAS,cAAc,SAAS;AACxE,QAAM,WAAW,WAAW,SAAS,eAAe;AACpD,QAAM,QAAQ,SAAS,SAAS,SAAS,QAAQ,SAAS;AAC1D,QAAM,WAAW,SAAS,WAAW,KAAK,SAAS,QAAQ,UAAU;AACrE,QAAM,YAAY,SAAS,WAAW;AACtC,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,KAAK;AAE1D,QAAM,iBAAiB,MAAM,YAAY,OAAO,UAAkD;AAChG,UAAM,gBAAgB;AACtB,QAAI,CAAC,cAAc,YAAa;AAChC,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,WAAW,SAAS,
|
|
4
|
+
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Check, ListTodo, Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n task: ListTodo,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>\n}\n\nexport function ActivityTimeline({ activities, onEdit, onMarkDone }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n onMarkDone={onMarkDone}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n onMarkDone,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n const isPlanned = activity.status === 'planned'\n const [markingDone, setMarkingDone] = React.useState(false)\n\n const handleMarkDone = React.useCallback(async (event: React.MouseEvent | React.KeyboardEvent) => {\n event.stopPropagation()\n if (!onMarkDone || markingDone) return\n setMarkingDone(true)\n try {\n await onMarkDone(activity.id, activity.updatedAt)\n } finally {\n setMarkingDone(false)\n }\n }, [activity.id, markingDone, onMarkDone])\n\n return (\n <div\n className={`py-2.5 ${withBorder ? 'border-b border-border/60' : ''} ${onEdit ? 'cursor-pointer hover:bg-accent/40 transition-colors' : ''}`}\n onClick={() => onEdit?.(activity)}\n role={onEdit ? 'button' : undefined}\n tabIndex={onEdit ? 0 : undefined}\n onKeyDown={onEdit ? (e) => { if (e.key === 'Enter') onEdit(activity) } : undefined}\n >\n <div className=\"grid items-start gap-3\" style={{ gridTemplateColumns: '75px 32px 1fr' }}>\n {/* Column 1: Date */}\n <div className=\"shrink-0\">\n <span className=\"block text-[11px] font-semibold leading-tight text-foreground\">\n {formatRelativeDate(dateStr, t)}\n </span>\n <span className=\"block text-[10px] leading-tight text-muted-foreground\">\n {formatTime(dateStr)}\n </span>\n </div>\n\n {/* Column 2: Type icon */}\n <div className=\"flex size-8 items-center justify-center rounded-md bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-3.5 text-muted-foreground\" /> : null}\n </div>\n\n {/* Column 3: Content */}\n <div className=\"min-w-0 space-y-1.5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"block text-[12px] font-semibold leading-tight text-foreground\">\n {title}{duration}\n </span>\n {isPlanned && onMarkDone ? (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={markingDone}\n onClick={handleMarkDone}\n className=\"shrink-0\"\n >\n <Check className=\"size-3.5\" />\n {t('customers.activities.actions.markDone', 'Mark done')}\n </Button>\n ) : null}\n </div>\n\n {activity.body && activity.title && (\n <p className=\"text-[11px] leading-snug text-muted-foreground\">\n {activity.body}\n </p>\n )}\n\n {activity.authorName && (\n <div className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <User className=\"size-2.5 shrink-0\" />\n <span>{t('customers.timeline.author', 'by {{name}}', { name: activity.authorName })}</span>\n </div>\n )}\n\n <AiActionChips activityType={activity.interactionType} />\n </div>\n </div>\n </div>\n )\n}\n\nfunction formatRelativeDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n // Compare calendar dates (not time-based diff) to correctly handle same-day future times\n const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const diffDays = Math.round((nowDay.getTime() - dateDay.getTime()) / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return t('customers.timeline.date.today', 'today')\n if (diffDays === 1) return t('customers.timeline.date.yesterday', 'yesterday')\n return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n } catch {\n return ''\n }\n}\n\nfunction formatTime(isoString: string): string {\n try {\n return new Date(isoString).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n } catch {\n return ''\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -56,6 +56,7 @@ function AddressesSection({
|
|
|
56
56
|
const response = await apiCallOrThrow(
|
|
57
57
|
"/api/customers/addresses",
|
|
58
58
|
{
|
|
59
|
+
// optimistic-lock-exempt: address link add/remove sub-resource
|
|
59
60
|
method: "POST",
|
|
60
61
|
headers: { "content-type": "application/json" },
|
|
61
62
|
body: JSON.stringify({
|
|
@@ -72,6 +73,7 @@ function AddressesSection({
|
|
|
72
73
|
await apiCallOrThrow(
|
|
73
74
|
"/api/customers/addresses",
|
|
74
75
|
{
|
|
76
|
+
// optimistic-lock-exempt: address link add/remove sub-resource
|
|
75
77
|
method: "PUT",
|
|
76
78
|
headers: { "content-type": "application/json" },
|
|
77
79
|
body: JSON.stringify({
|
|
@@ -87,6 +89,7 @@ function AddressesSection({
|
|
|
87
89
|
await apiCallOrThrow(
|
|
88
90
|
"/api/customers/addresses",
|
|
89
91
|
{
|
|
92
|
+
// optimistic-lock-exempt: address link add/remove sub-resource
|
|
90
93
|
method: "DELETE",
|
|
91
94
|
headers: { "content-type": "application/json" },
|
|
92
95
|
body: JSON.stringify({ id })
|
|
@@ -116,6 +119,7 @@ function AddressesSection({
|
|
|
116
119
|
const response = await apiCallOrThrow(
|
|
117
120
|
"/api/customers/dictionaries/address-types",
|
|
118
121
|
{
|
|
122
|
+
// optimistic-lock-exempt: address-type dictionary create-only
|
|
119
123
|
method: "POST",
|
|
120
124
|
headers: { "content-type": "application/json" },
|
|
121
125
|
body: JSON.stringify({ value })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/AddressesSection.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'\nimport type { AddressDataAdapter, AddressTypesAdapter, AddressFormatStrategy, SectionAction } from '@open-mercato/ui/backend/detail'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type AddressesSectionProps = {\n entityId: string | null\n emptyLabel: string\n addActionLabel: string\n emptyState: { title: string; actionLabel: string; description?: string }\n onActionChange?: (action: SectionAction | null) => void\n translator?: (key: string, fallback?: string, params?: Record<string, string | number>) => string\n onLoadingChange?: (isLoading: boolean) => void\n}\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function AddressesSection({\n entityId,\n emptyLabel,\n addActionLabel,\n emptyState,\n onActionChange,\n translator,\n onLoadingChange,\n}: AddressesSectionProps) {\n const tHook = useT()\n const fallbackTranslator = React.useMemo(() => createTranslatorWithFallback(tHook), [tHook])\n const t = translator ?? fallbackTranslator\n\n const dataAdapter = React.useMemo<AddressDataAdapter>(() => ({\n list: async ({ entityId: listEntityId }) => {\n if (!listEntityId) return []\n const params = new URLSearchParams({ entityId: listEntityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/customers/addresses?${params.toString()}`,\n undefined,\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId: targetId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/addresses',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: targetId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n id,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n delete: async ({ id }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n }), [t])\n\n const addressTypesAdapter = React.useMemo<AddressTypesAdapter>(() => ({\n list: async () => {\n const call = await apiCall<Record<string, unknown>>('/api/customers/dictionaries/address-types', {\n method: 'GET',\n })\n const payload = call.result ?? {}\n const rawItems = (payload as { items?: unknown[] }).items\n const items = Array.isArray(rawItems) ? rawItems : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const value = typeof record.value === 'string' ? record.value : null\n if (!value) return null\n const label = typeof record.label === 'string' && record.label.trim().length ? record.label : value\n return { value, label }\n })\n .filter((entry): entry is { value: string; label: string } => !!entry)\n },\n create: async (value: string) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/address-types',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ value }),\n },\n { errorMessage: t('customers.people.detail.addresses.types.saveError', 'Failed to save address type') },\n )\n const payload = response.result ?? {}\n const createdValue = typeof payload.value === 'string' ? payload.value : value\n const label = typeof payload.label === 'string' && payload.label.trim().length ? payload.label : createdValue\n return { value: createdValue, label }\n },\n manageHref: '/backend/config/customers',\n }), [t])\n\n const loadFormat = React.useCallback(async (): Promise<AddressFormatStrategy> => {\n const call = await apiCall<{ addressFormat?: string; error?: string }>(\n '/api/customers/settings/address-format',\n )\n const payload = (call.result ?? {}) as Record<string, unknown>\n if (!call.ok) {\n const message =\n typeof (payload as Record<string, unknown>)?.error === 'string'\n ? (payload as Record<string, unknown>).error as string\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n throw new Error(message)\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (value === 'street_first' || value === 'line_first') {\n return value\n }\n return 'line_first'\n }, [t])\n\n return (\n <SharedAddressesSection\n entityId={entityId}\n emptyLabel={emptyLabel}\n addActionLabel={addActionLabel}\n emptyState={emptyState}\n onActionChange={onActionChange}\n onLoadingChange={onLoadingChange}\n translator={t}\n dataAdapter={dataAdapter}\n addressTypesAdapter={addressTypesAdapter}\n loadFormat={loadFormat}\n />\n )\n}\n\nexport default AddressesSection\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'\nimport type { AddressDataAdapter, AddressTypesAdapter, AddressFormatStrategy, SectionAction } from '@open-mercato/ui/backend/detail'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type AddressesSectionProps = {\n entityId: string | null\n emptyLabel: string\n addActionLabel: string\n emptyState: { title: string; actionLabel: string; description?: string }\n onActionChange?: (action: SectionAction | null) => void\n translator?: (key: string, fallback?: string, params?: Record<string, string | number>) => string\n onLoadingChange?: (isLoading: boolean) => void\n}\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function AddressesSection({\n entityId,\n emptyLabel,\n addActionLabel,\n emptyState,\n onActionChange,\n translator,\n onLoadingChange,\n}: AddressesSectionProps) {\n const tHook = useT()\n const fallbackTranslator = React.useMemo(() => createTranslatorWithFallback(tHook), [tHook])\n const t = translator ?? fallbackTranslator\n\n const dataAdapter = React.useMemo<AddressDataAdapter>(() => ({\n list: async ({ entityId: listEntityId }) => {\n if (!listEntityId) return []\n const params = new URLSearchParams({ entityId: listEntityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/customers/addresses?${params.toString()}`,\n undefined,\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId: targetId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: targetId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n id,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n delete: async ({ id }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n }), [t])\n\n const addressTypesAdapter = React.useMemo<AddressTypesAdapter>(() => ({\n list: async () => {\n const call = await apiCall<Record<string, unknown>>('/api/customers/dictionaries/address-types', {\n method: 'GET',\n })\n const payload = call.result ?? {}\n const rawItems = (payload as { items?: unknown[] }).items\n const items = Array.isArray(rawItems) ? rawItems : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const value = typeof record.value === 'string' ? record.value : null\n if (!value) return null\n const label = typeof record.label === 'string' && record.label.trim().length ? record.label : value\n return { value, label }\n })\n .filter((entry): entry is { value: string; label: string } => !!entry)\n },\n create: async (value: string) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/address-types',\n {\n // optimistic-lock-exempt: address-type dictionary create-only\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ value }),\n },\n { errorMessage: t('customers.people.detail.addresses.types.saveError', 'Failed to save address type') },\n )\n const payload = response.result ?? {}\n const createdValue = typeof payload.value === 'string' ? payload.value : value\n const label = typeof payload.label === 'string' && payload.label.trim().length ? payload.label : createdValue\n return { value: createdValue, label }\n },\n manageHref: '/backend/config/customers',\n }), [t])\n\n const loadFormat = React.useCallback(async (): Promise<AddressFormatStrategy> => {\n const call = await apiCall<{ addressFormat?: string; error?: string }>(\n '/api/customers/settings/address-format',\n )\n const payload = (call.result ?? {}) as Record<string, unknown>\n if (!call.ok) {\n const message =\n typeof (payload as Record<string, unknown>)?.error === 'string'\n ? (payload as Record<string, unknown>).error as string\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n throw new Error(message)\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (value === 'street_first' || value === 'line_first') {\n return value\n }\n return 'line_first'\n }, [t])\n\n return (\n <SharedAddressesSection\n entityId={entityId}\n emptyLabel={emptyLabel}\n addActionLabel={addActionLabel}\n emptyState={emptyState}\n onActionChange={onActionChange}\n onLoadingChange={onLoadingChange}\n translator={t}\n dataAdapter={dataAdapter}\n addressTypesAdapter={addressTypesAdapter}\n loadFormat={loadFormat}\n />\n )\n}\n\nexport default AddressesSection\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|