@open-mercato/core 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js +18 -18
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/create/page.js +1 -1
- package/dist/modules/api_keys/backend/api-keys/create/page.js.map +1 -1
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +1 -1
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +1 -1
- package/dist/modules/attachments/fields/attachment.js +1 -1
- package/dist/modules/attachments/fields/attachment.js.map +1 -1
- package/dist/modules/audit_logs/components/ActionLogDetailsDialog.js +1 -1
- package/dist/modules/audit_logs/components/ActionLogDetailsDialog.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +1 -1
- package/dist/modules/audit_logs/lib/display-helpers.js.map +1 -1
- package/dist/modules/auth/backend/users/create/page.js +1 -1
- package/dist/modules/auth/backend/users/create/page.js.map +1 -1
- package/dist/modules/business_rules/backend/rules/page.js +6 -6
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +2 -2
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/components/ActionBuilder.js +5 -5
- package/dist/modules/business_rules/components/ActionBuilder.js.map +2 -2
- package/dist/modules/business_rules/components/ActionRow.js +8 -8
- package/dist/modules/business_rules/components/ActionRow.js.map +1 -1
- package/dist/modules/business_rules/components/ConditionBuilder.js +5 -5
- package/dist/modules/business_rules/components/ConditionBuilder.js.map +2 -2
- package/dist/modules/business_rules/components/ConditionGroup.js +2 -2
- package/dist/modules/business_rules/components/ConditionGroup.js.map +1 -1
- package/dist/modules/business_rules/components/ConditionRow.js +3 -3
- package/dist/modules/business_rules/components/ConditionRow.js.map +2 -2
- package/dist/modules/business_rules/components/RuleSetMembers.js +8 -8
- package/dist/modules/business_rules/components/RuleSetMembers.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +1 -1
- package/dist/modules/catalog/backend/catalog/products/create/page.js +5 -5
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +1 -1
- package/dist/modules/catalog/components/products/MetadataEditor.js +1 -1
- package/dist/modules/catalog/components/products/MetadataEditor.js.map +1 -1
- package/dist/modules/catalog/components/products/ProductImageCell.js +1 -1
- package/dist/modules/catalog/components/products/ProductImageCell.js.map +1 -1
- package/dist/modules/catalog/components/products/VariantBuilder.js +1 -1
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +1 -1
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +1 -1
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +1 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +9 -9
- 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 +7 -7
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +1 -1
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +3 -3
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +1 -1
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +1 -1
- package/dist/modules/customers/components/AddressTiles.js +1 -1
- package/dist/modules/customers/components/AddressTiles.js.map +1 -1
- package/dist/modules/customers/components/detail/ActivityForm.js +3 -3
- package/dist/modules/customers/components/detail/ActivityForm.js.map +1 -1
- package/dist/modules/customers/components/detail/AnnualRevenueField.js +2 -2
- package/dist/modules/customers/components/detail/AnnualRevenueField.js.map +1 -1
- package/dist/modules/customers/components/detail/CustomFieldValuesList.js +1 -1
- package/dist/modules/customers/components/detail/CustomFieldValuesList.js.map +1 -1
- package/dist/modules/customers/components/detail/DealForm.js +1 -1
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +1 -1
- package/dist/modules/customers/components/detail/DealsSection.js.map +1 -1
- package/dist/modules/customers/components/detail/DetailFieldsSection.js +1 -1
- package/dist/modules/customers/components/detail/DetailFieldsSection.js.map +1 -1
- package/dist/modules/customers/components/detail/InlineEditors.js +5 -5
- package/dist/modules/customers/components/detail/InlineEditors.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +1 -1
- package/dist/modules/customers/components/detail/TasksSection.js.map +1 -1
- package/dist/modules/customers/components/detail/TimelineItemHeader.js +1 -1
- package/dist/modules/customers/components/detail/TimelineItemHeader.js.map +1 -1
- package/dist/modules/customers/components/formConfig.js +2 -2
- package/dist/modules/customers/components/formConfig.js.map +1 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +1 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +1 -1
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js.map +1 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js +1 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js.map +1 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js +1 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js.map +1 -1
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +1 -1
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +1 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +1 -1
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +1 -1
- package/dist/modules/data_sync/backend/data-sync/page.js +4 -4
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +1 -1
- package/dist/modules/dictionaries/components/AppearanceSelector.js +3 -3
- package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +4 -4
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +3 -3
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +1 -1
- package/dist/modules/dictionaries/fields/dictionary.js +4 -4
- package/dist/modules/dictionaries/fields/dictionary.js.map +1 -1
- package/dist/modules/entities/components/EncryptionManager.js +3 -3
- package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js +1 -1
- package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/formConfig.js +1 -1
- package/dist/modules/feature_toggles/components/formConfig.js.map +1 -1
- package/dist/modules/feature_toggles/components/overrideFormConfig.js +2 -2
- package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +1 -1
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +12 -12
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/messages/InboxEmailPreview.js +1 -1
- package/dist/modules/inbox_ops/components/messages/InboxEmailPreview.js.map +1 -1
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js +12 -12
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js.map +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js +3 -3
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +6 -6
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +1 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +1 -1
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +1 -1
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +1 -1
- package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +1 -1
- package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +1 -1
- package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +1 -1
- package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +1 -1
- package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +1 -1
- package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +1 -1
- package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +1 -1
- package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +1 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +11 -11
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +4 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +4 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +1 -1
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +1 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +4 -4
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +1 -1
- package/dist/modules/sales/components/DocumentNumberSettings.js +1 -1
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +1 -1
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +1 -1
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +1 -1
- package/dist/modules/sales/components/documents/AdjustmentDialog.js +1 -1
- package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +1 -1
- package/dist/modules/sales/components/documents/DocumentTotals.js +3 -3
- package/dist/modules/sales/components/documents/DocumentTotals.js.map +1 -1
- package/dist/modules/sales/components/documents/PaymentDialog.js +1 -1
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +1 -1
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +4 -4
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +1 -1
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +4 -4
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +1 -1
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js +2 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js +1 -1
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js.map +1 -1
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +1 -1
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +1 -1
- package/dist/modules/translations/components/TranslationDrawerAction.js +2 -2
- package/dist/modules/translations/components/TranslationDrawerAction.js.map +1 -1
- package/dist/modules/translations/components/TranslationManager.js +3 -3
- package/dist/modules/translations/components/TranslationManager.js.map +1 -1
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +1 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.js +5 -5
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.js +4 -4
- package/dist/modules/workflows/backend/events/[id]/page.js.map +1 -1
- package/dist/modules/workflows/backend/instances/[id]/page.js +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.js.map +1 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js +20 -20
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -1
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +1 -1
- package/dist/modules/workflows/components/EdgeEditDialog.js +12 -12
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +1 -1
- package/dist/modules/workflows/components/NodeEditDialog.js +26 -26
- package/dist/modules/workflows/components/NodeEditDialog.js.map +1 -1
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +1 -1
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +1 -1
- package/dist/modules/workflows/components/mobile/MobileDefinitionDetail.js +2 -2
- package/dist/modules/workflows/components/mobile/MobileDefinitionDetail.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileInstanceOverview.js +7 -7
- package/dist/modules/workflows/components/mobile/MobileInstanceOverview.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js +11 -11
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileVisualEditor.js +1 -1
- package/dist/modules/workflows/components/mobile/MobileVisualEditor.js.map +1 -1
- package/dist/modules/workflows/components/mobile/MobileWorkflowTimeline.js +23 -23
- package/dist/modules/workflows/components/mobile/MobileWorkflowTimeline.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +6 -6
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +1 -1
- package/package.json +3 -3
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +18 -18
- package/src/modules/api_keys/backend/api-keys/create/page.tsx +1 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -3
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +1 -1
- package/src/modules/attachments/fields/attachment.tsx +1 -1
- package/src/modules/audit_logs/components/ActionLogDetailsDialog.tsx +1 -1
- package/src/modules/audit_logs/lib/display-helpers.tsx +1 -1
- package/src/modules/auth/backend/users/create/page.tsx +1 -1
- package/src/modules/business_rules/backend/rules/page.tsx +7 -7
- package/src/modules/business_rules/backend/sets/page.tsx +3 -3
- package/src/modules/business_rules/components/ActionBuilder.tsx +6 -6
- package/src/modules/business_rules/components/ActionRow.tsx +8 -8
- package/src/modules/business_rules/components/ConditionBuilder.tsx +6 -6
- package/src/modules/business_rules/components/ConditionGroup.tsx +2 -2
- package/src/modules/business_rules/components/ConditionRow.tsx +3 -3
- package/src/modules/business_rules/components/RuleSetMembers.tsx +9 -9
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2 -2
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +5 -5
- package/src/modules/catalog/components/products/MetadataEditor.tsx +1 -1
- package/src/modules/catalog/components/products/ProductImageCell.tsx +1 -1
- package/src/modules/catalog/components/products/VariantBuilder.tsx +1 -1
- package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +1 -1
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +2 -2
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +10 -10
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +9 -9
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -2
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +3 -3
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +2 -2
- package/src/modules/customers/components/AddressTiles.tsx +1 -1
- package/src/modules/customers/components/detail/ActivityForm.tsx +3 -3
- package/src/modules/customers/components/detail/AnnualRevenueField.tsx +2 -2
- package/src/modules/customers/components/detail/CustomFieldValuesList.tsx +1 -1
- package/src/modules/customers/components/detail/DealForm.tsx +1 -1
- package/src/modules/customers/components/detail/DealsSection.tsx +1 -1
- package/src/modules/customers/components/detail/DetailFieldsSection.tsx +1 -1
- package/src/modules/customers/components/detail/InlineEditors.tsx +5 -5
- package/src/modules/customers/components/detail/TasksSection.tsx +1 -1
- package/src/modules/customers/components/detail/TimelineItemHeader.tsx +1 -1
- package/src/modules/customers/components/formConfig.tsx +2 -2
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +1 -1
- package/src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx +2 -2
- package/src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx +1 -1
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx +1 -1
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +2 -2
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +1 -1
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +2 -2
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -4
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +2 -2
- package/src/modules/dictionaries/components/AppearanceSelector.tsx +3 -3
- package/src/modules/dictionaries/components/DictionariesManager.tsx +4 -4
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -2
- package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +3 -3
- package/src/modules/dictionaries/fields/dictionary.tsx +4 -4
- package/src/modules/entities/components/EncryptionManager.tsx +3 -3
- package/src/modules/entities/components/UserEntitiesTable.tsx +1 -1
- package/src/modules/feature_toggles/components/formConfig.tsx +1 -1
- package/src/modules/feature_toggles/components/overrideFormConfig.tsx +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +12 -12
- package/src/modules/inbox_ops/components/messages/InboxEmailPreview.tsx +1 -1
- package/src/modules/inbox_ops/components/proposals/ActionCard.tsx +12 -12
- package/src/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.tsx +4 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +6 -6
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +1 -1
- package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +1 -1
- package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +1 -1
- package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +1 -1
- package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +1 -1
- package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +1 -1
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +11 -11
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +2 -2
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +2 -2
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +4 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +4 -4
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +1 -1
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +4 -4
- package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -1
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +1 -1
- package/src/modules/sales/components/documents/AdjustmentDialog.tsx +1 -1
- package/src/modules/sales/components/documents/DocumentTotals.tsx +3 -3
- package/src/modules/sales/components/documents/PaymentDialog.tsx +1 -1
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +2 -2
- package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +4 -4
- package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +4 -4
- package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +2 -2
- package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +1 -1
- package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
- package/src/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.tsx +1 -1
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +1 -1
- package/src/modules/translations/components/TranslationDrawerAction.tsx +2 -2
- package/src/modules/translations/components/TranslationManager.tsx +3 -3
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +2 -2
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +5 -5
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +2 -2
- package/src/modules/workflows/backend/events/[id]/page.tsx +4 -4
- package/src/modules/workflows/backend/instances/[id]/page.tsx +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +23 -23
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/components/EdgeEditDialog.tsx +12 -12
- package/src/modules/workflows/components/NodeEditDialog.tsx +26 -26
- package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +1 -1
- package/src/modules/workflows/components/mobile/MobileDefinitionDetail.tsx +2 -2
- package/src/modules/workflows/components/mobile/MobileInstanceOverview.tsx +7 -7
- package/src/modules/workflows/components/mobile/MobileTaskForm.tsx +14 -14
- package/src/modules/workflows/components/mobile/MobileVisualEditor.tsx +1 -1
- package/src/modules/workflows/components/mobile/MobileWorkflowTimeline.tsx +23 -23
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +6 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/components/AddressTiles.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Loader2, Pencil, Plus, Trash2, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { AddressView, formatAddressJson, formatAddressString, type AddressFormatStrategy } from '../utils/addressFormat'\nimport AddressEditor from './AddressEditor'\nimport { useAddressTypes } from './detail/hooks/useAddressTypes'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@open-mercato/ui/primitives/dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ensureCustomerDictionary, invalidateCustomerDictionary } from './detail/hooks/useCustomerDictionary'\n\nexport type Translator = (\n key: string,\n fallback?: string,\n params?: Record<string, string | number>,\n) => string\n\nexport type CustomerAddressInput = {\n name?: string\n purpose?: string\n companyName?: string\n addressLine1: string\n addressLine2?: string\n buildingNumber?: string\n flatNumber?: string\n city?: string\n region?: string\n postalCode?: string\n country?: string\n isPrimary?: boolean\n}\n\nexport type CustomerAddressValue = CustomerAddressInput & {\n id: string\n purpose?: string | null\n companyName?: string | null\n}\n\ntype CustomerAddressTilesProps = {\n addresses: CustomerAddressValue[]\n onCreate: (payload: CustomerAddressInput) => Promise<void> | void\n onUpdate?: (id: string, payload: CustomerAddressInput) => Promise<void> | void\n onDelete?: (id: string) => Promise<void> | void\n t: Translator\n emptyLabel: string\n isSubmitting?: boolean\n gridClassName?: string\n hideAddButton?: boolean\n onAddActionChange?: (action: { openCreateForm: () => void; addDisabled: boolean } | null) => void\n emptyStateTitle?: string\n emptyStateActionLabel?: string\n}\n\ntype DraftAddressState = {\n name: string\n purpose: string\n companyName: string\n addressLine1: string\n addressLine2: string\n buildingNumber: string\n flatNumber: string\n city: string\n region: string\n postalCode: string\n country: string\n isPrimary: boolean\n}\n\ntype DraftFieldKey = keyof DraftAddressState\n\ntype AddressValidationDetail = {\n path?: Array<string | number>\n code?: string\n message?: string\n minimum?: number\n maximum?: number\n type?: string\n}\n\nconst defaultDraft: DraftAddressState = {\n name: '',\n purpose: '',\n companyName: '',\n addressLine1: '',\n addressLine2: '',\n buildingNumber: '',\n flatNumber: '',\n city: '',\n region: '',\n postalCode: '',\n country: '',\n isPrimary: false,\n}\n\nconst serverFieldMap: Record<string, DraftFieldKey> = {\n name: 'name',\n purpose: 'purpose',\n companyName: 'companyName',\n addressLine1: 'addressLine1',\n addressLine2: 'addressLine2',\n buildingNumber: 'buildingNumber',\n flatNumber: 'flatNumber',\n city: 'city',\n region: 'region',\n postalCode: 'postalCode',\n country: 'country',\n isPrimary: 'isPrimary',\n}\n\nfunction normalizeOptional(value: string): string | undefined {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : undefined\n}\n\nfunction extractValidationDetails(error: unknown): AddressValidationDetail[] {\n if (!error || typeof error !== 'object') return []\n const candidate = (error as { details?: unknown }).details\n if (!Array.isArray(candidate)) return []\n return candidate\n .map((entry) => (entry && typeof entry === 'object' ? (entry as AddressValidationDetail) : null))\n .filter((entry): entry is AddressValidationDetail => entry !== null)\n}\n\nfunction resolveFieldMessage(detail: AddressValidationDetail, fieldLabel: string, t: Translator): string {\n switch (detail.code) {\n case 'invalid_type':\n return t('customers.people.detail.addresses.validation.invalid', undefined, { field: fieldLabel })\n case 'too_small':\n if (detail.minimum === 1 && detail.type === 'string') {\n return t('customers.people.detail.addresses.validation.required', undefined, { field: fieldLabel })\n }\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n case 'too_big':\n if (typeof detail.maximum === 'number') {\n return t(\n 'customers.people.detail.addresses.validation.tooLong',\n undefined,\n {\n field: fieldLabel,\n max: detail.maximum,\n }\n )\n }\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n default:\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n }\n}\n\nexport function CustomerAddressTiles({\n addresses,\n onCreate,\n onUpdate,\n onDelete,\n t,\n emptyLabel,\n isSubmitting = false,\n gridClassName = 'grid gap-4 min-[480px]:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4',\n hideAddButton = false,\n onAddActionChange,\n emptyStateTitle,\n emptyStateActionLabel,\n}: CustomerAddressTilesProps) {\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const [isFormOpen, setIsFormOpen] = React.useState(false)\n const [editingId, setEditingId] = React.useState<string | null>(null)\n const [draft, setDraft] = React.useState<DraftAddressState>(defaultDraft)\n const [saving, setSaving] = React.useState(false)\n const [deletingId, setDeletingId] = React.useState<string | null>(null)\n const [generalError, setGeneralError] = React.useState<string | null>(null)\n const [fieldErrors, setFieldErrors] = React.useState<Partial<Record<DraftFieldKey, string>>>({})\n const [format, setFormat] = React.useState<AddressFormatStrategy>('line_first')\n const [formatLoading, setFormatLoading] = React.useState(false)\n const { map: addressTypeMap } = useAddressTypes(t)\n\n const fieldLabels = React.useMemo(\n () => ({\n name: t('customers.people.detail.addresses.fields.label'),\n purpose: t('customers.people.detail.addresses.fields.type'),\n companyName: t('customers.people.detail.addresses.fields.companyName', 'Company name'),\n addressLine1: t('customers.people.detail.addresses.fields.line1'),\n addressLine2: t('customers.people.detail.addresses.fields.line2'),\n street: t('customers.people.detail.addresses.fields.street', 'Street'),\n buildingNumber: t('customers.people.detail.addresses.fields.buildingNumber', 'Building number'),\n flatNumber: t('customers.people.detail.addresses.fields.flatNumber', 'Flat number'),\n city: t('customers.people.detail.addresses.fields.city'),\n region: t('customers.people.detail.addresses.fields.region'),\n postalCode: t('customers.people.detail.addresses.fields.postalCode'),\n country: t('customers.people.detail.addresses.fields.country'),\n isPrimary: t('customers.people.detail.addresses.fields.primary'),\n }),\n [t]\n )\n const line1FieldLabel = React.useMemo(\n () => (format === 'street_first' ? fieldLabels.street : fieldLabels.addressLine1),\n [fieldLabels.addressLine1, fieldLabels.street, format],\n )\n\n\n\n const resetForm = React.useCallback(() => {\n setDraft(defaultDraft)\n setFieldErrors({})\n setGeneralError(null)\n setEditingId(null)\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadFormat() {\n setFormatLoading(true)\n try {\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 if (!cancelled) {\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 flash(message, 'error')\n }\n return\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (!cancelled && (value === 'street_first' || value === 'line_first')) {\n setFormat(value)\n }\n } catch (err) {\n if (!cancelled) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setFormatLoading(false)\n }\n }\n loadFormat().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, t])\n\n\n const openCreateForm = React.useCallback(() => {\n resetForm()\n setIsFormOpen(true)\n }, [resetForm])\n\n const openEditForm = React.useCallback(\n (address: CustomerAddressValue) => {\n setDraft({\n name: address.name ?? '',\n purpose: address.purpose ?? '',\n companyName: address.companyName ?? '',\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2 ?? '',\n buildingNumber: address.buildingNumber ?? '',\n flatNumber: address.flatNumber ?? '',\n city: address.city ?? '',\n region: address.region ?? '',\n postalCode: address.postalCode ?? '',\n country: address.country ? address.country.toUpperCase() : '',\n isPrimary: address.isPrimary ?? false,\n })\n setFieldErrors({})\n setGeneralError(null)\n setEditingId(address.id)\n setIsFormOpen(true)\n },\n []\n )\n\n const handleCancel = React.useCallback(() => {\n setIsFormOpen(false)\n resetForm()\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n const trimmedLine1 = draft.addressLine1.trim()\n if (!trimmedLine1.length) {\n const message = t(\n 'customers.people.detail.addresses.validation.required',\n undefined,\n { field: line1FieldLabel }\n )\n setFieldErrors((prev) => ({ ...prev, addressLine1: message }))\n setGeneralError(message)\n return\n }\n\n const payload: CustomerAddressInput = {\n addressLine1: trimmedLine1,\n isPrimary: draft.isPrimary,\n }\n\n const purpose = normalizeOptional(draft.purpose)\n if (purpose !== undefined) payload.purpose = purpose\n const name = normalizeOptional(draft.name)\n if (name !== undefined) payload.name = name\n const companyName = normalizeOptional(draft.companyName)\n if (companyName !== undefined) payload.companyName = companyName\n const line2 = normalizeOptional(draft.addressLine2)\n if (line2 !== undefined) payload.addressLine2 = line2\n const buildingNumber = normalizeOptional(draft.buildingNumber)\n if (buildingNumber !== undefined) payload.buildingNumber = buildingNumber\n const flatNumber = normalizeOptional(draft.flatNumber)\n if (flatNumber !== undefined) payload.flatNumber = flatNumber\n const city = normalizeOptional(draft.city)\n if (city !== undefined) payload.city = city\n const region = normalizeOptional(draft.region)\n if (region !== undefined) payload.region = region\n const postal = normalizeOptional(draft.postalCode)\n if (postal !== undefined) payload.postalCode = postal\n const country = normalizeOptional(draft.country)\n if (country !== undefined) payload.country = country.toUpperCase()\n\n setSaving(true)\n setGeneralError(null)\n setFieldErrors({})\n try {\n if (editingId && onUpdate) await onUpdate(editingId, payload)\n else await onCreate(payload)\n resetForm()\n setIsFormOpen(false)\n } catch (err) {\n const details = extractValidationDetails(err)\n if (details.length) {\n const nextErrors: Partial<Record<DraftFieldKey, string>> = {}\n for (const detail of details) {\n const path = Array.isArray(detail.path) ? detail.path : []\n const targetKey = path.length ? serverFieldMap[String(path[0])] : undefined\n if (!targetKey) continue\n const message = resolveFieldMessage(\n detail,\n targetKey === 'addressLine1' ? line1FieldLabel : fieldLabels[targetKey],\n t,\n )\n if (message) nextErrors[targetKey] = message\n }\n if (Object.keys(nextErrors).length) {\n setFieldErrors(nextErrors)\n setGeneralError(Object.values(nextErrors)[0] ?? null)\n setSaving(false)\n return\n }\n }\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.error')\n setGeneralError(message)\n flash(message, 'error')\n } finally {\n setSaving(false)\n }\n }, [draft, editingId, fieldLabels, line1FieldLabel, onCreate, onUpdate, resetForm, t])\n\n const handleDelete = React.useCallback(\n async (id: string) => {\n if (!onDelete) return\n setDeletingId(id)\n try {\n await onDelete(id)\n if (editingId === id) {\n resetForm()\n setIsFormOpen(false)\n }\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.error')\n flash(message, 'error')\n } finally {\n setDeletingId(null)\n }\n },\n [editingId, onDelete, resetForm, t]\n )\n\n const disableActions = saving || isSubmitting || deletingId !== null\n const isEditing = editingId !== null\n const addDisabled = disableActions || isEditing\n const hasAddresses = addresses.length > 0\n const emptyTitle = emptyStateTitle ?? emptyLabel\n const emptyActionLabel = emptyStateActionLabel ?? t('customers.people.detail.addresses.add')\n\n React.useEffect(() => {\n if (!onAddActionChange) return\n onAddActionChange({ openCreateForm, addDisabled })\n }, [onAddActionChange, openCreateForm, addDisabled])\n\n React.useEffect(\n () => () => {\n if (onAddActionChange) onAddActionChange(null)\n },\n [onAddActionChange]\n )\n\n const renderFormTile = React.useCallback(\n (key: string) => (\n <div\n key={key}\n className=\"rounded-lg border-2 border-dashed border-muted-foreground/50 bg-muted/20 p-4 text-sm\"\n onKeyDown={(event) => {\n if (!(event.metaKey || event.ctrlKey)) return\n if (event.key !== 'Enter') return\n event.preventDefault()\n if (disableActions) return\n void handleSave()\n }}\n >\n <div className=\"flex items-center justify-between text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n <span>\n {editingId\n ? t('customers.people.detail.addresses.editTitle')\n : t('customers.people.detail.addresses.addTitle')}\n </span>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" onClick={handleCancel} disabled={disableActions}>\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n <div className=\"mt-3 space-y-3\">\n {formatLoading ? (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.detail.addresses.formatLoading', 'Loading address preferences\u2026')}\n </p>\n ) : null}\n <AddressEditor\n value={draft}\n onChange={(next) => {\n setDraft(next)\n if (Object.keys(fieldErrors).length) {\n const nextErrors = { ...fieldErrors }\n ;(Object.keys(nextErrors) as DraftFieldKey[]).forEach((key) => {\n const candidate = (next as Record<string, unknown>)[key]\n if (candidate !== undefined && candidate !== null && `${candidate}`.length) {\n delete nextErrors[key]\n }\n })\n setFieldErrors(nextErrors)\n }\n }}\n format={format}\n t={t}\n disabled={disableActions}\n errors={fieldErrors}\n showFormatHint={!formatLoading}\n />\n {generalError ? <p className=\"text-xs text-status-error-text\">{generalError}</p> : null}\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel} disabled={disableActions}>\n {t('customers.people.detail.addresses.cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={disableActions}>\n {saving ? (\n <>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n {editingId\n ? t('customers.people.detail.addresses.updating')\n : t('customers.people.detail.addresses.saving')}\n </>\n ) : editingId ? (\n t('customers.people.detail.addresses.update')\n ) : (\n t('customers.people.detail.addresses.save')\n )}\n </Button>\n </div>\n </div>\n </div>\n ),\n [\n disableActions,\n draft,\n editingId,\n fieldErrors,\n format,\n formatLoading,\n handleCancel,\n handleSave,\n generalError,\n saving,\n t,\n ]\n )\n\n return (\n <div className=\"space-y-4\">\n {!hideAddButton && hasAddresses ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={openCreateForm}\n disabled={addDisabled}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('customers.people.detail.addresses.add')}\n </Button>\n </div>\n ) : null}\n {hasAddresses ? (\n <div className={gridClassName}>\n {addresses.map((address) => {\n if (isFormOpen && editingId === address.id) {\n return renderFormTile(address.id)\n }\n const formattedJson = formatAddressJson(address, format)\n const formattedString = formatAddressString(address, format)\n\n return (\n <div\n key={address.id}\n className=\"rounded-lg border bg-background p-4 text-sm shadow-sm\"\n title={formattedString}\n data-address-json={JSON.stringify(formattedJson)}\n data-address-string={formattedString}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {address.name ||\n (address.purpose ? addressTypeMap.get(address.purpose) ?? address.purpose : null) ||\n t('customers.people.detail.address')}\n </span>\n {address.isPrimary ? (\n <span className=\"mt-1 inline-flex w-fit rounded bg-status-success-bg px-2 py-0.5 text-overline font-semibold text-status-success-text\">\n {t('customers.people.detail.primary')}\n </span>\n ) : null}\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => openEditForm(address)}\n disabled={disableActions}\n aria-label={t('customers.people.detail.addresses.editAction')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-destructive hover:text-destructive focus-visible:text-destructive\"\n onClick={() => handleDelete(address.id)}\n disabled={disableActions || !onDelete}\n aria-label={t('customers.people.detail.addresses.deleteAction')}\n >\n {deletingId === address.id ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </div>\n <div className=\"mt-2 space-y-1\">\n {address.purpose ? (\n <p className=\"text-xs text-muted-foreground\">\n {addressTypeMap.get(address.purpose) ?? address.purpose}\n </p>\n ) : null}\n <AddressView address={address} format={format} className=\"space-y-1\" lineClassName=\"text-sm\" />\n </div>\n </div>\n )\n })}\n {isFormOpen && !editingId ? renderFormTile('__new') : null}\n </div>\n ) : isFormOpen && !editingId ? (\n <div className={gridClassName}>{renderFormTile('__new')}</div>\n ) : (\n <TabEmptyState\n title={emptyTitle}\n action={{\n label: emptyActionLabel,\n onClick: openCreateForm,\n disabled: addDisabled,\n }}\n />\n )}\n </div>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Loader2, Pencil, Plus, Trash2, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { AddressView, formatAddressJson, formatAddressString, type AddressFormatStrategy } from '../utils/addressFormat'\nimport AddressEditor from './AddressEditor'\nimport { useAddressTypes } from './detail/hooks/useAddressTypes'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@open-mercato/ui/primitives/dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ensureCustomerDictionary, invalidateCustomerDictionary } from './detail/hooks/useCustomerDictionary'\n\nexport type Translator = (\n key: string,\n fallback?: string,\n params?: Record<string, string | number>,\n) => string\n\nexport type CustomerAddressInput = {\n name?: string\n purpose?: string\n companyName?: string\n addressLine1: string\n addressLine2?: string\n buildingNumber?: string\n flatNumber?: string\n city?: string\n region?: string\n postalCode?: string\n country?: string\n isPrimary?: boolean\n}\n\nexport type CustomerAddressValue = CustomerAddressInput & {\n id: string\n purpose?: string | null\n companyName?: string | null\n}\n\ntype CustomerAddressTilesProps = {\n addresses: CustomerAddressValue[]\n onCreate: (payload: CustomerAddressInput) => Promise<void> | void\n onUpdate?: (id: string, payload: CustomerAddressInput) => Promise<void> | void\n onDelete?: (id: string) => Promise<void> | void\n t: Translator\n emptyLabel: string\n isSubmitting?: boolean\n gridClassName?: string\n hideAddButton?: boolean\n onAddActionChange?: (action: { openCreateForm: () => void; addDisabled: boolean } | null) => void\n emptyStateTitle?: string\n emptyStateActionLabel?: string\n}\n\ntype DraftAddressState = {\n name: string\n purpose: string\n companyName: string\n addressLine1: string\n addressLine2: string\n buildingNumber: string\n flatNumber: string\n city: string\n region: string\n postalCode: string\n country: string\n isPrimary: boolean\n}\n\ntype DraftFieldKey = keyof DraftAddressState\n\ntype AddressValidationDetail = {\n path?: Array<string | number>\n code?: string\n message?: string\n minimum?: number\n maximum?: number\n type?: string\n}\n\nconst defaultDraft: DraftAddressState = {\n name: '',\n purpose: '',\n companyName: '',\n addressLine1: '',\n addressLine2: '',\n buildingNumber: '',\n flatNumber: '',\n city: '',\n region: '',\n postalCode: '',\n country: '',\n isPrimary: false,\n}\n\nconst serverFieldMap: Record<string, DraftFieldKey> = {\n name: 'name',\n purpose: 'purpose',\n companyName: 'companyName',\n addressLine1: 'addressLine1',\n addressLine2: 'addressLine2',\n buildingNumber: 'buildingNumber',\n flatNumber: 'flatNumber',\n city: 'city',\n region: 'region',\n postalCode: 'postalCode',\n country: 'country',\n isPrimary: 'isPrimary',\n}\n\nfunction normalizeOptional(value: string): string | undefined {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : undefined\n}\n\nfunction extractValidationDetails(error: unknown): AddressValidationDetail[] {\n if (!error || typeof error !== 'object') return []\n const candidate = (error as { details?: unknown }).details\n if (!Array.isArray(candidate)) return []\n return candidate\n .map((entry) => (entry && typeof entry === 'object' ? (entry as AddressValidationDetail) : null))\n .filter((entry): entry is AddressValidationDetail => entry !== null)\n}\n\nfunction resolveFieldMessage(detail: AddressValidationDetail, fieldLabel: string, t: Translator): string {\n switch (detail.code) {\n case 'invalid_type':\n return t('customers.people.detail.addresses.validation.invalid', undefined, { field: fieldLabel })\n case 'too_small':\n if (detail.minimum === 1 && detail.type === 'string') {\n return t('customers.people.detail.addresses.validation.required', undefined, { field: fieldLabel })\n }\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n case 'too_big':\n if (typeof detail.maximum === 'number') {\n return t(\n 'customers.people.detail.addresses.validation.tooLong',\n undefined,\n {\n field: fieldLabel,\n max: detail.maximum,\n }\n )\n }\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n default:\n return t('customers.people.detail.addresses.validation.generic', undefined, { field: fieldLabel })\n }\n}\n\nexport function CustomerAddressTiles({\n addresses,\n onCreate,\n onUpdate,\n onDelete,\n t,\n emptyLabel,\n isSubmitting = false,\n gridClassName = 'grid gap-4 min-[480px]:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4',\n hideAddButton = false,\n onAddActionChange,\n emptyStateTitle,\n emptyStateActionLabel,\n}: CustomerAddressTilesProps) {\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const [isFormOpen, setIsFormOpen] = React.useState(false)\n const [editingId, setEditingId] = React.useState<string | null>(null)\n const [draft, setDraft] = React.useState<DraftAddressState>(defaultDraft)\n const [saving, setSaving] = React.useState(false)\n const [deletingId, setDeletingId] = React.useState<string | null>(null)\n const [generalError, setGeneralError] = React.useState<string | null>(null)\n const [fieldErrors, setFieldErrors] = React.useState<Partial<Record<DraftFieldKey, string>>>({})\n const [format, setFormat] = React.useState<AddressFormatStrategy>('line_first')\n const [formatLoading, setFormatLoading] = React.useState(false)\n const { map: addressTypeMap } = useAddressTypes(t)\n\n const fieldLabels = React.useMemo(\n () => ({\n name: t('customers.people.detail.addresses.fields.label'),\n purpose: t('customers.people.detail.addresses.fields.type'),\n companyName: t('customers.people.detail.addresses.fields.companyName', 'Company name'),\n addressLine1: t('customers.people.detail.addresses.fields.line1'),\n addressLine2: t('customers.people.detail.addresses.fields.line2'),\n street: t('customers.people.detail.addresses.fields.street', 'Street'),\n buildingNumber: t('customers.people.detail.addresses.fields.buildingNumber', 'Building number'),\n flatNumber: t('customers.people.detail.addresses.fields.flatNumber', 'Flat number'),\n city: t('customers.people.detail.addresses.fields.city'),\n region: t('customers.people.detail.addresses.fields.region'),\n postalCode: t('customers.people.detail.addresses.fields.postalCode'),\n country: t('customers.people.detail.addresses.fields.country'),\n isPrimary: t('customers.people.detail.addresses.fields.primary'),\n }),\n [t]\n )\n const line1FieldLabel = React.useMemo(\n () => (format === 'street_first' ? fieldLabels.street : fieldLabels.addressLine1),\n [fieldLabels.addressLine1, fieldLabels.street, format],\n )\n\n\n\n const resetForm = React.useCallback(() => {\n setDraft(defaultDraft)\n setFieldErrors({})\n setGeneralError(null)\n setEditingId(null)\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadFormat() {\n setFormatLoading(true)\n try {\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 if (!cancelled) {\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 flash(message, 'error')\n }\n return\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (!cancelled && (value === 'street_first' || value === 'line_first')) {\n setFormat(value)\n }\n } catch (err) {\n if (!cancelled) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setFormatLoading(false)\n }\n }\n loadFormat().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, t])\n\n\n const openCreateForm = React.useCallback(() => {\n resetForm()\n setIsFormOpen(true)\n }, [resetForm])\n\n const openEditForm = React.useCallback(\n (address: CustomerAddressValue) => {\n setDraft({\n name: address.name ?? '',\n purpose: address.purpose ?? '',\n companyName: address.companyName ?? '',\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2 ?? '',\n buildingNumber: address.buildingNumber ?? '',\n flatNumber: address.flatNumber ?? '',\n city: address.city ?? '',\n region: address.region ?? '',\n postalCode: address.postalCode ?? '',\n country: address.country ? address.country.toUpperCase() : '',\n isPrimary: address.isPrimary ?? false,\n })\n setFieldErrors({})\n setGeneralError(null)\n setEditingId(address.id)\n setIsFormOpen(true)\n },\n []\n )\n\n const handleCancel = React.useCallback(() => {\n setIsFormOpen(false)\n resetForm()\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n const trimmedLine1 = draft.addressLine1.trim()\n if (!trimmedLine1.length) {\n const message = t(\n 'customers.people.detail.addresses.validation.required',\n undefined,\n { field: line1FieldLabel }\n )\n setFieldErrors((prev) => ({ ...prev, addressLine1: message }))\n setGeneralError(message)\n return\n }\n\n const payload: CustomerAddressInput = {\n addressLine1: trimmedLine1,\n isPrimary: draft.isPrimary,\n }\n\n const purpose = normalizeOptional(draft.purpose)\n if (purpose !== undefined) payload.purpose = purpose\n const name = normalizeOptional(draft.name)\n if (name !== undefined) payload.name = name\n const companyName = normalizeOptional(draft.companyName)\n if (companyName !== undefined) payload.companyName = companyName\n const line2 = normalizeOptional(draft.addressLine2)\n if (line2 !== undefined) payload.addressLine2 = line2\n const buildingNumber = normalizeOptional(draft.buildingNumber)\n if (buildingNumber !== undefined) payload.buildingNumber = buildingNumber\n const flatNumber = normalizeOptional(draft.flatNumber)\n if (flatNumber !== undefined) payload.flatNumber = flatNumber\n const city = normalizeOptional(draft.city)\n if (city !== undefined) payload.city = city\n const region = normalizeOptional(draft.region)\n if (region !== undefined) payload.region = region\n const postal = normalizeOptional(draft.postalCode)\n if (postal !== undefined) payload.postalCode = postal\n const country = normalizeOptional(draft.country)\n if (country !== undefined) payload.country = country.toUpperCase()\n\n setSaving(true)\n setGeneralError(null)\n setFieldErrors({})\n try {\n if (editingId && onUpdate) await onUpdate(editingId, payload)\n else await onCreate(payload)\n resetForm()\n setIsFormOpen(false)\n } catch (err) {\n const details = extractValidationDetails(err)\n if (details.length) {\n const nextErrors: Partial<Record<DraftFieldKey, string>> = {}\n for (const detail of details) {\n const path = Array.isArray(detail.path) ? detail.path : []\n const targetKey = path.length ? serverFieldMap[String(path[0])] : undefined\n if (!targetKey) continue\n const message = resolveFieldMessage(\n detail,\n targetKey === 'addressLine1' ? line1FieldLabel : fieldLabels[targetKey],\n t,\n )\n if (message) nextErrors[targetKey] = message\n }\n if (Object.keys(nextErrors).length) {\n setFieldErrors(nextErrors)\n setGeneralError(Object.values(nextErrors)[0] ?? null)\n setSaving(false)\n return\n }\n }\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.error')\n setGeneralError(message)\n flash(message, 'error')\n } finally {\n setSaving(false)\n }\n }, [draft, editingId, fieldLabels, line1FieldLabel, onCreate, onUpdate, resetForm, t])\n\n const handleDelete = React.useCallback(\n async (id: string) => {\n if (!onDelete) return\n setDeletingId(id)\n try {\n await onDelete(id)\n if (editingId === id) {\n resetForm()\n setIsFormOpen(false)\n }\n } catch (err) {\n const message =\n err instanceof Error && err.message\n ? err.message\n : t('customers.people.detail.addresses.error')\n flash(message, 'error')\n } finally {\n setDeletingId(null)\n }\n },\n [editingId, onDelete, resetForm, t]\n )\n\n const disableActions = saving || isSubmitting || deletingId !== null\n const isEditing = editingId !== null\n const addDisabled = disableActions || isEditing\n const hasAddresses = addresses.length > 0\n const emptyTitle = emptyStateTitle ?? emptyLabel\n const emptyActionLabel = emptyStateActionLabel ?? t('customers.people.detail.addresses.add')\n\n React.useEffect(() => {\n if (!onAddActionChange) return\n onAddActionChange({ openCreateForm, addDisabled })\n }, [onAddActionChange, openCreateForm, addDisabled])\n\n React.useEffect(\n () => () => {\n if (onAddActionChange) onAddActionChange(null)\n },\n [onAddActionChange]\n )\n\n const renderFormTile = React.useCallback(\n (key: string) => (\n <div\n key={key}\n className=\"rounded-lg border-2 border-dashed border-muted-foreground/50 bg-muted/30 p-4 text-sm\"\n onKeyDown={(event) => {\n if (!(event.metaKey || event.ctrlKey)) return\n if (event.key !== 'Enter') return\n event.preventDefault()\n if (disableActions) return\n void handleSave()\n }}\n >\n <div className=\"flex items-center justify-between text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n <span>\n {editingId\n ? t('customers.people.detail.addresses.editTitle')\n : t('customers.people.detail.addresses.addTitle')}\n </span>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" onClick={handleCancel} disabled={disableActions}>\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n <div className=\"mt-3 space-y-3\">\n {formatLoading ? (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.people.detail.addresses.formatLoading', 'Loading address preferences\u2026')}\n </p>\n ) : null}\n <AddressEditor\n value={draft}\n onChange={(next) => {\n setDraft(next)\n if (Object.keys(fieldErrors).length) {\n const nextErrors = { ...fieldErrors }\n ;(Object.keys(nextErrors) as DraftFieldKey[]).forEach((key) => {\n const candidate = (next as Record<string, unknown>)[key]\n if (candidate !== undefined && candidate !== null && `${candidate}`.length) {\n delete nextErrors[key]\n }\n })\n setFieldErrors(nextErrors)\n }\n }}\n format={format}\n t={t}\n disabled={disableActions}\n errors={fieldErrors}\n showFormatHint={!formatLoading}\n />\n {generalError ? <p className=\"text-xs text-status-error-text\">{generalError}</p> : null}\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel} disabled={disableActions}>\n {t('customers.people.detail.addresses.cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={disableActions}>\n {saving ? (\n <>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n {editingId\n ? t('customers.people.detail.addresses.updating')\n : t('customers.people.detail.addresses.saving')}\n </>\n ) : editingId ? (\n t('customers.people.detail.addresses.update')\n ) : (\n t('customers.people.detail.addresses.save')\n )}\n </Button>\n </div>\n </div>\n </div>\n ),\n [\n disableActions,\n draft,\n editingId,\n fieldErrors,\n format,\n formatLoading,\n handleCancel,\n handleSave,\n generalError,\n saving,\n t,\n ]\n )\n\n return (\n <div className=\"space-y-4\">\n {!hideAddButton && hasAddresses ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={openCreateForm}\n disabled={addDisabled}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('customers.people.detail.addresses.add')}\n </Button>\n </div>\n ) : null}\n {hasAddresses ? (\n <div className={gridClassName}>\n {addresses.map((address) => {\n if (isFormOpen && editingId === address.id) {\n return renderFormTile(address.id)\n }\n const formattedJson = formatAddressJson(address, format)\n const formattedString = formatAddressString(address, format)\n\n return (\n <div\n key={address.id}\n className=\"rounded-lg border bg-background p-4 text-sm shadow-sm\"\n title={formattedString}\n data-address-json={JSON.stringify(formattedJson)}\n data-address-string={formattedString}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">\n {address.name ||\n (address.purpose ? addressTypeMap.get(address.purpose) ?? address.purpose : null) ||\n t('customers.people.detail.address')}\n </span>\n {address.isPrimary ? (\n <span className=\"mt-1 inline-flex w-fit rounded bg-status-success-bg px-2 py-0.5 text-overline font-semibold text-status-success-text\">\n {t('customers.people.detail.primary')}\n </span>\n ) : null}\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => openEditForm(address)}\n disabled={disableActions}\n aria-label={t('customers.people.detail.addresses.editAction')}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-destructive hover:text-destructive focus-visible:text-destructive\"\n onClick={() => handleDelete(address.id)}\n disabled={disableActions || !onDelete}\n aria-label={t('customers.people.detail.addresses.deleteAction')}\n >\n {deletingId === address.id ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </div>\n <div className=\"mt-2 space-y-1\">\n {address.purpose ? (\n <p className=\"text-xs text-muted-foreground\">\n {addressTypeMap.get(address.purpose) ?? address.purpose}\n </p>\n ) : null}\n <AddressView address={address} format={format} className=\"space-y-1\" lineClassName=\"text-sm\" />\n </div>\n </div>\n )\n })}\n {isFormOpen && !editingId ? renderFormTile('__new') : null}\n </div>\n ) : isFormOpen && !editingId ? (\n <div className={gridClassName}>{renderFormTile('__new')}</div>\n ) : (\n <TabEmptyState\n title={emptyTitle}\n action={{\n label: emptyActionLabel,\n onClick: openCreateForm,\n disabled: addDisabled,\n }}\n />\n )}\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["message", "key"]
|
|
7
7
|
}
|
|
@@ -92,7 +92,7 @@ function ActivityForm({
|
|
|
92
92
|
return /* @__PURE__ */ jsx(
|
|
93
93
|
"select",
|
|
94
94
|
{
|
|
95
|
-
className: "h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
95
|
+
className: "h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
96
96
|
value: currentValue,
|
|
97
97
|
onChange: (event) => setValue(event.target.value),
|
|
98
98
|
children: normalizedEntityOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option.id, children: option.label }, option.id))
|
|
@@ -112,7 +112,7 @@ function ActivityForm({
|
|
|
112
112
|
return /* @__PURE__ */ jsxs(
|
|
113
113
|
"select",
|
|
114
114
|
{
|
|
115
|
-
className: "h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
115
|
+
className: "h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
116
116
|
value: currentValue,
|
|
117
117
|
onChange: (event) => setValue(event.target.value),
|
|
118
118
|
children: [
|
|
@@ -167,7 +167,7 @@ function ActivityForm({
|
|
|
167
167
|
"input",
|
|
168
168
|
{
|
|
169
169
|
type: "datetime-local",
|
|
170
|
-
className: "w-full rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
|
|
170
|
+
className: "w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
171
171
|
value: typeof value === "string" ? value : "",
|
|
172
172
|
onChange: (event) => setValue(event.target.value || ""),
|
|
173
173
|
onFocus: (event) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ActivityForm.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { DictionaryEntrySelect, type DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { E } from '#generated/entities.ids.generated'\nimport { toLocalDateTimeInput } from './utils'\nimport { normalizeCustomFieldSubmitValue } from './customFieldUtils'\n\ntype DictionaryOption = {\n value: string\n label: string\n color: string | null\n icon: string | null\n}\n\nexport type ActivityFormBaseValues = {\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n dealId?: string | null\n}\n\nexport type ActivityFormSubmitPayload = {\n base: ActivityFormBaseValues\n custom: Record<string, unknown>\n entityId?: string | null\n}\n\nexport type ActivityFormProps = {\n mode: 'create' | 'edit'\n initialValues?: Partial<ActivityFormBaseValues & Record<string, unknown>>\n onSubmit: (payload: ActivityFormSubmitPayload) => Promise<void>\n onCancel: () => void\n submitLabel?: string\n cancelLabel?: string\n isSubmitting?: boolean\n activityTypeLabels: DictionarySelectLabels\n loadActivityOptions: () => Promise<DictionaryOption[]>\n createActivityOption?: (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => Promise<DictionaryOption>\n dealOptions?: Array<{ id: string; label: string }>\n entityOptions?: Array<{ id: string; label: string }>\n defaultEntityId?: string | null\n}\n\nconst schema = z.object({\n activityType: z.string().min(1),\n subject: z.string().transform((value) => value.trim()).optional(),\n body: z.string().transform((value) => value.trim()).optional(),\n occurredAt: z\n .string()\n .transform((value) => value.trim())\n .refine((value) => {\n if (!value) return true\n const parsed = new Date(value)\n return !Number.isNaN(parsed.getTime())\n }, { message: 'customers.people.detail.activities.invalidDate' })\n .optional(),\n}).passthrough()\n\nconst ACTIVITY_ENTITY_IDS = [E.customers.customer_activity]\n\nexport function ActivityForm({\n mode,\n initialValues,\n onSubmit,\n onCancel,\n submitLabel,\n cancelLabel,\n isSubmitting = false,\n activityTypeLabels,\n loadActivityOptions,\n createActivityOption,\n dealOptions,\n entityOptions,\n defaultEntityId,\n}: ActivityFormProps) {\n const t = useT()\n const [pending, setPending] = React.useState(false)\n\n const dictionaryAppearanceLabels = React.useMemo(\n () => ({\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.dialog.previewEmpty', 'No appearance selected'),\n }),\n [t],\n )\n\n const normalizedDealOptions = React.useMemo(() => {\n if (!Array.isArray(dealOptions)) return []\n const seen = new Set<string>()\n return dealOptions\n .map((option) => {\n if (!option || typeof option !== 'object') return null\n const id = typeof option.id === 'string' ? option.id.trim() : ''\n if (!id || seen.has(id)) return null\n const label =\n typeof option.label === 'string' && option.label.trim().length\n ? option.label.trim()\n : id\n seen.add(id)\n return { id, label }\n })\n .filter((option): option is { id: string; label: string } => !!option)\n }, [dealOptions])\n\n const normalizedEntityOptions = React.useMemo(() => {\n if (!Array.isArray(entityOptions)) return []\n const seen = new Set<string>()\n return entityOptions\n .map((option) => {\n if (!option || typeof option !== 'object') return null\n const id = typeof option.id === 'string' ? option.id.trim() : ''\n if (!id || seen.has(id)) return null\n const label =\n typeof option.label === 'string' && option.label.trim().length\n ? option.label.trim()\n : id\n seen.add(id)\n return { id, label }\n })\n .filter((option): option is { id: string; label: string } => !!option)\n }, [entityOptions])\n\n const baseFields = React.useMemo<CrudField[]>(() => {\n const fields: CrudField[] = []\n\n if (normalizedEntityOptions.length) {\n fields.push({\n id: 'entityId',\n label: t('customers.people.detail.activities.fields.entity', 'Assign to customer'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => {\n const currentValue =\n typeof value === 'string' && value.length ? value : normalizedEntityOptions[0]?.id ?? ''\n return (\n <select\n className=\"h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n value={currentValue}\n onChange={(event) => setValue(event.target.value)}\n >\n {normalizedEntityOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n )\n },\n } as CrudField)\n }\n\n if (normalizedDealOptions.length) {\n fields.push({\n id: 'dealId',\n label: t('customers.people.detail.activities.fields.deal', 'Link to deal (optional)'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' ? value : ''\n return (\n <select\n className=\"h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n value={currentValue}\n onChange={(event) => setValue(event.target.value)}\n >\n <option value=\"\">\n {t('customers.people.detail.activities.fields.dealPlaceholder', 'No linked deal')}\n </option>\n {normalizedDealOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n )\n },\n } as CrudField)\n }\n\n fields.push({\n id: 'activityType',\n label: t('customers.people.detail.activities.fields.type'),\n type: 'custom',\n required: true,\n layout: 'half',\n component: ({ value, setValue }) => (\n <DictionaryEntrySelect\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next ?? '')}\n fetchOptions={loadActivityOptions}\n createOption={createActivityOption}\n labels={activityTypeLabels}\n allowAppearance\n allowInlineCreate\n appearanceLabels={dictionaryAppearanceLabels}\n selectClassName=\"w-full\"\n manageHref=\"/backend/config/customers\"\n />\n ),\n } as CrudField)\n\n fields.push({\n id: 'subject',\n label: t('customers.people.detail.activities.fields.subject'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.detail.activities.subjectPlaceholder', 'Add a subject (optional)'),\n } as CrudField)\n\n fields.push({\n id: 'body',\n label: t('customers.people.detail.activities.fields.body'),\n type: 'textarea',\n placeholder: t('customers.people.detail.activities.bodyPlaceholder', 'Describe the interaction'),\n } as CrudField)\n\n fields.push({\n id: 'occurredAt',\n label: t('customers.people.detail.activities.fields.occurredAt'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <input\n type=\"datetime-local\"\n className=\"w-full rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n value={typeof value === 'string' ? value : ''}\n onChange={(event) => setValue(event.target.value || '')}\n onFocus={(event) => {\n const target = event.currentTarget as HTMLInputElement & { showPicker?: () => void }\n if (typeof target.showPicker === 'function') {\n try { target.showPicker() } catch { /* ignore unsupported */ }\n }\n }}\n onClick={(event) => {\n const target = event.currentTarget as HTMLInputElement & { showPicker?: () => void }\n if (typeof target.showPicker === 'function') {\n try { target.showPicker() } catch { /* ignore unsupported */ }\n }\n }}\n />\n ),\n layout: 'half',\n } as CrudField)\n\n return fields\n }, [\n activityTypeLabels,\n createActivityOption,\n dictionaryAppearanceLabels,\n loadActivityOptions,\n normalizedDealOptions,\n normalizedEntityOptions,\n t,\n ])\n\n const baseFieldIds = React.useMemo(() => new Set(baseFields.map((field) => field.id)), [baseFields])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const detailFields: string[] = []\n if (normalizedEntityOptions.length) detailFields.push('entityId')\n if (normalizedDealOptions.length) detailFields.push('dealId')\n detailFields.push('activityType', 'subject', 'occurredAt', 'body')\n return [\n {\n id: 'details',\n title: t('customers.people.detail.activities.form.details', 'Activity details'),\n column: 1,\n fields: detailFields,\n },\n {\n id: 'custom',\n title: t('customers.people.detail.activities.form.customFields', 'Custom fields'),\n column: 2,\n kind: 'customFields',\n },\n ]\n }, [normalizedDealOptions.length, normalizedEntityOptions.length, t])\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n if (pending || isSubmitting) return\n setPending(true)\n try {\n const parsed = schema.safeParse(values)\n if (!parsed.success) {\n throw buildActivityValidationError(parsed.error.issues, t)\n }\n const rawEntityId = typeof values.entityId === 'string' ? values.entityId.trim() : ''\n const resolvedEntityId = rawEntityId || (typeof defaultEntityId === 'string' ? defaultEntityId : '')\n const rawDealId = typeof values.dealId === 'string' ? values.dealId.trim() : ''\n const base: ActivityFormBaseValues = {\n activityType: parsed.data.activityType,\n subject: parsed.data.subject || undefined,\n body: parsed.data.body || undefined,\n occurredAt: parsed.data.occurredAt && parsed.data.occurredAt.length\n ? new Date(parsed.data.occurredAt).toISOString()\n : undefined,\n dealId: rawDealId.length ? rawDealId : undefined,\n }\n const reservedCustomKeys = new Set(['entityId', 'dealId'])\n const customEntries = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n accept: (fieldId) => !reservedCustomKeys.has(fieldId),\n })\n Object.entries(values).forEach(([key, value]) => {\n if (key.startsWith('cf_')) return\n if (!baseFieldIds.has(key) && key !== 'id') {\n if (reservedCustomKeys.has(key)) return\n customEntries[key] = normalizeCustomFieldSubmitValue(value)\n }\n })\n await onSubmit({ base, custom: customEntries, entityId: resolvedEntityId.length ? resolvedEntityId : undefined })\n } finally {\n setPending(false)\n }\n },\n [baseFieldIds, defaultEntityId, isSubmitting, onSubmit, pending, t],\n )\n\n const embeddedInitialValues = React.useMemo(() => {\n const occurredAt = toLocalDateTimeInput(initialValues?.occurredAt ?? null)\n const resolvedEntity = (() => {\n const raw = typeof (initialValues as Record<string, unknown> | undefined)?.entityId === 'string'\n ? (initialValues as Record<string, unknown>).entityId as string\n : typeof defaultEntityId === 'string'\n ? defaultEntityId\n : normalizedEntityOptions[0]?.id ?? ''\n return raw ?? ''\n })()\n const resolvedDeal = typeof (initialValues as Record<string, unknown> | undefined)?.dealId === 'string'\n ? (initialValues as Record<string, unknown>).dealId as string\n : ''\n\n return {\n entityId: resolvedEntity,\n dealId: resolvedDeal,\n activityType: initialValues?.activityType ?? '',\n subject: initialValues?.subject ?? '',\n body: initialValues?.body ?? '',\n occurredAt,\n ...Object.fromEntries(\n Object.entries(initialValues ?? {})\n .filter(([key]) => {\n if (!key.startsWith('cf_')) return false\n const trimmed = key.slice(3)\n return trimmed !== 'entityId' && trimmed !== 'dealId'\n })\n .map(([key, value]) => [key, value]),\n ),\n }\n }, [defaultEntityId, initialValues, normalizedEntityOptions])\n\n return (\n <CrudForm<Record<string, unknown>>\n embedded\n fields={baseFields}\n groups={groups}\n initialValues={embeddedInitialValues}\n onSubmit={handleSubmit}\n submitLabel={submitLabel ?? (mode === 'edit'\n ? t('customers.people.detail.activities.update', 'Update activity (\u2318/Ctrl + Enter)')\n : t('customers.people.detail.activities.save', 'Save activity (\u2318/Ctrl + Enter)'))}\n extraActions={(\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onCancel}\n disabled={pending || isSubmitting}\n >\n {cancelLabel ?? t('customers.people.detail.activities.cancel', 'Cancel')}\n </Button>\n )}\n entityIds={ACTIVITY_ENTITY_IDS}\n />\n )\n}\n\nexport function buildActivityValidationError(issues: z.ZodIssue[], t: (key: string, fallback?: string) => string) {\n const issue = issues[0]\n const message = issue?.message ?? t('customers.people.detail.activities.error')\n const firstPath = Array.isArray(issue?.path) ? issue?.path?.[0] : undefined\n const field = typeof firstPath === 'string' ? firstPath : undefined\n throw createCrudFormError(message, field ? { [field]: message } : undefined)\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { DictionaryEntrySelect, type DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { E } from '#generated/entities.ids.generated'\nimport { toLocalDateTimeInput } from './utils'\nimport { normalizeCustomFieldSubmitValue } from './customFieldUtils'\n\ntype DictionaryOption = {\n value: string\n label: string\n color: string | null\n icon: string | null\n}\n\nexport type ActivityFormBaseValues = {\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n dealId?: string | null\n}\n\nexport type ActivityFormSubmitPayload = {\n base: ActivityFormBaseValues\n custom: Record<string, unknown>\n entityId?: string | null\n}\n\nexport type ActivityFormProps = {\n mode: 'create' | 'edit'\n initialValues?: Partial<ActivityFormBaseValues & Record<string, unknown>>\n onSubmit: (payload: ActivityFormSubmitPayload) => Promise<void>\n onCancel: () => void\n submitLabel?: string\n cancelLabel?: string\n isSubmitting?: boolean\n activityTypeLabels: DictionarySelectLabels\n loadActivityOptions: () => Promise<DictionaryOption[]>\n createActivityOption?: (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => Promise<DictionaryOption>\n dealOptions?: Array<{ id: string; label: string }>\n entityOptions?: Array<{ id: string; label: string }>\n defaultEntityId?: string | null\n}\n\nconst schema = z.object({\n activityType: z.string().min(1),\n subject: z.string().transform((value) => value.trim()).optional(),\n body: z.string().transform((value) => value.trim()).optional(),\n occurredAt: z\n .string()\n .transform((value) => value.trim())\n .refine((value) => {\n if (!value) return true\n const parsed = new Date(value)\n return !Number.isNaN(parsed.getTime())\n }, { message: 'customers.people.detail.activities.invalidDate' })\n .optional(),\n}).passthrough()\n\nconst ACTIVITY_ENTITY_IDS = [E.customers.customer_activity]\n\nexport function ActivityForm({\n mode,\n initialValues,\n onSubmit,\n onCancel,\n submitLabel,\n cancelLabel,\n isSubmitting = false,\n activityTypeLabels,\n loadActivityOptions,\n createActivityOption,\n dealOptions,\n entityOptions,\n defaultEntityId,\n}: ActivityFormProps) {\n const t = useT()\n const [pending, setPending] = React.useState(false)\n\n const dictionaryAppearanceLabels = React.useMemo(\n () => ({\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.dialog.previewEmpty', 'No appearance selected'),\n }),\n [t],\n )\n\n const normalizedDealOptions = React.useMemo(() => {\n if (!Array.isArray(dealOptions)) return []\n const seen = new Set<string>()\n return dealOptions\n .map((option) => {\n if (!option || typeof option !== 'object') return null\n const id = typeof option.id === 'string' ? option.id.trim() : ''\n if (!id || seen.has(id)) return null\n const label =\n typeof option.label === 'string' && option.label.trim().length\n ? option.label.trim()\n : id\n seen.add(id)\n return { id, label }\n })\n .filter((option): option is { id: string; label: string } => !!option)\n }, [dealOptions])\n\n const normalizedEntityOptions = React.useMemo(() => {\n if (!Array.isArray(entityOptions)) return []\n const seen = new Set<string>()\n return entityOptions\n .map((option) => {\n if (!option || typeof option !== 'object') return null\n const id = typeof option.id === 'string' ? option.id.trim() : ''\n if (!id || seen.has(id)) return null\n const label =\n typeof option.label === 'string' && option.label.trim().length\n ? option.label.trim()\n : id\n seen.add(id)\n return { id, label }\n })\n .filter((option): option is { id: string; label: string } => !!option)\n }, [entityOptions])\n\n const baseFields = React.useMemo<CrudField[]>(() => {\n const fields: CrudField[] = []\n\n if (normalizedEntityOptions.length) {\n fields.push({\n id: 'entityId',\n label: t('customers.people.detail.activities.fields.entity', 'Assign to customer'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => {\n const currentValue =\n typeof value === 'string' && value.length ? value : normalizedEntityOptions[0]?.id ?? ''\n return (\n <select\n className=\"h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={currentValue}\n onChange={(event) => setValue(event.target.value)}\n >\n {normalizedEntityOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n )\n },\n } as CrudField)\n }\n\n if (normalizedDealOptions.length) {\n fields.push({\n id: 'dealId',\n label: t('customers.people.detail.activities.fields.deal', 'Link to deal (optional)'),\n type: 'custom',\n layout: 'half',\n component: ({ value, setValue }) => {\n const currentValue = typeof value === 'string' ? value : ''\n return (\n <select\n className=\"h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={currentValue}\n onChange={(event) => setValue(event.target.value)}\n >\n <option value=\"\">\n {t('customers.people.detail.activities.fields.dealPlaceholder', 'No linked deal')}\n </option>\n {normalizedDealOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n )\n },\n } as CrudField)\n }\n\n fields.push({\n id: 'activityType',\n label: t('customers.people.detail.activities.fields.type'),\n type: 'custom',\n required: true,\n layout: 'half',\n component: ({ value, setValue }) => (\n <DictionaryEntrySelect\n value={typeof value === 'string' ? value : undefined}\n onChange={(next) => setValue(next ?? '')}\n fetchOptions={loadActivityOptions}\n createOption={createActivityOption}\n labels={activityTypeLabels}\n allowAppearance\n allowInlineCreate\n appearanceLabels={dictionaryAppearanceLabels}\n selectClassName=\"w-full\"\n manageHref=\"/backend/config/customers\"\n />\n ),\n } as CrudField)\n\n fields.push({\n id: 'subject',\n label: t('customers.people.detail.activities.fields.subject'),\n type: 'text',\n layout: 'half',\n placeholder: t('customers.people.detail.activities.subjectPlaceholder', 'Add a subject (optional)'),\n } as CrudField)\n\n fields.push({\n id: 'body',\n label: t('customers.people.detail.activities.fields.body'),\n type: 'textarea',\n placeholder: t('customers.people.detail.activities.bodyPlaceholder', 'Describe the interaction'),\n } as CrudField)\n\n fields.push({\n id: 'occurredAt',\n label: t('customers.people.detail.activities.fields.occurredAt'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <input\n type=\"datetime-local\"\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={typeof value === 'string' ? value : ''}\n onChange={(event) => setValue(event.target.value || '')}\n onFocus={(event) => {\n const target = event.currentTarget as HTMLInputElement & { showPicker?: () => void }\n if (typeof target.showPicker === 'function') {\n try { target.showPicker() } catch { /* ignore unsupported */ }\n }\n }}\n onClick={(event) => {\n const target = event.currentTarget as HTMLInputElement & { showPicker?: () => void }\n if (typeof target.showPicker === 'function') {\n try { target.showPicker() } catch { /* ignore unsupported */ }\n }\n }}\n />\n ),\n layout: 'half',\n } as CrudField)\n\n return fields\n }, [\n activityTypeLabels,\n createActivityOption,\n dictionaryAppearanceLabels,\n loadActivityOptions,\n normalizedDealOptions,\n normalizedEntityOptions,\n t,\n ])\n\n const baseFieldIds = React.useMemo(() => new Set(baseFields.map((field) => field.id)), [baseFields])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n const detailFields: string[] = []\n if (normalizedEntityOptions.length) detailFields.push('entityId')\n if (normalizedDealOptions.length) detailFields.push('dealId')\n detailFields.push('activityType', 'subject', 'occurredAt', 'body')\n return [\n {\n id: 'details',\n title: t('customers.people.detail.activities.form.details', 'Activity details'),\n column: 1,\n fields: detailFields,\n },\n {\n id: 'custom',\n title: t('customers.people.detail.activities.form.customFields', 'Custom fields'),\n column: 2,\n kind: 'customFields',\n },\n ]\n }, [normalizedDealOptions.length, normalizedEntityOptions.length, t])\n\n const handleSubmit = React.useCallback(\n async (values: Record<string, unknown>) => {\n if (pending || isSubmitting) return\n setPending(true)\n try {\n const parsed = schema.safeParse(values)\n if (!parsed.success) {\n throw buildActivityValidationError(parsed.error.issues, t)\n }\n const rawEntityId = typeof values.entityId === 'string' ? values.entityId.trim() : ''\n const resolvedEntityId = rawEntityId || (typeof defaultEntityId === 'string' ? defaultEntityId : '')\n const rawDealId = typeof values.dealId === 'string' ? values.dealId.trim() : ''\n const base: ActivityFormBaseValues = {\n activityType: parsed.data.activityType,\n subject: parsed.data.subject || undefined,\n body: parsed.data.body || undefined,\n occurredAt: parsed.data.occurredAt && parsed.data.occurredAt.length\n ? new Date(parsed.data.occurredAt).toISOString()\n : undefined,\n dealId: rawDealId.length ? rawDealId : undefined,\n }\n const reservedCustomKeys = new Set(['entityId', 'dealId'])\n const customEntries = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n accept: (fieldId) => !reservedCustomKeys.has(fieldId),\n })\n Object.entries(values).forEach(([key, value]) => {\n if (key.startsWith('cf_')) return\n if (!baseFieldIds.has(key) && key !== 'id') {\n if (reservedCustomKeys.has(key)) return\n customEntries[key] = normalizeCustomFieldSubmitValue(value)\n }\n })\n await onSubmit({ base, custom: customEntries, entityId: resolvedEntityId.length ? resolvedEntityId : undefined })\n } finally {\n setPending(false)\n }\n },\n [baseFieldIds, defaultEntityId, isSubmitting, onSubmit, pending, t],\n )\n\n const embeddedInitialValues = React.useMemo(() => {\n const occurredAt = toLocalDateTimeInput(initialValues?.occurredAt ?? null)\n const resolvedEntity = (() => {\n const raw = typeof (initialValues as Record<string, unknown> | undefined)?.entityId === 'string'\n ? (initialValues as Record<string, unknown>).entityId as string\n : typeof defaultEntityId === 'string'\n ? defaultEntityId\n : normalizedEntityOptions[0]?.id ?? ''\n return raw ?? ''\n })()\n const resolvedDeal = typeof (initialValues as Record<string, unknown> | undefined)?.dealId === 'string'\n ? (initialValues as Record<string, unknown>).dealId as string\n : ''\n\n return {\n entityId: resolvedEntity,\n dealId: resolvedDeal,\n activityType: initialValues?.activityType ?? '',\n subject: initialValues?.subject ?? '',\n body: initialValues?.body ?? '',\n occurredAt,\n ...Object.fromEntries(\n Object.entries(initialValues ?? {})\n .filter(([key]) => {\n if (!key.startsWith('cf_')) return false\n const trimmed = key.slice(3)\n return trimmed !== 'entityId' && trimmed !== 'dealId'\n })\n .map(([key, value]) => [key, value]),\n ),\n }\n }, [defaultEntityId, initialValues, normalizedEntityOptions])\n\n return (\n <CrudForm<Record<string, unknown>>\n embedded\n fields={baseFields}\n groups={groups}\n initialValues={embeddedInitialValues}\n onSubmit={handleSubmit}\n submitLabel={submitLabel ?? (mode === 'edit'\n ? t('customers.people.detail.activities.update', 'Update activity (\u2318/Ctrl + Enter)')\n : t('customers.people.detail.activities.save', 'Save activity (\u2318/Ctrl + Enter)'))}\n extraActions={(\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onCancel}\n disabled={pending || isSubmitting}\n >\n {cancelLabel ?? t('customers.people.detail.activities.cancel', 'Cancel')}\n </Button>\n )}\n entityIds={ACTIVITY_ENTITY_IDS}\n />\n )\n}\n\nexport function buildActivityValidationError(issues: z.ZodIssue[], t: (key: string, fallback?: string) => string) {\n const issue = issues[0]\n const message = issue?.message ?? t('customers.people.detail.activities.error')\n const firstPath = Array.isArray(issue?.path) ? issue?.path?.[0] : undefined\n const field = typeof firstPath === 'string' ? firstPath : undefined\n throw createCrudFormError(message, field ? { [field]: message } : undefined)\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -134,7 +134,7 @@ function AnnualRevenueField({
|
|
|
134
134
|
}
|
|
135
135
|
}, [draftAmount, draftCurrency, onSave, saving, t, validator]);
|
|
136
136
|
const containerClasses = React.useMemo(
|
|
137
|
-
() => cn("group rounded border bg-muted/
|
|
137
|
+
() => cn("group rounded border bg-muted/30 p-3", {
|
|
138
138
|
"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring": !editing
|
|
139
139
|
}),
|
|
140
140
|
[editing]
|
|
@@ -190,7 +190,7 @@ function AnnualRevenueField({
|
|
|
190
190
|
/* @__PURE__ */ jsx(
|
|
191
191
|
"input",
|
|
192
192
|
{
|
|
193
|
-
className: "w-full rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
|
|
193
|
+
className: "w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
194
194
|
value: draftAmount,
|
|
195
195
|
onChange: (event) => {
|
|
196
196
|
setDraftAmount(event.target.value);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/AnnualRevenueField.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DictionaryEntrySelect } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useCurrencyDictionary } from './hooks/useCurrencyDictionary'\nimport type { InlineFieldProps } from './InlineEditors'\n\nexport type AnnualRevenueFieldProps = {\n label: string\n amount: string | null\n currency: string | null\n emptyLabel: string\n validator?: NonNullable<InlineFieldProps['validator']>\n onSave: (payload: { amount: number | null; currency: string | null }) => Promise<void>\n}\n\nexport function AnnualRevenueField({\n label,\n amount,\n currency,\n emptyLabel,\n validator,\n onSave,\n}: AnnualRevenueFieldProps) {\n const t = useT()\n const {\n data: currencyDictionary,\n error: currencyDictionaryErrorRaw,\n isLoading: currencyDictionaryLoading,\n refetch: refetchCurrencyDictionary,\n } = useCurrencyDictionary()\n\n const currencyDictionaryError =\n currencyDictionaryErrorRaw instanceof Error\n ? currencyDictionaryErrorRaw.message\n : currencyDictionaryErrorRaw\n ? String(currencyDictionaryErrorRaw)\n : null\n\n const [editing, setEditing] = React.useState(false)\n const [draftAmount, setDraftAmount] = React.useState(() => (typeof amount === 'string' ? amount : ''))\n const [draftCurrency, setDraftCurrency] = React.useState(() => (typeof currency === 'string' ? currency : ''))\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) {\n setDraftAmount(typeof amount === 'string' ? amount : '')\n setDraftCurrency(typeof currency === 'string' ? currency : '')\n setError(null)\n }\n }, [amount, currency, editing])\n\n const currencyLabel = React.useMemo(() => {\n if (!currency) return null\n const entries = currencyDictionary?.entries ?? []\n const match = entries.find((entry) => entry.value === currency)\n if (!match) return currency\n return match.label || match.value\n }, [currency, currencyDictionary?.entries])\n\n const fetchCurrencyOptions = React.useCallback(async () => {\n if (currencyDictionary && currencyDictionary.entries.length) {\n return currencyDictionary.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }\n const payload = await refetchCurrencyDictionary()\n return payload.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [currencyDictionary, refetchCurrencyDictionary])\n\n const display = React.useMemo(() => {\n const value = typeof amount === 'string' ? amount.trim() : ''\n if (!value.length) {\n return <p className=\"text-sm text-muted-foreground\">{emptyLabel}</p>\n }\n const numeric = Number(value.replace(/,/g, ''))\n let formatted = value\n if (!Number.isNaN(numeric)) {\n try {\n formatted = new Intl.NumberFormat(undefined, {\n style: currency ? 'currency' : 'decimal',\n currency: currency ?? undefined,\n maximumFractionDigits: 2,\n }).format(numeric)\n } catch {\n formatted = currency ? `${currency} ${numeric}` : `${numeric}`\n }\n }\n return (\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-sm font-medium text-foreground\">{formatted}</span>\n {currencyLabel ? (\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">{currencyLabel}</span>\n ) : null}\n </div>\n )\n }, [amount, currency, currencyLabel, emptyLabel])\n\n const currencyLabels = React.useMemo(\n () => ({\n placeholder: t('customers.companies.detail.currency.placeholder', 'Select currency\u2026'),\n addLabel: t('customers.companies.detail.currency.add', 'Add currency'),\n addPrompt: t('customers.companies.detail.currency.addPrompt', 'Enter a 3-letter ISO currency code.'),\n dialogTitle: t('customers.companies.detail.currency.dialogTitle', 'Add currency'),\n valueLabel: t('customers.companies.detail.currency.valueLabel', 'Currency code'),\n valuePlaceholder: t('customers.companies.detail.currency.valuePlaceholder', 'e.g. USD'),\n labelLabel: t('customers.companies.detail.currency.labelLabel', 'Display label (optional)'),\n labelPlaceholder: t('customers.companies.detail.currency.labelPlaceholder', 'e.g. US Dollar'),\n emptyError: t('customers.companies.detail.currency.emptyError', 'Please provide a currency code.'),\n cancelLabel: t('customers.companies.detail.currency.cancel', 'Cancel'),\n saveLabel: t('customers.companies.detail.currency.save', 'Save'),\n saveShortcutHint: t('customers.companies.detail.currency.saveShortcutHint', 'Press Enter to save'),\n successCreateLabel: t('customers.companies.detail.currency.success', 'Currency added.'),\n errorLoad: t('customers.companies.detail.currency.fetchError', 'Unable to load currencies.'),\n errorSave: t('customers.companies.detail.currency.createError', 'Unable to add currency.'),\n loadingLabel: t('customers.companies.detail.currency.loading', 'Loading currencies\u2026'),\n manageTitle: t('customers.companies.detail.currency.manageTitle', 'Manage currencies'),\n }),\n [t],\n )\n\n const handleSave = React.useCallback(async () => {\n if (saving) return\n const trimmedAmount = draftAmount.trim()\n if (validator) {\n const validationError = validator(trimmedAmount)\n if (validationError) {\n setError(validationError)\n return\n }\n }\n let numeric: number | null = null\n if (trimmedAmount.length) {\n numeric = Number(trimmedAmount)\n if (Number.isNaN(numeric)) {\n setError(t('customers.companies.detail.currency.invalidAmount', 'Enter a valid amount.'))\n return\n }\n }\n setSaving(true)\n try {\n await onSave({ amount: numeric, currency: draftCurrency.trim() ? draftCurrency.trim() : null })\n setEditing(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.companies.detail.inline.error', 'Unable to update company.')\n setError(message)\n } finally {\n setSaving(false)\n }\n }, [draftAmount, draftCurrency, onSave, saving, t, validator])\n\n const containerClasses = React.useMemo(\n () =>\n cn('group rounded border bg-muted/20 p-3', {\n 'cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring': !editing,\n }),\n [editing],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [editing, handleActivate],\n )\n\n return (\n <div\n className={containerClasses}\n role={editing ? undefined : 'button'}\n tabIndex={editing ? -1 : 0}\n onClick={() => {\n if (!editing) handleActivate()\n }}\n onKeyDown={handleKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">{label}</p>\n <div className=\"mt-1 text-sm text-foreground\">{display}</div>\n {currencyDictionaryError ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{currencyDictionaryError}</p>\n ) : null}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setEditing((prev) => !prev)}\n className=\"h-8 w-8 opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">{editing ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}</span>\n </Button>\n </div>\n {editing ? (\n <div className=\"mt-3 space-y-3\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.companies.detail.fields.annualRevenuePlaceholder', 'Enter amount')}\n </label>\n <input\n className=\"w-full rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n value={draftAmount}\n onChange={(event) => {\n setDraftAmount(event.target.value)\n if (error) setError(null)\n }}\n placeholder={t('customers.companies.detail.fields.annualRevenuePlaceholder', 'Enter amount')}\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.companies.detail.highlights.annualRevenueCurrency', 'Currency')}\n </label>\n <DictionaryEntrySelect\n value={draftCurrency || undefined}\n onChange={(next) => setDraftCurrency(next ?? '')}\n fetchOptions={fetchCurrencyOptions}\n labels={currencyLabels}\n manageHref=\"/backend/config/dictionaries?key=currency\"\n allowInlineCreate={false}\n allowAppearance={false}\n selectClassName=\"w-full\"\n disabled={currencyDictionaryLoading}\n showLabelInput={false}\n />\n </div>\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={saving} onClick={() => setEditing(false)}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n disabled={saving}\n onClick={() => {\n setDraftAmount('')\n setDraftCurrency('')\n if (error) setError(null)\n }}\n >\n {t('customers.companies.detail.currency.clear', 'Clear')}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Loader2, Pencil, X } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DictionaryEntrySelect } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useCurrencyDictionary } from './hooks/useCurrencyDictionary'\nimport type { InlineFieldProps } from './InlineEditors'\n\nexport type AnnualRevenueFieldProps = {\n label: string\n amount: string | null\n currency: string | null\n emptyLabel: string\n validator?: NonNullable<InlineFieldProps['validator']>\n onSave: (payload: { amount: number | null; currency: string | null }) => Promise<void>\n}\n\nexport function AnnualRevenueField({\n label,\n amount,\n currency,\n emptyLabel,\n validator,\n onSave,\n}: AnnualRevenueFieldProps) {\n const t = useT()\n const {\n data: currencyDictionary,\n error: currencyDictionaryErrorRaw,\n isLoading: currencyDictionaryLoading,\n refetch: refetchCurrencyDictionary,\n } = useCurrencyDictionary()\n\n const currencyDictionaryError =\n currencyDictionaryErrorRaw instanceof Error\n ? currencyDictionaryErrorRaw.message\n : currencyDictionaryErrorRaw\n ? String(currencyDictionaryErrorRaw)\n : null\n\n const [editing, setEditing] = React.useState(false)\n const [draftAmount, setDraftAmount] = React.useState(() => (typeof amount === 'string' ? amount : ''))\n const [draftCurrency, setDraftCurrency] = React.useState(() => (typeof currency === 'string' ? currency : ''))\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) {\n setDraftAmount(typeof amount === 'string' ? amount : '')\n setDraftCurrency(typeof currency === 'string' ? currency : '')\n setError(null)\n }\n }, [amount, currency, editing])\n\n const currencyLabel = React.useMemo(() => {\n if (!currency) return null\n const entries = currencyDictionary?.entries ?? []\n const match = entries.find((entry) => entry.value === currency)\n if (!match) return currency\n return match.label || match.value\n }, [currency, currencyDictionary?.entries])\n\n const fetchCurrencyOptions = React.useCallback(async () => {\n if (currencyDictionary && currencyDictionary.entries.length) {\n return currencyDictionary.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }\n const payload = await refetchCurrencyDictionary()\n return payload.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [currencyDictionary, refetchCurrencyDictionary])\n\n const display = React.useMemo(() => {\n const value = typeof amount === 'string' ? amount.trim() : ''\n if (!value.length) {\n return <p className=\"text-sm text-muted-foreground\">{emptyLabel}</p>\n }\n const numeric = Number(value.replace(/,/g, ''))\n let formatted = value\n if (!Number.isNaN(numeric)) {\n try {\n formatted = new Intl.NumberFormat(undefined, {\n style: currency ? 'currency' : 'decimal',\n currency: currency ?? undefined,\n maximumFractionDigits: 2,\n }).format(numeric)\n } catch {\n formatted = currency ? `${currency} ${numeric}` : `${numeric}`\n }\n }\n return (\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-sm font-medium text-foreground\">{formatted}</span>\n {currencyLabel ? (\n <span className=\"text-xs uppercase tracking-wide text-muted-foreground\">{currencyLabel}</span>\n ) : null}\n </div>\n )\n }, [amount, currency, currencyLabel, emptyLabel])\n\n const currencyLabels = React.useMemo(\n () => ({\n placeholder: t('customers.companies.detail.currency.placeholder', 'Select currency\u2026'),\n addLabel: t('customers.companies.detail.currency.add', 'Add currency'),\n addPrompt: t('customers.companies.detail.currency.addPrompt', 'Enter a 3-letter ISO currency code.'),\n dialogTitle: t('customers.companies.detail.currency.dialogTitle', 'Add currency'),\n valueLabel: t('customers.companies.detail.currency.valueLabel', 'Currency code'),\n valuePlaceholder: t('customers.companies.detail.currency.valuePlaceholder', 'e.g. USD'),\n labelLabel: t('customers.companies.detail.currency.labelLabel', 'Display label (optional)'),\n labelPlaceholder: t('customers.companies.detail.currency.labelPlaceholder', 'e.g. US Dollar'),\n emptyError: t('customers.companies.detail.currency.emptyError', 'Please provide a currency code.'),\n cancelLabel: t('customers.companies.detail.currency.cancel', 'Cancel'),\n saveLabel: t('customers.companies.detail.currency.save', 'Save'),\n saveShortcutHint: t('customers.companies.detail.currency.saveShortcutHint', 'Press Enter to save'),\n successCreateLabel: t('customers.companies.detail.currency.success', 'Currency added.'),\n errorLoad: t('customers.companies.detail.currency.fetchError', 'Unable to load currencies.'),\n errorSave: t('customers.companies.detail.currency.createError', 'Unable to add currency.'),\n loadingLabel: t('customers.companies.detail.currency.loading', 'Loading currencies\u2026'),\n manageTitle: t('customers.companies.detail.currency.manageTitle', 'Manage currencies'),\n }),\n [t],\n )\n\n const handleSave = React.useCallback(async () => {\n if (saving) return\n const trimmedAmount = draftAmount.trim()\n if (validator) {\n const validationError = validator(trimmedAmount)\n if (validationError) {\n setError(validationError)\n return\n }\n }\n let numeric: number | null = null\n if (trimmedAmount.length) {\n numeric = Number(trimmedAmount)\n if (Number.isNaN(numeric)) {\n setError(t('customers.companies.detail.currency.invalidAmount', 'Enter a valid amount.'))\n return\n }\n }\n setSaving(true)\n try {\n await onSave({ amount: numeric, currency: draftCurrency.trim() ? draftCurrency.trim() : null })\n setEditing(false)\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : t('customers.companies.detail.inline.error', 'Unable to update company.')\n setError(message)\n } finally {\n setSaving(false)\n }\n }, [draftAmount, draftCurrency, onSave, saving, t, validator])\n\n const containerClasses = React.useMemo(\n () =>\n cn('group rounded border bg-muted/30 p-3', {\n 'cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring': !editing,\n }),\n [editing],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [editing, handleActivate],\n )\n\n return (\n <div\n className={containerClasses}\n role={editing ? undefined : 'button'}\n tabIndex={editing ? -1 : 0}\n onClick={() => {\n if (!editing) handleActivate()\n }}\n onKeyDown={handleKeyDown}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">{label}</p>\n <div className=\"mt-1 text-sm text-foreground\">{display}</div>\n {currencyDictionaryError ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{currencyDictionaryError}</p>\n ) : null}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setEditing((prev) => !prev)}\n className=\"h-8 w-8 opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100\"\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n <span className=\"sr-only\">{editing ? t('ui.forms.actions.cancel') : t('ui.forms.actions.edit')}</span>\n </Button>\n </div>\n {editing ? (\n <div className=\"mt-3 space-y-3\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.companies.detail.fields.annualRevenuePlaceholder', 'Enter amount')}\n </label>\n <input\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={draftAmount}\n onChange={(event) => {\n setDraftAmount(event.target.value)\n if (error) setError(null)\n }}\n placeholder={t('customers.companies.detail.fields.annualRevenuePlaceholder', 'Enter amount')}\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.companies.detail.highlights.annualRevenueCurrency', 'Currency')}\n </label>\n <DictionaryEntrySelect\n value={draftCurrency || undefined}\n onChange={(next) => setDraftCurrency(next ?? '')}\n fetchOptions={fetchCurrencyOptions}\n labels={currencyLabels}\n manageHref=\"/backend/config/dictionaries?key=currency\"\n allowInlineCreate={false}\n allowAppearance={false}\n selectClassName=\"w-full\"\n disabled={currencyDictionaryLoading}\n showLabelInput={false}\n />\n </div>\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.forms.actions.save')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={saving} onClick={() => setEditing(false)}>\n {t('ui.forms.actions.cancel')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n disabled={saving}\n onClick={() => {\n setDraftAmount('')\n setDraftCurrency('')\n if (error) setError(null)\n }}\n >\n {t('customers.companies.detail.currency.clear', 'Clear')}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -168,7 +168,7 @@ function CustomFieldValuesList({
|
|
|
168
168
|
return /* @__PURE__ */ jsxs(
|
|
169
169
|
"div",
|
|
170
170
|
{
|
|
171
|
-
className: "rounded-md border border-border/
|
|
171
|
+
className: "rounded-md border border-border/70 bg-muted/30 px-3 py-2",
|
|
172
172
|
children: [
|
|
173
173
|
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: entry.label }),
|
|
174
174
|
/* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-foreground", children: content })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/CustomFieldValuesList.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n DictionaryValue,\n type DictionaryMap,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type { CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n extractDictionaryValue,\n isEmptyCustomValue,\n normalizeCustomFieldKey,\n resolveCustomFieldLabel,\n stringifyCustomValue,\n} from './customFieldUtils'\nimport type { CustomFieldDisplayResources } from './hooks/useCustomFieldDisplay'\n\ntype CustomFieldEntry = {\n key: string\n value: unknown\n label?: string | null\n}\n\ntype DisplayEntry = {\n id: string\n key: string\n normalizedKey: string\n label: string\n value: unknown\n dictionaryMap: DictionaryMap | null\n multi: boolean\n}\n\ntype CustomFieldValuesListProps = {\n values?: Record<string, unknown> | null\n entries?: CustomFieldEntry[]\n definitions?: CustomFieldDefDto[]\n dictionaryMapsByKey?: Record<string, DictionaryMap>\n resources?: CustomFieldDisplayResources\n emptyLabel?: string\n className?: string\n itemKeyPrefix?: string\n}\n\nfunction defaultEmptyLabel(label?: string): string {\n if (typeof label === 'string' && label.trim().length) return label\n return '\u2014'\n}\n\nfunction ensureDictionaryMap(\n key: string,\n normalizedKey: string,\n dictionaryMaps?: Record<string, DictionaryMap>,\n): DictionaryMap | null {\n if (!dictionaryMaps) return null\n if (dictionaryMaps[key]) return dictionaryMaps[key]\n if (dictionaryMaps[normalizedKey]) return dictionaryMaps[normalizedKey]\n return null\n}\n\nfunction renderDictionaryValues(\n values: unknown,\n dictionaryMap: DictionaryMap | null,\n multi: boolean,\n): React.ReactNode {\n if (!dictionaryMap) return null\n if (multi || Array.isArray(values)) {\n const resolved = (Array.isArray(values) ? values : [values])\n .map((entry) => extractDictionaryValue(entry))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n if (!resolved.length) return null\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {resolved.map((value, index) => (\n <DictionaryValue\n key={`${value}-${index}`}\n value={value}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-card px-2 py-1 text-xs\"\n iconWrapperClassName=\"inline-flex h-4 w-4 items-center justify-center rounded-full border border-border bg-background\"\n iconClassName=\"h-3 w-3\"\n colorClassName=\"h-2.5 w-2.5 rounded-full\"\n />\n ))}\n </div>\n )\n }\n const resolved = extractDictionaryValue(values)\n if (!resolved) return null\n return (\n <DictionaryValue\n value={resolved}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-2 text-sm\"\n />\n )\n}\n\nfunction renderPrimitiveValues(value: unknown): React.ReactNode {\n if (Array.isArray(value)) {\n const parts = value\n .map((entry) => stringifyCustomValue(entry))\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n if (!parts.length) return null\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {parts.map((entry, index) => (\n <span\n key={`${entry}-${index}`}\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground\"\n >\n {entry}\n </span>\n ))}\n </div>\n )\n }\n const label = stringifyCustomValue(value).trim()\n if (!label.length) return null\n return <span className=\"text-sm text-foreground\">{label}</span>\n}\n\nfunction buildDisplayEntries(\n values: Record<string, unknown> | null | undefined,\n entries: CustomFieldEntry[] | undefined,\n definitions: CustomFieldDefDto[],\n dictionaryMaps: Record<string, DictionaryMap> | undefined,\n): DisplayEntry[] {\n const combined = new Map<\n string,\n {\n key: string\n value: unknown\n label?: string | null\n }\n >()\n\n if (values) {\n Object.entries(values).forEach(([rawKey, value]) => {\n const normalizedKey = normalizeCustomFieldKey(rawKey)\n if (!normalizedKey) return\n if (!combined.has(normalizedKey)) {\n combined.set(normalizedKey, { key: rawKey, value })\n } else {\n const existing = combined.get(normalizedKey)\n if (existing) {\n existing.value = value\n }\n }\n })\n }\n\n if (entries) {\n entries.forEach((entry) => {\n const normalizedKey = normalizeCustomFieldKey(entry.key)\n if (!normalizedKey) return\n const existing = combined.get(normalizedKey)\n if (existing) {\n combined.set(normalizedKey, {\n key: existing.key,\n value: entry.value,\n label: entry.label ?? existing.label,\n })\n } else {\n combined.set(normalizedKey, {\n key: entry.key,\n value: entry.value,\n label: entry.label,\n })\n }\n })\n }\n\n const ordered: DisplayEntry[] = []\n const consumedKeys = new Set<string>()\n\n definitions.forEach((def, index) => {\n const normalizedKey = normalizeCustomFieldKey(def.key)\n if (!normalizedKey) return\n const entry = combined.get(normalizedKey)\n if (!entry || isEmptyCustomValue(entry.value)) return\n const label = resolveCustomFieldLabel(entry.label ?? def.label, entry.key)\n const dictionaryMap = ensureDictionaryMap(entry.key, normalizedKey, dictionaryMaps)\n ordered.push({\n id: `${normalizedKey}-${index}`,\n key: entry.key,\n normalizedKey,\n label,\n value: entry.value,\n dictionaryMap,\n multi: def.multi ?? Array.isArray(entry.value),\n })\n consumedKeys.add(normalizedKey)\n })\n\n const extras: DisplayEntry[] = []\n combined.forEach((entry, normalizedKey) => {\n if (consumedKeys.has(normalizedKey)) return\n if (isEmptyCustomValue(entry.value)) return\n const label = resolveCustomFieldLabel(entry.label, entry.key)\n const dictionaryMap = ensureDictionaryMap(entry.key, normalizedKey, dictionaryMaps)\n extras.push({\n id: normalizedKey,\n key: entry.key,\n normalizedKey,\n label,\n value: entry.value,\n dictionaryMap,\n multi: Array.isArray(entry.value),\n })\n })\n\n extras.sort((a, b) => a.label.localeCompare(b.label))\n\n return [...ordered, ...extras]\n}\n\nexport function CustomFieldValuesList({\n values = null,\n entries,\n definitions,\n dictionaryMapsByKey,\n resources,\n emptyLabel,\n className,\n itemKeyPrefix,\n}: CustomFieldValuesListProps) {\n const displayEntries = React.useMemo(() => {\n const defs = definitions ?? resources?.definitions ?? []\n const maps = dictionaryMapsByKey ?? resources?.dictionaryMapsByKey ?? {}\n return buildDisplayEntries(values, entries, defs, maps)\n }, [definitions, dictionaryMapsByKey, entries, resources, values])\n\n if (!displayEntries.length) return null\n\n const resolvedEmptyLabel = defaultEmptyLabel(emptyLabel)\n const prefix = itemKeyPrefix ?? 'custom-field'\n\n return (\n <div className={cn('grid gap-3 sm:grid-cols-2', className)}>\n {displayEntries.map((entry, index) => {\n const dictionaryContent = renderDictionaryValues(entry.value, entry.dictionaryMap, entry.multi)\n const primitiveContent = dictionaryContent ?? renderPrimitiveValues(entry.value)\n const content =\n dictionaryContent ??\n primitiveContent ??\n <span className=\"text-sm text-muted-foreground\">{resolvedEmptyLabel}</span>\n return (\n <div\n key={`${prefix}-${entry.normalizedKey}-${index}`}\n className=\"rounded-md border border-border/
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n DictionaryValue,\n type DictionaryMap,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type { CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport {\n extractDictionaryValue,\n isEmptyCustomValue,\n normalizeCustomFieldKey,\n resolveCustomFieldLabel,\n stringifyCustomValue,\n} from './customFieldUtils'\nimport type { CustomFieldDisplayResources } from './hooks/useCustomFieldDisplay'\n\ntype CustomFieldEntry = {\n key: string\n value: unknown\n label?: string | null\n}\n\ntype DisplayEntry = {\n id: string\n key: string\n normalizedKey: string\n label: string\n value: unknown\n dictionaryMap: DictionaryMap | null\n multi: boolean\n}\n\ntype CustomFieldValuesListProps = {\n values?: Record<string, unknown> | null\n entries?: CustomFieldEntry[]\n definitions?: CustomFieldDefDto[]\n dictionaryMapsByKey?: Record<string, DictionaryMap>\n resources?: CustomFieldDisplayResources\n emptyLabel?: string\n className?: string\n itemKeyPrefix?: string\n}\n\nfunction defaultEmptyLabel(label?: string): string {\n if (typeof label === 'string' && label.trim().length) return label\n return '\u2014'\n}\n\nfunction ensureDictionaryMap(\n key: string,\n normalizedKey: string,\n dictionaryMaps?: Record<string, DictionaryMap>,\n): DictionaryMap | null {\n if (!dictionaryMaps) return null\n if (dictionaryMaps[key]) return dictionaryMaps[key]\n if (dictionaryMaps[normalizedKey]) return dictionaryMaps[normalizedKey]\n return null\n}\n\nfunction renderDictionaryValues(\n values: unknown,\n dictionaryMap: DictionaryMap | null,\n multi: boolean,\n): React.ReactNode {\n if (!dictionaryMap) return null\n if (multi || Array.isArray(values)) {\n const resolved = (Array.isArray(values) ? values : [values])\n .map((entry) => extractDictionaryValue(entry))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n if (!resolved.length) return null\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {resolved.map((value, index) => (\n <DictionaryValue\n key={`${value}-${index}`}\n value={value}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-card px-2 py-1 text-xs\"\n iconWrapperClassName=\"inline-flex h-4 w-4 items-center justify-center rounded-full border border-border bg-background\"\n iconClassName=\"h-3 w-3\"\n colorClassName=\"h-2.5 w-2.5 rounded-full\"\n />\n ))}\n </div>\n )\n }\n const resolved = extractDictionaryValue(values)\n if (!resolved) return null\n return (\n <DictionaryValue\n value={resolved}\n map={dictionaryMap}\n className=\"inline-flex items-center gap-2 text-sm\"\n />\n )\n}\n\nfunction renderPrimitiveValues(value: unknown): React.ReactNode {\n if (Array.isArray(value)) {\n const parts = value\n .map((entry) => stringifyCustomValue(entry))\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n if (!parts.length) return null\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {parts.map((entry, index) => (\n <span\n key={`${entry}-${index}`}\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground\"\n >\n {entry}\n </span>\n ))}\n </div>\n )\n }\n const label = stringifyCustomValue(value).trim()\n if (!label.length) return null\n return <span className=\"text-sm text-foreground\">{label}</span>\n}\n\nfunction buildDisplayEntries(\n values: Record<string, unknown> | null | undefined,\n entries: CustomFieldEntry[] | undefined,\n definitions: CustomFieldDefDto[],\n dictionaryMaps: Record<string, DictionaryMap> | undefined,\n): DisplayEntry[] {\n const combined = new Map<\n string,\n {\n key: string\n value: unknown\n label?: string | null\n }\n >()\n\n if (values) {\n Object.entries(values).forEach(([rawKey, value]) => {\n const normalizedKey = normalizeCustomFieldKey(rawKey)\n if (!normalizedKey) return\n if (!combined.has(normalizedKey)) {\n combined.set(normalizedKey, { key: rawKey, value })\n } else {\n const existing = combined.get(normalizedKey)\n if (existing) {\n existing.value = value\n }\n }\n })\n }\n\n if (entries) {\n entries.forEach((entry) => {\n const normalizedKey = normalizeCustomFieldKey(entry.key)\n if (!normalizedKey) return\n const existing = combined.get(normalizedKey)\n if (existing) {\n combined.set(normalizedKey, {\n key: existing.key,\n value: entry.value,\n label: entry.label ?? existing.label,\n })\n } else {\n combined.set(normalizedKey, {\n key: entry.key,\n value: entry.value,\n label: entry.label,\n })\n }\n })\n }\n\n const ordered: DisplayEntry[] = []\n const consumedKeys = new Set<string>()\n\n definitions.forEach((def, index) => {\n const normalizedKey = normalizeCustomFieldKey(def.key)\n if (!normalizedKey) return\n const entry = combined.get(normalizedKey)\n if (!entry || isEmptyCustomValue(entry.value)) return\n const label = resolveCustomFieldLabel(entry.label ?? def.label, entry.key)\n const dictionaryMap = ensureDictionaryMap(entry.key, normalizedKey, dictionaryMaps)\n ordered.push({\n id: `${normalizedKey}-${index}`,\n key: entry.key,\n normalizedKey,\n label,\n value: entry.value,\n dictionaryMap,\n multi: def.multi ?? Array.isArray(entry.value),\n })\n consumedKeys.add(normalizedKey)\n })\n\n const extras: DisplayEntry[] = []\n combined.forEach((entry, normalizedKey) => {\n if (consumedKeys.has(normalizedKey)) return\n if (isEmptyCustomValue(entry.value)) return\n const label = resolveCustomFieldLabel(entry.label, entry.key)\n const dictionaryMap = ensureDictionaryMap(entry.key, normalizedKey, dictionaryMaps)\n extras.push({\n id: normalizedKey,\n key: entry.key,\n normalizedKey,\n label,\n value: entry.value,\n dictionaryMap,\n multi: Array.isArray(entry.value),\n })\n })\n\n extras.sort((a, b) => a.label.localeCompare(b.label))\n\n return [...ordered, ...extras]\n}\n\nexport function CustomFieldValuesList({\n values = null,\n entries,\n definitions,\n dictionaryMapsByKey,\n resources,\n emptyLabel,\n className,\n itemKeyPrefix,\n}: CustomFieldValuesListProps) {\n const displayEntries = React.useMemo(() => {\n const defs = definitions ?? resources?.definitions ?? []\n const maps = dictionaryMapsByKey ?? resources?.dictionaryMapsByKey ?? {}\n return buildDisplayEntries(values, entries, defs, maps)\n }, [definitions, dictionaryMapsByKey, entries, resources, values])\n\n if (!displayEntries.length) return null\n\n const resolvedEmptyLabel = defaultEmptyLabel(emptyLabel)\n const prefix = itemKeyPrefix ?? 'custom-field'\n\n return (\n <div className={cn('grid gap-3 sm:grid-cols-2', className)}>\n {displayEntries.map((entry, index) => {\n const dictionaryContent = renderDictionaryValues(entry.value, entry.dictionaryMap, entry.multi)\n const primitiveContent = dictionaryContent ?? renderPrimitiveValues(entry.value)\n const content =\n dictionaryContent ??\n primitiveContent ??\n <span className=\"text-sm text-muted-foreground\">{resolvedEmptyLabel}</span>\n return (\n <div\n key={`${prefix}-${entry.normalizedKey}-${index}`}\n className=\"rounded-md border border-border/70 bg-muted/30 px-3 py-2\"\n >\n <div className=\"text-xs font-medium text-muted-foreground\">{entry.label}</div>\n <div className=\"mt-1 text-sm text-foreground\">{content}</div>\n </div>\n )\n })}\n </div>\n )\n}\n\nexport default CustomFieldValuesList\n"],
|
|
5
5
|
"mappings": ";AA2EU,cA+KA,YA/KA;AAzEV,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,OAEK;AACP,SAAS,UAAU;AAEnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA8BP,SAAS,kBAAkB,OAAwB;AACjD,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,OAAQ,QAAO;AAC7D,SAAO;AACT;AAEA,SAAS,oBACP,KACA,eACA,gBACsB;AACtB,MAAI,CAAC,eAAgB,QAAO;AAC5B,MAAI,eAAe,GAAG,EAAG,QAAO,eAAe,GAAG;AAClD,MAAI,eAAe,aAAa,EAAG,QAAO,eAAe,aAAa;AACtE,SAAO;AACT;AAEA,SAAS,uBACP,QACA,eACA,OACiB;AACjB,MAAI,CAAC,cAAe,QAAO;AAC3B,MAAI,SAAS,MAAM,QAAQ,MAAM,GAAG;AAClC,UAAMA,aAAY,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,GACvD,IAAI,CAAC,UAAU,uBAAuB,KAAK,CAAC,EAC5C,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AACnF,QAAI,CAACA,UAAS,OAAQ,QAAO;AAC7B,WACE,oBAAC,SAAI,WAAU,0BACZ,UAAAA,UAAS,IAAI,CAAC,OAAO,UACpB;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA,KAAK;AAAA,QACL,WAAU;AAAA,QACV,sBAAqB;AAAA,QACrB,eAAc;AAAA,QACd,gBAAe;AAAA;AAAA,MANV,GAAG,KAAK,IAAI,KAAK;AAAA,IAOxB,CACD,GACH;AAAA,EAEJ;AACA,QAAM,WAAW,uBAAuB,MAAM;AAC9C,MAAI,CAAC,SAAU,QAAO;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,KAAK;AAAA,MACL,WAAU;AAAA;AAAA,EACZ;AAEJ;AAEA,SAAS,sBAAsB,OAAiC;AAC9D,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,QAAQ,MACX,IAAI,CAAC,UAAU,qBAAqB,KAAK,CAAC,EAC1C,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AACrC,QAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,WACE,oBAAC,SAAI,WAAU,0BACZ,gBAAM,IAAI,CAAC,OAAO,UACjB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAET;AAAA;AAAA,MAHI,GAAG,KAAK,IAAI,KAAK;AAAA,IAIxB,CACD,GACH;AAAA,EAEJ;AACA,QAAM,QAAQ,qBAAqB,KAAK,EAAE,KAAK;AAC/C,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SAAO,oBAAC,UAAK,WAAU,2BAA2B,iBAAM;AAC1D;AAEA,SAAS,oBACP,QACA,SACA,aACA,gBACgB;AAChB,QAAM,WAAW,oBAAI,IAOnB;AAEF,MAAI,QAAQ;AACV,WAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK,MAAM;AAClD,YAAM,gBAAgB,wBAAwB,MAAM;AACpD,UAAI,CAAC,cAAe;AACpB,UAAI,CAAC,SAAS,IAAI,aAAa,GAAG;AAChC,iBAAS,IAAI,eAAe,EAAE,KAAK,QAAQ,MAAM,CAAC;AAAA,MACpD,OAAO;AACL,cAAM,WAAW,SAAS,IAAI,aAAa;AAC3C,YAAI,UAAU;AACZ,mBAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,SAAS;AACX,YAAQ,QAAQ,CAAC,UAAU;AACzB,YAAM,gBAAgB,wBAAwB,MAAM,GAAG;AACvD,UAAI,CAAC,cAAe;AACpB,YAAM,WAAW,SAAS,IAAI,aAAa;AAC3C,UAAI,UAAU;AACZ,iBAAS,IAAI,eAAe;AAAA,UAC1B,KAAK,SAAS;AAAA,UACd,OAAO,MAAM;AAAA,UACb,OAAO,MAAM,SAAS,SAAS;AAAA,QACjC,CAAC;AAAA,MACH,OAAO;AACL,iBAAS,IAAI,eAAe;AAAA,UAC1B,KAAK,MAAM;AAAA,UACX,OAAO,MAAM;AAAA,UACb,OAAO,MAAM;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,UAA0B,CAAC;AACjC,QAAM,eAAe,oBAAI,IAAY;AAErC,cAAY,QAAQ,CAAC,KAAK,UAAU;AAClC,UAAM,gBAAgB,wBAAwB,IAAI,GAAG;AACrD,QAAI,CAAC,cAAe;AACpB,UAAM,QAAQ,SAAS,IAAI,aAAa;AACxC,QAAI,CAAC,SAAS,mBAAmB,MAAM,KAAK,EAAG;AAC/C,UAAM,QAAQ,wBAAwB,MAAM,SAAS,IAAI,OAAO,MAAM,GAAG;AACzE,UAAM,gBAAgB,oBAAoB,MAAM,KAAK,eAAe,cAAc;AAClF,YAAQ,KAAK;AAAA,MACX,IAAI,GAAG,aAAa,IAAI,KAAK;AAAA,MAC7B,KAAK,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA,OAAO,MAAM;AAAA,MACb;AAAA,MACA,OAAO,IAAI,SAAS,MAAM,QAAQ,MAAM,KAAK;AAAA,IAC/C,CAAC;AACD,iBAAa,IAAI,aAAa;AAAA,EAChC,CAAC;AAED,QAAM,SAAyB,CAAC;AAChC,WAAS,QAAQ,CAAC,OAAO,kBAAkB;AACzC,QAAI,aAAa,IAAI,aAAa,EAAG;AACrC,QAAI,mBAAmB,MAAM,KAAK,EAAG;AACrC,UAAM,QAAQ,wBAAwB,MAAM,OAAO,MAAM,GAAG;AAC5D,UAAM,gBAAgB,oBAAoB,MAAM,KAAK,eAAe,cAAc;AAClF,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,KAAK,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA,OAAO,MAAM;AAAA,MACb;AAAA,MACA,OAAO,MAAM,QAAQ,MAAM,KAAK;AAAA,IAClC,CAAC;AAAA,EACH,CAAC;AAED,SAAO,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAEpD,SAAO,CAAC,GAAG,SAAS,GAAG,MAAM;AAC/B;AAEO,SAAS,sBAAsB;AAAA,EACpC,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACzC,UAAM,OAAO,eAAe,WAAW,eAAe,CAAC;AACvD,UAAM,OAAO,uBAAuB,WAAW,uBAAuB,CAAC;AACvE,WAAO,oBAAoB,QAAQ,SAAS,MAAM,IAAI;AAAA,EACxD,GAAG,CAAC,aAAa,qBAAqB,SAAS,WAAW,MAAM,CAAC;AAEjE,MAAI,CAAC,eAAe,OAAQ,QAAO;AAEnC,QAAM,qBAAqB,kBAAkB,UAAU;AACvD,QAAM,SAAS,iBAAiB;AAEhC,SACE,oBAAC,SAAI,WAAW,GAAG,6BAA6B,SAAS,GACtD,yBAAe,IAAI,CAAC,OAAO,UAAU;AACpC,UAAM,oBAAoB,uBAAuB,MAAM,OAAO,MAAM,eAAe,MAAM,KAAK;AAC9F,UAAM,mBAAmB,qBAAqB,sBAAsB,MAAM,KAAK;AAC/E,UAAM,UACJ,qBACA,oBACA,oBAAC,UAAK,WAAU,iCAAiC,8BAAmB;AACtE,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAU,6CAA6C,gBAAM,OAAM;AAAA,UACxE,oBAAC,SAAI,WAAU,gCAAgC,mBAAQ;AAAA;AAAA;AAAA,MAJlD,GAAG,MAAM,IAAI,MAAM,aAAa,IAAI,KAAK;AAAA,IAKhD;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,IAAO,gCAAQ;",
|
|
6
6
|
"names": ["resolved"]
|
|
7
7
|
}
|
|
@@ -280,7 +280,7 @@ function EntityMultiSelect({
|
|
|
280
280
|
"aria-label": option.label,
|
|
281
281
|
children: /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-start", children: [
|
|
282
282
|
/* @__PURE__ */ jsx("span", { children: option.label }),
|
|
283
|
-
option.subtitle ? /* @__PURE__ */ jsx("span", { className: "text-
|
|
283
|
+
option.subtitle ? /* @__PURE__ */ jsx("span", { className: "text-overline text-muted-foreground", children: option.subtitle }) : null
|
|
284
284
|
] })
|
|
285
285
|
},
|
|
286
286
|
option.id
|