@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.287
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/README.md +1 -1
- package/package.json +13 -13
- package/src/lib/components/cart.js +25 -12
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +70 -13
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +2 -1
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/payment-methods-card.component.js +1 -1
- package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
- package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
- package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
- package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
- package/src/lib/components/console/pos/use-pos-display.js +50 -0
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
- package/src/lib/components/console/pos-cellular-control.component.js +211 -0
- package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
- package/src/lib/components/console/pos-devices-card.component.js +47 -15
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
- package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-display-page.component.js +44 -2
- package/src/lib/components/console/pos-display-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
- package/src/lib/components/console/pos-hardware-card.component.js +157 -36
- package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.d.ts +1 -1
- package/src/lib/components/console/pos-page.component.js +63 -12
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
- package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
- package/src/lib/components/console/product-check-in-fields.component.js +60 -14
- package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +44 -1
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
- package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
- package/src/lib/components/console/product-register-fields.component.js +31 -2
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +11 -2
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
- package/src/lib/components/console/register-hardware-card.component.js +56 -27
- package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +9 -0
- package/src/lib/components/console/reservations-card.component.js +158 -23
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
- package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
- package/src/lib/components/console/shipstation-card.component.js +3 -3
- package/src/lib/components/console/shipstation-card.component.js.map +1 -1
- package/src/lib/components/product-detail.d.ts +4 -0
- package/src/lib/components/product-detail.js +40 -5
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-reviews.js +28 -11
- package/src/lib/components/product-reviews.js.map +1 -1
- package/src/lib/components/reservation-widget.js +28 -5
- package/src/lib/components/reservation-widget.js.map +1 -1
- package/src/lib/components/use-day-picker.d.ts +25 -0
- package/src/lib/components/use-day-picker.js +57 -0
- package/src/lib/components/use-day-picker.js.map +1 -0
- package/src/lib/constants/operator-alerts.d.ts +55 -0
- package/src/lib/constants/operator-alerts.js +156 -1
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/declarations.console-server.js +54 -1
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +4 -2
- package/src/lib/declarations.js +11 -4
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +9 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-cart.d.ts +9 -1
- package/src/lib/model/commerce-cart.js +4 -3
- package/src/lib/model/commerce-cart.js.map +1 -1
- package/src/lib/model/commerce-check-in-product.d.ts +26 -0
- package/src/lib/model/commerce-check-in-product.js +64 -2
- package/src/lib/model/commerce-check-in-product.js.map +1 -1
- package/src/lib/model/commerce-check-in-record.d.ts +127 -0
- package/src/lib/model/commerce-check-in-record.js +36 -0
- package/src/lib/model/commerce-check-in-record.js.map +1 -0
- package/src/lib/model/commerce-check-in.d.ts +91 -87
- package/src/lib/model/commerce-check-in.js +186 -62
- package/src/lib/model/commerce-check-in.js.map +1 -1
- package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
- package/src/lib/model/commerce-kiosk-offer.js +35 -0
- package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +76 -0
- package/src/lib/model/commerce-orders.js +6 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
- package/src/lib/model/commerce-pos-day-report.js +39 -2
- package/src/lib/model/commerce-pos-day-report.js.map +1 -1
- package/src/lib/model/commerce-pos-offline.d.ts +1 -1
- package/src/lib/model/commerce-pos-offline.js +6 -1
- package/src/lib/model/commerce-pos-offline.js.map +1 -1
- package/src/lib/model/commerce-pos-ops.js +3 -2
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +36 -3
- package/src/lib/model/commerce-pos.js +14 -6
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-receipt.js +3 -2
- package/src/lib/model/commerce-receipt.js.map +1 -1
- package/src/lib/model/commerce-reservations.d.ts +69 -4
- package/src/lib/model/commerce-reservations.js +57 -5
- package/src/lib/model/commerce-reservations.js.map +1 -1
- package/src/lib/model/commerce.d.ts +66 -0
- package/src/lib/model/commerce.js +15 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/order-list-fields.d.ts +11 -0
- package/src/lib/model/order-list-fields.js +17 -1
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/own-store-tax-summary.d.ts +152 -0
- package/src/lib/model/own-store-tax-summary.js +288 -0
- package/src/lib/model/own-store-tax-summary.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +67 -0
- package/src/lib/model/plugin-permissions.js +224 -7
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/model/pos-cellular.d.ts +223 -0
- package/src/lib/model/pos-cellular.js +293 -0
- package/src/lib/model/pos-cellular.js.map +1 -0
- package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
- package/src/lib/model/pos-hardware-in-person.js +224 -0
- package/src/lib/model/pos-hardware-in-person.js.map +1 -0
- package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
- package/src/lib/model/pos-hardware-tax-summary.js +225 -0
- package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
- package/src/lib/model/pos-hardware-terms.d.ts +74 -0
- package/src/lib/model/pos-hardware-terms.js +115 -0
- package/src/lib/model/pos-hardware-terms.js.map +1 -0
- package/src/lib/model/pos-hardware.d.ts +349 -7
- package/src/lib/model/pos-hardware.js +291 -20
- package/src/lib/model/pos-hardware.js.map +1 -1
- package/src/lib/model/product-write.d.ts +10 -0
- package/src/lib/model/product-write.js +4 -2
- package/src/lib/model/product-write.js.map +1 -1
- package/src/lib/plugin.js +16 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +25 -1
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cancel-order.js +7 -5
- package/src/lib/server/cancel-order.js.map +1 -1
- package/src/lib/server/cart-checkout.js +20 -8
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.js +29 -0
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/checkout.js +42 -13
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/collection-membership.d.ts +4 -0
- package/src/lib/server/collection-membership.js +5 -10
- package/src/lib/server/collection-membership.js.map +1 -1
- package/src/lib/server/commerce-site-keys.d.ts +29 -0
- package/src/lib/server/commerce-site-keys.js +40 -0
- package/src/lib/server/commerce-site-keys.js.map +1 -0
- package/src/lib/server/draft-order.js +8 -5
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/fulfill-order.js +7 -5
- package/src/lib/server/fulfill-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +8 -5
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.js +9 -6
- package/src/lib/server/local-fulfillment-status.js.map +1 -1
- package/src/lib/server/member-post.js +6 -5
- package/src/lib/server/member-post.js.map +1 -1
- package/src/lib/server/membership-admin-password.d.ts +4 -2
- package/src/lib/server/membership-admin-password.js +10 -8
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-admin-remove.d.ts +7 -5
- package/src/lib/server/membership-admin-remove.js +9 -9
- package/src/lib/server/membership-admin-remove.js.map +1 -1
- package/src/lib/server/order-notifications.js +5 -2
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/order-print.js +7 -5
- package/src/lib/server/order-print.js.map +1 -1
- package/src/lib/server/order-receipt-send.js +8 -5
- package/src/lib/server/order-receipt-send.js.map +1 -1
- package/src/lib/server/orders-shipping-prepare.js +9 -6
- package/src/lib/server/orders-shipping-prepare.js.map +1 -1
- package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
- package/src/lib/server/own-store-tax-return-source.js +312 -0
- package/src/lib/server/own-store-tax-return-source.js.map +1 -0
- package/src/lib/server/payment-methods.js +13 -9
- package/src/lib/server/payment-methods.js.map +1 -1
- package/src/lib/server/pos-auth.d.ts +37 -6
- package/src/lib/server/pos-auth.js +40 -15
- package/src/lib/server/pos-auth.js.map +1 -1
- package/src/lib/server/pos-cellular-billing.d.ts +81 -0
- package/src/lib/server/pos-cellular-billing.js +711 -0
- package/src/lib/server/pos-cellular-billing.js.map +1 -0
- package/src/lib/server/pos-cellular-notify.d.ts +47 -0
- package/src/lib/server/pos-cellular-notify.js +150 -0
- package/src/lib/server/pos-cellular-notify.js.map +1 -0
- package/src/lib/server/pos-cellular.d.ts +88 -0
- package/src/lib/server/pos-cellular.js +339 -0
- package/src/lib/server/pos-cellular.js.map +1 -0
- package/src/lib/server/pos-check-in.d.ts +5 -1
- package/src/lib/server/pos-check-in.js +296 -28
- package/src/lib/server/pos-check-in.js.map +1 -1
- package/src/lib/server/pos-day-report.js +29 -3
- package/src/lib/server/pos-day-report.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +16 -0
- package/src/lib/server/pos-display.js +129 -2
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-hardware-admin.d.ts +10 -1
- package/src/lib/server/pos-hardware-admin.js +250 -84
- package/src/lib/server/pos-hardware-admin.js.map +1 -1
- package/src/lib/server/pos-hardware-attach.d.ts +105 -0
- package/src/lib/server/pos-hardware-attach.js +443 -0
- package/src/lib/server/pos-hardware-attach.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
- package/src/lib/server/pos-hardware-buyer-record.js +86 -0
- package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
- package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
- package/src/lib/server/pos-hardware-cancel.js +147 -0
- package/src/lib/server/pos-hardware-cancel.js.map +1 -0
- package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
- package/src/lib/server/pos-hardware-closure-notices.js +85 -0
- package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
- package/src/lib/server/pos-hardware-closure.d.ts +60 -0
- package/src/lib/server/pos-hardware-closure.js +153 -0
- package/src/lib/server/pos-hardware-closure.js.map +1 -0
- package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
- package/src/lib/server/pos-hardware-in-person.js +236 -0
- package/src/lib/server/pos-hardware-in-person.js.map +1 -0
- package/src/lib/server/pos-hardware-notify.d.ts +40 -2
- package/src/lib/server/pos-hardware-notify.js +195 -14
- package/src/lib/server/pos-hardware-notify.js.map +1 -1
- package/src/lib/server/pos-hardware-readers.d.ts +115 -0
- package/src/lib/server/pos-hardware-readers.js +430 -0
- package/src/lib/server/pos-hardware-readers.js.map +1 -0
- package/src/lib/server/pos-hardware-returns.d.ts +116 -0
- package/src/lib/server/pos-hardware-returns.js +502 -0
- package/src/lib/server/pos-hardware-returns.js.map +1 -0
- package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
- package/src/lib/server/pos-hardware-sale-fields.js +44 -0
- package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
- package/src/lib/server/pos-hardware-sale.d.ts +54 -0
- package/src/lib/server/pos-hardware-sale.js +369 -0
- package/src/lib/server/pos-hardware-sale.js.map +1 -0
- package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
- package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
- package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
- package/src/lib/server/pos-hardware-terms.d.ts +64 -0
- package/src/lib/server/pos-hardware-terms.js +154 -0
- package/src/lib/server/pos-hardware-terms.js.map +1 -0
- package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
- package/src/lib/server/pos-hardware-user-eraser.js +31 -7
- package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
- package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
- package/src/lib/server/pos-hardware-webhook.js +51 -6
- package/src/lib/server/pos-hardware-webhook.js.map +1 -1
- package/src/lib/server/pos-hardware.d.ts +74 -1
- package/src/lib/server/pos-hardware.js +175 -10
- package/src/lib/server/pos-hardware.js.map +1 -1
- package/src/lib/server/pos-kiosk.d.ts +2 -0
- package/src/lib/server/pos-kiosk.js +17 -12
- package/src/lib/server/pos-kiosk.js.map +1 -1
- package/src/lib/server/pos-offline-card-order.d.ts +64 -0
- package/src/lib/server/pos-offline-card-order.js +102 -0
- package/src/lib/server/pos-offline-card-order.js.map +1 -0
- package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
- package/src/lib/server/pos-offline-card-reconcile.js +215 -18
- package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
- package/src/lib/server/pos-offline-sync.d.ts +39 -0
- package/src/lib/server/pos-offline-sync.js +190 -55
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-ops-gate.d.ts +15 -4
- package/src/lib/server/pos-ops-gate.js +42 -9
- package/src/lib/server/pos-ops-gate.js.map +1 -1
- package/src/lib/server/pos-ops-routes.js +24 -0
- package/src/lib/server/pos-ops-routes.js.map +1 -1
- package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
- package/src/lib/server/pos-order-refund-ids.js +31 -0
- package/src/lib/server/pos-order-refund-ids.js.map +1 -0
- package/src/lib/server/pos-order.js +52 -49
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.js +1 -1
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-reader-splash-admin.js +30 -32
- package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
- package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
- package/src/lib/server/pos-reader-splash-images-route.js +113 -0
- package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
- package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
- package/src/lib/server/pos-reader-splash-images.js +123 -0
- package/src/lib/server/pos-reader-splash-images.js.map +1 -0
- package/src/lib/server/pos-reader-splash.d.ts +68 -1
- package/src/lib/server/pos-reader-splash.js +182 -11
- package/src/lib/server/pos-reader-splash.js.map +1 -1
- package/src/lib/server/pos-readers.d.ts +29 -0
- package/src/lib/server/pos-readers.js +134 -35
- package/src/lib/server/pos-readers.js.map +1 -1
- package/src/lib/server/pos-return.d.ts +10 -0
- package/src/lib/server/pos-return.js +26 -1
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.js +6 -1
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +11 -0
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/pos-staff-pin.js +25 -20
- package/src/lib/server/pos-staff-pin.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +14 -4
- package/src/lib/server/pos-terminal.js +34 -38
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/printers.d.ts +7 -3
- package/src/lib/server/printers.js +18 -12
- package/src/lib/server/printers.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +11 -1
- package/src/lib/server/product-drafts.js +12 -8
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product.d.ts +15 -1
- package/src/lib/server/product.js +16 -3
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/products-write.d.ts +26 -2
- package/src/lib/server/products-write.js +19 -7
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/refund.js +34 -11
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/reservation-availability-query.d.ts +8 -0
- package/src/lib/server/reservation-availability-query.js +11 -1
- package/src/lib/server/reservation-availability-query.js.map +1 -1
- package/src/lib/server/reservation-availability.d.ts +1 -1
- package/src/lib/server/reservation-availability.js +7 -2
- package/src/lib/server/reservation-availability.js.map +1 -1
- package/src/lib/server/reservation-guests.d.ts +32 -0
- package/src/lib/server/reservation-guests.js +285 -0
- package/src/lib/server/reservation-guests.js.map +1 -0
- package/src/lib/server/reservation-walk-in.d.ts +11 -1
- package/src/lib/server/reservation-walk-in.js +56 -12
- package/src/lib/server/reservation-walk-in.js.map +1 -1
- package/src/lib/server/reserve.js +18 -5
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/returns.js +9 -6
- package/src/lib/server/returns.js.map +1 -1
- package/src/lib/server/reviews.d.ts +22 -2
- package/src/lib/server/reviews.js +88 -20
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/shipping-connectors.js +10 -11
- package/src/lib/server/shipping-connectors.js.map +1 -1
- package/src/lib/server/site-page-resolver.js +20 -3
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server/store-day.d.ts +33 -0
- package/src/lib/server/store-day.js +46 -0
- package/src/lib/server/store-day.js.map +1 -0
- package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
- package/src/lib/server/store-setup-ai-writer.js +5 -6
- package/src/lib/server/store-setup-ai-writer.js.map +1 -1
- package/src/lib/server/storefront-tax.d.ts +13 -0
- package/src/lib/server/storefront-tax.js +8 -1
- package/src/lib/server/storefront-tax.js.map +1 -1
- package/src/lib/server/tax-return-source.d.ts +32 -3
- package/src/lib/server/tax-return-source.js +99 -20
- package/src/lib/server/tax-return-source.js.map +1 -1
- package/src/lib/server.js +100 -2
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/fake-firestore.js +58 -16
- package/src/lib/testing/fake-firestore.js.map +1 -1
- package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
- package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
- package/src/lib/testing/site-register-permissions.d.ts +29 -0
- package/src/lib/testing/site-register-permissions.js +38 -0
- package/src/lib/testing/site-register-permissions.js.map +1 -0
- package/src/lib/transfer/tracking.server.js +8 -5
- package/src/lib/transfer/tracking.server.js.map +1 -1
- package/src/lib/utils/add-to-cart.d.ts +2 -0
- package/src/lib/utils/add-to-cart.js +6 -3
- package/src/lib/utils/add-to-cart.js.map +1 -1
|
@@ -48,6 +48,7 @@ import { ID as RELATED_PRODUCTS_ID } from "./related-products.js";
|
|
|
48
48
|
import { readLocalWishlist, toggleWishlist } from "./wishlist.js";
|
|
49
49
|
import { StorefrontPaymentElementFallback } from "./storefront-payment-element-fallback.js";
|
|
50
50
|
import { CheckoutReturnNotice } from "./checkout-return-notice.js";
|
|
51
|
+
import { zonedDayKey } from "@aglyn/shared-util-timestamp/zoned-time";
|
|
51
52
|
/**
|
|
52
53
|
* The Payment Element (AGL-1944), behind a lazy boundary rather than a plain
|
|
53
54
|
* import. Stripe.js and its React wrapper are a large dependency, the flag is
|
|
@@ -60,6 +61,10 @@ import { CheckoutReturnNotice } from "./checkout-return-notice.js";
|
|
|
60
61
|
// Component ids are persisted in screen documents; never rename.
|
|
61
62
|
export const ID = 'product-detail';
|
|
62
63
|
/** What the page says where a variant with no price yet would show one (AGL-3676). */ const PRICE_COMING_SOON_LABEL = 'Price coming soon';
|
|
64
|
+
/**
|
|
65
|
+
* The use-day picker (AGL-4043), in its own chunk: only a product whose
|
|
66
|
+
* variant asks for a day downloads the date picker.
|
|
67
|
+
*/ const UseDayPicker = /*#__PURE__*/ lazy(()=>import("./use-day-picker.js"));
|
|
63
68
|
const SAMPLE = {
|
|
64
69
|
id: 'sample',
|
|
65
70
|
name: 'Sample product',
|
|
@@ -250,6 +255,10 @@ function slugFromLocation() {
|
|
|
250
255
|
// used to set this, so it opened with nothing selected — an empty select.
|
|
251
256
|
const [selections, setSelections] = useState(()=>initialSelections(seededProduct));
|
|
252
257
|
const [quantity, setQuantity] = useState(1);
|
|
258
|
+
/**
|
|
259
|
+
* The day the buyer chose to use a pass (AGL-4043), `YYYY-MM-DD` on the
|
|
260
|
+
* store's calendar; '' is the day they buy, which is also the default.
|
|
261
|
+
*/ const [useDay, setUseDay] = useState('');
|
|
253
262
|
/** A discount or coupon code typed on the product page. */ const [coupon, setCoupon] = useState('');
|
|
254
263
|
// A thumbnail the shopper picked; null follows the variant's own photo.
|
|
255
264
|
const [activeImage, setActiveImage] = useState(null);
|
|
@@ -340,6 +349,11 @@ function slugFromLocation() {
|
|
|
340
349
|
resolved,
|
|
341
350
|
selections
|
|
342
351
|
]);
|
|
352
|
+
// The day to send with this variant: only when it asks for one and the
|
|
353
|
+
// buyer chose a day (AGL-4043).
|
|
354
|
+
const chosenUseDay = (variant == null ? void 0 : variant.asksUseDate) && useDay ? useDay : '';
|
|
355
|
+
// Today on the store's calendar, the first day the picker offers.
|
|
356
|
+
const storeTodayKey = (resolved == null ? void 0 : resolved.useDayTimeZone) ? zonedDayKey(Date.now(), resolved.useDayTimeZone) : '';
|
|
343
357
|
// Add to cart (AGL-293) beside instant buy; badge refresh via event.
|
|
344
358
|
const handleAddToCart = async ()=>{
|
|
345
359
|
if (!hostId || !resolved || !variant) return;
|
|
@@ -349,14 +363,17 @@ function slugFromLocation() {
|
|
|
349
363
|
// so GA4's "value added to cart" is a real number. The funnel step
|
|
350
364
|
// (AGL-3605) and the badge refresh ride the same shared helper the
|
|
351
365
|
// product grid's quick add uses.
|
|
352
|
-
const ok = await addToCart({
|
|
366
|
+
const ok = await addToCart(_extends({
|
|
353
367
|
hostId,
|
|
354
368
|
siteFetch,
|
|
355
369
|
productId: resolved.id,
|
|
356
370
|
variantId: variant.id,
|
|
357
|
-
quantity
|
|
371
|
+
quantity
|
|
372
|
+
}, chosenUseDay ? {
|
|
373
|
+
useDayKey: chosenUseDay
|
|
374
|
+
} : {}, {
|
|
358
375
|
item: buyItem(resolved, variant, quantity)
|
|
359
|
-
});
|
|
376
|
+
}));
|
|
360
377
|
if (ok) setAdded(true);
|
|
361
378
|
};
|
|
362
379
|
/**
|
|
@@ -391,7 +408,8 @@ function slugFromLocation() {
|
|
|
391
408
|
shipTo,
|
|
392
409
|
shipPostal,
|
|
393
410
|
coupon,
|
|
394
|
-
fulfillment.signature
|
|
411
|
+
fulfillment.signature,
|
|
412
|
+
chosenUseDay
|
|
395
413
|
]);
|
|
396
414
|
const handleBuy = async ()=>{
|
|
397
415
|
if (!hostId || !resolved || !variant || status === 'sending') return;
|
|
@@ -415,7 +433,9 @@ function slugFromLocation() {
|
|
|
415
433
|
productId: resolved.id,
|
|
416
434
|
variantId: variant.id,
|
|
417
435
|
quantity
|
|
418
|
-
},
|
|
436
|
+
}, chosenUseDay ? {
|
|
437
|
+
useDayKey: chosenUseDay
|
|
438
|
+
} : {}, resolved.subscriptionOptional ? {
|
|
419
439
|
billing
|
|
420
440
|
} : {}, shipTo && !fulfillment.request ? {
|
|
421
441
|
shippingCountry: shipTo
|
|
@@ -835,6 +855,21 @@ function slugFromLocation() {
|
|
|
835
855
|
},
|
|
836
856
|
children: 'Not on sale yet — check back soon.'
|
|
837
857
|
}) : null,
|
|
858
|
+
priced && (variant == null ? void 0 : variant.asksUseDate) && storeTodayKey ? /*#__PURE__*/ _jsx(Box, {
|
|
859
|
+
sx: {
|
|
860
|
+
mb: 2
|
|
861
|
+
},
|
|
862
|
+
children: /*#__PURE__*/ _jsx(Suspense, {
|
|
863
|
+
fallback: null,
|
|
864
|
+
children: /*#__PURE__*/ _jsx(UseDayPicker, {
|
|
865
|
+
value: useDay,
|
|
866
|
+
onChange: setUseDay,
|
|
867
|
+
todayKey: storeTodayKey,
|
|
868
|
+
label: "Day you will use it (optional)",
|
|
869
|
+
helperText: "Leave it blank to use it the day you buy."
|
|
870
|
+
})
|
|
871
|
+
})
|
|
872
|
+
}) : null,
|
|
838
873
|
/*#__PURE__*/ _jsxs(Box, {
|
|
839
874
|
sx: {
|
|
840
875
|
display: priced ? 'flex' : 'none',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/product-detail.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { advertisingConsentField } from '@aglyn/aglyn/app-utils/advertising-consent'\nimport * as Aglyn from '@aglyn/aglyn'\nimport {\n buildBeginCheckoutParams,\n trackEvent,\n trackEventBeforeNavigation,\n type AnalyticsItem,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport { isPaymentsNotConfigured } from '@aglyn/aglyn/app-utils/payments-configured'\nimport { storefrontPaymentsNotConfiguredText } from '../constants/storefront-payments'\nimport * as CommerceModel from '../model'\nimport { mdiChevronDown, mdiTagOutline } from '@aglyn/shared-data-mdi'\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport MenuItem from '@mui/material/MenuItem'\nimport Skeleton from '@mui/material/Skeleton'\nimport SvgIcon from '@mui/material/SvgIcon'\nimport TextField from '@mui/material/TextField'\nimport ToggleButton from '@mui/material/ToggleButton'\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup'\nimport Typography from '@mui/material/Typography'\nimport {\n Suspense,\n forwardRef,\n lazy,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport { useStorefrontPurchaseEvent } from '../utils/use-storefront-purchase-event'\nimport { addToCart } from '../utils/add-to-cart'\nimport { CartFulfillmentChoice, useCartFulfillment } from './cart-fulfillment'\nimport { ID as PRODUCT_REVIEWS_ID } from './product-reviews'\nimport { ID as RELATED_PRODUCTS_ID } from './related-products'\nimport { readLocalWishlist, toggleWishlist } from './wishlist'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\nimport { CheckoutReturnNotice } from './checkout-return-notice'\n\n/**\n * The Payment Element (AGL-1944), behind a lazy boundary rather than a plain\n * import. Stripe.js and its React wrapper are a large dependency, the flag is\n * OFF, and a static import would put the whole SDK into the bundle of every\n * product page on every published site to serve a code path no shopper reaches.\n * Split, it is fetched by the shoppers who actually get the in-page form.\n */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'product-detail'\n\nexport interface ProductDetailProps {\n /** Product slug; blank resolves from /products/{slug} in the URL. */\n slug?: string\n buyLabel?: string\n /** Hide the description block (design it separately with tokens). */\n hideDescription?: boolean\n /** Offer a discount/coupon code field before the buy button. */\n showCoupon?: boolean\n /**\n * A \"Details\" panel under the description: the facts the product record\n * holds — its kind (digital, service), the choices it comes in, the\n * selected variant's SKU, its tags. Never a fact the record does not hold.\n * Off by default, so a page that already places this block keeps its shape.\n */\n showDetails?: boolean\n /**\n * A \"Shipping & returns\" panel: how it is delivered (shipping priced at\n * checkout, or delivered digitally), and the store's own return window\n * when the store takes returns of this kind of product. Off by default.\n */\n showShipping?: boolean\n}\n\ninterface DetailVariant {\n id: string\n options?: Record<string, string>\n /** `null` while the product is listed before it has a price (AGL-3676). */\n priceUsd: number | null\n compareAtPriceUsd?: number\n soldOut: boolean\n imageUrl?: string\n sku?: string\n}\n\n/** What the page says where a variant with no price yet would show one (AGL-3676). */\nconst PRICE_COMING_SOON_LABEL = 'Price coming soon'\n\ninterface Detail {\n id: string\n name: string\n slug: string\n description?: string\n type?: CommerceModel.ProductType\n tags?: string[]\n mediaUrls: string[]\n options: CommerceModel.ProductOption[]\n variants: DetailVariant[]\n /** Recurring billing (AGL-303); framing + buyer choice on the PDP. */\n subscription?: { interval: 'month' | 'year'; trialDays?: number }\n /** Buyer picks one-time or subscribe at the same price (AGL-545). */\n subscriptionOptional?: boolean\n}\n\nconst SAMPLE: Detail = {\n id: 'sample',\n name: 'Sample product',\n slug: '#',\n description: 'Drop this block on your product page template.',\n mediaUrls: [],\n options: [{ name: 'Size', values: ['S', 'M', 'L'] }],\n variants: [\n { id: 'a', options: { Size: 'S' }, priceUsd: 29, soldOut: false },\n { id: 'b', options: { Size: 'M' }, priceUsd: 29, soldOut: false },\n { id: 'c', options: { Size: 'L' }, priceUsd: 32, soldOut: true },\n ],\n}\n\n/**\n * The GA4 `items` entry for one line of this product.\n *\n * `item_id` is the PRODUCT id and never the variant's, matching the\n * `view_item` above and the cart's lines below: GA joins the funnel on that\n * id, and a `begin_checkout` keyed on a variant would report a product nothing\n * else on the storefront had ever mentioned.\n *\n * `price` is the resolved variant's, which arrived from the server's product\n * payload — the same figure `checkout` prices the charge from, so the reported\n * value and the amount Stripe collects come from one source.\n */\nfunction buyItem(\n product: Detail,\n variant: DetailVariant | undefined,\n quantity: number,\n): AnalyticsItem {\n return {\n item_id: product.id,\n item_name: product.name,\n price: variant?.priceUsd ?? undefined,\n quantity,\n }\n}\n\n/** How one option is offered on the page. */\nexport interface OptionPresentation {\n name: string\n /** The values a shopper can actually get, in the option's own order. */\n values: string[]\n /**\n * `select` only when there is a real choice — two or more values that\n * variants carry; `text` for the one value every variant has (\"Scent:\n * Lavender\"); `hidden` for an option with no value at all.\n */\n mode: 'select' | 'text' | 'hidden'\n}\n\n/**\n * Which options are a CHOICE (AGL-3676 follow-up). A select with one entry —\n * or with entries no variant carries — is not a choice, and on a live store\n * it read as a broken control: an AI-built candle listed a \"Scent\" select\n * that offered nothing to pick. Decided from the variants, which are what is\n * sold: an option's values count only where a variant carries them, and only\n * when no variant names the option at all do its listed values stand in —\n * and then as a choice only when there are several variants to choose among.\n */\nexport function optionPresentation(\n options: readonly CommerceModel.ProductOption[],\n variants: ReadonlyArray<Pick<DetailVariant, 'options'>>,\n): OptionPresentation[] {\n return options.map((option) => {\n const listed = [\n ...new Set(\n (option.values ?? []).map((value) => String(value).trim()).filter(Boolean),\n ),\n ]\n const carried = new Set(\n variants\n .map((variant) => variant.options?.[option.name])\n .filter(\n (value): value is string => typeof value === 'string' && value.trim() !== '',\n ),\n )\n const values = carried.size\n ? [\n ...listed.filter((value) => carried.has(value)),\n ...[...carried].filter((value) => !listed.includes(value)),\n ]\n : variants.length > 1 || listed.length === 1\n ? listed\n : []\n return {\n name: option.name,\n values,\n mode: values.length >= 2 ? 'select' : values.length === 1 ? 'text' : 'hidden',\n }\n })\n}\n\n/** The selections a page opens on: the first variant on sale, else the first. */\nfunction initialSelections(\n product: Pick<Detail, 'variants'> | undefined,\n): Record<string, string> {\n const first =\n product?.variants.find((variant) => !variant.soldOut) ?? product?.variants[0]\n return { ...(first?.options ?? {}) }\n}\n\n/** What the Details panel lists: only facts the product record holds. */\nexport function productDetailFacts(\n product: Pick<Detail, 'type' | 'tags'>,\n variant: Pick<DetailVariant, 'sku'> | undefined,\n presented: readonly OptionPresentation[],\n): Array<{ label: string; value: string }> {\n const facts: Array<{ label: string; value: string }> = []\n if (product.type === 'digital') facts.push({ label: 'Format', value: 'Digital product' })\n if (product.type === 'service') facts.push({ label: 'Format', value: 'Service' })\n for (const option of presented) {\n if (option.mode !== 'hidden') {\n facts.push({ label: option.name, value: option.values.join(', ') })\n }\n }\n if (variant?.sku) facts.push({ label: 'SKU', value: variant.sku })\n if (product.tags?.length) facts.push({ label: 'Tags', value: product.tags.join(', ') })\n return facts\n}\n\n/**\n * What the Shipping & returns panel says, from the product's kind and the\n * store's own return settings — never a policy the store has not set.\n */\nexport function productShippingLines(\n product: Pick<Detail, 'type'>,\n returns: { windowDays: number } | undefined,\n): string[] {\n const lines: string[] = []\n if (product.type === 'digital') lines.push('Delivered digitally after purchase — nothing ships.')\n else if (product.type === 'service') lines.push('A service — nothing ships.')\n else lines.push('Shipping is calculated at checkout.')\n if (returns && returns.windowDays > 0) {\n lines.push(\n `Returns accepted within ${returns.windowDays} ` +\n `${returns.windowDays === 1 ? 'day' : 'days'} of shipping — ` +\n 'request one from your order status page.',\n )\n }\n return lines\n}\n\nfunction slugFromLocation(): string {\n if (typeof window === 'undefined') return ''\n const match = window.location.pathname.match(/\\/products\\/([^/?#]+)/)\n return match ? decodeURIComponent(match[1]) : ''\n}\n\n/**\n * Product detail block (AGL-292): gallery, option pickers that resolve\n * the variant (price/media/stock follow), quantity, and a buy button\n * that charges through the server-priced checkout with the selected\n * variant. Resolves its product from the /products/{slug} URL unless a\n * slug prop pins it; sample data on the inert canvas.\n */\nconst ProductDetail = forwardRef<HTMLDivElement, ProductDetailProps>(\n (props, ref) => {\n const {\n slug: slugProp,\n buyLabel,\n hideDescription,\n showCoupon,\n showDetails,\n showShipping,\n ...rest\n } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const site = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const { hostId } = site\n\n // The single-product (\"buy now\") path returns the shopper to this page\n // rather than to the cart, so the PDP is the second of the two surfaces\n // that has to be able to report `purchase` (AGL-1641). Both mount points\n // share one guard, so a page carrying a cart AND a PDP still sends one.\n useStorefrontPurchaseEvent(hostId, siteFetch)\n // Seeded from the server-resolved page data (AGL-659) so the PDP renders\n // its real content in the SSR HTML. Starting at null meant the server\n // emitted a <Skeleton> and the crawler got a product page with no\n // product in it. Absent in the besigner/preview, where the effect below\n // still fetches — so this is an optimisation, not a new requirement.\n const seededCommerce = (\n site.pageData as\n | { commerce?: { product?: Detail; returns?: { windowDays: number } } }\n | undefined\n )?.commerce\n const seededProduct = seededCommerce?.product\n // The store's return window, seeded with the built-in product page only\n // when the store takes returns of this product's kind.\n const seededReturns = seededCommerce?.returns\n const [detail, setDetail] = useState<Detail | null | 'missing'>(\n seededProduct ?? null,\n )\n // Opened on the first variant on sale. A seeded page skips the fetch that\n // used to set this, so it opened with nothing selected — an empty select.\n const [selections, setSelections] = useState<Record<string, string>>(() =>\n initialSelections(seededProduct),\n )\n const [quantity, setQuantity] = useState(1)\n /** A discount or coupon code typed on the product page. */\n const [coupon, setCoupon] = useState('')\n // A thumbnail the shopper picked; null follows the variant's own photo.\n const [activeImage, setActiveImage] = useState<number | null>(null)\n // `unconfigured` is not an `error` with softer words (AGL-2019). A store\n // with no Stripe key answers 501, and rendering that at `severity=\"error\"`\n // tells a shopper their payment failed when nothing was ever attempted —\n // the same distinction `ask` already makes, and the same one the cart's\n // 423 lockdown branch makes. It is the terminal one: it latches Buy off,\n // because every further click gets the identical refusal.\n const [status, setStatus] = useState<\n 'idle' | 'sending' | 'error' | 'ask' | 'unconfigured'\n >('idle')\n const [message, setMessage] = useState('')\n // Buy-now's half of AGL-1721: asked only when the server refuses to price\n // shipping without a destination, so a digital product, a subscription, or\n // a merchant whose rates are the same everywhere never shows it. `null` is\n // \"not asked\" — the field appearing is the server's answer, not a guess.\n const [shipTo, setShipTo] = useState('')\n const [shipCountries, setShipCountries] = useState<string[] | null>(null)\n // Live carrier rates price by postal code (AGL-3612): asked only when the\n // store prices that way and the server says so.\n const [shipPostal, setShipPostal] = useState('')\n const [askPostal, setAskPostal] = useState(false)\n const [added, setAdded] = useState(false)\n const [wishlisted, setWishlisted] = useState(false)\n const [notifyEmail, setNotifyEmail] = useState('')\n const [notifyState, setNotifyState] = useState<'idle' | 'done'>('idle')\n // Buyer-chosen billing (AGL-545): only meaningful when the product\n // is subscriptionOptional; defaults to a one-time purchase.\n const [billing, setBilling] = useState<CommerceModel.CheckoutBillingChoice>(\n 'once',\n )\n /**\n * The in-page checkout session (AGL-1944), null on every store until the\n * flag AND a publishable key say otherwise. A `clientSecret` is Stripe's\n * instruction to the browser; holding it says nothing about money having\n * moved, and nothing in this component ever claims it has.\n */\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n /** The wallets the merchant hid (AGL-3629). */\n wallets?: CommerceModel.StorefrontCheckoutWallets\n } | null>(null)\n\n const slug = slugProp || slugFromLocation()\n\n useEffect(() => {\n if (hostId && resolvedId) {\n setWishlisted(readLocalWishlist(hostId).includes(resolvedId))\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hostId, detail])\n\n useEffect(() => {\n if (!hostId || !slug) return\n // Already delivered with the page (AGL-659) — refetching the identical\n // payload on hydrate would just be a wasted round trip per visitor.\n if (seededProduct && seededProduct.slug === slug) return\n let active = true\n void fetch(\n `/api/commerce/product?hostId=${encodeURIComponent(hostId)}` +\n `&slug=${encodeURIComponent(slug)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .then((payload) => {\n if (!active) return\n const product = payload?.product as Detail | undefined\n setDetail(product ?? 'missing')\n if (product) {\n // GA4 ecommerce mirror (AGL-327), through the shared taxonomy\n // since AGL-1591 rather than raw gtag — same consent gate, same\n // sanitizer, and the name is now checked by the compiler.\n trackEvent('view_item', {\n items: [{ item_id: product.id, item_name: product.name }],\n })\n setSelections(initialSelections(product))\n }\n })\n .catch(() => {\n if (active) setDetail('missing')\n })\n return () => {\n active = false\n }\n }, [hostId, slug])\n\n const resolvedId =\n hostId && detail && detail !== 'missing' ? detail.id : null\n const resolved: Detail | null = hostId\n ? detail === 'missing'\n ? null\n : detail\n : SAMPLE\n\n const variant = useMemo(() => {\n if (!resolved) return undefined\n return (\n CommerceModel.findVariant(\n { variants: resolved.variants as any },\n selections,\n ) as DetailVariant | undefined\n ) ?? resolved.variants[0]\n }, [resolved, selections])\n\n // Add to cart (AGL-293) beside instant buy; badge refresh via event.\n const handleAddToCart = async () => {\n if (!hostId || !resolved || !variant) return\n setAdded(false)\n // Priced (AGL-1591's shape, completed): the resolved variant's price\n // and the chosen quantity both come from the server's product payload,\n // so GA4's \"value added to cart\" is a real number. The funnel step\n // (AGL-3605) and the badge refresh ride the same shared helper the\n // product grid's quick add uses.\n const ok = await addToCart({\n hostId,\n siteFetch,\n productId: resolved.id,\n variantId: variant.id,\n quantity,\n item: buyItem(resolved, variant, quantity),\n })\n if (ok) setAdded(true)\n }\n\n /**\n * Idempotency key for ONE buy-now attempt (AGL-1697).\n *\n * Minted lazily on the first buy click, retired whenever the purchase\n * changes shape — a different product, variant, quantity, billing choice\n * or destination is a different attempt. A retry of THIS attempt presents\n * the same key, so the server replays the original session instead of\n * opening a second one (for a subscription product, a second RECURRING\n * subscription).\n */\n // Pickup or the store's own delivery (AGL-3624), for a one-time sale; the\n // server offers nothing for a product with nothing physical to collect.\n const fulfillment = useCartFulfillment(\n hostId,\n resolved?.id ?? '[]',\n resolved &&\n variant &&\n !(resolved.subscription && (!resolved.subscriptionOptional || billing === 'subscribe'))\n ? { productId: resolved.id, variantId: variant.id, quantity }\n : null,\n )\n const attemptKey = useRef('')\n useEffect(() => {\n attemptKey.current = ''\n // `coupon` is in here because it CHANGES THE PRICE. Without it a shopper\n // who buys, comes back, types a code and buys again presents the same\n // key, and the server replays the original full-price session — a quoted\n // number that is not the number charged, which is the whole defect class\n // this path has been cleared of.\n }, [resolved?.id, variant?.id, quantity, billing, shipTo, shipPostal, coupon, fulfillment.signature])\n\n const handleBuy = async () => {\n if (!hostId || !resolved || !variant || status === 'sending') return\n setStatus('sending')\n setMessage('')\n if (!attemptKey.current) {\n attemptKey.current =\n globalThis.crypto?.randomUUID?.() ??\n `${Date.now()}-${Math.random().toString(36).slice(2)}`\n }\n try {\n const response = await siteFetch('/api/commerce/checkout', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Idempotency-Key': attemptKey.current,\n },\n body: JSON.stringify({\n hostId,\n productId: resolved.id,\n variantId: variant.id,\n quantity,\n // Billing choice (AGL-545): the server re-validates against\n // the product doc, so this is a request, not an instruction.\n ...(resolved.subscriptionOptional ? { billing } : {}),\n // Likewise a request (AGL-1721): the server resolves this\n // country's rates AND restricts the session to addresses in it,\n // so naming a cheap zone here cannot ship a parcel anywhere else.\n ...(shipTo && !fulfillment.request ? { shippingCountry: shipTo } : {}),\n ...(shipPostal.trim() && !fulfillment.request ? { shippingPostalCode: shipPostal.trim() } : {}),\n // Where and when, never the fee (AGL-3624).\n ...(fulfillment.request ? { fulfillment: fulfillment.request } : {}),\n // The server resolves this against the discounts hub first and the\n // legacy coupons second, and refuses a code it cannot apply with a\n // reason — never a silent full-price charge.\n ...(coupon.trim() ? { couponCode: coupon.trim() } : {}),\n // The visitor's advertising consent and the vendors' browser ids, only\n // where that consent grants advertising (AGL-3694); absent otherwise.\n ...advertisingConsentField(hostId),\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // In-page payment (AGL-1944). A native session returns a client secret\n // and NO url — the two are mutually exclusive by construction, so the\n // redirect branch below is unreachable in native mode and vice versa.\n // Checked FIRST so a server that somehow sent both cannot silently\n // navigate the shopper away from the form we just decided to show.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n // Buy-now's `begin_checkout`. The cart path has reported this since\n // AGL-1591 and this one never did, so a storefront whose shoppers\n // skip the cart showed `view_item` → `add_to_cart` → nothing →\n // `purchase`: GA4's shopping funnel put every single-product sale in\n // the \"abandoned checkout\" bucket, and the merchant's checkout rate\n // read as a collapse rather than as an unmeasured path.\n //\n // Reported on BOTH branches, and from the same place, for the reason\n // the cart states: a count that halved the day the in-page payment\n // flag flipped would look like a conversion collapse.\n trackEvent(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [buyItem(resolved, variant, quantity)],\n }),\n )\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: CommerceModel.readStorefrontCheckoutWallets(payload.wallets),\n })\n setStatus('idle')\n return\n }\n if (response.ok && payload?.url) {\n // Awaited before the redirect (AGL-1580), for the reason spelled out\n // on the cart's matching branch: delivery here is a synchronous\n // `window.gtag` call today and the await costs nothing, but the\n // property that makes a bare call safe is invisible from this file.\n await trackEventBeforeNavigation(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [buyItem(resolved, variant, quantity)],\n }),\n )\n window.location.assign(payload.url)\n return\n }\n // Buy-now's half of AGL-2019. The server's own 501 wording is not\n // rendered to a visitor; this surface is public.\n if (payload?.fulfillmentChanged) {\n fulfillment.reload()\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n return\n }\n if (isPaymentsNotConfigured(response.status)) {\n setMessage(storefrontPaymentsNotConfiguredText())\n setStatus('unconfigured')\n return\n }\n if (payload?.needsShippingCountry) {\n if (payload?.needsShippingPostalCode) setAskPostal(true)\n setShipCountries(\n (payload.shippingCountries as string[] | undefined)?.length\n ? (payload.shippingCountries as string[])\n : [...CommerceModel.CHECKOUT_SHIPPING_COUNTRIES],\n )\n setMessage(String(payload?.error ?? ''))\n // An unserved destination is a refusal and reads as one; being\n // asked the first time is not.\n setStatus(shipTo ? 'error' : 'ask')\n return\n }\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n } catch {\n setStatus('error')\n }\n }\n\n if (hostId && detail === null) {\n return (\n <Box ref={ref} {...rest} sx={[{ display: 'flex', gap: 3 }, ...nodeSx]}>\n <Skeleton variant=\"rectangular\" width={320} height={320} />\n <Box sx={{ flex: 1 }}>\n <Skeleton width=\"60%\" height={36} />\n <Skeleton width=\"25%\" />\n <Skeleton width=\"90%\" />\n </Box>\n </Box>\n )\n }\n if (!resolved) {\n return (\n <Box ref={ref} {...rest} sx={[{ p: 3 }, ...nodeSx]}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Product not found.'}\n </Typography>\n </Box>\n )\n }\n\n // Every rendered `<img src>` on this page goes through\n // `siteRelativeMediaSrc` (AGL-1726). Commerce called NO resolver at all,\n // which cost it two things at once: a `media:` reference — writable via\n // the resources API and the CSV importer — would have reached an `<img>`\n // as the literal string, and a stored absolute\n // `https://{subdomain}.aglyn.app/api/media/cdn/…` stayed absolute, so a\n // white-label storefront on the customer's own domain served product\n // photos naming OUR platform, cross-origin, in page source and in every\n // visitor's request. Production carried exactly one such document; the\n // resolver fixes it at READ time, so no backfill stands between the\n // defect and the fix.\n //\n // Deliberately NOT applied to `resolved.mediaUrls` wholesale: the\n // schema.org `image` array below is read out of band by a crawler, where\n // an absolute URL is the point. That one wants `absoluteMediaSrc` with\n // the site's own origin, which is the tenant page's job (AGL-1725).\n const galleryImage = Aglyn.siteRelativeMediaSrc(\n (activeImage !== null ? resolved.mediaUrls[activeImage] : undefined) ??\n variant?.imageUrl ??\n resolved.mediaUrls[0],\n { hostId },\n )\n const presentedOptions = optionPresentation(resolved.options, resolved.variants)\n const detailFacts = showDetails\n ? productDetailFacts(resolved, variant, presentedOptions)\n : []\n const shippingLines = showShipping\n ? productShippingLines(\n resolved,\n seededProduct?.id === resolved.id ? seededReturns : undefined,\n )\n : []\n\n // Subscription framing (AGL-545): subscription-only products price as\n // $X/mo|/yr with a \"Subscribe\" button; subscriptionOptional products\n // surface the one-time/subscribe toggle instead. Same price either way\n // — the server re-prices from the product doc regardless.\n const subscription = resolved.subscription\n const intervalSuffix = subscription?.interval === 'year' ? '/yr' : '/mo'\n const subscribing =\n Boolean(subscription) &&\n (!resolved.subscriptionOptional || billing === 'subscribe')\n // Listed before it has a price (AGL-3676): no price to show and nothing\n // to buy; every sale door would refuse it anyway.\n const priced = typeof variant?.priceUsd === 'number'\n\n // schema.org Product/Offer (AGL-299). Kept ONLY for the case where this\n // block renders without server-seeded page data — the besigner preview,\n // or a page whose resolver didn't supply it. When the tenant page seeds\n // us it emits the same Product node server-side (AGL-660), and two\n // Product nodes for one item is worse than one, so we stand down.\n const structuredData =\n hostId && resolvedId && !seededProduct\n ? {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: resolved.name,\n ...(resolved.description\n ? { description: resolved.description }\n : {}),\n ...(resolved.mediaUrls.length\n ? { image: resolved.mediaUrls }\n : {}),\n // No offer without a price: a price of 0 would read as free.\n ...(priced\n ? {\n offers: {\n '@type': 'Offer',\n priceCurrency: 'USD',\n price: String(variant?.priceUsd),\n availability: variant?.soldOut\n ? 'https://schema.org/OutOfStock'\n : 'https://schema.org/InStock',\n },\n }\n : {}),\n }\n : null\n\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n display: 'flex',\n gap: 3,\n flexDirection: { xs: 'column', md: 'row' },\n },\n ...nodeSx,\n ]}\n >\n <CheckoutReturnNotice hostId={hostId} siteFetch={siteFetch} />\n <Box sx={{ flex: 1, minWidth: 0 }}>\n {galleryImage ? (\n <Box\n component=\"img\"\n src={galleryImage}\n alt={resolved.name}\n // DELIBERATELY NOT DEFERRED (AGL-2486). This is the gallery\n // hero at the top of a product page — the one image on this\n // surface that really is the LCP candidate, and the browser\n // default here is already `eager`. Spreading\n // `DEFERRED_IMAGE_ATTRIBUTES` over it to \"finish the job\" is\n // the obvious next edit and it re-introduces the bug this\n // issue opened with: an LCP image not discovered until after\n // layout has run. The thumbnail strip below it IS deferred.\n //\n // No `fetchpriority` either, for the reason written out at\n // `image.tsx`: `high` is a claim about every other request in\n // flight, and a page whose real LCP is the product NAME would\n // pay for that claim.\n sx={{\n width: '100%',\n aspectRatio: '1 / 1',\n objectFit: 'cover',\n borderRadius: 1,\n }}\n />\n ) : (\n <Box\n sx={{\n width: '100%',\n aspectRatio: '1 / 1',\n bgcolor: 'action.hover',\n borderRadius: 1,\n }}\n />\n )}\n {resolved.mediaUrls.length > 1 ? (\n <Box sx={{ display: 'flex', gap: 1, mt: 1, flexWrap: 'wrap' }}>\n {resolved.mediaUrls.map((url, index) => (\n <Box\n key={`${url}-${index}`}\n component=\"img\"\n // Same resolver as the hero (AGL-1726) — a thumbnail is an\n // `<img>` on the customer's page and leaks exactly as much.\n src={Aglyn.siteRelativeMediaSrc(url, { hostId })}\n alt=\"\"\n onClick={() => setActiveImage(index)}\n sx={{\n width: 64,\n height: 64,\n objectFit: 'cover',\n borderRadius: 1,\n cursor: 'pointer',\n border: 2,\n borderColor:\n index === (activeImage ?? 0) ? 'primary.main' : 'transparent',\n }}\n // Deferred (AGL-2486): 56px thumbnails that exist to swap\n // the hero above. They were fetching eagerly ALONGSIDE\n // that hero, so a five-image gallery had the hero\n // competing with four thumbnails nobody had asked for yet.\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n ))}\n </Box>\n ) : null}\n </Box>\n {structuredData ? (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: Aglyn.safeJsonLd(structuredData) }}\n />\n ) : null}\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"h4\" component=\"h1\" gutterBottom>\n {resolved.name}\n </Typography>\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 2 }}>\n <Typography variant=\"h6\">\n {priced\n ? `$${variant?.priceUsd}${subscribing ? intervalSuffix : ''}`\n : PRICE_COMING_SOON_LABEL}\n </Typography>\n {subscribing && subscription?.trialDays ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${subscription.trialDays}-day free trial`}\n </Typography>\n ) : null}\n {variant?.compareAtPriceUsd ? (\n <>\n <Typography\n variant=\"body1\"\n color=\"text.disabled\"\n sx={{ textDecoration: 'line-through' }}\n >\n {`$${variant.compareAtPriceUsd}`}\n </Typography>\n <Chip label=\"Sale\" size=\"small\" color=\"primary\" />\n </>\n ) : null}\n {variant?.soldOut ? (\n <Chip label=\"Sold out\" size=\"small\" variant=\"outlined\" />\n ) : null}\n <Button\n size=\"small\"\n onClick={async () => {\n if (hostId && resolved.id !== 'sample') {\n setWishlisted(await toggleWishlist(hostId, resolved.id, siteFetch))\n }\n }}\n >\n {wishlisted ? '♥ Saved' : '♡ Save'}\n </Button>\n </Box>\n {subscription && resolved.subscriptionOptional ? (\n <ToggleButtonGroup\n value={billing}\n exclusive\n size=\"small\"\n onChange={(_event, value) => {\n if (value === 'once' || value === 'subscribe') {\n setBilling(value)\n }\n }}\n sx={{ mb: 2 }}\n >\n <ToggleButton value=\"once\">\n {priced ? `One-time $${variant?.priceUsd}` : 'One-time'}\n </ToggleButton>\n <ToggleButton value=\"subscribe\">\n {priced ? `Subscribe $${variant?.priceUsd}${intervalSuffix}` : 'Subscribe'}\n </ToggleButton>\n </ToggleButtonGroup>\n ) : null}\n {presentedOptions.map((option) =>\n option.mode === 'hidden' ? null : option.mode === 'text' ? (\n <Typography\n key={option.name}\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ mb: 1.5 }}\n >\n {`${option.name}: ${option.values[0]}`}\n </Typography>\n ) : (\n <TextField\n key={option.name}\n label={option.name}\n value={\n option.values.includes(selections[option.name] ?? '')\n ? selections[option.name]\n : ''\n }\n onChange={(event) => {\n // A new variant shows its own photo, not the last thumbnail.\n setActiveImage(null)\n setSelections((prev) => ({\n ...prev,\n [option.name]: event.target.value,\n }))\n }}\n size=\"small\"\n select\n fullWidth\n sx={{ mb: 1.5 }}\n >\n {option.values.map((value) => (\n <MenuItem key={value} value={value}>\n {value}\n </MenuItem>\n ))}\n </TextField>\n ),\n )}\n {showCoupon ? (\n <TextField\n label=\"Discount code\"\n value={coupon}\n onChange={(event) => setCoupon(event.target.value)}\n size=\"small\"\n sx={{ mb: 2, display: 'block' }}\n />\n ) : null}\n {!priced ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 2 }}>\n {'Not on sale yet — check back soon.'}\n </Typography>\n ) : null}\n <Box sx={{ display: priced ? 'flex' : 'none', gap: 1.5, alignItems: 'center', mb: 2 }}>\n <TextField\n label=\"Qty\"\n value={quantity}\n onChange={(event) =>\n setQuantity(\n Math.max(\n 1,\n Math.min(99, Math.round(Number(event.target.value)) || 1),\n ),\n )\n }\n size=\"small\"\n sx={{ width: 80 }}\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <Button\n variant=\"outlined\"\n color=\"primary\"\n size=\"large\"\n disabled={!hostId || !priced || variant?.soldOut}\n onClick={handleAddToCart}\n >\n {added ? 'Added ✓' : 'Add to cart'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"large\"\n disabled={\n !hostId ||\n !priced ||\n status === 'sending' ||\n variant?.soldOut ||\n // No payments on this deployment: the same 501 every time, so\n // the control latches off rather than inviting a retry that\n // cannot succeed (AGL-2019).\n status === 'unconfigured' ||\n // Asked but unanswered: the server would only refuse again.\n (fulfillment.method === 'shipping' && shipCountries !== null && !shipTo) ||\n (fulfillment.method === 'shipping' && askPostal && !shipPostal.trim()) ||\n !fulfillment.ready\n }\n onClick={handleBuy}\n sx={{ flex: 1 }}\n >\n {variant?.soldOut\n ? 'Sold out'\n : status === 'sending'\n ? // \"Redirecting\" is a lie once the form opens in place, and\n // it is the shopper's only clue about what is about to\n // happen to their page (AGL-1944).\n nativeCheckout\n ? 'Opening…'\n : 'Redirecting…'\n : buyLabel || (subscribing ? 'Subscribe' : 'Buy now')}\n </Button>\n </Box>\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={buyLabel || (subscribing ? 'Subscribe' : 'Pay now')}\n // An expired or unloadable session is replaced, never\n // replayed: the old attempt key would hand back the dead one.\n onRestart={() => {\n attemptKey.current = ''\n setNativeCheckout(null)\n void handleBuy()\n }}\n // Cancelling drops the form and leaves the session open —\n // deliberately. The shopper may come back to the same\n // attempt key, and an abandoned session is what the AGL-323\n // recovery emails are built on. Nothing is expired from the\n // browser: that is a write against the merchant's account.\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : null}\n {fulfillment.offered && priced ? (\n <Box sx={{ mb: 2 }}>\n <CartFulfillmentChoice\n state={fulfillment}\n formatCents={(cents) => `$${(cents / 100).toFixed(2)}`}\n />\n </Box>\n ) : null}\n {shipCountries && fulfillment.method === 'shipping' && priced ? (\n <TextField\n select\n label=\"Ship to\"\n value={shipTo}\n onChange={(event) => setShipTo(event.target.value)}\n size=\"small\"\n fullWidth\n helperText=\"Shipping rates depend on where this is going\"\n sx={{ mb: 2 }}\n >\n {shipCountries.map((code) => (\n <MenuItem key={code} value={code}>\n {CommerceModel.CHECKOUT_SHIPPING_COUNTRY_NAMES[code] ?? code}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {askPostal && fulfillment.method === 'shipping' && priced ? (\n <TextField\n label=\"Postal code\"\n value={shipPostal}\n onChange={(event) => setShipPostal(event.target.value)}\n size=\"small\"\n fullWidth\n helperText=\"Carrier rates depend on the postal code\"\n slotProps={{ htmlInput: { autoComplete: 'shipping postal-code', maxLength: 12 } }}\n sx={{ mb: 2 }}\n />\n ) : null}\n {status === 'ask' || status === 'unconfigured' ? (\n <Alert severity=\"info\" sx={{ mb: 2 }}>\n {message}\n </Alert>\n ) : null}\n {status === 'error' ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {message || 'Checkout is unavailable right now.'}\n </Alert>\n ) : null}\n {variant?.soldOut && hostId ? (\n notifyState === 'done' ? (\n <Alert severity=\"success\" sx={{ mb: 2 }}>\n {'We will email you when it is back.'}\n </Alert>\n ) : (\n <Box sx={{ display: 'flex', gap: 1, mb: 2 }}>\n <TextField\n placeholder=\"you@example.com\"\n type=\"email\"\n // Third instance of the nameless-input defect (AGL-2392).\n // Named for its job rather than \"Email address\": this row\n // appears inside a product page that may also carry the\n // newsletter block, and two fields both announced as\n // \"Email address\" is barely better than none.\n slotProps={{\n htmlInput: {\n 'aria-label': 'Email address for back-in-stock alert',\n },\n }}\n value={notifyEmail}\n onChange={(event) => setNotifyEmail(event.target.value)}\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <Button\n size=\"small\"\n variant=\"outlined\"\n disabled={!notifyEmail.trim()}\n onClick={async () => {\n const response = await siteFetch(\n '/api/commerce/notify-restock',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n productId: resolved.id,\n email: notifyEmail,\n }),\n },\n ).catch(() => null)\n if (response?.ok) setNotifyState('done')\n }}\n >\n {'Notify me'}\n </Button>\n </Box>\n )\n ) : null}\n {!hideDescription && resolved.description ? (\n <Typography\n variant=\"body1\"\n color=\"text.secondary\"\n sx={{ whiteSpace: 'pre-line' }}\n >\n {resolved.description}\n </Typography>\n ) : null}\n {detailFacts.length || shippingLines.length ? (\n <Box sx={{ mt: 3 }}>\n {detailFacts.length ? (\n <ProductDetailPanel title=\"Details\">\n <Box\n component=\"dl\"\n sx={{\n m: 0,\n display: 'grid',\n gridTemplateColumns: 'auto 1fr',\n columnGap: 2,\n rowGap: 0.75,\n }}\n >\n {detailFacts.map((fact) => (\n <Box key={fact.label} sx={{ display: 'contents' }}>\n <Typography component=\"dt\" variant=\"body2\" sx={{ fontWeight: 600 }}>\n {fact.label}\n </Typography>\n <Typography\n component=\"dd\"\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ m: 0 }}\n >\n {fact.value}\n </Typography>\n </Box>\n ))}\n </Box>\n </ProductDetailPanel>\n ) : null}\n {shippingLines.length ? (\n <ProductDetailPanel title=\"Shipping & returns\">\n {shippingLines.map((line) => (\n <Typography\n key={line}\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ mb: 0.75 }}\n >\n {line}\n </Typography>\n ))}\n </ProductDetailPanel>\n ) : null}\n </Box>\n ) : null}\n </Box>\n </Box>\n )\n },\n)\nProductDetail.displayName = 'AglynProductDetail'\n\n/**\n * One fold of the panels under the buy box: a flat, divided accordion in the\n * theme's own colours — the way a designer storefront stacks Details and\n * Shipping under the description.\n */\nfunction ProductDetailPanel({\n title,\n children,\n}: {\n title: string\n children: ReactNode\n}) {\n return (\n <Accordion\n disableGutters\n elevation={0}\n square\n sx={{\n bgcolor: 'transparent',\n borderTop: 1,\n borderColor: 'divider',\n '&:last-of-type': { borderBottom: 1, borderColor: 'divider' },\n '&::before': { display: 'none' },\n }}\n >\n <AccordionSummary\n expandIcon={\n <SvgIcon fontSize=\"small\">\n <path d={mdiChevronDown.path} />\n </SvgIcon>\n }\n sx={{ px: 0 }}\n >\n <Typography variant=\"subtitle1\" component=\"h2\">\n {title}\n </Typography>\n </AccordionSummary>\n <AccordionDetails sx={{ px: 0, pt: 0, pb: 2 }}>{children}</AccordionDetails>\n </Accordion>\n )\n}\n\nexport const schema: Aglyn.ComponentSchema<ProductDetailProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product detail',\n description: \"One product's gallery, options and buy button.\",\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'slug',\n label: 'Product slug',\n description:\n 'Pin to one product; blank follows the /products/{slug} URL ' +\n '(product page template).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'buyLabel',\n label: 'Buy button label',\n description: 'Defaults to \"Buy now\".',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'hideDescription',\n label: 'Hide description',\n description: 'Design the description separately with tokens.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n // Off by default, so no existing page changes shape on deploy. The cart\n // has carried this field all along and the product page had none, so a\n // shopper buying the same goods through Buy now had nowhere to enter a\n // code the merchant had advertised.\n name: 'showCoupon',\n label: 'Show discount code field',\n description: 'Lets a buyer enter a discount or coupon code before buying.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n // Off by default, so no existing page changes shape on deploy.\n name: 'showDetails',\n label: 'Show details panel',\n description:\n 'A Details fold under the description with the facts the product ' +\n 'holds: its options, SKU, tags, and whether it is digital or a service.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showShipping',\n label: 'Show shipping & returns panel',\n description:\n 'A Shipping & returns fold: shipping priced at checkout (or digital ' +\n 'delivery), and your return window when your store takes returns.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product detail',\n pluginId: BUNDLE_ID,\n description: 'Gallery, variant picker, and buy button for one product',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n {\n // Product page (AGL-561): the commerce-standard PDP subtree —\n // breadcrumb, detail, related products, reviews — for the product\n // page template screen. `{{product.name}}` resolves there via the\n // site page resolver's token pass (AGL-292); node shapes follow\n // the Sections & Blocks convention (AGL-539) and reference only\n // persisted component ids.\n $id: generatePresetId(ID, 'page'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product page',\n pluginId: BUNDLE_ID,\n description:\n 'Breadcrumb, product detail, related products, and reviews',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { spacing: 4 },\n // Styling on the node's own sx, never in props (AGL-1346): both\n // records render, but only `node.sx` is the one the Styles panel can\n // read, edit or clear.\n sx: { paddingTop: 2, paddingBottom: 2 },\n nodes: [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { direction: 'row', spacing: 1 },\n sx: { alignItems: 'center' },\n nodes: [\n {\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { children: 'Shop', size: 'small', color: 'inherit' },\n },\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { variant: 'body2', children: '/ {{product.name}}' },\n },\n ],\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n {\n $id: null,\n componentId: RELATED_PRODUCTS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n {\n $id: null,\n componentId: PRODUCT_REVIEWS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n ],\n },\n },\n]\n\nexport default ProductDetail\n"],"names":["advertisingConsentField","Aglyn","buildBeginCheckoutParams","trackEvent","trackEventBeforeNavigation","isPaymentsNotConfigured","storefrontPaymentsNotConfiguredText","CommerceModel","mdiChevronDown","mdiTagOutline","Accordion","AccordionDetails","AccordionSummary","Alert","Box","Button","Chip","MenuItem","Skeleton","SvgIcon","TextField","ToggleButton","ToggleButtonGroup","Typography","Suspense","forwardRef","lazy","useEffect","useMemo","useRef","useState","BUNDLE_ID","generatePresetId","useStorefrontPurchaseEvent","addToCart","CartFulfillmentChoice","useCartFulfillment","ID","PRODUCT_REVIEWS_ID","RELATED_PRODUCTS_ID","readLocalWishlist","toggleWishlist","StorefrontPaymentElementFallback","CheckoutReturnNotice","StorefrontPaymentElement","then","module","default","PRICE_COMING_SOON_LABEL","SAMPLE","id","name","slug","description","mediaUrls","options","values","variants","Size","priceUsd","soldOut","buyItem","product","variant","quantity","item_id","item_name","price","undefined","optionPresentation","map","option","listed","Set","value","String","trim","filter","Boolean","carried","size","has","includes","length","mode","initialSelections","first","find","productDetailFacts","presented","facts","type","push","label","join","sku","tags","productShippingLines","returns","lines","windowDays","slugFromLocation","window","match","location","pathname","decodeURIComponent","ProductDetail","props","ref","activeImage","site","slugProp","buyLabel","hideDescription","showCoupon","showDetails","showShipping","rest","nodeSx","Array","isArray","useSite","siteFetch","useSiteFetch","hostId","seededCommerce","pageData","commerce","seededProduct","seededReturns","detail","setDetail","selections","setSelections","setQuantity","coupon","setCoupon","setActiveImage","status","setStatus","message","setMessage","shipTo","setShipTo","shipCountries","setShipCountries","shipPostal","setShipPostal","askPostal","setAskPostal","added","setAdded","wishlisted","setWishlisted","notifyEmail","setNotifyEmail","notifyState","setNotifyState","billing","setBilling","nativeCheckout","setNativeCheckout","resolvedId","active","fetch","encodeURIComponent","response","ok","json","payload","items","catch","resolved","findVariant","handleAddToCart","productId","variantId","item","fulfillment","subscription","subscriptionOptional","attemptKey","current","signature","handleBuy","globalThis","crypto","randomUUID","Date","now","Math","random","toString","slice","method","headers","body","JSON","stringify","request","shippingCountry","shippingPostalCode","couponCode","clientSecret","publishableKey","wallets","readStorefrontCheckoutWallets","url","assign","fulfillmentChanged","reload","error","needsShippingCountry","needsShippingPostalCode","shippingCountries","CHECKOUT_SHIPPING_COUNTRIES","sx","display","gap","width","height","flex","p","color","galleryImage","siteRelativeMediaSrc","imageUrl","presentedOptions","detailFacts","shippingLines","intervalSuffix","interval","subscribing","priced","structuredData","image","offers","priceCurrency","availability","flexDirection","xs","md","minWidth","component","src","alt","aspectRatio","objectFit","borderRadius","bgcolor","mt","flexWrap","index","onClick","cursor","border","borderColor","DEFERRED_IMAGE_ATTRIBUTES","script","dangerouslySetInnerHTML","__html","safeJsonLd","gutterBottom","alignItems","mb","trialDays","compareAtPriceUsd","textDecoration","exclusive","onChange","_event","event","prev","target","select","fullWidth","max","min","round","Number","slotProps","htmlInput","inputMode","disabled","ready","fallback","payLabel","onRestart","onCancel","offered","state","formatCents","cents","toFixed","helperText","code","CHECKOUT_SHIPPING_COUNTRY_NAMES","autoComplete","maxLength","severity","placeholder","email","whiteSpace","ProductDetailPanel","title","m","gridTemplateColumns","columnGap","rowGap","fact","fontWeight","line","displayName","children","disableGutters","elevation","square","borderTop","borderBottom","expandIcon","fontSize","path","d","px","pt","pb","schema","$id","pluginId","category","ComponentCategory","COMMERCE","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","CHECKBOX","presets","NodeType","PRESET","data","componentId","MUI_BUNDLE_ID","spacing","paddingTop","paddingBottom","nodes","direction"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/product-detail.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { advertisingConsentField } from '@aglyn/aglyn/app-utils/advertising-consent'\nimport * as Aglyn from '@aglyn/aglyn'\nimport {\n buildBeginCheckoutParams,\n trackEvent,\n trackEventBeforeNavigation,\n type AnalyticsItem,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport { isPaymentsNotConfigured } from '@aglyn/aglyn/app-utils/payments-configured'\nimport { storefrontPaymentsNotConfiguredText } from '../constants/storefront-payments'\nimport * as CommerceModel from '../model'\nimport { mdiChevronDown, mdiTagOutline } from '@aglyn/shared-data-mdi'\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport MenuItem from '@mui/material/MenuItem'\nimport Skeleton from '@mui/material/Skeleton'\nimport SvgIcon from '@mui/material/SvgIcon'\nimport TextField from '@mui/material/TextField'\nimport ToggleButton from '@mui/material/ToggleButton'\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup'\nimport Typography from '@mui/material/Typography'\nimport {\n Suspense,\n forwardRef,\n lazy,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport { useStorefrontPurchaseEvent } from '../utils/use-storefront-purchase-event'\nimport { addToCart } from '../utils/add-to-cart'\nimport { CartFulfillmentChoice, useCartFulfillment } from './cart-fulfillment'\nimport { ID as PRODUCT_REVIEWS_ID } from './product-reviews'\nimport { ID as RELATED_PRODUCTS_ID } from './related-products'\nimport { readLocalWishlist, toggleWishlist } from './wishlist'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\nimport { CheckoutReturnNotice } from './checkout-return-notice'\nimport { zonedDayKey } from '@aglyn/shared-util-timestamp/zoned-time'\n\n/**\n * The Payment Element (AGL-1944), behind a lazy boundary rather than a plain\n * import. Stripe.js and its React wrapper are a large dependency, the flag is\n * OFF, and a static import would put the whole SDK into the bundle of every\n * product page on every published site to serve a code path no shopper reaches.\n * Split, it is fetched by the shoppers who actually get the in-page form.\n */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'product-detail'\n\nexport interface ProductDetailProps {\n /** Product slug; blank resolves from /products/{slug} in the URL. */\n slug?: string\n buyLabel?: string\n /** Hide the description block (design it separately with tokens). */\n hideDescription?: boolean\n /** Offer a discount/coupon code field before the buy button. */\n showCoupon?: boolean\n /**\n * A \"Details\" panel under the description: the facts the product record\n * holds — its kind (digital, service), the choices it comes in, the\n * selected variant's SKU, its tags. Never a fact the record does not hold.\n * Off by default, so a page that already places this block keeps its shape.\n */\n showDetails?: boolean\n /**\n * A \"Shipping & returns\" panel: how it is delivered (shipping priced at\n * checkout, or delivered digitally), and the store's own return window\n * when the store takes returns of this kind of product. Off by default.\n */\n showShipping?: boolean\n}\n\ninterface DetailVariant {\n id: string\n options?: Record<string, string>\n /** `null` while the product is listed before it has a price (AGL-3676). */\n priceUsd: number | null\n compareAtPriceUsd?: number\n soldOut: boolean\n imageUrl?: string\n sku?: string\n /** The buyer may choose the day they will use it (AGL-4043). */\n asksUseDate?: true\n}\n\n/** What the page says where a variant with no price yet would show one (AGL-3676). */\nconst PRICE_COMING_SOON_LABEL = 'Price coming soon'\n\ninterface Detail {\n id: string\n name: string\n slug: string\n description?: string\n type?: CommerceModel.ProductType\n tags?: string[]\n mediaUrls: string[]\n options: CommerceModel.ProductOption[]\n variants: DetailVariant[]\n /** Recurring billing (AGL-303); framing + buyer choice on the PDP. */\n subscription?: { interval: 'month' | 'year'; trialDays?: number }\n /** Buyer picks one-time or subscribe at the same price (AGL-545). */\n subscriptionOptional?: boolean\n /** The store's time zone, when a variant asks for a use day (AGL-4043). */\n useDayTimeZone?: string\n}\n\n/**\n * The use-day picker (AGL-4043), in its own chunk: only a product whose\n * variant asks for a day downloads the date picker.\n */\nconst UseDayPicker = lazy(() => import('./use-day-picker'))\n\nconst SAMPLE: Detail = {\n id: 'sample',\n name: 'Sample product',\n slug: '#',\n description: 'Drop this block on your product page template.',\n mediaUrls: [],\n options: [{ name: 'Size', values: ['S', 'M', 'L'] }],\n variants: [\n { id: 'a', options: { Size: 'S' }, priceUsd: 29, soldOut: false },\n { id: 'b', options: { Size: 'M' }, priceUsd: 29, soldOut: false },\n { id: 'c', options: { Size: 'L' }, priceUsd: 32, soldOut: true },\n ],\n}\n\n/**\n * The GA4 `items` entry for one line of this product.\n *\n * `item_id` is the PRODUCT id and never the variant's, matching the\n * `view_item` above and the cart's lines below: GA joins the funnel on that\n * id, and a `begin_checkout` keyed on a variant would report a product nothing\n * else on the storefront had ever mentioned.\n *\n * `price` is the resolved variant's, which arrived from the server's product\n * payload — the same figure `checkout` prices the charge from, so the reported\n * value and the amount Stripe collects come from one source.\n */\nfunction buyItem(\n product: Detail,\n variant: DetailVariant | undefined,\n quantity: number,\n): AnalyticsItem {\n return {\n item_id: product.id,\n item_name: product.name,\n price: variant?.priceUsd ?? undefined,\n quantity,\n }\n}\n\n/** How one option is offered on the page. */\nexport interface OptionPresentation {\n name: string\n /** The values a shopper can actually get, in the option's own order. */\n values: string[]\n /**\n * `select` only when there is a real choice — two or more values that\n * variants carry; `text` for the one value every variant has (\"Scent:\n * Lavender\"); `hidden` for an option with no value at all.\n */\n mode: 'select' | 'text' | 'hidden'\n}\n\n/**\n * Which options are a CHOICE (AGL-3676 follow-up). A select with one entry —\n * or with entries no variant carries — is not a choice, and on a live store\n * it read as a broken control: an AI-built candle listed a \"Scent\" select\n * that offered nothing to pick. Decided from the variants, which are what is\n * sold: an option's values count only where a variant carries them, and only\n * when no variant names the option at all do its listed values stand in —\n * and then as a choice only when there are several variants to choose among.\n */\nexport function optionPresentation(\n options: readonly CommerceModel.ProductOption[],\n variants: ReadonlyArray<Pick<DetailVariant, 'options'>>,\n): OptionPresentation[] {\n return options.map((option) => {\n const listed = [\n ...new Set(\n (option.values ?? []).map((value) => String(value).trim()).filter(Boolean),\n ),\n ]\n const carried = new Set(\n variants\n .map((variant) => variant.options?.[option.name])\n .filter(\n (value): value is string => typeof value === 'string' && value.trim() !== '',\n ),\n )\n const values = carried.size\n ? [\n ...listed.filter((value) => carried.has(value)),\n ...[...carried].filter((value) => !listed.includes(value)),\n ]\n : variants.length > 1 || listed.length === 1\n ? listed\n : []\n return {\n name: option.name,\n values,\n mode: values.length >= 2 ? 'select' : values.length === 1 ? 'text' : 'hidden',\n }\n })\n}\n\n/** The selections a page opens on: the first variant on sale, else the first. */\nfunction initialSelections(\n product: Pick<Detail, 'variants'> | undefined,\n): Record<string, string> {\n const first =\n product?.variants.find((variant) => !variant.soldOut) ?? product?.variants[0]\n return { ...(first?.options ?? {}) }\n}\n\n/** What the Details panel lists: only facts the product record holds. */\nexport function productDetailFacts(\n product: Pick<Detail, 'type' | 'tags'>,\n variant: Pick<DetailVariant, 'sku'> | undefined,\n presented: readonly OptionPresentation[],\n): Array<{ label: string; value: string }> {\n const facts: Array<{ label: string; value: string }> = []\n if (product.type === 'digital') facts.push({ label: 'Format', value: 'Digital product' })\n if (product.type === 'service') facts.push({ label: 'Format', value: 'Service' })\n for (const option of presented) {\n if (option.mode !== 'hidden') {\n facts.push({ label: option.name, value: option.values.join(', ') })\n }\n }\n if (variant?.sku) facts.push({ label: 'SKU', value: variant.sku })\n if (product.tags?.length) facts.push({ label: 'Tags', value: product.tags.join(', ') })\n return facts\n}\n\n/**\n * What the Shipping & returns panel says, from the product's kind and the\n * store's own return settings — never a policy the store has not set.\n */\nexport function productShippingLines(\n product: Pick<Detail, 'type'>,\n returns: { windowDays: number } | undefined,\n): string[] {\n const lines: string[] = []\n if (product.type === 'digital') lines.push('Delivered digitally after purchase — nothing ships.')\n else if (product.type === 'service') lines.push('A service — nothing ships.')\n else lines.push('Shipping is calculated at checkout.')\n if (returns && returns.windowDays > 0) {\n lines.push(\n `Returns accepted within ${returns.windowDays} ` +\n `${returns.windowDays === 1 ? 'day' : 'days'} of shipping — ` +\n 'request one from your order status page.',\n )\n }\n return lines\n}\n\nfunction slugFromLocation(): string {\n if (typeof window === 'undefined') return ''\n const match = window.location.pathname.match(/\\/products\\/([^/?#]+)/)\n return match ? decodeURIComponent(match[1]) : ''\n}\n\n/**\n * Product detail block (AGL-292): gallery, option pickers that resolve\n * the variant (price/media/stock follow), quantity, and a buy button\n * that charges through the server-priced checkout with the selected\n * variant. Resolves its product from the /products/{slug} URL unless a\n * slug prop pins it; sample data on the inert canvas.\n */\nconst ProductDetail = forwardRef<HTMLDivElement, ProductDetailProps>(\n (props, ref) => {\n const {\n slug: slugProp,\n buyLabel,\n hideDescription,\n showCoupon,\n showDetails,\n showShipping,\n ...rest\n } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const site = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const { hostId } = site\n\n // The single-product (\"buy now\") path returns the shopper to this page\n // rather than to the cart, so the PDP is the second of the two surfaces\n // that has to be able to report `purchase` (AGL-1641). Both mount points\n // share one guard, so a page carrying a cart AND a PDP still sends one.\n useStorefrontPurchaseEvent(hostId, siteFetch)\n // Seeded from the server-resolved page data (AGL-659) so the PDP renders\n // its real content in the SSR HTML. Starting at null meant the server\n // emitted a <Skeleton> and the crawler got a product page with no\n // product in it. Absent in the besigner/preview, where the effect below\n // still fetches — so this is an optimisation, not a new requirement.\n const seededCommerce = (\n site.pageData as\n | { commerce?: { product?: Detail; returns?: { windowDays: number } } }\n | undefined\n )?.commerce\n const seededProduct = seededCommerce?.product\n // The store's return window, seeded with the built-in product page only\n // when the store takes returns of this product's kind.\n const seededReturns = seededCommerce?.returns\n const [detail, setDetail] = useState<Detail | null | 'missing'>(\n seededProduct ?? null,\n )\n // Opened on the first variant on sale. A seeded page skips the fetch that\n // used to set this, so it opened with nothing selected — an empty select.\n const [selections, setSelections] = useState<Record<string, string>>(() =>\n initialSelections(seededProduct),\n )\n const [quantity, setQuantity] = useState(1)\n /**\n * The day the buyer chose to use a pass (AGL-4043), `YYYY-MM-DD` on the\n * store's calendar; '' is the day they buy, which is also the default.\n */\n const [useDay, setUseDay] = useState('')\n /** A discount or coupon code typed on the product page. */\n const [coupon, setCoupon] = useState('')\n // A thumbnail the shopper picked; null follows the variant's own photo.\n const [activeImage, setActiveImage] = useState<number | null>(null)\n // `unconfigured` is not an `error` with softer words (AGL-2019). A store\n // with no Stripe key answers 501, and rendering that at `severity=\"error\"`\n // tells a shopper their payment failed when nothing was ever attempted —\n // the same distinction `ask` already makes, and the same one the cart's\n // 423 lockdown branch makes. It is the terminal one: it latches Buy off,\n // because every further click gets the identical refusal.\n const [status, setStatus] = useState<\n 'idle' | 'sending' | 'error' | 'ask' | 'unconfigured'\n >('idle')\n const [message, setMessage] = useState('')\n // Buy-now's half of AGL-1721: asked only when the server refuses to price\n // shipping without a destination, so a digital product, a subscription, or\n // a merchant whose rates are the same everywhere never shows it. `null` is\n // \"not asked\" — the field appearing is the server's answer, not a guess.\n const [shipTo, setShipTo] = useState('')\n const [shipCountries, setShipCountries] = useState<string[] | null>(null)\n // Live carrier rates price by postal code (AGL-3612): asked only when the\n // store prices that way and the server says so.\n const [shipPostal, setShipPostal] = useState('')\n const [askPostal, setAskPostal] = useState(false)\n const [added, setAdded] = useState(false)\n const [wishlisted, setWishlisted] = useState(false)\n const [notifyEmail, setNotifyEmail] = useState('')\n const [notifyState, setNotifyState] = useState<'idle' | 'done'>('idle')\n // Buyer-chosen billing (AGL-545): only meaningful when the product\n // is subscriptionOptional; defaults to a one-time purchase.\n const [billing, setBilling] = useState<CommerceModel.CheckoutBillingChoice>(\n 'once',\n )\n /**\n * The in-page checkout session (AGL-1944), null on every store until the\n * flag AND a publishable key say otherwise. A `clientSecret` is Stripe's\n * instruction to the browser; holding it says nothing about money having\n * moved, and nothing in this component ever claims it has.\n */\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n /** The wallets the merchant hid (AGL-3629). */\n wallets?: CommerceModel.StorefrontCheckoutWallets\n } | null>(null)\n\n const slug = slugProp || slugFromLocation()\n\n useEffect(() => {\n if (hostId && resolvedId) {\n setWishlisted(readLocalWishlist(hostId).includes(resolvedId))\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hostId, detail])\n\n useEffect(() => {\n if (!hostId || !slug) return\n // Already delivered with the page (AGL-659) — refetching the identical\n // payload on hydrate would just be a wasted round trip per visitor.\n if (seededProduct && seededProduct.slug === slug) return\n let active = true\n void fetch(\n `/api/commerce/product?hostId=${encodeURIComponent(hostId)}` +\n `&slug=${encodeURIComponent(slug)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .then((payload) => {\n if (!active) return\n const product = payload?.product as Detail | undefined\n setDetail(product ?? 'missing')\n if (product) {\n // GA4 ecommerce mirror (AGL-327), through the shared taxonomy\n // since AGL-1591 rather than raw gtag — same consent gate, same\n // sanitizer, and the name is now checked by the compiler.\n trackEvent('view_item', {\n items: [{ item_id: product.id, item_name: product.name }],\n })\n setSelections(initialSelections(product))\n }\n })\n .catch(() => {\n if (active) setDetail('missing')\n })\n return () => {\n active = false\n }\n }, [hostId, slug])\n\n const resolvedId =\n hostId && detail && detail !== 'missing' ? detail.id : null\n const resolved: Detail | null = hostId\n ? detail === 'missing'\n ? null\n : detail\n : SAMPLE\n\n const variant = useMemo(() => {\n if (!resolved) return undefined\n return (\n CommerceModel.findVariant(\n { variants: resolved.variants as any },\n selections,\n ) as DetailVariant | undefined\n ) ?? resolved.variants[0]\n }, [resolved, selections])\n\n // The day to send with this variant: only when it asks for one and the\n // buyer chose a day (AGL-4043).\n const chosenUseDay = variant?.asksUseDate && useDay ? useDay : ''\n // Today on the store's calendar, the first day the picker offers.\n const storeTodayKey = resolved?.useDayTimeZone\n ? zonedDayKey(Date.now(), resolved.useDayTimeZone)\n : ''\n\n // Add to cart (AGL-293) beside instant buy; badge refresh via event.\n const handleAddToCart = async () => {\n if (!hostId || !resolved || !variant) return\n setAdded(false)\n // Priced (AGL-1591's shape, completed): the resolved variant's price\n // and the chosen quantity both come from the server's product payload,\n // so GA4's \"value added to cart\" is a real number. The funnel step\n // (AGL-3605) and the badge refresh ride the same shared helper the\n // product grid's quick add uses.\n const ok = await addToCart({\n hostId,\n siteFetch,\n productId: resolved.id,\n variantId: variant.id,\n quantity,\n ...(chosenUseDay ? { useDayKey: chosenUseDay } : {}),\n item: buyItem(resolved, variant, quantity),\n })\n if (ok) setAdded(true)\n }\n\n /**\n * Idempotency key for ONE buy-now attempt (AGL-1697).\n *\n * Minted lazily on the first buy click, retired whenever the purchase\n * changes shape — a different product, variant, quantity, billing choice\n * or destination is a different attempt. A retry of THIS attempt presents\n * the same key, so the server replays the original session instead of\n * opening a second one (for a subscription product, a second RECURRING\n * subscription).\n */\n // Pickup or the store's own delivery (AGL-3624), for a one-time sale; the\n // server offers nothing for a product with nothing physical to collect.\n const fulfillment = useCartFulfillment(\n hostId,\n resolved?.id ?? '[]',\n resolved &&\n variant &&\n !(resolved.subscription && (!resolved.subscriptionOptional || billing === 'subscribe'))\n ? { productId: resolved.id, variantId: variant.id, quantity }\n : null,\n )\n const attemptKey = useRef('')\n useEffect(() => {\n attemptKey.current = ''\n // `coupon` is in here because it CHANGES THE PRICE. Without it a shopper\n // who buys, comes back, types a code and buys again presents the same\n // key, and the server replays the original full-price session — a quoted\n // number that is not the number charged, which is the whole defect class\n // this path has been cleared of.\n }, [resolved?.id, variant?.id, quantity, billing, shipTo, shipPostal, coupon, fulfillment.signature, chosenUseDay])\n\n const handleBuy = async () => {\n if (!hostId || !resolved || !variant || status === 'sending') return\n setStatus('sending')\n setMessage('')\n if (!attemptKey.current) {\n attemptKey.current =\n globalThis.crypto?.randomUUID?.() ??\n `${Date.now()}-${Math.random().toString(36).slice(2)}`\n }\n try {\n const response = await siteFetch('/api/commerce/checkout', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Idempotency-Key': attemptKey.current,\n },\n body: JSON.stringify({\n hostId,\n productId: resolved.id,\n variantId: variant.id,\n quantity,\n // The day the buyer will use it (AGL-4043); the server checks it\n // against the product and the store's calendar.\n ...(chosenUseDay ? { useDayKey: chosenUseDay } : {}),\n // Billing choice (AGL-545): the server re-validates against\n // the product doc, so this is a request, not an instruction.\n ...(resolved.subscriptionOptional ? { billing } : {}),\n // Likewise a request (AGL-1721): the server resolves this\n // country's rates AND restricts the session to addresses in it,\n // so naming a cheap zone here cannot ship a parcel anywhere else.\n ...(shipTo && !fulfillment.request ? { shippingCountry: shipTo } : {}),\n ...(shipPostal.trim() && !fulfillment.request ? { shippingPostalCode: shipPostal.trim() } : {}),\n // Where and when, never the fee (AGL-3624).\n ...(fulfillment.request ? { fulfillment: fulfillment.request } : {}),\n // The server resolves this against the discounts hub first and the\n // legacy coupons second, and refuses a code it cannot apply with a\n // reason — never a silent full-price charge.\n ...(coupon.trim() ? { couponCode: coupon.trim() } : {}),\n // The visitor's advertising consent and the vendors' browser ids, only\n // where that consent grants advertising (AGL-3694); absent otherwise.\n ...advertisingConsentField(hostId),\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // In-page payment (AGL-1944). A native session returns a client secret\n // and NO url — the two are mutually exclusive by construction, so the\n // redirect branch below is unreachable in native mode and vice versa.\n // Checked FIRST so a server that somehow sent both cannot silently\n // navigate the shopper away from the form we just decided to show.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n // Buy-now's `begin_checkout`. The cart path has reported this since\n // AGL-1591 and this one never did, so a storefront whose shoppers\n // skip the cart showed `view_item` → `add_to_cart` → nothing →\n // `purchase`: GA4's shopping funnel put every single-product sale in\n // the \"abandoned checkout\" bucket, and the merchant's checkout rate\n // read as a collapse rather than as an unmeasured path.\n //\n // Reported on BOTH branches, and from the same place, for the reason\n // the cart states: a count that halved the day the in-page payment\n // flag flipped would look like a conversion collapse.\n trackEvent(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [buyItem(resolved, variant, quantity)],\n }),\n )\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: CommerceModel.readStorefrontCheckoutWallets(payload.wallets),\n })\n setStatus('idle')\n return\n }\n if (response.ok && payload?.url) {\n // Awaited before the redirect (AGL-1580), for the reason spelled out\n // on the cart's matching branch: delivery here is a synchronous\n // `window.gtag` call today and the await costs nothing, but the\n // property that makes a bare call safe is invisible from this file.\n await trackEventBeforeNavigation(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [buyItem(resolved, variant, quantity)],\n }),\n )\n window.location.assign(payload.url)\n return\n }\n // Buy-now's half of AGL-2019. The server's own 501 wording is not\n // rendered to a visitor; this surface is public.\n if (payload?.fulfillmentChanged) {\n fulfillment.reload()\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n return\n }\n if (isPaymentsNotConfigured(response.status)) {\n setMessage(storefrontPaymentsNotConfiguredText())\n setStatus('unconfigured')\n return\n }\n if (payload?.needsShippingCountry) {\n if (payload?.needsShippingPostalCode) setAskPostal(true)\n setShipCountries(\n (payload.shippingCountries as string[] | undefined)?.length\n ? (payload.shippingCountries as string[])\n : [...CommerceModel.CHECKOUT_SHIPPING_COUNTRIES],\n )\n setMessage(String(payload?.error ?? ''))\n // An unserved destination is a refusal and reads as one; being\n // asked the first time is not.\n setStatus(shipTo ? 'error' : 'ask')\n return\n }\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n } catch {\n setStatus('error')\n }\n }\n\n if (hostId && detail === null) {\n return (\n <Box ref={ref} {...rest} sx={[{ display: 'flex', gap: 3 }, ...nodeSx]}>\n <Skeleton variant=\"rectangular\" width={320} height={320} />\n <Box sx={{ flex: 1 }}>\n <Skeleton width=\"60%\" height={36} />\n <Skeleton width=\"25%\" />\n <Skeleton width=\"90%\" />\n </Box>\n </Box>\n )\n }\n if (!resolved) {\n return (\n <Box ref={ref} {...rest} sx={[{ p: 3 }, ...nodeSx]}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Product not found.'}\n </Typography>\n </Box>\n )\n }\n\n // Every rendered `<img src>` on this page goes through\n // `siteRelativeMediaSrc` (AGL-1726). Commerce called NO resolver at all,\n // which cost it two things at once: a `media:` reference — writable via\n // the resources API and the CSV importer — would have reached an `<img>`\n // as the literal string, and a stored absolute\n // `https://{subdomain}.aglyn.app/api/media/cdn/…` stayed absolute, so a\n // white-label storefront on the customer's own domain served product\n // photos naming OUR platform, cross-origin, in page source and in every\n // visitor's request. Production carried exactly one such document; the\n // resolver fixes it at READ time, so no backfill stands between the\n // defect and the fix.\n //\n // Deliberately NOT applied to `resolved.mediaUrls` wholesale: the\n // schema.org `image` array below is read out of band by a crawler, where\n // an absolute URL is the point. That one wants `absoluteMediaSrc` with\n // the site's own origin, which is the tenant page's job (AGL-1725).\n const galleryImage = Aglyn.siteRelativeMediaSrc(\n (activeImage !== null ? resolved.mediaUrls[activeImage] : undefined) ??\n variant?.imageUrl ??\n resolved.mediaUrls[0],\n { hostId },\n )\n const presentedOptions = optionPresentation(resolved.options, resolved.variants)\n const detailFacts = showDetails\n ? productDetailFacts(resolved, variant, presentedOptions)\n : []\n const shippingLines = showShipping\n ? productShippingLines(\n resolved,\n seededProduct?.id === resolved.id ? seededReturns : undefined,\n )\n : []\n\n // Subscription framing (AGL-545): subscription-only products price as\n // $X/mo|/yr with a \"Subscribe\" button; subscriptionOptional products\n // surface the one-time/subscribe toggle instead. Same price either way\n // — the server re-prices from the product doc regardless.\n const subscription = resolved.subscription\n const intervalSuffix = subscription?.interval === 'year' ? '/yr' : '/mo'\n const subscribing =\n Boolean(subscription) &&\n (!resolved.subscriptionOptional || billing === 'subscribe')\n // Listed before it has a price (AGL-3676): no price to show and nothing\n // to buy; every sale door would refuse it anyway.\n const priced = typeof variant?.priceUsd === 'number'\n\n // schema.org Product/Offer (AGL-299). Kept ONLY for the case where this\n // block renders without server-seeded page data — the besigner preview,\n // or a page whose resolver didn't supply it. When the tenant page seeds\n // us it emits the same Product node server-side (AGL-660), and two\n // Product nodes for one item is worse than one, so we stand down.\n const structuredData =\n hostId && resolvedId && !seededProduct\n ? {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: resolved.name,\n ...(resolved.description\n ? { description: resolved.description }\n : {}),\n ...(resolved.mediaUrls.length\n ? { image: resolved.mediaUrls }\n : {}),\n // No offer without a price: a price of 0 would read as free.\n ...(priced\n ? {\n offers: {\n '@type': 'Offer',\n priceCurrency: 'USD',\n price: String(variant?.priceUsd),\n availability: variant?.soldOut\n ? 'https://schema.org/OutOfStock'\n : 'https://schema.org/InStock',\n },\n }\n : {}),\n }\n : null\n\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n display: 'flex',\n gap: 3,\n flexDirection: { xs: 'column', md: 'row' },\n },\n ...nodeSx,\n ]}\n >\n <CheckoutReturnNotice hostId={hostId} siteFetch={siteFetch} />\n <Box sx={{ flex: 1, minWidth: 0 }}>\n {galleryImage ? (\n <Box\n component=\"img\"\n src={galleryImage}\n alt={resolved.name}\n // DELIBERATELY NOT DEFERRED (AGL-2486). This is the gallery\n // hero at the top of a product page — the one image on this\n // surface that really is the LCP candidate, and the browser\n // default here is already `eager`. Spreading\n // `DEFERRED_IMAGE_ATTRIBUTES` over it to \"finish the job\" is\n // the obvious next edit and it re-introduces the bug this\n // issue opened with: an LCP image not discovered until after\n // layout has run. The thumbnail strip below it IS deferred.\n //\n // No `fetchpriority` either, for the reason written out at\n // `image.tsx`: `high` is a claim about every other request in\n // flight, and a page whose real LCP is the product NAME would\n // pay for that claim.\n sx={{\n width: '100%',\n aspectRatio: '1 / 1',\n objectFit: 'cover',\n borderRadius: 1,\n }}\n />\n ) : (\n <Box\n sx={{\n width: '100%',\n aspectRatio: '1 / 1',\n bgcolor: 'action.hover',\n borderRadius: 1,\n }}\n />\n )}\n {resolved.mediaUrls.length > 1 ? (\n <Box sx={{ display: 'flex', gap: 1, mt: 1, flexWrap: 'wrap' }}>\n {resolved.mediaUrls.map((url, index) => (\n <Box\n key={`${url}-${index}`}\n component=\"img\"\n // Same resolver as the hero (AGL-1726) — a thumbnail is an\n // `<img>` on the customer's page and leaks exactly as much.\n src={Aglyn.siteRelativeMediaSrc(url, { hostId })}\n alt=\"\"\n onClick={() => setActiveImage(index)}\n sx={{\n width: 64,\n height: 64,\n objectFit: 'cover',\n borderRadius: 1,\n cursor: 'pointer',\n border: 2,\n borderColor:\n index === (activeImage ?? 0) ? 'primary.main' : 'transparent',\n }}\n // Deferred (AGL-2486): 56px thumbnails that exist to swap\n // the hero above. They were fetching eagerly ALONGSIDE\n // that hero, so a five-image gallery had the hero\n // competing with four thumbnails nobody had asked for yet.\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n ))}\n </Box>\n ) : null}\n </Box>\n {structuredData ? (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: Aglyn.safeJsonLd(structuredData) }}\n />\n ) : null}\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"h4\" component=\"h1\" gutterBottom>\n {resolved.name}\n </Typography>\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 2 }}>\n <Typography variant=\"h6\">\n {priced\n ? `$${variant?.priceUsd}${subscribing ? intervalSuffix : ''}`\n : PRICE_COMING_SOON_LABEL}\n </Typography>\n {subscribing && subscription?.trialDays ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${subscription.trialDays}-day free trial`}\n </Typography>\n ) : null}\n {variant?.compareAtPriceUsd ? (\n <>\n <Typography\n variant=\"body1\"\n color=\"text.disabled\"\n sx={{ textDecoration: 'line-through' }}\n >\n {`$${variant.compareAtPriceUsd}`}\n </Typography>\n <Chip label=\"Sale\" size=\"small\" color=\"primary\" />\n </>\n ) : null}\n {variant?.soldOut ? (\n <Chip label=\"Sold out\" size=\"small\" variant=\"outlined\" />\n ) : null}\n <Button\n size=\"small\"\n onClick={async () => {\n if (hostId && resolved.id !== 'sample') {\n setWishlisted(await toggleWishlist(hostId, resolved.id, siteFetch))\n }\n }}\n >\n {wishlisted ? '♥ Saved' : '♡ Save'}\n </Button>\n </Box>\n {subscription && resolved.subscriptionOptional ? (\n <ToggleButtonGroup\n value={billing}\n exclusive\n size=\"small\"\n onChange={(_event, value) => {\n if (value === 'once' || value === 'subscribe') {\n setBilling(value)\n }\n }}\n sx={{ mb: 2 }}\n >\n <ToggleButton value=\"once\">\n {priced ? `One-time $${variant?.priceUsd}` : 'One-time'}\n </ToggleButton>\n <ToggleButton value=\"subscribe\">\n {priced ? `Subscribe $${variant?.priceUsd}${intervalSuffix}` : 'Subscribe'}\n </ToggleButton>\n </ToggleButtonGroup>\n ) : null}\n {presentedOptions.map((option) =>\n option.mode === 'hidden' ? null : option.mode === 'text' ? (\n <Typography\n key={option.name}\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ mb: 1.5 }}\n >\n {`${option.name}: ${option.values[0]}`}\n </Typography>\n ) : (\n <TextField\n key={option.name}\n label={option.name}\n value={\n option.values.includes(selections[option.name] ?? '')\n ? selections[option.name]\n : ''\n }\n onChange={(event) => {\n // A new variant shows its own photo, not the last thumbnail.\n setActiveImage(null)\n setSelections((prev) => ({\n ...prev,\n [option.name]: event.target.value,\n }))\n }}\n size=\"small\"\n select\n fullWidth\n sx={{ mb: 1.5 }}\n >\n {option.values.map((value) => (\n <MenuItem key={value} value={value}>\n {value}\n </MenuItem>\n ))}\n </TextField>\n ),\n )}\n {showCoupon ? (\n <TextField\n label=\"Discount code\"\n value={coupon}\n onChange={(event) => setCoupon(event.target.value)}\n size=\"small\"\n sx={{ mb: 2, display: 'block' }}\n />\n ) : null}\n {!priced ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 2 }}>\n {'Not on sale yet — check back soon.'}\n </Typography>\n ) : null}\n {priced && variant?.asksUseDate && storeTodayKey ? (\n <Box sx={{ mb: 2 }}>\n <Suspense fallback={null}>\n <UseDayPicker\n value={useDay}\n onChange={setUseDay}\n todayKey={storeTodayKey}\n label=\"Day you will use it (optional)\"\n helperText=\"Leave it blank to use it the day you buy.\"\n />\n </Suspense>\n </Box>\n ) : null}\n <Box sx={{ display: priced ? 'flex' : 'none', gap: 1.5, alignItems: 'center', mb: 2 }}>\n <TextField\n label=\"Qty\"\n value={quantity}\n onChange={(event) =>\n setQuantity(\n Math.max(\n 1,\n Math.min(99, Math.round(Number(event.target.value)) || 1),\n ),\n )\n }\n size=\"small\"\n sx={{ width: 80 }}\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <Button\n variant=\"outlined\"\n color=\"primary\"\n size=\"large\"\n disabled={!hostId || !priced || variant?.soldOut}\n onClick={handleAddToCart}\n >\n {added ? 'Added ✓' : 'Add to cart'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"large\"\n disabled={\n !hostId ||\n !priced ||\n status === 'sending' ||\n variant?.soldOut ||\n // No payments on this deployment: the same 501 every time, so\n // the control latches off rather than inviting a retry that\n // cannot succeed (AGL-2019).\n status === 'unconfigured' ||\n // Asked but unanswered: the server would only refuse again.\n (fulfillment.method === 'shipping' && shipCountries !== null && !shipTo) ||\n (fulfillment.method === 'shipping' && askPostal && !shipPostal.trim()) ||\n !fulfillment.ready\n }\n onClick={handleBuy}\n sx={{ flex: 1 }}\n >\n {variant?.soldOut\n ? 'Sold out'\n : status === 'sending'\n ? // \"Redirecting\" is a lie once the form opens in place, and\n // it is the shopper's only clue about what is about to\n // happen to their page (AGL-1944).\n nativeCheckout\n ? 'Opening…'\n : 'Redirecting…'\n : buyLabel || (subscribing ? 'Subscribe' : 'Buy now')}\n </Button>\n </Box>\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={buyLabel || (subscribing ? 'Subscribe' : 'Pay now')}\n // An expired or unloadable session is replaced, never\n // replayed: the old attempt key would hand back the dead one.\n onRestart={() => {\n attemptKey.current = ''\n setNativeCheckout(null)\n void handleBuy()\n }}\n // Cancelling drops the form and leaves the session open —\n // deliberately. The shopper may come back to the same\n // attempt key, and an abandoned session is what the AGL-323\n // recovery emails are built on. Nothing is expired from the\n // browser: that is a write against the merchant's account.\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : null}\n {fulfillment.offered && priced ? (\n <Box sx={{ mb: 2 }}>\n <CartFulfillmentChoice\n state={fulfillment}\n formatCents={(cents) => `$${(cents / 100).toFixed(2)}`}\n />\n </Box>\n ) : null}\n {shipCountries && fulfillment.method === 'shipping' && priced ? (\n <TextField\n select\n label=\"Ship to\"\n value={shipTo}\n onChange={(event) => setShipTo(event.target.value)}\n size=\"small\"\n fullWidth\n helperText=\"Shipping rates depend on where this is going\"\n sx={{ mb: 2 }}\n >\n {shipCountries.map((code) => (\n <MenuItem key={code} value={code}>\n {CommerceModel.CHECKOUT_SHIPPING_COUNTRY_NAMES[code] ?? code}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {askPostal && fulfillment.method === 'shipping' && priced ? (\n <TextField\n label=\"Postal code\"\n value={shipPostal}\n onChange={(event) => setShipPostal(event.target.value)}\n size=\"small\"\n fullWidth\n helperText=\"Carrier rates depend on the postal code\"\n slotProps={{ htmlInput: { autoComplete: 'shipping postal-code', maxLength: 12 } }}\n sx={{ mb: 2 }}\n />\n ) : null}\n {status === 'ask' || status === 'unconfigured' ? (\n <Alert severity=\"info\" sx={{ mb: 2 }}>\n {message}\n </Alert>\n ) : null}\n {status === 'error' ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {message || 'Checkout is unavailable right now.'}\n </Alert>\n ) : null}\n {variant?.soldOut && hostId ? (\n notifyState === 'done' ? (\n <Alert severity=\"success\" sx={{ mb: 2 }}>\n {'We will email you when it is back.'}\n </Alert>\n ) : (\n <Box sx={{ display: 'flex', gap: 1, mb: 2 }}>\n <TextField\n placeholder=\"you@example.com\"\n type=\"email\"\n // Third instance of the nameless-input defect (AGL-2392).\n // Named for its job rather than \"Email address\": this row\n // appears inside a product page that may also carry the\n // newsletter block, and two fields both announced as\n // \"Email address\" is barely better than none.\n slotProps={{\n htmlInput: {\n 'aria-label': 'Email address for back-in-stock alert',\n },\n }}\n value={notifyEmail}\n onChange={(event) => setNotifyEmail(event.target.value)}\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <Button\n size=\"small\"\n variant=\"outlined\"\n disabled={!notifyEmail.trim()}\n onClick={async () => {\n const response = await siteFetch(\n '/api/commerce/notify-restock',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n productId: resolved.id,\n email: notifyEmail,\n }),\n },\n ).catch(() => null)\n if (response?.ok) setNotifyState('done')\n }}\n >\n {'Notify me'}\n </Button>\n </Box>\n )\n ) : null}\n {!hideDescription && resolved.description ? (\n <Typography\n variant=\"body1\"\n color=\"text.secondary\"\n sx={{ whiteSpace: 'pre-line' }}\n >\n {resolved.description}\n </Typography>\n ) : null}\n {detailFacts.length || shippingLines.length ? (\n <Box sx={{ mt: 3 }}>\n {detailFacts.length ? (\n <ProductDetailPanel title=\"Details\">\n <Box\n component=\"dl\"\n sx={{\n m: 0,\n display: 'grid',\n gridTemplateColumns: 'auto 1fr',\n columnGap: 2,\n rowGap: 0.75,\n }}\n >\n {detailFacts.map((fact) => (\n <Box key={fact.label} sx={{ display: 'contents' }}>\n <Typography component=\"dt\" variant=\"body2\" sx={{ fontWeight: 600 }}>\n {fact.label}\n </Typography>\n <Typography\n component=\"dd\"\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ m: 0 }}\n >\n {fact.value}\n </Typography>\n </Box>\n ))}\n </Box>\n </ProductDetailPanel>\n ) : null}\n {shippingLines.length ? (\n <ProductDetailPanel title=\"Shipping & returns\">\n {shippingLines.map((line) => (\n <Typography\n key={line}\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ mb: 0.75 }}\n >\n {line}\n </Typography>\n ))}\n </ProductDetailPanel>\n ) : null}\n </Box>\n ) : null}\n </Box>\n </Box>\n )\n },\n)\nProductDetail.displayName = 'AglynProductDetail'\n\n/**\n * One fold of the panels under the buy box: a flat, divided accordion in the\n * theme's own colours — the way a designer storefront stacks Details and\n * Shipping under the description.\n */\nfunction ProductDetailPanel({\n title,\n children,\n}: {\n title: string\n children: ReactNode\n}) {\n return (\n <Accordion\n disableGutters\n elevation={0}\n square\n sx={{\n bgcolor: 'transparent',\n borderTop: 1,\n borderColor: 'divider',\n '&:last-of-type': { borderBottom: 1, borderColor: 'divider' },\n '&::before': { display: 'none' },\n }}\n >\n <AccordionSummary\n expandIcon={\n <SvgIcon fontSize=\"small\">\n <path d={mdiChevronDown.path} />\n </SvgIcon>\n }\n sx={{ px: 0 }}\n >\n <Typography variant=\"subtitle1\" component=\"h2\">\n {title}\n </Typography>\n </AccordionSummary>\n <AccordionDetails sx={{ px: 0, pt: 0, pb: 2 }}>{children}</AccordionDetails>\n </Accordion>\n )\n}\n\nexport const schema: Aglyn.ComponentSchema<ProductDetailProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product detail',\n description: \"One product's gallery, options and buy button.\",\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'slug',\n label: 'Product slug',\n description:\n 'Pin to one product; blank follows the /products/{slug} URL ' +\n '(product page template).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'buyLabel',\n label: 'Buy button label',\n description: 'Defaults to \"Buy now\".',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'hideDescription',\n label: 'Hide description',\n description: 'Design the description separately with tokens.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n // Off by default, so no existing page changes shape on deploy. The cart\n // has carried this field all along and the product page had none, so a\n // shopper buying the same goods through Buy now had nowhere to enter a\n // code the merchant had advertised.\n name: 'showCoupon',\n label: 'Show discount code field',\n description: 'Lets a buyer enter a discount or coupon code before buying.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n // Off by default, so no existing page changes shape on deploy.\n name: 'showDetails',\n label: 'Show details panel',\n description:\n 'A Details fold under the description with the facts the product ' +\n 'holds: its options, SKU, tags, and whether it is digital or a service.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showShipping',\n label: 'Show shipping & returns panel',\n description:\n 'A Shipping & returns fold: shipping priced at checkout (or digital ' +\n 'delivery), and your return window when your store takes returns.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product detail',\n pluginId: BUNDLE_ID,\n description: 'Gallery, variant picker, and buy button for one product',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n {\n // Product page (AGL-561): the commerce-standard PDP subtree —\n // breadcrumb, detail, related products, reviews — for the product\n // page template screen. `{{product.name}}` resolves there via the\n // site page resolver's token pass (AGL-292); node shapes follow\n // the Sections & Blocks convention (AGL-539) and reference only\n // persisted component ids.\n $id: generatePresetId(ID, 'page'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product page',\n pluginId: BUNDLE_ID,\n description:\n 'Breadcrumb, product detail, related products, and reviews',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiTagOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { spacing: 4 },\n // Styling on the node's own sx, never in props (AGL-1346): both\n // records render, but only `node.sx` is the one the Styles panel can\n // read, edit or clear.\n sx: { paddingTop: 2, paddingBottom: 2 },\n nodes: [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { direction: 'row', spacing: 1 },\n sx: { alignItems: 'center' },\n nodes: [\n {\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { children: 'Shop', size: 'small', color: 'inherit' },\n },\n {\n $id: null,\n componentId: 'muiTypography',\n pluginId: Aglyn.MUI_BUNDLE_ID,\n props: { variant: 'body2', children: '/ {{product.name}}' },\n },\n ],\n },\n {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n {\n $id: null,\n componentId: RELATED_PRODUCTS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n {\n $id: null,\n componentId: PRODUCT_REVIEWS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n ],\n },\n },\n]\n\nexport default ProductDetail\n"],"names":["advertisingConsentField","Aglyn","buildBeginCheckoutParams","trackEvent","trackEventBeforeNavigation","isPaymentsNotConfigured","storefrontPaymentsNotConfiguredText","CommerceModel","mdiChevronDown","mdiTagOutline","Accordion","AccordionDetails","AccordionSummary","Alert","Box","Button","Chip","MenuItem","Skeleton","SvgIcon","TextField","ToggleButton","ToggleButtonGroup","Typography","Suspense","forwardRef","lazy","useEffect","useMemo","useRef","useState","BUNDLE_ID","generatePresetId","useStorefrontPurchaseEvent","addToCart","CartFulfillmentChoice","useCartFulfillment","ID","PRODUCT_REVIEWS_ID","RELATED_PRODUCTS_ID","readLocalWishlist","toggleWishlist","StorefrontPaymentElementFallback","CheckoutReturnNotice","zonedDayKey","StorefrontPaymentElement","then","module","default","PRICE_COMING_SOON_LABEL","UseDayPicker","SAMPLE","id","name","slug","description","mediaUrls","options","values","variants","Size","priceUsd","soldOut","buyItem","product","variant","quantity","item_id","item_name","price","undefined","optionPresentation","map","option","listed","Set","value","String","trim","filter","Boolean","carried","size","has","includes","length","mode","initialSelections","first","find","productDetailFacts","presented","facts","type","push","label","join","sku","tags","productShippingLines","returns","lines","windowDays","slugFromLocation","window","match","location","pathname","decodeURIComponent","ProductDetail","props","ref","activeImage","site","slugProp","buyLabel","hideDescription","showCoupon","showDetails","showShipping","rest","nodeSx","Array","isArray","useSite","siteFetch","useSiteFetch","hostId","seededCommerce","pageData","commerce","seededProduct","seededReturns","detail","setDetail","selections","setSelections","setQuantity","useDay","setUseDay","coupon","setCoupon","setActiveImage","status","setStatus","message","setMessage","shipTo","setShipTo","shipCountries","setShipCountries","shipPostal","setShipPostal","askPostal","setAskPostal","added","setAdded","wishlisted","setWishlisted","notifyEmail","setNotifyEmail","notifyState","setNotifyState","billing","setBilling","nativeCheckout","setNativeCheckout","resolvedId","active","fetch","encodeURIComponent","response","ok","json","payload","items","catch","resolved","findVariant","chosenUseDay","asksUseDate","storeTodayKey","useDayTimeZone","Date","now","handleAddToCart","productId","variantId","useDayKey","item","fulfillment","subscription","subscriptionOptional","attemptKey","current","signature","handleBuy","globalThis","crypto","randomUUID","Math","random","toString","slice","method","headers","body","JSON","stringify","request","shippingCountry","shippingPostalCode","couponCode","clientSecret","publishableKey","wallets","readStorefrontCheckoutWallets","url","assign","fulfillmentChanged","reload","error","needsShippingCountry","needsShippingPostalCode","shippingCountries","CHECKOUT_SHIPPING_COUNTRIES","sx","display","gap","width","height","flex","p","color","galleryImage","siteRelativeMediaSrc","imageUrl","presentedOptions","detailFacts","shippingLines","intervalSuffix","interval","subscribing","priced","structuredData","image","offers","priceCurrency","availability","flexDirection","xs","md","minWidth","component","src","alt","aspectRatio","objectFit","borderRadius","bgcolor","mt","flexWrap","index","onClick","cursor","border","borderColor","DEFERRED_IMAGE_ATTRIBUTES","script","dangerouslySetInnerHTML","__html","safeJsonLd","gutterBottom","alignItems","mb","trialDays","compareAtPriceUsd","textDecoration","exclusive","onChange","_event","event","prev","target","select","fullWidth","fallback","todayKey","helperText","max","min","round","Number","slotProps","htmlInput","inputMode","disabled","ready","payLabel","onRestart","onCancel","offered","state","formatCents","cents","toFixed","code","CHECKOUT_SHIPPING_COUNTRY_NAMES","autoComplete","maxLength","severity","placeholder","email","whiteSpace","ProductDetailPanel","title","m","gridTemplateColumns","columnGap","rowGap","fact","fontWeight","line","displayName","children","disableGutters","elevation","square","borderTop","borderBottom","expandIcon","fontSize","path","d","px","pt","pb","schema","$id","pluginId","category","ComponentCategory","COMMERCE","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","CHECKBOX","presets","NodeType","PRESET","data","componentId","MUI_BUNDLE_ID","spacing","paddingTop","paddingBottom","nodes","direction"],"mappings":"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"}
|
|
@@ -94,7 +94,9 @@ ProductReviews.displayName = 'AglynProductReviews';
|
|
|
94
94
|
/**
|
|
95
95
|
* The store-wide reviews band (`scope: 'store'`): the store's latest APPROVED
|
|
96
96
|
* reviews, read-only stars, the reviewer's first name and initial, a verified
|
|
97
|
-
* badge, and the product reviewed
|
|
97
|
+
* badge, and the product reviewed — linked to its page, or, for a product
|
|
98
|
+
* sold in person only, marked "Sold in store" and linked nowhere (AGL-4060).
|
|
99
|
+
* Real reviews or nothing: with none it
|
|
98
100
|
* renders an empty, zero-height element — never sample reviews on a live page
|
|
99
101
|
* (sample testimonials presented as customers' would be fake reviews). The
|
|
100
102
|
* editor, which has no site, gets a dashed hint instead.
|
|
@@ -269,18 +271,33 @@ ProductReviews.displayName = 'AglynProductReviews';
|
|
|
269
271
|
}) : null
|
|
270
272
|
]
|
|
271
273
|
}),
|
|
272
|
-
review.productName ? /*#__PURE__*/
|
|
273
|
-
variant: "caption",
|
|
274
|
-
color: "text.secondary",
|
|
275
|
-
component: review.productSlug ? 'a' : 'span'
|
|
276
|
-
}, review.productSlug ? {
|
|
277
|
-
href: `/products/${review.productSlug}`
|
|
278
|
-
} : {}, {
|
|
274
|
+
review.productName || review.soldInStore ? /*#__PURE__*/ _jsxs(Box, {
|
|
279
275
|
sx: {
|
|
280
|
-
|
|
276
|
+
display: 'flex',
|
|
277
|
+
flexWrap: 'wrap',
|
|
278
|
+
gap: 1,
|
|
279
|
+
alignItems: 'center'
|
|
281
280
|
},
|
|
282
|
-
children:
|
|
283
|
-
|
|
281
|
+
children: [
|
|
282
|
+
review.productName ? /*#__PURE__*/ _jsx(Typography, _extends({
|
|
283
|
+
variant: "caption",
|
|
284
|
+
color: "text.secondary",
|
|
285
|
+
component: review.productSlug && !review.soldInStore ? 'a' : 'span'
|
|
286
|
+
}, review.productSlug && !review.soldInStore ? {
|
|
287
|
+
href: `/products/${review.productSlug}`
|
|
288
|
+
} : {}, {
|
|
289
|
+
sx: {
|
|
290
|
+
textDecoration: 'none'
|
|
291
|
+
},
|
|
292
|
+
children: review.productName
|
|
293
|
+
})) : null,
|
|
294
|
+
review.soldInStore ? /*#__PURE__*/ _jsx(Chip, {
|
|
295
|
+
label: "Sold in store",
|
|
296
|
+
size: "small",
|
|
297
|
+
variant: "outlined"
|
|
298
|
+
}) : null
|
|
299
|
+
]
|
|
300
|
+
}) : null
|
|
284
301
|
]
|
|
285
302
|
}, review.id))
|
|
286
303
|
})
|