@open-mercato/core 0.9.1-develop.7473.1.de5b22888f → 0.9.1-develop.7475.1.28ca93ed97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/catalog_price_history_entry/index.js +53 -0
- package/dist/generated/entities/catalog_price_history_entry/index.js.map +7 -0
- package/dist/generated/entities/customer_group_terms/index.js +2 -0
- package/dist/generated/entities/customer_group_terms/index.js.map +2 -2
- package/dist/generated/entities/ecommerce_store/index.js +33 -0
- package/dist/generated/entities/ecommerce_store/index.js.map +7 -0
- package/dist/generated/entities/ecommerce_store_channel_binding/index.js +29 -0
- package/dist/generated/entities/ecommerce_store_channel_binding/index.js.map +7 -0
- package/dist/generated/entities/ecommerce_store_domain_binding/index.js +23 -0
- package/dist/generated/entities/ecommerce_store_domain_binding/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +8 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +72 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/customerGroupsFixtures.js.map +2 -2
- package/dist/modules/catalog/acl.js +8 -1
- package/dist/modules/catalog/acl.js.map +2 -2
- package/dist/modules/catalog/api/config/omnibus/route.js +184 -0
- package/dist/modules/catalog/api/config/omnibus/route.js.map +7 -0
- package/dist/modules/catalog/api/prices/history/route.js +131 -0
- package/dist/modules/catalog/api/prices/history/route.js.map +7 -0
- package/dist/modules/catalog/api/prices/omnibus-preview/route.js +184 -0
- package/dist/modules/catalog/api/prices/omnibus-preview/route.js.map +7 -0
- package/dist/modules/catalog/api/products/route.js +54 -245
- package/dist/modules/catalog/api/products/route.js.map +3 -3
- package/dist/modules/catalog/api/tags/route.js +6 -0
- package/dist/modules/catalog/api/tags/route.js.map +2 -2
- package/dist/modules/catalog/backend/config/catalog/page.js +3 -1
- package/dist/modules/catalog/backend/config/catalog/page.js.map +2 -2
- package/dist/modules/catalog/cli.js +80 -2
- package/dist/modules/catalog/cli.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +51 -2
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/prices.js +43 -1
- package/dist/modules/catalog/commands/prices.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +71 -0
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +7 -0
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/OmnibusSettings.js +703 -0
- package/dist/modules/catalog/components/OmnibusSettings.js.map +7 -0
- package/dist/modules/catalog/components/PriceEditorOmnibusRow.js +152 -0
- package/dist/modules/catalog/components/PriceEditorOmnibusRow.js.map +7 -0
- package/dist/modules/catalog/components/lookupSources.js +31 -0
- package/dist/modules/catalog/components/lookupSources.js.map +7 -0
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js +8 -2
- package/dist/modules/catalog/components/prices/PriceScopeSelectors.js.map +2 -2
- package/dist/modules/catalog/components/products/VariantBuilder.js +11 -1
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +122 -1
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +78 -0
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/di.js +18 -0
- package/dist/modules/catalog/di.js.map +2 -2
- package/dist/modules/catalog/lib/omnibus.js +285 -0
- package/dist/modules/catalog/lib/omnibus.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusBackfill.js +146 -0
- package/dist/modules/catalog/lib/omnibusBackfill.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusCache.js +89 -0
- package/dist/modules/catalog/lib/omnibusCache.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusConfig.js +64 -0
- package/dist/modules/catalog/lib/omnibusConfig.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusHistoryQueries.js +191 -0
- package/dist/modules/catalog/lib/omnibusHistoryQueries.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusPresentedEntry.js +73 -0
- package/dist/modules/catalog/lib/omnibusPresentedEntry.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusProductListEnrichment.js +94 -0
- package/dist/modules/catalog/lib/omnibusProductListEnrichment.js.map +7 -0
- package/dist/modules/catalog/lib/omnibusTypes.js +115 -0
- package/dist/modules/catalog/lib/omnibusTypes.js.map +7 -0
- package/dist/modules/catalog/lib/optionSchemaTranslations.js +55 -0
- package/dist/modules/catalog/lib/optionSchemaTranslations.js.map +7 -0
- package/dist/modules/catalog/lib/priceHistoryQuery.js +103 -0
- package/dist/modules/catalog/lib/priceHistoryQuery.js.map +7 -0
- package/dist/modules/catalog/lib/pricing.js +26 -2
- package/dist/modules/catalog/lib/pricing.js.map +2 -2
- package/dist/modules/catalog/lib/productFilters.js +273 -0
- package/dist/modules/catalog/lib/productFilters.js.map +7 -0
- package/dist/modules/catalog/lib/productScopeKeys.js +105 -0
- package/dist/modules/catalog/lib/productScopeKeys.js.map +7 -0
- package/dist/modules/catalog/lib/productScopeReindex.js +73 -0
- package/dist/modules/catalog/lib/productScopeReindex.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js +39 -0
- package/dist/modules/catalog/migrations/Migration20261005105352_catalog.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js +39 -0
- package/dist/modules/catalog/migrations/Migration20261005150824_catalog.js.map +7 -0
- package/dist/modules/catalog/services/catalogOmnibusService.js +480 -0
- package/dist/modules/catalog/services/catalogOmnibusService.js.map +7 -0
- package/dist/modules/catalog/setup.js +3 -1
- package/dist/modules/catalog/setup.js.map +2 -2
- package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js +16 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-deleted.js.map +7 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js +17 -0
- package/dist/modules/catalog/subscribers/product-scope-keys-category-updated.js.map +7 -0
- package/dist/modules/catalog/translations.js +10 -0
- package/dist/modules/catalog/translations.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +28 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js +5 -0
- package/dist/modules/customer_groups/api/customer-groups/[id]/terms/route.js.map +2 -2
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js +111 -3
- package/dist/modules/customer_groups/components/CustomerGroupTermsSection.js.map +2 -2
- package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js +43 -0
- package/dist/modules/customer_groups/components/customerGroupAssortmentScope.js.map +7 -0
- package/dist/modules/customer_groups/data/entities.js +3 -0
- package/dist/modules/customer_groups/data/entities.js.map +2 -2
- package/dist/modules/customer_groups/data/validators.js +9 -0
- package/dist/modules/customer_groups/data/validators.js.map +2 -2
- package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js +17 -0
- package/dist/modules/customer_groups/migrations/Migration20261005110250_customer_groups.js.map +7 -0
- package/dist/modules/customer_groups/services/customerGroupsService.js +62 -15
- package/dist/modules/customer_groups/services/customerGroupsService.js.map +2 -2
- package/dist/modules/ecommerce/acl.js +13 -0
- package/dist/modules/ecommerce/acl.js.map +7 -0
- package/dist/modules/ecommerce/api/domain-mappings/route.js +72 -0
- package/dist/modules/ecommerce/api/domain-mappings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/openapi.js +27 -0
- package/dist/modules/ecommerce/api/openapi.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js +109 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/crud.js +265 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/route.js +67 -0
- package/dist/modules/ecommerce/api/store-channel-bindings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/crud.js +296 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/route.js +73 -0
- package/dist/modules/ecommerce/api/store-domain-bindings/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js +87 -0
- package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js +50 -0
- package/dist/modules/ecommerce/api/storefront/categories/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/categories/route.js +75 -0
- package/dist/modules/ecommerce/api/storefront/categories/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/context/route.js +163 -0
- package/dist/modules/ecommerce/api/storefront/context/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js +87 -0
- package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js +177 -0
- package/dist/modules/ecommerce/api/storefront/products/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/products/route.js +78 -0
- package/dist/modules/ecommerce/api/storefront/products/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js +25 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/route.js +75 -0
- package/dist/modules/ecommerce/api/storefront/search/suggest/route.js.map +7 -0
- package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js +58 -0
- package/dist/modules/ecommerce/api/storefront/storefrontRouteSupport.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/[id]/branding/route.js +183 -0
- package/dist/modules/ecommerce/api/stores/[id]/branding/route.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js +92 -0
- package/dist/modules/ecommerce/api/stores/[id]/preview-branding/route.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/crud.js +401 -0
- package/dist/modules/ecommerce/api/stores/crud.js.map +7 -0
- package/dist/modules/ecommerce/api/stores/route.js +64 -0
- package/dist/modules/ecommerce/api/stores/route.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js +9 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js +16 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.js +9 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.js.map +7 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js +16 -0
- package/dist/modules/ecommerce/backend/config/ecommerce/page.meta.js.map +7 -0
- package/dist/modules/ecommerce/commands/stores.js +110 -0
- package/dist/modules/ecommerce/commands/stores.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelAssortmentCount.js +90 -0
- package/dist/modules/ecommerce/components/ChannelAssortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelBindingFormSections.js +33 -0
- package/dist/modules/ecommerce/components/ChannelBindingFormSections.js.map +7 -0
- package/dist/modules/ecommerce/components/ChannelLookupPicker.js +11 -0
- package/dist/modules/ecommerce/components/ChannelLookupPicker.js.map +7 -0
- package/dist/modules/ecommerce/components/DomainStatusWarning.js +24 -0
- package/dist/modules/ecommerce/components/DomainStatusWarning.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js +190 -0
- package/dist/modules/ecommerce/components/StoreAvailabilityDefaultsSection.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingControls.js +67 -0
- package/dist/modules/ecommerce/components/StoreBrandingControls.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingPreview.js +69 -0
- package/dist/modules/ecommerce/components/StoreBrandingPreview.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreBrandingTab.js +218 -0
- package/dist/modules/ecommerce/components/StoreBrandingTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js +270 -0
- package/dist/modules/ecommerce/components/StoreChannelBindingDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreChannelsTab.js +313 -0
- package/dist/modules/ecommerce/components/StoreChannelsTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreCreateDialog.js +164 -0
- package/dist/modules/ecommerce/components/StoreCreateDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js +162 -0
- package/dist/modules/ecommerce/components/StoreDomainBindingDialog.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreDomainsTab.js +357 -0
- package/dist/modules/ecommerce/components/StoreDomainsTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreEditPage.js +155 -0
- package/dist/modules/ecommerce/components/StoreEditPage.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreGeneralTab.js +167 -0
- package/dist/modules/ecommerce/components/StoreGeneralTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreListPage.js +290 -0
- package/dist/modules/ecommerce/components/StoreListPage.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreSeoTab.js +132 -0
- package/dist/modules/ecommerce/components/StoreSeoTab.js.map +7 -0
- package/dist/modules/ecommerce/components/StoreStatusBadge.js +20 -0
- package/dist/modules/ecommerce/components/StoreStatusBadge.js.map +7 -0
- package/dist/modules/ecommerce/components/channelLookups.js +28 -0
- package/dist/modules/ecommerce/components/channelLookups.js.map +7 -0
- package/dist/modules/ecommerce/components/storeAdmin.js +41 -0
- package/dist/modules/ecommerce/components/storeAdmin.js.map +7 -0
- package/dist/modules/ecommerce/components/storeBrandingForm.js +197 -0
- package/dist/modules/ecommerce/components/storeBrandingForm.js.map +7 -0
- package/dist/modules/ecommerce/components/storeChannels.js +140 -0
- package/dist/modules/ecommerce/components/storeChannels.js.map +7 -0
- package/dist/modules/ecommerce/components/storeDomains.js +167 -0
- package/dist/modules/ecommerce/components/storeDomains.js.map +7 -0
- package/dist/modules/ecommerce/components/storeEditTabs.js +62 -0
- package/dist/modules/ecommerce/components/storeEditTabs.js.map +7 -0
- package/dist/modules/ecommerce/components/storeGeneral.js +95 -0
- package/dist/modules/ecommerce/components/storeGeneral.js.map +7 -0
- package/dist/modules/ecommerce/components/storeSeo.js +69 -0
- package/dist/modules/ecommerce/components/storeSeo.js.map +7 -0
- package/dist/modules/ecommerce/components/useChannelAssortmentCount.js +45 -0
- package/dist/modules/ecommerce/components/useChannelAssortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/components/useStoreAccess.js +28 -0
- package/dist/modules/ecommerce/components/useStoreAccess.js.map +7 -0
- package/dist/modules/ecommerce/data/enrichers.js +157 -0
- package/dist/modules/ecommerce/data/enrichers.js.map +7 -0
- package/dist/modules/ecommerce/data/entities.js +197 -0
- package/dist/modules/ecommerce/data/entities.js.map +7 -0
- package/dist/modules/ecommerce/data/validators.js +406 -0
- package/dist/modules/ecommerce/data/validators.js.map +7 -0
- package/dist/modules/ecommerce/di.js +11 -0
- package/dist/modules/ecommerce/di.js.map +7 -0
- package/dist/modules/ecommerce/events.js +27 -0
- package/dist/modules/ecommerce/events.js.map +7 -0
- package/dist/modules/ecommerce/index.js +16 -0
- package/dist/modules/ecommerce/index.js.map +7 -0
- package/dist/modules/ecommerce/lib/assortmentCount.js +112 -0
- package/dist/modules/ecommerce/lib/assortmentCount.js.map +7 -0
- package/dist/modules/ecommerce/lib/brandingStyles.js +184 -0
- package/dist/modules/ecommerce/lib/brandingStyles.js.map +7 -0
- package/dist/modules/ecommerce/lib/buyerContext.js +284 -0
- package/dist/modules/ecommerce/lib/buyerContext.js.map +7 -0
- package/dist/modules/ecommerce/lib/cacheInvalidation.js +186 -0
- package/dist/modules/ecommerce/lib/cacheInvalidation.js.map +7 -0
- package/dist/modules/ecommerce/lib/cacheKeys.js +236 -0
- package/dist/modules/ecommerce/lib/cacheKeys.js.map +7 -0
- package/dist/modules/ecommerce/lib/createConflictRecheck.js +29 -0
- package/dist/modules/ecommerce/lib/createConflictRecheck.js.map +7 -0
- package/dist/modules/ecommerce/lib/crudEvents.js +94 -0
- package/dist/modules/ecommerce/lib/crudEvents.js.map +7 -0
- package/dist/modules/ecommerce/lib/crudSupport.js +64 -0
- package/dist/modules/ecommerce/lib/crudSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/domainBindingRebind.js +99 -0
- package/dist/modules/ecommerce/lib/domainBindingRebind.js.map +7 -0
- package/dist/modules/ecommerce/lib/domainMappingSummaries.js +39 -0
- package/dist/modules/ecommerce/lib/domainMappingSummaries.js.map +7 -0
- package/dist/modules/ecommerce/lib/exclusiveFlag.js +57 -0
- package/dist/modules/ecommerce/lib/exclusiveFlag.js.map +7 -0
- package/dist/modules/ecommerce/lib/references.js +70 -0
- package/dist/modules/ecommerce/lib/references.js.map +7 -0
- package/dist/modules/ecommerce/lib/seedDraftStore.js +99 -0
- package/dist/modules/ecommerce/lib/seedDraftStore.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBindingCascade.js +109 -0
- package/dist/modules/ecommerce/lib/storeBindingCascade.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBranding.js +40 -0
- package/dist/modules/ecommerce/lib/storeBranding.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeBrandingRoute.js +76 -0
- package/dist/modules/ecommerce/lib/storeBrandingRoute.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeContext.js +393 -0
- package/dist/modules/ecommerce/lib/storeContext.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeContextService.js +43 -0
- package/dist/modules/ecommerce/lib/storeContextService.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeLocale.js +60 -0
- package/dist/modules/ecommerce/lib/storeLocale.js.map +7 -0
- package/dist/modules/ecommerce/lib/storeNotifications.js +41 -0
- package/dist/modules/ecommerce/lib/storeNotifications.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js +248 -0
- package/dist/modules/ecommerce/lib/storefrontCatalogSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCategories.js +241 -0
- package/dist/modules/ecommerce/lib/storefrontCategories.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontCategoryCache.js +71 -0
- package/dist/modules/ecommerce/lib/storefrontCategoryCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontDetail.js +447 -0
- package/dist/modules/ecommerce/lib/storefrontDetail.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontFacets.js +441 -0
- package/dist/modules/ecommerce/lib/storefrontFacets.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontOptionFilter.js +15 -0
- package/dist/modules/ecommerce/lib/storefrontOptionFilter.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontPricing.js +393 -0
- package/dist/modules/ecommerce/lib/storefrontPricing.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProductCache.js +90 -0
- package/dist/modules/ecommerce/lib/storefrontProductCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProductScope.js +107 -0
- package/dist/modules/ecommerce/lib/storefrontProductScope.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontProducts.js +670 -0
- package/dist/modules/ecommerce/lib/storefrontProducts.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontQuery.js +156 -0
- package/dist/modules/ecommerce/lib/storefrontQuery.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontRateLimit.js +99 -0
- package/dist/modules/ecommerce/lib/storefrontRateLimit.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontSearch.js +303 -0
- package/dist/modules/ecommerce/lib/storefrontSearch.js.map +7 -0
- package/dist/modules/ecommerce/lib/storefrontSearchCache.js +35 -0
- package/dist/modules/ecommerce/lib/storefrontSearchCache.js.map +7 -0
- package/dist/modules/ecommerce/lib/subscriberSupport.js +33 -0
- package/dist/modules/ecommerce/lib/subscriberSupport.js.map +7 -0
- package/dist/modules/ecommerce/lib/types.js +1 -0
- package/dist/modules/ecommerce/lib/types.js.map +7 -0
- package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js +32 -0
- package/dist/modules/ecommerce/migrations/Migration20261005113233_ecommerce.js.map +7 -0
- package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js +17 -0
- package/dist/modules/ecommerce/migrations/Migration20261006112733_ecommerce.js.map +7 -0
- package/dist/modules/ecommerce/notifications.client.js +47 -0
- package/dist/modules/ecommerce/notifications.client.js.map +7 -0
- package/dist/modules/ecommerce/notifications.js +48 -0
- package/dist/modules/ecommerce/notifications.js.map +7 -0
- package/dist/modules/ecommerce/search.js +83 -0
- package/dist/modules/ecommerce/search.js.map +7 -0
- package/dist/modules/ecommerce/setup.js +17 -0
- package/dist/modules/ecommerce/setup.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js +14 -0
- package/dist/modules/ecommerce/subscribers/assortment-empty-notifications.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/availability-policy-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-category-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-price-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-product-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js +16 -0
- package/dist/modules/ecommerce/subscribers/domain-binding-rebind.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.js.map +7 -0
- package/dist/modules/ecommerce/subscribers/store-notifications.js +14 -0
- package/dist/modules/ecommerce/subscribers/store-notifications.js.map +7 -0
- package/dist/modules/query_index/lib/batch.js +23 -9
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/doc-enrichers.js +212 -0
- package/dist/modules/query_index/lib/doc-enrichers.js.map +7 -0
- package/dist/modules/query_index/lib/document.js +2 -0
- package/dist/modules/query_index/lib/document.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +68 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +7 -0
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +2 -0
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js +17 -0
- package/dist/modules/query_index/migrations/Migration20261005201500_query_index.js.map +7 -0
- package/dist/modules/translations/components/TranslationManager.js +3 -3
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/data/validators.js +1 -1
- package/dist/modules/translations/data/validators.js.map +1 -1
- package/dist/modules/translations/lib/batch.js +21 -1
- package/dist/modules/translations/lib/batch.js.map +2 -2
- package/dist/modules/translations/lib/helpers.js +3 -0
- package/dist/modules/translations/lib/helpers.js.map +2 -2
- package/dist/modules/translations/lib/resolve-field-list.js +14 -2
- package/dist/modules/translations/lib/resolve-field-list.js.map +2 -2
- package/generated/entities/catalog_price_history_entry/index.ts +25 -0
- package/generated/entities/customer_group_terms/index.ts +1 -0
- package/generated/entities/ecommerce_store/index.ts +15 -0
- package/generated/entities/ecommerce_store_channel_binding/index.ts +13 -0
- package/generated/entities/ecommerce_store_domain_binding/index.ts +10 -0
- package/generated/entities.ids.generated.ts +8 -1
- package/generated/entity-fields-registry.ts +72 -0
- package/package.json +7 -7
- package/src/helpers/integration/customerGroupsFixtures.ts +2 -0
- package/src/modules/auth/i18n/de.json +8 -0
- package/src/modules/auth/i18n/en.json +8 -0
- package/src/modules/auth/i18n/es.json +8 -0
- package/src/modules/auth/i18n/ko.json +8 -0
- package/src/modules/auth/i18n/pl.json +8 -0
- package/src/modules/catalog/AGENTS.md +5 -2
- package/src/modules/catalog/acl.ts +7 -0
- package/src/modules/catalog/api/config/omnibus/route.ts +204 -0
- package/src/modules/catalog/api/prices/history/route.ts +139 -0
- package/src/modules/catalog/api/prices/omnibus-preview/route.ts +202 -0
- package/src/modules/catalog/api/products/route.ts +53 -308
- package/src/modules/catalog/api/tags/route.ts +6 -0
- package/src/modules/catalog/backend/config/catalog/page.tsx +2 -0
- package/src/modules/catalog/cli.ts +84 -1
- package/src/modules/catalog/commands/categories.ts +54 -2
- package/src/modules/catalog/commands/prices.ts +43 -1
- package/src/modules/catalog/commands/products.ts +84 -1
- package/src/modules/catalog/commands/variants.ts +7 -0
- package/src/modules/catalog/components/OmnibusSettings.tsx +832 -0
- package/src/modules/catalog/components/PriceEditorOmnibusRow.tsx +219 -0
- package/src/modules/catalog/components/lookupSources.ts +29 -0
- package/src/modules/catalog/components/prices/PriceScopeSelectors.tsx +9 -0
- package/src/modules/catalog/components/products/VariantBuilder.tsx +9 -0
- package/src/modules/catalog/data/entities.ts +123 -1
- package/src/modules/catalog/data/validators.ts +118 -0
- package/src/modules/catalog/di.ts +23 -0
- package/src/modules/catalog/i18n/de.json +77 -0
- package/src/modules/catalog/i18n/en.json +77 -0
- package/src/modules/catalog/i18n/es.json +77 -0
- package/src/modules/catalog/i18n/ko.json +77 -0
- package/src/modules/catalog/i18n/pl.json +77 -0
- package/src/modules/catalog/lib/omnibus.ts +406 -0
- package/src/modules/catalog/lib/omnibusBackfill.ts +198 -0
- package/src/modules/catalog/lib/omnibusCache.ts +111 -0
- package/src/modules/catalog/lib/omnibusConfig.ts +73 -0
- package/src/modules/catalog/lib/omnibusHistoryQueries.ts +248 -0
- package/src/modules/catalog/lib/omnibusPresentedEntry.ts +76 -0
- package/src/modules/catalog/lib/omnibusProductListEnrichment.ts +125 -0
- package/src/modules/catalog/lib/omnibusTypes.ts +202 -0
- package/src/modules/catalog/lib/optionSchemaTranslations.ts +55 -0
- package/src/modules/catalog/lib/priceHistoryQuery.ts +155 -0
- package/src/modules/catalog/lib/pricing.ts +42 -4
- package/src/modules/catalog/lib/productFilters.ts +349 -0
- package/src/modules/catalog/lib/productScopeKeys.ts +162 -0
- package/src/modules/catalog/lib/productScopeReindex.ts +139 -0
- package/src/modules/catalog/migrations/.snapshot-open-mercato.json +572 -0
- package/src/modules/catalog/migrations/Migration20261005105352_catalog.ts +39 -0
- package/src/modules/catalog/migrations/Migration20261005150824_catalog.ts +39 -0
- package/src/modules/catalog/services/catalogOmnibusService.ts +642 -0
- package/src/modules/catalog/setup.ts +2 -0
- package/src/modules/catalog/subscribers/product-scope-keys-category-deleted.ts +18 -0
- package/src/modules/catalog/subscribers/product-scope-keys-category-updated.ts +19 -0
- package/src/modules/catalog/translations.ts +12 -0
- package/src/modules/configs/i18n/de.json +5 -1
- package/src/modules/configs/i18n/en.json +5 -1
- package/src/modules/configs/i18n/es.json +5 -1
- package/src/modules/configs/i18n/ko.json +5 -1
- package/src/modules/configs/i18n/pl.json +5 -1
- package/src/modules/configs/lib/upgrade-actions.ts +35 -0
- package/src/modules/customer_groups/api/customer-groups/[id]/terms/route.ts +7 -0
- package/src/modules/customer_groups/components/CustomerGroupTermsSection.tsx +124 -2
- package/src/modules/customer_groups/components/customerGroupAssortmentScope.ts +46 -0
- package/src/modules/customer_groups/data/entities.ts +4 -0
- package/src/modules/customer_groups/data/validators.ts +14 -0
- package/src/modules/customer_groups/i18n/de.json +12 -0
- package/src/modules/customer_groups/i18n/en.json +12 -0
- package/src/modules/customer_groups/i18n/es.json +12 -0
- package/src/modules/customer_groups/i18n/ko.json +12 -0
- package/src/modules/customer_groups/i18n/pl.json +12 -0
- package/src/modules/customer_groups/migrations/.snapshot-open-mercato.json +17 -0
- package/src/modules/customer_groups/migrations/Migration20261005110250_customer_groups.ts +15 -0
- package/src/modules/customer_groups/services/customerGroupsService.ts +74 -23
- package/src/modules/ecommerce/acl.ts +9 -0
- package/src/modules/ecommerce/api/domain-mappings/route.ts +76 -0
- package/src/modules/ecommerce/api/openapi.ts +28 -0
- package/src/modules/ecommerce/api/store-channel-bindings/[id]/assortment-count/route.ts +141 -0
- package/src/modules/ecommerce/api/store-channel-bindings/crud.ts +283 -0
- package/src/modules/ecommerce/api/store-channel-bindings/route.ts +67 -0
- package/src/modules/ecommerce/api/store-domain-bindings/crud.ts +324 -0
- package/src/modules/ecommerce/api/store-domain-bindings/route.ts +73 -0
- package/src/modules/ecommerce/api/storefront/categories/[slug]/route.ts +94 -0
- package/src/modules/ecommerce/api/storefront/categories/openapiSchemas.ts +63 -0
- package/src/modules/ecommerce/api/storefront/categories/route.ts +78 -0
- package/src/modules/ecommerce/api/storefront/context/route.ts +203 -0
- package/src/modules/ecommerce/api/storefront/products/[idOrHandle]/route.ts +94 -0
- package/src/modules/ecommerce/api/storefront/products/openapiSchemas.ts +193 -0
- package/src/modules/ecommerce/api/storefront/products/route.ts +81 -0
- package/src/modules/ecommerce/api/storefront/search/suggest/openapiSchemas.ts +25 -0
- package/src/modules/ecommerce/api/storefront/search/suggest/route.ts +78 -0
- package/src/modules/ecommerce/api/storefront/storefrontRouteSupport.ts +68 -0
- package/src/modules/ecommerce/api/stores/[id]/branding/route.ts +205 -0
- package/src/modules/ecommerce/api/stores/[id]/preview-branding/route.ts +99 -0
- package/src/modules/ecommerce/api/stores/crud.ts +457 -0
- package/src/modules/ecommerce/api/stores/route.ts +66 -0
- package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.meta.ts +12 -0
- package/src/modules/ecommerce/backend/config/ecommerce/[id]/page.tsx +5 -0
- package/src/modules/ecommerce/backend/config/ecommerce/page.meta.ts +12 -0
- package/src/modules/ecommerce/backend/config/ecommerce/page.tsx +5 -0
- package/src/modules/ecommerce/commands/stores.ts +154 -0
- package/src/modules/ecommerce/components/ChannelAssortmentCount.tsx +138 -0
- package/src/modules/ecommerce/components/ChannelBindingFormSections.tsx +40 -0
- package/src/modules/ecommerce/components/ChannelLookupPicker.tsx +5 -0
- package/src/modules/ecommerce/components/DomainStatusWarning.tsx +32 -0
- package/src/modules/ecommerce/components/StoreAvailabilityDefaultsSection.tsx +219 -0
- package/src/modules/ecommerce/components/StoreBrandingControls.tsx +73 -0
- package/src/modules/ecommerce/components/StoreBrandingPreview.tsx +77 -0
- package/src/modules/ecommerce/components/StoreBrandingTab.tsx +242 -0
- package/src/modules/ecommerce/components/StoreChannelBindingDialog.tsx +306 -0
- package/src/modules/ecommerce/components/StoreChannelsTab.tsx +375 -0
- package/src/modules/ecommerce/components/StoreCreateDialog.tsx +204 -0
- package/src/modules/ecommerce/components/StoreDomainBindingDialog.tsx +198 -0
- package/src/modules/ecommerce/components/StoreDomainsTab.tsx +426 -0
- package/src/modules/ecommerce/components/StoreEditPage.tsx +193 -0
- package/src/modules/ecommerce/components/StoreGeneralTab.tsx +189 -0
- package/src/modules/ecommerce/components/StoreListPage.tsx +326 -0
- package/src/modules/ecommerce/components/StoreSeoTab.tsx +152 -0
- package/src/modules/ecommerce/components/StoreStatusBadge.tsx +22 -0
- package/src/modules/ecommerce/components/channelLookups.ts +24 -0
- package/src/modules/ecommerce/components/storeAdmin.ts +56 -0
- package/src/modules/ecommerce/components/storeBrandingForm.ts +230 -0
- package/src/modules/ecommerce/components/storeChannels.ts +210 -0
- package/src/modules/ecommerce/components/storeDomains.ts +221 -0
- package/src/modules/ecommerce/components/storeEditTabs.tsx +76 -0
- package/src/modules/ecommerce/components/storeGeneral.ts +155 -0
- package/src/modules/ecommerce/components/storeSeo.ts +78 -0
- package/src/modules/ecommerce/components/useChannelAssortmentCount.ts +67 -0
- package/src/modules/ecommerce/components/useStoreAccess.ts +36 -0
- package/src/modules/ecommerce/data/enrichers.ts +213 -0
- package/src/modules/ecommerce/data/entities.ts +168 -0
- package/src/modules/ecommerce/data/validators.ts +587 -0
- package/src/modules/ecommerce/di.ts +9 -0
- package/src/modules/ecommerce/events.ts +27 -0
- package/src/modules/ecommerce/i18n/de.json +341 -0
- package/src/modules/ecommerce/i18n/en.json +341 -0
- package/src/modules/ecommerce/i18n/es.json +341 -0
- package/src/modules/ecommerce/i18n/ko.json +341 -0
- package/src/modules/ecommerce/i18n/pl.json +341 -0
- package/src/modules/ecommerce/index.ts +14 -0
- package/src/modules/ecommerce/lib/assortmentCount.ts +175 -0
- package/src/modules/ecommerce/lib/brandingStyles.ts +215 -0
- package/src/modules/ecommerce/lib/buyerContext.ts +401 -0
- package/src/modules/ecommerce/lib/cacheInvalidation.ts +302 -0
- package/src/modules/ecommerce/lib/cacheKeys.ts +340 -0
- package/src/modules/ecommerce/lib/createConflictRecheck.ts +31 -0
- package/src/modules/ecommerce/lib/crudEvents.ts +128 -0
- package/src/modules/ecommerce/lib/crudSupport.ts +85 -0
- package/src/modules/ecommerce/lib/domainBindingRebind.ts +138 -0
- package/src/modules/ecommerce/lib/domainMappingSummaries.ts +71 -0
- package/src/modules/ecommerce/lib/exclusiveFlag.ts +90 -0
- package/src/modules/ecommerce/lib/references.ts +93 -0
- package/src/modules/ecommerce/lib/seedDraftStore.ts +125 -0
- package/src/modules/ecommerce/lib/storeBindingCascade.ts +138 -0
- package/src/modules/ecommerce/lib/storeBranding.ts +48 -0
- package/src/modules/ecommerce/lib/storeBrandingRoute.ts +91 -0
- package/src/modules/ecommerce/lib/storeContext.ts +669 -0
- package/src/modules/ecommerce/lib/storeContextService.ts +71 -0
- package/src/modules/ecommerce/lib/storeLocale.ts +88 -0
- package/src/modules/ecommerce/lib/storeNotifications.ts +55 -0
- package/src/modules/ecommerce/lib/storefrontCatalogSupport.ts +427 -0
- package/src/modules/ecommerce/lib/storefrontCategories.ts +419 -0
- package/src/modules/ecommerce/lib/storefrontCategoryCache.ts +113 -0
- package/src/modules/ecommerce/lib/storefrontDetail.ts +654 -0
- package/src/modules/ecommerce/lib/storefrontFacets.ts +697 -0
- package/src/modules/ecommerce/lib/storefrontOptionFilter.ts +44 -0
- package/src/modules/ecommerce/lib/storefrontPricing.ts +583 -0
- package/src/modules/ecommerce/lib/storefrontProductCache.ts +126 -0
- package/src/modules/ecommerce/lib/storefrontProductScope.ts +181 -0
- package/src/modules/ecommerce/lib/storefrontProducts.ts +963 -0
- package/src/modules/ecommerce/lib/storefrontQuery.ts +215 -0
- package/src/modules/ecommerce/lib/storefrontRateLimit.ts +126 -0
- package/src/modules/ecommerce/lib/storefrontSearch.ts +454 -0
- package/src/modules/ecommerce/lib/storefrontSearchCache.ts +49 -0
- package/src/modules/ecommerce/lib/subscriberSupport.ts +41 -0
- package/src/modules/ecommerce/lib/types.ts +69 -0
- package/src/modules/ecommerce/migrations/.snapshot-open-mercato.json +829 -0
- package/src/modules/ecommerce/migrations/Migration20261005113233_ecommerce.ts +32 -0
- package/src/modules/ecommerce/migrations/Migration20261006112733_ecommerce.ts +15 -0
- package/src/modules/ecommerce/notifications.client.ts +46 -0
- package/src/modules/ecommerce/notifications.ts +46 -0
- package/src/modules/ecommerce/search.ts +93 -0
- package/src/modules/ecommerce/setup.ts +15 -0
- package/src/modules/ecommerce/subscribers/assortment-empty-notifications.ts +12 -0
- package/src/modules/ecommerce/subscribers/availability-policy-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-category-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-price-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-product-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/catalog-variant-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-membership-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-group-terms-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-user-deleted-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/customer-user-updated-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/domain-binding-rebind.ts +14 -0
- package/src/modules/ecommerce/subscribers/domain-mapping-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-channel-binding-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-domain-binding-cache-invalidation.ts +12 -0
- package/src/modules/ecommerce/subscribers/store-notifications.ts +12 -0
- package/src/modules/query_index/lib/batch.ts +25 -9
- package/src/modules/query_index/lib/doc-enrichers.ts +306 -0
- package/src/modules/query_index/lib/document.ts +2 -0
- package/src/modules/query_index/lib/engine.ts +58 -1
- package/src/modules/query_index/lib/indexer.ts +8 -0
- package/src/modules/query_index/lib/search-tokens.ts +2 -0
- package/src/modules/query_index/migrations/Migration20261005201500_query_index.ts +42 -0
- package/src/modules/translations/components/TranslationManager.tsx +3 -3
- package/src/modules/translations/data/validators.ts +1 -1
- package/src/modules/translations/lib/batch.ts +47 -0
- package/src/modules/translations/lib/helpers.ts +4 -0
- package/src/modules/translations/lib/resolve-field-list.ts +16 -2
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Plus, Trash2 } from "lucide-react";
|
|
5
|
+
import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
|
|
6
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
|
+
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
8
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
9
|
+
import { FormField } from "@open-mercato/ui/primitives/form-field";
|
|
10
|
+
import { SwitchField } from "@open-mercato/ui/primitives/switch-field";
|
|
11
|
+
import { TagInput } from "@open-mercato/ui/primitives/tag-input";
|
|
12
|
+
import {
|
|
13
|
+
Select,
|
|
14
|
+
SelectContent,
|
|
15
|
+
SelectItem,
|
|
16
|
+
SelectTrigger,
|
|
17
|
+
SelectValue
|
|
18
|
+
} from "@open-mercato/ui/primitives/select";
|
|
19
|
+
import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
|
|
20
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
21
|
+
import { useBackendChrome } from "@open-mercato/ui/backend/BackendChromeProvider";
|
|
22
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
23
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
24
|
+
import { hasFeature } from "@open-mercato/shared/security/features";
|
|
25
|
+
import { useOrganizationScopeDetail, useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
26
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
27
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
28
|
+
import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
|
|
29
|
+
import { PriceChannelSelect, PricePriceKindSelect } from "./prices/PriceScopeSelectors.js";
|
|
30
|
+
const logger = createLogger("catalog").child({ component: "OmnibusSettings" });
|
|
31
|
+
const OMNIBUS_CONFIG_PATH = "/api/catalog/config/omnibus";
|
|
32
|
+
const MUTATION_CONTEXT_ID = "catalog-omnibus-settings";
|
|
33
|
+
const DEFAULT_LOOKBACK_DAYS = 30;
|
|
34
|
+
const MIN_LOOKBACK_DAYS = 1;
|
|
35
|
+
const MAX_LOOKBACK_DAYS = 365;
|
|
36
|
+
const COUNTRY_CODE_PATTERN = /^[A-Z]{2}$/;
|
|
37
|
+
class OmnibusSaveError extends Error {
|
|
38
|
+
constructor(status, body) {
|
|
39
|
+
super(`[internal] catalog omnibus config save failed with status ${status}`);
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.body = body;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let rowSequence = 0;
|
|
45
|
+
function nextRowKey() {
|
|
46
|
+
rowSequence += 1;
|
|
47
|
+
return `omnibus-channel-${rowSequence}`;
|
|
48
|
+
}
|
|
49
|
+
function toFormState(config) {
|
|
50
|
+
const channels = Object.entries(config?.channels ?? {}).map(([channelId, channel]) => ({
|
|
51
|
+
key: nextRowKey(),
|
|
52
|
+
channelId,
|
|
53
|
+
presentedPriceKindId: channel.presentedPriceKindId ?? "",
|
|
54
|
+
countryCode: channel.countryCode ?? "",
|
|
55
|
+
lookbackDays: typeof channel.lookbackDays === "number" ? String(channel.lookbackDays) : "",
|
|
56
|
+
minimizationAxis: channel.minimizationAxis ?? "inherit"
|
|
57
|
+
}));
|
|
58
|
+
return {
|
|
59
|
+
enabled: config?.enabled === true,
|
|
60
|
+
lookbackDays: String(config?.lookbackDays ?? DEFAULT_LOOKBACK_DAYS),
|
|
61
|
+
enabledCountryCodes: Array.isArray(config?.enabledCountryCodes) ? [...config.enabledCountryCodes] : [],
|
|
62
|
+
noChannelMode: config?.noChannelMode ?? "best_effort",
|
|
63
|
+
minimizationAxis: config?.minimizationAxis ?? "gross",
|
|
64
|
+
defaultPresentedPriceKindId: config?.defaultPresentedPriceKindId ?? "",
|
|
65
|
+
channels
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function parseLookbackDays(raw) {
|
|
69
|
+
const trimmed = raw.trim();
|
|
70
|
+
if (!/^\d+$/.test(trimmed)) return null;
|
|
71
|
+
const value = Number(trimmed);
|
|
72
|
+
if (!Number.isInteger(value) || value < MIN_LOOKBACK_DAYS || value > MAX_LOOKBACK_DAYS) return null;
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
function channelErrorKey(rowKey, field) {
|
|
76
|
+
return `channels.${rowKey}.${field}`;
|
|
77
|
+
}
|
|
78
|
+
function isRecord(value) {
|
|
79
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
80
|
+
}
|
|
81
|
+
function asStoredConfig(value) {
|
|
82
|
+
return isRecord(value) ? value : null;
|
|
83
|
+
}
|
|
84
|
+
function listStaleBackfillScopes(stored, form) {
|
|
85
|
+
const coverage = stored?.backfillCoverage ?? {};
|
|
86
|
+
const globalLookback = parseLookbackDays(form.lookbackDays);
|
|
87
|
+
if (globalLookback === null) return [];
|
|
88
|
+
const channelLookbacks = new Map(
|
|
89
|
+
form.channels.filter((row) => row.channelId).map((row) => [row.channelId, parseLookbackDays(row.lookbackDays) ?? globalLookback])
|
|
90
|
+
);
|
|
91
|
+
return Object.entries(coverage).filter(([scopeId, entry]) => {
|
|
92
|
+
const effective = scopeId ? channelLookbacks.get(scopeId) ?? globalLookback : globalLookback;
|
|
93
|
+
return entry.lookbackDays < effective;
|
|
94
|
+
}).map(([scopeId]) => scopeId).sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
95
|
+
}
|
|
96
|
+
function OmnibusSettings() {
|
|
97
|
+
const t = useT();
|
|
98
|
+
const scopeVersion = useOrganizationScopeVersion();
|
|
99
|
+
const scopeTenantId = useOrganizationScopeDetail().tenantId;
|
|
100
|
+
const { payload: chromePayload, isReady: chromeReady } = useBackendChrome();
|
|
101
|
+
const grantedFeatures = chromePayload?.grantedFeatures;
|
|
102
|
+
const canManage = hasFeature(grantedFeatures, "catalog.settings.manage");
|
|
103
|
+
const canView = canManage || hasFeature(grantedFeatures, "catalog.settings.view");
|
|
104
|
+
const [stored, setStored] = React.useState(null);
|
|
105
|
+
const [form, setForm] = React.useState(() => toFormState(null));
|
|
106
|
+
const [loading, setLoading] = React.useState(true);
|
|
107
|
+
const [loadError, setLoadError] = React.useState(null);
|
|
108
|
+
const [saving, setSaving] = React.useState(false);
|
|
109
|
+
const [fieldErrors, setFieldErrors] = React.useState({});
|
|
110
|
+
const [formError, setFormError] = React.useState(null);
|
|
111
|
+
const [backfillChannels, setBackfillChannels] = React.useState(null);
|
|
112
|
+
const [backfillChannelNames, setBackfillChannelNames] = React.useState({});
|
|
113
|
+
const [reloadToken, setReloadToken] = React.useState(0);
|
|
114
|
+
const loadedSourceRef = React.useRef(null);
|
|
115
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
116
|
+
contextId: MUTATION_CONTEXT_ID,
|
|
117
|
+
blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
|
|
118
|
+
});
|
|
119
|
+
const readOnly = !canManage || saving;
|
|
120
|
+
const errorMessages = React.useMemo(() => ({
|
|
121
|
+
omnibus_country_code_alpha2_required: t("catalog.omnibus.errors.countryCodeFormat", "Use a two-letter ISO country code."),
|
|
122
|
+
omnibus_country_code_eu_not_allowed: t("catalog.omnibus.errors.countryCodeEu", 'List individual member states instead of "EU".'),
|
|
123
|
+
omnibus_country_code_unknown: t("catalog.omnibus.errors.countryCodeUnknown", "Unknown country code."),
|
|
124
|
+
omnibus_presented_price_kind_required: t("catalog.omnibus.errors.presentedPriceKindRequired", "Select a default presented price kind, or configure a channel with its own price kind."),
|
|
125
|
+
omnibus_field_not_supported: t("catalog.omnibus.errors.fieldNotSupported", "This setting is not supported."),
|
|
126
|
+
omnibus_derogation_not_supported: t("catalog.omnibus.errors.fieldNotSupported", "This setting is not supported."),
|
|
127
|
+
omnibus_backfill_coverage_read_only: t("catalog.omnibus.errors.fieldNotSupported", "This setting is not supported.")
|
|
128
|
+
}), [t]);
|
|
129
|
+
const invalidValueMessage = t("catalog.omnibus.errors.invalidValue", "Invalid value.");
|
|
130
|
+
const lookbackRangeMessage = t("catalog.omnibus.errors.lookbackRange", "Enter a whole number of days between 1 and 365.");
|
|
131
|
+
const requiredMessage = t("catalog.omnibus.errors.required", "This field is required.");
|
|
132
|
+
const duplicateChannelMessage = t("catalog.omnibus.errors.duplicateChannel", "This channel is already configured.");
|
|
133
|
+
const saveErrorMessage = t("catalog.omnibus.errors.save", "Failed to save Omnibus settings.");
|
|
134
|
+
const staleBackfillScopes = React.useMemo(() => listStaleBackfillScopes(stored, form), [form, stored]);
|
|
135
|
+
const channelNameLookupKey = React.useMemo(
|
|
136
|
+
() => Array.from(new Set([...backfillChannels ?? [], ...staleBackfillScopes].filter((channelId) => channelId.length > 0))).sort((left, right) => left < right ? -1 : left > right ? 1 : 0).join(","),
|
|
137
|
+
[backfillChannels, staleBackfillScopes]
|
|
138
|
+
);
|
|
139
|
+
React.useEffect(() => {
|
|
140
|
+
const channelIds = channelNameLookupKey ? channelNameLookupKey.split(",") : [];
|
|
141
|
+
if (!channelIds.length) return;
|
|
142
|
+
let cancelled = false;
|
|
143
|
+
const query = new URLSearchParams({ ids: channelIds.join(","), pageSize: String(Math.min(channelIds.length, 100)) });
|
|
144
|
+
apiCall(`/api/sales/channels?${query.toString()}`).then((call) => {
|
|
145
|
+
if (cancelled || !call?.ok) return;
|
|
146
|
+
const items = Array.isArray(call.result?.items) ? call.result.items : [];
|
|
147
|
+
const names = {};
|
|
148
|
+
for (const item of items) {
|
|
149
|
+
if (typeof item.id === "string" && typeof item.name === "string" && item.name.length) names[item.id] = item.name;
|
|
150
|
+
}
|
|
151
|
+
setBackfillChannelNames((previous) => ({ ...previous, ...names }));
|
|
152
|
+
}).catch((err) => {
|
|
153
|
+
logger.warn("catalog.omnibus.settings.backfillChannelNames failed", { err });
|
|
154
|
+
getTelemetryRuntime()?.reportError(err, { module: "catalog", code: "catalog.omnibus_channel_names_load_failed" });
|
|
155
|
+
});
|
|
156
|
+
return () => {
|
|
157
|
+
cancelled = true;
|
|
158
|
+
};
|
|
159
|
+
}, [channelNameLookupKey]);
|
|
160
|
+
const loadErrorMessage = t("catalog.omnibus.errors.load", "Failed to load Omnibus settings.");
|
|
161
|
+
React.useEffect(() => {
|
|
162
|
+
if (!chromeReady || !canView) return;
|
|
163
|
+
let cancelled = false;
|
|
164
|
+
const previous = loadedSourceRef.current;
|
|
165
|
+
if (!previous) setLoading(true);
|
|
166
|
+
setLoadError(null);
|
|
167
|
+
apiCall(OMNIBUS_CONFIG_PATH).then((call) => {
|
|
168
|
+
if (cancelled) return;
|
|
169
|
+
if (!call.ok) {
|
|
170
|
+
loadedSourceRef.current = null;
|
|
171
|
+
setLoadError(loadErrorMessage);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const config = asStoredConfig(call.result);
|
|
175
|
+
const configKey = JSON.stringify(config);
|
|
176
|
+
const keepsEdits = previous !== null && previous.configKey === configKey && (previous.tenantId === null || previous.tenantId === scopeTenantId);
|
|
177
|
+
loadedSourceRef.current = { tenantId: scopeTenantId, configKey };
|
|
178
|
+
setStored(config);
|
|
179
|
+
if (keepsEdits) return;
|
|
180
|
+
setForm(toFormState(config));
|
|
181
|
+
setFieldErrors({});
|
|
182
|
+
setFormError(null);
|
|
183
|
+
setBackfillChannels(null);
|
|
184
|
+
}).catch((err) => {
|
|
185
|
+
logger.error("catalog.omnibus.settings.load failed", { err });
|
|
186
|
+
getTelemetryRuntime()?.reportError(err, { module: "catalog", code: "catalog.omnibus_settings_load_failed" });
|
|
187
|
+
if (!cancelled) setLoadError(loadErrorMessage);
|
|
188
|
+
}).finally(() => {
|
|
189
|
+
if (!cancelled) setLoading(false);
|
|
190
|
+
});
|
|
191
|
+
return () => {
|
|
192
|
+
cancelled = true;
|
|
193
|
+
};
|
|
194
|
+
}, [canView, chromeReady, loadErrorMessage, reloadToken, scopeTenantId, scopeVersion]);
|
|
195
|
+
const translateServerError = React.useCallback(
|
|
196
|
+
(messages) => {
|
|
197
|
+
const first = Array.isArray(messages) ? messages.find((entry) => typeof entry === "string") : null;
|
|
198
|
+
if (typeof first !== "string") return invalidValueMessage;
|
|
199
|
+
return errorMessages[first] ?? invalidValueMessage;
|
|
200
|
+
},
|
|
201
|
+
[errorMessages, invalidValueMessage]
|
|
202
|
+
);
|
|
203
|
+
const mapServerFieldErrors = React.useCallback(
|
|
204
|
+
(raw) => {
|
|
205
|
+
const fields = {};
|
|
206
|
+
let unmatched = null;
|
|
207
|
+
for (const [path, messages] of Object.entries(raw)) {
|
|
208
|
+
const message = translateServerError(messages);
|
|
209
|
+
const segments = path.split(".");
|
|
210
|
+
const head = segments[0];
|
|
211
|
+
if (head === "channels" && segments.length >= 2) {
|
|
212
|
+
const row = form.channels.find((entry) => entry.channelId === segments[1]);
|
|
213
|
+
const field = segments[2] ?? "channelId";
|
|
214
|
+
if (row) {
|
|
215
|
+
fields[channelErrorKey(row.key, field)] = message;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
} else if (head && head !== "_root" && head in form) {
|
|
219
|
+
fields[head] = fields[head] ?? message;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
unmatched = unmatched ?? message;
|
|
223
|
+
}
|
|
224
|
+
return { fields, unmatched };
|
|
225
|
+
},
|
|
226
|
+
[form, translateServerError]
|
|
227
|
+
);
|
|
228
|
+
const buildPatch = React.useCallback(() => {
|
|
229
|
+
const errors = {};
|
|
230
|
+
const lookbackDays = parseLookbackDays(form.lookbackDays);
|
|
231
|
+
if (lookbackDays === null) errors.lookbackDays = lookbackRangeMessage;
|
|
232
|
+
const channels = {};
|
|
233
|
+
for (const row of form.channels) {
|
|
234
|
+
const channelId = row.channelId.trim();
|
|
235
|
+
if (!channelId) {
|
|
236
|
+
errors[channelErrorKey(row.key, "channelId")] = requiredMessage;
|
|
237
|
+
} else if (channels[channelId]) {
|
|
238
|
+
errors[channelErrorKey(row.key, "channelId")] = duplicateChannelMessage;
|
|
239
|
+
}
|
|
240
|
+
if (!row.presentedPriceKindId) errors[channelErrorKey(row.key, "presentedPriceKindId")] = requiredMessage;
|
|
241
|
+
const countryCode = row.countryCode.trim().toUpperCase();
|
|
242
|
+
if (countryCode && !COUNTRY_CODE_PATTERN.test(countryCode)) {
|
|
243
|
+
errors[channelErrorKey(row.key, "countryCode")] = errorMessages.omnibus_country_code_alpha2_required;
|
|
244
|
+
}
|
|
245
|
+
const channelLookback = row.lookbackDays.trim() ? parseLookbackDays(row.lookbackDays) : void 0;
|
|
246
|
+
if (channelLookback === null) errors[channelErrorKey(row.key, "lookbackDays")] = lookbackRangeMessage;
|
|
247
|
+
if (!channelId || channels[channelId]) continue;
|
|
248
|
+
channels[channelId] = {
|
|
249
|
+
presentedPriceKindId: row.presentedPriceKindId,
|
|
250
|
+
...countryCode ? { countryCode } : {},
|
|
251
|
+
...typeof channelLookback === "number" ? { lookbackDays: channelLookback } : {},
|
|
252
|
+
...row.minimizationAxis !== "inherit" ? { minimizationAxis: row.minimizationAxis } : {}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (Object.keys(errors).length > 0 || lookbackDays === null) return { patch: null, errors };
|
|
256
|
+
return {
|
|
257
|
+
patch: {
|
|
258
|
+
enabled: form.enabled,
|
|
259
|
+
lookbackDays,
|
|
260
|
+
enabledCountryCodes: form.enabledCountryCodes,
|
|
261
|
+
noChannelMode: form.noChannelMode,
|
|
262
|
+
minimizationAxis: form.minimizationAxis,
|
|
263
|
+
defaultPresentedPriceKindId: form.defaultPresentedPriceKindId || null,
|
|
264
|
+
channels
|
|
265
|
+
},
|
|
266
|
+
errors
|
|
267
|
+
};
|
|
268
|
+
}, [duplicateChannelMessage, errorMessages, form, lookbackRangeMessage, requiredMessage]);
|
|
269
|
+
const handleSubmit = React.useCallback(async () => {
|
|
270
|
+
if (!canManage || saving) return;
|
|
271
|
+
const { patch, errors } = buildPatch();
|
|
272
|
+
setFormError(null);
|
|
273
|
+
setBackfillChannels(null);
|
|
274
|
+
setFieldErrors(errors);
|
|
275
|
+
if (!patch) return;
|
|
276
|
+
setSaving(true);
|
|
277
|
+
try {
|
|
278
|
+
const saved = await runMutation({
|
|
279
|
+
operation: async () => {
|
|
280
|
+
const call = await apiCall(OMNIBUS_CONFIG_PATH, {
|
|
281
|
+
method: "PATCH",
|
|
282
|
+
headers: { "content-type": "application/json" },
|
|
283
|
+
body: JSON.stringify(patch)
|
|
284
|
+
});
|
|
285
|
+
if (!call.ok) {
|
|
286
|
+
throw new OmnibusSaveError(call.status, isRecord(call.result) ? call.result : null);
|
|
287
|
+
}
|
|
288
|
+
return asStoredConfig(call.result);
|
|
289
|
+
},
|
|
290
|
+
context: {
|
|
291
|
+
formId: MUTATION_CONTEXT_ID,
|
|
292
|
+
resourceKind: "catalog.settings",
|
|
293
|
+
resourceId: "omnibus",
|
|
294
|
+
retryLastMutation
|
|
295
|
+
},
|
|
296
|
+
mutationPayload: patch
|
|
297
|
+
});
|
|
298
|
+
loadedSourceRef.current = { tenantId: scopeTenantId, configKey: JSON.stringify(saved) };
|
|
299
|
+
setStored(saved);
|
|
300
|
+
setForm(toFormState(saved));
|
|
301
|
+
setFieldErrors({});
|
|
302
|
+
flash(t("catalog.omnibus.messages.saved", "Omnibus settings saved."), "success");
|
|
303
|
+
} catch (err) {
|
|
304
|
+
if (err instanceof OmnibusSaveError) {
|
|
305
|
+
const body = err.body;
|
|
306
|
+
if (err.status === 422 && body?.error === "backfill_required_before_enable") {
|
|
307
|
+
const channels = Array.isArray(body.channels) ? body.channels.filter((entry) => typeof entry === "string") : [];
|
|
308
|
+
setBackfillChannels(channels);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const detailFieldErrors = body?.details?.fieldErrors;
|
|
312
|
+
const rawFieldErrors = isRecord(detailFieldErrors) ? detailFieldErrors : null;
|
|
313
|
+
if (err.status === 400 && rawFieldErrors) {
|
|
314
|
+
const mapped = mapServerFieldErrors(rawFieldErrors);
|
|
315
|
+
setFieldErrors(mapped.fields);
|
|
316
|
+
setFormError(mapped.unmatched ?? t("catalog.omnibus.errors.invalid", "Fix the highlighted fields and try again."));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
setFormError(saveErrorMessage);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
logger.error("catalog.omnibus.settings.save failed", { err });
|
|
323
|
+
getTelemetryRuntime()?.reportError(err, { module: "catalog", code: "catalog.omnibus_settings_save_failed" });
|
|
324
|
+
setFormError(err instanceof Error && !err.message.startsWith("[internal]") ? err.message : saveErrorMessage);
|
|
325
|
+
} finally {
|
|
326
|
+
setSaving(false);
|
|
327
|
+
}
|
|
328
|
+
}, [buildPatch, canManage, mapServerFieldErrors, retryLastMutation, runMutation, saveErrorMessage, saving, scopeTenantId, t]);
|
|
329
|
+
const handleCancel = React.useCallback(() => {
|
|
330
|
+
setForm(toFormState(stored));
|
|
331
|
+
setFieldErrors({});
|
|
332
|
+
setFormError(null);
|
|
333
|
+
setBackfillChannels(null);
|
|
334
|
+
}, [stored]);
|
|
335
|
+
const handleKeyDown = React.useCallback(
|
|
336
|
+
(event) => {
|
|
337
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
338
|
+
event.preventDefault();
|
|
339
|
+
void handleSubmit();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (event.key === "Escape" && !event.defaultPrevented && canManage) {
|
|
343
|
+
event.preventDefault();
|
|
344
|
+
handleCancel();
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
[canManage, handleCancel, handleSubmit]
|
|
348
|
+
);
|
|
349
|
+
const updateForm = React.useCallback((patch) => {
|
|
350
|
+
setForm((prev) => ({ ...prev, ...patch }));
|
|
351
|
+
}, []);
|
|
352
|
+
const updateChannel = React.useCallback((rowKey, patch) => {
|
|
353
|
+
setForm((prev) => ({
|
|
354
|
+
...prev,
|
|
355
|
+
channels: prev.channels.map((row) => row.key === rowKey ? { ...row, ...patch } : row)
|
|
356
|
+
}));
|
|
357
|
+
}, []);
|
|
358
|
+
const addChannel = React.useCallback(() => {
|
|
359
|
+
setForm((prev) => ({
|
|
360
|
+
...prev,
|
|
361
|
+
channels: [
|
|
362
|
+
...prev.channels,
|
|
363
|
+
{ key: nextRowKey(), channelId: "", presentedPriceKindId: "", countryCode: "", lookbackDays: "", minimizationAxis: "inherit" }
|
|
364
|
+
]
|
|
365
|
+
}));
|
|
366
|
+
}, []);
|
|
367
|
+
const removeChannel = React.useCallback((rowKey) => {
|
|
368
|
+
setForm((prev) => ({ ...prev, channels: prev.channels.filter((row) => row.key !== rowKey) }));
|
|
369
|
+
}, []);
|
|
370
|
+
const formatChannel = React.useCallback(
|
|
371
|
+
(channelId) => backfillChannelNames[channelId] ? `${backfillChannelNames[channelId]} (${channelId})` : channelId,
|
|
372
|
+
[backfillChannelNames]
|
|
373
|
+
);
|
|
374
|
+
const formatScope = React.useCallback(
|
|
375
|
+
(scopeId) => scopeId ? formatChannel(scopeId) : t("catalog.omnibus.settings.backfill.globalScope", "All channels (unscoped)"),
|
|
376
|
+
[formatChannel, t]
|
|
377
|
+
);
|
|
378
|
+
if (!chromeReady) {
|
|
379
|
+
return /* @__PURE__ */ jsx(LoadingMessage, { label: t("catalog.omnibus.settings.loading", "Loading Omnibus settings\u2026") });
|
|
380
|
+
}
|
|
381
|
+
if (!canView) return null;
|
|
382
|
+
const noChannelModeLabels = {
|
|
383
|
+
best_effort: t("catalog.omnibus.settings.noChannelMode.bestEffort", "Best effort (use global settings)"),
|
|
384
|
+
require_channel: t("catalog.omnibus.settings.noChannelMode.requireChannel", "Require a channel")
|
|
385
|
+
};
|
|
386
|
+
const axisLabels = {
|
|
387
|
+
gross: t("catalog.omnibus.settings.axis.gross", "Gross (B2C)"),
|
|
388
|
+
net: t("catalog.omnibus.settings.axis.net", "Net (B2B)")
|
|
389
|
+
};
|
|
390
|
+
return /* @__PURE__ */ jsxs("section", { className: "border bg-card text-card-foreground shadow-sm", "data-testid": "catalog-omnibus-settings", children: [
|
|
391
|
+
/* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4 space-y-1", children: [
|
|
392
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("catalog.omnibus.settings.title", "Omnibus price tracking") }),
|
|
393
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
|
|
394
|
+
"catalog.omnibus.settings.description",
|
|
395
|
+
"Show the lowest price from the lookback period next to announced price reductions (EU Directive 2019/2161)."
|
|
396
|
+
) })
|
|
397
|
+
] }),
|
|
398
|
+
/* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: loading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("catalog.omnibus.settings.loading", "Loading Omnibus settings\u2026") }) : loadError ? /* @__PURE__ */ jsx(
|
|
399
|
+
ErrorMessage,
|
|
400
|
+
{
|
|
401
|
+
label: loadError,
|
|
402
|
+
action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setReloadToken((token) => token + 1), children: t("catalog.omnibus.settings.actions.retry", "Retry") })
|
|
403
|
+
}
|
|
404
|
+
) : /* @__PURE__ */ jsxs(
|
|
405
|
+
"form",
|
|
406
|
+
{
|
|
407
|
+
className: "space-y-6",
|
|
408
|
+
noValidate: true,
|
|
409
|
+
onKeyDown: handleKeyDown,
|
|
410
|
+
onSubmit: (event) => {
|
|
411
|
+
event.preventDefault();
|
|
412
|
+
void handleSubmit();
|
|
413
|
+
},
|
|
414
|
+
children: [
|
|
415
|
+
!canManage ? /* @__PURE__ */ jsx(Alert, { status: "information", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("catalog.omnibus.settings.readOnly", "You can view these settings but not change them.") }) }) : null,
|
|
416
|
+
backfillChannels ? /* @__PURE__ */ jsxs(Alert, { status: "error", "data-testid": "catalog-omnibus-backfill-required", children: [
|
|
417
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("catalog.omnibus.settings.backfill.requiredTitle", "Backfill required before enabling") }),
|
|
418
|
+
/* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
419
|
+
/* @__PURE__ */ jsx("p", { children: t(
|
|
420
|
+
"catalog.omnibus.settings.backfill.requiredDescription",
|
|
421
|
+
'Price history must be backfilled for every in-scope EU channel before Omnibus can be enabled. Run "mercato catalog omnibus:backfill --tenant <tenantId>" (add "--channel-id <channelId>" per channel), then save again.'
|
|
422
|
+
) }),
|
|
423
|
+
backfillChannels.length > 0 ? /* @__PURE__ */ jsx("p", { className: "mt-1", children: t("catalog.omnibus.settings.backfill.channels", "Channels without backfill: {{channels}}", {
|
|
424
|
+
channels: backfillChannels.map(formatChannel).join(", ")
|
|
425
|
+
}) }) : null
|
|
426
|
+
] })
|
|
427
|
+
] }) : null,
|
|
428
|
+
staleBackfillScopes.length > 0 ? /* @__PURE__ */ jsxs(Alert, { status: "warning", "data-testid": "catalog-omnibus-backfill-stale", children: [
|
|
429
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("catalog.omnibus.settings.backfill.staleTitle", "Lookback increased since the last backfill") }),
|
|
430
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: t(
|
|
431
|
+
"catalog.omnibus.settings.backfill.staleDescription",
|
|
432
|
+
"Re-run the backfill so the longer window has baseline history: {{scopes}}",
|
|
433
|
+
{ scopes: staleBackfillScopes.map(formatScope).join(", ") }
|
|
434
|
+
) })
|
|
435
|
+
] }) : null,
|
|
436
|
+
formError ? /* @__PURE__ */ jsx(ErrorMessage, { label: formError }) : null,
|
|
437
|
+
/* @__PURE__ */ jsx(
|
|
438
|
+
SwitchField,
|
|
439
|
+
{
|
|
440
|
+
label: t("catalog.omnibus.settings.enabled", "Enable Omnibus reference prices"),
|
|
441
|
+
description: t(
|
|
442
|
+
"catalog.omnibus.settings.enabledDescription",
|
|
443
|
+
"When enabled, products in EU channels expose the lowest price from the lookback window."
|
|
444
|
+
),
|
|
445
|
+
checked: form.enabled,
|
|
446
|
+
disabled: readOnly,
|
|
447
|
+
onCheckedChange: (next) => updateForm({ enabled: next })
|
|
448
|
+
}
|
|
449
|
+
),
|
|
450
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
|
|
451
|
+
/* @__PURE__ */ jsx(
|
|
452
|
+
FormField,
|
|
453
|
+
{
|
|
454
|
+
label: t("catalog.omnibus.settings.lookbackDays", "Lookback window (days)"),
|
|
455
|
+
description: t("catalog.omnibus.settings.lookbackDaysDescription", "Between 1 and 365 days. The directive requires at least 30."),
|
|
456
|
+
error: fieldErrors.lookbackDays,
|
|
457
|
+
required: true,
|
|
458
|
+
disabled: readOnly,
|
|
459
|
+
children: /* @__PURE__ */ jsx(
|
|
460
|
+
Input,
|
|
461
|
+
{
|
|
462
|
+
type: "number",
|
|
463
|
+
inputMode: "numeric",
|
|
464
|
+
min: MIN_LOOKBACK_DAYS,
|
|
465
|
+
max: MAX_LOOKBACK_DAYS,
|
|
466
|
+
value: form.lookbackDays,
|
|
467
|
+
onChange: (event) => updateForm({ lookbackDays: event.target.value }),
|
|
468
|
+
"data-testid": "catalog-omnibus-lookback"
|
|
469
|
+
}
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
/* @__PURE__ */ jsx(
|
|
474
|
+
FormField,
|
|
475
|
+
{
|
|
476
|
+
label: t("catalog.omnibus.settings.enabledCountryCodes", "EU member states"),
|
|
477
|
+
description: t(
|
|
478
|
+
"catalog.omnibus.settings.enabledCountryCodesDescription",
|
|
479
|
+
"Two-letter ISO codes of the member states where Omnibus applies. Leave empty to disable it for every channel."
|
|
480
|
+
),
|
|
481
|
+
error: fieldErrors.enabledCountryCodes,
|
|
482
|
+
disabled: readOnly,
|
|
483
|
+
children: /* @__PURE__ */ jsx(
|
|
484
|
+
TagInput,
|
|
485
|
+
{
|
|
486
|
+
value: form.enabledCountryCodes,
|
|
487
|
+
onChange: (next) => updateForm({ enabledCountryCodes: Array.from(new Set(next.map((code) => code.trim().toUpperCase()))) }),
|
|
488
|
+
validate: (tag) => {
|
|
489
|
+
const code = tag.trim().toUpperCase();
|
|
490
|
+
if (code === "EU") return errorMessages.omnibus_country_code_eu_not_allowed;
|
|
491
|
+
return COUNTRY_CODE_PATTERN.test(code) || errorMessages.omnibus_country_code_alpha2_required;
|
|
492
|
+
},
|
|
493
|
+
placeholder: t("catalog.omnibus.settings.enabledCountryCodesPlaceholder", "e.g. PL, DE"),
|
|
494
|
+
"aria-label": t("catalog.omnibus.settings.enabledCountryCodes", "EU member states"),
|
|
495
|
+
removeTagLabel: (tag) => t("catalog.omnibus.settings.removeCountry", "Remove {{code}}", { code: tag }),
|
|
496
|
+
disabled: readOnly
|
|
497
|
+
}
|
|
498
|
+
)
|
|
499
|
+
}
|
|
500
|
+
),
|
|
501
|
+
/* @__PURE__ */ jsx(
|
|
502
|
+
FormField,
|
|
503
|
+
{
|
|
504
|
+
label: t("catalog.omnibus.settings.noChannelModeLabel", "Requests without a channel"),
|
|
505
|
+
error: fieldErrors.noChannelMode,
|
|
506
|
+
disabled: readOnly,
|
|
507
|
+
children: /* @__PURE__ */ jsxs(
|
|
508
|
+
Select,
|
|
509
|
+
{
|
|
510
|
+
value: form.noChannelMode,
|
|
511
|
+
onValueChange: (next) => updateForm({ noChannelMode: next }),
|
|
512
|
+
disabled: readOnly,
|
|
513
|
+
children: [
|
|
514
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { children: noChannelModeLabels[form.noChannelMode] }) }),
|
|
515
|
+
/* @__PURE__ */ jsx(SelectContent, { children: Object.keys(noChannelModeLabels).map((mode) => /* @__PURE__ */ jsx(SelectItem, { value: mode, children: noChannelModeLabels[mode] }, mode)) })
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
}
|
|
520
|
+
),
|
|
521
|
+
/* @__PURE__ */ jsx(
|
|
522
|
+
FormField,
|
|
523
|
+
{
|
|
524
|
+
label: t("catalog.omnibus.settings.minimizationAxis", "Compare prices by"),
|
|
525
|
+
error: fieldErrors.minimizationAxis,
|
|
526
|
+
disabled: readOnly,
|
|
527
|
+
children: /* @__PURE__ */ jsxs(
|
|
528
|
+
Select,
|
|
529
|
+
{
|
|
530
|
+
value: form.minimizationAxis,
|
|
531
|
+
onValueChange: (next) => updateForm({ minimizationAxis: next }),
|
|
532
|
+
disabled: readOnly,
|
|
533
|
+
children: [
|
|
534
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { children: axisLabels[form.minimizationAxis] }) }),
|
|
535
|
+
/* @__PURE__ */ jsx(SelectContent, { children: Object.keys(axisLabels).map((axis) => /* @__PURE__ */ jsx(SelectItem, { value: axis, children: axisLabels[axis] }, axis)) })
|
|
536
|
+
]
|
|
537
|
+
}
|
|
538
|
+
)
|
|
539
|
+
}
|
|
540
|
+
),
|
|
541
|
+
/* @__PURE__ */ jsx(
|
|
542
|
+
FormField,
|
|
543
|
+
{
|
|
544
|
+
label: t("catalog.omnibus.settings.defaultPresentedPriceKind", "Default presented price kind"),
|
|
545
|
+
description: t(
|
|
546
|
+
"catalog.omnibus.settings.defaultPresentedPriceKindDescription",
|
|
547
|
+
"The price kind shown to shoppers, used when a channel has no override. Required when Omnibus is enabled without channel overrides."
|
|
548
|
+
),
|
|
549
|
+
error: fieldErrors.defaultPresentedPriceKindId,
|
|
550
|
+
disabled: readOnly,
|
|
551
|
+
className: "md:col-span-2",
|
|
552
|
+
children: /* @__PURE__ */ jsx(
|
|
553
|
+
PricePriceKindSelect,
|
|
554
|
+
{
|
|
555
|
+
value: form.defaultPresentedPriceKindId,
|
|
556
|
+
onChange: (next) => updateForm({ defaultPresentedPriceKindId: next }),
|
|
557
|
+
disabled: readOnly,
|
|
558
|
+
clearable: true
|
|
559
|
+
}
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
)
|
|
563
|
+
] }),
|
|
564
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
565
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
566
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
567
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("catalog.omnibus.settings.channels.title", "Channel overrides") }),
|
|
568
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t(
|
|
569
|
+
"catalog.omnibus.settings.channels.description",
|
|
570
|
+
"Map sales channels to a member state and override the presented price kind, lookback or comparison axis per channel."
|
|
571
|
+
) })
|
|
572
|
+
] }),
|
|
573
|
+
canManage ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addChannel, disabled: saving, children: [
|
|
574
|
+
/* @__PURE__ */ jsx(Plus, { className: "size-4", "aria-hidden": true }),
|
|
575
|
+
t("catalog.omnibus.settings.channels.add", "Add channel")
|
|
576
|
+
] }) : null
|
|
577
|
+
] }),
|
|
578
|
+
form.channels.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("catalog.omnibus.settings.channels.empty", "No channel overrides. Global settings apply to every channel.") }) : form.channels.map((row) => {
|
|
579
|
+
const rowError = (field) => fieldErrors[channelErrorKey(row.key, field)];
|
|
580
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-3 rounded-md border p-4", "data-testid": "catalog-omnibus-channel-row", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
581
|
+
/* @__PURE__ */ jsxs("div", { className: "grid flex-1 gap-4 md:grid-cols-2", children: [
|
|
582
|
+
/* @__PURE__ */ jsx(
|
|
583
|
+
FormField,
|
|
584
|
+
{
|
|
585
|
+
label: t("catalog.omnibus.settings.channels.channel", "Channel"),
|
|
586
|
+
error: rowError("channelId"),
|
|
587
|
+
disabled: readOnly,
|
|
588
|
+
children: /* @__PURE__ */ jsx(
|
|
589
|
+
PriceChannelSelect,
|
|
590
|
+
{
|
|
591
|
+
value: row.channelId,
|
|
592
|
+
onChange: (next) => updateChannel(row.key, { channelId: next }),
|
|
593
|
+
disabled: readOnly
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
}
|
|
597
|
+
),
|
|
598
|
+
/* @__PURE__ */ jsx(
|
|
599
|
+
FormField,
|
|
600
|
+
{
|
|
601
|
+
label: t("catalog.omnibus.settings.channels.presentedPriceKind", "Presented price kind"),
|
|
602
|
+
error: rowError("presentedPriceKindId"),
|
|
603
|
+
disabled: readOnly,
|
|
604
|
+
children: /* @__PURE__ */ jsx(
|
|
605
|
+
PricePriceKindSelect,
|
|
606
|
+
{
|
|
607
|
+
value: row.presentedPriceKindId,
|
|
608
|
+
onChange: (next) => updateChannel(row.key, { presentedPriceKindId: next }),
|
|
609
|
+
disabled: readOnly
|
|
610
|
+
}
|
|
611
|
+
)
|
|
612
|
+
}
|
|
613
|
+
),
|
|
614
|
+
/* @__PURE__ */ jsx(
|
|
615
|
+
FormField,
|
|
616
|
+
{
|
|
617
|
+
label: t("catalog.omnibus.settings.channels.countryCode", "Member state"),
|
|
618
|
+
description: t("catalog.omnibus.settings.channels.countryCodeDescription", "Leave empty for non-EU channels."),
|
|
619
|
+
error: rowError("countryCode"),
|
|
620
|
+
disabled: readOnly,
|
|
621
|
+
children: /* @__PURE__ */ jsx(
|
|
622
|
+
Input,
|
|
623
|
+
{
|
|
624
|
+
value: row.countryCode,
|
|
625
|
+
maxLength: 2,
|
|
626
|
+
onChange: (event) => updateChannel(row.key, { countryCode: event.target.value.toUpperCase() }),
|
|
627
|
+
placeholder: t("catalog.omnibus.settings.channels.countryCodePlaceholder", "e.g. PL")
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
}
|
|
631
|
+
),
|
|
632
|
+
/* @__PURE__ */ jsx(
|
|
633
|
+
FormField,
|
|
634
|
+
{
|
|
635
|
+
label: t("catalog.omnibus.settings.channels.lookbackDays", "Lookback override (days)"),
|
|
636
|
+
description: t("catalog.omnibus.settings.channels.lookbackDaysDescription", "Leave empty to use the global window."),
|
|
637
|
+
error: rowError("lookbackDays"),
|
|
638
|
+
disabled: readOnly,
|
|
639
|
+
children: /* @__PURE__ */ jsx(
|
|
640
|
+
Input,
|
|
641
|
+
{
|
|
642
|
+
type: "number",
|
|
643
|
+
inputMode: "numeric",
|
|
644
|
+
min: MIN_LOOKBACK_DAYS,
|
|
645
|
+
max: MAX_LOOKBACK_DAYS,
|
|
646
|
+
value: row.lookbackDays,
|
|
647
|
+
onChange: (event) => updateChannel(row.key, { lookbackDays: event.target.value })
|
|
648
|
+
}
|
|
649
|
+
)
|
|
650
|
+
}
|
|
651
|
+
),
|
|
652
|
+
/* @__PURE__ */ jsx(
|
|
653
|
+
FormField,
|
|
654
|
+
{
|
|
655
|
+
label: t("catalog.omnibus.settings.channels.minimizationAxis", "Compare prices by"),
|
|
656
|
+
error: rowError("minimizationAxis"),
|
|
657
|
+
disabled: readOnly,
|
|
658
|
+
children: /* @__PURE__ */ jsxs(
|
|
659
|
+
Select,
|
|
660
|
+
{
|
|
661
|
+
value: row.minimizationAxis,
|
|
662
|
+
onValueChange: (next) => updateChannel(row.key, { minimizationAxis: next }),
|
|
663
|
+
disabled: readOnly,
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { children: row.minimizationAxis === "inherit" ? t("catalog.omnibus.settings.channels.axisInherit", "Use global setting") : axisLabels[row.minimizationAxis] }) }),
|
|
666
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
667
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "inherit", children: t("catalog.omnibus.settings.channels.axisInherit", "Use global setting") }),
|
|
668
|
+
Object.keys(axisLabels).map((axis) => /* @__PURE__ */ jsx(SelectItem, { value: axis, children: axisLabels[axis] }, axis))
|
|
669
|
+
] })
|
|
670
|
+
]
|
|
671
|
+
}
|
|
672
|
+
)
|
|
673
|
+
}
|
|
674
|
+
)
|
|
675
|
+
] }),
|
|
676
|
+
canManage ? /* @__PURE__ */ jsx(
|
|
677
|
+
IconButton,
|
|
678
|
+
{
|
|
679
|
+
type: "button",
|
|
680
|
+
variant: "ghost",
|
|
681
|
+
size: "sm",
|
|
682
|
+
"aria-label": t("catalog.omnibus.settings.channels.remove", "Remove channel override"),
|
|
683
|
+
onClick: () => removeChannel(row.key),
|
|
684
|
+
disabled: saving,
|
|
685
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "size-4", "aria-hidden": true })
|
|
686
|
+
}
|
|
687
|
+
) : null
|
|
688
|
+
] }) }, row.key);
|
|
689
|
+
})
|
|
690
|
+
] }),
|
|
691
|
+
canManage ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
692
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleCancel, disabled: saving, children: t("catalog.omnibus.settings.actions.cancel", "Cancel") }),
|
|
693
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: saving, "data-testid": "catalog-omnibus-save", children: saving ? t("catalog.omnibus.settings.actions.saving", "Saving\u2026") : t("catalog.omnibus.settings.actions.save", "Save") })
|
|
694
|
+
] }) : null
|
|
695
|
+
]
|
|
696
|
+
}
|
|
697
|
+
) })
|
|
698
|
+
] });
|
|
699
|
+
}
|
|
700
|
+
export {
|
|
701
|
+
OmnibusSettings
|
|
702
|
+
};
|
|
703
|
+
//# sourceMappingURL=OmnibusSettings.js.map
|