@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,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/components/OmnibusSettings.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus, Trash2 } from 'lucide-react'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { SwitchField } from '@open-mercato/ui/primitives/switch-field'\nimport { TagInput } from '@open-mercato/ui/primitives/tag-input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useBackendChrome } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { useOrganizationScopeDetail, useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\nimport type {\n OmnibusConfig,\n OmnibusMinimizationAxis,\n OmnibusNoChannelMode,\n} from '../lib/omnibusTypes'\nimport { PriceChannelSelect, PricePriceKindSelect } from './prices/PriceScopeSelectors'\n\nconst logger = createLogger('catalog').child({ component: 'OmnibusSettings' })\n\nconst OMNIBUS_CONFIG_PATH = '/api/catalog/config/omnibus'\nconst MUTATION_CONTEXT_ID = 'catalog-omnibus-settings'\nconst DEFAULT_LOOKBACK_DAYS = 30\nconst MIN_LOOKBACK_DAYS = 1\nconst MAX_LOOKBACK_DAYS = 365\nconst COUNTRY_CODE_PATTERN = /^[A-Z]{2}$/\n\ntype StoredOmnibusConfig = Partial<OmnibusConfig>\n\ntype ChannelAxisValue = OmnibusMinimizationAxis | 'inherit'\n\ntype OmnibusChannelRow = {\n key: string\n channelId: string\n presentedPriceKindId: string\n countryCode: string\n lookbackDays: string\n minimizationAxis: ChannelAxisValue\n}\n\ntype OmnibusFormState = {\n enabled: boolean\n lookbackDays: string\n enabledCountryCodes: string[]\n noChannelMode: OmnibusNoChannelMode\n minimizationAxis: OmnibusMinimizationAxis\n defaultPresentedPriceKindId: string\n channels: OmnibusChannelRow[]\n}\n\ntype OmnibusChannelPatch = {\n presentedPriceKindId: string\n countryCode?: string\n lookbackDays?: number\n minimizationAxis?: OmnibusMinimizationAxis\n}\n\ntype OmnibusConfigPatchBody = {\n enabled: boolean\n lookbackDays: number\n enabledCountryCodes: string[]\n noChannelMode: OmnibusNoChannelMode\n minimizationAxis: OmnibusMinimizationAxis\n defaultPresentedPriceKindId: string | null\n channels: Record<string, OmnibusChannelPatch>\n}\n\ntype FieldErrors = Record<string, string>\n\ntype OmnibusMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\ntype OmnibusErrorBody = {\n error?: unknown\n field?: unknown\n channels?: unknown\n details?: { fieldErrors?: Record<string, unknown> } | null\n}\n\nclass OmnibusSaveError extends Error {\n readonly status: number\n readonly body: OmnibusErrorBody | null\n\n constructor(status: number, body: OmnibusErrorBody | null) {\n super(`[internal] catalog omnibus config save failed with status ${status}`)\n this.status = status\n this.body = body\n }\n}\n\nlet rowSequence = 0\n\nfunction nextRowKey(): string {\n rowSequence += 1\n return `omnibus-channel-${rowSequence}`\n}\n\nfunction toFormState(config: StoredOmnibusConfig | null): OmnibusFormState {\n const channels = Object.entries(config?.channels ?? {}).map(([channelId, channel]): OmnibusChannelRow => ({\n key: nextRowKey(),\n channelId,\n presentedPriceKindId: channel.presentedPriceKindId ?? '',\n countryCode: channel.countryCode ?? '',\n lookbackDays: typeof channel.lookbackDays === 'number' ? String(channel.lookbackDays) : '',\n minimizationAxis: channel.minimizationAxis ?? 'inherit',\n }))\n return {\n enabled: config?.enabled === true,\n lookbackDays: String(config?.lookbackDays ?? DEFAULT_LOOKBACK_DAYS),\n enabledCountryCodes: Array.isArray(config?.enabledCountryCodes) ? [...config.enabledCountryCodes] : [],\n noChannelMode: config?.noChannelMode ?? 'best_effort',\n minimizationAxis: config?.minimizationAxis ?? 'gross',\n defaultPresentedPriceKindId: config?.defaultPresentedPriceKindId ?? '',\n channels,\n }\n}\n\nfunction parseLookbackDays(raw: string): number | null {\n const trimmed = raw.trim()\n if (!/^\\d+$/.test(trimmed)) return null\n const value = Number(trimmed)\n if (!Number.isInteger(value) || value < MIN_LOOKBACK_DAYS || value > MAX_LOOKBACK_DAYS) return null\n return value\n}\n\nfunction channelErrorKey(rowKey: string, field: string): string {\n return `channels.${rowKey}.${field}`\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction asStoredConfig(value: unknown): StoredOmnibusConfig | null {\n return isRecord(value) ? (value as StoredOmnibusConfig) : null\n}\n\nfunction listStaleBackfillScopes(stored: StoredOmnibusConfig | null, form: OmnibusFormState): string[] {\n const coverage = stored?.backfillCoverage ?? {}\n const globalLookback = parseLookbackDays(form.lookbackDays)\n if (globalLookback === null) return []\n const channelLookbacks = new Map(\n form.channels\n .filter((row) => row.channelId)\n .map((row) => [row.channelId, parseLookbackDays(row.lookbackDays) ?? globalLookback]),\n )\n return Object.entries(coverage)\n .filter(([scopeId, entry]) => {\n const effective = scopeId ? channelLookbacks.get(scopeId) ?? globalLookback : globalLookback\n return entry.lookbackDays < effective\n })\n .map(([scopeId]) => scopeId)\n .sort((left, right) => (left < right ? -1 : left > right ? 1 : 0))\n}\n\nexport function OmnibusSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const scopeTenantId = useOrganizationScopeDetail().tenantId\n const { payload: chromePayload, isReady: chromeReady } = useBackendChrome()\n const grantedFeatures = chromePayload?.grantedFeatures\n const canManage = hasFeature(grantedFeatures, 'catalog.settings.manage')\n const canView = canManage || hasFeature(grantedFeatures, 'catalog.settings.view')\n\n const [stored, setStored] = React.useState<StoredOmnibusConfig | null>(null)\n const [form, setForm] = React.useState<OmnibusFormState>(() => toFormState(null))\n const [loading, setLoading] = React.useState(true)\n const [loadError, setLoadError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [fieldErrors, setFieldErrors] = React.useState<FieldErrors>({})\n const [formError, setFormError] = React.useState<string | null>(null)\n const [backfillChannels, setBackfillChannels] = React.useState<string[] | null>(null)\n const [backfillChannelNames, setBackfillChannelNames] = React.useState<Record<string, string>>({})\n const [reloadToken, setReloadToken] = React.useState(0)\n const loadedSourceRef = React.useRef<{ tenantId: string | null; configKey: string } | null>(null)\n\n const { runMutation, retryLastMutation } = useGuardedMutation<OmnibusMutationContext>({\n contextId: MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const readOnly = !canManage || saving\n\n const errorMessages = React.useMemo<Record<string, string>>(() => ({\n omnibus_country_code_alpha2_required: t('catalog.omnibus.errors.countryCodeFormat', 'Use a two-letter ISO country code.'),\n omnibus_country_code_eu_not_allowed: t('catalog.omnibus.errors.countryCodeEu', 'List individual member states instead of \"EU\".'),\n omnibus_country_code_unknown: t('catalog.omnibus.errors.countryCodeUnknown', 'Unknown country code.'),\n 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.'),\n omnibus_field_not_supported: t('catalog.omnibus.errors.fieldNotSupported', 'This setting is not supported.'),\n omnibus_derogation_not_supported: t('catalog.omnibus.errors.fieldNotSupported', 'This setting is not supported.'),\n omnibus_backfill_coverage_read_only: t('catalog.omnibus.errors.fieldNotSupported', 'This setting is not supported.'),\n }), [t])\n const invalidValueMessage = t('catalog.omnibus.errors.invalidValue', 'Invalid value.')\n const lookbackRangeMessage = t('catalog.omnibus.errors.lookbackRange', 'Enter a whole number of days between 1 and 365.')\n const requiredMessage = t('catalog.omnibus.errors.required', 'This field is required.')\n const duplicateChannelMessage = t('catalog.omnibus.errors.duplicateChannel', 'This channel is already configured.')\n const saveErrorMessage = t('catalog.omnibus.errors.save', 'Failed to save Omnibus settings.')\n const staleBackfillScopes = React.useMemo(() => listStaleBackfillScopes(stored, form), [form, stored])\n const channelNameLookupKey = React.useMemo(\n () => Array.from(new Set([...(backfillChannels ?? []), ...staleBackfillScopes].filter((channelId) => channelId.length > 0))).sort((left, right) => (left < right ? -1 : left > right ? 1 : 0)).join(','),\n [backfillChannels, staleBackfillScopes],\n )\n\n React.useEffect(() => {\n const channelIds = channelNameLookupKey ? channelNameLookupKey.split(',') : []\n if (!channelIds.length) return\n let cancelled = false\n const query = new URLSearchParams({ ids: channelIds.join(','), pageSize: String(Math.min(channelIds.length, 100)) })\n apiCall<{ items?: Array<Record<string, unknown>> }>(`/api/sales/channels?${query.toString()}`)\n .then((call) => {\n if (cancelled || !call?.ok) return\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const names: Record<string, string> = {}\n for (const item of items) {\n if (typeof item.id === 'string' && typeof item.name === 'string' && item.name.length) names[item.id] = item.name\n }\n setBackfillChannelNames((previous) => ({ ...previous, ...names }))\n })\n .catch((err) => {\n logger.warn('catalog.omnibus.settings.backfillChannelNames failed', { err })\n getTelemetryRuntime()?.reportError(err, { module: 'catalog', code: 'catalog.omnibus_channel_names_load_failed' })\n })\n return () => {\n cancelled = true\n }\n }, [channelNameLookupKey])\n\n const loadErrorMessage = t('catalog.omnibus.errors.load', 'Failed to load Omnibus settings.')\n\n React.useEffect(() => {\n if (!chromeReady || !canView) return\n let cancelled = false\n const previous = loadedSourceRef.current\n if (!previous) setLoading(true)\n setLoadError(null)\n apiCall<unknown>(OMNIBUS_CONFIG_PATH)\n .then((call) => {\n if (cancelled) return\n if (!call.ok) {\n loadedSourceRef.current = null\n setLoadError(loadErrorMessage)\n return\n }\n const config = asStoredConfig(call.result)\n const configKey = JSON.stringify(config)\n const keepsEdits =\n previous !== null &&\n previous.configKey === configKey &&\n (previous.tenantId === null || previous.tenantId === scopeTenantId)\n loadedSourceRef.current = { tenantId: scopeTenantId, configKey }\n setStored(config)\n if (keepsEdits) return\n setForm(toFormState(config))\n setFieldErrors({})\n setFormError(null)\n setBackfillChannels(null)\n })\n .catch((err) => {\n logger.error('catalog.omnibus.settings.load failed', { err })\n getTelemetryRuntime()?.reportError(err, { module: 'catalog', code: 'catalog.omnibus_settings_load_failed' })\n if (!cancelled) setLoadError(loadErrorMessage)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [canView, chromeReady, loadErrorMessage, reloadToken, scopeTenantId, scopeVersion])\n\n const translateServerError = React.useCallback(\n (messages: unknown): string => {\n const first = Array.isArray(messages) ? messages.find((entry) => typeof entry === 'string') : null\n if (typeof first !== 'string') return invalidValueMessage\n return errorMessages[first] ?? invalidValueMessage\n },\n [errorMessages, invalidValueMessage],\n )\n\n const mapServerFieldErrors = React.useCallback(\n (raw: Record<string, unknown>): { fields: FieldErrors; unmatched: string | null } => {\n const fields: FieldErrors = {}\n let unmatched: string | null = null\n for (const [path, messages] of Object.entries(raw)) {\n const message = translateServerError(messages)\n const segments = path.split('.')\n const head = segments[0]\n if (head === 'channels' && segments.length >= 2) {\n const row = form.channels.find((entry) => entry.channelId === segments[1])\n const field = segments[2] ?? 'channelId'\n if (row) {\n fields[channelErrorKey(row.key, field)] = message\n continue\n }\n } else if (head && head !== '_root' && head in form) {\n fields[head] = fields[head] ?? message\n continue\n }\n unmatched = unmatched ?? message\n }\n return { fields, unmatched }\n },\n [form, translateServerError],\n )\n\n const buildPatch = React.useCallback((): { patch: OmnibusConfigPatchBody | null; errors: FieldErrors } => {\n const errors: FieldErrors = {}\n const lookbackDays = parseLookbackDays(form.lookbackDays)\n if (lookbackDays === null) errors.lookbackDays = lookbackRangeMessage\n const channels: Record<string, OmnibusChannelPatch> = {}\n for (const row of form.channels) {\n const channelId = row.channelId.trim()\n if (!channelId) {\n errors[channelErrorKey(row.key, 'channelId')] = requiredMessage\n } else if (channels[channelId]) {\n errors[channelErrorKey(row.key, 'channelId')] = duplicateChannelMessage\n }\n if (!row.presentedPriceKindId) errors[channelErrorKey(row.key, 'presentedPriceKindId')] = requiredMessage\n const countryCode = row.countryCode.trim().toUpperCase()\n if (countryCode && !COUNTRY_CODE_PATTERN.test(countryCode)) {\n errors[channelErrorKey(row.key, 'countryCode')] = errorMessages.omnibus_country_code_alpha2_required\n }\n const channelLookback = row.lookbackDays.trim() ? parseLookbackDays(row.lookbackDays) : undefined\n if (channelLookback === null) errors[channelErrorKey(row.key, 'lookbackDays')] = lookbackRangeMessage\n if (!channelId || channels[channelId]) continue\n channels[channelId] = {\n presentedPriceKindId: row.presentedPriceKindId,\n ...(countryCode ? { countryCode } : {}),\n ...(typeof channelLookback === 'number' ? { lookbackDays: channelLookback } : {}),\n ...(row.minimizationAxis !== 'inherit' ? { minimizationAxis: row.minimizationAxis } : {}),\n }\n }\n if (Object.keys(errors).length > 0 || lookbackDays === null) return { patch: null, errors }\n return {\n patch: {\n enabled: form.enabled,\n lookbackDays,\n enabledCountryCodes: form.enabledCountryCodes,\n noChannelMode: form.noChannelMode,\n minimizationAxis: form.minimizationAxis,\n defaultPresentedPriceKindId: form.defaultPresentedPriceKindId || null,\n channels,\n },\n errors,\n }\n }, [duplicateChannelMessage, errorMessages, form, lookbackRangeMessage, requiredMessage])\n\n const handleSubmit = React.useCallback(async () => {\n if (!canManage || saving) return\n const { patch, errors } = buildPatch()\n setFormError(null)\n setBackfillChannels(null)\n setFieldErrors(errors)\n if (!patch) return\n setSaving(true)\n try {\n const saved = await runMutation({\n operation: async () => {\n // optimistic-lock-exempt: single tenant-scoped Omnibus config blob merged server-side; no per-record version to compare\n const call = await apiCall<unknown>(OMNIBUS_CONFIG_PATH, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(patch),\n })\n if (!call.ok) {\n throw new OmnibusSaveError(call.status, isRecord(call.result) ? (call.result as OmnibusErrorBody) : null)\n }\n return asStoredConfig(call.result)\n },\n context: {\n formId: MUTATION_CONTEXT_ID,\n resourceKind: 'catalog.settings',\n resourceId: 'omnibus',\n retryLastMutation,\n },\n mutationPayload: patch,\n })\n loadedSourceRef.current = { tenantId: scopeTenantId, configKey: JSON.stringify(saved) }\n setStored(saved)\n setForm(toFormState(saved))\n setFieldErrors({})\n flash(t('catalog.omnibus.messages.saved', 'Omnibus settings saved.'), 'success')\n } catch (err) {\n if (err instanceof OmnibusSaveError) {\n const body = err.body\n if (err.status === 422 && body?.error === 'backfill_required_before_enable') {\n const channels = Array.isArray(body.channels)\n ? body.channels.filter((entry): entry is string => typeof entry === 'string')\n : []\n setBackfillChannels(channels)\n return\n }\n const detailFieldErrors = body?.details?.fieldErrors\n const rawFieldErrors = isRecord(detailFieldErrors) ? detailFieldErrors : null\n if (err.status === 400 && rawFieldErrors) {\n const mapped = mapServerFieldErrors(rawFieldErrors)\n setFieldErrors(mapped.fields)\n setFormError(mapped.unmatched ?? t('catalog.omnibus.errors.invalid', 'Fix the highlighted fields and try again.'))\n return\n }\n setFormError(saveErrorMessage)\n return\n }\n logger.error('catalog.omnibus.settings.save failed', { err })\n getTelemetryRuntime()?.reportError(err, { module: 'catalog', code: 'catalog.omnibus_settings_save_failed' })\n setFormError(err instanceof Error && !err.message.startsWith('[internal]') ? err.message : saveErrorMessage)\n } finally {\n setSaving(false)\n }\n }, [buildPatch, canManage, mapServerFieldErrors, retryLastMutation, runMutation, saveErrorMessage, saving, scopeTenantId, t])\n\n const handleCancel = React.useCallback(() => {\n setForm(toFormState(stored))\n setFieldErrors({})\n setFormError(null)\n setBackfillChannels(null)\n }, [stored])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n return\n }\n if (event.key === 'Escape' && !event.defaultPrevented && canManage) {\n event.preventDefault()\n handleCancel()\n }\n },\n [canManage, handleCancel, handleSubmit],\n )\n\n const updateForm = React.useCallback((patch: Partial<OmnibusFormState>) => {\n setForm((prev) => ({ ...prev, ...patch }))\n }, [])\n\n const updateChannel = React.useCallback((rowKey: string, patch: Partial<OmnibusChannelRow>) => {\n setForm((prev) => ({\n ...prev,\n channels: prev.channels.map((row) => (row.key === rowKey ? { ...row, ...patch } : row)),\n }))\n }, [])\n\n const addChannel = React.useCallback(() => {\n setForm((prev) => ({\n ...prev,\n channels: [\n ...prev.channels,\n { key: nextRowKey(), channelId: '', presentedPriceKindId: '', countryCode: '', lookbackDays: '', minimizationAxis: 'inherit' },\n ],\n }))\n }, [])\n\n const removeChannel = React.useCallback((rowKey: string) => {\n setForm((prev) => ({ ...prev, channels: prev.channels.filter((row) => row.key !== rowKey) }))\n }, [])\n\n const formatChannel = React.useCallback(\n (channelId: string) => (backfillChannelNames[channelId] ? `${backfillChannelNames[channelId]} (${channelId})` : channelId),\n [backfillChannelNames],\n )\n\n const formatScope = React.useCallback(\n (scopeId: string) => (scopeId ? formatChannel(scopeId) : t('catalog.omnibus.settings.backfill.globalScope', 'All channels (unscoped)')),\n [formatChannel, t],\n )\n\n if (!chromeReady) {\n return <LoadingMessage label={t('catalog.omnibus.settings.loading', 'Loading Omnibus settings\u2026')} />\n }\n if (!canView) return null\n\n const noChannelModeLabels: Record<OmnibusNoChannelMode, string> = {\n best_effort: t('catalog.omnibus.settings.noChannelMode.bestEffort', 'Best effort (use global settings)'),\n require_channel: t('catalog.omnibus.settings.noChannelMode.requireChannel', 'Require a channel'),\n }\n const axisLabels: Record<OmnibusMinimizationAxis, string> = {\n gross: t('catalog.omnibus.settings.axis.gross', 'Gross (B2C)'),\n net: t('catalog.omnibus.settings.axis.net', 'Net (B2B)'),\n }\n\n return (\n <section className=\"border bg-card text-card-foreground shadow-sm\" data-testid=\"catalog-omnibus-settings\">\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-semibold\">{t('catalog.omnibus.settings.title', 'Omnibus price tracking')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'catalog.omnibus.settings.description',\n 'Show the lowest price from the lookback period next to announced price reductions (EU Directive 2019/2161).',\n )}\n </p>\n </div>\n <div className=\"px-6 py-4\">\n {loading ? (\n <LoadingMessage label={t('catalog.omnibus.settings.loading', 'Loading Omnibus settings\u2026')} />\n ) : loadError ? (\n <ErrorMessage\n label={loadError}\n action={(\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setReloadToken((token) => token + 1)}>\n {t('catalog.omnibus.settings.actions.retry', 'Retry')}\n </Button>\n )}\n />\n ) : (\n <form\n className=\"space-y-6\"\n noValidate\n onKeyDown={handleKeyDown}\n onSubmit={(event) => {\n event.preventDefault()\n void handleSubmit()\n }}\n >\n {!canManage ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('catalog.omnibus.settings.readOnly', 'You can view these settings but not change them.')}\n </AlertDescription>\n </Alert>\n ) : null}\n {backfillChannels ? (\n <Alert status=\"error\" data-testid=\"catalog-omnibus-backfill-required\">\n <AlertTitle>{t('catalog.omnibus.settings.backfill.requiredTitle', 'Backfill required before enabling')}</AlertTitle>\n <AlertDescription>\n <p>\n {t(\n 'catalog.omnibus.settings.backfill.requiredDescription',\n '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.',\n )}\n </p>\n {backfillChannels.length > 0 ? (\n <p className=\"mt-1\">\n {t('catalog.omnibus.settings.backfill.channels', 'Channels without backfill: {{channels}}', {\n channels: backfillChannels.map(formatChannel).join(', '),\n })}\n </p>\n ) : null}\n </AlertDescription>\n </Alert>\n ) : null}\n {staleBackfillScopes.length > 0 ? (\n <Alert status=\"warning\" data-testid=\"catalog-omnibus-backfill-stale\">\n <AlertTitle>{t('catalog.omnibus.settings.backfill.staleTitle', 'Lookback increased since the last backfill')}</AlertTitle>\n <AlertDescription>\n {t(\n 'catalog.omnibus.settings.backfill.staleDescription',\n 'Re-run the backfill so the longer window has baseline history: {{scopes}}',\n { scopes: staleBackfillScopes.map(formatScope).join(', ') },\n )}\n </AlertDescription>\n </Alert>\n ) : null}\n {formError ? <ErrorMessage label={formError} /> : null}\n\n <SwitchField\n label={t('catalog.omnibus.settings.enabled', 'Enable Omnibus reference prices')}\n description={t(\n 'catalog.omnibus.settings.enabledDescription',\n 'When enabled, products in EU channels expose the lowest price from the lookback window.',\n )}\n checked={form.enabled}\n disabled={readOnly}\n onCheckedChange={(next) => updateForm({ enabled: next })}\n />\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <FormField\n label={t('catalog.omnibus.settings.lookbackDays', 'Lookback window (days)')}\n description={t('catalog.omnibus.settings.lookbackDaysDescription', 'Between 1 and 365 days. The directive requires at least 30.')}\n error={fieldErrors.lookbackDays}\n required\n disabled={readOnly}\n >\n <Input\n type=\"number\"\n inputMode=\"numeric\"\n min={MIN_LOOKBACK_DAYS}\n max={MAX_LOOKBACK_DAYS}\n value={form.lookbackDays}\n onChange={(event) => updateForm({ lookbackDays: event.target.value })}\n data-testid=\"catalog-omnibus-lookback\"\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.enabledCountryCodes', 'EU member states')}\n description={t(\n 'catalog.omnibus.settings.enabledCountryCodesDescription',\n 'Two-letter ISO codes of the member states where Omnibus applies. Leave empty to disable it for every channel.',\n )}\n error={fieldErrors.enabledCountryCodes}\n disabled={readOnly}\n >\n <TagInput\n value={form.enabledCountryCodes}\n onChange={(next) => updateForm({ enabledCountryCodes: Array.from(new Set(next.map((code) => code.trim().toUpperCase()))) })}\n validate={(tag) => {\n const code = tag.trim().toUpperCase()\n if (code === 'EU') return errorMessages.omnibus_country_code_eu_not_allowed\n return COUNTRY_CODE_PATTERN.test(code) || errorMessages.omnibus_country_code_alpha2_required\n }}\n placeholder={t('catalog.omnibus.settings.enabledCountryCodesPlaceholder', 'e.g. PL, DE')}\n aria-label={t('catalog.omnibus.settings.enabledCountryCodes', 'EU member states')}\n removeTagLabel={(tag) => t('catalog.omnibus.settings.removeCountry', 'Remove {{code}}', { code: tag })}\n disabled={readOnly}\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.noChannelModeLabel', 'Requests without a channel')}\n error={fieldErrors.noChannelMode}\n disabled={readOnly}\n >\n <Select\n value={form.noChannelMode}\n onValueChange={(next) => updateForm({ noChannelMode: next as OmnibusNoChannelMode })}\n disabled={readOnly}\n >\n <SelectTrigger>\n <SelectValue>{noChannelModeLabels[form.noChannelMode]}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(noChannelModeLabels) as OmnibusNoChannelMode[]).map((mode) => (\n <SelectItem key={mode} value={mode}>{noChannelModeLabels[mode]}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.minimizationAxis', 'Compare prices by')}\n error={fieldErrors.minimizationAxis}\n disabled={readOnly}\n >\n <Select\n value={form.minimizationAxis}\n onValueChange={(next) => updateForm({ minimizationAxis: next as OmnibusMinimizationAxis })}\n disabled={readOnly}\n >\n <SelectTrigger>\n <SelectValue>{axisLabels[form.minimizationAxis]}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(axisLabels) as OmnibusMinimizationAxis[]).map((axis) => (\n <SelectItem key={axis} value={axis}>{axisLabels[axis]}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.defaultPresentedPriceKind', 'Default presented price kind')}\n description={t(\n 'catalog.omnibus.settings.defaultPresentedPriceKindDescription',\n 'The price kind shown to shoppers, used when a channel has no override. Required when Omnibus is enabled without channel overrides.',\n )}\n error={fieldErrors.defaultPresentedPriceKindId}\n disabled={readOnly}\n className=\"md:col-span-2\"\n >\n <PricePriceKindSelect\n value={form.defaultPresentedPriceKindId}\n onChange={(next) => updateForm({ defaultPresentedPriceKindId: next })}\n disabled={readOnly}\n clearable\n />\n </FormField>\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold\">{t('catalog.omnibus.settings.channels.title', 'Channel overrides')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'catalog.omnibus.settings.channels.description',\n 'Map sales channels to a member state and override the presented price kind, lookback or comparison axis per channel.',\n )}\n </p>\n </div>\n {canManage ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addChannel} disabled={saving}>\n <Plus className=\"size-4\" aria-hidden />\n {t('catalog.omnibus.settings.channels.add', 'Add channel')}\n </Button>\n ) : null}\n </div>\n {form.channels.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('catalog.omnibus.settings.channels.empty', 'No channel overrides. Global settings apply to every channel.')}\n </p>\n ) : (\n form.channels.map((row) => {\n const rowError = (field: string) => fieldErrors[channelErrorKey(row.key, field)]\n return (\n <div key={row.key} className=\"space-y-3 rounded-md border p-4\" data-testid=\"catalog-omnibus-channel-row\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"grid flex-1 gap-4 md:grid-cols-2\">\n <FormField\n label={t('catalog.omnibus.settings.channels.channel', 'Channel')}\n error={rowError('channelId')}\n disabled={readOnly}\n >\n <PriceChannelSelect\n value={row.channelId}\n onChange={(next) => updateChannel(row.key, { channelId: next })}\n disabled={readOnly}\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.channels.presentedPriceKind', 'Presented price kind')}\n error={rowError('presentedPriceKindId')}\n disabled={readOnly}\n >\n <PricePriceKindSelect\n value={row.presentedPriceKindId}\n onChange={(next) => updateChannel(row.key, { presentedPriceKindId: next })}\n disabled={readOnly}\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.channels.countryCode', 'Member state')}\n description={t('catalog.omnibus.settings.channels.countryCodeDescription', 'Leave empty for non-EU channels.')}\n error={rowError('countryCode')}\n disabled={readOnly}\n >\n <Input\n value={row.countryCode}\n maxLength={2}\n onChange={(event) => updateChannel(row.key, { countryCode: event.target.value.toUpperCase() })}\n placeholder={t('catalog.omnibus.settings.channels.countryCodePlaceholder', 'e.g. PL')}\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.channels.lookbackDays', 'Lookback override (days)')}\n description={t('catalog.omnibus.settings.channels.lookbackDaysDescription', 'Leave empty to use the global window.')}\n error={rowError('lookbackDays')}\n disabled={readOnly}\n >\n <Input\n type=\"number\"\n inputMode=\"numeric\"\n min={MIN_LOOKBACK_DAYS}\n max={MAX_LOOKBACK_DAYS}\n value={row.lookbackDays}\n onChange={(event) => updateChannel(row.key, { lookbackDays: event.target.value })}\n />\n </FormField>\n <FormField\n label={t('catalog.omnibus.settings.channels.minimizationAxis', 'Compare prices by')}\n error={rowError('minimizationAxis')}\n disabled={readOnly}\n >\n <Select\n value={row.minimizationAxis}\n onValueChange={(next) => updateChannel(row.key, { minimizationAxis: next as ChannelAxisValue })}\n disabled={readOnly}\n >\n <SelectTrigger>\n <SelectValue>\n {row.minimizationAxis === 'inherit'\n ? t('catalog.omnibus.settings.channels.axisInherit', 'Use global setting')\n : axisLabels[row.minimizationAxis]}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"inherit\">\n {t('catalog.omnibus.settings.channels.axisInherit', 'Use global setting')}\n </SelectItem>\n {(Object.keys(axisLabels) as OmnibusMinimizationAxis[]).map((axis) => (\n <SelectItem key={axis} value={axis}>{axisLabels[axis]}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n </div>\n {canManage ? (\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('catalog.omnibus.settings.channels.remove', 'Remove channel override')}\n onClick={() => removeChannel(row.key)}\n disabled={saving}\n >\n <Trash2 className=\"size-4\" aria-hidden />\n </IconButton>\n ) : null}\n </div>\n </div>\n )\n })\n )}\n </div>\n\n {canManage ? (\n <div className=\"flex items-center justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel} disabled={saving}>\n {t('catalog.omnibus.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={saving} data-testid=\"catalog-omnibus-save\">\n {saving\n ? t('catalog.omnibus.settings.actions.saving', 'Saving\u2026')\n : t('catalog.omnibus.settings.actions.save', 'Save')}\n </Button>\n </div>\n ) : null}\n </form>\n )}\n </div>\n </section>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
5
|
+
import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
|
|
6
|
+
import { useBackendChrome } from "@open-mercato/ui/backend/BackendChromeProvider";
|
|
7
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
+
import { hasFeature } from "@open-mercato/shared/security/features";
|
|
9
|
+
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
10
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
11
|
+
import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
|
|
12
|
+
const logger = createLogger("catalog").child({ component: "PriceEditorOmnibusRow" });
|
|
13
|
+
const PRICE_HISTORY_VIEW_FEATURE = "catalog.price_history.view";
|
|
14
|
+
const NOT_APPLICABLE_REASONS = /* @__PURE__ */ new Set([
|
|
15
|
+
"no_history",
|
|
16
|
+
"not_in_eu_market",
|
|
17
|
+
"missing_channel_context",
|
|
18
|
+
"perishable_exempt"
|
|
19
|
+
]);
|
|
20
|
+
const REASON_VARIANTS = {
|
|
21
|
+
no_history: "neutral",
|
|
22
|
+
not_in_eu_market: "neutral",
|
|
23
|
+
missing_channel_context: "warning",
|
|
24
|
+
insufficient_history: "warning",
|
|
25
|
+
announced_promotion: "info",
|
|
26
|
+
not_announced: "neutral",
|
|
27
|
+
progressive_reduction_frozen: "info",
|
|
28
|
+
perishable_exempt: "neutral",
|
|
29
|
+
perishable_last_price: "info",
|
|
30
|
+
new_arrival_reduced_window: "info"
|
|
31
|
+
};
|
|
32
|
+
function isOmnibusBlock(value) {
|
|
33
|
+
if (!value || typeof value !== "object") return false;
|
|
34
|
+
const candidate = value;
|
|
35
|
+
return typeof candidate.applicabilityReason === "string" && typeof candidate.lookbackDays === "number";
|
|
36
|
+
}
|
|
37
|
+
function pickAxisAmount(block, net, gross) {
|
|
38
|
+
return block.minimizationAxis === "net" ? net ?? gross : gross ?? net;
|
|
39
|
+
}
|
|
40
|
+
function formatAmount(amount, currencyCode, locale) {
|
|
41
|
+
if (!amount) return null;
|
|
42
|
+
const numeric = Number(amount);
|
|
43
|
+
const code = currencyCode.toUpperCase();
|
|
44
|
+
if (!Number.isFinite(numeric)) return `${code} ${amount}`;
|
|
45
|
+
try {
|
|
46
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(numeric);
|
|
47
|
+
} catch {
|
|
48
|
+
const formatted = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(numeric);
|
|
49
|
+
return `${code} ${formatted}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function formatDate(value, locale) {
|
|
53
|
+
if (!value) return null;
|
|
54
|
+
const date = new Date(value);
|
|
55
|
+
return Number.isNaN(date.getTime()) ? value : new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date);
|
|
56
|
+
}
|
|
57
|
+
function PriceEditorOmnibusRow({
|
|
58
|
+
priceKindId,
|
|
59
|
+
currencyCode,
|
|
60
|
+
productId,
|
|
61
|
+
variantId,
|
|
62
|
+
offerId,
|
|
63
|
+
channelId,
|
|
64
|
+
channelSelectable = true
|
|
65
|
+
}) {
|
|
66
|
+
const t = useT();
|
|
67
|
+
const locale = useLocale();
|
|
68
|
+
const { payload: chromePayload, isReady: chromeReady } = useBackendChrome();
|
|
69
|
+
const canView = chromeReady && hasFeature(chromePayload?.grantedFeatures, PRICE_HISTORY_VIEW_FEATURE);
|
|
70
|
+
const normalizedCurrency = typeof currencyCode === "string" ? currencyCode.trim().toUpperCase() : "";
|
|
71
|
+
const hasTarget = Boolean(productId || variantId || offerId);
|
|
72
|
+
const [state, setState] = React.useState({ status: "loading" });
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
if (!canView || !hasTarget || !priceKindId || !normalizedCurrency) {
|
|
75
|
+
setState({ status: "hidden" });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
let cancelled = false;
|
|
79
|
+
setState({ status: "loading" });
|
|
80
|
+
const params = new URLSearchParams({ priceKindId, currencyCode: normalizedCurrency });
|
|
81
|
+
if (productId) params.set("productId", productId);
|
|
82
|
+
if (variantId) params.set("variantId", variantId);
|
|
83
|
+
if (offerId) params.set("offerId", offerId);
|
|
84
|
+
if (channelId) params.set("channelId", channelId);
|
|
85
|
+
apiCall(`/api/catalog/prices/omnibus-preview?${params.toString()}`).then((call) => {
|
|
86
|
+
if (cancelled) return;
|
|
87
|
+
if (!call.ok) {
|
|
88
|
+
setState(call.status === 403 || call.status === 404 ? { status: "hidden" } : { status: "error" });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
setState(isOmnibusBlock(call.result) ? { status: "ready", block: call.result } : { status: "hidden" });
|
|
92
|
+
}).catch((err) => {
|
|
93
|
+
logger.error("catalog.omnibus.preview.load failed", { err });
|
|
94
|
+
getTelemetryRuntime()?.reportError(err, { module: "catalog", code: "catalog.omnibus_preview_load_failed" });
|
|
95
|
+
if (!cancelled) setState({ status: "error" });
|
|
96
|
+
});
|
|
97
|
+
return () => {
|
|
98
|
+
cancelled = true;
|
|
99
|
+
};
|
|
100
|
+
}, [canView, channelId, hasTarget, normalizedCurrency, offerId, priceKindId, productId, variantId]);
|
|
101
|
+
const reasonLabels = React.useMemo(() => ({
|
|
102
|
+
no_history: t("catalog.omnibus.reason.noHistory", "No price history"),
|
|
103
|
+
not_in_eu_market: t("catalog.omnibus.reason.notInEuMarket", "Not an EU market"),
|
|
104
|
+
missing_channel_context: t("catalog.omnibus.reason.missingChannelContext", "Channel required"),
|
|
105
|
+
insufficient_history: t("catalog.omnibus.reason.insufficientHistory", "Insufficient history"),
|
|
106
|
+
announced_promotion: t("catalog.omnibus.reason.announcedPromotion", "Announced promotion"),
|
|
107
|
+
not_announced: t("catalog.omnibus.reason.notAnnounced", "No announced reduction"),
|
|
108
|
+
progressive_reduction_frozen: t("catalog.omnibus.reason.progressiveReductionFrozen", "Progressive reduction"),
|
|
109
|
+
perishable_exempt: t("catalog.omnibus.reason.perishableExempt", "Perishable goods exemption"),
|
|
110
|
+
perishable_last_price: t("catalog.omnibus.reason.perishableLastPrice", "Perishable goods: last price"),
|
|
111
|
+
new_arrival_reduced_window: t("catalog.omnibus.reason.newArrivalReducedWindow", "New arrival: shorter window")
|
|
112
|
+
}), [t]);
|
|
113
|
+
if (state.status === "hidden") return null;
|
|
114
|
+
if (state.status === "loading") {
|
|
115
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground", "data-testid": "catalog-price-omnibus-row", children: [
|
|
116
|
+
/* @__PURE__ */ jsx(Spinner, { className: "size-3" }),
|
|
117
|
+
t("catalog.omnibus.priceEditor.loading", "Loading Omnibus reference price\u2026")
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
if (state.status === "error") {
|
|
121
|
+
return /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-status-error-text", "data-testid": "catalog-price-omnibus-row", children: t("catalog.omnibus.priceEditor.loadError", "Could not load the Omnibus reference price.") });
|
|
122
|
+
}
|
|
123
|
+
const { block } = state;
|
|
124
|
+
const reason = block.applicabilityReason;
|
|
125
|
+
const reasonBadge = /* @__PURE__ */ jsx(StatusBadge, { variant: REASON_VARIANTS[reason] ?? "neutral", children: reasonLabels[reason] ?? reason });
|
|
126
|
+
const lowest = formatAmount(pickAxisAmount(block, block.lowestPriceNet, block.lowestPriceGross), block.currencyCode, locale);
|
|
127
|
+
if (NOT_APPLICABLE_REASONS.has(reason) || !lowest) {
|
|
128
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1 text-xs", "data-testid": "catalog-price-omnibus-row", children: [
|
|
129
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-muted-foreground", children: [
|
|
130
|
+
/* @__PURE__ */ jsx("span", { children: t("catalog.omnibus.priceEditor.notApplicable", "Omnibus reference price not applicable") }),
|
|
131
|
+
reasonBadge
|
|
132
|
+
] }),
|
|
133
|
+
reason === "missing_channel_context" ? /* @__PURE__ */ jsx("p", { className: "text-status-warning-text", children: channelSelectable ? t("catalog.omnibus.priceEditor.missingChannel", "Select a channel to compute the reference price.") : t("catalog.omnibus.priceEditor.perChannelReference", "The reference price is computed per sales channel.") }) : null
|
|
134
|
+
] });
|
|
135
|
+
}
|
|
136
|
+
const isProgressive = reason === "progressive_reduction_frozen";
|
|
137
|
+
const previous = isProgressive ? formatAmount(pickAxisAmount(block, block.previousPriceNet, block.previousPriceGross), block.currencyCode, locale) : null;
|
|
138
|
+
const coverageStart = reason === "insufficient_history" ? formatDate(block.coverageStartAt, locale) : null;
|
|
139
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1 text-xs", "data-testid": "catalog-price-omnibus-row", children: [
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
141
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: isProgressive ? t("catalog.omnibus.priceEditor.progressiveRef", "Reference price (frozen for the progressive reduction)") : t("catalog.omnibus.priceEditor.lowestInDays", "Lowest price in the last {{days}} days", { days: block.lookbackDays }) }),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", "data-testid": "catalog-price-omnibus-reference", children: lowest }),
|
|
143
|
+
reasonBadge
|
|
144
|
+
] }),
|
|
145
|
+
previous ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t("catalog.omnibus.priceEditor.previousPrice", "Price before the reduction: {{price}}", { price: previous }) }) : null,
|
|
146
|
+
reason === "insufficient_history" ? /* @__PURE__ */ jsx("p", { className: "text-status-warning-text", children: coverageStart ? t("catalog.omnibus.priceEditor.insufficientHistorySince", "Price history is only available since {{date}}; the reference may be incomplete.", { date: coverageStart }) : t("catalog.omnibus.priceEditor.insufficientHistory", "Price history does not cover the full window; the reference may be incomplete.") }) : null
|
|
147
|
+
] });
|
|
148
|
+
}
|
|
149
|
+
export {
|
|
150
|
+
PriceEditorOmnibusRow
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=PriceEditorOmnibusRow.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/components/PriceEditorOmnibusRow.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { StatusBadge, type StatusBadgeVariant } from '@open-mercato/ui/primitives/status-badge'\nimport { useBackendChrome } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\nimport type { OmnibusApplicabilityReason, OmnibusBlock } from '../lib/omnibusTypes'\n\nconst logger = createLogger('catalog').child({ component: 'PriceEditorOmnibusRow' })\n\nconst PRICE_HISTORY_VIEW_FEATURE = 'catalog.price_history.view'\n\nconst NOT_APPLICABLE_REASONS: ReadonlySet<OmnibusApplicabilityReason> = new Set([\n 'no_history',\n 'not_in_eu_market',\n 'missing_channel_context',\n 'perishable_exempt',\n])\n\nconst REASON_VARIANTS: Record<OmnibusApplicabilityReason, StatusBadgeVariant> = {\n no_history: 'neutral',\n not_in_eu_market: 'neutral',\n missing_channel_context: 'warning',\n insufficient_history: 'warning',\n announced_promotion: 'info',\n not_announced: 'neutral',\n progressive_reduction_frozen: 'info',\n perishable_exempt: 'neutral',\n perishable_last_price: 'info',\n new_arrival_reduced_window: 'info',\n}\n\ntype PreviewState =\n | { status: 'loading' }\n | { status: 'hidden' }\n | { status: 'error' }\n | { status: 'ready'; block: OmnibusBlock }\n\nexport type PriceEditorOmnibusRowProps = {\n priceKindId: string\n currencyCode: string | null | undefined\n productId?: string | null\n variantId?: string | null\n offerId?: string | null\n channelId?: string | null\n channelSelectable?: boolean\n}\n\nfunction isOmnibusBlock(value: unknown): value is OmnibusBlock {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Partial<OmnibusBlock>\n return typeof candidate.applicabilityReason === 'string' && typeof candidate.lookbackDays === 'number'\n}\n\nfunction pickAxisAmount(block: OmnibusBlock, net: string | null, gross: string | null): string | null {\n return block.minimizationAxis === 'net' ? net ?? gross : gross ?? net\n}\n\nfunction formatAmount(amount: string | null, currencyCode: string, locale: string): string | null {\n if (!amount) return null\n const numeric = Number(amount)\n const code = currencyCode.toUpperCase()\n if (!Number.isFinite(numeric)) return `${code} ${amount}`\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(numeric)\n } catch {\n const formatted = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(numeric)\n return `${code} ${formatted}`\n }\n}\n\nfunction formatDate(value: string | null, locale: string): string | null {\n if (!value) return null\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? value : new Intl.DateTimeFormat(locale, { dateStyle: 'medium' }).format(date)\n}\n\nexport function PriceEditorOmnibusRow({\n priceKindId,\n currencyCode,\n productId,\n variantId,\n offerId,\n channelId,\n channelSelectable = true,\n}: PriceEditorOmnibusRowProps) {\n const t = useT()\n const locale = useLocale()\n const { payload: chromePayload, isReady: chromeReady } = useBackendChrome()\n const canView = chromeReady && hasFeature(chromePayload?.grantedFeatures, PRICE_HISTORY_VIEW_FEATURE)\n const normalizedCurrency = typeof currencyCode === 'string' ? currencyCode.trim().toUpperCase() : ''\n const hasTarget = Boolean(productId || variantId || offerId)\n const [state, setState] = React.useState<PreviewState>({ status: 'loading' })\n\n React.useEffect(() => {\n if (!canView || !hasTarget || !priceKindId || !normalizedCurrency) {\n setState({ status: 'hidden' })\n return\n }\n let cancelled = false\n setState({ status: 'loading' })\n const params = new URLSearchParams({ priceKindId, currencyCode: normalizedCurrency })\n if (productId) params.set('productId', productId)\n if (variantId) params.set('variantId', variantId)\n if (offerId) params.set('offerId', offerId)\n if (channelId) params.set('channelId', channelId)\n apiCall<unknown>(`/api/catalog/prices/omnibus-preview?${params.toString()}`)\n .then((call) => {\n if (cancelled) return\n if (!call.ok) {\n setState(call.status === 403 || call.status === 404 ? { status: 'hidden' } : { status: 'error' })\n return\n }\n setState(isOmnibusBlock(call.result) ? { status: 'ready', block: call.result } : { status: 'hidden' })\n })\n .catch((err) => {\n logger.error('catalog.omnibus.preview.load failed', { err })\n getTelemetryRuntime()?.reportError(err, { module: 'catalog', code: 'catalog.omnibus_preview_load_failed' })\n if (!cancelled) setState({ status: 'error' })\n })\n return () => {\n cancelled = true\n }\n }, [canView, channelId, hasTarget, normalizedCurrency, offerId, priceKindId, productId, variantId])\n\n const reasonLabels = React.useMemo<Record<OmnibusApplicabilityReason, string>>(() => ({\n no_history: t('catalog.omnibus.reason.noHistory', 'No price history'),\n not_in_eu_market: t('catalog.omnibus.reason.notInEuMarket', 'Not an EU market'),\n missing_channel_context: t('catalog.omnibus.reason.missingChannelContext', 'Channel required'),\n insufficient_history: t('catalog.omnibus.reason.insufficientHistory', 'Insufficient history'),\n announced_promotion: t('catalog.omnibus.reason.announcedPromotion', 'Announced promotion'),\n not_announced: t('catalog.omnibus.reason.notAnnounced', 'No announced reduction'),\n progressive_reduction_frozen: t('catalog.omnibus.reason.progressiveReductionFrozen', 'Progressive reduction'),\n perishable_exempt: t('catalog.omnibus.reason.perishableExempt', 'Perishable goods exemption'),\n perishable_last_price: t('catalog.omnibus.reason.perishableLastPrice', 'Perishable goods: last price'),\n new_arrival_reduced_window: t('catalog.omnibus.reason.newArrivalReducedWindow', 'New arrival: shorter window'),\n }), [t])\n\n if (state.status === 'hidden') return null\n\n if (state.status === 'loading') {\n return (\n <div className=\"mt-2 flex items-center gap-2 text-xs text-muted-foreground\" data-testid=\"catalog-price-omnibus-row\">\n <Spinner className=\"size-3\" />\n {t('catalog.omnibus.priceEditor.loading', 'Loading Omnibus reference price\u2026')}\n </div>\n )\n }\n\n if (state.status === 'error') {\n return (\n <p className=\"mt-2 text-xs text-status-error-text\" data-testid=\"catalog-price-omnibus-row\">\n {t('catalog.omnibus.priceEditor.loadError', 'Could not load the Omnibus reference price.')}\n </p>\n )\n }\n\n const { block } = state\n const reason = block.applicabilityReason\n const reasonBadge = (\n <StatusBadge variant={REASON_VARIANTS[reason] ?? 'neutral'}>{reasonLabels[reason] ?? reason}</StatusBadge>\n )\n const lowest = formatAmount(pickAxisAmount(block, block.lowestPriceNet, block.lowestPriceGross), block.currencyCode, locale)\n\n if (NOT_APPLICABLE_REASONS.has(reason) || !lowest) {\n return (\n <div className=\"mt-2 space-y-1 text-xs\" data-testid=\"catalog-price-omnibus-row\">\n <div className=\"flex flex-wrap items-center gap-2 text-muted-foreground\">\n <span>{t('catalog.omnibus.priceEditor.notApplicable', 'Omnibus reference price not applicable')}</span>\n {reasonBadge}\n </div>\n {reason === 'missing_channel_context' ? (\n <p className=\"text-status-warning-text\">\n {channelSelectable\n ? t('catalog.omnibus.priceEditor.missingChannel', 'Select a channel to compute the reference price.')\n : t('catalog.omnibus.priceEditor.perChannelReference', 'The reference price is computed per sales channel.')}\n </p>\n ) : null}\n </div>\n )\n }\n\n const isProgressive = reason === 'progressive_reduction_frozen'\n const previous = isProgressive\n ? formatAmount(pickAxisAmount(block, block.previousPriceNet, block.previousPriceGross), block.currencyCode, locale)\n : null\n const coverageStart = reason === 'insufficient_history' ? formatDate(block.coverageStartAt, locale) : null\n\n return (\n <div className=\"mt-2 space-y-1 text-xs\" data-testid=\"catalog-price-omnibus-row\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-muted-foreground\">\n {isProgressive\n ? t('catalog.omnibus.priceEditor.progressiveRef', 'Reference price (frozen for the progressive reduction)')\n : t('catalog.omnibus.priceEditor.lowestInDays', 'Lowest price in the last {{days}} days', { days: block.lookbackDays })}\n </span>\n <span className=\"font-medium\" data-testid=\"catalog-price-omnibus-reference\">{lowest}</span>\n {reasonBadge}\n </div>\n {previous ? (\n <p className=\"text-muted-foreground\">\n {t('catalog.omnibus.priceEditor.previousPrice', 'Price before the reduction: {{price}}', { price: previous })}\n </p>\n ) : null}\n {reason === 'insufficient_history' ? (\n <p className=\"text-status-warning-text\">\n {coverageStart\n ? t('catalog.omnibus.priceEditor.insufficientHistorySince', 'Price history is only available since {{date}}; the reference may be incomplete.', { date: coverageStart })\n : t('catalog.omnibus.priceEditor.insufficientHistory', 'Price history does not cover the full window; the reference may be incomplete.')}\n </p>\n ) : null}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createIdsLookupSource,
|
|
3
|
+
pickLookupString
|
|
4
|
+
} from "@open-mercato/ui/backend/inputs/lookupSources";
|
|
5
|
+
const categoryLookupSource = createIdsLookupSource(
|
|
6
|
+
"categories",
|
|
7
|
+
"/api/catalog/categories",
|
|
8
|
+
(item) => {
|
|
9
|
+
const value = pickLookupString(item, "id");
|
|
10
|
+
if (!value) return null;
|
|
11
|
+
return { value, label: pickLookupString(item, "pathLabel", "name") || value };
|
|
12
|
+
},
|
|
13
|
+
{ view: "manage" }
|
|
14
|
+
);
|
|
15
|
+
const productLookupSource = createIdsLookupSource("products", "/api/catalog/products", (item) => {
|
|
16
|
+
const value = pickLookupString(item, "id");
|
|
17
|
+
if (!value) return null;
|
|
18
|
+
const sku = pickLookupString(item, "sku");
|
|
19
|
+
return { value, label: pickLookupString(item, "title", "name") || value, description: sku || null };
|
|
20
|
+
});
|
|
21
|
+
const tagLookupSource = createIdsLookupSource("tags", "/api/catalog/tags", (item) => {
|
|
22
|
+
const value = pickLookupString(item, "id");
|
|
23
|
+
if (!value) return null;
|
|
24
|
+
return { value, label: pickLookupString(item, "label") || value };
|
|
25
|
+
});
|
|
26
|
+
export {
|
|
27
|
+
categoryLookupSource,
|
|
28
|
+
productLookupSource,
|
|
29
|
+
tagLookupSource
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=lookupSources.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/components/lookupSources.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n createIdsLookupSource,\n pickLookupString,\n type LookupSource,\n} from '@open-mercato/ui/backend/inputs/lookupSources'\n\nexport const categoryLookupSource: LookupSource = createIdsLookupSource(\n 'categories',\n '/api/catalog/categories',\n (item) => {\n const value = pickLookupString(item, 'id')\n if (!value) return null\n return { value, label: pickLookupString(item, 'pathLabel', 'name') || value }\n },\n { view: 'manage' },\n)\n\nexport const productLookupSource: LookupSource = createIdsLookupSource('products', '/api/catalog/products', (item) => {\n const value = pickLookupString(item, 'id')\n if (!value) return null\n const sku = pickLookupString(item, 'sku')\n return { value, label: pickLookupString(item, 'title', 'name') || value, description: sku || null }\n})\n\nexport const tagLookupSource: LookupSource = createIdsLookupSource('tags', '/api/catalog/tags', (item) => {\n const value = pickLookupString(item, 'id')\n if (!value) return null\n return { value, label: pickLookupString(item, 'label') || value }\n})\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAEA,MAAM,uBAAqC;AAAA,EAChD;AAAA,EACA;AAAA,EACA,CAAC,SAAS;AACR,UAAM,QAAQ,iBAAiB,MAAM,IAAI;AACzC,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,EAAE,OAAO,OAAO,iBAAiB,MAAM,aAAa,MAAM,KAAK,MAAM;AAAA,EAC9E;AAAA,EACA,EAAE,MAAM,SAAS;AACnB;AAEO,MAAM,sBAAoC,sBAAsB,YAAY,yBAAyB,CAAC,SAAS;AACpH,QAAM,QAAQ,iBAAiB,MAAM,IAAI;AACzC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,iBAAiB,MAAM,KAAK;AACxC,SAAO,EAAE,OAAO,OAAO,iBAAiB,MAAM,SAAS,MAAM,KAAK,OAAO,aAAa,OAAO,KAAK;AACpG,CAAC;AAEM,MAAM,kBAAgC,sBAAsB,QAAQ,qBAAqB,CAAC,SAAS;AACxG,QAAM,QAAQ,iBAAiB,MAAM,IAAI;AACzC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,EAAE,OAAO,OAAO,iBAAiB,MAAM,OAAO,KAAK,MAAM;AAClE,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -120,7 +120,8 @@ function PriceCustomerSelect({
|
|
|
120
120
|
}
|
|
121
121
|
function PriceChannelSelect({
|
|
122
122
|
value,
|
|
123
|
-
onChange
|
|
123
|
+
onChange,
|
|
124
|
+
disabled
|
|
124
125
|
}) {
|
|
125
126
|
const t = useT();
|
|
126
127
|
const mapItem = React.useCallback((item) => {
|
|
@@ -135,6 +136,7 @@ function PriceChannelSelect({
|
|
|
135
136
|
{
|
|
136
137
|
value,
|
|
137
138
|
onChange,
|
|
139
|
+
disabled,
|
|
138
140
|
allowCustomValues: false,
|
|
139
141
|
clearable: true,
|
|
140
142
|
placeholder: t("catalog.prices.select.channel.placeholder", "Select a channel\u2026"),
|
|
@@ -145,7 +147,9 @@ function PriceChannelSelect({
|
|
|
145
147
|
}
|
|
146
148
|
function PricePriceKindSelect({
|
|
147
149
|
value,
|
|
148
|
-
onChange
|
|
150
|
+
onChange,
|
|
151
|
+
disabled,
|
|
152
|
+
clearable
|
|
149
153
|
}) {
|
|
150
154
|
const t = useT();
|
|
151
155
|
const mapItem = React.useCallback((item) => {
|
|
@@ -160,7 +164,9 @@ function PricePriceKindSelect({
|
|
|
160
164
|
{
|
|
161
165
|
value,
|
|
162
166
|
onChange,
|
|
167
|
+
disabled,
|
|
163
168
|
allowCustomValues: false,
|
|
169
|
+
clearable,
|
|
164
170
|
placeholder: t("catalog.prices.select.priceKind.placeholder", "Select a price kind\u2026"),
|
|
165
171
|
loadSuggestions: (query) => loadOptions("/api/catalog/price-kinds", buildLookupParams(query, "20"), mapItem),
|
|
166
172
|
resolveLabel: (id) => resolveOne("/api/catalog/price-kinds", "ids", id, mapItem)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/catalog/components/prices/PriceScopeSelectors.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { ComboboxInput, type ComboboxOption } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('catalog').child({ component: 'PriceScopeSelectors' })\n\ntype RemoteItem = Record<string, unknown>\n\nfunction pickString(item: RemoteItem, ...keys: string[]): string {\n for (const key of keys) {\n const value = item[key]\n if (typeof value === 'string' && value.length) return value\n }\n return ''\n}\n\nasync function loadOptions(\n path: string,\n params: Record<string, string>,\n mapItem: (item: RemoteItem) => ComboboxOption | null,\n): Promise<ComboboxOption[]> {\n try {\n const search = new URLSearchParams(params)\n const payload = await readApiResultOrThrow<{ items?: RemoteItem[] }>(\n `${path}?${search.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n return items.map(mapItem).filter((option): option is ComboboxOption => option !== null)\n } catch (err) {\n logger.error('catalog.prices.scopeSelect.load', { err, path })\n return []\n }\n}\n\nasync function resolveOne(\n path: string,\n idParam: string,\n id: string,\n mapItem: (item: RemoteItem) => ComboboxOption | null,\n): Promise<string> {\n const options = await loadOptions(path, { [idParam]: id, pageSize: '1' }, mapItem)\n return options.find((option) => option.value === id)?.label ?? id\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n/**\n * A typed query that is itself a record id (a pasted UUID) is searched via\n * the generic `ids=` narrowing instead of the entity's free-text `search=`\n * filter \u2014 free-text search matches title/name/sku columns, never the id\n * column, so pasting an exact id would otherwise return zero suggestions.\n */\nfunction buildLookupParams(query: string | undefined, pageSize: string): Record<string, string> {\n const trimmed = (query ?? '').trim()\n if (UUID_PATTERN.test(trimmed)) return { ids: trimmed, pageSize: '1' }\n return { search: trimmed, pageSize }\n}\n\nexport function PriceProductSelect({\n value,\n onChange,\n disabled,\n}: {\n value: string\n onChange: (next: string) => void\n disabled?: boolean\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const title = pickString(item, 'title', 'name') || id\n const sku = pickString(item, 'sku')\n return { value: id, label: sku ? `${title} (${sku})` : title }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.product.placeholder', 'Search products\u2026')}\n loadSuggestions={(query) => loadOptions('/api/catalog/products', buildLookupParams(query, '10'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/catalog/products', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceVariantSelect({\n productId,\n value,\n onChange,\n}: {\n productId: string\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'name') || id\n const sku = pickString(item, 'sku')\n return { value: id, label: sku ? `${name} (${sku})` : name }\n }, [])\n const disabled = !productId\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable\n placeholder={\n disabled\n ? t('catalog.prices.form.field.product', 'Product')\n : t('catalog.prices.select.product.placeholder', 'Search products\u2026')\n }\n loadSuggestions={(query) =>\n disabled\n ? Promise.resolve([])\n : loadOptions('/api/catalog/variants', { ...buildLookupParams(query, '10'), productId }, mapItem)\n }\n resolveLabel={(id) => resolveOne('/api/catalog/variants', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceCustomerSelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'displayName', 'display_name', 'name') || id\n const email = pickString(item, 'primaryEmail', 'primary_email')\n return { value: id, label: name, description: email || null }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.customer.placeholder', 'Search customers\u2026')}\n loadSuggestions={(query) => loadOptions('/api/customers/people', buildLookupParams(query, '10'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/customers/people', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceChannelSelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'name') || id\n const code = pickString(item, 'code')\n return { value: id, label: code ? `${name} (${code})` : name }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.channel.placeholder', 'Select a channel\u2026')}\n loadSuggestions={(query) => loadOptions('/api/sales/channels', buildLookupParams(query, '50'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/sales/channels', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PricePriceKindSelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const title = pickString(item, 'title') || id\n const code = pickString(item, 'code')\n return { value: id, label: code ? `${title} (${code})` : title }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n placeholder={t('catalog.prices.select.priceKind.placeholder', 'Select a price kind\u2026')}\n loadSuggestions={(query) => loadOptions('/api/catalog/price-kinds', buildLookupParams(query, '20'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/catalog/price-kinds', 'ids', id, mapItem)}\n />\n )\n}\n\nexport function PriceCurrencySelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const code = pickString(item, 'value')\n if (!code) return null\n const label = pickString(item, 'label') || code\n return { value: code, label: label === code ? code : `${code} \u2014 ${label}` }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n placeholder={t('catalog.prices.select.currency.placeholder', 'Select a currency\u2026')}\n loadSuggestions={(query) => loadOptions('/api/currencies/currencies/options', { search: query ?? '', limit: '20' }, mapItem)}\n resolveLabel={(id) => resolveOne('/api/currencies/currencies/options', 'search', id, mapItem)}\n />\n )\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { ComboboxInput, type ComboboxOption } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('catalog').child({ component: 'PriceScopeSelectors' })\n\ntype RemoteItem = Record<string, unknown>\n\nfunction pickString(item: RemoteItem, ...keys: string[]): string {\n for (const key of keys) {\n const value = item[key]\n if (typeof value === 'string' && value.length) return value\n }\n return ''\n}\n\nasync function loadOptions(\n path: string,\n params: Record<string, string>,\n mapItem: (item: RemoteItem) => ComboboxOption | null,\n): Promise<ComboboxOption[]> {\n try {\n const search = new URLSearchParams(params)\n const payload = await readApiResultOrThrow<{ items?: RemoteItem[] }>(\n `${path}?${search.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n return items.map(mapItem).filter((option): option is ComboboxOption => option !== null)\n } catch (err) {\n logger.error('catalog.prices.scopeSelect.load', { err, path })\n return []\n }\n}\n\nasync function resolveOne(\n path: string,\n idParam: string,\n id: string,\n mapItem: (item: RemoteItem) => ComboboxOption | null,\n): Promise<string> {\n const options = await loadOptions(path, { [idParam]: id, pageSize: '1' }, mapItem)\n return options.find((option) => option.value === id)?.label ?? id\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n/**\n * A typed query that is itself a record id (a pasted UUID) is searched via\n * the generic `ids=` narrowing instead of the entity's free-text `search=`\n * filter \u2014 free-text search matches title/name/sku columns, never the id\n * column, so pasting an exact id would otherwise return zero suggestions.\n */\nfunction buildLookupParams(query: string | undefined, pageSize: string): Record<string, string> {\n const trimmed = (query ?? '').trim()\n if (UUID_PATTERN.test(trimmed)) return { ids: trimmed, pageSize: '1' }\n return { search: trimmed, pageSize }\n}\n\nexport function PriceProductSelect({\n value,\n onChange,\n disabled,\n}: {\n value: string\n onChange: (next: string) => void\n disabled?: boolean\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const title = pickString(item, 'title', 'name') || id\n const sku = pickString(item, 'sku')\n return { value: id, label: sku ? `${title} (${sku})` : title }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.product.placeholder', 'Search products\u2026')}\n loadSuggestions={(query) => loadOptions('/api/catalog/products', buildLookupParams(query, '10'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/catalog/products', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceVariantSelect({\n productId,\n value,\n onChange,\n}: {\n productId: string\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'name') || id\n const sku = pickString(item, 'sku')\n return { value: id, label: sku ? `${name} (${sku})` : name }\n }, [])\n const disabled = !productId\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable\n placeholder={\n disabled\n ? t('catalog.prices.form.field.product', 'Product')\n : t('catalog.prices.select.product.placeholder', 'Search products\u2026')\n }\n loadSuggestions={(query) =>\n disabled\n ? Promise.resolve([])\n : loadOptions('/api/catalog/variants', { ...buildLookupParams(query, '10'), productId }, mapItem)\n }\n resolveLabel={(id) => resolveOne('/api/catalog/variants', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceCustomerSelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'displayName', 'display_name', 'name') || id\n const email = pickString(item, 'primaryEmail', 'primary_email')\n return { value: id, label: name, description: email || null }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.customer.placeholder', 'Search customers\u2026')}\n loadSuggestions={(query) => loadOptions('/api/customers/people', buildLookupParams(query, '10'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/customers/people', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PriceChannelSelect({\n value,\n onChange,\n disabled,\n}: {\n value: string\n onChange: (next: string) => void\n disabled?: boolean\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const name = pickString(item, 'name') || id\n const code = pickString(item, 'code')\n return { value: id, label: code ? `${name} (${code})` : name }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable\n placeholder={t('catalog.prices.select.channel.placeholder', 'Select a channel\u2026')}\n loadSuggestions={(query) => loadOptions('/api/sales/channels', buildLookupParams(query, '50'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/sales/channels', 'id', id, mapItem)}\n />\n )\n}\n\nexport function PricePriceKindSelect({\n value,\n onChange,\n disabled,\n clearable,\n}: {\n value: string\n onChange: (next: string) => void\n disabled?: boolean\n clearable?: boolean\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const id = pickString(item, 'id')\n if (!id) return null\n const title = pickString(item, 'title') || id\n const code = pickString(item, 'code')\n return { value: id, label: code ? `${title} (${code})` : title }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n disabled={disabled}\n allowCustomValues={false}\n clearable={clearable}\n placeholder={t('catalog.prices.select.priceKind.placeholder', 'Select a price kind\u2026')}\n loadSuggestions={(query) => loadOptions('/api/catalog/price-kinds', buildLookupParams(query, '20'), mapItem)}\n resolveLabel={(id) => resolveOne('/api/catalog/price-kinds', 'ids', id, mapItem)}\n />\n )\n}\n\nexport function PriceCurrencySelect({\n value,\n onChange,\n}: {\n value: string\n onChange: (next: string) => void\n}) {\n const t = useT()\n const mapItem = React.useCallback((item: RemoteItem): ComboboxOption | null => {\n const code = pickString(item, 'value')\n if (!code) return null\n const label = pickString(item, 'label') || code\n return { value: code, label: label === code ? code : `${code} \u2014 ${label}` }\n }, [])\n return (\n <ComboboxInput\n value={value}\n onChange={onChange}\n allowCustomValues={false}\n placeholder={t('catalog.prices.select.currency.placeholder', 'Select a currency\u2026')}\n loadSuggestions={(query) => loadOptions('/api/currencies/currencies/options', { search: query ?? '', limit: '20' }, mapItem)}\n resolveLabel={(id) => resolveOne('/api/currencies/currencies/options', 'search', id, mapItem)}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAkFI;AAhFJ,YAAY,WAAW;AACvB,SAAS,qBAA0C;AACnD,SAAS,4BAA4B;AACrC,SAAS,YAAY;AACrB,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,SAAS,EAAE,MAAM,EAAE,WAAW,sBAAsB,CAAC;AAIjF,SAAS,WAAW,SAAqB,MAAwB;AAC/D,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,KAAK,GAAG;AACtB,QAAI,OAAO,UAAU,YAAY,MAAM,OAAQ,QAAO;AAAA,EACxD;AACA,SAAO;AACT;AAEA,eAAe,YACb,MACA,QACA,SAC2B;AAC3B,MAAI;AACF,UAAM,SAAS,IAAI,gBAAgB,MAAM;AACzC,UAAM,UAAU,MAAM;AAAA,MACpB,GAAG,IAAI,IAAI,OAAO,SAAS,CAAC;AAAA,MAC5B;AAAA,MACA,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,IAC5B;AACA,UAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,WAAO,MAAM,IAAI,OAAO,EAAE,OAAO,CAAC,WAAqC,WAAW,IAAI;AAAA,EACxF,SAAS,KAAK;AACZ,WAAO,MAAM,mCAAmC,EAAE,KAAK,KAAK,CAAC;AAC7D,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,WACb,MACA,SACA,IACA,SACiB;AACjB,QAAM,UAAU,MAAM,YAAY,MAAM,EAAE,CAAC,OAAO,GAAG,IAAI,UAAU,IAAI,GAAG,OAAO;AACjF,SAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,EAAE,GAAG,SAAS;AACjE;AAEA,MAAM,eAAe;AAQrB,SAAS,kBAAkB,OAA2B,UAA0C;AAC9F,QAAM,WAAW,SAAS,IAAI,KAAK;AACnC,MAAI,aAAa,KAAK,OAAO,EAAG,QAAO,EAAE,KAAK,SAAS,UAAU,IAAI;AACrE,SAAO,EAAE,QAAQ,SAAS,SAAS;AACrC;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,KAAK,WAAW,MAAM,IAAI;AAChC,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,QAAQ,WAAW,MAAM,SAAS,MAAM,KAAK;AACnD,UAAM,MAAM,WAAW,MAAM,KAAK;AAClC,WAAO,EAAE,OAAO,IAAI,OAAO,MAAM,GAAG,KAAK,KAAK,GAAG,MAAM,MAAM;AAAA,EAC/D,GAAG,CAAC,CAAC;AACL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,WAAS;AAAA,MACT,aAAa,EAAE,6CAA6C,uBAAkB;AAAA,MAC9E,iBAAiB,CAAC,UAAU,YAAY,yBAAyB,kBAAkB,OAAO,IAAI,GAAG,OAAO;AAAA,MACxG,cAAc,CAAC,OAAO,WAAW,yBAAyB,MAAM,IAAI,OAAO;AAAA;AAAA,EAC7E;AAEJ;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,KAAK,WAAW,MAAM,IAAI;AAChC,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,OAAO,WAAW,MAAM,MAAM,KAAK;AACzC,UAAM,MAAM,WAAW,MAAM,KAAK;AAClC,WAAO,EAAE,OAAO,IAAI,OAAO,MAAM,GAAG,IAAI,KAAK,GAAG,MAAM,KAAK;AAAA,EAC7D,GAAG,CAAC,CAAC;AACL,QAAM,WAAW,CAAC;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,WAAS;AAAA,MACT,aACE,WACI,EAAE,qCAAqC,SAAS,IAChD,EAAE,6CAA6C,uBAAkB;AAAA,MAEvE,iBAAiB,CAAC,UAChB,WACI,QAAQ,QAAQ,CAAC,CAAC,IAClB,YAAY,yBAAyB,EAAE,GAAG,kBAAkB,OAAO,IAAI,GAAG,UAAU,GAAG,OAAO;AAAA,MAEpG,cAAc,CAAC,OAAO,WAAW,yBAAyB,MAAM,IAAI,OAAO;AAAA;AAAA,EAC7E;AAEJ;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,KAAK,WAAW,MAAM,IAAI;AAChC,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,OAAO,WAAW,MAAM,eAAe,gBAAgB,MAAM,KAAK;AACxE,UAAM,QAAQ,WAAW,MAAM,gBAAgB,eAAe;AAC9D,WAAO,EAAE,OAAO,IAAI,OAAO,MAAM,aAAa,SAAS,KAAK;AAAA,EAC9D,GAAG,CAAC,CAAC;AACL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,WAAS;AAAA,MACT,aAAa,EAAE,8CAA8C,wBAAmB;AAAA,MAChF,iBAAiB,CAAC,UAAU,YAAY,yBAAyB,kBAAkB,OAAO,IAAI,GAAG,OAAO;AAAA,MACxG,cAAc,CAAC,OAAO,WAAW,yBAAyB,MAAM,IAAI,OAAO;AAAA;AAAA,EAC7E;AAEJ;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,KAAK,WAAW,MAAM,IAAI;AAChC,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,OAAO,WAAW,MAAM,MAAM,KAAK;AACzC,UAAM,OAAO,WAAW,MAAM,MAAM;AACpC,WAAO,EAAE,OAAO,IAAI,OAAO,OAAO,GAAG,IAAI,KAAK,IAAI,MAAM,KAAK;AAAA,EAC/D,GAAG,CAAC,CAAC;AACL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,WAAS;AAAA,MACT,aAAa,EAAE,6CAA6C,wBAAmB;AAAA,MAC/E,iBAAiB,CAAC,UAAU,YAAY,uBAAuB,kBAAkB,OAAO,IAAI,GAAG,OAAO;AAAA,MACtG,cAAc,CAAC,OAAO,WAAW,uBAAuB,MAAM,IAAI,OAAO;AAAA;AAAA,EAC3E;AAEJ;AAEO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,KAAK,WAAW,MAAM,IAAI;AAChC,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,QAAQ,WAAW,MAAM,OAAO,KAAK;AAC3C,UAAM,OAAO,WAAW,MAAM,MAAM;AACpC,WAAO,EAAE,OAAO,IAAI,OAAO,OAAO,GAAG,KAAK,KAAK,IAAI,MAAM,MAAM;AAAA,EACjE,GAAG,CAAC,CAAC;AACL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB;AAAA,MACA,aAAa,EAAE,+CAA+C,2BAAsB;AAAA,MACpF,iBAAiB,CAAC,UAAU,YAAY,4BAA4B,kBAAkB,OAAO,IAAI,GAAG,OAAO;AAAA,MAC3G,cAAc,CAAC,OAAO,WAAW,4BAA4B,OAAO,IAAI,OAAO;AAAA;AAAA,EACjF;AAEJ;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,MAAM,YAAY,CAAC,SAA4C;AAC7E,UAAM,OAAO,WAAW,MAAM,OAAO;AACrC,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,WAAW,MAAM,OAAO,KAAK;AAC3C,WAAO,EAAE,OAAO,MAAM,OAAO,UAAU,OAAO,OAAO,GAAG,IAAI,WAAM,KAAK,GAAG;AAAA,EAC5E,GAAG,CAAC,CAAC;AACL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,aAAa,EAAE,8CAA8C,yBAAoB;AAAA,MACjF,iBAAiB,CAAC,UAAU,YAAY,sCAAsC,EAAE,QAAQ,SAAS,IAAI,OAAO,KAAK,GAAG,OAAO;AAAA,MAC3H,cAAc,CAAC,OAAO,WAAW,sCAAsC,UAAU,IAAI,OAAO;AAAA;AAAA,EAC9F;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { Switch } from "@open-mercato/ui/primitives/switch";
|
|
16
16
|
import { ProductMediaManager } from "./ProductMediaManager.js";
|
|
17
17
|
import { MetadataEditor } from "./MetadataEditor.js";
|
|
18
|
+
import { PriceEditorOmnibusRow } from "../PriceEditorOmnibusRow.js";
|
|
18
19
|
import { formatTaxRateLabel } from "./productForm.js";
|
|
19
20
|
import { CATALOG_GTIN_TYPES } from "../../data/types.js";
|
|
20
21
|
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
@@ -346,7 +347,16 @@ function VariantPricesSection({
|
|
|
346
347
|
onChange: (event) => updatePrice(kind.id, { amount: event.target.value }),
|
|
347
348
|
placeholder: "0.00"
|
|
348
349
|
}
|
|
349
|
-
)
|
|
350
|
+
),
|
|
351
|
+
values.id && draft?.priceId ? /* @__PURE__ */ jsx(
|
|
352
|
+
PriceEditorOmnibusRow,
|
|
353
|
+
{
|
|
354
|
+
variantId: values.id,
|
|
355
|
+
priceKindId: kind.id,
|
|
356
|
+
currencyCode: draft.currencyCode ?? kind.currencyCode,
|
|
357
|
+
channelSelectable: false
|
|
358
|
+
}
|
|
359
|
+
) : null
|
|
350
360
|
] }, kind.id);
|
|
351
361
|
}) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("catalog.variants.form.pricesEmpty", "No price kinds configured yet.") }) })
|
|
352
362
|
] });
|