@nextblock-cms/ecom 0.21.0 → 0.21.1
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 +43 -0
- package/index.cjs +1 -0
- package/lib/CurrencyProvider.cjs +1 -0
- package/lib/CurrencyProvider.es.js +1 -1
- package/lib/PaymentReadinessProvider.cjs +1 -0
- package/lib/PaymentReadinessProvider.es.js +1 -1
- package/lib/cart-store.cjs +1 -0
- package/lib/cart-store.es.js +1 -1
- package/lib/components/AccountNavigationMenu.cjs +1 -0
- package/lib/components/AccountNavigationMenu.es.js +1 -1
- package/lib/components/AddToCartButton.cjs +1 -0
- package/lib/components/AddToCartButton.es.js +1 -1
- package/lib/components/Cart.cjs +1 -0
- package/lib/components/Cart.es.js +1 -1
- package/lib/components/CartDrawer.cjs +1 -0
- package/lib/components/CartDrawer.es.js +1 -1
- package/lib/components/CartIcon.cjs +1 -0
- package/lib/components/CartIcon.es.js +1 -1
- package/lib/components/Checkout.cjs +1 -0
- package/lib/components/Checkout.es.js +1 -1
- package/lib/components/CouponForm.cjs +1 -0
- package/lib/components/CouponForm.es.js +1 -1
- package/lib/components/CurrencySwitcher.cjs +1 -0
- package/lib/components/CurrencySwitcher.es.js +1 -1
- package/lib/components/CustomerProfileForm.cjs +1 -0
- package/lib/components/CustomerProfileForm.es.js +1 -1
- package/lib/components/FeaturedProduct.cjs +1 -0
- package/lib/components/FeaturedProduct.es.js +1 -1
- package/lib/components/FreemiusLicensePanel.cjs +1 -0
- package/lib/components/FreemiusLicensePanel.es.js +1 -1
- package/lib/components/InvoiceDocument.cjs +1 -0
- package/lib/components/InvoiceDocument.es.js +1 -1
- package/lib/components/{InvoiceViewerShell.cjs.js → InvoiceViewerShell.cjs} +1 -1
- package/lib/components/InvoiceViewerShell.es.js +1 -1
- package/lib/components/ProductCard.cjs +1 -0
- package/lib/components/ProductCard.es.js +1 -1
- package/lib/components/ProductDetailsLayout.cjs +1 -0
- package/lib/components/ProductDetailsLayout.es.js +1 -1
- package/lib/components/ProductGallery.cjs +1 -0
- package/lib/components/ProductGallery.es.js +1 -1
- package/lib/components/ProductGrid.cjs +1 -0
- package/lib/components/ProductGrid.es.js +1 -1
- package/lib/components/ShippingEstimator.cjs +1 -0
- package/lib/components/ShippingEstimator.es.js +1 -1
- package/lib/components/ShortDescription.cjs +1 -0
- package/lib/components/ShortDescription.es.js +1 -1
- package/lib/components/SimpleTiptapRenderer.cjs +1 -0
- package/lib/components/SimpleTiptapRenderer.es.js +1 -1
- package/lib/components/SubscriptionSelector.cjs +1 -0
- package/lib/components/SubscriptionSelector.es.js +1 -1
- package/lib/countries.es.js +1 -1
- package/lib/coupon-server.cjs +1 -0
- package/lib/coupon-server.es.js +1 -1
- package/lib/coupons.es.js +1 -1
- package/lib/currency-constants.es.js +1 -1
- package/lib/currency-rest-client.es.js +1 -1
- package/lib/currency-store.es.js +1 -1
- package/lib/currency-sync.cjs +1 -0
- package/lib/currency-sync.es.js +1 -1
- package/lib/currency.es.js +1 -1
- package/lib/customer-addresses.cjs +1 -0
- package/lib/customer-addresses.es.js +1 -1
- package/lib/customer-orders.cjs +1 -0
- package/lib/customer-orders.es.js +1 -1
- package/lib/customer.cjs +1 -0
- package/lib/customer.es.js +1 -1
- package/lib/export-helpers.cjs +1 -0
- package/lib/export-helpers.es.js +1 -1
- package/lib/factory.cjs +1 -0
- package/lib/factory.es.js +1 -1
- package/lib/freemius-coupons.cjs +1 -0
- package/lib/freemius-coupons.es.js +1 -1
- package/lib/freemius-license-claim.cjs +1 -0
- package/lib/freemius-license-claim.es.js +1 -1
- package/lib/freemius-license.cjs +1 -0
- package/lib/freemius-license.es.js +1 -1
- package/lib/freemius-order-sync.cjs +1 -0
- package/lib/freemius-order-sync.es.js +1 -1
- package/lib/freemius-trial-provision.cjs +1 -0
- package/lib/freemius-trial-provision.es.js +1 -1
- package/lib/inventory-settings.es.js +1 -1
- package/lib/{invoice-server.cjs.js → invoice-server.cjs} +1 -1
- package/lib/invoice-server.es.js +1 -1
- package/lib/invoice-ui.es.js +1 -1
- package/lib/invoice.es.js +1 -1
- package/lib/{order-inventory.cjs.js → order-inventory.cjs} +1 -1
- package/lib/order-inventory.es.js +1 -1
- package/lib/order-tax-details.es.js +1 -1
- package/lib/pages/cms/coupons/CouponEditorForm.cjs +1 -0
- package/lib/pages/cms/coupons/CouponEditorForm.es.js +1 -1
- package/lib/pages/cms/coupons/{CouponsPage.cjs.js → CouponsPage.cjs} +1 -1
- package/lib/pages/cms/coupons/CouponsPage.es.js +1 -1
- package/lib/pages/cms/coupons/CreateCouponDialog.cjs +1 -0
- package/lib/pages/cms/coupons/CreateCouponDialog.es.js +1 -1
- package/lib/pages/cms/coupons/EditCouponPage.cjs +1 -0
- package/lib/pages/cms/coupons/EditCouponPage.es.js +1 -1
- package/lib/pages/cms/coupons/ProductScopePicker.es.js +1 -1
- package/lib/pages/cms/coupons/actions.cjs +1 -0
- package/lib/pages/cms/coupons/actions.es.js +1 -1
- package/lib/pages/cms/coupons/index.cjs +1 -0
- package/lib/pages/cms/coupons/product-options.es.js +1 -1
- package/lib/pages/cms/orders/ExportReportsDialog.cjs +1 -0
- package/lib/pages/cms/orders/ExportReportsDialog.es.js +1 -1
- package/lib/pages/cms/orders/OrderDetailPage.cjs +1 -0
- package/lib/pages/cms/orders/OrderDetailPage.es.js +1 -1
- package/lib/pages/cms/orders/OrderPrintButton.es.js +1 -1
- package/lib/pages/cms/orders/OrderStatusForm.cjs +1 -0
- package/lib/pages/cms/orders/OrderStatusForm.es.js +1 -1
- package/lib/pages/cms/orders/OrdersPage.cjs +1 -0
- package/lib/pages/cms/orders/OrdersPage.es.js +1 -1
- package/lib/pages/cms/orders/actions.es.js +1 -1
- package/lib/pages/cms/orders/export-actions.es.js +1 -1
- package/lib/pages/cms/orders/index.cjs +1 -0
- package/lib/pages/cms/orders/server-actions.cjs +1 -0
- package/lib/pages/cms/orders/server-actions.es.js +1 -1
- package/lib/pages/cms/payments/PaymentsClient.es.js +1 -1
- package/lib/pages/cms/payments/PaymentsPage.cjs +1 -0
- package/lib/pages/cms/payments/PaymentsPage.es.js +1 -1
- package/lib/pages/cms/payments/actions.cjs +1 -0
- package/lib/pages/cms/payments/actions.es.js +1 -1
- package/lib/pages/cms/payments/index.cjs +1 -0
- package/lib/pages/cms/payments/queries.cjs +1 -0
- package/lib/pages/cms/payments/queries.es.js +1 -1
- package/lib/pages/cms/products/ProductsPage.cjs +1 -0
- package/lib/pages/cms/products/ProductsPage.es.js +1 -1
- package/lib/pages/cms/products/[id]/edit/EditProductPage.cjs +1 -0
- package/lib/pages/cms/products/{_id_ → [id]}/edit/EditProductPage.es.js +1 -1
- package/lib/pages/cms/products/{actions.cjs.js → actions.cjs} +1 -1
- package/lib/pages/cms/products/actions.es.js +1 -1
- package/lib/pages/cms/products/attributes/AttributeManagementPage.cjs +1 -0
- package/lib/pages/cms/products/attributes/AttributeManagementPage.es.js +1 -1
- package/lib/pages/cms/products/attributes/components/AttributeManager.es.js +1 -1
- package/lib/pages/cms/products/categories/CategoryManagementPage.cjs +1 -0
- package/lib/pages/cms/products/categories/CategoryManagementPage.es.js +1 -1
- package/lib/pages/cms/products/categories/components/CategoryManager.cjs +1 -0
- package/lib/pages/cms/products/categories/components/CategoryManager.es.js +1 -1
- package/lib/pages/cms/products/components/CopyProductFromLanguage.cjs +1 -0
- package/lib/pages/cms/products/components/CopyProductFromLanguage.es.js +1 -1
- package/lib/pages/cms/products/components/CurrencyPriceFields.cjs +1 -0
- package/lib/pages/cms/products/components/CurrencyPriceFields.es.js +1 -1
- package/lib/pages/cms/products/components/DeleteProductButton.es.js +1 -1
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.cjs +1 -0
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.es.js +1 -1
- package/lib/pages/cms/products/components/ProductCategorySelector.cjs +1 -0
- package/lib/pages/cms/products/components/ProductCategorySelector.es.js +1 -1
- package/lib/pages/cms/products/components/ProductForm.cjs +1 -0
- package/lib/pages/cms/products/components/ProductForm.es.js +1 -1
- package/lib/pages/cms/products/components/ProductMediaManager.cjs +1 -0
- package/lib/pages/cms/products/components/ProductMediaManager.es.js +1 -1
- package/lib/pages/cms/products/components/ProductsBulkTable.cjs +1 -0
- package/lib/pages/cms/products/components/ProductsBulkTable.es.js +1 -1
- package/lib/pages/cms/products/components/SaleScheduleFields.es.js +1 -1
- package/lib/pages/cms/products/components/SyncFreemiusButton.cjs +1 -0
- package/lib/pages/cms/products/components/SyncFreemiusButton.es.js +1 -1
- package/lib/pages/cms/products/components/{SyncFreemiusPricingButton.cjs.js → SyncFreemiusPricingButton.cjs} +1 -1
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.es.js +1 -1
- package/lib/pages/cms/products/components/VariationsEditor.cjs +1 -0
- package/lib/pages/cms/products/components/VariationsEditor.es.js +1 -1
- package/lib/pages/cms/products/index.cjs +1 -0
- package/lib/pages/cms/products/index.es.js +1 -1
- package/lib/pages/cms/products/inventory/InventoryPage.cjs +1 -0
- package/lib/pages/cms/products/inventory/InventoryPage.es.js +1 -1
- package/lib/pages/cms/products/inventory/{InventoryTableClient.cjs.js → InventoryTableClient.cjs} +1 -1
- package/lib/pages/cms/products/inventory/InventoryTableClient.es.js +1 -1
- package/lib/pages/cms/products/inventory/{actions.cjs.js → actions.cjs} +1 -1
- package/lib/pages/cms/products/inventory/actions.es.js +1 -1
- package/lib/pages/cms/products/new/NewProductPage.cjs +1 -0
- package/lib/pages/cms/products/new/NewProductPage.es.js +1 -1
- package/lib/pages/cms/products/product-price-sync.cjs +1 -0
- package/lib/pages/cms/products/product-price-sync.es.js +1 -1
- package/lib/pages/cms/products/server-actions.cjs +1 -0
- package/lib/pages/cms/products/server-actions.es.js +1 -1
- package/lib/pages/cms/shipping/{ShippingPage.cjs.js → ShippingPage.cjs} +1 -1
- package/lib/pages/cms/shipping/ShippingPage.es.js +1 -1
- package/lib/pages/cms/shipping/components/RateForm.cjs +1 -0
- package/lib/pages/cms/shipping/components/RateForm.es.js +1 -1
- package/lib/pages/cms/shipping/components/ZoneForm.cjs +1 -0
- package/lib/pages/cms/shipping/components/ZoneForm.es.js +1 -1
- package/lib/pages/cms/shipping/index.cjs +1 -0
- package/lib/pages/cms/shipping/server-actions.cjs +1 -0
- package/lib/pages/cms/shipping/server-actions.es.js +1 -1
- package/lib/pages/cms/taxes/TaxesPage.cjs +1 -0
- package/lib/pages/cms/taxes/TaxesPage.es.js +1 -1
- package/lib/pages/cms/taxes/actions.cjs +1 -0
- package/lib/pages/cms/taxes/actions.es.js +1 -1
- package/lib/pages/cms/taxes/components/TaxRateForm.cjs +1 -0
- package/lib/pages/cms/taxes/components/TaxRateForm.es.js +1 -1
- package/lib/pages/cms/taxes/index.cjs +1 -0
- package/lib/payment-config.es.js +1 -1
- package/lib/{product-actions.cjs.js → product-actions.cjs} +1 -1
- package/lib/product-actions.es.js +1 -1
- package/lib/product-context.cjs +1 -0
- package/lib/product-context.es.js +1 -1
- package/lib/product-schema.cjs +1 -0
- package/lib/product-schema.es.js +1 -1
- package/lib/providers/freemius.cjs +1 -0
- package/lib/providers/freemius.es.js +1 -1
- package/lib/providers/stripe.cjs +1 -0
- package/lib/providers/stripe.es.js +1 -1
- package/lib/server-actions/coupon-actions.cjs +1 -0
- package/lib/server-actions/coupon-actions.es.js +1 -1
- package/lib/server-actions/customer-actions.cjs +1 -0
- package/lib/server-actions/customer-actions.es.js +1 -1
- package/lib/server-actions/product-actions.cjs +1 -0
- package/lib/server-actions/product-actions.es.js +1 -1
- package/lib/server-actions/shipping-actions.cjs +1 -0
- package/lib/server-actions/shipping-actions.es.js +1 -1
- package/lib/server-actions/tax-actions.cjs +1 -0
- package/lib/server-actions/tax-actions.es.js +1 -1
- package/lib/shared-inventory.es.js +1 -1
- package/lib/shipping/{resolver.cjs.js → resolver.cjs} +1 -1
- package/lib/shipping/resolver.es.js +1 -1
- package/lib/shipping-rate-currency.cjs +1 -0
- package/lib/shipping-rate-currency.es.js +1 -1
- package/lib/states.cjs +1 -0
- package/lib/stripe/checkout.cjs +1 -0
- package/lib/stripe/checkout.es.js +1 -1
- package/lib/stripe/client.cjs +1 -0
- package/lib/stripe/client.es.js +1 -1
- package/lib/stripe/order-sync.cjs +1 -0
- package/lib/stripe/order-sync.es.js +1 -1
- package/lib/stripe/webhooks.cjs +1 -0
- package/lib/stripe/webhooks.es.js +1 -1
- package/lib/tax-calculation.cjs +1 -0
- package/lib/tax-calculation.es.js +1 -1
- package/lib/trials.es.js +1 -1
- package/lib/types.es.js +1 -1
- package/lib/use-cart.cjs +1 -0
- package/lib/use-cart.es.js +1 -1
- package/lib/use-price-formatter.es.js +1 -1
- package/lib/variation-utils.cjs +1 -0
- package/lib/variation-utils.es.js +1 -1
- package/lib/zod-config.es.js +1 -1
- package/package.json +10 -9
- package/server.cjs +1 -0
- package/server.es.js +1 -1
- package/index.cjs.js +0 -1
- package/lib/CurrencyProvider.cjs.js +0 -1
- package/lib/PaymentReadinessProvider.cjs.js +0 -1
- package/lib/cart-store.cjs.js +0 -1
- package/lib/components/AccountNavigationMenu.cjs.js +0 -1
- package/lib/components/AddToCartButton.cjs.js +0 -1
- package/lib/components/Cart.cjs.js +0 -1
- package/lib/components/CartDrawer.cjs.js +0 -1
- package/lib/components/CartIcon.cjs.js +0 -1
- package/lib/components/Checkout.cjs.js +0 -1
- package/lib/components/CouponForm.cjs.js +0 -1
- package/lib/components/CurrencySwitcher.cjs.js +0 -1
- package/lib/components/CustomerProfileForm.cjs.js +0 -1
- package/lib/components/FeaturedProduct.cjs.js +0 -1
- package/lib/components/FreemiusLicensePanel.cjs.js +0 -1
- package/lib/components/InvoiceDocument.cjs.js +0 -1
- package/lib/components/ProductCard.cjs.js +0 -1
- package/lib/components/ProductDetailsLayout.cjs.js +0 -1
- package/lib/components/ProductGallery.cjs.js +0 -1
- package/lib/components/ProductGrid.cjs.js +0 -1
- package/lib/components/ShippingEstimator.cjs.js +0 -1
- package/lib/components/ShortDescription.cjs.js +0 -1
- package/lib/components/SimpleTiptapRenderer.cjs.js +0 -1
- package/lib/components/SubscriptionSelector.cjs.js +0 -1
- package/lib/coupon-server.cjs.js +0 -1
- package/lib/currency-sync.cjs.js +0 -1
- package/lib/customer-addresses.cjs.js +0 -1
- package/lib/customer-orders.cjs.js +0 -1
- package/lib/customer.cjs.js +0 -1
- package/lib/export-helpers.cjs.js +0 -1
- package/lib/factory.cjs.js +0 -1
- package/lib/freemius-coupons.cjs.js +0 -1
- package/lib/freemius-license-claim.cjs.js +0 -1
- package/lib/freemius-license.cjs.js +0 -1
- package/lib/freemius-order-sync.cjs.js +0 -1
- package/lib/freemius-trial-provision.cjs.js +0 -1
- package/lib/pages/cms/coupons/CouponEditorForm.cjs.js +0 -1
- package/lib/pages/cms/coupons/CreateCouponDialog.cjs.js +0 -1
- package/lib/pages/cms/coupons/EditCouponPage.cjs.js +0 -1
- package/lib/pages/cms/coupons/actions.cjs.js +0 -1
- package/lib/pages/cms/coupons/index.cjs.js +0 -1
- package/lib/pages/cms/orders/ExportReportsDialog.cjs.js +0 -1
- package/lib/pages/cms/orders/OrderDetailPage.cjs.js +0 -1
- package/lib/pages/cms/orders/OrderStatusForm.cjs.js +0 -1
- package/lib/pages/cms/orders/OrdersPage.cjs.js +0 -1
- package/lib/pages/cms/orders/index.cjs.js +0 -1
- package/lib/pages/cms/orders/server-actions.cjs.js +0 -1
- package/lib/pages/cms/payments/PaymentsPage.cjs.js +0 -1
- package/lib/pages/cms/payments/actions.cjs.js +0 -1
- package/lib/pages/cms/payments/index.cjs.js +0 -1
- package/lib/pages/cms/payments/queries.cjs.js +0 -1
- package/lib/pages/cms/products/ProductsPage.cjs.js +0 -1
- package/lib/pages/cms/products/_id_/edit/EditProductPage.cjs.js +0 -1
- package/lib/pages/cms/products/attributes/AttributeManagementPage.cjs.js +0 -1
- package/lib/pages/cms/products/categories/CategoryManagementPage.cjs.js +0 -1
- package/lib/pages/cms/products/categories/components/CategoryManager.cjs.js +0 -1
- package/lib/pages/cms/products/components/CopyProductFromLanguage.cjs.js +0 -1
- package/lib/pages/cms/products/components/CurrencyPriceFields.cjs.js +0 -1
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.cjs.js +0 -1
- package/lib/pages/cms/products/components/ProductCategorySelector.cjs.js +0 -1
- package/lib/pages/cms/products/components/ProductForm.cjs.js +0 -1
- package/lib/pages/cms/products/components/ProductMediaManager.cjs.js +0 -1
- package/lib/pages/cms/products/components/ProductsBulkTable.cjs.js +0 -1
- package/lib/pages/cms/products/components/SyncFreemiusButton.cjs.js +0 -1
- package/lib/pages/cms/products/components/VariationsEditor.cjs.js +0 -1
- package/lib/pages/cms/products/index.cjs.js +0 -1
- package/lib/pages/cms/products/inventory/InventoryPage.cjs.js +0 -1
- package/lib/pages/cms/products/new/NewProductPage.cjs.js +0 -1
- package/lib/pages/cms/products/product-price-sync.cjs.js +0 -1
- package/lib/pages/cms/products/server-actions.cjs.js +0 -1
- package/lib/pages/cms/shipping/components/RateForm.cjs.js +0 -1
- package/lib/pages/cms/shipping/components/ZoneForm.cjs.js +0 -1
- package/lib/pages/cms/shipping/index.cjs.js +0 -1
- package/lib/pages/cms/shipping/server-actions.cjs.js +0 -1
- package/lib/pages/cms/taxes/TaxesPage.cjs.js +0 -1
- package/lib/pages/cms/taxes/actions.cjs.js +0 -1
- package/lib/pages/cms/taxes/components/TaxRateForm.cjs.js +0 -1
- package/lib/pages/cms/taxes/index.cjs.js +0 -1
- package/lib/product-context.cjs.js +0 -1
- package/lib/product-schema.cjs.js +0 -1
- package/lib/providers/freemius.cjs.js +0 -1
- package/lib/providers/stripe.cjs.js +0 -1
- package/lib/server-actions/coupon-actions.cjs.js +0 -1
- package/lib/server-actions/customer-actions.cjs.js +0 -1
- package/lib/server-actions/product-actions.cjs.js +0 -1
- package/lib/server-actions/shipping-actions.cjs.js +0 -1
- package/lib/server-actions/tax-actions.cjs.js +0 -1
- package/lib/shipping-rate-currency.cjs.js +0 -1
- package/lib/states.cjs.js +0 -1
- package/lib/stripe/checkout.cjs.js +0 -1
- package/lib/stripe/client.cjs.js +0 -1
- package/lib/stripe/order-sync.cjs.js +0 -1
- package/lib/stripe/webhooks.cjs.js +0 -1
- package/lib/tax-calculation.cjs.js +0 -1
- package/lib/use-cart.cjs.js +0 -1
- package/lib/variation-utils.cjs.js +0 -1
- package/server.cjs.js +0 -1
- /package/_virtual/_rolldown/{runtime.cjs.js → runtime.cjs} +0 -0
- /package/lib/{countries.cjs.js → countries.cjs} +0 -0
- /package/lib/{coupons.cjs.js → coupons.cjs} +0 -0
- /package/lib/{currency-constants.cjs.js → currency-constants.cjs} +0 -0
- /package/lib/{currency-rest-client.cjs.js → currency-rest-client.cjs} +0 -0
- /package/lib/{currency-store.cjs.js → currency-store.cjs} +0 -0
- /package/lib/{currency.cjs.js → currency.cjs} +0 -0
- /package/lib/{inventory-settings.cjs.js → inventory-settings.cjs} +0 -0
- /package/lib/{invoice-ui.cjs.js → invoice-ui.cjs} +0 -0
- /package/lib/{invoice.cjs.js → invoice.cjs} +0 -0
- /package/lib/{order-tax-details.cjs.js → order-tax-details.cjs} +0 -0
- /package/lib/pages/cms/coupons/{ProductScopePicker.cjs.js → ProductScopePicker.cjs} +0 -0
- /package/lib/pages/cms/coupons/{product-options.cjs.js → product-options.cjs} +0 -0
- /package/lib/pages/cms/orders/{OrderPrintButton.cjs.js → OrderPrintButton.cjs} +0 -0
- /package/lib/pages/cms/orders/{actions.cjs.js → actions.cjs} +0 -0
- /package/lib/pages/cms/orders/{export-actions.cjs.js → export-actions.cjs} +0 -0
- /package/lib/pages/cms/payments/{PaymentsClient.cjs.js → PaymentsClient.cjs} +0 -0
- /package/lib/pages/cms/products/attributes/components/{AttributeManager.cjs.js → AttributeManager.cjs} +0 -0
- /package/lib/pages/cms/products/components/{DeleteProductButton.cjs.js → DeleteProductButton.cjs} +0 -0
- /package/lib/pages/cms/products/components/{SaleScheduleFields.cjs.js → SaleScheduleFields.cjs} +0 -0
- /package/lib/{payment-config.cjs.js → payment-config.cjs} +0 -0
- /package/lib/{shared-inventory.cjs.js → shared-inventory.cjs} +0 -0
- /package/lib/{trials.cjs.js → trials.cjs} +0 -0
- /package/lib/{types.cjs.js → types.cjs} +0 -0
- /package/lib/{use-price-formatter.cjs.js → use-price-formatter.cjs} +0 -0
- /package/lib/{zod-config.cjs.js → zod-config.cjs} +0 -0
|
@@ -8,7 +8,7 @@ import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
|
8
8
|
import { useRouter as ie } from "next/navigation";
|
|
9
9
|
import ae from "next/image";
|
|
10
10
|
import { Badge as oe, Button as u, Checkbox as d, Input as se, Select as f, SelectContent as p, SelectItem as m, SelectTrigger as h, SelectValue as g, SeoScoreBadge as _, Table as v, TableBody as y, TableCell as b, TableHead as x, TableHeader as S, TableRow as C } from "@nextblock-cms/ui";
|
|
11
|
-
//#region
|
|
11
|
+
//#region src/lib/pages/cms/products/components/ProductsBulkTable.tsx
|
|
12
12
|
var w = process.env.NEXT_PUBLIC_R2_BASE_URL || "";
|
|
13
13
|
function T(e) {
|
|
14
14
|
return e ? e.startsWith("http") || !w ? e : `${w.replace(/\/+$/, "")}/${e.replace(/^\/+/, "")}` : null;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { cn as e } from "@nextblock-cms/utils";
|
|
3
3
|
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
4
|
import { Input as i, Label as a } from "@nextblock-cms/ui";
|
|
5
|
-
//#region
|
|
5
|
+
//#region src/lib/pages/cms/products/components/SaleScheduleFields.tsx
|
|
6
6
|
var o = (e) => String(e).padStart(2, "0");
|
|
7
7
|
function s(e) {
|
|
8
8
|
if (!e) return "";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../actions.cjs");let t=require("react"),n=require("lucide-react"),r=require("react/jsx-runtime"),i=require("sonner"),a=require("@nextblock-cms/ui");function o({title:o=`Sync Full Store`}){let[s,c]=(0,t.useState)(!1);return(0,r.jsxs)(a.Button,{variant:`secondary`,onClick:async()=>{c(!0);try{let t=await e.triggerFreemiusSync();t.error?i.toast.error(t.error):i.toast.success(`Full store sync complete! Found ${t.data?.count||0} products.`)}catch(e){i.toast.error(e.message||`An unexpected error occurred during sync`)}finally{c(!1)}},disabled:s,className:`gap-2`,children:[(0,r.jsx)(n.RefreshCw,{className:`w-4 h-4 ${s?`animate-spin`:``}`}),s?`Syncing...`:o]})}exports.SyncFreemiusButton=o;
|
|
@@ -5,7 +5,7 @@ import { RefreshCw as n } from "lucide-react";
|
|
|
5
5
|
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
6
|
import { toast as a } from "sonner";
|
|
7
7
|
import { Button as o } from "@nextblock-cms/ui";
|
|
8
|
-
//#region
|
|
8
|
+
//#region src/lib/pages/cms/products/components/SyncFreemiusButton.tsx
|
|
9
9
|
function s({ title: s = "Sync Full Store" }) {
|
|
10
10
|
let [c, l] = t(!1);
|
|
11
11
|
return /* @__PURE__ */ i(o, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";const e=require("../actions.cjs
|
|
1
|
+
"use client";const e=require("../actions.cjs");let t=require("react"),n=require("lucide-react"),r=require("react/jsx-runtime"),i=require("sonner"),a=require("next/navigation"),o=require("@nextblock-cms/ui");function s({productId:s,hasOpenDraft:c=!1}){let l=(0,a.useRouter)(),[u,d]=(0,t.useState)(!1);return(0,r.jsxs)(o.Button,{variant:`outline`,onClick:async()=>{if(!s){i.toast.error(`Product ID is missing`);return}if(!c||window.confirm(`You have unpublished draft changes for this product.
|
|
2
2
|
|
|
3
3
|
Syncing updates the live pricing now, but publishing your draft afterward will overwrite it with the draft’s older values. Publish or discard your draft first to keep the synced prices.
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
|
6
6
|
import { toast as a } from "sonner";
|
|
7
7
|
import { useRouter as o } from "next/navigation";
|
|
8
8
|
import { Button as s } from "@nextblock-cms/ui";
|
|
9
|
-
//#region
|
|
9
|
+
//#region src/lib/pages/cms/products/components/SyncFreemiusPricingButton.tsx
|
|
10
10
|
function c({ productId: c, hasOpenDraft: l = !1 }) {
|
|
11
11
|
let u = o(), [d, f] = t(!1);
|
|
12
12
|
return /* @__PURE__ */ i(s, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../currency.cjs"),n=require("../../../../variation-utils.cjs"),r=require("./CurrencyPriceFields.cjs"),i=require("./SaleScheduleFields.cjs"),a=require("../product-price-sync.cjs");let o=require("next/link");o=e.__toESM(o,1);let s=require("react"),c=require("@nextblock-cms/utils"),l=require("react/jsx-runtime"),u=require("@nextblock-cms/ui");var d=process.env.NEXT_PUBLIC_R2_BASE_URL||``,f=process.env.NEXT_PUBLIC_SUPABASE_URL||``,p=e=>e.startsWith(`http`)?e:d?`${d.replace(/\/+$/,``)}/${e.replace(/^\/+/,``)}`:f?`${f.replace(/\/+$/,``)}/storage/v1/object/public/media/${e.replace(/^\/+/,``)}`:e;function m(e,t=`USD`){return new Intl.NumberFormat(`en-US`,{style:`currency`,currency:t}).format(e)}function h(e){return Object.entries(e).filter(([,e])=>e.length>0).map(([e,t])=>({attribute_id:e,term_ids:t}))}function g({globalAttributes:e,currentLanguageCode:d,baseSku:f,basePrice:g,basePrices:_,baseSalePrice:v,baseSalePrices:y,currencies:b,availableVariantImages:x=[],initialVariationAttributes:S,initialVariants:C,onChange:w}){let[T,E]=(0,s.useState)(()=>S&&S.length>0?S.reduce((e,t)=>(e[t.attribute_id]=t.term_ids,e),{}):n.extractSelectedTermsByAttribute(C||[])),[D,O]=(0,s.useState)(a.sanitizeVariantDraftsForStoreManagedCurrencies(C||[],b)),k=(0,s.useMemo)(()=>e.map(e=>({attribute_id:e.id,attribute_name:n.resolveAttributeName(e,d),terms:e.terms.filter(t=>(T[e.id]||[]).includes(t.id)).map(e=>({...e,value:n.resolveTermValue(e,d)}))})).filter(e=>e.terms.length>0),[d,e,T]);(0,s.useEffect)(()=>{if(k.length===0){O([]);return}O(e=>a.sanitizeVariantDraftsForStoreManagedCurrencies(n.generateVariantDrafts({baseSku:f,basePrice:g,basePrices:t.normalizePriceMap(_),baseSalePrice:v,baseSalePrices:t.normalizeSalePriceMap(y),selectedAttributes:k,previousVariants:e}),b))},[g,_,v,y,f,b,k]),(0,s.useEffect)(()=>{w({variationAttributes:h(T),variants:D})},[w,T,D]);let A=D.reduce((e,t)=>e+(t.stock_quantity||0),0),j=b.find(e=>e.is_default)??b[0],M=(0,s.useMemo)(()=>a.getStoreManagedPriceCurrencyCodes(b),[b]),N=(e,t)=>{E(n=>{let r=new Set(n[e]||[]);return r.has(t)?r.delete(t):r.add(t),{...n,[e]:[...r]}})},P=(e,t,n)=>{O(r=>r.map(r=>{if(r.combination_key!==e)return r;if(t===`sku`)return{...r,sku:n};if(t===`upc`)return{...r,upc:n};if(t===`sale_price`&&n===``)return{...r,sale_price:null};if(t===`prices`||t===`sale_prices`)return r;let i=n===``?0:Number(n);return{...r,[t]:Number.isFinite(i)?i:0}}))},F=(e,t,n)=>{O(r=>r.map(r=>r.combination_key===e?{...r,[t]:n}:r))},I=(e,t,n,r)=>{let i=b.find(e=>e.is_default)??b[0];O(a=>a.map(a=>{if(a.combination_key!==e)return a;let o={...n===`prices`?a.prices:a.sale_prices,[t]:r};return{...a,[n]:o,...t===i?.code?n===`prices`?{price:r??0}:{sale_price:r}:{}}}))},L=e=>{let n=b.find(e=>e.is_default)??b[0],r=new Set(M);n&&O(i=>i.map(i=>{if(i.combination_key!==e)return i;let a=b.reduce((e,a)=>{if(a.code!==n.code&&r.has(a.code))return e;let o=t.convertMinorUnitAmount({amount:(0,c.majorUnitAmountToMinor)(i.price,n.code),fromCurrencyCode:n.code,toCurrencyCode:a.code,currencies:b,applyRounding:!0});return e[a.code]=(0,c.minorUnitAmountToMajor)(o,a.code),e},{}),o=b.reduce((e,a)=>{if(a.code!==n.code&&r.has(a.code))return e;if(typeof i.sale_price!=`number`)return e[a.code]=null,e;let o=t.convertMinorUnitAmount({amount:(0,c.majorUnitAmountToMinor)(i.sale_price,n.code),fromCurrencyCode:n.code,toCurrencyCode:a.code,currencies:b,applyRounding:!0});return e[a.code]=(0,c.minorUnitAmountToMajor)(o,a.code),e},{});return{...i,prices:a,sale_prices:o}}))},R=(e,t)=>{let n=x.find(e=>e.media_id===t);if(!n)return;let r=n.file_path,i=p(r);O(t=>t.map(t=>t.combination_key===e?{...t,main_media_id:n.media_id,main_image_url:i}:t))},z=e=>{O(t=>t.map(t=>t.combination_key===e?{...t,main_media_id:null,main_image_url:null}:t))};return e.length===0?(0,l.jsxs)(`div`,{className:`rounded-lg border border-dashed p-6 text-sm text-muted-foreground`,children:[`No global attributes have been created yet. Create them first in`,` `,(0,l.jsx)(o.default,{href:`/cms/products/attributes`,className:`font-medium text-primary underline-offset-4 hover:underline`,children:`Attribute Management`}),`.`]}):(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`space-y-2`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,l.jsx)(`span`,{className:`text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none`,children:`Attributes`}),(0,l.jsxs)(u.Badge,{variant:`outline`,className:`text-[10px] px-1.5 h-4`,children:[D.length,` variants`]}),(0,l.jsxs)(u.Badge,{variant:`secondary`,className:`text-[10px] px-1.5 h-4`,children:[`Stock: `,A]})]}),(0,l.jsx)(u.Button,{asChild:!0,variant:`outline`,size:`sm`,className:`h-7 text-xs px-3`,children:(0,l.jsx)(o.default,{href:`/cms/products/attributes`,children:`Manage`})})]}),(0,l.jsx)(`div`,{className:`grid gap-2 lg:grid-cols-2`,children:e.map(e=>{let t=T[e.id]||[];return(0,l.jsxs)(`div`,{className:`flex items-center gap-3 rounded border p-2.5`,children:[(0,l.jsxs)(`div`,{className:`shrink-0 w-[100px]`,children:[(0,l.jsx)(`span`,{className:`text-sm font-bold block leading-tight`,children:n.resolveAttributeName(e,d)}),(0,l.jsxs)(`span`,{className:`text-[10px] text-muted-foreground leading-none`,children:[t.length,` selected`]})]}),(0,l.jsx)(`div`,{className:`flex flex-wrap gap-1.5 flex-1`,children:e.terms.map(r=>{let i=t.includes(r.id);return(0,l.jsx)(`button`,{type:`button`,onClick:()=>N(e.id,r.id),className:`rounded-full border px-2.5 py-0.5 text-[11px] font-medium transition-colors ${i?`border-primary bg-primary/10 text-primary`:`border-border bg-background text-foreground hover:border-primary/40`}`,children:n.resolveTermValue(r,d)},r.id)})})]},e.id)})})]}),D.length===0?(0,l.jsx)(`div`,{className:`rounded border border-dashed p-3 text-xs text-muted-foreground text-center`,children:`Select terms above to generate variations.`}):(0,l.jsx)(`div`,{className:`space-y-2`,children:D.map(e=>{let t=a.resolveEditorCurrencyPriceMaps({currencies:b,prices:e.prices||{},salePrices:e.sale_prices||{},fallbackPrice:e.price,fallbackSalePrice:e.sale_price});return(0,l.jsxs)(`div`,{className:`rounded border p-3 space-y-2`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(`span`,{className:`text-sm font-bold`,children:e.label}),(0,l.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.selected_options.map(e=>`${e.attribute_name}: ${e.term_value}`).join(` · `)})]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-3 text-xs text-muted-foreground`,children:[(0,l.jsxs)(`span`,{children:[`Reg: `,m(e.price,j?.code||`USD`)]}),(0,l.jsxs)(`span`,{children:[`Sale:`,` `,e.sale_price!==null&&e.sale_price!==void 0?m(e.sale_price,j?.code||`USD`):`—`]})]})]}),(0,l.jsxs)(`div`,{className:`grid grid-cols-3 gap-2.5`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(u.Label,{htmlFor:`variant-sku-${e.combination_key}`,className:`text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0`,children:`SKU`}),(0,l.jsx)(u.Input,{id:`variant-sku-${e.combination_key}`,value:e.sku,onChange:t=>P(e.combination_key,`sku`,t.target.value),placeholder:`SKU`,className:`h-8 text-sm font-mono`})]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(u.Label,{htmlFor:`variant-upc-${e.combination_key}`,className:`text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0`,children:`UPC`}),(0,l.jsx)(u.Input,{id:`variant-upc-${e.combination_key}`,value:e.upc??``,onChange:t=>P(e.combination_key,`upc`,t.target.value),placeholder:`—`,className:`h-8 text-sm font-mono`})]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(u.Label,{htmlFor:`variant-stock-${e.combination_key}`,className:`text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0`,children:`Qty`}),(0,l.jsx)(u.Input,{id:`variant-stock-${e.combination_key}`,type:`number`,min:`0`,value:e.stock_quantity,onChange:t=>P(e.combination_key,`stock_quantity`,t.target.value),className:`h-8 text-sm font-mono w-20`})]})]}),(0,l.jsx)(r.CurrencyPriceFields,{idPrefix:`variant-${e.combination_key}`,currencies:b,prices:t.prices,salePrices:t.salePrices,managedCurrencyCodes:M,onPriceChange:(t,n)=>I(e.combination_key,t,`prices`,n),onSalePriceChange:(t,n)=>I(e.combination_key,t,`sale_prices`,n),onAutoFill:()=>L(e.combination_key),helperText:M.length>0?`Store-managed currencies derive from ${j?.code||`the base currency`}.`:void 0,trailing:(0,l.jsx)(i.SaleScheduleFields,{idPrefix:`variant-${e.combination_key}`,startAt:e.sale_start_at,endAt:e.sale_end_at,onChange:(t,n)=>F(e.combination_key,t,n),bare:!0})}),(0,l.jsxs)(`div`,{className:`flex items-center gap-3 pt-1.5 border-t border-muted/30`,children:[e.main_image_url&&(0,l.jsx)(`div`,{className:`h-9 w-9 overflow-hidden rounded border bg-background shrink-0`,children:(0,l.jsx)(`img`,{src:e.main_image_url,alt:`${e.label} image`,className:`h-full w-full object-cover`})}),(0,l.jsx)(`span`,{className:`text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0`,children:`Image`}),x.length>0?(0,l.jsxs)(`select`,{className:`flex h-8 rounded-md border border-input bg-background px-2 py-1 text-sm min-w-[180px]`,value:e.main_media_id??``,onChange:t=>{if(!t.target.value){z(e.combination_key);return}R(e.combination_key,t.target.value)},children:[(0,l.jsx)(`option`,{value:``,children:`Use parent image`}),x.map((e,t)=>(0,l.jsx)(`option`,{value:e.media_id,children:e.alt?.trim()||`Gallery image ${t+1}`},e.media_id))]}):(0,l.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Add gallery images first.`}),e.main_media_id&&(0,l.jsx)(u.Button,{type:`button`,variant:`ghost`,size:`sm`,className:`h-7 text-xs px-2 text-muted-foreground hover:text-destructive`,onClick:()=>z(e.combination_key),children:`Remove`})]})]},e.combination_key)})})]})}exports.VariationsEditor=g;
|
|
@@ -9,7 +9,7 @@ import { useEffect as p, useMemo as m, useState as h } from "react";
|
|
|
9
9
|
import { majorUnitAmountToMinor as g, minorUnitAmountToMajor as _ } from "@nextblock-cms/utils";
|
|
10
10
|
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
11
11
|
import { Badge as b, Button as x, Input as S, Label as C } from "@nextblock-cms/ui";
|
|
12
|
-
//#region
|
|
12
|
+
//#region src/lib/pages/cms/products/components/VariationsEditor.tsx
|
|
13
13
|
var w = process.env.NEXT_PUBLIC_R2_BASE_URL || "", T = process.env.NEXT_PUBLIC_SUPABASE_URL || "", E = (e) => e.startsWith("http") ? e : w ? `${w.replace(/\/+$/, "")}/${e.replace(/^\/+/, "")}` : T ? `${T.replace(/\/+$/, "")}/storage/v1/object/public/media/${e.replace(/^\/+/, "")}` : e;
|
|
14
14
|
function D(e, t = "USD") {
|
|
15
15
|
return new Intl.NumberFormat("en-US", {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./ProductsPage.cjs"),t=require("./inventory/InventoryPage.cjs"),n=require("./attributes/AttributeManagementPage.cjs"),r=require("./new/NewProductPage.cjs"),i=require("./[id]/edit/EditProductPage.cjs"),a=require("./components/CopyProductFromLanguage.cjs"),o=require("./categories/CategoryManagementPage.cjs");exports.AttributeManagementPage=n.AttributeManagementPage,exports.CategoryManagementPage=o.CategoryManagementPage,exports.CopyProductFromLanguage=a.CopyProductFromLanguage,exports.EditProductPage=i.EditProductPage,exports.InventoryPage=t.InventoryPage,exports.NewProductPage=r.NewProductPage,exports.ProductsPage=e.ProductsPage;
|
|
@@ -2,7 +2,7 @@ import { ProductsPage as e } from "./ProductsPage.es.js";
|
|
|
2
2
|
import { InventoryPage as t } from "./inventory/InventoryPage.es.js";
|
|
3
3
|
import { AttributeManagementPage as n } from "./attributes/AttributeManagementPage.es.js";
|
|
4
4
|
import { NewProductPage as r } from "./new/NewProductPage.es.js";
|
|
5
|
-
import { EditProductPage as i } from "./
|
|
5
|
+
import { EditProductPage as i } from "./[id]/edit/EditProductPage.es.js";
|
|
6
6
|
import { CopyProductFromLanguage as a } from "./components/CopyProductFromLanguage.es.js";
|
|
7
7
|
import { CategoryManagementPage as o } from "./categories/CategoryManagementPage.es.js";
|
|
8
8
|
export { n as AttributeManagementPage, o as CategoryManagementPage, a as CopyProductFromLanguage, i as EditProductPage, t as InventoryPage, r as NewProductPage, e as ProductsPage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../../../../shared-inventory.cjs"),t=require("./InventoryTableClient.cjs");let n=require("react/jsx-runtime");async function r(){let r=await e.getInventoryItems();return(0,n.jsxs)(`div`,{className:`p-8 space-y-6`,children:[(0,n.jsxs)(`div`,{className:`space-y-2`,children:[(0,n.jsx)(`h1`,{className:`text-3xl font-bold`,children:`Inventory`}),(0,n.jsx)(`p`,{className:`max-w-3xl text-sm text-muted-foreground`,children:`Manage source-of-truth stock for every sellable SKU in one place. Matching SKUs share the same quantity across products, translations, and variants, and you can update those shared quantities inline or in bulk through CSV import and export.`})]}),(0,n.jsx)(t.InventoryTableClient,{initialItems:r})]})}exports.InventoryPage=r;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getInventoryItems as e } from "../../../../shared-inventory.es.js";
|
|
2
2
|
import { InventoryTableClient as t } from "./InventoryTableClient.es.js";
|
|
3
3
|
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
-
//#region
|
|
4
|
+
//#region src/lib/pages/cms/products/inventory/InventoryPage.tsx
|
|
5
5
|
async function i() {
|
|
6
6
|
let i = await e();
|
|
7
7
|
return /* @__PURE__ */ r("div", {
|
package/lib/pages/cms/products/inventory/{InventoryTableClient.cjs.js → InventoryTableClient.cjs}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("./actions.cjs
|
|
1
|
+
"use client";const e=require("./actions.cjs");let t=require("react"),n=require("lucide-react"),r=require("react/jsx-runtime"),i=require("sonner"),a=require("@nextblock-cms/ui");function o(e){let t=String(e??``);return/[",\n]/.test(t)?`"${t.replace(/"/g,`""`)}"`:t}function s(e){return[[`sku`,`stock`,`usage_type`,`product_titles`,`languages`,`statuses`,`parent_product_skus`],...e.map(e=>[e.sku,e.stock,e.usageType,e.productTitles.join(`|`),e.languages.join(`|`),e.statuses.join(`|`),e.parentProductSkus.join(`|`)])].map(e=>e.map(e=>o(e)).join(`,`)).join(`
|
|
2
2
|
`)}function c(e){return e.usageType===`mixed`?`Shared SKU`:e.usageType===`variant`?`Variant SKU ${e.sku}`:`Simple Product`}function l(e){return e.usageType===`variant`?`secondary`:`outline`}function u({initialItems:o}){let[u,d]=(0,t.useState)(o),[f,p]=(0,t.useState)(()=>o.reduce((e,t)=>(e[t.key]=String(t.stock),e),{})),[m,h]=(0,t.useState)(``),[g,_]=(0,t.useTransition)(),[v,y]=(0,t.useState)(null),b=(0,t.useRef)(null),x=(0,t.useMemo)(()=>{let e=m.trim().toLowerCase();return e?u.filter(t=>t.sku.toLowerCase().includes(e)||t.productTitles.join(` `).toLowerCase().includes(e)||t.parentProductSkus.join(` `).toLowerCase().includes(e)||t.languages.join(` `).toLowerCase().includes(e)):u},[u,m]),S=()=>{let e=s(u),t=new Blob([e],{type:`text/csv;charset=utf-8;`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`inventory-export.csv`,r.click(),URL.revokeObjectURL(n)},C=t=>{let n=f[t.key]??String(t.stock),r=Number.parseInt(n,10);if(!Number.isFinite(r)||r<0){i.toast.error(`Stock must be a non-negative whole number.`);return}y(t.key),_(async()=>{let n=await e.updateInventoryQuantityAction({sku:t.sku,stock:r});if(!n.success){i.toast.error(n.error||`Failed to update inventory.`),y(null);return}let a=typeof n.stock==`number`?n.stock:r;d(e=>e.map(e=>e.key===t.key?{...e,stock:a}:e)),p(e=>({...e,[t.key]:String(a)})),y(null),i.toast.success(`Inventory updated for ${t.sku}.`)})},w=()=>{b.current?.click()},T=async t=>{let n=await t.text();y(`import`),_(async()=>{let t=await e.importInventoryCsvAction(n);if(!t.success){i.toast.error(t.error||`Failed to import inventory CSV.`),y(null);return}let r=t.items||[];d(r),p(r.reduce((e,t)=>(e[t.key]=String(t.stock),e),{})),y(null),i.toast.success(`Imported ${t.updatedCount||0} inventory updates.`)})};return(0,r.jsxs)(`div`,{className:`space-y-4`,children:[(0,r.jsxs)(`div`,{className:`flex flex-col gap-3 rounded-xl border bg-card p-4`,children:[(0,r.jsxs)(`div`,{className:`flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between`,children:[(0,r.jsxs)(`div`,{className:`relative w-full lg:max-w-md`,children:[(0,r.jsx)(n.Search,{className:`absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground`}),(0,r.jsx)(a.Input,{value:m,onChange:e=>h(e.target.value),placeholder:`Search by SKU, product title, parent SKU, or language...`,className:`pl-9`})]}),(0,r.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,r.jsx)(`input`,{ref:b,type:`file`,accept:`.csv,text/csv`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];t&&T(t),e.currentTarget.value=``}}),(0,r.jsxs)(a.Button,{type:`button`,variant:`outline`,onClick:w,disabled:g,children:[(0,r.jsx)(n.Upload,{className:`mr-2 h-4 w-4`}),`Import CSV`]}),(0,r.jsxs)(a.Button,{type:`button`,variant:`outline`,onClick:S,disabled:g,children:[(0,r.jsx)(n.Download,{className:`mr-2 h-4 w-4`}),`Export CSV`]})]})]}),(0,r.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Inventory is keyed by sellable SKU. Any product or variant using the same SKU shares the same quantity, and CSV imports can update those shared SKU quantities in bulk.`})]}),(0,r.jsx)(`div`,{className:`rounded-xl border bg-card`,children:(0,r.jsxs)(a.Table,{children:[(0,r.jsx)(a.TableHeader,{children:(0,r.jsxs)(a.TableRow,{children:[(0,r.jsx)(a.TableHead,{children:`SKU`}),(0,r.jsx)(a.TableHead,{children:`Usage`}),(0,r.jsx)(a.TableHead,{children:`Linked Products`}),(0,r.jsx)(a.TableHead,{children:`Languages`}),(0,r.jsx)(a.TableHead,{children:`Status`}),(0,r.jsx)(a.TableHead,{className:`w-[160px]`,children:`Quantity`}),(0,r.jsx)(a.TableHead,{className:`text-right`,children:`Actions`})]})}),(0,r.jsx)(a.TableBody,{children:x.length>0?x.map(e=>{let t=f[e.key]??String(e.stock),i=Number.parseInt(t,10),o=Number.isFinite(i)&&i!==e.stock,s=v===e.key;return(0,r.jsxs)(a.TableRow,{children:[(0,r.jsx)(a.TableCell,{className:`font-mono text-sm`,children:e.sku}),(0,r.jsx)(a.TableCell,{children:(0,r.jsx)(a.Badge,{variant:l(e),children:c(e)})}),(0,r.jsx)(a.TableCell,{children:(0,r.jsxs)(`div`,{className:`space-y-1`,children:[(0,r.jsx)(`p`,{className:`font-medium`,children:e.productTitles.join(`, `)}),e.usageType===`product`?null:(0,r.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Parent SKU`,e.parentProductSkus.length>1?`s`:``,`:`,` `,(0,r.jsx)(`span`,{className:`font-mono`,children:e.parentProductSkus.join(`, `)})]})]})}),(0,r.jsx)(a.TableCell,{children:(0,r.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.languages.map(t=>(0,r.jsx)(a.Badge,{variant:`outline`,children:t},`${e.key}:${t}`))})}),(0,r.jsx)(a.TableCell,{children:(0,r.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.statuses.map(t=>(0,r.jsx)(a.Badge,{variant:`outline`,children:t},`${e.key}:${t}`))})}),(0,r.jsx)(a.TableCell,{children:(0,r.jsx)(a.Input,{type:`number`,min:0,step:1,value:t,disabled:g,onChange:t=>p(n=>({...n,[e.key]:t.target.value})),className:`w-28`})}),(0,r.jsx)(a.TableCell,{className:`text-right`,children:(0,r.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,r.jsxs)(a.Button,{type:`button`,size:`sm`,variant:`ghost`,disabled:!o||g,onClick:()=>p(t=>({...t,[e.key]:String(e.stock)})),children:[(0,r.jsx)(n.RotateCcw,{className:`mr-2 h-4 w-4`}),`Reset`]}),(0,r.jsxs)(a.Button,{type:`button`,size:`sm`,disabled:!o||g,onClick:()=>C(e),children:[(0,r.jsx)(n.Save,{className:`mr-2 h-4 w-4`}),s?`Saving...`:`Save`]})]})})]},e.key)}):(0,r.jsx)(a.TableRow,{children:(0,r.jsx)(a.TableCell,{colSpan:7,className:`py-10 text-center text-muted-foreground`,children:`No inventory rows matched your search.`})})})]})})]})}exports.InventoryTableClient=u;
|
|
@@ -5,7 +5,7 @@ import { Download as o, RotateCcw as s, Save as c, Search as l, Upload as u } fr
|
|
|
5
5
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
6
6
|
import { toast as p } from "sonner";
|
|
7
7
|
import { Badge as m, Button as h, Input as g, Table as _, TableBody as v, TableCell as y, TableHead as b, TableHeader as x, TableRow as S } from "@nextblock-cms/ui";
|
|
8
|
-
//#region
|
|
8
|
+
//#region src/lib/pages/cms/products/inventory/InventoryTableClient.tsx
|
|
9
9
|
function C(e) {
|
|
10
10
|
let t = String(e ?? "");
|
|
11
11
|
return /[",\n]/.test(t) ? `"${t.replace(/"/g, "\"\"")}"` : t;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use server";const e=require("../../../../shared-inventory.cjs
|
|
1
|
+
"use server";const e=require("../../../../shared-inventory.cjs");let t=require("@nextblock-cms/db/server"),n=require("next/cache");function r(e){let t=[],n=[],r=``,i=!1;for(let a=0;a<e.length;a+=1){let o=e[a],s=e[a+1];if(o===`"`){i&&s===`"`?(r+=`"`,a+=1):i=!i;continue}if(o===`,`&&!i){n.push(r),r=``;continue}if((o===`
|
|
2
2
|
`||o===`\r`)&&!i){o===`\r`&&s===`
|
|
3
3
|
`&&(a+=1),(r.length>0||n.length>0)&&(n.push(r),t.push(n)),n=[],r=``;continue}r+=o}return(r.length>0||n.length>0)&&(n.push(r),t.push(n)),t.filter(e=>e.some(e=>e.trim().length>0))}function i(e){return e.sku}async function a(t){try{let r=Math.max(0,Math.trunc(t.stock));return await e.setSharedInventoryQuantity({sku:t.sku,stock:r}),(0,n.revalidatePath)(`/cms/products`),(0,n.revalidatePath)(`/cms/products/inventory`),{success:!0,itemKey:i(t),stock:r}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Failed to update inventory.`}}}async function o(i){try{let a=r(i);if(a.length<2)return{success:!1,error:`The CSV file is empty.`};let[o,...s]=a,c=o.map(e=>e.trim().toLowerCase()),l=c.indexOf(`sku`),u=c.indexOf(`stock`);if(l===-1||u===-1)return{success:!1,error:`The CSV format is invalid. Please import a file exported from the Inventory page.`};let d=(0,t.getServiceRoleSupabaseClient)(),f=0;for(let t of s){let n=(t[l]||``).trim(),r=Number.parseInt((t[u]||``).trim(),10);if(n){if(!Number.isFinite(r)||r<0)return{success:!1,error:`Invalid stock value for SKU "${n}".`};await e.setSharedInventoryQuantity({sku:n,stock:r},d),f+=1}}let p=await e.getInventoryItems(d);return(0,n.revalidatePath)(`/cms/products`),(0,n.revalidatePath)(`/cms/products/inventory`),{success:!0,updatedCount:f,items:p}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Failed to import inventory CSV.`}}}exports.importInventoryCsvAction=o,exports.updateInventoryQuantityAction=a;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { getInventoryItems as e, setSharedInventoryQuantity as t } from "../../../../shared-inventory.es.js";
|
|
3
3
|
import { getServiceRoleSupabaseClient as n } from "@nextblock-cms/db/server";
|
|
4
4
|
import { revalidatePath as r } from "next/cache";
|
|
5
|
-
//#region
|
|
5
|
+
//#region src/lib/pages/cms/products/inventory/actions.ts
|
|
6
6
|
function i(e) {
|
|
7
7
|
let t = [], n = [], r = "", i = !1;
|
|
8
8
|
for (let a = 0; a < e.length; a += 1) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../../../../currency.cjs"),t=require("../../../../variation-utils.cjs"),n=require("../actions.cjs"),r=require("../server-actions.cjs"),i=require("../components/ProductForm.cjs"),a=require("../../payments/queries.cjs");let o=require("@nextblock-cms/utils"),s=require("react/jsx-runtime"),c=require("@nextblock-cms/db/server");async function l({mediaPickerNode:l,availableLanguagesProp:u,translationGroupId:d,targetLanguageId:f,initialData:p}){let[m,h,g,_]=await Promise.all([a.getEnabledPaymentProviders(),a.getStoreConfigStatus(),n.getGlobalProductAttributes(),(0,c.getServiceRoleSupabaseClient)().from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}).then(e=>e.data||[])]),v=(_||[]).map(t=>e.normalizeCurrencyRecord(t)),y=(g||[]).map(e=>({id:e.id,name:e.name,name_translations:e.name_translations||{},slug:e.slug,terms:(e.product_attribute_terms||[]).map(e=>({...e,value_translations:e.value_translations||{}}))})),b=u.find(e=>e.id===p?.language_id)?.code||u.find(e=>e.id===(f?parseInt(f,10):void 0))?.code||u.find(e=>e.is_default)?.code,{attributes:x,variants:S}=t.mapRawVariantRelations(p?.product_variants||[],b),C=p&&{...p,variation_attributes:p.variation_attributes||x.map(e=>({attribute_id:e.id,term_ids:e.terms.map(e=>e.id)})),variants:p.variants||S.map(e=>({...e,upc:e.upc??null,price:e.price/100,prices:Object.entries(e.prices||{}).reduce((e,[t,n])=>(e[t]=(0,o.minorUnitAmountToMajor)(n,t),e),{}),sale_price:typeof e.sale_price==`number`?e.sale_price/100:null,sale_prices:Object.entries(e.sale_prices||{}).reduce((e,[t,n])=>(e[t]=typeof n==`number`?(0,o.minorUnitAmountToMajor)(n,t):null,e),{}),main_media_id:e.main_media_id??null,main_image_url:e.image_url??null}))};return(0,s.jsx)(`div`,{className:`p-8`,children:(0,s.jsx)(i.ProductForm,{mediaPickerNode:l,availableLanguagesProp:u,globalAttributesProp:y,currenciesProp:v,translationGroupId:d,targetLanguageId:f,initialData:C,enabledProviders:m,configStatus:h,createAction:r.createProductAction})})}exports.NewProductPage=l;
|
|
@@ -7,7 +7,7 @@ import { getEnabledPaymentProviders as a, getStoreConfigStatus as o } from "../.
|
|
|
7
7
|
import { minorUnitAmountToMajor as s } from "@nextblock-cms/utils";
|
|
8
8
|
import { jsx as c } from "react/jsx-runtime";
|
|
9
9
|
import { getServiceRoleSupabaseClient as l } from "@nextblock-cms/db/server";
|
|
10
|
-
//#region
|
|
10
|
+
//#region src/lib/pages/cms/products/new/NewProductPage.tsx
|
|
11
11
|
async function u({ mediaPickerNode: u, availableLanguagesProp: d, translationGroupId: f, targetLanguageId: p, initialData: m }) {
|
|
12
12
|
let [h, g, _, v] = await Promise.all([
|
|
13
13
|
a(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../../../currency.cjs");let t=require("@nextblock-cms/utils");function n(e){return Object.entries(e||{}).reduce((e,[n,r])=>(typeof r==`number`&&Number.isFinite(r)&&r>=0?e[(0,t.normalizeCurrencyCode)(n)]=r:r===null&&(e[(0,t.normalizeCurrencyCode)(n)]=null),e),{})}function r(t){let n=e.normalizeCurrencyRecord(t);return n.is_default!==!0&&n.auto_sync_product_prices===!0}function i(t){return t.map(t=>e.normalizeCurrencyRecord(t)).filter(e=>r(e)).map(e=>e.code)}function a(e,t){let r=new Set(i(t)),a=n(e);return Object.entries(a).reduce((e,[t,n])=>(r.has(t)||(e[t]=n),e),{})}function o(n){let{baseAmount:r,defaultCurrencyCode:i,targetCurrencyCode:a,currencies:o}=n;if(typeof r!=`number`||!Number.isFinite(r)||r<0)return null;let s=e.convertMinorUnitAmount({amount:(0,t.majorUnitAmountToMinor)(r,i),fromCurrencyCode:i,toCurrencyCode:a,currencies:o,applyRounding:!0});return(0,t.minorUnitAmountToMajor)(s,a)}function s(i){let{currencies:a,fallbackPrice:s,fallbackSalePrice:c}=i,l=n(i.prices),u=n(i.salePrices),d=a.find(e=>e.is_default)??a[0];if(!d)return{prices:l,salePrices:u};let f=(0,t.normalizeCurrencyCode)(d.code),p=l[f]??(typeof s==`number`?s:null),m=u[f]??(typeof c==`number`?c:null);return{prices:a.reduce((t,n)=>{let i=e.normalizeCurrencyRecord(n);return r(i)?(t[i.code]=o({baseAmount:p,defaultCurrencyCode:f,targetCurrencyCode:i.code,currencies:a}),t):(t[i.code]=l[i.code]??(i.code===f?p:void 0),t)},{}),salePrices:a.reduce((t,n)=>{let i=e.normalizeCurrencyRecord(n);return r(i)?(t[i.code]=o({baseAmount:m,defaultCurrencyCode:f,targetCurrencyCode:i.code,currencies:a}),t):(t[i.code]=u[i.code]??(i.code===f?m:void 0),t)},{})}}function c(e,n){let r=n.find(e=>e.is_default)??n[0],i=r?(0,t.normalizeCurrencyCode)(r.code):`USD`,o=a(e.prices,n),s=a(e.sale_prices,n);return{...e,price:typeof o[i]==`number`?o[i]:e.price,prices:o,sale_price:typeof s[i]==`number`?s[i]:e.sale_price??null,sale_prices:s}}function l(e,t){return e?.map(e=>c(e,t))||[]}function u(e,n){let r=n.find(e=>e.is_default)??n[0],i=r?(0,t.normalizeCurrencyCode)(r.code):`USD`,o=a(e.prices,n),s=a(e.sale_prices,n);return{...e,price:typeof o[i]==`number`?o[i]:e.price,prices:o,sale_price:typeof s[i]==`number`?s[i]:e.sale_price??null,sale_prices:s,variants:l(e.variants,n)}}exports.getStoreManagedPriceCurrencyCodes=i,exports.isCurrencyStoreManagedPrice=r,exports.resolveEditorCurrencyPriceMaps=s,exports.sanitizeProductFormValuesForStoreManagedCurrencies=u,exports.sanitizeVariantDraftForStoreManagedCurrencies=c,exports.sanitizeVariantDraftsForStoreManagedCurrencies=l;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { convertMinorUnitAmount as e, normalizeCurrencyRecord as t } from "../../../currency.es.js";
|
|
2
2
|
import { majorUnitAmountToMinor as n, minorUnitAmountToMajor as r, normalizeCurrencyCode as i } from "@nextblock-cms/utils";
|
|
3
|
-
//#region
|
|
3
|
+
//#region src/lib/pages/cms/products/product-price-sync.ts
|
|
4
4
|
function a(e) {
|
|
5
5
|
return Object.entries(e || {}).reduce((e, [t, n]) => (typeof n == "number" && Number.isFinite(n) && n >= 0 ? e[i(t)] = n : n === null && (e[i(t)] = null), e), {});
|
|
6
6
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use server";const e=require("../../../currency.cjs"),t=require("../../../product-actions.cjs"),n=require("./product-price-sync.cjs"),r=require("../../../freemius-coupons.cjs");let i=require("@nextblock-cms/db/server"),a=require("next/navigation"),o=require("next/cache");function s(e){return e.toLowerCase().trim().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``).replace(/-+/g,`-`).replace(/^-|-$/g,``)}async function c(s){let c=(0,i.createClient)(),{data:l}=await c.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),u=n.sanitizeProductFormValuesForStoreManagedCurrencies(s,(l||[]).map(t=>e.normalizeCurrencyRecord(t))),d=await t.createProduct(c,u);if(u.payment_provider===`freemius`&&d?.id)try{await r.syncProductSaleCouponToFreemius({productId:d.id,client:(0,i.getServiceRoleSupabaseClient)()})}catch(e){console.error(`Failed to sync Freemius sale coupon on create:`,e)}(0,o.revalidatePath)(`/cms/products`),(0,a.redirect)(`/cms/products`)}async function l(e,t,n,r){let i={author_id:n,meta:r,updated_at:new Date().toISOString()},a=async()=>{let{error:n}=await e.from(`product_drafts`).update(i).eq(`product_id`,t);if(n)throw Error(`Failed to save product draft: ${n.message}`)},{data:o,error:s}=await e.from(`product_drafts`).select(`id`).eq(`product_id`,t).maybeSingle();if(s)throw Error(`Failed to read product draft: ${s.message}`);if(o){await a();return}let{data:c,error:l}=await e.from(`blocks`).select(`id, page_id, post_id, product_id, language_id, block_type, content, order, created_at, updated_at`).eq(`product_id`,t).order(`order`,{ascending:!0});if(l)throw Error(`Failed to read product blocks: ${l.message}`);let{error:u}=await e.from(`product_drafts`).insert({...i,blocks:c??[],product_id:t});if(u){if(u.code===`23505`){await a();return}throw Error(`Failed to save product draft: ${u.message}`)}}async function u(t,r){let a=(0,i.createClient)(),{data:{user:o}}=await a.auth.getUser();if(!o)throw Error(`User not authenticated.`);let{data:s}=await a.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),c=n.sanitizeProductFormValuesForStoreManagedCurrencies(r,(s||[]).map(t=>e.normalizeCurrencyRecord(t)));return await l(a,t,o.id,c),{success:!0}}async function d(e){let n=(0,i.createClient)();await t.deleteProduct(n,e),(0,o.revalidatePath)(`/cms/products`)}function f(e){return Array.from(new Set(e.map(e=>e.trim()).filter(Boolean)))}async function p(e){let t=f(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,i.createClient)().from(`products`).delete().in(`id`,t);return n?{success:!1,error:n.message}:((0,o.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function m(e){let t=f(e);if(t.length===0)return{success:!1,error:`Select at least one product.`};let{error:n}=await(0,i.createClient)().from(`products`).update({status:`draft`,updated_at:new Date().toISOString()}).in(`id`,t);return n?{success:!1,error:n.message}:((0,o.revalidatePath)(`/cms/products`),{success:!0,count:t.length})}async function h(e){let t=String(e||``).trim();if(!t)return{error:`Missing product id.`};let n=(0,i.createClient)(),{data:{user:r}}=await n.auth.getUser();if(!r)return{error:`You must be signed in to publish a product.`};let{data:a,error:s}=await n.from(`products`).update({status:`active`,updated_at:new Date().toISOString()}).eq(`id`,t).select(`slug`).single();return s||!a?{error:s?.message||`Could not publish the product.`}:((0,o.revalidatePath)(`/cms/products`),(0,o.revalidatePath)(`/cms/products/${t}/edit`),a.slug&&(0,o.revalidatePath)(`/product/${a.slug}`),{})}async function g(e){let t=(0,i.getServiceRoleSupabaseClient)(),n=e.name.trim(),r=s(e.slug?.trim()||e.name);if(!n||!r)return{success:!1,error:`Attribute name is required.`};let{error:a}=await t.from(`product_attributes`).insert({name:n,slug:r});return a?{success:!1,error:a.message}:((0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function _(e){let{error:t}=await(0,i.getServiceRoleSupabaseClient)().from(`product_attributes`).delete().eq(`id`,e);return t?{success:!1,error:t.message}:((0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function v(e){let t=(0,i.getServiceRoleSupabaseClient)(),n=e.value.trim(),r=s(e.slug?.trim()||e.value);if(!n||!r)return{success:!1,error:`Term value is required.`};let{data:a}=await t.from(`product_attribute_terms`).select(`sort_order`).eq(`attribute_id`,e.attributeId).order(`sort_order`,{ascending:!1}).limit(1),c=typeof a?.[0]?.sort_order==`number`?a[0].sort_order+1:0,{error:l}=await t.from(`product_attribute_terms`).insert({attribute_id:e.attributeId,value:n,slug:r,sort_order:c});return l?{success:!1,error:l.message}:((0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function y(e){let t=(0,i.getServiceRoleSupabaseClient)();for(let[n,r]of e.orderedTermIds.entries()){let{error:i}=await t.from(`product_attribute_terms`).update({sort_order:n,updated_at:new Date().toISOString()}).eq(`id`,r).eq(`attribute_id`,e.attributeId);if(i)return{success:!1,error:i.message}}return(0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0}}async function b(e){let t=(0,i.getServiceRoleSupabaseClient)(),{error:n}=await t.from(`product_attributes`).update({name_translations:e.nameTranslations,updated_at:new Date().toISOString()}).eq(`id`,e.attributeId);if(n)return{success:!1,error:n.message};for(let n of e.termTranslations){let{error:r}=await t.from(`product_attribute_terms`).update({value_translations:n.valueTranslations,updated_at:new Date().toISOString()}).eq(`id`,n.termId).eq(`attribute_id`,e.attributeId);if(r)return{success:!1,error:r.message}}return(0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0}}async function x(e){let{error:t}=await(0,i.getServiceRoleSupabaseClient)().from(`product_attribute_terms`).delete().eq(`id`,e);return t?{success:!1,error:t.message}:((0,o.revalidatePath)(`/cms/products/attributes`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function S(e){let t=(0,i.getServiceRoleSupabaseClient)(),n=e.name.trim(),r=s(e.slug?.trim()||e.name);if(!n||!r)return{success:!1,error:`Category name is required.`};let{data:a,error:c}=await t.from(`categories`).insert({name:n,slug:r,description:e.description?.trim()||null,name_translations:e.nameTranslations||{},description_translations:e.descriptionTranslations||{}}).select().single();return c?{success:!1,error:c.message}:((0,o.revalidatePath)(`/cms/products/categories`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0,category:a})}async function C(e,t){let n=(0,i.getServiceRoleSupabaseClient)(),r=t.name.trim(),a=s(t.slug?.trim()||t.name);if(!r||!a)return{success:!1,error:`Category name is required.`};let{error:c}=await n.from(`categories`).update({name:r,slug:a,description:t.description?.trim()||null,name_translations:t.nameTranslations||{},description_translations:t.descriptionTranslations||{}}).eq(`id`,e);return c?{success:!1,error:c.message}:((0,o.revalidatePath)(`/cms/products/categories`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function w(e){let{error:t}=await(0,i.getServiceRoleSupabaseClient)().from(`categories`).delete().eq(`id`,e);return t?{success:!1,error:t.message}:((0,o.revalidatePath)(`/cms/products/categories`),(0,o.revalidatePath)(`/cms/products/new`),(0,o.revalidatePath)(`/cms/products`),{success:!0})}async function T(e,n){let r=(0,i.getServiceRoleSupabaseClient)();try{return await t.syncCategoriesForTranslationGroup(r,e,n),(0,o.revalidatePath)(`/cms/products`),(0,o.revalidatePath)(`/cms/products/${e}/edit`),{success:!0}}catch(e){return{success:!1,error:e.message}}}exports.bulkDeleteProductsAction=p,exports.bulkDraftProductsAction=m,exports.createCategoryAction=S,exports.createProductAction=c,exports.createProductAttributeAction=g,exports.createProductAttributeTermAction=v,exports.deleteCategoryAction=w,exports.deleteProductAction=d,exports.deleteProductAttributeAction=_,exports.deleteProductAttributeTermAction=x,exports.publishProductAction=h,exports.reorderProductAttributeTermsAction=y,exports.syncProductCategoriesAction=T,exports.updateCategoryAction=C,exports.updateProductAction=u,exports.updateProductAttributeTranslationsAction=b;
|
|
@@ -6,7 +6,7 @@ import { syncProductSaleCouponToFreemius as a } from "../../../freemius-coupons.
|
|
|
6
6
|
import { createClient as o, getServiceRoleSupabaseClient as s } from "@nextblock-cms/db/server";
|
|
7
7
|
import { redirect as c } from "next/navigation";
|
|
8
8
|
import { revalidatePath as l } from "next/cache";
|
|
9
|
-
//#region
|
|
9
|
+
//#region src/lib/pages/cms/products/server-actions.ts
|
|
10
10
|
function u(e) {
|
|
11
11
|
return e.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require("../../../../_virtual/_rolldown/runtime.cjs
|
|
1
|
+
const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../currency.cjs"),n=require("../../../states.cjs"),r=require("../../../inventory-settings.cjs"),i=require("./server-actions.cjs"),a=require("./components/ZoneForm.cjs"),o=require("./components/RateForm.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("lucide-react"),l=require("@nextblock-cms/utils"),u=require("react/jsx-runtime"),d=require("@nextblock-cms/db/server"),f=require("@nextblock-cms/ui");async function p({searchParams:e}){let s=(0,d.getServiceRoleSupabaseClient)(),[{data:p},m,{data:h},{data:g}]=await Promise.all([s.from(`shipping_zones`).select(`
|
|
2
2
|
*,
|
|
3
3
|
shipping_zone_locations (*),
|
|
4
4
|
shipping_zone_methods (*)
|
|
@@ -10,7 +10,7 @@ import { formatPrice as p } from "@nextblock-cms/utils";
|
|
|
10
10
|
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
11
11
|
import { getServiceRoleSupabaseClient as g } from "@nextblock-cms/db/server";
|
|
12
12
|
import { Badge as _, Button as v, Card as y, CardContent as b, CardDescription as x, CardHeader as S, CardTitle as C, Tooltip as w, TooltipContent as T, TooltipProvider as E, TooltipTrigger as D } from "@nextblock-cms/ui";
|
|
13
|
-
//#region
|
|
13
|
+
//#region src/lib/pages/cms/shipping/ShippingPage.tsx
|
|
14
14
|
async function O({ searchParams: O }) {
|
|
15
15
|
let k = g(), [{ data: A }, j, { data: M }, { data: N }] = await Promise.all([
|
|
16
16
|
k.from("shipping_zones").select("\n *,\n shipping_zone_locations (*),\n shipping_zone_methods (*)\n ").order("priority_order", { ascending: !0 }),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../../../../currency.cjs"),t=require("../../../../shipping-rate-currency.cjs"),n=require("../server-actions.cjs");let r=require("react"),i=require("lucide-react"),a=require("@nextblock-cms/utils"),o=require("react/jsx-runtime"),s=require("@nextblock-cms/ui");function c(e,t){if(typeof e!=`number`)return``;let n=(0,a.minorUnitAmountToMajor)(e,t);return(0,a.getCurrencyMinorUnitFactor)(t)===1?n.toFixed(0):n.toFixed(2)}function l(e){return e.reduce((e,t)=>(e[t.code]=(0,a.getCurrencyMinorUnitFactor)(t.code)===1?`0`:`0.00`,e),{})}function u(e,t){let n=String(e||``).trim();if(!n)return null;let r=Number(n);return!Number.isFinite(r)||r<0?null:(0,a.majorUnitAmountToMinor)(r,t)}function d(e){return e.currencies.reduce((t,n)=>(t[n.code]=c(e.amounts[n.code],n.code),t),{})}function f({zoneId:f,zoneName:p,languages:m,currencies:h=[],defaultCurrencyCode:g=`USD`,mode:_=`create`,initialData:v}){let[y,b]=(0,r.useState)(!1),x=_===`edit`,S=(0,r.useMemo)(()=>m.find(e=>e.is_default)||m[0]||null,[m]),C=(0,r.useMemo)(()=>m.filter(e=>!e.is_default),[m]),w=(0,a.normalizeCurrencyCode)(g),T=(0,r.useMemo)(()=>{let t=e.normalizeCurrencyRecord({code:w,symbol:w,exchange_rate:1,is_default:!0,is_active:!0}),n=(h.length>0?h:[t]).map(t=>e.normalizeCurrencyRecord(t)).filter(e=>e.is_active!==!1).sort((e,t)=>e.is_default===t.is_default?e.code.localeCompare(t.code):e.is_default?-1:1);return n.length>0?n:[t]},[h,w]),E=(0,r.useMemo)(()=>T.find(e=>e.is_default)||T[0],[T]),[D,O]=(0,r.useState)(v?.name||``),[k,A]=(0,r.useState)(v?.name_translations||{}),[j,M]=(0,r.useState)(v?.method_type||`flat_rate`),[N,P]=(0,r.useState)(t.normalizeShippingRateCurrencyMode(v?.currency_pricing_mode)),[F,I]=(0,r.useState)((0,a.normalizeCurrencyCode)(v?.cost_currency||E?.code||w)),[L,R]=(0,r.useState)({}),[z,B]=(0,r.useState)({}),[V,H]=(0,r.useState)(!1),U=(0,r.useMemo)(()=>{if(N===`manual`)return T.reduce((e,t)=>(e[t.code]=L[t.code]??``,e),{});let t=T.reduce((e,t)=>(e[t.code]=L[t.code]??(t.code,``),e),{}),n=u(L[F],F);if(n===null)return t;for(let r of T){if(r.code===F){t[r.code]=L[r.code]??c(n,r.code);continue}t[r.code]=c(e.convertMinorUnitAmount({amount:n,fromCurrencyCode:F,toCurrencyCode:r.code,currencies:T}),r.code)}return t},[T,L,N,F]),W=(0,r.useMemo)(()=>{if(N===`manual`)return T.reduce((e,t)=>(e[t.code]=z[t.code]??``,e),{});let t=T.reduce((e,t)=>(e[t.code]=z[t.code]??``,e),{}),n=u(z[F],F);if(n===null)return t;for(let r of T){if(r.code===F){t[r.code]=z[r.code]??c(n,r.code);continue}t[r.code]=c(e.convertMinorUnitAmount({amount:n,fromCurrencyCode:F,toCurrencyCode:r.code,currencies:T}),r.code)}return t},[T,z,N,F]);(0,r.useEffect)(()=>{E&&(T.some(e=>e.code===F)||I(E.code))},[T,E,F]),(0,r.useEffect)(()=>{if(!y||!E)return;let e=t.normalizeShippingRateCurrencyMode(v?.currency_pricing_mode),n=t.sanitizeShippingRateAmountMaps({currencies:T,mode:e,sourceCurrencyCode:v?.cost_currency||E.code,costAmounts:v?.cost_amounts||void 0,minOrderAmounts:v?.min_order_amounts||void 0,fallbackCostAmount:v?.cost_amount,fallbackMinOrderAmount:v?.min_order_amount});O(v?.name||``),A(v?.name_translations||{}),M(v?.method_type||`flat_rate`),P(e),I(n.sourceCurrencyCode),R(d({amounts:n.costAmounts,currencies:T})),B(d({amounts:n.minOrderAmounts,currencies:T}))},[T,E,v,y]);let G=e=>{e!==N&&(e===`manual`&&(R(U),B(W)),P(e))};return(0,o.jsxs)(s.Dialog,{open:y,onOpenChange:b,children:[(0,o.jsx)(s.DialogTrigger,{asChild:!0,children:x?(0,o.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-7 w-7 text-slate-400 hover:text-primary`,children:(0,o.jsx)(i.Edit2,{className:`h-3 w-3`})}):(0,o.jsxs)(s.Button,{variant:`outline`,size:`sm`,className:`h-8 gap-1.5 border-dashed hover:border-solid shadow-sm`,children:[(0,o.jsx)(i.Plus,{className:`h-3.5 w-3.5`}),`Add Rate`]})}),(0,o.jsx)(s.DialogContent,{className:`max-h-[85vh] max-w-4xl overflow-y-auto`,children:(0,o.jsxs)(`form`,{onSubmit:async e=>{e.preventDefault(),H(!0);let t={},r={};if(N===`manual`)for(let e of T){let n=e.code;if(j===`free_shipping`)t[n]=0;else{let e=u(L[n],n);if(e===null){H(!1),alert(`Enter a valid shipping cost for ${n}.`);return}t[n]=e}r[n]=u(z[n],n)??0}else{let e=j===`free_shipping`?0:u(L[F],F);if(e===null){H(!1),alert(`Enter a valid shipping cost for ${F}.`);return}t[F]=e,r[F]=u(z[F],F)??0}let i={name:D,nameTranslations:k,type:j,currencyPricingMode:N,sourceCurrencyCode:F,costAmounts:t,minOrderAmounts:r},a=x&&v?.id?await n.updateShippingRate(v.id,i):await n.createShippingRate(f,i);H(!1),a.success?b(!1):a.error&&alert(a.error)},children:[(0,o.jsxs)(s.DialogHeader,{children:[(0,o.jsx)(s.DialogTitle,{children:x?`Edit Shipping Rate`:`Add Shipping Rate`}),(0,o.jsxs)(s.DialogDescription,{children:[`Configure shipping costs and localized labels for matching orders in `,(0,o.jsx)(`strong`,{children:p}),`.`]})]}),(0,o.jsxs)(`div`,{className:`grid gap-5 py-6`,children:[(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsxs)(s.Label,{htmlFor:`rate-name`,children:[`Rate Name`,S?` (${S.name})`:``]}),(0,o.jsx)(s.Input,{id:`rate-name`,value:D,onChange:e=>O(e.target.value),placeholder:`e.g. Standard, Express, Free Shipping`,required:!0})]}),C.length>0&&(0,o.jsxs)(`div`,{className:`space-y-4 rounded-xl border bg-slate-50/70 p-4 dark:bg-slate-900/40`,children:[(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(i.Languages,{className:`h-4 w-4 text-slate-500`}),(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`p`,{className:`text-sm font-medium`,children:`Translations`}),(0,o.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Add translated shipping rate labels for the active storefront languages.`})]})]}),(0,o.jsx)(`div`,{className:`grid gap-4 md:grid-cols-2`,children:C.map(e=>(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsx)(s.Label,{htmlFor:`rate-name-${e.code}`,children:e.name}),(0,o.jsx)(s.Input,{id:`rate-name-${e.code}`,value:k[e.code]||``,onChange:t=>A(n=>({...n,[e.code]:t.target.value})),placeholder:D||`Translated label`})]},e.code))})]}),(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsx)(s.Label,{htmlFor:`type`,children:`Method Type`}),(0,o.jsxs)(s.Select,{value:j,onValueChange:e=>{M(e),e===`free_shipping`&&R(l(T))},children:[(0,o.jsx)(s.SelectTrigger,{id:`type`,className:`bg-slate-50/50 dark:bg-slate-900/50`,children:(0,o.jsx)(s.SelectValue,{placeholder:`Select type`})}),(0,o.jsxs)(s.SelectContent,{children:[(0,o.jsx)(s.SelectItem,{value:`flat_rate`,children:(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`div`,{className:`p-1 min-w-5 h-5 rounded bg-emerald-100 dark:bg-emerald-900/30 text-emerald-600`,children:(0,o.jsx)(i.DollarSign,{className:`h-3 w-3`})}),(0,o.jsx)(`span`,{children:`Flat Rate`})]})}),(0,o.jsx)(s.SelectItem,{value:`free_shipping`,children:(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`div`,{className:`p-1 min-w-5 h-5 rounded bg-amber-100 dark:bg-amber-900/30 text-amber-600`,children:(0,o.jsx)(i.Gift,{className:`h-3 w-3`})}),(0,o.jsx)(`span`,{children:`Free Shipping`})]})})]})]})]}),(0,o.jsxs)(`div`,{className:`space-y-3 rounded-xl border bg-slate-50/70 p-4 dark:bg-slate-900/40`,children:[(0,o.jsxs)(`label`,{className:`flex items-start gap-3`,children:[(0,o.jsx)(`input`,{type:`checkbox`,checked:N===`auto`,onChange:e=>G(e.target.checked?`auto`:`manual`),className:`mt-1 h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary`}),(0,o.jsxs)(`span`,{className:`space-y-1`,children:[(0,o.jsx)(`span`,{className:`block text-sm font-medium text-slate-900 dark:text-slate-100`,children:`Auto-sync all currency rates from one source amount`}),(0,o.jsx)(`span`,{className:`block text-xs text-muted-foreground`,children:`Turn this off to set exact shipping costs and free-shipping thresholds for every active currency manually.`})]})]}),N===`auto`?(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsx)(s.Label,{htmlFor:`rate-currency`,children:`Sync From Currency`}),(0,o.jsxs)(s.Select,{value:F,onValueChange:e=>{let t=(0,a.normalizeCurrencyCode)(e);R(e=>({...e,[t]:U[t]??e[t]??``})),B(e=>({...e,[t]:W[t]??e[t]??``})),I(t)},children:[(0,o.jsx)(s.SelectTrigger,{id:`rate-currency`,className:`bg-background`,children:(0,o.jsx)(s.SelectValue,{placeholder:`Select currency`})}),(0,o.jsx)(s.SelectContent,{children:T.map(e=>(0,o.jsxs)(s.SelectItem,{value:e.code,children:[e.code,e.is_default?` (Default)`:``]},e.code))})]}),(0,o.jsx)(`p`,{className:`text-[10px] text-slate-500`,children:`Enter the source amount once and the other currencies will be derived automatically using the current FX rates.`})]}):(0,o.jsx)(`p`,{className:`text-[10px] text-slate-500`,children:`Manual mode stores exact values per currency. This is the best choice when shipping should not follow exchange-rate math directly.`})]}),(0,o.jsxs)(`div`,{className:`space-y-3`,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`p`,{className:`text-sm font-medium`,children:`Currency Rates`}),(0,o.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:j===`free_shipping`?`Free-shipping methods keep cost at zero, but you can still control the threshold per currency.`:N===`auto`?`Only ${F} is editable. The rest are derived automatically.`:`Set the exact shopper-facing shipping price for each active currency.`})]}),(0,o.jsx)(`div`,{className:`grid gap-4 md:grid-cols-2 xl:grid-cols-3`,children:T.map(e=>{let t=N===`auto`&&e.code!==F,n=(0,a.getCurrencyMinorUnitFactor)(e.code)===1?`1`:`0.01`;return(0,o.jsxs)(`div`,{className:`space-y-4 rounded-xl border bg-card/70 p-4 shadow-sm`,children:[(0,o.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`p`,{className:`font-medium`,children:e.code}),(0,o.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Rate `,e.exchange_rate]})]}),(0,o.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[e.is_default?(0,o.jsx)(s.Badge,{variant:`outline`,children:`Default`}):null,N===`auto`&&e.code===F?(0,o.jsx)(s.Badge,{children:`Source`}):null,t?(0,o.jsx)(s.Badge,{variant:`outline`,children:`Derived`}):null]})]}),(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsxs)(s.Label,{htmlFor:`rate-cost-${e.code}`,children:[`Cost (`,e.code,`)`]}),(0,o.jsxs)(`div`,{className:`relative`,children:[(0,o.jsx)(i.DollarSign,{className:`absolute left-2.5 top-2.5 h-4 w-4 text-slate-400`}),(0,o.jsx)(s.Input,{id:`rate-cost-${e.code}`,type:`number`,step:n,min:`0`,value:U[e.code]??``,onChange:t=>R(n=>({...n,[e.code]:t.target.value})),className:`pl-9 bg-slate-50/50 dark:bg-slate-900/50 disabled:opacity-70`,disabled:j===`free_shipping`||t,required:j!==`free_shipping`&&N===`manual`})]})]}),(0,o.jsxs)(`div`,{className:`space-y-2`,children:[(0,o.jsxs)(s.Label,{htmlFor:`rate-threshold-${e.code}`,children:[`Free-Shipping Threshold (`,e.code,`)`]}),(0,o.jsxs)(`div`,{className:`relative`,children:[(0,o.jsx)(i.DollarSign,{className:`absolute left-2.5 top-2.5 h-4 w-4 text-slate-400`}),(0,o.jsx)(s.Input,{id:`rate-threshold-${e.code}`,type:`number`,step:n,min:`0`,value:W[e.code]??``,onChange:t=>B(n=>({...n,[e.code]:t.target.value})),className:`pl-9 bg-slate-50/50 dark:bg-slate-900/50 disabled:opacity-70`,disabled:t,placeholder:(0,a.getCurrencyMinorUnitFactor)(e.code)===1?`0`:`0.00`})]})]}),t?(0,o.jsxs)(`p`,{className:`text-[10px] text-muted-foreground`,children:[`This currency is synced automatically from `,F,`.`]}):N===`manual`?(0,o.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`Enter the exact amount shoppers should see in this currency.`}):null]},e.code)})})]})]}),(0,o.jsxs)(s.DialogFooter,{className:`bg-slate-50 dark:bg-slate-900/50 -mx-6 -mb-6 p-4 border-t dark:border-slate-800`,children:[(0,o.jsx)(s.Button,{type:`button`,variant:`ghost`,onClick:()=>b(!1),disabled:V,children:`Cancel`}),(0,o.jsx)(s.Button,{type:`submit`,disabled:V||!D.trim(),children:V?x?`Saving...`:`Adding...`:x?`Save Changes`:`Add Rate`})]})]})})]})}exports.RateForm=f;
|
|
@@ -7,7 +7,7 @@ import { DollarSign as s, Edit2 as ne, Gift as re, Languages as ie, Plus as ae }
|
|
|
7
7
|
import { getCurrencyMinorUnitFactor as c, majorUnitAmountToMinor as l, minorUnitAmountToMajor as u, normalizeCurrencyCode as d } from "@nextblock-cms/utils";
|
|
8
8
|
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
9
|
import { Badge as m, Button as h, Dialog as oe, DialogContent as se, DialogDescription as ce, DialogFooter as le, DialogHeader as ue, DialogTitle as de, DialogTrigger as fe, Input as g, Label as _, Select as pe, SelectContent as v, SelectItem as y, SelectTrigger as b, SelectValue as x } from "@nextblock-cms/ui";
|
|
10
|
-
//#region
|
|
10
|
+
//#region src/lib/pages/cms/shipping/components/RateForm.tsx
|
|
11
11
|
function S(e, t) {
|
|
12
12
|
if (typeof e != "number") return "";
|
|
13
13
|
let n = u(e, t);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../countries.cjs"),n=require("../../../../states.cjs"),r=require("../server-actions.cjs");let i=require("react");i=e.__toESM(i,1);let a=require("lucide-react"),o=require("react/jsx-runtime"),s=require("@nextblock-cms/ui");function c(e=[]){return[...new Set(e.map(e=>e.country_code))]}function l(e=[]){return e.reduce((e,t)=>{if(!t.state_code)return e;let n=new Set(e[t.country_code]||[]);return n.add(t.state_code),e[t.country_code]=[...n],e},{})}function u(e,t){return e.flatMap(e=>{let n=t[e]||[];return n.length===0?[{country_code:e,state_code:null}]:n.map(t=>({country_code:e,state_code:t}))})}function d({mode:e=`create`,initialData:d}){let[f,p]=(0,i.useState)(!1),m=e===`edit`,[h,g]=(0,i.useState)(d?.name||``),[_,v]=(0,i.useState)(d?.priority_order||0),[y,b]=(0,i.useState)(c(d?.locations)),[x,S]=(0,i.useState)(l(d?.locations)),[C,w]=(0,i.useState)(``),[T,E]=(0,i.useState)(!1);(0,i.useEffect)(()=>{f&&(g(d?.name||``),v(d?.priority_order||0),b(c(d?.locations)),S(l(d?.locations)),w(``))},[d,f]);let D=(0,i.useMemo)(()=>{let e=C.trim().toLowerCase();return e?t.countries.filter(t=>t.name.toLowerCase().includes(e)||t.code.toLowerCase().includes(e)):t.countries},[C]),O=(0,i.useMemo)(()=>t.countries.filter(e=>y.includes(e.code)),[y]),k=e=>{b(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e]),S(t=>{if(t[e]){let n={...t};return delete n[e],n}return t})},A=(e,t)=>{S(n=>{let r=new Set(n[e]||[]);return r.has(t)?r.delete(t):r.add(t),{...n,[e]:[...r]}})};return(0,o.jsxs)(s.Dialog,{open:f,onOpenChange:p,children:[(0,o.jsx)(s.DialogTrigger,{asChild:!0,children:m?(0,o.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8 text-slate-400 hover:text-primary`,children:(0,o.jsx)(a.Edit2,{className:`h-4 w-4`})}):(0,o.jsxs)(s.Button,{className:`gap-2 shadow-sm`,children:[(0,o.jsx)(a.Plus,{className:`h-4 w-4`}),`New Zone`]})}),(0,o.jsx)(s.DialogContent,{className:`max-w-4xl max-h-[90vh] flex flex-col overflow-hidden`,children:(0,o.jsxs)(`form`,{onSubmit:async e=>{if(e.preventDefault(),!h||y.length===0)return;E(!0);let t=u(y,x),n=m&&d?.id?await r.updateShippingZone(d.id,h,_,t):await r.createShippingZone(h,_,t);E(!1),n.success?(p(!1),m||(g(``),v(0),b([]),S({}),w(``))):n.error&&alert(n.error)},className:`flex h-full flex-col overflow-hidden`,children:[(0,o.jsxs)(s.DialogHeader,{children:[(0,o.jsx)(s.DialogTitle,{children:m?`Edit Shipping Zone`:`Create Shipping Zone`}),(0,o.jsx)(s.DialogDescription,{children:`Select countries first, then optionally limit a zone to specific states or provinces. Leaving state selections empty keeps the whole country in the zone.`})]}),(0,o.jsxs)(`div`,{className:`grid gap-6 overflow-y-auto py-6 pr-2`,children:[(0,o.jsxs)(`div`,{className:`grid grid-cols-4 items-center gap-4`,children:[(0,o.jsx)(s.Label,{htmlFor:`name`,className:`text-right`,children:`Zone Name`}),(0,o.jsx)(s.Input,{id:`name`,value:h,onChange:e=>g(e.target.value),placeholder:`e.g. North America, Canada East, US West`,className:`col-span-3`,required:!0})]}),(0,o.jsxs)(`div`,{className:`grid grid-cols-4 items-center gap-4`,children:[(0,o.jsx)(s.Label,{htmlFor:`priority`,className:`text-right`,children:`Priority Order`}),(0,o.jsx)(s.Input,{id:`priority`,type:`number`,value:_,onChange:e=>v(Number(e.target.value)),className:`col-span-3`})]}),(0,o.jsxs)(`div`,{className:`grid gap-6 lg:grid-cols-[1.2fr_1fr]`,children:[(0,o.jsxs)(`div`,{className:`space-y-4`,children:[(0,o.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,o.jsxs)(s.Label,{className:`text-sm font-semibold`,children:[`Countries (`,y.length,`)`]}),(0,o.jsxs)(`div`,{className:`relative w-full max-w-xs`,children:[(0,o.jsx)(a.Search,{className:`absolute left-2.5 top-2.5 h-4 w-4 text-slate-400`}),(0,o.jsx)(s.Input,{placeholder:`Search countries...`,className:`pl-9 h-9`,value:C,onChange:e=>w(e.target.value)})]})]}),(0,o.jsx)(s.Card,{className:`border-slate-200 bg-slate-50/30 p-4 dark:border-slate-800 dark:bg-slate-900/30`,children:(0,o.jsx)(`div`,{className:`grid max-h-[360px] grid-cols-1 gap-3 overflow-y-auto pr-1 sm:grid-cols-2`,children:D.map(e=>{let t=y.includes(e.code);return(0,o.jsxs)(`div`,{className:`flex items-center space-x-2 rounded-md border p-2 transition-colors ${t?`border-primary/30 bg-primary/5 text-primary`:`border-transparent hover:bg-slate-100 dark:hover:bg-slate-800/60`}`,children:[(0,o.jsx)(s.Checkbox,{id:`country-${e.code}`,checked:t,onCheckedChange:()=>k(e.code)}),(0,o.jsxs)(`label`,{htmlFor:`country-${e.code}`,className:`flex-1 cursor-pointer text-xs py-1`,children:[e.name,` (`,e.code,`)`]})]},e.code)})})})]}),(0,o.jsxs)(`div`,{className:`space-y-4`,children:[(0,o.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(a.MapPin,{className:`h-4 w-4 text-slate-500`}),(0,o.jsx)(s.Label,{className:`text-sm font-semibold`,children:`States / Provinces`})]}),O.length===0?(0,o.jsx)(s.Card,{className:`border-dashed p-4 text-sm text-muted-foreground`,children:`Select one or more countries to optionally narrow the zone to specific states or provinces.`}):(0,o.jsx)(`div`,{className:`space-y-4`,children:O.map(e=>{let t=n.getStatesForCountry(e.code),r=x[e.code]||[];return(0,o.jsx)(s.Card,{className:`p-4`,children:(0,o.jsxs)(`div`,{className:`space-y-3`,children:[(0,o.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`p`,{className:`font-medium`,children:[e.name,` (`,e.code,`)`]}),(0,o.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t.length>0?`Leave all unchecked to apply this zone to the whole country.`:`This country uses a country-level zone in the current UI.`})]}),(0,o.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:r.length>0?`${r.length} selected`:`Whole country`})]}),t.length>0?(0,o.jsx)(`div`,{className:`grid max-h-[220px] grid-cols-1 gap-2 overflow-y-auto pr-1 sm:grid-cols-2`,children:t.map(t=>{let n=r.includes(t.code);return(0,o.jsxs)(`div`,{className:`flex items-center space-x-2 rounded-md border p-2 transition-colors ${n?`border-primary/30 bg-primary/5 text-primary`:`border-transparent hover:bg-slate-50 dark:hover:bg-slate-800/60`}`,children:[(0,o.jsx)(s.Checkbox,{id:`${e.code}-${t.code}`,checked:n,onCheckedChange:()=>A(e.code,t.code)}),(0,o.jsxs)(`label`,{htmlFor:`${e.code}-${t.code}`,className:`flex-1 cursor-pointer text-xs py-1`,children:[t.name,` (`,t.code,`)`]})]},`${e.code}-${t.code}`)})}):null]})},e.code)})})]})]})]}),(0,o.jsxs)(s.DialogFooter,{className:`mt-auto border-t pt-4`,children:[(0,o.jsx)(s.Button,{type:`button`,variant:`ghost`,onClick:()=>p(!1),children:`Cancel`}),(0,o.jsx)(s.Button,{type:`submit`,disabled:T||!h||y.length===0,children:T?m?`Updating...`:`Creating...`:m?`Save Changes`:`Create Zone`})]})]})})]})}exports.ZoneForm=d;
|
|
@@ -6,7 +6,7 @@ import { useEffect as i, useMemo as a, useState as o } from "react";
|
|
|
6
6
|
import { Edit2 as s, MapPin as c, Plus as l, Search as u } from "lucide-react";
|
|
7
7
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
8
|
import { Button as p, Card as m, Checkbox as h, Dialog as g, DialogContent as _, DialogDescription as v, DialogFooter as y, DialogHeader as b, DialogTitle as x, DialogTrigger as S, Input as C, Label as w } from "@nextblock-cms/ui";
|
|
9
|
-
//#region
|
|
9
|
+
//#region src/lib/pages/cms/shipping/components/ZoneForm.tsx
|
|
10
10
|
function T(e = []) {
|
|
11
11
|
return [...new Set(e.map((e) => e.country_code))];
|
|
12
12
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./server-actions.cjs"),t=require("./ShippingPage.cjs");exports.ShippingPage=t.ShippingPage,exports.createShippingRate=e.createShippingRate,exports.createShippingZone=e.createShippingZone,exports.deleteShippingRate=e.deleteShippingRate,exports.deleteShippingZone=e.deleteShippingZone,exports.updateInventoryTrackingAction=e.updateInventoryTrackingAction,exports.updateShippingRate=e.updateShippingRate,exports.updateShippingZone=e.updateShippingZone;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use server";const e=require("../../../currency.cjs"),t=require("../../../countries.cjs"),n=require("../../../shipping-rate-currency.cjs"),r=require("../../../states.cjs"),i=require("../../../inventory-settings.cjs");let a=require("@nextblock-cms/db/server"),o=require("next/navigation"),s=require("next/cache");function c(e){return Object.entries(e||{}).reduce((e,[t,n])=>{let r=t.trim().toLowerCase(),i=n.trim();return r&&i&&(e[r]=i),e},{})}async function l(e){let t=(0,a.createClient)(),{data:{user:n}}=await t.auth.getUser();if(!n)throw Error(`Unauthorized`);let{data:r}=await t.from(`profiles`).select(`role`).eq(`id`,n.id).single();if(!r||r.role!==`ADMIN`)throw Error(`Forbidden`);let c=e.getAll(`trackQuantities`).includes(`true`),l=await i.getEcommerceInventorySettings(t),{error:u}=await i.upsertEcommerceInventorySettings(t,{trackQuantities:c,enableTaxes:l.enableTaxes,taxCalculationMode:l.taxCalculationMode});if(u)throw Error(u.message);(0,s.revalidatePath)(`/cms/shipping`),(0,o.redirect)(`/cms/shipping?success=Inventory settings updated`)}function u(e){let n=new Map;for(let i of e){let e=t.normalizeCountryCode(i.country_code);if(!e)continue;let a=r.normalizeSubdivisionCode(e,i.state_code)||null,o=`${e}:${a??`*`}`;n.set(o,{country_code:e,state_code:a})}return[...n.values()]}async function d(e){let{data:t,error:n}=await e.from(`currencies`).select(`code, is_default`).eq(`is_active`,!0).order(`is_default`,{ascending:!1}).order(`code`,{ascending:!0});return n?{error:n.message}:{currencies:t||[]}}async function f(e,t,n){let r=(0,a.getServiceRoleSupabaseClient)(),i=u(n),{data:o,error:c}=await r.from(`shipping_zones`).insert({name:e,priority_order:t}).select().single();if(c||!o)return{error:c?.message||`Failed to create zone`};if(i.length>0){let e=i.map(e=>({zone_id:o.id,country_code:e.country_code,state_code:e.state_code??null})),{error:t}=await r.from(`shipping_zone_locations`).insert(e);if(t)return{error:t.message}}return(0,s.revalidatePath)(`/cms/shipping`),{success:!0}}async function p(e,t,n,r){let i=(0,a.getServiceRoleSupabaseClient)(),o=u(r),{error:c}=await i.from(`shipping_zones`).update({name:t,priority_order:n,updated_at:new Date().toISOString()}).eq(`id`,e);if(c)return{error:c.message||`Failed to update zone`};let{error:l}=await i.from(`shipping_zone_locations`).delete().eq(`zone_id`,e);if(l)return{error:`Failed to refresh locations`};if(o.length>0){let t=o.map(t=>({zone_id:e,country_code:t.country_code,state_code:t.state_code??null})),{error:n}=await i.from(`shipping_zone_locations`).insert(t);if(n)return{error:n.message}}return(0,s.revalidatePath)(`/cms/shipping`),{success:!0}}async function m(e){let{error:t}=await(0,a.getServiceRoleSupabaseClient)().from(`shipping_zones`).delete().eq(`id`,e);return t?{error:t.message}:((0,s.revalidatePath)(`/cms/shipping`),{success:!0})}async function h(t,r){let i=(0,a.getServiceRoleSupabaseClient)(),o=await d(i);if(`error`in o)return{error:o.error};let l=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).insert({zone_id:t,name:r.name.trim(),name_translations:c(r.nameTranslations),method_type:r.type,currency_pricing_mode:l.mode,cost_amount:l.costAmounts[l.sourceCurrencyCode],cost_amounts:l.costAmounts,cost_currency:l.sourceCurrencyCode,min_order_amount:l.minOrderAmounts[l.sourceCurrencyCode],min_order_amounts:l.minOrderAmounts});return u?{error:u.message}:((0,s.revalidatePath)(`/cms/shipping`),{success:!0})}async function g(t,r){let i=(0,a.getServiceRoleSupabaseClient)(),o=await d(i);if(`error`in o)return{error:o.error};let l=n.sanitizeShippingRateAmountMaps({currencies:o.currencies.map(t=>e.normalizeCurrencyRecord(t)),mode:r.currencyPricingMode,sourceCurrencyCode:r.sourceCurrencyCode,costAmounts:r.costAmounts,minOrderAmounts:r.minOrderAmounts,fallbackCostAmount:r.cost,fallbackMinOrderAmount:r.minOrderAmount}),{error:u}=await i.from(`shipping_zone_methods`).update({name:r.name.trim(),name_translations:c(r.nameTranslations),method_type:r.type,currency_pricing_mode:l.mode,cost_amount:l.costAmounts[l.sourceCurrencyCode],cost_amounts:l.costAmounts,cost_currency:l.sourceCurrencyCode,min_order_amount:l.minOrderAmounts[l.sourceCurrencyCode],min_order_amounts:l.minOrderAmounts,updated_at:new Date().toISOString()}).eq(`id`,t);return u?{error:u.message}:((0,s.revalidatePath)(`/cms/shipping`),{success:!0})}async function _(e){let{error:t}=await(0,a.getServiceRoleSupabaseClient)().from(`shipping_zone_methods`).delete().eq(`id`,e);return t?{error:t.message}:((0,s.revalidatePath)(`/cms/shipping`),{success:!0})}exports.createShippingRate=h,exports.createShippingZone=f,exports.deleteShippingRate=_,exports.deleteShippingZone=m,exports.updateInventoryTrackingAction=l,exports.updateShippingRate=g,exports.updateShippingZone=p;
|
|
@@ -7,7 +7,7 @@ import { getEcommerceInventorySettings as i, upsertEcommerceInventorySettings as
|
|
|
7
7
|
import { createClient as o, getServiceRoleSupabaseClient as s } from "@nextblock-cms/db/server";
|
|
8
8
|
import { redirect as c } from "next/navigation";
|
|
9
9
|
import { revalidatePath as l } from "next/cache";
|
|
10
|
-
//#region
|
|
10
|
+
//#region src/lib/pages/cms/shipping/server-actions.ts
|
|
11
11
|
function u(e) {
|
|
12
12
|
return Object.entries(e || {}).reduce((e, [t, n]) => {
|
|
13
13
|
let r = t.trim().toLowerCase(), i = n.trim();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../states.cjs"),n=require("../../../inventory-settings.cjs"),r=require("../payments/queries.cjs"),i=require("./actions.cjs"),a=require("./components/TaxRateForm.cjs");let o=require("next/link");o=e.__toESM(o,1);let s=require("lucide-react"),c=require("react/jsx-runtime"),l=require("@nextblock-cms/db/server"),u=require("@nextblock-cms/ui");function d(e){return`${e.toFixed(4).replace(/\.?0+$/,``)}%`}function f(e){return e.state_code?`${e.country_code} - ${t.resolveSubdivisionName(e.country_code,e.state_code)}`:`${e.country_code} - Country-wide`}async function p({searchParams:e}){let t=(0,l.createClient)(),p=(0,l.getServiceRoleSupabaseClient)(),[m,h,g]=await Promise.all([n.getEcommerceInventorySettings(t),r.getEnabledPaymentProviders(),p.from(`tax_rates`).select(`id, country_code, state_code, tax_name, tax_rate, created_at, updated_at`).order(`country_code`).order(`state_code`).order(`tax_name`)]),_=g.data||[],v=g.error,y=h.stripe;return(0,c.jsxs)(`div`,{className:`mx-auto w-full max-w-6xl space-y-6 px-6 py-8`,children:[e?.success?(0,c.jsx)(`div`,{className:`rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700`,children:e.success}):null,(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,size:`icon`,"aria-label":`Back to shipping`,children:(0,c.jsx)(o.default,{href:`/cms/shipping`,children:(0,c.jsx)(s.ArrowLeft,{className:`h-4 w-4`})})}),(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`h1`,{className:`text-2xl font-bold`,children:`Tax Settings`}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Configure Stripe tax behavior globally and maintain manual country or state/province tax rates for physical goods.`})]})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsxs)(u.Badge,{variant:y?`default`:`outline`,className:`uppercase`,children:[`Stripe `,y?`Enabled`:`Disabled`]}),(0,c.jsx)(`div`,{className:`rounded-full border bg-muted/30 p-3 text-muted-foreground`,children:(0,c.jsx)(s.Settings2,{className:`h-5 w-5`})})]})]}),y?(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(u.Card,{children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Global Tax Controls`}),(0,c.jsx)(u.CardDescription,{children:`Manual mode uses the tax rates below. Automatic mode uses Stripe Tax during Stripe Checkout instead of a free third-party tax API.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsxs)(`form`,{action:i.updateTaxSettingsAction,className:`space-y-6`,children:[(0,c.jsxs)(`div`,{className:`rounded-lg border bg-muted/20 p-4`,children:[(0,c.jsx)(`input`,{type:`hidden`,name:`enableTaxes`,value:`false`}),(0,c.jsxs)(`label`,{htmlFor:`enable-taxes`,className:`flex cursor-pointer items-start gap-3`,children:[(0,c.jsx)(`input`,{id:`enable-taxes`,name:`enableTaxes`,type:`checkbox`,value:`true`,defaultChecked:m.enableTaxes,className:`mt-1 h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary`}),(0,c.jsxs)(`span`,{className:`space-y-1`,children:[(0,c.jsx)(`span`,{className:`block font-medium`,children:`Enable taxes`}),(0,c.jsx)(`span`,{className:`block text-sm text-muted-foreground`,children:`When disabled, tax totals resolve to zero even if product or jurisdiction records exist.`})]})]})]}),(0,c.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-[minmax(0,1fr)_auto] md:items-end`,children:[(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`label`,{htmlFor:`tax-calculation-mode`,className:`text-sm font-medium text-foreground`,children:`Tax calculation mode`}),(0,c.jsxs)(`select`,{id:`tax-calculation-mode`,name:`taxCalculationMode`,defaultValue:m.taxCalculationMode,className:`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm`,children:[(0,c.jsx)(`option`,{value:`manual`,children:`Manual tax rates`}),(0,c.jsx)(`option`,{value:`automatic`,children:`Automatic via Stripe Tax`})]}),(0,c.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Automatic mode depends on your Stripe Tax setup. Manual rates stay saved and can be used again if you switch back later.`})]}),(0,c.jsx)(`div`,{className:`flex justify-end`,children:(0,c.jsx)(u.Button,{type:`submit`,children:`Save Tax Settings`})})]})]})})]}),(0,c.jsxs)(u.Card,{children:[(0,c.jsx)(u.CardHeader,{children:(0,c.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,c.jsxs)(`div`,{children:[(0,c.jsx)(u.CardTitle,{children:`Manual Tax Rates`}),(0,c.jsx)(u.CardDescription,{children:`Add combined taxes as separate rows. For example, create both GST and PST for the same province if they should stack.`})]}),(0,c.jsx)(u.Badge,{variant:m.taxCalculationMode===`manual`?`default`:`outline`,children:m.taxCalculationMode===`manual`?`Active Mode`:`Stored for Manual Mode`})]})}),(0,c.jsxs)(u.CardContent,{className:`space-y-6`,children:[v?(0,c.jsx)(`div`,{className:`rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800`,children:`Tax rates couldn't be loaded yet. This usually means the new tax migration hasn't been applied to the current database.`}):null,v?null:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(`div`,{className:`rounded-xl border bg-card p-4`,children:[(0,c.jsxs)(`div`,{className:`mb-4 flex items-center gap-2`,children:[(0,c.jsx)(s.ShieldCheck,{className:`h-4 w-4 text-primary`}),(0,c.jsx)(`h2`,{className:`font-semibold`,children:`Create a Tax Rate`})]}),(0,c.jsx)(a.TaxRateForm,{})]}),(0,c.jsx)(`div`,{className:`space-y-4`,children:_.length===0?(0,c.jsxs)(`div`,{className:`rounded-xl border border-dashed bg-muted/10 px-4 py-8 text-center`,children:[(0,c.jsx)(`p`,{className:`font-medium`,children:`No manual tax rates yet`}),(0,c.jsx)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:`Add country-wide or state/province-specific rows to start calculating manual taxes.`})]}):_.map(e=>(0,c.jsxs)(u.Card,{className:`border-muted`,children:[(0,c.jsx)(u.CardHeader,{className:`pb-4`,children:(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,c.jsxs)(`div`,{className:`space-y-1`,children:[(0,c.jsx)(u.CardTitle,{className:`text-base`,children:e.tax_name}),(0,c.jsx)(u.CardDescription,{children:f(e)})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsx)(u.Badge,{variant:`outline`,children:d(Number(e.tax_rate))}),(0,c.jsx)(`form`,{action:async()=>{"use server";await i.deleteTaxRateAction(e.id)},children:(0,c.jsx)(u.Button,{type:`submit`,variant:`ghost`,size:`icon`,"aria-label":`Delete tax rate`,children:(0,c.jsx)(s.Trash2,{className:`h-4 w-4`})})})]})]})}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(a.TaxRateForm,{initialData:e,submitLabel:`Update tax rate`,compact:!0})})]},e.id))})]})]})]})]}):(0,c.jsxs)(u.Card,{className:`border-dashed`,children:[(0,c.jsxs)(u.CardHeader,{children:[(0,c.jsx)(u.CardTitle,{children:`Enable Stripe to configure physical-product taxes`}),(0,c.jsx)(u.CardDescription,{children:`Stripe tax settings apply whenever Stripe is enabled for physical products. Freemius still handles taxes on its own digital checkout flow.`})]}),(0,c.jsx)(u.CardContent,{children:(0,c.jsx)(u.Button,{asChild:!0,variant:`outline`,children:(0,c.jsx)(o.default,{href:`/cms/payments`,children:`Open Payment Settings`})})})]})]})}exports.TaxesPage=p;
|
|
@@ -8,7 +8,7 @@ import { ArrowLeft as s, Settings2 as c, ShieldCheck as l, Trash2 as u } from "l
|
|
|
8
8
|
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
9
|
import { createClient as m, getServiceRoleSupabaseClient as h } from "@nextblock-cms/db/server";
|
|
10
10
|
import { Badge as g, Button as _, Card as v, CardContent as y, CardDescription as b, CardHeader as x, CardTitle as S } from "@nextblock-cms/ui";
|
|
11
|
-
//#region
|
|
11
|
+
//#region src/lib/pages/cms/taxes/TaxesPage.tsx
|
|
12
12
|
function C(e) {
|
|
13
13
|
return `${e.toFixed(4).replace(/\.?0+$/, "")}%`;
|
|
14
14
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use server";const e=require("../../../countries.cjs"),t=require("../../../states.cjs"),n=require("../../../inventory-settings.cjs");let r=require("@nextblock-cms/db/server"),i=require("next/navigation"),a=require("next/cache");async function o(){let e=(0,r.createClient)(),{data:{user:t}}=await e.auth.getUser();if(!t)throw Error(`Unauthorized`);let{data:n}=await e.from(`profiles`).select(`role`).eq(`id`,t.id).single();if(!n||n.role!==`ADMIN`)throw Error(`Forbidden`);return e}async function s(e){let t=await o(),r=await n.getEcommerceInventorySettings(t),s=e.getAll(`enableTaxes`).includes(`true`),c=e.get(`taxCalculationMode`)===`automatic`?`automatic`:`manual`,{error:l}=await n.upsertEcommerceInventorySettings(t,{trackQuantities:r.trackQuantities,enableTaxes:s,taxCalculationMode:c});if(l)throw Error(l.message);(0,a.revalidatePath)(`/cms/shipping`),(0,a.revalidatePath)(`/cms/settings/taxes`),(0,i.redirect)(`/cms/settings/taxes?success=Tax settings updated`)}async function c(n){let r=await o(),i=String(n.get(`id`)||``).trim(),s=e.normalizeCountryCode(String(n.get(`country_code`)||``).trim()),c=String(n.get(`state_code`)||``).trim(),l=String(n.get(`tax_name`)||``).trim(),u=Number(n.get(`tax_rate`));if(!s)throw Error(`Country code is required.`);if(!l)throw Error(`Tax name is required.`);if(!Number.isFinite(u)||u<0||u>100)throw Error(`Tax rate must be between 0 and 100.`);let d={country_code:s,state_code:t.normalizeSubdivisionCode(s,c)||null,tax_name:l,tax_rate:u},{error:f}=await(i?r.from(`tax_rates`).update(d).eq(`id`,i):r.from(`tax_rates`).insert(d));if(f)throw Error(f.message);(0,a.revalidatePath)(`/cms/settings/taxes`)}async function l(e){let{error:t}=await(await o()).from(`tax_rates`).delete().eq(`id`,e);if(t)throw Error(t.message);(0,a.revalidatePath)(`/cms/settings/taxes`)}exports.deleteTaxRateAction=l,exports.saveTaxRateAction=c,exports.updateTaxSettingsAction=s;
|
|
@@ -5,7 +5,7 @@ import { getEcommerceInventorySettings as n, upsertEcommerceInventorySettings as
|
|
|
5
5
|
import { createClient as i } from "@nextblock-cms/db/server";
|
|
6
6
|
import { redirect as a } from "next/navigation";
|
|
7
7
|
import { revalidatePath as o } from "next/cache";
|
|
8
|
-
//#region
|
|
8
|
+
//#region src/lib/pages/cms/taxes/actions.ts
|
|
9
9
|
async function s() {
|
|
10
10
|
let e = i(), { data: { user: t } } = await e.auth.getUser();
|
|
11
11
|
if (!t) throw Error("Unauthorized");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../../../../countries.cjs"),t=require("../../../../states.cjs"),n=require("../actions.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("@nextblock-cms/ui");function o({initialData:o,submitLabel:s=`Save tax rate`,compact:c=!1}){let l=e.normalizeCountryCode(o?.country_code)||`US`,[u,d]=(0,r.useState)(l),[f,p]=(0,r.useState)(t.normalizeSubdivisionCode(l,o?.state_code)||o?.state_code||``),m=(0,r.useMemo)(()=>t.getStatesForCountry(u),[u]),h=t.countryUsesStructuredStates(u);return(0,i.jsxs)(`form`,{action:n.saveTaxRateAction,className:`space-y-4`,children:[o?.id?(0,i.jsx)(`input`,{type:`hidden`,name:`id`,value:o.id}):null,(0,i.jsxs)(`div`,{className:c?`grid gap-4 md:grid-cols-4`:`grid gap-4 md:grid-cols-2 xl:grid-cols-4`,children:[(0,i.jsxs)(`div`,{className:`space-y-2`,children:[(0,i.jsx)(a.Label,{htmlFor:o?.id?`country-${o.id}`:`tax-rate-country`,children:`Country`}),(0,i.jsx)(`select`,{id:o?.id?`country-${o.id}`:`tax-rate-country`,name:`country_code`,value:u,onChange:e=>{let n=e.target.value,r=t.getStatesForCountry(n);d(n),p(r.some(e=>e.code===f)?f:``)},className:`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm`,children:e.countries.map(e=>(0,i.jsx)(`option`,{value:e.code,children:e.name},e.code))})]}),(0,i.jsxs)(`div`,{className:`space-y-2`,children:[(0,i.jsx)(a.Label,{htmlFor:o?.id?`state-${o.id}`:`tax-rate-state`,children:`State / Province`}),h?(0,i.jsxs)(`select`,{id:o?.id?`state-${o.id}`:`tax-rate-state`,name:`state_code`,value:f,onChange:e=>p(e.target.value),className:`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm`,children:[(0,i.jsx)(`option`,{value:``,children:`Country-wide / federal`}),m.map(e=>(0,i.jsx)(`option`,{value:e.code,children:e.name},e.code))]}):(0,i.jsx)(a.Input,{id:o?.id?`state-${o.id}`:`tax-rate-state`,name:`state_code`,value:f,onChange:e=>p(e.target.value),placeholder:`Optional`})]}),(0,i.jsxs)(`div`,{className:`space-y-2`,children:[(0,i.jsx)(a.Label,{htmlFor:o?.id?`name-${o.id}`:`tax-rate-name`,children:`Tax name`}),(0,i.jsx)(a.Input,{id:o?.id?`name-${o.id}`:`tax-rate-name`,name:`tax_name`,defaultValue:o?.tax_name||``,placeholder:`GST, PST, State Sales Tax`,required:!0})]}),(0,i.jsxs)(`div`,{className:`space-y-2`,children:[(0,i.jsx)(a.Label,{htmlFor:o?.id?`rate-${o.id}`:`tax-rate-rate`,children:`Rate (%)`}),(0,i.jsx)(a.Input,{id:o?.id?`rate-${o.id}`:`tax-rate-rate`,name:`tax_rate`,type:`number`,min:`0`,max:`100`,step:`0.0001`,defaultValue:typeof o?.tax_rate==`number`?o.tax_rate.toString():``,placeholder:`5.0000`,required:!0})]})]}),(0,i.jsx)(`div`,{className:`flex justify-end`,children:(0,i.jsx)(a.Button,{type:`submit`,size:c?`sm`:`default`,children:s})})]})}exports.TaxRateForm=o;
|
|
@@ -5,7 +5,7 @@ import { saveTaxRateAction as a } from "../actions.es.js";
|
|
|
5
5
|
import { useMemo as o, useState as s } from "react";
|
|
6
6
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
7
|
import { Button as u, Input as d, Label as f } from "@nextblock-cms/ui";
|
|
8
|
-
//#region
|
|
8
|
+
//#region src/lib/pages/cms/taxes/components/TaxRateForm.tsx
|
|
9
9
|
function p({ initialData: p, submitLabel: m = "Save tax rate", compact: h = !1 }) {
|
|
10
10
|
let g = t(p?.country_code) || "US", [_, v] = s(g), [y, b] = s(i(g, p?.state_code) || p?.state_code || ""), x = o(() => r(_), [_]), S = n(_);
|
|
11
11
|
return /* @__PURE__ */ l("form", {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./actions.cjs"),t=require("./TaxesPage.cjs");exports.TaxesPage=t.TaxesPage,exports.deleteTaxRateAction=e.deleteTaxRateAction,exports.saveTaxRateAction=e.saveTaxRateAction,exports.updateTaxSettingsAction=e.updateTaxSettingsAction;
|
package/lib/payment-config.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createClient as e, encryptWithEnvKey as t, getSecretEnvelopeStatus as n, getServiceRoleSupabaseClient as r, isSandboxEnvironment as i, resolveConfigValue as a, tryDecryptWithEnvKey as o } from "@nextblock-cms/db/server";
|
|
2
|
-
//#region
|
|
2
|
+
//#region src/lib/payment-config.ts
|
|
3
3
|
var s = "payment_secret", c = "payment_public", l = 6e4, u = null;
|
|
4
4
|
function d(e) {
|
|
5
5
|
return e && typeof e == "object" && !Array.isArray(e) ? e : {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require("./shared-inventory.cjs
|
|
1
|
+
const e=require("./shared-inventory.cjs");let t=require("@nextblock-cms/utils"),n=require("@nextblock-cms/utils/server"),r=require("@nextblock-cms/utils/utils");var i=e=>Math.round(e*100);function a(e){return Object.entries(e||{}).reduce((e,[t,n])=>(typeof n==`number`&&Number.isFinite(n)&&n>=0&&(e[(0,r.normalizeCurrencyCode)(t)]=i(n)),e),{})}function o(e){return(e||[]).map(e=>({id:e.id,sku:e.sku,upc:e.upc??null,price:i(e.price),sale_price:typeof e.sale_price==`number`&&!isNaN(e.sale_price)?i(e.sale_price):null,prices:a(e.prices),sale_prices:a(e.sale_prices),sale_start_at:e.sale_start_at??null,sale_end_at:e.sale_end_at??null,stock_quantity:e.stock_quantity,main_media_id:e.main_media_id??null,attribute_term_ids:e.attribute_term_ids}))}function s(e,t){let n=e.product_type===`digital`&&e.payment_provider===`freemius`?Math.max(0,Number(e.trial_period_days??0)):0;return{id:t,product_type:e.product_type,payment_provider:e.payment_provider,title:e.title,slug:e.slug,sku:e.sku,upc:e.upc??null,stock:e.stock,status:e.status,short_description:e.short_description??null,description_json:e.description_json??null,metadata:{},price:i(e.price),sale_price:typeof e.sale_price==`number`&&!isNaN(e.sale_price)?i(e.sale_price):null,prices:a(e.prices),sale_prices:a(e.sale_prices),sale_start_at:e.sale_start_at??null,sale_end_at:e.sale_end_at??null,freemius_plan_id:e.freemius_plan_id??null,freemius_product_id:e.freemius_product_id??null,trial_period_days:n,trial_requires_payment_method:n>0?e.trial_requires_payment_method??!1:!1,is_taxable:e.is_taxable,language_id:e.language_id,translation_group_id:e.translation_group_id||void 0,variants:o(e.variants)}}async function c(e,t,n){let r=e=>(typeof e==`string`?e.trim():``)||null,{error:i}=await e.from(`products`).update({meta_title:r(n.meta_title),meta_description:r(n.meta_description),custom_canonical:r(n.custom_canonical),updated_at:new Date().toISOString()}).eq(`id`,t);if(i)throw i}async function l(e,t,n){let{error:r}=await e.from(`products`).update({is_taxable:n,updated_at:new Date().toISOString()}).eq(`id`,t);if(r)throw r}async function u(e,t,n){let r=new Date().toISOString(),{data:i}=await e.from(`products`).select(`sku, sale_price, sale_prices`).eq(`id`,t).maybeSingle(),a=i?.sku??n.sku,{data:o}=await e.from(`products`).select(`id`).eq(`sku`,a),s=(o??[]).map(e=>e.id);s.length===0&&s.push(t);let{error:c}=await e.from(`products`).update({sale_price:i?.sale_price??null,sale_prices:i?.sale_prices??null,sale_start_at:n.sale_start_at??null,sale_end_at:n.sale_end_at??null,updated_at:r}).in(`id`,s);if(c)throw c;let l=n.variants??[];if(l.length===0)return;let{data:u}=await e.from(`product_variants`).select(`sku, sale_price, sale_prices`).eq(`product_id`,t),d=new Map((u??[]).map(e=>[e.sku,e]));for(let t of l){let n=d.get(t.sku);if(!n)continue;let{error:i}=await e.from(`product_variants`).update({sale_price:n.sale_price??null,sale_prices:n.sale_prices??null,sale_start_at:t.sale_start_at??null,sale_end_at:t.sale_end_at??null,updated_at:r}).eq(`sku`,t.sku).in(`product_id`,s);if(i)throw i}}async function d(e,{page:t=1,limit:n=10,offset:r,search:i=``,languageId:a,categoryId:o,categoryIds:s,productIds:c,translationGroupIds:l,status:u=`active`}={}){let d=n>0,f=typeof r==`number`?Math.max(0,r):(t-1)*n,p=f+n-1,m=e.from(`products`).select(`id, title, meta_title, meta_description, average_rating, total_reviews, sku, upc, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, is_taxable, product_type, payment_provider, short_description, stock, status, slug, language_id, translation_group_id, freemius_product_id, freemius_plan_id, trial_period_days, trial_requires_payment_method, product_media(media(file_path, object_key)), product_variants(id, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at), freemius_plans(id, name, title, freemius_pricing(id, license_quota, api_monthly_price, api_annual_price, api_lifetime_price, override_monthly_price, override_annual_price, override_lifetime_price, is_active)), product_categories(category:categories(id, name, slug, description, name_translations, description_translations))`,{count:`exact`}).order(`created_at`,{ascending:!1});if(d&&(m=m.range(f,p)),u!==`all`&&(m=m.eq(`status`,u)),a&&(m=m.eq(`language_id`,a)),c){if(c.length===0)return{data:[],error:null,count:0};m=m.in(`id`,c)}if(l){if(l.length===0)return{data:[],error:null,count:0};m=m.in(`translation_group_id`,l)}let h=s?.length?s:o?[o]:[];if(h.length>0){let{data:t,error:n}=await e.from(`product_categories`).select(`product_id`).in(`category_id`,h);if(n)return{data:[],error:n,count:0};let r=Array.from(new Set((t||[]).map(e=>e.product_id).filter(Boolean)));if(r.length===0)return{data:[],error:null,count:0};m=m.in(`id`,r)}return i&&(m=m.or(`title.ilike.%${i}%,sku.ilike.%${i}%`)),m}async function f(e,t){return e.from(`products`).select(`
|
|
2
2
|
*,
|
|
3
3
|
languages (
|
|
4
4
|
code
|
|
@@ -2,7 +2,7 @@ import { syncSharedInventoryForSavedProduct as e } from "./shared-inventory.es.j
|
|
|
2
2
|
import { buildPublishedAtOrFilter as t } from "@nextblock-cms/utils";
|
|
3
3
|
import { deleteMediaFiles as n } from "@nextblock-cms/utils/server";
|
|
4
4
|
import { normalizeCurrencyCode as r } from "@nextblock-cms/utils/utils";
|
|
5
|
-
//#region
|
|
5
|
+
//#region src/lib/product-actions.ts
|
|
6
6
|
var i = (e) => Math.round(e * 100);
|
|
7
7
|
function a(e) {
|
|
8
8
|
return Object.entries(e || {}).reduce((e, [t, n]) => (typeof n == "number" && Number.isFinite(n) && n >= 0 && (e[r(t)] = i(n)), e), {});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("react");t=e.__toESM(t,1);let n=require("react/jsx-runtime");var r=(0,t.createContext)(void 0),i=({product:e,children:t})=>(0,n.jsx)(r.Provider,{value:{product:e},children:t}),a=()=>{let e=(0,t.useContext)(r);if(!e)throw Error(`useProduct must be used within a ProductProvider. Ensure the component is wrapped in a ProductProvider.`);return e.product};exports.ProductProvider=i,exports.useProduct=a;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createContext as e, useContext as t } from "react";
|
|
3
3
|
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
-
//#region
|
|
4
|
+
//#region src/lib/product-context.tsx
|
|
5
5
|
var r = e(void 0), i = ({ product: e, children: t }) => /* @__PURE__ */ n(r.Provider, {
|
|
6
6
|
value: { product: e },
|
|
7
7
|
children: t
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require("./zod-config.cjs");let e=require("zod");var t=e.z.enum([`physical`,`digital`]).or(e.z.literal(``)).refine(e=>e!==``,{message:`Product type is required`}).transform(e=>e),n=e.z.record(e.z.string().regex(/^[A-Z]{3}$/,`Currency code must be ISO 4217`),e.z.coerce.number().min(0,`Prices must be non-negative`)),r=e.z.record(e.z.string().regex(/^[A-Z]{3}$/,`Currency code must be ISO 4217`),e.z.coerce.number().min(0,`Sale prices must be non-negative`).nullable()),i=e.z.string().trim().refine(e=>e===``||!Number.isNaN(Date.parse(e)),{message:`Must be a valid date and time`}).transform(e=>e===``?null:e).nullable().optional();function a(e,t){if(!e||!t)return!0;let n=Date.parse(e),r=Date.parse(t);return Number.isNaN(n)||Number.isNaN(r)?!0:n<r}var o=e.z.object({attribute_id:e.z.string().uuid(),attribute_name:e.z.string(),term_id:e.z.string().uuid(),term_value:e.z.string(),term_slug:e.z.string().optional()}),s=e.z.object({id:e.z.string().uuid().optional(),combination_key:e.z.string().min(1),sku:e.z.string().min(1,`Variant SKU is required`),upc:e.z.string().optional().nullable(),price:e.z.coerce.number().min(0,`Variant price must be non-negative`),prices:n.default({}),sale_price:e.z.coerce.number().min(0,`Variant sale price must be non-negative`).optional().nullable(),sale_prices:r.default({}),sale_start_at:i,sale_end_at:i,stock_quantity:e.z.coerce.number().int().min(0,`Variant stock must be a non-negative integer`),main_media_id:e.z.string().uuid().optional().nullable(),main_image_url:e.z.string().optional().nullable(),attribute_term_ids:e.z.array(e.z.string().uuid()).min(1),selected_options:e.z.array(o).min(1),label:e.z.string().min(1)}).refine(e=>e.sale_price===null||e.sale_price===void 0||e.sale_price<=e.price,{message:`Variant sale price cannot exceed the regular price`,path:[`sale_price`]}).refine(e=>Object.entries(e.sale_prices||{}).every(([t,n])=>{if(n==null)return!0;let r=e.prices?.[t];return typeof r!=`number`||n<=r}),{message:`Variant sale prices cannot exceed regular prices`,path:[`sale_prices`]}).refine(e=>a(e.sale_start_at,e.sale_end_at),{message:`Sale end must be after the sale start`,path:[`sale_end_at`]}),c=e.z.object({attribute_id:e.z.string().uuid(),term_ids:e.z.array(e.z.string().uuid())}),l=e.z.object({product_type:t,payment_provider:e.z.enum([`stripe`,`freemius`]),title:e.z.string().min(1,`Title is required`),slug:e.z.string().min(1,`Slug is required`).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/,`Slug must be lowercase alphanumeric with hyphens`),sku:e.z.string().min(1,`SKU is required`),upc:e.z.string().optional().nullable(),price:e.z.coerce.number().min(0,`Price must be non-negative`),prices:n.default({}),sale_price:e.z.coerce.number().min(0,`Sale price must be non-negative`).optional().nullable(),sale_prices:r.default({}),sale_start_at:i,sale_end_at:i,stock:e.z.coerce.number().int().min(0,`Stock must be a non-negative integer`),meta_title:e.z.string().optional().nullable(),meta_description:e.z.string().optional().nullable(),custom_canonical:e.z.string().optional().nullable(),short_description:e.z.string().optional(),description_json:e.z.any().optional(),freemius_plan_id:e.z.string().optional(),freemius_product_id:e.z.string().optional(),trial_period_days:e.z.coerce.number().int().min(0,`Trial period must be zero or greater`).default(0),trial_requires_payment_method:e.z.boolean().default(!1),media_id:e.z.string().optional(),product_media:e.z.array(e.z.object({media_id:e.z.string()})).optional(),category_ids:e.z.array(e.z.string().uuid()).optional(),is_taxable:e.z.boolean(),status:e.z.enum([`draft`,`active`,`archived`]),language_id:e.z.coerce.number().int().min(1,`Language is required`),translation_group_id:e.z.string().uuid().optional().or(e.z.literal(``)).transform(e=>e===``?void 0:e),explicitly_removed_media_ids:e.z.array(e.z.string()).optional(),variation_attributes:e.z.array(c).optional(),variants:e.z.array(s).optional()}).refine(e=>e.sale_price===null||e.sale_price===void 0||e.sale_price<=e.price,{message:`Sale price cannot exceed the regular price`,path:[`sale_price`]}).refine(e=>Object.entries(e.sale_prices||{}).every(([t,n])=>{if(n==null)return!0;let r=e.prices?.[t];return typeof r!=`number`||n<=r}),{message:`Sale prices cannot exceed regular prices`,path:[`sale_prices`]}).refine(e=>a(e.sale_start_at,e.sale_end_at),{message:`Sale end must be after the sale start`,path:[`sale_end_at`]});exports.productSchema=l;
|
package/lib/product-schema.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z as e } from "./zod-config.es.js";
|
|
2
|
-
//#region
|
|
2
|
+
//#region src/lib/product-schema.ts
|
|
3
3
|
var t = e.enum(["physical", "digital"]).or(e.literal("")).refine((e) => e !== "", { message: "Product type is required" }).transform((e) => e), n = e.record(e.string().regex(/^[A-Z]{3}$/, "Currency code must be ISO 4217"), e.coerce.number().min(0, "Prices must be non-negative")), r = e.record(e.string().regex(/^[A-Z]{3}$/, "Currency code must be ISO 4217"), e.coerce.number().min(0, "Sale prices must be non-negative").nullable()), i = e.string().trim().refine((e) => e === "" || !Number.isNaN(Date.parse(e)), { message: "Must be a valid date and time" }).transform((e) => e === "" ? null : e).nullable().optional();
|
|
4
4
|
function a(e, t) {
|
|
5
5
|
if (!e || !t) return !0;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../currency.cjs"),n=require("../coupon-server.cjs"),r=require("../customer.cjs"),i=require("../customer-addresses.cjs"),a=require("../payment-config.cjs");let o=require("@supabase/supabase-js"),s=require("crypto");s=e.__toESM(s,1);let c=require("@freemius/sdk");function l(e){let t=process.env[e];if(!t)return null;let n=t.trim();return n.startsWith(`"`)&&n.endsWith(`"`)||n.startsWith(`'`)&&n.endsWith(`'`)?n.slice(1,-1).trim():n}function u(e){let t=e?.trim();if(!t)return{firstName:null,lastName:null};let[n,...r]=t.split(/\s+/);return{firstName:n||null,lastName:r.length>0?r.join(` `):null}}function d(e){if(e==null||e===``)return 0;let t=Number(e);return!Number.isFinite(t)||t<=0?0:Math.round(t)}function f(e){return e===!0||e===1||e===`1`||e===`true`}function p(e,t){let n=e?.[t];return Array.isArray(n)?n:n&&typeof n==`object`?[n]:[]}function m(e,t){for(let n of t){let t=p(e,n);if(t.length>0)return t}return Array.isArray(e)?e:[]}function h(e){if(e==null||e===``)return null;let t=Number(e);return Number.isFinite(t)?t:null}function g(e){return e===null?0:e>5e3?(console.warn(`[Freemius Sync] Suspiciously high price detected: ${e}. Assuming it is already in cents.`),Math.round(e)):Math.round(e*100)}function _(e){let t=Number(e);return!Number.isFinite(t)||t<1?1:Math.round(t)}function v(){let e=l(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`);if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t==`object`?t:null}catch(e){return console.error(`[Freemius Checkout] Failed to parse FREEMIUS_CHECKOUT_PRODUCTS_JSON:`,e),null}}function y(e){let t=v(),n=String(e),r=t?.[n],i=l(`FREEMIUS_PRODUCT_ID`),a=l(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),o=l(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);return r?.publicKey?{publicKey:r.publicKey,secretKey:r.secretKey??null,apiKey:r.apiKey??null,source:`product-map`}:process.env.FREEMIUS_SANDBOX_ENABLED===`true`&&i&&i===n&&a?{publicKey:a,secretKey:o,apiKey:l(`FREEMIUS_API_KEY`),source:`single-product-sandbox-env`}:i&&i===n&&l(`FREEMIUS_PUBLIC_KEY`)?{publicKey:l(`FREEMIUS_PUBLIC_KEY`),secretKey:l(`FREEMIUS_SECRET_KEY`),apiKey:l(`FREEMIUS_API_KEY`),source:`single-product-env`}:{publicKey:l(`FREEMIUS_PUBLIC_KEY`),secretKey:l(`FREEMIUS_SECRET_KEY`),apiKey:l(`FREEMIUS_API_KEY`),source:`legacy-env`}}async function b(e){if(!e.apiKey)throw Error(`Missing Freemius API key for SDK sandbox generation.`);return new c.Freemius({productId:Number(e.productId),apiKey:e.apiKey,secretKey:e.secretKey,publicKey:e.publicKey}).checkout.getSandboxParams()}var x=class{getProviderName(){return`Freemius`}async createCheckoutSession({items:e,customerEmail:c,customerPhone:f,userId:p,billingAddress:m,shippingAddress:h,currencyCode:g,couponCode:_,couponContextItems:v}){let x=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,S=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!x||!S)return{error:`Missing Supabase credentials for checkout (Service Key required).`,url:null};let C=(0,o.createClient)(x,S);if(!e||e.length===0)return{error:`Cart is empty`,url:null};if(e.length!==1)return{error:`Freemius items must be checked out one at a time.`,url:null};let{data:w,error:T}=await C.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),E=w??[];if(T||E.length===0)return{error:`Failed to resolve store currencies`,url:null};let D=t.getDefaultCurrency(E),O=E.find(e=>e.code===(g||``).toUpperCase())??D,k=e[0],{data:A,error:j}=await C.from(`products`).select(`id, title, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, freemius_plan_id, freemius_product_id, trial_period_days, trial_requires_payment_method`).eq(`id`,k.product_id).single();if(j||!A)return{error:`Product not found`,url:null};let M=A.freemius_plan_id,N=A.freemius_product_id;if(!M||!N)return{error:`Product is not configured for Freemius checkout (missing Plan ID or Product ID)`,url:null};let P=t.resolveEffectivePriceForCurrency({prices:A.prices||{},salePrices:A.sale_prices||{},fallbackPrice:A.price,fallbackSalePrice:A.sale_price,saleStartAt:A.sale_start_at,saleEndAt:A.sale_end_at,scheduledPrice:A.scheduled_price,scheduledPrices:A.scheduled_prices||{},scheduledPriceAt:A.scheduled_price_at,currencyCode:O.code,currencies:E}),F=P.sale_price??P.price,I=t.isSaleWindowActive({saleStartAt:A.sale_start_at,saleEndAt:A.sale_end_at}),L=F*k.quantity,R=null,z=0;if(_){let t=await n.getCouponQuote({client:C,code:_,items:v&&v.length>0?v:e,currencyCode:O.code});if(!t.success)return{error:t.error,errorKey:t.errorKey,errorStatus:400,url:null};R=t.quote,z=Math.min(L,R.lineDiscounts.filter(e=>e.product_id===A.id).reduce((e,t)=>e+t.discount,0))}let B=d(A.trial_period_days),V=B>0?k.trial_preference?k.trial_preference:A.trial_requires_payment_method?`paid`:`free`:null,H=`pending`,U=u(m?.recipient_name??null),{data:W,error:G}=await C.from(`orders`).insert({status:H,total:Math.max(0,L-z),currency:O.code,exchange_rate_at_purchase:O.exchange_rate,subtotal:L,discount_total:z,coupon_id:R?.couponId??null,coupon_code:R?.code??null,discount_details:R?{code:R.code,discount_type:R.discountType,discount_amount:R.discountAmount,provider:`freemius`,provider_discounts:R.providerDiscounts,line_discounts:R.lineDiscounts,final_amount_owned_by:`freemius`}:null,provider:`freemius`,freemius_product_id:String(N),freemius_plan_id:String(M),user_id:p||null,customer_details:r.normalizeOrderCustomerDetails({email:c,phone:f,name:m?.recipient_name,billing:m,shipping:h})}).select(`id`).single();if(G||!W)return console.error(`Failed to create pending order:`,G),{error:`Failed to initiate order`,url:null};let{error:K}=await C.from(`order_items`).insert([{order_id:W.id,product_id:A.id,quantity:k.quantity,price_at_purchase:F}]);if(K&&console.error(`Failed to insert order items:`,K),p)try{await i.upsertDefaultUserAddresses({userId:p,billingAddress:m,shippingAddress:h,client:C}),await i.fillMissingUserProfileCheckoutDetails({userId:p,fullName:m?.recipient_name??h?.recipient_name??null,phone:f,client:C})}catch(e){console.error(`Failed to sync checkout profile defaults before checkout:`,e)}R&&await n.recordCouponRedemption({client:C,quote:R,orderId:W.id,provider:`freemius`,discountTotal:z,userId:p,customerEmail:c,metadata:{currency:O.code,subtotal:L,final_amount_owned_by:`freemius`}}),await a.hydrateFreemiusEnvFromDb();let q=process.env.FREEMIUS_SANDBOX_ENABLED===`true`,J=y(N),Y=J.publicKey,X=J.secretKey,Z=J.apiKey;if(!Y||q&&!X)return console.error(`Freemius checkout blocked: missing credentials (PUBLIC_KEY or SECRET_KEY) in CMS → Payments or environment.`),{error:`This store is not able to take payments right now. Please contact the seller to complete your purchase.`,errorKey:`ecommerce.checkout_payments_unavailable`,errorStatus:503,url:null};if(q&&J.source===`legacy-env`){let e=l(`FREEMIUS_PRODUCT_ID`),t=!!l(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),n=!!l(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);console.warn(`[Freemius Checkout] Sandbox is enabled for product ${N}, but no product-scoped checkout credentials were selected. Falling back to legacy FREEMIUS_PUBLIC_KEY/FREEMIUS_SECRET_KEY may open live checkout instead of sandbox.`,{configuredProductId:e,productIdsMatch:e===String(N),hasSandboxOverridePublicKey:t,hasSandboxOverrideSecretKey:n,hasCheckoutProductsJson:!!l(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`)})}let Q=!1;if(q&&X&&Y)try{Q=await b({productId:N,publicKey:Y,secretKey:X,apiKey:Z})}catch(e){console.warn(`Freemius Checkout - SDK sandbox generation failed. Falling back to manual token generation.`,e,{credentialSource:J.source,hasApiKey:!!Z});let t=Math.floor(Date.now()/1e3).toString(),n=`${t}${N}${X}${Y}checkout`;Q={ctx:t,token:s.default.createHash(`md5`).update(n).digest(`hex`)}}let $=new URL(`https://checkout.freemius.com/app/${N}/plan/${M}/`);if(q&&X&&Y?($.searchParams.append(`sandbox`,Q.token),$.searchParams.append(`s_ctx_ts`,Q.ctx)):q&&$.searchParams.append(`sandbox`,`true`),c&&$.searchParams.append(`user_email`,c),U.firstName&&$.searchParams.append(`user_firstname`,U.firstName),U.lastName&&$.searchParams.append(`user_lastname`,U.lastName),$.searchParams.append(`currency`,O.code.toLowerCase()),k.billing_cycle&&$.searchParams.append(`billing_cycle`,k.billing_cycle),V&&$.searchParams.append(`trial`,V),R)$.searchParams.append(`coupon`,R.code);else if(I){let{data:e}=await C.from(`product_freemius_sale_coupons`).select(`freemius_coupon_code, is_active, starts_at, ends_at, sync_status`).eq(`product_id`,A.id).maybeSingle();e?.is_active&&e.sync_status===`synced`&&e.freemius_coupon_code&&t.isSaleWindowActive({saleStartAt:e.starts_at,saleEndAt:e.ends_at})&&$.searchParams.append(`coupon`,e.freemius_coupon_code)}return{url:$.toString(),customProps:{provider:`freemius`,plugin_id:N,plan_id:M,public_key:Y,user_email:c,user_firstname:U.firstName,user_lastname:U.lastName,credential_source:J.source,sandbox:Q,billing_cycle:k.billing_cycle,trial:V,trial_period_days:B,trial_requires_payment_method:A.trial_requires_payment_method,initial_order_status:H,coupon:R?.code??null,order_id:W.id}}}};async function S(e,t,n,r){let i=new Date().toUTCString().replace(`GMT`,`+0000`),a=`GET\n\n\n${i}\n${e}`,o=s.default.createHmac(`sha256`,r).update(a).digest(`hex`),c=`FS ${t}:${n}:${Buffer.from(o).toString(`base64`).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}`,l=await fetch(`https://api.freemius.com${e}`,{headers:{Authorization:c,Date:i,Accept:`application/json`}});if(!l.ok){let t=await l.text();throw console.error(`[Freemius API] [ERROR] ${e} returned ${l.status}: ${t}`),Error(`Freemius API failed on ${e}: ${l.status} - ${t}`)}return l.json()}async function C(){let e=l(`FREEMIUS_DEVELOPER_ID`),t=l(`FREEMIUS_PUBLIC_KEY`),n=l(`FREEMIUS_SECRET_KEY`),r=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,i=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!t||!n||!r||!i)throw Error(`Missing necessary environment variables for Freemius Sync.`);let a=(0,o.createClient)(r,i,{auth:{autoRefreshToken:!1,persistSession:!1}}),s=r=>S(r,e,t,n);try{console.log(`[Freemius Sync] Fetching all plugins for developer ${e}...`);let t=m(await s(`/v1/developers/${e}/plugins.json`),[`plugins`,`plugin`]);console.log(`[Freemius Sync] Found ${t.length} plugins. Syncing plans...`);let n=0,{data:r}=await a.from(`languages`).select(`id`).eq(`code`,`en`).single(),i=r?.id;if(!i)throw Error(`English language not found in database. Cannot sync products.`);for(let r of t){let t=r.id?.toString();if(!t){console.warn(`[Freemius Sync] Skipping plugin without an id:`,r);continue}let o=await T(a,e,t,r.title||r.name||`Freemius Product ${t}`,s,i);n+=o}return{success:!0,count:n}}catch(e){throw console.error(`[Freemius Sync] Global Error:`,e),e}}async function w(e){let t=l(`FREEMIUS_DEVELOPER_ID`),n=l(`FREEMIUS_PUBLIC_KEY`),r=l(`FREEMIUS_SECRET_KEY`),i=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,a=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!t||!n||!r||!i||!a)throw Error(`Missing environment variables for Freemius Sync.`);let s=(0,o.createClient)(i,a),c=e=>S(e,t,n,r),{data:u}=await s.from(`languages`).select(`id`).eq(`code`,`en`).single(),d=u?.id;if(!d)throw Error(`English language not found in database. Cannot sync products.`);let f=await c(`/v1/developers/${t}/plugins/${e}.json`),p=f.plugin??f;return{success:!0,count:await T(s,t,e,p.title||p.name||`Freemius Product ${e}`,c,d)}}async function T(e,t,n,r,i,a){console.log(`[Freemius Sync] Fetching plans for plugin: ${r} (${n})...`);let o=0;try{let s=m(await i(`/v1/developers/${t}/plugins/${n}/plans.json`),[`plans`,`plan`]);console.log(`[Freemius Sync] Received ${s.length} plans for plugin ${n}.`);for(let c of s){let s=c.id?.toString();if(!s){console.warn(`[Freemius Sync] Skipping plan without an id:`,c);continue}let l=c.name||c.title||s,u=c.title||l;console.log(`[Freemius Sync] Processing plan: ${u} (${s})...`);let p=c;if(p.trial_period===void 0||p.is_require_subscription===void 0)try{let e=await i(`/v1/developers/${t}/plugins/${n}/plans/${s}.json`),r=e.plan??e;p={...p,...r}}catch(e){console.warn(`[Freemius Sync] Could not fetch trial details for plan ${s}:`,e instanceof Error?e.message:e)}let v=d(p.trial_period),y=v>0&&f(p.is_require_subscription),b=0,x=[];try{if(x=m(await i(`/v1/developers/${t}/plugins/${n}/plans/${s}/pricing.json`),[`pricing`,`prices`,`pricings`]),x.length>0){let e=x[0];b=g(h(e.annual_price)??h(e.monthly_price)??h(e.lifetime_price))}console.log(`[Freemius Sync] Plan: ${u} -> Resolved Price (cents): ${b}`)}catch(e){console.warn(`[Freemius Sync] Could not fetch pricing for plan ${s}:`,e instanceof Error?e.message:e)}let S=`${r}-${u}`.toLowerCase().replace(/[^\w\s-]/g,``).replace(/[\s_]+/g,`-`).replace(/^-+|-+$/g,``),C={title:`${r} - ${u}`,slug:S,short_description:c.description||``,price:b,product_type:`digital`,payment_provider:`freemius`,freemius_plan_id:s,freemius_product_id:n,trial_period_days:v,trial_requires_payment_method:y,status:`active`,stock:999,sku:`FM-${n}-${s}`,language_id:a},{data:w,error:T}=await e.from(`products`).upsert(C,{onConflict:`language_id, sku`}).select();if(T||!w||w.length===0){console.error(`[Freemius Sync] Error upserting product ${C.sku}:`,T);continue}let E=w[0].id,{data:D,error:O}=await e.from(`freemius_plans`).select(`id`).eq(`product_id`,E).eq(`name`,l).maybeSingle();O&&console.warn(`[Freemius Sync] Could not check existing local plan for ${C.sku}:`,O.message||O);let k=``;if(D){k=D.id;let{error:t}=await e.from(`freemius_plans`).update({title:u,updated_at:new Date().toISOString()}).eq(`id`,k);t&&console.warn(`[Freemius Sync] Could not update local plan ${k}:`,t.message||t)}else{let{data:t,error:n}=await e.from(`freemius_plans`).insert({product_id:E,name:l,title:u}).select(`id`).single();n&&console.warn(`[Freemius Sync] Could not insert local plan for ${C.sku}:`,n.message||n),t&&(k=t.id)}if(k&&x.length>0)for(let t of x){let n=_(t.licenses??t.license_quota??t.quota),{data:r,error:i}=await e.from(`freemius_pricing`).select(`id`).eq(`plan_id`,k).eq(`license_quota`,n).maybeSingle();i&&console.warn(`[Freemius Sync] Could not check pricing for plan ${k}, quota ${n}:`,i.message||i);let a={api_monthly_price:h(t.monthly_price),api_annual_price:h(t.annual_price),api_lifetime_price:h(t.lifetime_price),updated_at:new Date().toISOString()};if(r){let{error:t}=await e.from(`freemius_pricing`).update(a).eq(`id`,r.id);t&&console.warn(`[Freemius Sync] Could not update pricing ${r.id}:`,t.message||t)}else{let{error:t}=await e.from(`freemius_pricing`).insert({plan_id:k,license_quota:n,...a});t&&console.warn(`[Freemius Sync] Could not insert pricing for plan ${k}, quota ${n}:`,t.message||t)}}console.log(`[Freemius Sync] Successfully fully synced product ${C.sku}.`),o++}}catch(e){console.error(`[Freemius Sync] Failed sync for plugin ${n}:`,e.message)}return o}exports.FreemiusProvider=x,exports.parseFreemiusCheckoutCredentialsMap=v,exports.readFreemiusEnvValue=l,exports.resolveFreemiusCheckoutCredentials=y,exports.syncFreemiusProductsToSupabase=C,exports.syncSingleFreemiusProduct=w;
|
|
@@ -6,7 +6,7 @@ import { hydrateFreemiusEnvFromDb as c } from "../payment-config.es.js";
|
|
|
6
6
|
import { createClient as l } from "@supabase/supabase-js";
|
|
7
7
|
import u from "crypto";
|
|
8
8
|
import { Freemius as d } from "@freemius/sdk";
|
|
9
|
-
//#region
|
|
9
|
+
//#region src/lib/providers/freemius.ts
|
|
10
10
|
function f(e) {
|
|
11
11
|
let t = process.env[e];
|
|
12
12
|
if (!t) return null;
|