@aglyn/plugins-commerce 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +10 -0
- package/package.json +57 -0
- package/src/index.d.ts +38 -0
- package/src/index.js +38 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/account.d.ts +31 -0
- package/src/lib/components/account.js +645 -0
- package/src/lib/components/account.js.map +1 -0
- package/src/lib/components/cart.d.ts +38 -0
- package/src/lib/components/cart.js +851 -0
- package/src/lib/components/cart.js.map +1 -0
- package/src/lib/components/commerce-console-page.d.ts +32 -0
- package/src/lib/components/commerce-console-page.js +296 -0
- package/src/lib/components/commerce-console-page.js.map +1 -0
- package/src/lib/components/commerce-console-sections.d.ts +34 -0
- package/src/lib/components/commerce-console-sections.js +62 -0
- package/src/lib/components/commerce-console-sections.js.map +1 -0
- package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
- package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
- package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
- package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
- package/src/lib/components/console/commerce-glance-card.component.js +340 -0
- package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
- package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
- package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
- package/src/lib/components/console/discounts-card.component.d.ts +14 -0
- package/src/lib/components/console/discounts-card.component.js +443 -0
- package/src/lib/components/console/discounts-card.component.js.map +1 -0
- package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
- package/src/lib/components/console/entitlement-gate.component.js +115 -0
- package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
- package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
- package/src/lib/components/console/gift-cards-card.component.js +379 -0
- package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
- package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
- package/src/lib/components/console/host-coupons-card.component.js +252 -0
- package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
- package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
- package/src/lib/components/console/host-orders-card.component.js +861 -0
- package/src/lib/components/console/host-orders-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.d.ts +14 -0
- package/src/lib/components/console/locations-card.component.js +256 -0
- package/src/lib/components/console/locations-card.component.js.map +1 -0
- package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
- package/src/lib/components/console/member-posts-card.component.js +283 -0
- package/src/lib/components/console/member-posts-card.component.js.map +1 -0
- package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
- package/src/lib/components/console/newest-site-users-card.component.js +126 -0
- package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
- package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
- package/src/lib/components/console/order-detail-dialog.component.js +976 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
- package/src/lib/components/console/paid-media.d.ts +127 -0
- package/src/lib/components/console/paid-media.js +397 -0
- package/src/lib/components/console/paid-media.js.map +1 -0
- package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
- package/src/lib/components/console/payments-settings-card.component.js +295 -0
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
- package/src/lib/components/console/pos-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-page.component.js +916 -0
- package/src/lib/components/console/pos-page.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
- package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
- package/src/lib/components/console/products-hub-card.component.js +1280 -0
- package/src/lib/components/console/products-hub-card.component.js.map +1 -0
- package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
- package/src/lib/components/console/products-hub-zone.component.js +200 -0
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
- package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
- package/src/lib/components/console/recovery-queue-card.component.js +262 -0
- package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/registers-card.component.d.ts +21 -0
- package/src/lib/components/console/registers-card.component.js +296 -0
- package/src/lib/components/console/registers-card.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +14 -0
- package/src/lib/components/console/reservations-card.component.js +650 -0
- package/src/lib/components/console/reservations-card.component.js.map +1 -0
- package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
- package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
- package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
- package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
- package/src/lib/components/console/shipping-settings-card.component.js +560 -0
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
- package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
- package/src/lib/components/console/stock-movements-card.component.js +333 -0
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
- package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/store-settings-card.component.js +300 -0
- package/src/lib/components/console/store-settings-card.component.js.map +1 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
- package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
- package/src/lib/components/console/suppliers-card.component.js +328 -0
- package/src/lib/components/console/suppliers-card.component.js.map +1 -0
- package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/tax-settings-card.component.js +473 -0
- package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
- package/src/lib/components/gate.d.ts +39 -0
- package/src/lib/components/gate.js +202 -0
- package/src/lib/components/gate.js.map +1 -0
- package/src/lib/components/gated-video.d.ts +40 -0
- package/src/lib/components/gated-video.js +366 -0
- package/src/lib/components/gated-video.js.map +1 -0
- package/src/lib/components/member-feed.d.ts +32 -0
- package/src/lib/components/member-feed.js +198 -0
- package/src/lib/components/member-feed.js.map +1 -0
- package/src/lib/components/member-recovery.d.ts +35 -0
- package/src/lib/components/member-recovery.js +313 -0
- package/src/lib/components/member-recovery.js.map +1 -0
- package/src/lib/components/member-signin.d.ts +35 -0
- package/src/lib/components/member-signin.js +257 -0
- package/src/lib/components/member-signin.js.map +1 -0
- package/src/lib/components/member-signup.d.ts +34 -0
- package/src/lib/components/member-signup.js +287 -0
- package/src/lib/components/member-signup.js.map +1 -0
- package/src/lib/components/newsletter-signup.d.ts +39 -0
- package/src/lib/components/newsletter-signup.js +229 -0
- package/src/lib/components/newsletter-signup.js.map +1 -0
- package/src/lib/components/product-detail.d.ts +38 -0
- package/src/lib/components/product-detail.js +1022 -0
- package/src/lib/components/product-detail.js.map +1 -0
- package/src/lib/components/product-grid.d.ts +67 -0
- package/src/lib/components/product-grid.js +909 -0
- package/src/lib/components/product-grid.js.map +1 -0
- package/src/lib/components/product-reviews.d.ts +32 -0
- package/src/lib/components/product-reviews.js +349 -0
- package/src/lib/components/product-reviews.js.map +1 -0
- package/src/lib/components/related-products.d.ts +33 -0
- package/src/lib/components/related-products.js +232 -0
- package/src/lib/components/related-products.js.map +1 -0
- package/src/lib/components/reservation-widget.d.ts +33 -0
- package/src/lib/components/reservation-widget.js +418 -0
- package/src/lib/components/reservation-widget.js.map +1 -0
- package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
- package/src/lib/components/storefront-payment-element-fallback.js +51 -0
- package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
- package/src/lib/components/storefront-payment-element.d.ts +78 -0
- package/src/lib/components/storefront-payment-element.js +156 -0
- package/src/lib/components/storefront-payment-element.js.map +1 -0
- package/src/lib/components/wishlist.d.ts +46 -0
- package/src/lib/components/wishlist.js +304 -0
- package/src/lib/components/wishlist.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +18 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/product-filters.d.ts +35 -0
- package/src/lib/constants/product-filters.js +109 -0
- package/src/lib/constants/product-filters.js.map +1 -0
- package/src/lib/model/commerce-cart.d.ts +52 -0
- package/src/lib/model/commerce-cart.js +102 -0
- package/src/lib/model/commerce-cart.js.map +1 -0
- package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
- package/src/lib/model/commerce-connect-transfer.js +231 -0
- package/src/lib/model/commerce-connect-transfer.js.map +1 -0
- package/src/lib/model/commerce-discounts.d.ts +164 -0
- package/src/lib/model/commerce-discounts.js +231 -0
- package/src/lib/model/commerce-discounts.js.map +1 -0
- package/src/lib/model/commerce-dispute.d.ts +124 -0
- package/src/lib/model/commerce-dispute.js +225 -0
- package/src/lib/model/commerce-dispute.js.map +1 -0
- package/src/lib/model/commerce-gift-cards.d.ts +107 -0
- package/src/lib/model/commerce-gift-cards.js +121 -0
- package/src/lib/model/commerce-gift-cards.js.map +1 -0
- package/src/lib/model/commerce-io.d.ts +36 -0
- package/src/lib/model/commerce-io.js +245 -0
- package/src/lib/model/commerce-io.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +1040 -0
- package/src/lib/model/commerce-orders.js +1022 -0
- package/src/lib/model/commerce-orders.js.map +1 -0
- package/src/lib/model/commerce-promotions.d.ts +188 -0
- package/src/lib/model/commerce-promotions.js +199 -0
- package/src/lib/model/commerce-promotions.js.map +1 -0
- package/src/lib/model/commerce-reservations.d.ts +175 -0
- package/src/lib/model/commerce-reservations.js +157 -0
- package/src/lib/model/commerce-reservations.js.map +1 -0
- package/src/lib/model/commerce-shipping.d.ts +316 -0
- package/src/lib/model/commerce-shipping.js +484 -0
- package/src/lib/model/commerce-shipping.js.map +1 -0
- package/src/lib/model/commerce-stock-holds.d.ts +199 -0
- package/src/lib/model/commerce-stock-holds.js +190 -0
- package/src/lib/model/commerce-stock-holds.js.map +1 -0
- package/src/lib/model/commerce-subscription-status.d.ts +67 -0
- package/src/lib/model/commerce-subscription-status.js +76 -0
- package/src/lib/model/commerce-subscription-status.js.map +1 -0
- package/src/lib/model/commerce-tax-decision.d.ts +222 -0
- package/src/lib/model/commerce-tax-decision.js +165 -0
- package/src/lib/model/commerce-tax-decision.js.map +1 -0
- package/src/lib/model/commerce-tax.d.ts +176 -0
- package/src/lib/model/commerce-tax.js +92 -0
- package/src/lib/model/commerce-tax.js.map +1 -0
- package/src/lib/model/commerce.d.ts +551 -0
- package/src/lib/model/commerce.js +739 -0
- package/src/lib/model/commerce.js.map +1 -0
- package/src/lib/model/index.d.ts +40 -0
- package/src/lib/model/index.js +40 -0
- package/src/lib/model/index.js.map +1 -0
- package/src/lib/model/order-figures.d.ts +48 -0
- package/src/lib/model/order-figures.js +74 -0
- package/src/lib/model/order-figures.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +23 -0
- package/src/lib/model/plugin-permissions.js +34 -0
- package/src/lib/model/plugin-permissions.js.map +1 -0
- package/src/lib/model/purchase-analytics.d.ts +186 -0
- package/src/lib/model/purchase-analytics.js +216 -0
- package/src/lib/model/purchase-analytics.js.map +1 -0
- package/src/lib/plugin-config.d.ts +62 -0
- package/src/lib/plugin-config.js +78 -0
- package/src/lib/plugin-config.js.map +1 -0
- package/src/lib/plugin.d.ts +28 -0
- package/src/lib/plugin.js +147 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/billing-webhook.d.ts +26 -0
- package/src/lib/server/billing-webhook.js +4011 -0
- package/src/lib/server/billing-webhook.js.map +1 -0
- package/src/lib/server/cancel-order.d.ts +87 -0
- package/src/lib/server/cancel-order.js +368 -0
- package/src/lib/server/cancel-order.js.map +1 -0
- package/src/lib/server/cart-checkout.d.ts +25 -0
- package/src/lib/server/cart-checkout.js +976 -0
- package/src/lib/server/cart-checkout.js.map +1 -0
- package/src/lib/server/cart-cookie.d.ts +32 -0
- package/src/lib/server/cart-cookie.js +77 -0
- package/src/lib/server/cart-cookie.js.map +1 -0
- package/src/lib/server/cart.d.ts +34 -0
- package/src/lib/server/cart.js +181 -0
- package/src/lib/server/cart.js.map +1 -0
- package/src/lib/server/catalog.d.ts +127 -0
- package/src/lib/server/catalog.js +277 -0
- package/src/lib/server/catalog.js.map +1 -0
- package/src/lib/server/checkout.d.ts +36 -0
- package/src/lib/server/checkout.js +915 -0
- package/src/lib/server/checkout.js.map +1 -0
- package/src/lib/server/connect.d.ts +26 -0
- package/src/lib/server/connect.js +238 -0
- package/src/lib/server/connect.js.map +1 -0
- package/src/lib/server/contact-refund.d.ts +117 -0
- package/src/lib/server/contact-refund.js +196 -0
- package/src/lib/server/contact-refund.js.map +1 -0
- package/src/lib/server/download.d.ts +39 -0
- package/src/lib/server/download.js +206 -0
- package/src/lib/server/download.js.map +1 -0
- package/src/lib/server/draft-order.d.ts +26 -0
- package/src/lib/server/draft-order.js +706 -0
- package/src/lib/server/draft-order.js.map +1 -0
- package/src/lib/server/feed.d.ts +24 -0
- package/src/lib/server/feed.js +59 -0
- package/src/lib/server/feed.js.map +1 -0
- package/src/lib/server/fulfill-order.d.ts +97 -0
- package/src/lib/server/fulfill-order.js +235 -0
- package/src/lib/server/fulfill-order.js.map +1 -0
- package/src/lib/server/gate.d.ts +36 -0
- package/src/lib/server/gate.js +112 -0
- package/src/lib/server/gate.js.map +1 -0
- package/src/lib/server/gift-cards.d.ts +42 -0
- package/src/lib/server/gift-cards.js +219 -0
- package/src/lib/server/gift-cards.js.map +1 -0
- package/src/lib/server/low-stock.d.ts +49 -0
- package/src/lib/server/low-stock.js +60 -0
- package/src/lib/server/low-stock.js.map +1 -0
- package/src/lib/server/manual-tax-rate.d.ts +82 -0
- package/src/lib/server/manual-tax-rate.js +113 -0
- package/src/lib/server/manual-tax-rate.js.map +1 -0
- package/src/lib/server/member-feed.d.ts +24 -0
- package/src/lib/server/member-feed.js +72 -0
- package/src/lib/server/member-feed.js.map +1 -0
- package/src/lib/server/member-name-search.d.ts +37 -0
- package/src/lib/server/member-name-search.js +42 -0
- package/src/lib/server/member-name-search.js.map +1 -0
- package/src/lib/server/member-post.d.ts +23 -0
- package/src/lib/server/member-post.js +166 -0
- package/src/lib/server/member-post.js.map +1 -0
- package/src/lib/server/membership-account.d.ts +37 -0
- package/src/lib/server/membership-account.js +148 -0
- package/src/lib/server/membership-account.js.map +1 -0
- package/src/lib/server/membership-admin-password.d.ts +33 -0
- package/src/lib/server/membership-admin-password.js +202 -0
- package/src/lib/server/membership-admin-password.js.map +1 -0
- package/src/lib/server/membership-content.d.ts +23 -0
- package/src/lib/server/membership-content.js +105 -0
- package/src/lib/server/membership-content.js.map +1 -0
- package/src/lib/server/membership-login.d.ts +19 -0
- package/src/lib/server/membership-login.js +137 -0
- package/src/lib/server/membership-login.js.map +1 -0
- package/src/lib/server/membership-logout.d.ts +19 -0
- package/src/lib/server/membership-logout.js +35 -0
- package/src/lib/server/membership-logout.js.map +1 -0
- package/src/lib/server/membership-recover.d.ts +60 -0
- package/src/lib/server/membership-recover.js +244 -0
- package/src/lib/server/membership-recover.js.map +1 -0
- package/src/lib/server/membership-register.d.ts +22 -0
- package/src/lib/server/membership-register.js +241 -0
- package/src/lib/server/membership-register.js.map +1 -0
- package/src/lib/server/membership-reset.d.ts +26 -0
- package/src/lib/server/membership-reset.js +88 -0
- package/src/lib/server/membership-reset.js.map +1 -0
- package/src/lib/server/membership-wishlist.d.ts +23 -0
- package/src/lib/server/membership-wishlist.js +89 -0
- package/src/lib/server/membership-wishlist.js.map +1 -0
- package/src/lib/server/membership.d.ts +96 -0
- package/src/lib/server/membership.js +222 -0
- package/src/lib/server/membership.js.map +1 -0
- package/src/lib/server/native-checkout.d.ts +170 -0
- package/src/lib/server/native-checkout.js +193 -0
- package/src/lib/server/native-checkout.js.map +1 -0
- package/src/lib/server/newsletter.d.ts +23 -0
- package/src/lib/server/newsletter.js +323 -0
- package/src/lib/server/newsletter.js.map +1 -0
- package/src/lib/server/notify-restock.d.ts +22 -0
- package/src/lib/server/notify-restock.js +84 -0
- package/src/lib/server/notify-restock.js.map +1 -0
- package/src/lib/server/order-analytics.d.ts +134 -0
- package/src/lib/server/order-analytics.js +263 -0
- package/src/lib/server/order-analytics.js.map +1 -0
- package/src/lib/server/order-figures.d.ts +33 -0
- package/src/lib/server/order-figures.js +220 -0
- package/src/lib/server/order-figures.js.map +1 -0
- package/src/lib/server/paid-media-delivery.d.ts +173 -0
- package/src/lib/server/paid-media-delivery.js +212 -0
- package/src/lib/server/paid-media-delivery.js.map +1 -0
- package/src/lib/server/pos-order.d.ts +54 -0
- package/src/lib/server/pos-order.js +1137 -0
- package/src/lib/server/pos-order.js.map +1 -0
- package/src/lib/server/process-abandoned.d.ts +54 -0
- package/src/lib/server/process-abandoned.js +222 -0
- package/src/lib/server/process-abandoned.js.map +1 -0
- package/src/lib/server/process-restock.d.ts +42 -0
- package/src/lib/server/process-restock.js +219 -0
- package/src/lib/server/process-restock.js.map +1 -0
- package/src/lib/server/product-card.d.ts +29 -0
- package/src/lib/server/product-card.js +54 -0
- package/src/lib/server/product-card.js.map +1 -0
- package/src/lib/server/product.d.ts +70 -0
- package/src/lib/server/product.js +105 -0
- package/src/lib/server/product.js.map +1 -0
- package/src/lib/server/promotion-hold.d.ts +144 -0
- package/src/lib/server/promotion-hold.js +174 -0
- package/src/lib/server/promotion-hold.js.map +1 -0
- package/src/lib/server/reconcile-stock.d.ts +106 -0
- package/src/lib/server/reconcile-stock.js +349 -0
- package/src/lib/server/reconcile-stock.js.map +1 -0
- package/src/lib/server/refund.d.ts +45 -0
- package/src/lib/server/refund.js +607 -0
- package/src/lib/server/refund.js.map +1 -0
- package/src/lib/server/related.d.ts +24 -0
- package/src/lib/server/related.js +104 -0
- package/src/lib/server/related.js.map +1 -0
- package/src/lib/server/reservation-availability.d.ts +23 -0
- package/src/lib/server/reservation-availability.js +111 -0
- package/src/lib/server/reservation-availability.js.map +1 -0
- package/src/lib/server/reserve-stock.d.ts +156 -0
- package/src/lib/server/reserve-stock.js +146 -0
- package/src/lib/server/reserve-stock.js.map +1 -0
- package/src/lib/server/reserve.d.ts +25 -0
- package/src/lib/server/reserve.js +426 -0
- package/src/lib/server/reserve.js.map +1 -0
- package/src/lib/server/restock-flag.d.ts +202 -0
- package/src/lib/server/restock-flag.js +449 -0
- package/src/lib/server/restock-flag.js.map +1 -0
- package/src/lib/server/reviews.d.ts +51 -0
- package/src/lib/server/reviews.js +132 -0
- package/src/lib/server/reviews.js.map +1 -0
- package/src/lib/server/site-page-enricher.d.ts +42 -0
- package/src/lib/server/site-page-enricher.js +149 -0
- package/src/lib/server/site-page-enricher.js.map +1 -0
- package/src/lib/server/site-page-resolver.d.ts +26 -0
- package/src/lib/server/site-page-resolver.js +223 -0
- package/src/lib/server/site-page-resolver.js.map +1 -0
- package/src/lib/server/stock-hold.d.ts +127 -0
- package/src/lib/server/stock-hold.js +258 -0
- package/src/lib/server/stock-hold.js.map +1 -0
- package/src/lib/server/storefront-tax-record.d.ts +22 -0
- package/src/lib/server/storefront-tax-record.js +218 -0
- package/src/lib/server/storefront-tax-record.js.map +1 -0
- package/src/lib/server/storefront-tax.d.ts +197 -0
- package/src/lib/server/storefront-tax.js +245 -0
- package/src/lib/server/storefront-tax.js.map +1 -0
- package/src/lib/server/stream.d.ts +25 -0
- package/src/lib/server/stream.js +191 -0
- package/src/lib/server/stream.js.map +1 -0
- package/src/lib/server/subscription-portal.d.ts +24 -0
- package/src/lib/server/subscription-portal.js +91 -0
- package/src/lib/server/subscription-portal.js.map +1 -0
- package/src/lib/server/supplier-outbox.d.ts +190 -0
- package/src/lib/server/supplier-outbox.js +342 -0
- package/src/lib/server/supplier-outbox.js.map +1 -0
- package/src/lib/server/supplier-update.d.ts +23 -0
- package/src/lib/server/supplier-update.js +289 -0
- package/src/lib/server/supplier-update.js.map +1 -0
- package/src/lib/server/tax-profile.d.ts +29 -0
- package/src/lib/server/tax-profile.js +40 -0
- package/src/lib/server/tax-profile.js.map +1 -0
- package/src/lib/server.d.ts +32 -0
- package/src/lib/server.js +311 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/site.d.ts +27 -0
- package/src/lib/site.js +134 -0
- package/src/lib/site.js.map +1 -0
- package/src/lib/utils/escape-html.d.ts +41 -0
- package/src/lib/utils/escape-html.js +41 -0
- package/src/lib/utils/escape-html.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/member-continue.d.ts +45 -0
- package/src/lib/utils/member-continue.js +49 -0
- package/src/lib/utils/member-continue.js.map +1 -0
- package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
- package/src/lib/utils/use-storefront-purchase-event.js +142 -0
- package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
|
@@ -0,0 +1,1374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
19
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
20
|
+
import * as CommerceModel from "../../model/index.js";
|
|
21
|
+
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
22
|
+
import { Timestamp } from "@aglyn/shared-util-timestamp";
|
|
23
|
+
import { Alert, Autocomplete, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, IconButton, MenuItem, Stack, TableBody, TableCell, TableHead, TableRow, TextField, Typography } from "@mui/material";
|
|
24
|
+
import { collection, doc, getDoc, setDoc } from "firebase/firestore";
|
|
25
|
+
import { useCallback, useMemo, useState } from "react";
|
|
26
|
+
import { ceilingedWindow, collectionCeiling, useFirestore, useFirestoreCollection, useHostResourceApi, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
|
|
27
|
+
import { useMediaPicker } from "@aglyn/aglyn";
|
|
28
|
+
import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
|
|
29
|
+
import { seoListingFieldCount, seoListingFieldTooLong } from "@aglyn/aglyn/app-utils/seo-listing-fields";
|
|
30
|
+
import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
|
|
31
|
+
import { EntitlementUpsell, useCommerceEntitlement } from "./entitlement-gate.component.js";
|
|
32
|
+
import { MembersVideosField, PaidDownloadAddButton, PaidMediaProtection } from "./paid-media.js";
|
|
33
|
+
/**
|
|
34
|
+
* What each picker in this dialog will offer.
|
|
35
|
+
*
|
|
36
|
+
* Every one is a chooser rather than a list, so the ceiling is the number of
|
|
37
|
+
* options a reader can meaningfully scan, and the walk that reaches it is
|
|
38
|
+
* ordered by document name — a picker that silently omits an option is worse
|
|
39
|
+
* than one that admits it stops, because the omission looks like the option
|
|
40
|
+
* not existing.
|
|
41
|
+
*/ const CATEGORY_CEILING = 250;
|
|
42
|
+
const RELATED_PRODUCT_CEILING = 300;
|
|
43
|
+
const SUPPLIER_CEILING = 50;
|
|
44
|
+
/**
|
|
45
|
+
* The search listing fields this editor holds (AGL-2910): `product.seo`
|
|
46
|
+
* carries a title and a description beside its share image, and nothing
|
|
47
|
+
* else a listing zone may propose.
|
|
48
|
+
*/ const PRODUCT_SEO_LISTING_FIELDS = [
|
|
49
|
+
'title',
|
|
50
|
+
'description'
|
|
51
|
+
];
|
|
52
|
+
/** A product nobody has saved yet, as the editor starts one. */ function blankProduct() {
|
|
53
|
+
return {
|
|
54
|
+
name: '',
|
|
55
|
+
slug: '',
|
|
56
|
+
type: 'physical',
|
|
57
|
+
status: 'draft',
|
|
58
|
+
variants: [
|
|
59
|
+
{
|
|
60
|
+
id: 'default',
|
|
61
|
+
priceUsd: 0
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Stable key for matching variants across matrix regenerations. */ function comboKey(options) {
|
|
67
|
+
return Object.entries(options != null ? options : {}).sort(([a], [b])=>a.localeCompare(b)).map(([name, value])=>`${name}:${value}`).join('|');
|
|
68
|
+
}
|
|
69
|
+
function comboLabel(options) {
|
|
70
|
+
const values = Object.values(options != null ? options : {});
|
|
71
|
+
return values.length ? values.join(' / ') : 'Default';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Products hub editor (AGL-279): the full catalog editor — basics,
|
|
75
|
+
* media, tags, options → variants matrix, per-variant pricing/stock, and
|
|
76
|
+
* SEO overrides. Saving denormalizes `priceUsd`/`inventory` from the
|
|
77
|
+
* first variant so the legacy Product block + checkout API (AGL-90) keep
|
|
78
|
+
* charging correctly without reading the variants array.
|
|
79
|
+
*/ export function ProductEditorDialog(props) {
|
|
80
|
+
var _ref, _ref1, _current_description, _current_tags, _current_categoryIds, _current_options, _current_mediaUrls, _ref2, _ref3, _current_supplierId, _current_description1, _current_tags1, _current_mediaUrls1, _current_options1, _ref4, _subs_planLabel, _gifts_planLabel, _subs_planLabel1, _gifts_planLabel1, _current_oversellPolicy, _gifts_planLabel2, _gifts_planLabel3, _current_lowStockThreshold, _subs_planLabel2, _current_subscription_trialDays, _current_digitalFiles, _current_downloadLimit, _current_gatedVideos, _ref5, _ref6, _ref7, _current_description2, _ref8, _ref9;
|
|
81
|
+
var _current_seo, _current_seo1, _current_options2, _current_seo2, _current_seo3, _current_seo4, _current_seo5, _current_seo6, _current_seo7, _current_seo8, _current_seo9, _current_seo10, _current_seo11;
|
|
82
|
+
const { hostId, product, seedFromCache, seedUnreadable, open, onClose } = props;
|
|
83
|
+
/**
|
|
84
|
+
* Field-level entitlement gates (AGL-2080). Both of these were fully
|
|
85
|
+
* configurable by an unentitled org and refused only at checkout — by
|
|
86
|
+
* `server/checkout.ts:149` for subscriptions and `:157` /
|
|
87
|
+
* `cart-checkout.ts:156` for gift cards. The operator saw a saved product;
|
|
88
|
+
* the buyer saw the refusal.
|
|
89
|
+
*
|
|
90
|
+
* `ready && !entitled`, never `!entitled`. `checkEntitlement(undefined)`
|
|
91
|
+
* resolves the FREE tier rather than "unknown", so gating on the raw call
|
|
92
|
+
* would disable these controls at a PAYING org for the render or two its
|
|
93
|
+
* org doc is in flight. Erring open for that window costs nothing — the
|
|
94
|
+
* server enforces regardless — while erring closed is a paying customer
|
|
95
|
+
* told they cannot use what they bought.
|
|
96
|
+
*/ const subs = useCommerceEntitlement(hostId, 'storefrontSubscriptions');
|
|
97
|
+
const gifts = useCommerceEntitlement(hostId, 'giftCards');
|
|
98
|
+
const subsLocked = subs.ready && !subs.entitled;
|
|
99
|
+
const giftsLocked = gifts.ready && !gifts.entitled;
|
|
100
|
+
const firestore = useFirestore();
|
|
101
|
+
const createHostResource = useHostResourceApi();
|
|
102
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
103
|
+
/**
|
|
104
|
+
* The three pickers this dialog draws, read only once it is OPEN.
|
|
105
|
+
*
|
|
106
|
+
* `ProductEditorDialog` is rendered unconditionally by the products hub and
|
|
107
|
+
* takes `open` as a prop, so its body runs on every render of that page. A
|
|
108
|
+
* listener built here without the gate subscribes whether or not anyone
|
|
109
|
+
* opens the editor, which charges every visit to the catalog for three
|
|
110
|
+
* collections the visitor never sees.
|
|
111
|
+
*
|
|
112
|
+
* `null` is what `useFirestoreCollection` takes to mean "do not subscribe",
|
|
113
|
+
* so the closed dialog costs nothing and the open one pays once.
|
|
114
|
+
*/ const { data: categoryDocs } = useFirestoreCollection(()=>open ? collectionCeiling(collection(firestore, 'hosts', hostId, 'productCategories'), CATEGORY_CEILING) : null, [
|
|
115
|
+
firestore,
|
|
116
|
+
hostId,
|
|
117
|
+
open
|
|
118
|
+
], {
|
|
119
|
+
idField: '$id'
|
|
120
|
+
});
|
|
121
|
+
const { data: allProductDocs } = useFirestoreCollection(()=>open ? collectionCeiling(collection(firestore, 'hosts', hostId, 'products'), RELATED_PRODUCT_CEILING) : null, [
|
|
122
|
+
firestore,
|
|
123
|
+
hostId,
|
|
124
|
+
open
|
|
125
|
+
], {
|
|
126
|
+
idField: '$id'
|
|
127
|
+
});
|
|
128
|
+
const { data: supplierDocs } = useFirestoreCollection(()=>open ? collectionCeiling(collection(firestore, 'hosts', hostId, 'suppliers'), SUPPLIER_CEILING) : null, [
|
|
129
|
+
firestore,
|
|
130
|
+
hostId,
|
|
131
|
+
open
|
|
132
|
+
], {
|
|
133
|
+
idField: '$id'
|
|
134
|
+
});
|
|
135
|
+
const categories = useMemo(()=>ceilingedWindow(categoryDocs != null ? categoryDocs : undefined, CATEGORY_CEILING), [
|
|
136
|
+
categoryDocs
|
|
137
|
+
]);
|
|
138
|
+
const relatedProducts = useMemo(()=>ceilingedWindow(allProductDocs != null ? allProductDocs : undefined, RELATED_PRODUCT_CEILING), [
|
|
139
|
+
allProductDocs
|
|
140
|
+
]);
|
|
141
|
+
const suppliers = useMemo(()=>ceilingedWindow(supplierDocs != null ? supplierDocs : undefined, SUPPLIER_CEILING), [
|
|
142
|
+
supplierDocs
|
|
143
|
+
]);
|
|
144
|
+
const lifted = useMemo(()=>product ? CommerceModel.liftLegacyProduct(product) : null, [
|
|
145
|
+
product
|
|
146
|
+
]);
|
|
147
|
+
const [draft, setDraft] = useState(null);
|
|
148
|
+
const [slugTouched, setSlugTouched] = useState(false);
|
|
149
|
+
// The console media browser is provided by the shell (AGL-395); opening it
|
|
150
|
+
// resolves with the chosen asset (or null if cancelled).
|
|
151
|
+
const { pickMedia } = useMediaPicker();
|
|
152
|
+
const pick = useCallback(async (apply)=>{
|
|
153
|
+
const media = await (pickMedia == null ? void 0 : pickMedia());
|
|
154
|
+
if (media) apply(media);
|
|
155
|
+
}, [
|
|
156
|
+
pickMedia
|
|
157
|
+
]);
|
|
158
|
+
// Lazy-init per open; parent remounts via `key` on product change.
|
|
159
|
+
const current = (_ref = draft != null ? draft : lifted) != null ? _ref : blankProduct();
|
|
160
|
+
const update = (patch)=>setDraft(_extends({}, current, patch));
|
|
161
|
+
/** The shell's zone renderer (AGL-2910); `null` outside the console shell. */ const WidgetSlot = useConsoleWidgetSlot();
|
|
162
|
+
/**
|
|
163
|
+
* A listing zone widget's proposal, staged into the draft like typing.
|
|
164
|
+
* Functional, because a proposal can arrive after a generation finishes,
|
|
165
|
+
* and a closure over the render that started it would put back every edit
|
|
166
|
+
* made while it ran. Only the fields a product's listing holds are taken.
|
|
167
|
+
*/ const proposeSeoValues = useCallback((values)=>{
|
|
168
|
+
const staged = {};
|
|
169
|
+
for (const field of PRODUCT_SEO_LISTING_FIELDS){
|
|
170
|
+
const value = values[field];
|
|
171
|
+
if (typeof value === 'string') staged[field] = value;
|
|
172
|
+
}
|
|
173
|
+
if (!Object.keys(staged).length) return;
|
|
174
|
+
setDraft((prior)=>{
|
|
175
|
+
var _ref;
|
|
176
|
+
const base = (_ref = prior != null ? prior : lifted) != null ? _ref : blankProduct();
|
|
177
|
+
return _extends({}, base, {
|
|
178
|
+
seo: _extends({}, base.seo, staged)
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}, [
|
|
182
|
+
lifted
|
|
183
|
+
]);
|
|
184
|
+
/**
|
|
185
|
+
* The product zone's proposal (AGL-2916): copy staged into the draft like
|
|
186
|
+
* typing, functional for the reason `proposeSeoValues` gives. Option names
|
|
187
|
+
* go through `renameProductOptions`, so every variant keeps its price, SKU
|
|
188
|
+
* and stock.
|
|
189
|
+
*/ const proposeProductValues = useCallback((values)=>{
|
|
190
|
+
setDraft((prior)=>{
|
|
191
|
+
var _ref;
|
|
192
|
+
const base = (_ref = prior != null ? prior : lifted) != null ? _ref : blankProduct();
|
|
193
|
+
return _extends({}, base, CommerceModel.productCopyPatch(base, values));
|
|
194
|
+
});
|
|
195
|
+
}, [
|
|
196
|
+
lifted
|
|
197
|
+
]);
|
|
198
|
+
const zoneCategories = useMemo(()=>categories.rows.map((category)=>{
|
|
199
|
+
var _category_name;
|
|
200
|
+
return {
|
|
201
|
+
id: String(category.$id),
|
|
202
|
+
name: String((_category_name = category.name) != null ? _category_name : '')
|
|
203
|
+
};
|
|
204
|
+
}), [
|
|
205
|
+
categories.rows
|
|
206
|
+
]);
|
|
207
|
+
const zoneProduct = {
|
|
208
|
+
id: (_ref1 = product == null ? void 0 : product.$id) != null ? _ref1 : null,
|
|
209
|
+
name: current.name,
|
|
210
|
+
type: current.type,
|
|
211
|
+
description: String((_current_description = current.description) != null ? _current_description : ''),
|
|
212
|
+
tags: (_current_tags = current.tags) != null ? _current_tags : [],
|
|
213
|
+
categoryIds: (_current_categoryIds = current.categoryIds) != null ? _current_categoryIds : [],
|
|
214
|
+
options: ((_current_options = current.options) != null ? _current_options : []).map((option)=>({
|
|
215
|
+
name: option.name,
|
|
216
|
+
values: option.values
|
|
217
|
+
})),
|
|
218
|
+
mediaUrls: (_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
219
|
+
seoTitle: (_ref2 = (_current_seo = current.seo) == null ? void 0 : _current_seo.title) != null ? _ref2 : '',
|
|
220
|
+
seoDescription: (_ref3 = (_current_seo1 = current.seo) == null ? void 0 : _current_seo1.description) != null ? _ref3 : ''
|
|
221
|
+
};
|
|
222
|
+
const error = current.name ? CommerceModel.validateProduct(current) : null;
|
|
223
|
+
/**
|
|
224
|
+
* Stock tracking is inert on a subscription-only product (AGL-1744) —
|
|
225
|
+
* nothing decrements it on the first charge or on any renewal, so the
|
|
226
|
+
* editor stops offering a number it cannot keep true. Existing
|
|
227
|
+
* configuration is NOT discarded: the stored value stays on the document
|
|
228
|
+
* (this save is a full replace of `current`, and `current` is untouched
|
|
229
|
+
* here), stays visible in the disabled field, and becomes editable again
|
|
230
|
+
* the moment Billing goes back to "One-time purchase" or "Both".
|
|
231
|
+
*/ const stockApplies = CommerceModel.stockTrackingApplies(current);
|
|
232
|
+
const strandedStock = stockApplies ? null : CommerceModel.productInventory(current);
|
|
233
|
+
/**
|
|
234
|
+
* The one destructive move, and the merchant makes it deliberately.
|
|
235
|
+
*
|
|
236
|
+
* Needed because the checkout gate is unchanged: a stored `0` on a
|
|
237
|
+
* subscription-only product still 409s every new subscriber, and with the
|
|
238
|
+
* field disabled that would be a trap with no way out. `inventoryByLocation`
|
|
239
|
+
* goes with it — `adjustVariantInventory` re-sums the flat count from those
|
|
240
|
+
* buckets (AGL-286), so leaving them would let a later restock resurrect a
|
|
241
|
+
* count this just cleared. Keys are DELETED rather than set undefined; the
|
|
242
|
+
* save is a client-direct `setDoc`, which rejects undefined values.
|
|
243
|
+
*/ const handleClearStockTracking = ()=>{
|
|
244
|
+
update({
|
|
245
|
+
variants: current.variants.map((variant)=>{
|
|
246
|
+
const { inventoryByLocation: _perLocation } = variant, rest = _object_without_properties_loose(variant, [
|
|
247
|
+
"inventoryByLocation"
|
|
248
|
+
]);
|
|
249
|
+
return _extends({}, rest, {
|
|
250
|
+
inventory: null
|
|
251
|
+
});
|
|
252
|
+
})
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
const handleName = (name)=>update(_extends({
|
|
256
|
+
name
|
|
257
|
+
}, !product && !slugTouched ? {
|
|
258
|
+
slug: CommerceModel.commerceSlug(name)
|
|
259
|
+
} : {}));
|
|
260
|
+
const handleOptionsChange = useCallback((index, patch)=>{
|
|
261
|
+
var _current_options;
|
|
262
|
+
var _current_options1;
|
|
263
|
+
// A RENAME moves each variant's selection to the new name (AGL-3066).
|
|
264
|
+
// Rebuilding the matrix matches variants by name and value, so under a
|
|
265
|
+
// new name it finds none and replaces every variant, its id, price, SKU
|
|
266
|
+
// and stock with them. Only a change of values rebuilds.
|
|
267
|
+
if (patch && ((_current_options1 = current.options) == null ? void 0 : _current_options1[index]) && Object.keys(patch).length === 1 && typeof patch.name === 'string') {
|
|
268
|
+
update(CommerceModel.renameProductOptions(current, current.options.map((option, at)=>at === index ? patch.name : option.name)));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const options = [
|
|
272
|
+
...(_current_options = current.options) != null ? _current_options : []
|
|
273
|
+
];
|
|
274
|
+
if (patch === null) options.splice(index, 1);
|
|
275
|
+
else options[index] = _extends({
|
|
276
|
+
name: '',
|
|
277
|
+
values: []
|
|
278
|
+
}, options[index], patch);
|
|
279
|
+
// Regenerate the matrix, carrying data over by option-combo key so
|
|
280
|
+
// edits to prices/SKUs survive option tweaks.
|
|
281
|
+
const previous = new Map(current.variants.map((variant)=>[
|
|
282
|
+
comboKey(variant.options),
|
|
283
|
+
variant
|
|
284
|
+
]));
|
|
285
|
+
const fallback = current.variants[0];
|
|
286
|
+
const variants = CommerceModel.expandVariantMatrix(options).map((combo, comboIndex)=>{
|
|
287
|
+
var _ref, _ref1;
|
|
288
|
+
const existing = previous.get(comboKey(combo));
|
|
289
|
+
return existing != null ? existing : {
|
|
290
|
+
id: `v${Date.now().toString(36)}${comboIndex}`,
|
|
291
|
+
options: combo,
|
|
292
|
+
priceUsd: (_ref = fallback == null ? void 0 : fallback.priceUsd) != null ? _ref : 0,
|
|
293
|
+
inventory: (_ref1 = fallback == null ? void 0 : fallback.inventory) != null ? _ref1 : null
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
update({
|
|
297
|
+
options,
|
|
298
|
+
variants
|
|
299
|
+
});
|
|
300
|
+
}, [
|
|
301
|
+
current
|
|
302
|
+
]);
|
|
303
|
+
const handleVariantField = (index, field, raw)=>{
|
|
304
|
+
const variants = [
|
|
305
|
+
...current.variants
|
|
306
|
+
];
|
|
307
|
+
const numeric = [
|
|
308
|
+
'priceUsd',
|
|
309
|
+
'compareAtPriceUsd',
|
|
310
|
+
'weightGrams'
|
|
311
|
+
];
|
|
312
|
+
const value = field === 'inventory' ? raw.trim() === '' ? null : Math.max(0, Math.round(Number(raw))) : numeric.includes(field) ? raw.trim() === '' ? undefined : Number(raw) : raw;
|
|
313
|
+
variants[index] = _extends({}, variants[index], {
|
|
314
|
+
[field]: value
|
|
315
|
+
});
|
|
316
|
+
if (value === undefined && (field === 'compareAtPriceUsd' || field === 'weightGrams')) {
|
|
317
|
+
delete variants[index][field];
|
|
318
|
+
}
|
|
319
|
+
update({
|
|
320
|
+
variants
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
const handleSave = useCallback(async ()=>{
|
|
324
|
+
var _ref, _ref1, _ref2;
|
|
325
|
+
var _current_mediaUrls;
|
|
326
|
+
if (!current.name.trim() || error) return;
|
|
327
|
+
const primaryVariant = current.variants[0];
|
|
328
|
+
// JSON-safe base (no Firestore Timestamp — it won't survive the API
|
|
329
|
+
// hop); millis fields are what the checkout + Product block read.
|
|
330
|
+
/**
|
|
331
|
+
* `$id` is dropped, not carried (AGL-1374).
|
|
332
|
+
*
|
|
333
|
+
* `current` is `draft ?? liftLegacyProduct(product)`, and the hub stamps
|
|
334
|
+
* `$id` onto every row it lists (`{...liftLegacyProduct(p), $id: p.$id}`)
|
|
335
|
+
* — a SYNTHETIC key `idField: '$id'` puts on the in-memory object, which
|
|
336
|
+
* nothing persists. Spreading `current` carried it into the payload, and
|
|
337
|
+
* this write is `merge: false`, so it was stored as a real field on every
|
|
338
|
+
* product save. Nothing reads it; it is the listener's bookkeeping
|
|
339
|
+
* leaking into storage, and once there no reader can tell it from a field
|
|
340
|
+
* the editor meant to write. Excluding it also CLEANS the key off any
|
|
341
|
+
* product a previous save corrupted, because a replacing write stores
|
|
342
|
+
* exactly the payload.
|
|
343
|
+
*
|
|
344
|
+
* `product.$id` is still the doc path below — reading the synthetic key
|
|
345
|
+
* is what it is for. Writing it is the bug.
|
|
346
|
+
*/ const seeded = current;
|
|
347
|
+
const { $id: _syntheticId } = seeded, currentFields = _object_without_properties_loose(seeded, [
|
|
348
|
+
"$id"
|
|
349
|
+
]);
|
|
350
|
+
const base = _extends({}, currentFields, CommerceModel.productSearchFields({
|
|
351
|
+
name: current.name.trim().slice(0, 120),
|
|
352
|
+
variants: current.variants
|
|
353
|
+
}), {
|
|
354
|
+
slug: current.slug || CommerceModel.commerceSlug(current.name),
|
|
355
|
+
priceUsd: (_ref = primaryVariant == null ? void 0 : primaryVariant.priceUsd) != null ? _ref : 0,
|
|
356
|
+
inventory: CommerceModel.productInventory(current),
|
|
357
|
+
imageUrl: (_ref1 = (_ref2 = (_current_mediaUrls = current.mediaUrls) == null ? void 0 : _current_mediaUrls[0]) != null ? _ref2 : current.imageUrl) != null ? _ref1 : null,
|
|
358
|
+
updatedAtMs: Date.now()
|
|
359
|
+
});
|
|
360
|
+
try {
|
|
361
|
+
/**
|
|
362
|
+
* Refuse an EDIT whose seed the server never confirmed (AGL-1358).
|
|
363
|
+
*
|
|
364
|
+
* `merge: false` — a genuine full-document replace, and the payload is
|
|
365
|
+
* `{...current}`, which is `draft ?? lifted(product)`: every field the
|
|
366
|
+
* dialog was seeded with, whether or not it was touched. So a cached
|
|
367
|
+
* seed does not lose the one edit, it replaces the stored product with
|
|
368
|
+
* the cache's whole picture of it — price, variants, stock, media,
|
|
369
|
+
* status, SEO. Anything written since that snapshot, by a colleague or
|
|
370
|
+
* by the checkout engine, is gone.
|
|
371
|
+
*
|
|
372
|
+
* Only the edit path is guarded. A NEW product goes through the
|
|
373
|
+
* quota-enforcing resources API at a fresh uid and can overwrite
|
|
374
|
+
* nothing; the first snapshot of any listener is `fromCache: true`, so
|
|
375
|
+
* guarding a create would refuse a save that was never unsafe.
|
|
376
|
+
*
|
|
377
|
+
* The guard WRAPS the write: an early return is a shape you can keep
|
|
378
|
+
* while losing the protection.
|
|
379
|
+
*/ const verdict = await writeGuardedBySeed({
|
|
380
|
+
subject: 'product',
|
|
381
|
+
unreadable: Boolean(product) && seedUnreadable,
|
|
382
|
+
fromCache: Boolean(product) && seedFromCache
|
|
383
|
+
}, async ()=>{
|
|
384
|
+
if (product) {
|
|
385
|
+
/**
|
|
386
|
+
* RESERVATIONS ARE NOT THE EDITOR'S TO WRITE (AGL-2356).
|
|
387
|
+
*
|
|
388
|
+
* Checkout stores live stock holds in a `stockHolds` map on this
|
|
389
|
+
* document, and this is a `merge: false` replace of a payload
|
|
390
|
+
* built from the dialog's SEED. Left alone it would write whatever
|
|
391
|
+
* that seed happened to carry, and both directions are wrong: a
|
|
392
|
+
* seed taken before a shopper reached checkout erases a live
|
|
393
|
+
* reservation and reopens the oversell for that session, and a
|
|
394
|
+
* seed carrying a hold that has since settled resurrects a
|
|
395
|
+
* reservation against stock that is already sold.
|
|
396
|
+
*
|
|
397
|
+
* So the field is dropped from the payload and re-read from the
|
|
398
|
+
* server immediately before the write. One extra read on a product
|
|
399
|
+
* save, in exchange for an editor that cannot invent or destroy a
|
|
400
|
+
* reservation. The AGL-1358 seed guard above bounds how stale the
|
|
401
|
+
* REST of this payload can be; it cannot help here, because a hold
|
|
402
|
+
* legitimately appears seconds after a perfectly fresh seed.
|
|
403
|
+
*/ const productRef = doc(firestore, 'hosts', hostId, 'products', product.$id);
|
|
404
|
+
const { stockHolds: _seededHolds } = base, withoutHolds = _object_without_properties_loose(base, [
|
|
405
|
+
"stockHolds"
|
|
406
|
+
]);
|
|
407
|
+
const liveHolds = await getDoc(productRef).then((snapshot)=>snapshot.get('stockHolds')).catch(()=>undefined);
|
|
408
|
+
// Edit stays client-direct (no quota consumed); full replace.
|
|
409
|
+
await setDoc(productRef, _extends({}, withoutHolds, liveHolds ? {
|
|
410
|
+
stockHolds: liveHolds
|
|
411
|
+
} : {}, {
|
|
412
|
+
updatedAt: Timestamp.now()
|
|
413
|
+
}), {
|
|
414
|
+
merge: false
|
|
415
|
+
});
|
|
416
|
+
} else {
|
|
417
|
+
// New product rides the quota-enforcing resources API (AGL-473) —
|
|
418
|
+
// it re-checks the `commerce` entitlement and productsPerHost.
|
|
419
|
+
await createHostResource({
|
|
420
|
+
hostId,
|
|
421
|
+
resource: 'product',
|
|
422
|
+
data: _extends({}, base, {
|
|
423
|
+
createdAtMs: Date.now()
|
|
424
|
+
})
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
// A refusal leaves the editor open with every field as edited. Closing
|
|
429
|
+
// it would discard the work AND look like a save that succeeded.
|
|
430
|
+
if (!verdict.ok) {
|
|
431
|
+
return void enqueueSnackbar(verdict.message, {
|
|
432
|
+
variant: 'warning',
|
|
433
|
+
persist: false
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
onClose();
|
|
437
|
+
enqueueSnackbar('Product saved', {
|
|
438
|
+
variant: 'success',
|
|
439
|
+
persist: false
|
|
440
|
+
});
|
|
441
|
+
} catch (saveError) {
|
|
442
|
+
var _ref3;
|
|
443
|
+
console.error(saveError);
|
|
444
|
+
enqueueSnackbar((_ref3 = saveError == null ? void 0 : saveError.message) != null ? _ref3 : 'An error has occurred', {
|
|
445
|
+
variant: 'error',
|
|
446
|
+
allowDuplicate: true
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}, [
|
|
450
|
+
current,
|
|
451
|
+
error,
|
|
452
|
+
product,
|
|
453
|
+
seedFromCache,
|
|
454
|
+
seedUnreadable,
|
|
455
|
+
firestore,
|
|
456
|
+
hostId,
|
|
457
|
+
createHostResource,
|
|
458
|
+
onClose,
|
|
459
|
+
enqueueSnackbar
|
|
460
|
+
]);
|
|
461
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
462
|
+
open: open,
|
|
463
|
+
onClose: onClose,
|
|
464
|
+
maxWidth: "md",
|
|
465
|
+
fullWidth: true,
|
|
466
|
+
children: [
|
|
467
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
468
|
+
children: product ? 'Edit product' : 'Add product'
|
|
469
|
+
}),
|
|
470
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
471
|
+
sx: {
|
|
472
|
+
display: 'flex',
|
|
473
|
+
flexDirection: 'column',
|
|
474
|
+
gap: 2
|
|
475
|
+
},
|
|
476
|
+
children: [
|
|
477
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
478
|
+
direction: {
|
|
479
|
+
xs: 'column',
|
|
480
|
+
sm: 'row'
|
|
481
|
+
},
|
|
482
|
+
spacing: 2,
|
|
483
|
+
sx: {
|
|
484
|
+
mt: 1
|
|
485
|
+
},
|
|
486
|
+
children: [
|
|
487
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
488
|
+
label: "Name",
|
|
489
|
+
value: current.name,
|
|
490
|
+
onChange: (event)=>handleName(event.target.value),
|
|
491
|
+
size: "small",
|
|
492
|
+
autoFocus: true,
|
|
493
|
+
fullWidth: true
|
|
494
|
+
}),
|
|
495
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
496
|
+
label: "Slug",
|
|
497
|
+
value: current.slug,
|
|
498
|
+
onChange: (event)=>{
|
|
499
|
+
setSlugTouched(true);
|
|
500
|
+
update({
|
|
501
|
+
slug: CommerceModel.commerceSlug(event.target.value)
|
|
502
|
+
});
|
|
503
|
+
},
|
|
504
|
+
size: "small",
|
|
505
|
+
fullWidth: true,
|
|
506
|
+
helperText: current.slug ? `/products/${current.slug}` : undefined
|
|
507
|
+
})
|
|
508
|
+
]
|
|
509
|
+
}),
|
|
510
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
511
|
+
direction: "row",
|
|
512
|
+
spacing: 2,
|
|
513
|
+
children: [
|
|
514
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
515
|
+
label: "Type",
|
|
516
|
+
value: current.type,
|
|
517
|
+
onChange: (event)=>update({
|
|
518
|
+
type: event.target.value
|
|
519
|
+
}),
|
|
520
|
+
size: "small",
|
|
521
|
+
select: true,
|
|
522
|
+
sx: {
|
|
523
|
+
minWidth: 140
|
|
524
|
+
},
|
|
525
|
+
children: [
|
|
526
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
527
|
+
value: "physical",
|
|
528
|
+
children: 'Physical'
|
|
529
|
+
}),
|
|
530
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
531
|
+
value: "digital",
|
|
532
|
+
children: 'Digital'
|
|
533
|
+
}),
|
|
534
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
535
|
+
value: "service",
|
|
536
|
+
children: 'Service'
|
|
537
|
+
})
|
|
538
|
+
]
|
|
539
|
+
}),
|
|
540
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
541
|
+
label: "Status",
|
|
542
|
+
value: current.status,
|
|
543
|
+
onChange: (event)=>update({
|
|
544
|
+
status: event.target.value
|
|
545
|
+
}),
|
|
546
|
+
size: "small",
|
|
547
|
+
select: true,
|
|
548
|
+
sx: {
|
|
549
|
+
minWidth: 140
|
|
550
|
+
},
|
|
551
|
+
children: [
|
|
552
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
553
|
+
value: "draft",
|
|
554
|
+
children: 'Draft'
|
|
555
|
+
}),
|
|
556
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
557
|
+
value: "active",
|
|
558
|
+
children: 'Active'
|
|
559
|
+
}),
|
|
560
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
561
|
+
value: "archived",
|
|
562
|
+
children: 'Archived'
|
|
563
|
+
})
|
|
564
|
+
]
|
|
565
|
+
}),
|
|
566
|
+
suppliers.rows.length > 0 ? /*#__PURE__*/ _jsxs(TextField, {
|
|
567
|
+
label: "Supplier",
|
|
568
|
+
value: (_current_supplierId = current.supplierId) != null ? _current_supplierId : '',
|
|
569
|
+
onChange: (event)=>update({
|
|
570
|
+
supplierId: event.target.value || undefined
|
|
571
|
+
}),
|
|
572
|
+
size: "small",
|
|
573
|
+
select: true,
|
|
574
|
+
sx: {
|
|
575
|
+
minWidth: 160
|
|
576
|
+
},
|
|
577
|
+
helperText: "Routes paid orders",
|
|
578
|
+
children: [
|
|
579
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
580
|
+
value: "",
|
|
581
|
+
children: 'None (self-fulfilled)'
|
|
582
|
+
}),
|
|
583
|
+
suppliers.rows.map((supplier)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
584
|
+
value: supplier.$id,
|
|
585
|
+
children: supplier.name
|
|
586
|
+
}, supplier.$id))
|
|
587
|
+
]
|
|
588
|
+
}) : null
|
|
589
|
+
]
|
|
590
|
+
}),
|
|
591
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
592
|
+
label: "Description",
|
|
593
|
+
value: (_current_description1 = current.description) != null ? _current_description1 : '',
|
|
594
|
+
onChange: (event)=>update({
|
|
595
|
+
description: event.target.value
|
|
596
|
+
}),
|
|
597
|
+
size: "small",
|
|
598
|
+
multiline: true,
|
|
599
|
+
minRows: 2
|
|
600
|
+
}),
|
|
601
|
+
/*#__PURE__*/ _jsx(Autocomplete, {
|
|
602
|
+
multiple: true,
|
|
603
|
+
freeSolo: true,
|
|
604
|
+
options: [],
|
|
605
|
+
value: (_current_tags1 = current.tags) != null ? _current_tags1 : [],
|
|
606
|
+
onChange: (_event, tags)=>update({
|
|
607
|
+
tags: tags.map((tag)=>String(tag).trim()).filter(Boolean)
|
|
608
|
+
}),
|
|
609
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
610
|
+
label: "Tags",
|
|
611
|
+
size: "small",
|
|
612
|
+
placeholder: "Type and press Enter"
|
|
613
|
+
}))
|
|
614
|
+
}),
|
|
615
|
+
categories.rows.length > 0 ? /*#__PURE__*/ _jsx(Autocomplete, {
|
|
616
|
+
multiple: true,
|
|
617
|
+
options: categories.rows,
|
|
618
|
+
getOptionLabel: (category)=>category.name,
|
|
619
|
+
isOptionEqualToValue: (option, value)=>option.$id === value.$id,
|
|
620
|
+
value: categories.rows.filter((category)=>{
|
|
621
|
+
var _current_categoryIds;
|
|
622
|
+
return ((_current_categoryIds = current.categoryIds) != null ? _current_categoryIds : []).includes(category.$id);
|
|
623
|
+
}),
|
|
624
|
+
onChange: (_event, picked)=>update({
|
|
625
|
+
categoryIds: picked.map((category)=>category.$id)
|
|
626
|
+
}),
|
|
627
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
628
|
+
label: "Categories",
|
|
629
|
+
size: "small"
|
|
630
|
+
}))
|
|
631
|
+
}) : null,
|
|
632
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(WidgetSlot, {
|
|
633
|
+
slot: "productEditor",
|
|
634
|
+
hostId: hostId,
|
|
635
|
+
orgId: undefined,
|
|
636
|
+
product: zoneProduct,
|
|
637
|
+
categories: zoneCategories,
|
|
638
|
+
proposeValues: proposeProductValues
|
|
639
|
+
}) : null,
|
|
640
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
641
|
+
textAlign: "left",
|
|
642
|
+
children: 'Media'
|
|
643
|
+
}),
|
|
644
|
+
/*#__PURE__*/ _jsxs(Box, {
|
|
645
|
+
sx: {
|
|
646
|
+
display: 'flex',
|
|
647
|
+
gap: 1,
|
|
648
|
+
flexWrap: 'wrap'
|
|
649
|
+
},
|
|
650
|
+
children: [
|
|
651
|
+
((_current_mediaUrls1 = current.mediaUrls) != null ? _current_mediaUrls1 : []).map((url, index)=>/*#__PURE__*/ _jsxs(Box, {
|
|
652
|
+
sx: {
|
|
653
|
+
position: 'relative'
|
|
654
|
+
},
|
|
655
|
+
children: [
|
|
656
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
657
|
+
component: "img",
|
|
658
|
+
src: url,
|
|
659
|
+
alt: "",
|
|
660
|
+
sx: {
|
|
661
|
+
width: 72,
|
|
662
|
+
height: 72,
|
|
663
|
+
objectFit: 'cover',
|
|
664
|
+
borderRadius: 1,
|
|
665
|
+
border: 1,
|
|
666
|
+
borderColor: 'divider'
|
|
667
|
+
}
|
|
668
|
+
}),
|
|
669
|
+
/*#__PURE__*/ _jsx(IconButton, {
|
|
670
|
+
size: "small",
|
|
671
|
+
"aria-label": "Remove image",
|
|
672
|
+
onClick: ()=>{
|
|
673
|
+
var _current_mediaUrls;
|
|
674
|
+
return update({
|
|
675
|
+
mediaUrls: ((_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
676
|
+
});
|
|
677
|
+
},
|
|
678
|
+
sx: {
|
|
679
|
+
position: 'absolute',
|
|
680
|
+
top: -8,
|
|
681
|
+
right: -8,
|
|
682
|
+
bgcolor: 'background.paper',
|
|
683
|
+
border: 1,
|
|
684
|
+
borderColor: 'divider',
|
|
685
|
+
p: 0.25
|
|
686
|
+
},
|
|
687
|
+
children: '✕'
|
|
688
|
+
})
|
|
689
|
+
]
|
|
690
|
+
}, `${url}-${index}`)),
|
|
691
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
692
|
+
size: "small",
|
|
693
|
+
onClick: ()=>void pick((media)=>{
|
|
694
|
+
var _current_mediaUrls;
|
|
695
|
+
return update({
|
|
696
|
+
mediaUrls: [
|
|
697
|
+
...(_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
698
|
+
media.url
|
|
699
|
+
]
|
|
700
|
+
});
|
|
701
|
+
}),
|
|
702
|
+
children: 'Add image'
|
|
703
|
+
})
|
|
704
|
+
]
|
|
705
|
+
}),
|
|
706
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
707
|
+
textAlign: "left",
|
|
708
|
+
children: 'Options & variants'
|
|
709
|
+
}),
|
|
710
|
+
((_current_options1 = current.options) != null ? _current_options1 : []).map((option, index)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
711
|
+
direction: "row",
|
|
712
|
+
spacing: 1,
|
|
713
|
+
sx: {
|
|
714
|
+
alignItems: 'flex-start'
|
|
715
|
+
},
|
|
716
|
+
children: [
|
|
717
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
718
|
+
label: "Option",
|
|
719
|
+
value: option.name,
|
|
720
|
+
onChange: (event)=>handleOptionsChange(index, {
|
|
721
|
+
name: event.target.value
|
|
722
|
+
}),
|
|
723
|
+
size: "small",
|
|
724
|
+
sx: {
|
|
725
|
+
width: 160
|
|
726
|
+
},
|
|
727
|
+
placeholder: "Size"
|
|
728
|
+
}),
|
|
729
|
+
/*#__PURE__*/ _jsx(Autocomplete, {
|
|
730
|
+
multiple: true,
|
|
731
|
+
freeSolo: true,
|
|
732
|
+
options: [],
|
|
733
|
+
value: option.values,
|
|
734
|
+
onChange: (_event, values)=>handleOptionsChange(index, {
|
|
735
|
+
values: values.map((value)=>String(value).trim()).filter(Boolean)
|
|
736
|
+
}),
|
|
737
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
738
|
+
label: "Values",
|
|
739
|
+
size: "small",
|
|
740
|
+
placeholder: "S, M, L…"
|
|
741
|
+
})),
|
|
742
|
+
sx: {
|
|
743
|
+
flex: 1
|
|
744
|
+
}
|
|
745
|
+
}),
|
|
746
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
747
|
+
size: "small",
|
|
748
|
+
color: "error",
|
|
749
|
+
onClick: ()=>handleOptionsChange(index, null),
|
|
750
|
+
sx: {
|
|
751
|
+
mt: 0.5
|
|
752
|
+
},
|
|
753
|
+
children: 'Remove'
|
|
754
|
+
})
|
|
755
|
+
]
|
|
756
|
+
}, index)),
|
|
757
|
+
((_ref4 = (_current_options2 = current.options) == null ? void 0 : _current_options2.length) != null ? _ref4 : 0) < CommerceModel.COMMERCE_MAX_OPTIONS ? /*#__PURE__*/ _jsx(Button, {
|
|
758
|
+
size: "small",
|
|
759
|
+
sx: {
|
|
760
|
+
alignSelf: 'flex-start'
|
|
761
|
+
},
|
|
762
|
+
onClick: ()=>{
|
|
763
|
+
var _ref;
|
|
764
|
+
var _current_options;
|
|
765
|
+
return handleOptionsChange((_ref = (_current_options = current.options) == null ? void 0 : _current_options.length) != null ? _ref : 0, {
|
|
766
|
+
name: '',
|
|
767
|
+
values: []
|
|
768
|
+
});
|
|
769
|
+
},
|
|
770
|
+
children: 'Add option'
|
|
771
|
+
}) : null,
|
|
772
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
773
|
+
children: /*#__PURE__*/ _jsxs(ScrollTable, {
|
|
774
|
+
size: "small",
|
|
775
|
+
children: [
|
|
776
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
777
|
+
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
778
|
+
children: [
|
|
779
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
780
|
+
children: 'Variant'
|
|
781
|
+
}),
|
|
782
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
783
|
+
children: 'Price ($)'
|
|
784
|
+
}),
|
|
785
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
786
|
+
children: 'Compare-at'
|
|
787
|
+
}),
|
|
788
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
789
|
+
children: 'SKU'
|
|
790
|
+
}),
|
|
791
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
792
|
+
children: 'Barcode'
|
|
793
|
+
}),
|
|
794
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
795
|
+
children: 'Stock'
|
|
796
|
+
}),
|
|
797
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
798
|
+
children: 'Weight (g)'
|
|
799
|
+
})
|
|
800
|
+
]
|
|
801
|
+
})
|
|
802
|
+
}),
|
|
803
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
804
|
+
children: current.variants.map((variant, index)=>{
|
|
805
|
+
var _variant_priceUsd, _variant_compareAtPriceUsd, _variant_sku, _variant_barcode, _variant_inventory, _variant_weightGrams;
|
|
806
|
+
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
807
|
+
children: [
|
|
808
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
809
|
+
sx: {
|
|
810
|
+
whiteSpace: 'nowrap'
|
|
811
|
+
},
|
|
812
|
+
children: comboLabel(variant.options)
|
|
813
|
+
}),
|
|
814
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
815
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
816
|
+
value: (_variant_priceUsd = variant.priceUsd) != null ? _variant_priceUsd : '',
|
|
817
|
+
onChange: (event)=>handleVariantField(index, 'priceUsd', event.target.value),
|
|
818
|
+
size: "small",
|
|
819
|
+
sx: {
|
|
820
|
+
width: 88
|
|
821
|
+
},
|
|
822
|
+
// An empty price is marked (AGL-2916): a proposed
|
|
823
|
+
// product arrives with none, and Save waits for one.
|
|
824
|
+
error: !CommerceModel.variantHasPrice(variant),
|
|
825
|
+
placeholder: "Set",
|
|
826
|
+
slotProps: {
|
|
827
|
+
htmlInput: {
|
|
828
|
+
inputMode: 'decimal'
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
})
|
|
832
|
+
}),
|
|
833
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
834
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
835
|
+
value: (_variant_compareAtPriceUsd = variant.compareAtPriceUsd) != null ? _variant_compareAtPriceUsd : '',
|
|
836
|
+
onChange: (event)=>handleVariantField(index, 'compareAtPriceUsd', event.target.value),
|
|
837
|
+
size: "small",
|
|
838
|
+
sx: {
|
|
839
|
+
width: 88
|
|
840
|
+
},
|
|
841
|
+
slotProps: {
|
|
842
|
+
htmlInput: {
|
|
843
|
+
inputMode: 'decimal'
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
})
|
|
847
|
+
}),
|
|
848
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
849
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
850
|
+
value: (_variant_sku = variant.sku) != null ? _variant_sku : '',
|
|
851
|
+
onChange: (event)=>handleVariantField(index, 'sku', event.target.value),
|
|
852
|
+
size: "small",
|
|
853
|
+
sx: {
|
|
854
|
+
width: 110
|
|
855
|
+
}
|
|
856
|
+
})
|
|
857
|
+
}),
|
|
858
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
859
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
860
|
+
value: (_variant_barcode = variant.barcode) != null ? _variant_barcode : '',
|
|
861
|
+
onChange: (event)=>handleVariantField(index, 'barcode', event.target.value),
|
|
862
|
+
size: "small",
|
|
863
|
+
sx: {
|
|
864
|
+
width: 110
|
|
865
|
+
}
|
|
866
|
+
})
|
|
867
|
+
}),
|
|
868
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
869
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
870
|
+
value: (_variant_inventory = variant.inventory) != null ? _variant_inventory : '',
|
|
871
|
+
placeholder: stockApplies ? '—' : 'n/a',
|
|
872
|
+
disabled: !stockApplies,
|
|
873
|
+
onChange: (event)=>handleVariantField(index, 'inventory', event.target.value),
|
|
874
|
+
size: "small",
|
|
875
|
+
sx: {
|
|
876
|
+
width: 72
|
|
877
|
+
},
|
|
878
|
+
slotProps: {
|
|
879
|
+
htmlInput: {
|
|
880
|
+
inputMode: 'numeric',
|
|
881
|
+
'aria-label': `Stock — ${comboLabel(variant.options)}`
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
})
|
|
885
|
+
}),
|
|
886
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
887
|
+
children: /*#__PURE__*/ _jsx(TextField, {
|
|
888
|
+
value: (_variant_weightGrams = variant.weightGrams) != null ? _variant_weightGrams : '',
|
|
889
|
+
onChange: (event)=>handleVariantField(index, 'weightGrams', event.target.value),
|
|
890
|
+
size: "small",
|
|
891
|
+
sx: {
|
|
892
|
+
width: 88
|
|
893
|
+
},
|
|
894
|
+
slotProps: {
|
|
895
|
+
htmlInput: {
|
|
896
|
+
inputMode: 'numeric'
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
})
|
|
900
|
+
})
|
|
901
|
+
]
|
|
902
|
+
}, variant.id);
|
|
903
|
+
})
|
|
904
|
+
})
|
|
905
|
+
]
|
|
906
|
+
})
|
|
907
|
+
}),
|
|
908
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
909
|
+
variant: "caption",
|
|
910
|
+
color: "text.secondary",
|
|
911
|
+
children: stockApplies ? 'Blank stock = untracked; 0 shows sold out. The first variant’s ' + 'price feeds legacy Product blocks.' : 'Stock is not tracked on a digital or service subscription — ' + 'nothing decrements it, on the first charge or on any renewal. ' + 'A physical subscription decrements per cycle, and “Both — ' + 'buyer chooses” tracks the one-time sales. The first variant’s ' + 'price feeds legacy Product blocks.'
|
|
912
|
+
}),
|
|
913
|
+
strandedStock != null ? /*#__PURE__*/ _jsx(Alert, {
|
|
914
|
+
severity: "warning",
|
|
915
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
916
|
+
size: "small",
|
|
917
|
+
onClick: handleClearStockTracking,
|
|
918
|
+
children: 'Clear stock'
|
|
919
|
+
}),
|
|
920
|
+
children: `This product still has stock set (${strandedStock}), but a ` + 'digital or service subscription never decrements it — not the ' + 'first charge, not any renewal — so the number will not change ' + 'on its own and does not cap subscribers. It is kept, not ' + 'deleted: a stored 0 still blocks new subscribers, and the ' + 'value becomes editable again if you switch Billing back to ' + 'one-time or “Both”, or the Type to physical.'
|
|
921
|
+
}) : null,
|
|
922
|
+
subsLocked || giftsLocked ? /*#__PURE__*/ _jsx(EntitlementUpsell, {
|
|
923
|
+
planLabel: undefined,
|
|
924
|
+
upgradeHref: subsLocked ? subs.upgradeHref : gifts.upgradeHref,
|
|
925
|
+
children: subsLocked && giftsLocked ? `Subscription products (${(_subs_planLabel = subs.planLabel) != null ? _subs_planLabel : 'higher plan'}) ` + `and gift cards (${(_gifts_planLabel = gifts.planLabel) != null ? _gifts_planLabel : 'higher plan'}) are ` + 'not on your plan. You can still save this product — those ' + 'two options stay locked until you upgrade.' : subsLocked ? `Subscription products are on ${(_subs_planLabel1 = subs.planLabel) != null ? _subs_planLabel1 : 'a higher plan'}. ` + 'A subscription saved without it is refused at checkout, ' + 'so the option stays locked here instead.' : `Gift cards are on ${(_gifts_planLabel1 = gifts.planLabel) != null ? _gifts_planLabel1 : 'a higher plan'}. ` + 'A gift-card product saved without it is refused at ' + 'checkout, so the option stays locked here instead.'
|
|
926
|
+
}) : null,
|
|
927
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
928
|
+
direction: "row",
|
|
929
|
+
spacing: 2,
|
|
930
|
+
children: [
|
|
931
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
932
|
+
label: "When out of stock",
|
|
933
|
+
value: (_current_oversellPolicy = current.oversellPolicy) != null ? _current_oversellPolicy : 'deny',
|
|
934
|
+
onChange: (event)=>update({
|
|
935
|
+
oversellPolicy: event.target.value
|
|
936
|
+
}),
|
|
937
|
+
size: "small",
|
|
938
|
+
select: true,
|
|
939
|
+
sx: {
|
|
940
|
+
minWidth: 200
|
|
941
|
+
},
|
|
942
|
+
children: [
|
|
943
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
944
|
+
value: "deny",
|
|
945
|
+
children: 'Stop selling (sold out)'
|
|
946
|
+
}),
|
|
947
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
948
|
+
value: "backorder",
|
|
949
|
+
children: 'Keep selling (backorder)'
|
|
950
|
+
})
|
|
951
|
+
]
|
|
952
|
+
}),
|
|
953
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
954
|
+
label: "Kind",
|
|
955
|
+
value: current.giftCard ? 'gift' : 'standard',
|
|
956
|
+
onChange: (event)=>update({
|
|
957
|
+
giftCard: event.target.value === 'gift'
|
|
958
|
+
}),
|
|
959
|
+
size: "small",
|
|
960
|
+
select: true,
|
|
961
|
+
sx: {
|
|
962
|
+
minWidth: 130
|
|
963
|
+
},
|
|
964
|
+
helperText: giftsLocked ? `Gift cards are on ${(_gifts_planLabel2 = gifts.planLabel) != null ? _gifts_planLabel2 : 'a higher plan'}` : 'Gift cards issue a code',
|
|
965
|
+
children: [
|
|
966
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
967
|
+
value: "standard",
|
|
968
|
+
children: 'Standard'
|
|
969
|
+
}),
|
|
970
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
971
|
+
value: "gift",
|
|
972
|
+
disabled: giftsLocked,
|
|
973
|
+
children: giftsLocked ? `Gift card — ${(_gifts_planLabel3 = gifts.planLabel) != null ? _gifts_planLabel3 : 'upgrade'} plan` : 'Gift card'
|
|
974
|
+
})
|
|
975
|
+
]
|
|
976
|
+
}),
|
|
977
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
978
|
+
label: "Tax",
|
|
979
|
+
value: current.taxExempt ? 'exempt' : 'taxable',
|
|
980
|
+
onChange: (event)=>update({
|
|
981
|
+
taxExempt: event.target.value === 'exempt'
|
|
982
|
+
}),
|
|
983
|
+
size: "small",
|
|
984
|
+
select: true,
|
|
985
|
+
sx: {
|
|
986
|
+
minWidth: 120
|
|
987
|
+
},
|
|
988
|
+
children: [
|
|
989
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
990
|
+
value: "taxable",
|
|
991
|
+
children: 'Taxable'
|
|
992
|
+
}),
|
|
993
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
994
|
+
value: "exempt",
|
|
995
|
+
children: 'Tax exempt'
|
|
996
|
+
})
|
|
997
|
+
]
|
|
998
|
+
}),
|
|
999
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
1000
|
+
label: "Low-stock alert at",
|
|
1001
|
+
value: (_current_lowStockThreshold = current.lowStockThreshold) != null ? _current_lowStockThreshold : '',
|
|
1002
|
+
placeholder: "Off",
|
|
1003
|
+
disabled: !stockApplies,
|
|
1004
|
+
onChange: (event)=>{
|
|
1005
|
+
const raw = event.target.value.trim();
|
|
1006
|
+
update({
|
|
1007
|
+
lowStockThreshold: raw === '' ? undefined : Math.max(0, Math.round(Number(raw)))
|
|
1008
|
+
});
|
|
1009
|
+
},
|
|
1010
|
+
size: "small",
|
|
1011
|
+
sx: {
|
|
1012
|
+
width: 140
|
|
1013
|
+
},
|
|
1014
|
+
slotProps: {
|
|
1015
|
+
htmlInput: {
|
|
1016
|
+
inputMode: 'numeric'
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
helperText: "Notifies managers"
|
|
1020
|
+
})
|
|
1021
|
+
]
|
|
1022
|
+
}),
|
|
1023
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
1024
|
+
direction: "row",
|
|
1025
|
+
spacing: 2,
|
|
1026
|
+
children: [
|
|
1027
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
1028
|
+
label: "Billing",
|
|
1029
|
+
value: current.subscription ? current.subscriptionOptional ? 'both' : current.subscription.interval : 'once',
|
|
1030
|
+
onChange: (event)=>{
|
|
1031
|
+
const value = event.target.value;
|
|
1032
|
+
// "Both" (AGL-545): the PDP offers one-time OR subscribe at
|
|
1033
|
+
// the same price; the interval field beside picks the cadence.
|
|
1034
|
+
// Cleared keys are deleted (not set undefined) so the
|
|
1035
|
+
// client-direct setDoc on save never sees undefined values.
|
|
1036
|
+
const next = _extends({}, current);
|
|
1037
|
+
if (value === 'once') {
|
|
1038
|
+
delete next.subscription;
|
|
1039
|
+
} else {
|
|
1040
|
+
var _current_subscription, _ref;
|
|
1041
|
+
var _current_subscription1;
|
|
1042
|
+
next.subscription = _extends({}, (_current_subscription = current.subscription) != null ? _current_subscription : {}, {
|
|
1043
|
+
interval: value === 'both' ? (_ref = (_current_subscription1 = current.subscription) == null ? void 0 : _current_subscription1.interval) != null ? _ref : 'month' : value
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
if (value === 'both') next.subscriptionOptional = true;
|
|
1047
|
+
else delete next.subscriptionOptional;
|
|
1048
|
+
// setDraft directly: update() spreads the patch over
|
|
1049
|
+
// `current`, which would resurrect the deleted keys.
|
|
1050
|
+
setDraft(next);
|
|
1051
|
+
},
|
|
1052
|
+
size: "small",
|
|
1053
|
+
select: true,
|
|
1054
|
+
sx: {
|
|
1055
|
+
minWidth: 180
|
|
1056
|
+
},
|
|
1057
|
+
helperText: subsLocked ? `Subscriptions are on ${(_subs_planLabel2 = subs.planLabel) != null ? _subs_planLabel2 : 'a higher plan'}` : 'Subscriptions bill until canceled',
|
|
1058
|
+
children: [
|
|
1059
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1060
|
+
value: "once",
|
|
1061
|
+
children: 'One-time purchase'
|
|
1062
|
+
}),
|
|
1063
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1064
|
+
value: "month",
|
|
1065
|
+
disabled: subsLocked,
|
|
1066
|
+
children: 'Monthly subscription'
|
|
1067
|
+
}),
|
|
1068
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1069
|
+
value: "year",
|
|
1070
|
+
disabled: subsLocked,
|
|
1071
|
+
children: 'Yearly subscription'
|
|
1072
|
+
}),
|
|
1073
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1074
|
+
value: "both",
|
|
1075
|
+
disabled: subsLocked,
|
|
1076
|
+
children: 'Both — buyer chooses'
|
|
1077
|
+
})
|
|
1078
|
+
]
|
|
1079
|
+
}),
|
|
1080
|
+
current.subscription && current.subscriptionOptional ? /*#__PURE__*/ _jsxs(TextField, {
|
|
1081
|
+
label: "Interval",
|
|
1082
|
+
value: current.subscription.interval,
|
|
1083
|
+
onChange: (event)=>update({
|
|
1084
|
+
subscription: _extends({}, current.subscription, {
|
|
1085
|
+
interval: event.target.value
|
|
1086
|
+
})
|
|
1087
|
+
}),
|
|
1088
|
+
size: "small",
|
|
1089
|
+
select: true,
|
|
1090
|
+
sx: {
|
|
1091
|
+
minWidth: 120
|
|
1092
|
+
},
|
|
1093
|
+
children: [
|
|
1094
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1095
|
+
value: "month",
|
|
1096
|
+
children: 'Monthly'
|
|
1097
|
+
}),
|
|
1098
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1099
|
+
value: "year",
|
|
1100
|
+
children: 'Yearly'
|
|
1101
|
+
})
|
|
1102
|
+
]
|
|
1103
|
+
}) : null,
|
|
1104
|
+
current.subscription ? /*#__PURE__*/ _jsx(TextField, {
|
|
1105
|
+
label: "Free trial (days)",
|
|
1106
|
+
placeholder: "None",
|
|
1107
|
+
value: (_current_subscription_trialDays = current.subscription.trialDays) != null ? _current_subscription_trialDays : '',
|
|
1108
|
+
onChange: (event)=>{
|
|
1109
|
+
const raw = event.target.value.trim();
|
|
1110
|
+
update({
|
|
1111
|
+
subscription: _extends({}, current.subscription, raw === '' ? {
|
|
1112
|
+
trialDays: undefined
|
|
1113
|
+
} : {
|
|
1114
|
+
trialDays: Math.max(1, Math.round(Number(raw)))
|
|
1115
|
+
})
|
|
1116
|
+
});
|
|
1117
|
+
},
|
|
1118
|
+
size: "small",
|
|
1119
|
+
sx: {
|
|
1120
|
+
width: 140
|
|
1121
|
+
},
|
|
1122
|
+
slotProps: {
|
|
1123
|
+
htmlInput: {
|
|
1124
|
+
inputMode: 'numeric'
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}) : null
|
|
1128
|
+
]
|
|
1129
|
+
}),
|
|
1130
|
+
current.type === 'digital' ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
1131
|
+
children: [
|
|
1132
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
1133
|
+
textAlign: "left",
|
|
1134
|
+
children: 'Digital delivery'
|
|
1135
|
+
}),
|
|
1136
|
+
((_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []).map((file, index)=>{
|
|
1137
|
+
var _file_version;
|
|
1138
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
1139
|
+
direction: "row",
|
|
1140
|
+
spacing: 1,
|
|
1141
|
+
sx: {
|
|
1142
|
+
alignItems: 'center'
|
|
1143
|
+
},
|
|
1144
|
+
children: [
|
|
1145
|
+
/*#__PURE__*/ _jsxs(Typography, {
|
|
1146
|
+
variant: "body2",
|
|
1147
|
+
sx: {
|
|
1148
|
+
flex: 1
|
|
1149
|
+
},
|
|
1150
|
+
noWrap: true,
|
|
1151
|
+
children: [
|
|
1152
|
+
file.fileName,
|
|
1153
|
+
file.version ? ` · v${file.version}` : ''
|
|
1154
|
+
]
|
|
1155
|
+
}),
|
|
1156
|
+
/*#__PURE__*/ _jsx(PaidMediaProtection, {
|
|
1157
|
+
url: file.url,
|
|
1158
|
+
hostId: hostId,
|
|
1159
|
+
productId: product == null ? void 0 : product.$id,
|
|
1160
|
+
kind: "download"
|
|
1161
|
+
}),
|
|
1162
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
1163
|
+
label: "Version",
|
|
1164
|
+
value: (_file_version = file.version) != null ? _file_version : '',
|
|
1165
|
+
onChange: (event)=>{
|
|
1166
|
+
var _current_digitalFiles;
|
|
1167
|
+
const digitalFiles = [
|
|
1168
|
+
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []
|
|
1169
|
+
];
|
|
1170
|
+
digitalFiles[index] = _extends({}, file, {
|
|
1171
|
+
version: event.target.value.slice(0, 20)
|
|
1172
|
+
});
|
|
1173
|
+
update({
|
|
1174
|
+
digitalFiles
|
|
1175
|
+
});
|
|
1176
|
+
},
|
|
1177
|
+
size: "small",
|
|
1178
|
+
sx: {
|
|
1179
|
+
width: 100
|
|
1180
|
+
}
|
|
1181
|
+
}),
|
|
1182
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
1183
|
+
size: "small",
|
|
1184
|
+
color: "error",
|
|
1185
|
+
onClick: ()=>{
|
|
1186
|
+
var _current_digitalFiles;
|
|
1187
|
+
return update({
|
|
1188
|
+
digitalFiles: ((_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
1189
|
+
});
|
|
1190
|
+
},
|
|
1191
|
+
children: '✕'
|
|
1192
|
+
})
|
|
1193
|
+
]
|
|
1194
|
+
}, index);
|
|
1195
|
+
}),
|
|
1196
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
1197
|
+
direction: "row",
|
|
1198
|
+
spacing: 2,
|
|
1199
|
+
children: [
|
|
1200
|
+
/*#__PURE__*/ _jsx(PaidDownloadAddButton, {
|
|
1201
|
+
hostId: hostId,
|
|
1202
|
+
productId: product == null ? void 0 : product.$id,
|
|
1203
|
+
onAdd: (file)=>{
|
|
1204
|
+
var _current_digitalFiles;
|
|
1205
|
+
return update({
|
|
1206
|
+
digitalFiles: [
|
|
1207
|
+
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : [],
|
|
1208
|
+
file
|
|
1209
|
+
]
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
}),
|
|
1213
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
1214
|
+
label: "Download limit",
|
|
1215
|
+
placeholder: "Unlimited",
|
|
1216
|
+
value: (_current_downloadLimit = current.downloadLimit) != null ? _current_downloadLimit : '',
|
|
1217
|
+
onChange: (event)=>{
|
|
1218
|
+
const raw = event.target.value.trim();
|
|
1219
|
+
update({
|
|
1220
|
+
downloadLimit: raw === '' ? undefined : Math.max(1, Math.round(Number(raw)))
|
|
1221
|
+
});
|
|
1222
|
+
},
|
|
1223
|
+
size: "small",
|
|
1224
|
+
sx: {
|
|
1225
|
+
width: 140
|
|
1226
|
+
},
|
|
1227
|
+
slotProps: {
|
|
1228
|
+
htmlInput: {
|
|
1229
|
+
inputMode: 'numeric'
|
|
1230
|
+
}
|
|
1231
|
+
},
|
|
1232
|
+
helperText: "Attempts per order"
|
|
1233
|
+
})
|
|
1234
|
+
]
|
|
1235
|
+
}),
|
|
1236
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
1237
|
+
variant: "caption",
|
|
1238
|
+
color: "text.secondary",
|
|
1239
|
+
children: 'Buyers always download the current files — uploading a new ' + 'version re-delivers to everyone.'
|
|
1240
|
+
}),
|
|
1241
|
+
/*#__PURE__*/ _jsx(MembersVideosField, {
|
|
1242
|
+
hostId: hostId,
|
|
1243
|
+
productId: product == null ? void 0 : product.$id,
|
|
1244
|
+
videos: (_current_gatedVideos = current.gatedVideos) != null ? _current_gatedVideos : [],
|
|
1245
|
+
onChange: (gatedVideos)=>update({
|
|
1246
|
+
gatedVideos
|
|
1247
|
+
})
|
|
1248
|
+
})
|
|
1249
|
+
]
|
|
1250
|
+
}) : null,
|
|
1251
|
+
/*#__PURE__*/ _jsx(Autocomplete, {
|
|
1252
|
+
multiple: true,
|
|
1253
|
+
options: relatedProducts.rows.filter((item)=>!item.deletedAt && item.$id !== (product == null ? void 0 : product.$id)),
|
|
1254
|
+
getOptionLabel: (item)=>{
|
|
1255
|
+
var _item_name;
|
|
1256
|
+
return (_item_name = item.name) != null ? _item_name : item.$id;
|
|
1257
|
+
},
|
|
1258
|
+
isOptionEqualToValue: (option, value)=>option.$id === value.$id,
|
|
1259
|
+
value: relatedProducts.rows.filter((item)=>{
|
|
1260
|
+
var _current_relatedProductIds;
|
|
1261
|
+
return ((_current_relatedProductIds = current.relatedProductIds) != null ? _current_relatedProductIds : []).includes(item.$id);
|
|
1262
|
+
}),
|
|
1263
|
+
onChange: (_event, picked)=>update({
|
|
1264
|
+
relatedProductIds: picked.map((item)=>item.$id)
|
|
1265
|
+
}),
|
|
1266
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
1267
|
+
label: "Related products (upsells)",
|
|
1268
|
+
size: "small",
|
|
1269
|
+
helperText: "Shown by the Related products block; blank falls back to frequently-bought-together"
|
|
1270
|
+
}))
|
|
1271
|
+
}),
|
|
1272
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
1273
|
+
textAlign: "left",
|
|
1274
|
+
children: 'Search engine listing'
|
|
1275
|
+
}),
|
|
1276
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
1277
|
+
direction: {
|
|
1278
|
+
xs: 'column',
|
|
1279
|
+
sm: 'row'
|
|
1280
|
+
},
|
|
1281
|
+
spacing: 2,
|
|
1282
|
+
children: [
|
|
1283
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
1284
|
+
label: "SEO title",
|
|
1285
|
+
value: (_ref5 = (_current_seo2 = current.seo) == null ? void 0 : _current_seo2.title) != null ? _ref5 : '',
|
|
1286
|
+
onChange: (event)=>update({
|
|
1287
|
+
seo: _extends({}, current.seo, {
|
|
1288
|
+
title: event.target.value
|
|
1289
|
+
})
|
|
1290
|
+
}),
|
|
1291
|
+
// The counts every search listing editor prints (AGL-2910): what a
|
|
1292
|
+
// search result shows before it truncates.
|
|
1293
|
+
helperText: seoListingFieldCount('title', (_current_seo3 = current.seo) == null ? void 0 : _current_seo3.title),
|
|
1294
|
+
error: seoListingFieldTooLong('title', (_current_seo4 = current.seo) == null ? void 0 : _current_seo4.title),
|
|
1295
|
+
size: "small",
|
|
1296
|
+
fullWidth: true
|
|
1297
|
+
}),
|
|
1298
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
1299
|
+
size: "small",
|
|
1300
|
+
onClick: ()=>void pick((media)=>update({
|
|
1301
|
+
seo: _extends({}, current.seo, {
|
|
1302
|
+
imageUrl: media.url
|
|
1303
|
+
})
|
|
1304
|
+
})),
|
|
1305
|
+
children: ((_current_seo5 = current.seo) == null ? void 0 : _current_seo5.imageUrl) ? 'Change OG image' : 'OG image'
|
|
1306
|
+
})
|
|
1307
|
+
]
|
|
1308
|
+
}),
|
|
1309
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
1310
|
+
label: "SEO description",
|
|
1311
|
+
value: (_ref6 = (_current_seo6 = current.seo) == null ? void 0 : _current_seo6.description) != null ? _ref6 : '',
|
|
1312
|
+
onChange: (event)=>update({
|
|
1313
|
+
seo: _extends({}, current.seo, {
|
|
1314
|
+
description: event.target.value
|
|
1315
|
+
})
|
|
1316
|
+
}),
|
|
1317
|
+
helperText: seoListingFieldCount('description', (_current_seo7 = current.seo) == null ? void 0 : _current_seo7.description),
|
|
1318
|
+
error: seoListingFieldTooLong('description', (_current_seo8 = current.seo) == null ? void 0 : _current_seo8.description),
|
|
1319
|
+
size: "small",
|
|
1320
|
+
multiline: true,
|
|
1321
|
+
minRows: 2
|
|
1322
|
+
}),
|
|
1323
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(WidgetSlot, {
|
|
1324
|
+
slot: "seoFields",
|
|
1325
|
+
hostId: hostId,
|
|
1326
|
+
orgId: undefined,
|
|
1327
|
+
orgSlug: "",
|
|
1328
|
+
subject: {
|
|
1329
|
+
kind: 'product',
|
|
1330
|
+
id: (_ref7 = product == null ? void 0 : product.$id) != null ? _ref7 : null,
|
|
1331
|
+
name: current.name,
|
|
1332
|
+
description: String((_current_description2 = current.description) != null ? _current_description2 : '')
|
|
1333
|
+
},
|
|
1334
|
+
fields: PRODUCT_SEO_LISTING_FIELDS,
|
|
1335
|
+
values: {
|
|
1336
|
+
title: (_ref8 = (_current_seo9 = current.seo) == null ? void 0 : _current_seo9.title) != null ? _ref8 : '',
|
|
1337
|
+
description: (_ref9 = (_current_seo10 = current.seo) == null ? void 0 : _current_seo10.description) != null ? _ref9 : ''
|
|
1338
|
+
},
|
|
1339
|
+
hasImage: Boolean((_current_seo11 = current.seo) == null ? void 0 : _current_seo11.imageUrl),
|
|
1340
|
+
proposeValues: proposeSeoValues
|
|
1341
|
+
}) : null,
|
|
1342
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
1343
|
+
severity: "warning",
|
|
1344
|
+
children: error
|
|
1345
|
+
}) : null,
|
|
1346
|
+
(product == null ? void 0 : product.$id) ? /*#__PURE__*/ _jsx(Typography, {
|
|
1347
|
+
variant: "caption",
|
|
1348
|
+
color: "text.secondary",
|
|
1349
|
+
children: `id: ${product.$id}`
|
|
1350
|
+
}) : null
|
|
1351
|
+
]
|
|
1352
|
+
}),
|
|
1353
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
1354
|
+
children: [
|
|
1355
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
1356
|
+
onClick: onClose,
|
|
1357
|
+
children: 'Cancel'
|
|
1358
|
+
}),
|
|
1359
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
1360
|
+
variant: "contained",
|
|
1361
|
+
color: "primary",
|
|
1362
|
+
disabled: !current.name.trim() || Boolean(error),
|
|
1363
|
+
onClick: handleSave,
|
|
1364
|
+
children: 'Save product'
|
|
1365
|
+
})
|
|
1366
|
+
]
|
|
1367
|
+
})
|
|
1368
|
+
]
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
ProductEditorDialog.displayName = 'ProductEditorDialog';
|
|
1372
|
+
export default ProductEditorDialog;
|
|
1373
|
+
|
|
1374
|
+
//# sourceMappingURL=product-editor-dialog.component.js.map
|