@aglyn/plugins-commerce 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +10 -0
- package/package.json +57 -0
- package/src/index.d.ts +38 -0
- package/src/index.js +38 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/account.d.ts +31 -0
- package/src/lib/components/account.js +645 -0
- package/src/lib/components/account.js.map +1 -0
- package/src/lib/components/cart.d.ts +38 -0
- package/src/lib/components/cart.js +851 -0
- package/src/lib/components/cart.js.map +1 -0
- package/src/lib/components/commerce-console-page.d.ts +32 -0
- package/src/lib/components/commerce-console-page.js +296 -0
- package/src/lib/components/commerce-console-page.js.map +1 -0
- package/src/lib/components/commerce-console-sections.d.ts +34 -0
- package/src/lib/components/commerce-console-sections.js +62 -0
- package/src/lib/components/commerce-console-sections.js.map +1 -0
- package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
- package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
- package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
- package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
- package/src/lib/components/console/commerce-glance-card.component.js +340 -0
- package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
- package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
- package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
- package/src/lib/components/console/discounts-card.component.d.ts +14 -0
- package/src/lib/components/console/discounts-card.component.js +443 -0
- package/src/lib/components/console/discounts-card.component.js.map +1 -0
- package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
- package/src/lib/components/console/entitlement-gate.component.js +115 -0
- package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
- package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
- package/src/lib/components/console/gift-cards-card.component.js +379 -0
- package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
- package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
- package/src/lib/components/console/host-coupons-card.component.js +252 -0
- package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
- package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
- package/src/lib/components/console/host-orders-card.component.js +861 -0
- package/src/lib/components/console/host-orders-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.d.ts +14 -0
- package/src/lib/components/console/locations-card.component.js +256 -0
- package/src/lib/components/console/locations-card.component.js.map +1 -0
- package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
- package/src/lib/components/console/member-posts-card.component.js +283 -0
- package/src/lib/components/console/member-posts-card.component.js.map +1 -0
- package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
- package/src/lib/components/console/newest-site-users-card.component.js +126 -0
- package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
- package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
- package/src/lib/components/console/order-detail-dialog.component.js +976 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
- package/src/lib/components/console/paid-media.d.ts +127 -0
- package/src/lib/components/console/paid-media.js +397 -0
- package/src/lib/components/console/paid-media.js.map +1 -0
- package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
- package/src/lib/components/console/payments-settings-card.component.js +295 -0
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
- package/src/lib/components/console/pos-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-page.component.js +916 -0
- package/src/lib/components/console/pos-page.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
- package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
- package/src/lib/components/console/products-hub-card.component.js +1280 -0
- package/src/lib/components/console/products-hub-card.component.js.map +1 -0
- package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
- package/src/lib/components/console/products-hub-zone.component.js +200 -0
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
- package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
- package/src/lib/components/console/recovery-queue-card.component.js +262 -0
- package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/registers-card.component.d.ts +21 -0
- package/src/lib/components/console/registers-card.component.js +296 -0
- package/src/lib/components/console/registers-card.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +14 -0
- package/src/lib/components/console/reservations-card.component.js +650 -0
- package/src/lib/components/console/reservations-card.component.js.map +1 -0
- package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
- package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
- package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
- package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
- package/src/lib/components/console/shipping-settings-card.component.js +560 -0
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
- package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
- package/src/lib/components/console/stock-movements-card.component.js +333 -0
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
- package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/store-settings-card.component.js +300 -0
- package/src/lib/components/console/store-settings-card.component.js.map +1 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
- package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
- package/src/lib/components/console/suppliers-card.component.js +328 -0
- package/src/lib/components/console/suppliers-card.component.js.map +1 -0
- package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/tax-settings-card.component.js +473 -0
- package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
- package/src/lib/components/gate.d.ts +39 -0
- package/src/lib/components/gate.js +202 -0
- package/src/lib/components/gate.js.map +1 -0
- package/src/lib/components/gated-video.d.ts +40 -0
- package/src/lib/components/gated-video.js +366 -0
- package/src/lib/components/gated-video.js.map +1 -0
- package/src/lib/components/member-feed.d.ts +32 -0
- package/src/lib/components/member-feed.js +198 -0
- package/src/lib/components/member-feed.js.map +1 -0
- package/src/lib/components/member-recovery.d.ts +35 -0
- package/src/lib/components/member-recovery.js +313 -0
- package/src/lib/components/member-recovery.js.map +1 -0
- package/src/lib/components/member-signin.d.ts +35 -0
- package/src/lib/components/member-signin.js +257 -0
- package/src/lib/components/member-signin.js.map +1 -0
- package/src/lib/components/member-signup.d.ts +34 -0
- package/src/lib/components/member-signup.js +287 -0
- package/src/lib/components/member-signup.js.map +1 -0
- package/src/lib/components/newsletter-signup.d.ts +39 -0
- package/src/lib/components/newsletter-signup.js +229 -0
- package/src/lib/components/newsletter-signup.js.map +1 -0
- package/src/lib/components/product-detail.d.ts +38 -0
- package/src/lib/components/product-detail.js +1022 -0
- package/src/lib/components/product-detail.js.map +1 -0
- package/src/lib/components/product-grid.d.ts +67 -0
- package/src/lib/components/product-grid.js +909 -0
- package/src/lib/components/product-grid.js.map +1 -0
- package/src/lib/components/product-reviews.d.ts +32 -0
- package/src/lib/components/product-reviews.js +349 -0
- package/src/lib/components/product-reviews.js.map +1 -0
- package/src/lib/components/related-products.d.ts +33 -0
- package/src/lib/components/related-products.js +232 -0
- package/src/lib/components/related-products.js.map +1 -0
- package/src/lib/components/reservation-widget.d.ts +33 -0
- package/src/lib/components/reservation-widget.js +418 -0
- package/src/lib/components/reservation-widget.js.map +1 -0
- package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
- package/src/lib/components/storefront-payment-element-fallback.js +51 -0
- package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
- package/src/lib/components/storefront-payment-element.d.ts +78 -0
- package/src/lib/components/storefront-payment-element.js +156 -0
- package/src/lib/components/storefront-payment-element.js.map +1 -0
- package/src/lib/components/wishlist.d.ts +46 -0
- package/src/lib/components/wishlist.js +304 -0
- package/src/lib/components/wishlist.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +18 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/product-filters.d.ts +35 -0
- package/src/lib/constants/product-filters.js +109 -0
- package/src/lib/constants/product-filters.js.map +1 -0
- package/src/lib/model/commerce-cart.d.ts +52 -0
- package/src/lib/model/commerce-cart.js +102 -0
- package/src/lib/model/commerce-cart.js.map +1 -0
- package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
- package/src/lib/model/commerce-connect-transfer.js +231 -0
- package/src/lib/model/commerce-connect-transfer.js.map +1 -0
- package/src/lib/model/commerce-discounts.d.ts +164 -0
- package/src/lib/model/commerce-discounts.js +231 -0
- package/src/lib/model/commerce-discounts.js.map +1 -0
- package/src/lib/model/commerce-dispute.d.ts +124 -0
- package/src/lib/model/commerce-dispute.js +225 -0
- package/src/lib/model/commerce-dispute.js.map +1 -0
- package/src/lib/model/commerce-gift-cards.d.ts +107 -0
- package/src/lib/model/commerce-gift-cards.js +121 -0
- package/src/lib/model/commerce-gift-cards.js.map +1 -0
- package/src/lib/model/commerce-io.d.ts +36 -0
- package/src/lib/model/commerce-io.js +245 -0
- package/src/lib/model/commerce-io.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +1040 -0
- package/src/lib/model/commerce-orders.js +1022 -0
- package/src/lib/model/commerce-orders.js.map +1 -0
- package/src/lib/model/commerce-promotions.d.ts +188 -0
- package/src/lib/model/commerce-promotions.js +199 -0
- package/src/lib/model/commerce-promotions.js.map +1 -0
- package/src/lib/model/commerce-reservations.d.ts +175 -0
- package/src/lib/model/commerce-reservations.js +157 -0
- package/src/lib/model/commerce-reservations.js.map +1 -0
- package/src/lib/model/commerce-shipping.d.ts +316 -0
- package/src/lib/model/commerce-shipping.js +484 -0
- package/src/lib/model/commerce-shipping.js.map +1 -0
- package/src/lib/model/commerce-stock-holds.d.ts +199 -0
- package/src/lib/model/commerce-stock-holds.js +190 -0
- package/src/lib/model/commerce-stock-holds.js.map +1 -0
- package/src/lib/model/commerce-subscription-status.d.ts +67 -0
- package/src/lib/model/commerce-subscription-status.js +76 -0
- package/src/lib/model/commerce-subscription-status.js.map +1 -0
- package/src/lib/model/commerce-tax-decision.d.ts +222 -0
- package/src/lib/model/commerce-tax-decision.js +165 -0
- package/src/lib/model/commerce-tax-decision.js.map +1 -0
- package/src/lib/model/commerce-tax.d.ts +176 -0
- package/src/lib/model/commerce-tax.js +92 -0
- package/src/lib/model/commerce-tax.js.map +1 -0
- package/src/lib/model/commerce.d.ts +551 -0
- package/src/lib/model/commerce.js +739 -0
- package/src/lib/model/commerce.js.map +1 -0
- package/src/lib/model/index.d.ts +40 -0
- package/src/lib/model/index.js +40 -0
- package/src/lib/model/index.js.map +1 -0
- package/src/lib/model/order-figures.d.ts +48 -0
- package/src/lib/model/order-figures.js +74 -0
- package/src/lib/model/order-figures.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +23 -0
- package/src/lib/model/plugin-permissions.js +34 -0
- package/src/lib/model/plugin-permissions.js.map +1 -0
- package/src/lib/model/purchase-analytics.d.ts +186 -0
- package/src/lib/model/purchase-analytics.js +216 -0
- package/src/lib/model/purchase-analytics.js.map +1 -0
- package/src/lib/plugin-config.d.ts +62 -0
- package/src/lib/plugin-config.js +78 -0
- package/src/lib/plugin-config.js.map +1 -0
- package/src/lib/plugin.d.ts +28 -0
- package/src/lib/plugin.js +147 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/billing-webhook.d.ts +26 -0
- package/src/lib/server/billing-webhook.js +4011 -0
- package/src/lib/server/billing-webhook.js.map +1 -0
- package/src/lib/server/cancel-order.d.ts +87 -0
- package/src/lib/server/cancel-order.js +368 -0
- package/src/lib/server/cancel-order.js.map +1 -0
- package/src/lib/server/cart-checkout.d.ts +25 -0
- package/src/lib/server/cart-checkout.js +976 -0
- package/src/lib/server/cart-checkout.js.map +1 -0
- package/src/lib/server/cart-cookie.d.ts +32 -0
- package/src/lib/server/cart-cookie.js +77 -0
- package/src/lib/server/cart-cookie.js.map +1 -0
- package/src/lib/server/cart.d.ts +34 -0
- package/src/lib/server/cart.js +181 -0
- package/src/lib/server/cart.js.map +1 -0
- package/src/lib/server/catalog.d.ts +127 -0
- package/src/lib/server/catalog.js +277 -0
- package/src/lib/server/catalog.js.map +1 -0
- package/src/lib/server/checkout.d.ts +36 -0
- package/src/lib/server/checkout.js +915 -0
- package/src/lib/server/checkout.js.map +1 -0
- package/src/lib/server/connect.d.ts +26 -0
- package/src/lib/server/connect.js +238 -0
- package/src/lib/server/connect.js.map +1 -0
- package/src/lib/server/contact-refund.d.ts +117 -0
- package/src/lib/server/contact-refund.js +196 -0
- package/src/lib/server/contact-refund.js.map +1 -0
- package/src/lib/server/download.d.ts +39 -0
- package/src/lib/server/download.js +206 -0
- package/src/lib/server/download.js.map +1 -0
- package/src/lib/server/draft-order.d.ts +26 -0
- package/src/lib/server/draft-order.js +706 -0
- package/src/lib/server/draft-order.js.map +1 -0
- package/src/lib/server/feed.d.ts +24 -0
- package/src/lib/server/feed.js +59 -0
- package/src/lib/server/feed.js.map +1 -0
- package/src/lib/server/fulfill-order.d.ts +97 -0
- package/src/lib/server/fulfill-order.js +235 -0
- package/src/lib/server/fulfill-order.js.map +1 -0
- package/src/lib/server/gate.d.ts +36 -0
- package/src/lib/server/gate.js +112 -0
- package/src/lib/server/gate.js.map +1 -0
- package/src/lib/server/gift-cards.d.ts +42 -0
- package/src/lib/server/gift-cards.js +219 -0
- package/src/lib/server/gift-cards.js.map +1 -0
- package/src/lib/server/low-stock.d.ts +49 -0
- package/src/lib/server/low-stock.js +60 -0
- package/src/lib/server/low-stock.js.map +1 -0
- package/src/lib/server/manual-tax-rate.d.ts +82 -0
- package/src/lib/server/manual-tax-rate.js +113 -0
- package/src/lib/server/manual-tax-rate.js.map +1 -0
- package/src/lib/server/member-feed.d.ts +24 -0
- package/src/lib/server/member-feed.js +72 -0
- package/src/lib/server/member-feed.js.map +1 -0
- package/src/lib/server/member-name-search.d.ts +37 -0
- package/src/lib/server/member-name-search.js +42 -0
- package/src/lib/server/member-name-search.js.map +1 -0
- package/src/lib/server/member-post.d.ts +23 -0
- package/src/lib/server/member-post.js +166 -0
- package/src/lib/server/member-post.js.map +1 -0
- package/src/lib/server/membership-account.d.ts +37 -0
- package/src/lib/server/membership-account.js +148 -0
- package/src/lib/server/membership-account.js.map +1 -0
- package/src/lib/server/membership-admin-password.d.ts +33 -0
- package/src/lib/server/membership-admin-password.js +202 -0
- package/src/lib/server/membership-admin-password.js.map +1 -0
- package/src/lib/server/membership-content.d.ts +23 -0
- package/src/lib/server/membership-content.js +105 -0
- package/src/lib/server/membership-content.js.map +1 -0
- package/src/lib/server/membership-login.d.ts +19 -0
- package/src/lib/server/membership-login.js +137 -0
- package/src/lib/server/membership-login.js.map +1 -0
- package/src/lib/server/membership-logout.d.ts +19 -0
- package/src/lib/server/membership-logout.js +35 -0
- package/src/lib/server/membership-logout.js.map +1 -0
- package/src/lib/server/membership-recover.d.ts +60 -0
- package/src/lib/server/membership-recover.js +244 -0
- package/src/lib/server/membership-recover.js.map +1 -0
- package/src/lib/server/membership-register.d.ts +22 -0
- package/src/lib/server/membership-register.js +241 -0
- package/src/lib/server/membership-register.js.map +1 -0
- package/src/lib/server/membership-reset.d.ts +26 -0
- package/src/lib/server/membership-reset.js +88 -0
- package/src/lib/server/membership-reset.js.map +1 -0
- package/src/lib/server/membership-wishlist.d.ts +23 -0
- package/src/lib/server/membership-wishlist.js +89 -0
- package/src/lib/server/membership-wishlist.js.map +1 -0
- package/src/lib/server/membership.d.ts +96 -0
- package/src/lib/server/membership.js +222 -0
- package/src/lib/server/membership.js.map +1 -0
- package/src/lib/server/native-checkout.d.ts +170 -0
- package/src/lib/server/native-checkout.js +193 -0
- package/src/lib/server/native-checkout.js.map +1 -0
- package/src/lib/server/newsletter.d.ts +23 -0
- package/src/lib/server/newsletter.js +323 -0
- package/src/lib/server/newsletter.js.map +1 -0
- package/src/lib/server/notify-restock.d.ts +22 -0
- package/src/lib/server/notify-restock.js +84 -0
- package/src/lib/server/notify-restock.js.map +1 -0
- package/src/lib/server/order-analytics.d.ts +134 -0
- package/src/lib/server/order-analytics.js +263 -0
- package/src/lib/server/order-analytics.js.map +1 -0
- package/src/lib/server/order-figures.d.ts +33 -0
- package/src/lib/server/order-figures.js +220 -0
- package/src/lib/server/order-figures.js.map +1 -0
- package/src/lib/server/paid-media-delivery.d.ts +173 -0
- package/src/lib/server/paid-media-delivery.js +212 -0
- package/src/lib/server/paid-media-delivery.js.map +1 -0
- package/src/lib/server/pos-order.d.ts +54 -0
- package/src/lib/server/pos-order.js +1137 -0
- package/src/lib/server/pos-order.js.map +1 -0
- package/src/lib/server/process-abandoned.d.ts +54 -0
- package/src/lib/server/process-abandoned.js +222 -0
- package/src/lib/server/process-abandoned.js.map +1 -0
- package/src/lib/server/process-restock.d.ts +42 -0
- package/src/lib/server/process-restock.js +219 -0
- package/src/lib/server/process-restock.js.map +1 -0
- package/src/lib/server/product-card.d.ts +29 -0
- package/src/lib/server/product-card.js +54 -0
- package/src/lib/server/product-card.js.map +1 -0
- package/src/lib/server/product.d.ts +70 -0
- package/src/lib/server/product.js +105 -0
- package/src/lib/server/product.js.map +1 -0
- package/src/lib/server/promotion-hold.d.ts +144 -0
- package/src/lib/server/promotion-hold.js +174 -0
- package/src/lib/server/promotion-hold.js.map +1 -0
- package/src/lib/server/reconcile-stock.d.ts +106 -0
- package/src/lib/server/reconcile-stock.js +349 -0
- package/src/lib/server/reconcile-stock.js.map +1 -0
- package/src/lib/server/refund.d.ts +45 -0
- package/src/lib/server/refund.js +607 -0
- package/src/lib/server/refund.js.map +1 -0
- package/src/lib/server/related.d.ts +24 -0
- package/src/lib/server/related.js +104 -0
- package/src/lib/server/related.js.map +1 -0
- package/src/lib/server/reservation-availability.d.ts +23 -0
- package/src/lib/server/reservation-availability.js +111 -0
- package/src/lib/server/reservation-availability.js.map +1 -0
- package/src/lib/server/reserve-stock.d.ts +156 -0
- package/src/lib/server/reserve-stock.js +146 -0
- package/src/lib/server/reserve-stock.js.map +1 -0
- package/src/lib/server/reserve.d.ts +25 -0
- package/src/lib/server/reserve.js +426 -0
- package/src/lib/server/reserve.js.map +1 -0
- package/src/lib/server/restock-flag.d.ts +202 -0
- package/src/lib/server/restock-flag.js +449 -0
- package/src/lib/server/restock-flag.js.map +1 -0
- package/src/lib/server/reviews.d.ts +51 -0
- package/src/lib/server/reviews.js +132 -0
- package/src/lib/server/reviews.js.map +1 -0
- package/src/lib/server/site-page-enricher.d.ts +42 -0
- package/src/lib/server/site-page-enricher.js +149 -0
- package/src/lib/server/site-page-enricher.js.map +1 -0
- package/src/lib/server/site-page-resolver.d.ts +26 -0
- package/src/lib/server/site-page-resolver.js +223 -0
- package/src/lib/server/site-page-resolver.js.map +1 -0
- package/src/lib/server/stock-hold.d.ts +127 -0
- package/src/lib/server/stock-hold.js +258 -0
- package/src/lib/server/stock-hold.js.map +1 -0
- package/src/lib/server/storefront-tax-record.d.ts +22 -0
- package/src/lib/server/storefront-tax-record.js +218 -0
- package/src/lib/server/storefront-tax-record.js.map +1 -0
- package/src/lib/server/storefront-tax.d.ts +197 -0
- package/src/lib/server/storefront-tax.js +245 -0
- package/src/lib/server/storefront-tax.js.map +1 -0
- package/src/lib/server/stream.d.ts +25 -0
- package/src/lib/server/stream.js +191 -0
- package/src/lib/server/stream.js.map +1 -0
- package/src/lib/server/subscription-portal.d.ts +24 -0
- package/src/lib/server/subscription-portal.js +91 -0
- package/src/lib/server/subscription-portal.js.map +1 -0
- package/src/lib/server/supplier-outbox.d.ts +190 -0
- package/src/lib/server/supplier-outbox.js +342 -0
- package/src/lib/server/supplier-outbox.js.map +1 -0
- package/src/lib/server/supplier-update.d.ts +23 -0
- package/src/lib/server/supplier-update.js +289 -0
- package/src/lib/server/supplier-update.js.map +1 -0
- package/src/lib/server/tax-profile.d.ts +29 -0
- package/src/lib/server/tax-profile.js +40 -0
- package/src/lib/server/tax-profile.js.map +1 -0
- package/src/lib/server.d.ts +32 -0
- package/src/lib/server.js +311 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/site.d.ts +27 -0
- package/src/lib/site.js +134 -0
- package/src/lib/site.js.map +1 -0
- package/src/lib/utils/escape-html.d.ts +41 -0
- package/src/lib/utils/escape-html.js +41 -0
- package/src/lib/utils/escape-html.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/member-continue.d.ts +45 -0
- package/src/lib/utils/member-continue.js +49 -0
- package/src/lib/utils/member-continue.js.map +1 -0
- package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
- package/src/lib/utils/use-storefront-purchase-event.js +142 -0
- package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
|
+
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
19
|
+
import { Chip, Divider, Stack, Typography } from "@mui/material";
|
|
20
|
+
import { collection } from "firebase/firestore";
|
|
21
|
+
import { useMemo } from "react";
|
|
22
|
+
import { ceilingedWindow, collectionCeiling, useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
|
|
23
|
+
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
24
|
+
import { EntitlementUpsell, useCommerceEntitlement } from "./entitlement-gate.component.js";
|
|
25
|
+
/** `process-abandoned.ts` waits this long before it will remind a checkout. */ const REMIND_AFTER_MS = 60 * 60 * 1000;
|
|
26
|
+
/** …and gives up after this, marking the checkout `expired`. */ const GIVE_UP_AFTER_MS = 7 * 24 * 60 * 60 * 1000;
|
|
27
|
+
const recoveryHelp = pluginDocsHelp('commerce', {
|
|
28
|
+
anchor: '#recovery-and-alerts',
|
|
29
|
+
title: 'Recovery & alerts',
|
|
30
|
+
excerpt: 'Shoppers who left a checkout unfinished, and shoppers waiting to be ' + 'told a sold-out product is back. Both are emailed automatically.'
|
|
31
|
+
});
|
|
32
|
+
const relative = (atMs)=>{
|
|
33
|
+
if (!atMs) return '—';
|
|
34
|
+
const minutes = Math.max(0, Math.round((Date.now() - atMs) / 60000));
|
|
35
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
36
|
+
const hours = Math.round(minutes / 60);
|
|
37
|
+
if (hours < 48) return `${hours}h ago`;
|
|
38
|
+
return `${Math.round(hours / 24)}d ago`;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* How many documents each set of counters may be computed from.
|
|
42
|
+
*
|
|
43
|
+
* Every figure this card renders is a COUNT, so neither read can be paged — a
|
|
44
|
+
* tally over page one is not a tally. What makes a count trustworthy instead
|
|
45
|
+
* is that the walk reaching it is total, which is why both ask through
|
|
46
|
+
* `collectionCeiling` and order on the document name: an unordered cap returns
|
|
47
|
+
* a pseudo-random slice, and a count over a random slice is an undercount with
|
|
48
|
+
* nothing on screen to suggest it.
|
|
49
|
+
*
|
|
50
|
+
* These chips claim to mirror what `scanAbandonedCheckouts` will act on, so a
|
|
51
|
+
* ceiling that bites has to say so rather than quietly report a smaller queue
|
|
52
|
+
* than the job will find.
|
|
53
|
+
*/ const CHECKOUT_CEILING = 200;
|
|
54
|
+
const ALERT_CEILING = 200;
|
|
55
|
+
/**
|
|
56
|
+
* Recovery & alerts (AGL-2227).
|
|
57
|
+
*
|
|
58
|
+
* Two queues the storefront fills and a background job drains, neither of
|
|
59
|
+
* which the console showed at all:
|
|
60
|
+
*
|
|
61
|
+
* - **Abandoned checkouts** — `hosts/{hostId}/checkouts` with `status: 'open'`.
|
|
62
|
+
* `scanAbandonedCheckouts` emails one reminder per checkout that carries an
|
|
63
|
+
* email and has been sitting for an hour, then stamps `remindedAtMs`.
|
|
64
|
+
* - **Back-in-stock alerts** — `hosts/{hostId}/restockAlerts` with a null
|
|
65
|
+
* `notifiedAtMs`. `scanRestockAlerts` mails them once the product has stock.
|
|
66
|
+
*
|
|
67
|
+
* Both scans were dark until AGL-2227 put them on the platform job beat. That
|
|
68
|
+
* is the reason this card exists rather than only the wiring: a background job
|
|
69
|
+
* is the one surface with no user to notice it has stopped, so the merchant
|
|
70
|
+
* needs somewhere the queue depth is visible. A queue that is always empty and
|
|
71
|
+
* a queue that is never drained look identical from outside.
|
|
72
|
+
*
|
|
73
|
+
* Read-only, and deliberately so. The counts come from the same documents the
|
|
74
|
+
* scans read; nothing here writes, so this card cannot disagree with the job
|
|
75
|
+
* about what is owed. Sending is the job's to do — a "send now" button would
|
|
76
|
+
* be a second sender racing a beat that runs every 15 minutes, for a reminder
|
|
77
|
+
* the merchant cannot un-send.
|
|
78
|
+
*
|
|
79
|
+
* The abandoned half is entitlement-gated in place rather than gating the
|
|
80
|
+
* whole card: `abandonedCart` is Pro, back-in-stock alerts are on every plan
|
|
81
|
+
* that has commerce, and `EntitlementGatedCard` would have hidden the free
|
|
82
|
+
* half behind the paid one. `ready` is load-bearing for the same reason it is
|
|
83
|
+
* everywhere else — `checkEntitlement(undefined)` resolves the FREE tier, so
|
|
84
|
+
* refusing before the org doc lands accuses a paying customer.
|
|
85
|
+
*/ export function RecoveryQueueCard(props) {
|
|
86
|
+
const { hostId } = props;
|
|
87
|
+
const firestore = useFirestore();
|
|
88
|
+
const { ready, entitled, upgradeHref, planLabel } = useCommerceEntitlement(hostId, 'abandonedCart');
|
|
89
|
+
const { data: checkoutDocs } = useFirestoreCollection(()=>collectionCeiling(collection(firestore, 'hosts', hostId, 'checkouts'), CHECKOUT_CEILING), [
|
|
90
|
+
firestore,
|
|
91
|
+
hostId
|
|
92
|
+
], {
|
|
93
|
+
idField: '$id'
|
|
94
|
+
});
|
|
95
|
+
const { data: alertDocs } = useFirestoreCollection(()=>collectionCeiling(collection(firestore, 'hosts', hostId, 'restockAlerts'), ALERT_CEILING), [
|
|
96
|
+
firestore,
|
|
97
|
+
hostId
|
|
98
|
+
], {
|
|
99
|
+
idField: '$id'
|
|
100
|
+
});
|
|
101
|
+
const checkoutWindow = useMemo(()=>ceilingedWindow(checkoutDocs != null ? checkoutDocs : undefined, CHECKOUT_CEILING), [
|
|
102
|
+
checkoutDocs
|
|
103
|
+
]);
|
|
104
|
+
const alertWindow = useMemo(()=>ceilingedWindow(alertDocs != null ? alertDocs : undefined, ALERT_CEILING), [
|
|
105
|
+
alertDocs
|
|
106
|
+
]);
|
|
107
|
+
const checkouts = useMemo(()=>{
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
// The same three tests `scanAbandonedCheckouts` applies, in the same
|
|
110
|
+
// order, so the number here is the number the job will act on rather
|
|
111
|
+
// than a looser "open checkouts" count that would always read higher.
|
|
112
|
+
const open = checkoutWindow.rows.filter((row)=>row.status === 'open' && row.email);
|
|
113
|
+
return {
|
|
114
|
+
reminded: open.filter((row)=>row.remindedAtMs).length,
|
|
115
|
+
due: open.filter((row)=>{
|
|
116
|
+
var _row_createdAtMs, _row_createdAtMs1;
|
|
117
|
+
return !row.remindedAtMs && now - Number((_row_createdAtMs = row.createdAtMs) != null ? _row_createdAtMs : 0) >= REMIND_AFTER_MS && now - Number((_row_createdAtMs1 = row.createdAtMs) != null ? _row_createdAtMs1 : 0) <= GIVE_UP_AFTER_MS;
|
|
118
|
+
}).length,
|
|
119
|
+
waiting: open.filter((row)=>{
|
|
120
|
+
var _row_createdAtMs;
|
|
121
|
+
return !row.remindedAtMs && now - Number((_row_createdAtMs = row.createdAtMs) != null ? _row_createdAtMs : 0) < REMIND_AFTER_MS;
|
|
122
|
+
}).length,
|
|
123
|
+
recent: [
|
|
124
|
+
...open
|
|
125
|
+
].sort((a, b)=>{
|
|
126
|
+
var _b_createdAtMs, _a_createdAtMs;
|
|
127
|
+
return ((_b_createdAtMs = b.createdAtMs) != null ? _b_createdAtMs : 0) - ((_a_createdAtMs = a.createdAtMs) != null ? _a_createdAtMs : 0);
|
|
128
|
+
}).slice(0, 5)
|
|
129
|
+
};
|
|
130
|
+
}, [
|
|
131
|
+
checkoutWindow
|
|
132
|
+
]);
|
|
133
|
+
const alerts = useMemo(()=>{
|
|
134
|
+
const rows = alertWindow.rows;
|
|
135
|
+
return {
|
|
136
|
+
pending: rows.filter((row)=>row.notifiedAtMs == null).length,
|
|
137
|
+
notified: rows.filter((row)=>row.notifiedAtMs != null && !row.skipped).length
|
|
138
|
+
};
|
|
139
|
+
}, [
|
|
140
|
+
alertWindow
|
|
141
|
+
]);
|
|
142
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
143
|
+
header: 'Recovery & alerts',
|
|
144
|
+
help: recoveryHelp,
|
|
145
|
+
contentGutterX: true,
|
|
146
|
+
contentGutterY: true,
|
|
147
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
148
|
+
spacing: 2,
|
|
149
|
+
children: [
|
|
150
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
151
|
+
spacing: 1,
|
|
152
|
+
children: [
|
|
153
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
154
|
+
variant: "subtitle2",
|
|
155
|
+
children: 'Abandoned checkouts'
|
|
156
|
+
}),
|
|
157
|
+
!ready ? /*#__PURE__*/ _jsx(Typography, {
|
|
158
|
+
variant: "body2",
|
|
159
|
+
color: "text.secondary",
|
|
160
|
+
children: 'Checking your plan…'
|
|
161
|
+
}) : entitled ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
162
|
+
children: [
|
|
163
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
164
|
+
direction: "row",
|
|
165
|
+
spacing: 1,
|
|
166
|
+
useFlexGap: true,
|
|
167
|
+
sx: {
|
|
168
|
+
flexWrap: 'wrap'
|
|
169
|
+
},
|
|
170
|
+
children: [
|
|
171
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
172
|
+
size: "small",
|
|
173
|
+
color: checkouts.due ? 'warning' : 'default',
|
|
174
|
+
label: `${checkouts.due} due a reminder`
|
|
175
|
+
}),
|
|
176
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
177
|
+
size: "small",
|
|
178
|
+
label: `${checkouts.waiting} still within the first hour`
|
|
179
|
+
}),
|
|
180
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
181
|
+
size: "small",
|
|
182
|
+
color: checkouts.reminded ? 'success' : 'default',
|
|
183
|
+
label: `${checkouts.reminded} reminded`
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
}),
|
|
187
|
+
checkoutWindow.truncated ? /*#__PURE__*/ _jsx(Typography, {
|
|
188
|
+
variant: "caption",
|
|
189
|
+
color: "text.secondary",
|
|
190
|
+
children: `Counted across ${CHECKOUT_CEILING} checkouts. The reminder job reads the rest; these figures do not.`
|
|
191
|
+
}) : null,
|
|
192
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
193
|
+
variant: "caption",
|
|
194
|
+
color: "text.secondary",
|
|
195
|
+
children: 'Reminders send automatically about 15 minutes after a ' + 'checkout has been idle for an hour. A checkout that is ' + 'completed stops reminding itself.'
|
|
196
|
+
}),
|
|
197
|
+
checkouts.recent.length ? /*#__PURE__*/ _jsx(Stack, {
|
|
198
|
+
spacing: 0.5,
|
|
199
|
+
children: checkouts.recent.map((row)=>/*#__PURE__*/ _jsx(Typography, {
|
|
200
|
+
variant: "body2",
|
|
201
|
+
children: `${row.email} · started ${relative(row.createdAtMs)}${row.remindedAtMs ? ` · reminded ${relative(row.remindedAtMs)}` : ''}`
|
|
202
|
+
}, row.$id))
|
|
203
|
+
}) : /*#__PURE__*/ _jsx(Typography, {
|
|
204
|
+
variant: "body2",
|
|
205
|
+
color: "text.secondary",
|
|
206
|
+
children: 'No open checkouts with an email address.'
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
}) : /*#__PURE__*/ _jsx(EntitlementUpsell, {
|
|
210
|
+
planLabel: planLabel,
|
|
211
|
+
upgradeHref: upgradeHref,
|
|
212
|
+
children: 'Abandoned checkout recovery emails a shopper who reached ' + 'checkout, entered their email and left, with a link straight ' + 'back to the cart they built.'
|
|
213
|
+
})
|
|
214
|
+
]
|
|
215
|
+
}),
|
|
216
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
217
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
218
|
+
spacing: 1,
|
|
219
|
+
children: [
|
|
220
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
221
|
+
variant: "subtitle2",
|
|
222
|
+
children: 'Back-in-stock alerts'
|
|
223
|
+
}),
|
|
224
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
225
|
+
direction: "row",
|
|
226
|
+
spacing: 1,
|
|
227
|
+
useFlexGap: true,
|
|
228
|
+
sx: {
|
|
229
|
+
flexWrap: 'wrap'
|
|
230
|
+
},
|
|
231
|
+
children: [
|
|
232
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
233
|
+
size: "small",
|
|
234
|
+
color: alerts.pending ? 'info' : 'default',
|
|
235
|
+
label: `${alerts.pending} shoppers waiting`
|
|
236
|
+
}),
|
|
237
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
238
|
+
size: "small",
|
|
239
|
+
label: `${alerts.notified} notified`
|
|
240
|
+
})
|
|
241
|
+
]
|
|
242
|
+
}),
|
|
243
|
+
alertWindow.truncated ? /*#__PURE__*/ _jsx(Typography, {
|
|
244
|
+
variant: "caption",
|
|
245
|
+
color: "text.secondary",
|
|
246
|
+
children: `Counted across ${ALERT_CEILING} alerts. The notify job reads the rest; these figures do not.`
|
|
247
|
+
}) : null,
|
|
248
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
249
|
+
variant: "caption",
|
|
250
|
+
color: "text.secondary",
|
|
251
|
+
children: 'Anyone who used “Notify me when it’s back” on a sold-out ' + 'product is emailed once its stock goes above zero. Waiting ' + 'shoppers are a demand signal worth restocking against.'
|
|
252
|
+
})
|
|
253
|
+
]
|
|
254
|
+
})
|
|
255
|
+
]
|
|
256
|
+
})
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
RecoveryQueueCard.displayName = 'RecoveryQueueCard';
|
|
260
|
+
export default RecoveryQueueCard;
|
|
261
|
+
|
|
262
|
+
//# sourceMappingURL=recovery-queue-card.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/recovery-queue-card.component.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'use client'\n\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Chip, Divider, Stack, Typography } from '@mui/material'\nimport { collection } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport {\n EntitlementUpsell,\n useCommerceEntitlement,\n} from './entitlement-gate.component'\n\nexport interface RecoveryQueueCardProps {\n hostId: string\n}\n\n/** `process-abandoned.ts` waits this long before it will remind a checkout. */\nconst REMIND_AFTER_MS = 60 * 60 * 1000\n/** …and gives up after this, marking the checkout `expired`. */\nconst GIVE_UP_AFTER_MS = 7 * 24 * 60 * 60 * 1000\n\nconst recoveryHelp = pluginDocsHelp('commerce', {\n anchor: '#recovery-and-alerts',\n title: 'Recovery & alerts',\n excerpt:\n 'Shoppers who left a checkout unfinished, and shoppers waiting to be ' +\n 'told a sold-out product is back. Both are emailed automatically.',\n})\n\nconst relative = (atMs: number | undefined): string => {\n if (!atMs) return '—'\n const minutes = Math.max(0, Math.round((Date.now() - atMs) / 60_000))\n if (minutes < 60) return `${minutes}m ago`\n const hours = Math.round(minutes / 60)\n if (hours < 48) return `${hours}h ago`\n return `${Math.round(hours / 24)}d ago`\n}\n\n/**\n * How many documents each set of counters may be computed from.\n *\n * Every figure this card renders is a COUNT, so neither read can be paged — a\n * tally over page one is not a tally. What makes a count trustworthy instead\n * is that the walk reaching it is total, which is why both ask through\n * `collectionCeiling` and order on the document name: an unordered cap returns\n * a pseudo-random slice, and a count over a random slice is an undercount with\n * nothing on screen to suggest it.\n *\n * These chips claim to mirror what `scanAbandonedCheckouts` will act on, so a\n * ceiling that bites has to say so rather than quietly report a smaller queue\n * than the job will find.\n */\nconst CHECKOUT_CEILING = 200\nconst ALERT_CEILING = 200\n\n/**\n * Recovery & alerts (AGL-2227).\n *\n * Two queues the storefront fills and a background job drains, neither of\n * which the console showed at all:\n *\n * - **Abandoned checkouts** — `hosts/{hostId}/checkouts` with `status: 'open'`.\n * `scanAbandonedCheckouts` emails one reminder per checkout that carries an\n * email and has been sitting for an hour, then stamps `remindedAtMs`.\n * - **Back-in-stock alerts** — `hosts/{hostId}/restockAlerts` with a null\n * `notifiedAtMs`. `scanRestockAlerts` mails them once the product has stock.\n *\n * Both scans were dark until AGL-2227 put them on the platform job beat. That\n * is the reason this card exists rather than only the wiring: a background job\n * is the one surface with no user to notice it has stopped, so the merchant\n * needs somewhere the queue depth is visible. A queue that is always empty and\n * a queue that is never drained look identical from outside.\n *\n * Read-only, and deliberately so. The counts come from the same documents the\n * scans read; nothing here writes, so this card cannot disagree with the job\n * about what is owed. Sending is the job's to do — a \"send now\" button would\n * be a second sender racing a beat that runs every 15 minutes, for a reminder\n * the merchant cannot un-send.\n *\n * The abandoned half is entitlement-gated in place rather than gating the\n * whole card: `abandonedCart` is Pro, back-in-stock alerts are on every plan\n * that has commerce, and `EntitlementGatedCard` would have hidden the free\n * half behind the paid one. `ready` is load-bearing for the same reason it is\n * everywhere else — `checkEntitlement(undefined)` resolves the FREE tier, so\n * refusing before the org doc lands accuses a paying customer.\n */\nexport function RecoveryQueueCard(props: RecoveryQueueCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { ready, entitled, upgradeHref, planLabel } = useCommerceEntitlement(\n hostId,\n 'abandonedCart',\n )\n\n const { data: checkoutDocs } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'checkouts'),\n CHECKOUT_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { data: alertDocs } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'restockAlerts'),\n ALERT_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const checkoutWindow = useMemo(\n () => ceilingedWindow<any>(checkoutDocs ?? undefined, CHECKOUT_CEILING),\n [checkoutDocs],\n )\n const alertWindow = useMemo(\n () => ceilingedWindow<any>(alertDocs ?? undefined, ALERT_CEILING),\n [alertDocs],\n )\n\n const checkouts = useMemo(() => {\n const now = Date.now()\n // The same three tests `scanAbandonedCheckouts` applies, in the same\n // order, so the number here is the number the job will act on rather\n // than a looser \"open checkouts\" count that would always read higher.\n const open = checkoutWindow.rows.filter(\n (row: any) => row.status === 'open' && row.email,\n )\n return {\n reminded: open.filter((row: any) => row.remindedAtMs).length,\n due: open.filter(\n (row: any) =>\n !row.remindedAtMs &&\n now - Number(row.createdAtMs ?? 0) >= REMIND_AFTER_MS &&\n now - Number(row.createdAtMs ?? 0) <= GIVE_UP_AFTER_MS,\n ).length,\n waiting: open.filter(\n (row: any) =>\n !row.remindedAtMs &&\n now - Number(row.createdAtMs ?? 0) < REMIND_AFTER_MS,\n ).length,\n recent: [...open]\n .sort((a: any, b: any) => (b.createdAtMs ?? 0) - (a.createdAtMs ?? 0))\n .slice(0, 5),\n }\n }, [checkoutWindow])\n\n const alerts = useMemo(() => {\n const rows = alertWindow.rows\n return {\n pending: rows.filter((row: any) => row.notifiedAtMs == null).length,\n notified: rows.filter(\n (row: any) => row.notifiedAtMs != null && !row.skipped,\n ).length,\n }\n }, [alertWindow])\n\n return (\n <CardDisplay\n header={'Recovery & alerts'}\n help={recoveryHelp}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Abandoned checkouts'}</Typography>\n {!ready ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Checking your plan…'}\n </Typography>\n ) : entitled ? (\n <>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n <Chip\n size=\"small\"\n color={checkouts.due ? 'warning' : 'default'}\n label={`${checkouts.due} due a reminder`}\n />\n <Chip\n size=\"small\"\n label={`${checkouts.waiting} still within the first hour`}\n />\n <Chip\n size=\"small\"\n color={checkouts.reminded ? 'success' : 'default'}\n label={`${checkouts.reminded} reminded`}\n />\n </Stack>\n {checkoutWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Counted across ${CHECKOUT_CEILING} checkouts. The reminder job reads the rest; these figures do not.`}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Reminders send automatically about 15 minutes after a ' +\n 'checkout has been idle for an hour. A checkout that is ' +\n 'completed stops reminding itself.'}\n </Typography>\n {checkouts.recent.length ? (\n <Stack spacing={0.5}>\n {checkouts.recent.map((row: any) => (\n <Typography key={row.$id} variant=\"body2\">\n {`${row.email} · started ${relative(row.createdAtMs)}${\n row.remindedAtMs\n ? ` · reminded ${relative(row.remindedAtMs)}`\n : ''\n }`}\n </Typography>\n ))}\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No open checkouts with an email address.'}\n </Typography>\n )}\n </>\n ) : (\n <EntitlementUpsell planLabel={planLabel} upgradeHref={upgradeHref}>\n {'Abandoned checkout recovery emails a shopper who reached ' +\n 'checkout, entered their email and left, with a link straight ' +\n 'back to the cart they built.'}\n </EntitlementUpsell>\n )}\n </Stack>\n <Divider />\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Back-in-stock alerts'}</Typography>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n <Chip\n size=\"small\"\n color={alerts.pending ? 'info' : 'default'}\n label={`${alerts.pending} shoppers waiting`}\n />\n <Chip size=\"small\" label={`${alerts.notified} notified`} />\n </Stack>\n {alertWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Counted across ${ALERT_CEILING} alerts. The notify job reads the rest; these figures do not.`}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Anyone who used “Notify me when it’s back” on a sold-out ' +\n 'product is emailed once its stock goes above zero. Waiting ' +\n 'shoppers are a demand signal worth restocking against.'}\n </Typography>\n </Stack>\n </Stack>\n </CardDisplay>\n )\n}\nRecoveryQueueCard.displayName = 'RecoveryQueueCard'\n\nexport default RecoveryQueueCard\n"],"names":["CardDisplay","Chip","Divider","Stack","Typography","collection","useMemo","ceilingedWindow","collectionCeiling","useFirestore","useFirestoreCollection","pluginDocsHelp","EntitlementUpsell","useCommerceEntitlement","REMIND_AFTER_MS","GIVE_UP_AFTER_MS","recoveryHelp","anchor","title","excerpt","relative","atMs","minutes","Math","max","round","Date","now","hours","CHECKOUT_CEILING","ALERT_CEILING","RecoveryQueueCard","props","hostId","firestore","ready","entitled","upgradeHref","planLabel","data","checkoutDocs","idField","alertDocs","checkoutWindow","undefined","alertWindow","checkouts","open","rows","filter","row","status","email","reminded","remindedAtMs","length","due","Number","createdAtMs","waiting","recent","sort","a","b","slice","alerts","pending","notifiedAtMs","notified","skipped","header","help","contentGutterX","contentGutterY","spacing","variant","color","direction","useFlexGap","sx","flexWrap","size","label","truncated","map","$id","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface RegistersCardProps {
|
|
2
|
+
hostId: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* POS registers (AGL-472): named registers under `hosts/{hostId}/registers`,
|
|
6
|
+
* capped by the plan's `posRegisters` quota (Pro 1, Business 2, Advanced 5)
|
|
7
|
+
* PLUS the register seats the org has allocated to this site out of the
|
|
8
|
+
* purchased $89/mo pool (AGL-1775). Creation rides the quota-enforcing
|
|
9
|
+
* resources API so the cap is authoritative; every POS sale stamps its
|
|
10
|
+
* register so takings are attributable.
|
|
11
|
+
*
|
|
12
|
+
* The add-on used to raise the org-level entitlement, which every site
|
|
13
|
+
* inherited — one purchase, `hostLimit` registers. It is a pool now, and the
|
|
14
|
+
* message below tells an owner which of the two things to do about an
|
|
15
|
+
* exhausted one: assign a seat they already own, or buy another.
|
|
16
|
+
*/
|
|
17
|
+
export declare function RegistersCard(props: RegistersCardProps): import("react").JSX.Element;
|
|
18
|
+
export declare namespace RegistersCard {
|
|
19
|
+
var displayName: string;
|
|
20
|
+
}
|
|
21
|
+
export default RegistersCard;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
import * as Aglyn from "@aglyn/aglyn";
|
|
20
|
+
import * as CommerceModel from "../../model/index.js";
|
|
21
|
+
import { CardDisplay, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
22
|
+
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
23
|
+
import { Button, Chip, MenuItem, Stack, TextField, Typography } from "@mui/material";
|
|
24
|
+
import { collection, deleteDoc, doc, getCountFromServer, limit, query } from "firebase/firestore";
|
|
25
|
+
import { useCallback, useEffect, useState } from "react";
|
|
26
|
+
import { useFirestore, useFirestoreCollection, useHostResourceApi, useOrgPlan } from "@aglyn/tenant-feature-instance";
|
|
27
|
+
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
28
|
+
/**
|
|
29
|
+
* POS registers (AGL-472): named registers under `hosts/{hostId}/registers`,
|
|
30
|
+
* capped by the plan's `posRegisters` quota (Pro 1, Business 2, Advanced 5)
|
|
31
|
+
* PLUS the register seats the org has allocated to this site out of the
|
|
32
|
+
* purchased $89/mo pool (AGL-1775). Creation rides the quota-enforcing
|
|
33
|
+
* resources API so the cap is authoritative; every POS sale stamps its
|
|
34
|
+
* register so takings are attributable.
|
|
35
|
+
*
|
|
36
|
+
* The add-on used to raise the org-level entitlement, which every site
|
|
37
|
+
* inherited — one purchase, `hostLimit` registers. It is a pool now, and the
|
|
38
|
+
* message below tells an owner which of the two things to do about an
|
|
39
|
+
* exhausted one: assign a seat they already own, or buy another.
|
|
40
|
+
*/ export function RegistersCard(props) {
|
|
41
|
+
const { hostId } = props;
|
|
42
|
+
const firestore = useFirestore();
|
|
43
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
44
|
+
const { confirm } = useConfirmationContext();
|
|
45
|
+
const createHostResource = useHostResourceApi();
|
|
46
|
+
const { org, ready: planReady } = useOrgPlan(hostId);
|
|
47
|
+
const { data: registerDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)), [
|
|
48
|
+
firestore,
|
|
49
|
+
hostId
|
|
50
|
+
], {
|
|
51
|
+
idField: '$id'
|
|
52
|
+
});
|
|
53
|
+
const { data: locationDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'locations'), limit(25)), [
|
|
54
|
+
firestore,
|
|
55
|
+
hostId
|
|
56
|
+
], {
|
|
57
|
+
idField: '$id'
|
|
58
|
+
});
|
|
59
|
+
const registers = [
|
|
60
|
+
...registerDocs != null ? registerDocs : []
|
|
61
|
+
].sort((a, b)=>{
|
|
62
|
+
var _a_name, _b_name;
|
|
63
|
+
return String((_a_name = a.name) != null ? _a_name : '').localeCompare(String((_b_name = b.name) != null ? _b_name : ''));
|
|
64
|
+
});
|
|
65
|
+
const locations = locationDocs != null ? locationDocs : [];
|
|
66
|
+
/**
|
|
67
|
+
* The register HEAD-COUNT is a server aggregate, not the length of the
|
|
68
|
+
* capped listener (AGL-1738, the ninth instance of AGL-1716's AGL-1706
|
|
69
|
+
* shape — filed as latent, made real when the clamp was declined).
|
|
70
|
+
*
|
|
71
|
+
* The listener is `limit(25)` and the stock `posRegisters` bands top out
|
|
72
|
+
* at agency's 20 — under the window — but the $89/mo register add-on is
|
|
73
|
+
* sold flat up to `POS_REGISTERS_ADDON_MAX` (50) on any plan carrying
|
|
74
|
+
* `pos`, so an agency org's effective limit reaches 70. From the 26th
|
|
75
|
+
* register the listener saturates and the card understated usage in the
|
|
76
|
+
* flattering direction while `api/hosts/resources`, which counts the
|
|
77
|
+
* collection, refused the add.
|
|
78
|
+
*
|
|
79
|
+
* Re-read after an add AND a delete: registers are hard-deleted here
|
|
80
|
+
* (like locations, unlike the soft-deleting cards), so a removal really
|
|
81
|
+
* does free a slot on both sides, and a one-shot that missed it would
|
|
82
|
+
* keep refusing.
|
|
83
|
+
*/ const [registerCountEpoch, setRegisterCountEpoch] = useState(0);
|
|
84
|
+
const [serverRegisterCount, setServerRegisterCount] = useState(null);
|
|
85
|
+
useEffect(()=>{
|
|
86
|
+
let active = true;
|
|
87
|
+
void getCountFromServer(collection(firestore, 'hosts', hostId, 'registers')).then((snapshot)=>{
|
|
88
|
+
if (active) setServerRegisterCount(snapshot.data().count);
|
|
89
|
+
}).catch(()=>{
|
|
90
|
+
// Falls back to the loaded rows — a LOWER bound and the prior
|
|
91
|
+
// behaviour, never 0, which reads as "no registers used" on a site
|
|
92
|
+
// that is over its cap.
|
|
93
|
+
});
|
|
94
|
+
return ()=>{
|
|
95
|
+
active = false;
|
|
96
|
+
};
|
|
97
|
+
}, [
|
|
98
|
+
firestore,
|
|
99
|
+
hostId,
|
|
100
|
+
registerCountEpoch
|
|
101
|
+
]);
|
|
102
|
+
const registerCount = serverRegisterCount != null ? serverRegisterCount : registers.length;
|
|
103
|
+
// Per SITE (AGL-1775), not the org-level value: the plan's cap plus this
|
|
104
|
+
// host's allocated seats. The allocation rides the SAME org doc `useOrgPlan`
|
|
105
|
+
// already returns, so there is no second read to be loading or to fail —
|
|
106
|
+
// and an unallocated (or not-yet-arrived) org resolves to the plan cap,
|
|
107
|
+
// never to the pool.
|
|
108
|
+
const quota = Aglyn.checkHostRegisterQuota(org, hostId, registerCount);
|
|
109
|
+
const registerPool = Aglyn.resolveRegisterSeatPool(org);
|
|
110
|
+
// Registers beyond the plan cap (e.g. after a downgrade) can't transact —
|
|
111
|
+
// pos-order.ts blocks them by creation rank (AGL-482); mirror that here.
|
|
112
|
+
//
|
|
113
|
+
// Only once the org doc has arrived (AGL-1064). An absent org resolves to
|
|
114
|
+
// the free tier's `posRegisters: 0`, which would badge EVERY register
|
|
115
|
+
// "Over plan limit" for the first render or two of every mount.
|
|
116
|
+
const withinCap = planReady ? CommerceModel.registersWithinCap(registers, quota.limit) : new Set(registers.map((register)=>register.$id));
|
|
117
|
+
const [name, setName] = useState('');
|
|
118
|
+
const [locationId, setLocationId] = useState('');
|
|
119
|
+
const handleAdd = useCallback(async ()=>{
|
|
120
|
+
if (!name.trim()) return;
|
|
121
|
+
// The button is disabled until the plan is known; this guards the case
|
|
122
|
+
// where a click and the org doc race (AGL-1064).
|
|
123
|
+
if (!planReady) return;
|
|
124
|
+
if (!quota.allowed) {
|
|
125
|
+
// Three different answers, because the fix differs (AGL-1775). An
|
|
126
|
+
// exhausted POOL is a purchase; an UNASSIGNED seat the org already owns
|
|
127
|
+
// is a click, and telling that owner to buy another would sell them a
|
|
128
|
+
// register they are already paying for.
|
|
129
|
+
return void enqueueSnackbar(quota.limit === 0 ? 'POS registers require the Pro plan or above — see Billing' : registerPool.available > 0 ? `This site can run ${quota.limit} register${quota.limit === 1 ? '' : 's'} — you have ${registerPool.available} unassigned register seat${registerPool.available === 1 ? '' : 's'}; assign one to this site in Billing → Add-ons` : `This site can run ${quota.limit} register${quota.limit === 1 ? '' : 's'} and every purchased seat is assigned — add another from ` + 'Billing → Add-ons ($89/mo each)', {
|
|
130
|
+
variant: 'info',
|
|
131
|
+
persist: false
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
// Creation rides the quota-enforcing resources API (AGL-472/473).
|
|
136
|
+
await createHostResource({
|
|
137
|
+
hostId,
|
|
138
|
+
resource: 'register',
|
|
139
|
+
data: _extends({
|
|
140
|
+
name: name.trim().slice(0, 80)
|
|
141
|
+
}, locationId ? {
|
|
142
|
+
locationId
|
|
143
|
+
} : {})
|
|
144
|
+
});
|
|
145
|
+
setName('');
|
|
146
|
+
setLocationId('');
|
|
147
|
+
setRegisterCountEpoch((epoch)=>epoch + 1);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
var _ref;
|
|
150
|
+
enqueueSnackbar((_ref = error == null ? void 0 : error.message) != null ? _ref : 'Could not add register', {
|
|
151
|
+
variant: 'warning',
|
|
152
|
+
persist: false
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}, [
|
|
156
|
+
name,
|
|
157
|
+
locationId,
|
|
158
|
+
planReady,
|
|
159
|
+
quota,
|
|
160
|
+
hostId,
|
|
161
|
+
createHostResource,
|
|
162
|
+
enqueueSnackbar
|
|
163
|
+
]);
|
|
164
|
+
const handleDelete = useCallback((register)=>async ()=>{
|
|
165
|
+
const confirmed = await confirm({
|
|
166
|
+
title: 'Remove this register?',
|
|
167
|
+
description: `"${register.name}" stops being available at checkout. Past ` + 'sales keep their register tag.',
|
|
168
|
+
confirmationText: 'Remove',
|
|
169
|
+
confirmationButtonProps: {
|
|
170
|
+
color: 'error'
|
|
171
|
+
}
|
|
172
|
+
}).then(()=>true).catch(()=>false);
|
|
173
|
+
if (!confirmed) return;
|
|
174
|
+
await deleteDoc(doc(firestore, 'hosts', hostId, 'registers', register.$id));
|
|
175
|
+
// A HARD delete, so the slot really is freed on both sides — the
|
|
176
|
+
// one-shot aggregate has to be told (AGL-1716/AGL-1738).
|
|
177
|
+
setRegisterCountEpoch((epoch)=>epoch + 1);
|
|
178
|
+
}, [
|
|
179
|
+
confirm,
|
|
180
|
+
firestore,
|
|
181
|
+
hostId
|
|
182
|
+
]);
|
|
183
|
+
const locationName = (id)=>{
|
|
184
|
+
var _locations_find;
|
|
185
|
+
return (_locations_find = locations.find((location)=>location.$id === id)) == null ? void 0 : _locations_find.name;
|
|
186
|
+
};
|
|
187
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
188
|
+
header: 'POS registers',
|
|
189
|
+
help: pluginDocsHelp('pos', {
|
|
190
|
+
anchor: '#registers'
|
|
191
|
+
}),
|
|
192
|
+
contentGutterX: true,
|
|
193
|
+
contentGutterY: true,
|
|
194
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
195
|
+
spacing: 1,
|
|
196
|
+
children: [
|
|
197
|
+
registers.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
|
|
198
|
+
variant: "body2",
|
|
199
|
+
color: "text.secondary",
|
|
200
|
+
children: 'Name each till or device that takes in-person payments. Every ' + 'POS sale is tagged with its register for end-of-day takings.'
|
|
201
|
+
}) : registers.map((register)=>{
|
|
202
|
+
const overCap = !withinCap.has(register.$id);
|
|
203
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
204
|
+
direction: "row",
|
|
205
|
+
spacing: 1,
|
|
206
|
+
sx: {
|
|
207
|
+
alignItems: 'center',
|
|
208
|
+
opacity: overCap ? 0.6 : 1
|
|
209
|
+
},
|
|
210
|
+
children: [
|
|
211
|
+
/*#__PURE__*/ _jsxs(Typography, {
|
|
212
|
+
variant: "body2",
|
|
213
|
+
sx: {
|
|
214
|
+
flex: 1
|
|
215
|
+
},
|
|
216
|
+
noWrap: true,
|
|
217
|
+
children: [
|
|
218
|
+
register.name,
|
|
219
|
+
register.locationId && locationName(register.locationId) ? /*#__PURE__*/ _jsx(Typography, {
|
|
220
|
+
component: "span",
|
|
221
|
+
variant: "caption",
|
|
222
|
+
color: "text.secondary",
|
|
223
|
+
children: ` · ${locationName(register.locationId)}`
|
|
224
|
+
}) : null
|
|
225
|
+
]
|
|
226
|
+
}),
|
|
227
|
+
overCap ? /*#__PURE__*/ _jsx(Chip, {
|
|
228
|
+
label: "Over plan limit",
|
|
229
|
+
size: "small",
|
|
230
|
+
color: "warning",
|
|
231
|
+
variant: "outlined"
|
|
232
|
+
}) : null,
|
|
233
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
234
|
+
size: "small",
|
|
235
|
+
color: "error",
|
|
236
|
+
onClick: handleDelete(register),
|
|
237
|
+
children: 'Remove'
|
|
238
|
+
})
|
|
239
|
+
]
|
|
240
|
+
}, register.$id);
|
|
241
|
+
}),
|
|
242
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
243
|
+
direction: "row",
|
|
244
|
+
spacing: 1,
|
|
245
|
+
children: [
|
|
246
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
247
|
+
label: "New register",
|
|
248
|
+
value: name,
|
|
249
|
+
onChange: (event)=>setName(event.target.value),
|
|
250
|
+
size: "small",
|
|
251
|
+
sx: {
|
|
252
|
+
flex: 1
|
|
253
|
+
},
|
|
254
|
+
placeholder: "Front counter"
|
|
255
|
+
}),
|
|
256
|
+
locations.length > 1 ? /*#__PURE__*/ _jsxs(TextField, {
|
|
257
|
+
select: true,
|
|
258
|
+
label: "Location",
|
|
259
|
+
value: locationId,
|
|
260
|
+
onChange: (event)=>setLocationId(event.target.value),
|
|
261
|
+
size: "small",
|
|
262
|
+
sx: {
|
|
263
|
+
minWidth: 140
|
|
264
|
+
},
|
|
265
|
+
children: [
|
|
266
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
267
|
+
value: "",
|
|
268
|
+
children: 'Any'
|
|
269
|
+
}),
|
|
270
|
+
locations.map((location)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
271
|
+
value: location.$id,
|
|
272
|
+
children: location.name
|
|
273
|
+
}, location.$id))
|
|
274
|
+
]
|
|
275
|
+
}) : null,
|
|
276
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
277
|
+
size: "small",
|
|
278
|
+
disabled: !name.trim() || !planReady,
|
|
279
|
+
onClick: handleAdd,
|
|
280
|
+
children: 'Add'
|
|
281
|
+
})
|
|
282
|
+
]
|
|
283
|
+
}),
|
|
284
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
285
|
+
variant: "caption",
|
|
286
|
+
color: "text.secondary",
|
|
287
|
+
children: planReady ? `${registerCount}/${quota.limit === Aglyn.UNLIMITED ? '∞' : quota.limit} registers on your plan` : `${registerCount} register${registerCount === 1 ? '' : 's'} · checking your plan…`
|
|
288
|
+
})
|
|
289
|
+
]
|
|
290
|
+
})
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
RegistersCard.displayName = 'RegistersCard';
|
|
294
|
+
export default RegistersCard;
|
|
295
|
+
|
|
296
|
+
//# sourceMappingURL=registers-card.component.js.map
|