@nextblock-cms/ecom 0.8.6 → 0.8.7
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/index.cjs.js +1 -1
- package/index.es.js +136 -533
- package/lib/CurrencyProvider.cjs.js +1 -0
- package/lib/CurrencyProvider.es.js +99 -0
- package/lib/cart-store.cjs.js +1 -0
- package/{cart-store.es.js → lib/cart-store.es.js} +13 -13
- package/lib/components/AccountNavigationMenu.cjs.js +1 -0
- package/lib/components/AccountNavigationMenu.es.js +44 -0
- package/lib/components/AddToCartButton.cjs.js +1 -0
- package/{AddToCartButton-ffE0DhHu.js → lib/components/AddToCartButton.es.js} +14 -13
- package/lib/components/Cart.cjs.js +1 -0
- package/lib/components/Cart.es.js +148 -0
- package/lib/components/CartDrawer.cjs.js +1 -0
- package/{components → lib/components}/CartDrawer.es.js +15 -14
- package/{components → lib/components}/CartIcon.cjs.js +1 -1
- package/{components → lib/components}/CartIcon.es.js +1 -0
- package/lib/components/Checkout.cjs.js +1 -0
- package/{components → lib/components}/Checkout.es.js +330 -363
- package/lib/components/CouponForm.cjs.js +1 -0
- package/lib/components/CouponForm.es.js +136 -0
- package/lib/components/CurrencySwitcher.cjs.js +1 -0
- package/{components → lib/components}/CurrencySwitcher.es.js +5 -4
- package/lib/components/CustomerProfileForm.cjs.js +1 -0
- package/lib/components/CustomerProfileForm.es.js +355 -0
- package/lib/components/FeaturedProduct.cjs.js +1 -0
- package/{components → lib/components}/FeaturedProduct.es.js +9 -8
- package/lib/components/InvoiceDocument.cjs.js +1 -0
- package/lib/components/InvoiceDocument.es.js +196 -0
- package/lib/components/InvoiceViewerShell.cjs.js +29 -0
- package/lib/components/InvoiceViewerShell.es.js +100 -0
- package/lib/components/ProductCard.cjs.js +1 -0
- package/lib/components/ProductCard.es.js +119 -0
- package/lib/components/ProductDetailsLayout.cjs.js +1 -0
- package/lib/components/ProductDetailsLayout.es.js +361 -0
- package/lib/components/ProductGallery.cjs.js +1 -0
- package/lib/components/ProductGallery.es.js +41 -0
- package/lib/components/ProductGrid.cjs.js +1 -0
- package/lib/components/ProductGrid.es.js +19 -0
- package/lib/components/ShippingEstimator.cjs.js +1 -0
- package/lib/components/ShippingEstimator.es.js +125 -0
- package/lib/components/SubscriptionSelector.cjs.js +1 -0
- package/lib/components/SubscriptionSelector.es.js +140 -0
- package/lib/countries.cjs.js +1 -0
- package/lib/countries.es.js +77 -0
- package/lib/coupon-server.cjs.js +1 -0
- package/{coupon-server-DUKVtyYs.js → lib/coupon-server.es.js} +68 -82
- package/lib/coupons.cjs.js +1 -0
- package/lib/coupons.es.js +17 -0
- package/lib/currency-store.cjs.js +1 -0
- package/lib/currency-store.es.js +27 -0
- package/lib/currency-sync.cjs.js +1 -0
- package/lib/currency-sync.es.js +180 -0
- package/lib/customer-addresses.cjs.js +1 -0
- package/lib/customer-addresses.es.js +116 -0
- package/lib/customer-orders.cjs.js +1 -0
- package/lib/customer-orders.es.js +45 -0
- package/lib/customer.cjs.js +1 -0
- package/{customer-C3xccjUg.js → lib/customer.es.js} +15 -14
- package/lib/export-helpers.cjs.js +1 -0
- package/lib/export-helpers.es.js +56 -0
- package/lib/factory.cjs.js +1 -0
- package/lib/factory.es.js +8 -0
- package/lib/freemius-coupons.cjs.js +1 -0
- package/lib/freemius-coupons.es.js +272 -0
- package/lib/freemius-order-sync.cjs.js +1 -0
- package/lib/freemius-order-sync.es.js +284 -0
- package/lib/inventory-settings.cjs.js +1 -0
- package/lib/inventory-settings.es.js +86 -0
- package/lib/invoice-server.cjs.js +33 -0
- package/lib/invoice-server.es.js +141 -0
- package/lib/invoice-ui.cjs.js +1 -0
- package/lib/invoice-ui.es.js +71 -0
- package/lib/invoice.cjs.js +1 -0
- package/lib/invoice.es.js +102 -0
- package/lib/order-inventory.cjs.js +61 -0
- package/lib/order-inventory.es.js +128 -0
- package/lib/order-tax-details.cjs.js +1 -0
- package/lib/order-tax-details.es.js +164 -0
- package/lib/pages/cms/coupons/CouponEditorForm.cjs.js +1 -0
- package/lib/pages/cms/coupons/CouponEditorForm.es.js +189 -0
- package/lib/pages/cms/coupons/CouponsPage.cjs.js +5 -0
- package/lib/pages/cms/coupons/CouponsPage.es.js +171 -0
- package/lib/pages/cms/coupons/CreateCouponDialog.cjs.js +1 -0
- package/lib/pages/cms/coupons/CreateCouponDialog.es.js +35 -0
- package/lib/pages/cms/coupons/EditCouponPage.cjs.js +1 -0
- package/lib/pages/cms/coupons/EditCouponPage.es.js +48 -0
- package/lib/pages/cms/coupons/ProductScopePicker.cjs.js +1 -0
- package/lib/pages/cms/coupons/ProductScopePicker.es.js +120 -0
- package/lib/pages/cms/coupons/actions.cjs.js +1 -0
- package/lib/pages/cms/coupons/actions.es.js +128 -0
- package/lib/pages/cms/coupons/product-options.cjs.js +1 -0
- package/lib/pages/cms/coupons/product-options.es.js +27 -0
- package/lib/pages/cms/orders/ExportReportsDialog.cjs.js +1 -0
- package/lib/pages/cms/orders/ExportReportsDialog.es.js +130 -0
- package/lib/pages/cms/orders/OrderDetailPage.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderDetailPage.es.js +137 -0
- package/lib/pages/cms/orders/OrderPrintButton.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderPrintButton.es.js +22 -0
- package/lib/pages/cms/orders/OrderStatusForm.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderStatusForm.es.js +71 -0
- package/lib/pages/cms/orders/OrdersPage.cjs.js +1 -0
- package/lib/pages/cms/orders/OrdersPage.es.js +104 -0
- package/lib/pages/cms/orders/actions.cjs.js +7 -0
- package/lib/pages/cms/orders/actions.es.js +71 -0
- package/lib/pages/cms/orders/export-actions.cjs.js +1 -0
- package/lib/pages/cms/orders/export-actions.es.js +27 -0
- package/lib/pages/cms/orders/server-actions.cjs.js +1 -0
- package/lib/pages/cms/orders/server-actions.es.js +55 -0
- package/lib/pages/cms/payments/PaymentsClient.cjs.js +1 -0
- package/lib/pages/cms/payments/PaymentsClient.es.js +188 -0
- package/lib/pages/cms/payments/PaymentsPage.cjs.js +1 -0
- package/lib/pages/cms/payments/PaymentsPage.es.js +29 -0
- package/lib/pages/cms/payments/actions.cjs.js +1 -0
- package/lib/pages/cms/payments/actions.es.js +23 -0
- package/lib/pages/cms/payments/queries.cjs.js +1 -0
- package/lib/pages/cms/payments/queries.es.js +30 -0
- package/lib/pages/cms/products/ProductsPage.cjs.js +1 -0
- package/lib/pages/cms/products/ProductsPage.es.js +46 -0
- package/lib/pages/cms/products/_id_/edit/EditProductPage.cjs.js +1 -0
- package/lib/pages/cms/products/_id_/edit/EditProductPage.es.js +156 -0
- package/lib/pages/cms/products/actions.cjs.js +44 -0
- package/lib/pages/cms/products/actions.es.js +175 -0
- package/lib/pages/cms/products/attributes/AttributeManagementPage.cjs.js +1 -0
- package/lib/pages/cms/products/attributes/AttributeManagementPage.es.js +48 -0
- package/lib/pages/cms/products/attributes/components/AttributeManager.cjs.js +1 -0
- package/lib/pages/cms/products/attributes/components/AttributeManager.es.js +291 -0
- package/lib/pages/cms/products/categories/CategoryManagementPage.cjs.js +1 -0
- package/lib/pages/cms/products/categories/CategoryManagementPage.es.js +36 -0
- package/lib/pages/cms/products/categories/components/CategoryManager.cjs.js +1 -0
- package/lib/pages/cms/products/categories/components/CategoryManager.es.js +263 -0
- package/lib/pages/cms/products/components/CopyProductFromLanguage.cjs.js +1 -0
- package/lib/pages/cms/products/components/CopyProductFromLanguage.es.js +114 -0
- package/lib/pages/cms/products/components/CurrencyPriceFields.cjs.js +1 -0
- package/lib/pages/cms/products/components/CurrencyPriceFields.es.js +107 -0
- package/lib/pages/cms/products/components/DeleteProductButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/DeleteProductButton.es.js +48 -0
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.cjs.js +1 -0
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.es.js +86 -0
- package/lib/pages/cms/products/components/ProductCategorySelector.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductCategorySelector.es.js +160 -0
- package/lib/pages/cms/products/components/ProductForm.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductForm.es.js +702 -0
- package/lib/pages/cms/products/components/ProductMediaManager.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductMediaManager.es.js +104 -0
- package/lib/pages/cms/products/components/ProductsBulkTable.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductsBulkTable.es.js +228 -0
- package/lib/pages/cms/products/components/SaleScheduleFields.cjs.js +1 -0
- package/lib/pages/cms/products/components/SaleScheduleFields.es.js +137 -0
- package/lib/pages/cms/products/components/SyncFreemiusButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/SyncFreemiusButton.es.js +36 -0
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.es.js +40 -0
- package/lib/pages/cms/products/components/VariationsEditor.cjs.js +1 -0
- package/lib/pages/cms/products/components/VariationsEditor.es.js +408 -0
- package/lib/pages/cms/products/inventory/InventoryPage.cjs.js +1 -0
- package/lib/pages/cms/products/inventory/InventoryPage.es.js +16 -0
- package/lib/pages/cms/products/inventory/InventoryTableClient.cjs.js +2 -0
- package/lib/pages/cms/products/inventory/InventoryTableClient.es.js +214 -0
- package/lib/pages/cms/products/inventory/actions.cjs.js +3 -0
- package/lib/pages/cms/products/inventory/actions.es.js +95 -0
- package/lib/pages/cms/products/new/NewProductPage.cjs.js +1 -0
- package/lib/pages/cms/products/new/NewProductPage.es.js +76 -0
- package/lib/pages/cms/products/product-price-sync.cjs.js +1 -0
- package/lib/pages/cms/products/product-price-sync.es.js +98 -0
- package/lib/pages/cms/products/server-actions.cjs.js +1 -0
- package/lib/pages/cms/products/server-actions.es.js +193 -0
- package/lib/pages/cms/shipping/ShippingPage.cjs.js +5 -0
- package/lib/pages/cms/shipping/ShippingPage.es.js +211 -0
- package/lib/pages/cms/shipping/components/RateForm.cjs.js +1 -0
- package/lib/pages/cms/shipping/components/RateForm.es.js +441 -0
- package/lib/pages/cms/shipping/components/ZoneForm.cjs.js +1 -0
- package/lib/pages/cms/shipping/components/ZoneForm.es.js +228 -0
- package/lib/pages/cms/shipping/server-actions.cjs.js +1 -0
- package/lib/pages/cms/shipping/server-actions.es.js +159 -0
- package/lib/pages/cms/taxes/TaxesPage.cjs.js +1 -0
- package/lib/pages/cms/taxes/TaxesPage.es.js +172 -0
- package/lib/pages/cms/taxes/actions.cjs.js +1 -0
- package/lib/pages/cms/taxes/actions.es.js +57 -0
- package/lib/pages/cms/taxes/components/TaxRateForm.cjs.js +1 -0
- package/lib/pages/cms/taxes/components/TaxRateForm.es.js +100 -0
- package/lib/product-actions.cjs.js +237 -0
- package/lib/product-actions.es.js +524 -0
- package/lib/product-context.cjs.js +1 -0
- package/lib/product-context.es.js +16 -0
- package/lib/product-schema.cjs.js +1 -0
- package/lib/product-schema.es.js +134 -0
- package/lib/providers/freemius.cjs.js +5 -0
- package/lib/providers/freemius.es.js +538 -0
- package/lib/providers/stripe.cjs.js +1 -0
- package/lib/providers/stripe.es.js +473 -0
- package/lib/server-actions/coupon-actions.cjs.js +1 -0
- package/lib/server-actions/coupon-actions.es.js +23 -0
- package/lib/server-actions/customer-actions.cjs.js +1 -0
- package/lib/server-actions/customer-actions.es.js +30 -0
- package/lib/server-actions/product-actions.cjs.js +1 -0
- package/{server-actions → lib/server-actions}/product-actions.es.js +5 -4
- package/lib/server-actions/shipping-actions.cjs.js +1 -0
- package/{shipping-actions-BnHjlo2q.js → lib/server-actions/shipping-actions.es.js} +9 -7
- package/lib/server-actions/tax-actions.cjs.js +1 -0
- package/lib/server-actions/tax-actions.es.js +40 -0
- package/lib/shared-inventory.cjs.js +15 -0
- package/lib/shared-inventory.es.js +171 -0
- package/lib/shipping/resolver.cjs.js +7 -0
- package/lib/shipping/resolver.es.js +62 -0
- package/lib/shipping-rate-currency.cjs.js +1 -0
- package/lib/shipping-rate-currency.es.js +72 -0
- package/lib/states.cjs.js +1 -0
- package/{states-DlHJezQ1.js → lib/states.es.js} +27 -100
- package/lib/stripe/checkout.cjs.js +1 -0
- package/lib/stripe/checkout.es.js +182 -0
- package/lib/stripe/client.cjs.js +1 -0
- package/lib/stripe/client.es.js +7 -0
- package/lib/stripe/order-sync.cjs.js +1 -0
- package/lib/stripe/order-sync.es.js +130 -0
- package/lib/stripe/webhooks.cjs.js +1 -0
- package/lib/stripe/webhooks.es.js +30 -0
- package/lib/tax-calculation.cjs.js +1 -0
- package/lib/tax-calculation.es.js +101 -0
- package/lib/trials.cjs.js +1 -0
- package/{trials-RDcRAZKx.js → lib/trials.es.js} +9 -9
- package/{use-cart.es.js → lib/use-cart.es.js} +1 -0
- package/lib/zod-config.cjs.js +1 -0
- package/lib/zod-config.es.js +6 -0
- package/package.json +4 -4
- package/server.cjs.js +1 -110
- package/server.es.js +178 -6052
- package/AddToCartButton-DsSEH9yp.cjs +0 -1
- package/CouponForm-BI_5SBHQ.js +0 -152
- package/CouponForm-D_uu2bLP.cjs +0 -1
- package/CurrencyProvider-Cg-Q6ucj.cjs +0 -1
- package/CurrencyProvider-OzlRN96V.js +0 -120
- package/CurrencyProvider.cjs.js +0 -1
- package/CurrencyProvider.es.js +0 -10
- package/ProductDetailsLayout-BxJH_BxR.cjs +0 -1
- package/ProductDetailsLayout-Dg8dRTYp.js +0 -530
- package/ProductGrid-BdL7iglO.cjs +0 -1
- package/ProductGrid-D3AWM8sr.js +0 -130
- package/actions-AHmBrS5e.cjs +0 -48
- package/actions-j5fuSZX-.js +0 -820
- package/cart-store.cjs.js +0 -1
- package/components/Cart.cjs.js +0 -1
- package/components/Cart.es.js +0 -259
- package/components/CartDrawer.cjs.js +0 -1
- package/components/Checkout.cjs.js +0 -1
- package/components/CurrencySwitcher.cjs.js +0 -1
- package/components/FeaturedProduct.cjs.js +0 -1
- package/components/ProductDetailsLayout.cjs.js +0 -1
- package/components/ProductDetailsLayout.es.js +0 -19
- package/components/ProductGrid.cjs.js +0 -1
- package/components/ProductGrid.es.js +0 -6
- package/coupon-server-C9ySm3I5.cjs +0 -1
- package/customer-C-UPvrYN.cjs +0 -1
- package/invoice-ui-CAnJPu6n.cjs +0 -29
- package/invoice-ui-DtpbTJE1.js +0 -2886
- package/product-actions-CONBF8i6.cjs +0 -251
- package/product-actions-DjlIWCMH.js +0 -691
- package/resolver-Fz_FKsfX.cjs +0 -7
- package/resolver-cfrCaHpE.js +0 -128
- package/server-actions/product-actions.cjs.js +0 -1
- package/shipping-actions-D6zt20gg.cjs +0 -1
- package/states-CWYRxV4B.cjs +0 -1
- package/tax-calculation-Dab89aHd.js +0 -181
- package/tax-calculation-MkDKOEkL.cjs +0 -1
- package/trials-DvZaOtNy.cjs +0 -1
- /package/{components → lib/components}/SimpleTiptapRenderer.cjs.js +0 -0
- /package/{components → lib/components}/SimpleTiptapRenderer.es.js +0 -0
- /package/{currency-constants.cjs.js → lib/currency-constants.cjs.js} +0 -0
- /package/{currency-constants.es.js → lib/currency-constants.es.js} +0 -0
- /package/{currency-rest-client-uolJxUkL.cjs → lib/currency-rest-client.cjs.js} +0 -0
- /package/{currency-rest-client-CwoqdgAP.js → lib/currency-rest-client.es.js} +0 -0
- /package/{currency.cjs.js → lib/currency.cjs.js} +0 -0
- /package/{currency.es.js → lib/currency.es.js} +0 -0
- /package/{types.cjs.js → lib/types.cjs.js} +0 -0
- /package/{types.es.js → lib/types.es.js} +0 -0
- /package/{use-cart.cjs.js → lib/use-cart.cjs.js} +0 -0
- /package/{variation-utils.cjs.js → lib/variation-utils.cjs.js} +0 -0
- /package/{variation-utils.es.js → lib/variation-utils.es.js} +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as i, jsx as o } from "react/jsx-runtime";
|
|
3
|
+
import F from "next/link";
|
|
4
|
+
import { useState as R, useMemo as E, useEffect as v } from "react";
|
|
5
|
+
import { Badge as D, Button as z, Label as P, Input as U } from "@nextblock-cms/ui";
|
|
6
|
+
import { extractSelectedTermsByAttribute as re, resolveTermValue as L, resolveAttributeName as q, generateVariantDrafts as ne } from "../../../../variation-utils.es.js";
|
|
7
|
+
import { CurrencyPriceFields as oe } from "./CurrencyPriceFields.es.js";
|
|
8
|
+
import { SaleScheduleFields as se } from "./SaleScheduleFields.es.js";
|
|
9
|
+
import { normalizeSalePriceMap as ie, normalizePriceMap as de, convertMinorUnitAmount as I } from "../../../../currency.es.js";
|
|
10
|
+
import { sanitizeVariantDraftsForStoreManagedCurrencies as K, getStoreManagedPriceCurrencyCodes as ce, resolveEditorCurrencyPriceMaps as le } from "../product-price-sync.es.js";
|
|
11
|
+
import { majorUnitAmountToMinor as X, minorUnitAmountToMajor as G } from "@nextblock-cms/utils";
|
|
12
|
+
const O = process.env.NEXT_PUBLIC_R2_BASE_URL || "", Q = process.env.NEXT_PUBLIC_SUPABASE_URL || "", ae = (c) => c.startsWith("http") ? c : O ? `${O.replace(/\/+$/, "")}/${c.replace(/^\/+/, "")}` : Q ? `${Q.replace(/\/+$/, "")}/storage/v1/object/public/media/${c.replace(/^\/+/, "")}` : c;
|
|
13
|
+
function W(c, m = "USD") {
|
|
14
|
+
return new Intl.NumberFormat("en-US", {
|
|
15
|
+
style: "currency",
|
|
16
|
+
currency: m
|
|
17
|
+
}).format(c);
|
|
18
|
+
}
|
|
19
|
+
function me(c) {
|
|
20
|
+
return Object.entries(c).filter(([, m]) => m.length > 0).map(([m, _]) => ({ attribute_id: m, term_ids: _ }));
|
|
21
|
+
}
|
|
22
|
+
function Ne({
|
|
23
|
+
globalAttributes: c,
|
|
24
|
+
currentLanguageCode: m,
|
|
25
|
+
baseSku: _,
|
|
26
|
+
basePrice: $,
|
|
27
|
+
basePrices: M,
|
|
28
|
+
baseSalePrice: w,
|
|
29
|
+
baseSalePrices: A,
|
|
30
|
+
currencies: d,
|
|
31
|
+
availableVariantImages: x = [],
|
|
32
|
+
initialVariationAttributes: b,
|
|
33
|
+
initialVariants: T,
|
|
34
|
+
onChange: B
|
|
35
|
+
}) {
|
|
36
|
+
const [g, H] = R(() => b && b.length > 0 ? b.reduce((e, r) => (e[r.attribute_id] = r.term_ids, e), {}) : re(T || [])), [h, f] = R(
|
|
37
|
+
K(
|
|
38
|
+
T || [],
|
|
39
|
+
d
|
|
40
|
+
)
|
|
41
|
+
), y = E(
|
|
42
|
+
() => c.map((e) => ({
|
|
43
|
+
attribute_id: e.id,
|
|
44
|
+
attribute_name: q(e, m),
|
|
45
|
+
terms: e.terms.filter((r) => (g[e.id] || []).includes(r.id)).map((r) => ({
|
|
46
|
+
...r,
|
|
47
|
+
value: L(r, m)
|
|
48
|
+
}))
|
|
49
|
+
})).filter((e) => e.terms.length > 0),
|
|
50
|
+
[m, c, g]
|
|
51
|
+
);
|
|
52
|
+
v(() => {
|
|
53
|
+
if (y.length === 0) {
|
|
54
|
+
f([]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
f(
|
|
58
|
+
(e) => K(
|
|
59
|
+
ne({
|
|
60
|
+
baseSku: _,
|
|
61
|
+
basePrice: $,
|
|
62
|
+
basePrices: de(M),
|
|
63
|
+
baseSalePrice: w,
|
|
64
|
+
baseSalePrices: ie(A),
|
|
65
|
+
selectedAttributes: y,
|
|
66
|
+
previousVariants: e
|
|
67
|
+
}),
|
|
68
|
+
d
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
}, [$, M, w, A, _, d, y]), v(() => {
|
|
72
|
+
B({
|
|
73
|
+
variationAttributes: me(g),
|
|
74
|
+
variants: h
|
|
75
|
+
});
|
|
76
|
+
}, [B, g, h]);
|
|
77
|
+
const J = h.reduce(
|
|
78
|
+
(e, r) => e + (r.stock_quantity || 0),
|
|
79
|
+
0
|
|
80
|
+
), k = d.find((e) => e.is_default) ?? d[0], N = E(
|
|
81
|
+
() => ce(d),
|
|
82
|
+
[d]
|
|
83
|
+
), Y = (e, r) => {
|
|
84
|
+
H((t) => {
|
|
85
|
+
const n = new Set(t[e] || []);
|
|
86
|
+
return n.has(r) ? n.delete(r) : n.add(r), {
|
|
87
|
+
...t,
|
|
88
|
+
[e]: [...n]
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}, C = (e, r, t) => {
|
|
92
|
+
f(
|
|
93
|
+
(n) => n.map((s) => {
|
|
94
|
+
if (s.combination_key !== e)
|
|
95
|
+
return s;
|
|
96
|
+
if (r === "sku")
|
|
97
|
+
return {
|
|
98
|
+
...s,
|
|
99
|
+
sku: t
|
|
100
|
+
};
|
|
101
|
+
if (r === "upc")
|
|
102
|
+
return {
|
|
103
|
+
...s,
|
|
104
|
+
upc: t
|
|
105
|
+
};
|
|
106
|
+
if (r === "sale_price" && t === "")
|
|
107
|
+
return {
|
|
108
|
+
...s,
|
|
109
|
+
sale_price: null
|
|
110
|
+
};
|
|
111
|
+
if (r === "prices" || r === "sale_prices")
|
|
112
|
+
return s;
|
|
113
|
+
const l = t === "" ? 0 : Number(t);
|
|
114
|
+
return {
|
|
115
|
+
...s,
|
|
116
|
+
[r]: Number.isFinite(l) ? l : 0
|
|
117
|
+
};
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
}, Z = (e, r, t) => {
|
|
121
|
+
f(
|
|
122
|
+
(n) => n.map(
|
|
123
|
+
(s) => s.combination_key === e ? { ...s, [r]: t } : s
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
}, V = (e, r, t, n) => {
|
|
127
|
+
const s = d.find((l) => l.is_default) ?? d[0];
|
|
128
|
+
f(
|
|
129
|
+
(l) => l.map((p) => {
|
|
130
|
+
if (p.combination_key !== e)
|
|
131
|
+
return p;
|
|
132
|
+
const u = {
|
|
133
|
+
...t === "prices" ? p.prices : p.sale_prices,
|
|
134
|
+
[r]: n
|
|
135
|
+
};
|
|
136
|
+
return {
|
|
137
|
+
...p,
|
|
138
|
+
[t]: u,
|
|
139
|
+
...r === s?.code ? t === "prices" ? { price: n ?? 0 } : { sale_price: n } : {}
|
|
140
|
+
};
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
}, ee = (e) => {
|
|
144
|
+
const r = d.find((n) => n.is_default) ?? d[0], t = new Set(N);
|
|
145
|
+
r && f(
|
|
146
|
+
(n) => n.map((s) => {
|
|
147
|
+
if (s.combination_key !== e)
|
|
148
|
+
return s;
|
|
149
|
+
const l = d.reduce((u, a) => {
|
|
150
|
+
if (a.code !== r.code && t.has(a.code))
|
|
151
|
+
return u;
|
|
152
|
+
const S = I({
|
|
153
|
+
amount: X(s.price, r.code),
|
|
154
|
+
fromCurrencyCode: r.code,
|
|
155
|
+
toCurrencyCode: a.code,
|
|
156
|
+
currencies: d,
|
|
157
|
+
applyRounding: !0
|
|
158
|
+
});
|
|
159
|
+
return u[a.code] = G(S, a.code), u;
|
|
160
|
+
}, {}), p = d.reduce(
|
|
161
|
+
(u, a) => {
|
|
162
|
+
if (a.code !== r.code && t.has(a.code))
|
|
163
|
+
return u;
|
|
164
|
+
if (typeof s.sale_price != "number")
|
|
165
|
+
return u[a.code] = null, u;
|
|
166
|
+
const S = I({
|
|
167
|
+
amount: X(s.sale_price, r.code),
|
|
168
|
+
fromCurrencyCode: r.code,
|
|
169
|
+
toCurrencyCode: a.code,
|
|
170
|
+
currencies: d,
|
|
171
|
+
applyRounding: !0
|
|
172
|
+
});
|
|
173
|
+
return u[a.code] = G(S, a.code), u;
|
|
174
|
+
},
|
|
175
|
+
{}
|
|
176
|
+
);
|
|
177
|
+
return {
|
|
178
|
+
...s,
|
|
179
|
+
prices: l,
|
|
180
|
+
sale_prices: p
|
|
181
|
+
};
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
}, te = (e, r) => {
|
|
185
|
+
const t = x.find((l) => l.media_id === r);
|
|
186
|
+
if (!t)
|
|
187
|
+
return;
|
|
188
|
+
const n = t.file_path, s = ae(n);
|
|
189
|
+
f(
|
|
190
|
+
(l) => l.map(
|
|
191
|
+
(p) => p.combination_key === e ? {
|
|
192
|
+
...p,
|
|
193
|
+
main_media_id: t.media_id,
|
|
194
|
+
main_image_url: s
|
|
195
|
+
} : p
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
}, j = (e) => {
|
|
199
|
+
f(
|
|
200
|
+
(r) => r.map(
|
|
201
|
+
(t) => t.combination_key === e ? {
|
|
202
|
+
...t,
|
|
203
|
+
main_media_id: null,
|
|
204
|
+
main_image_url: null
|
|
205
|
+
} : t
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
};
|
|
209
|
+
return c.length === 0 ? /* @__PURE__ */ i("div", { className: "rounded-lg border border-dashed p-6 text-sm text-muted-foreground", children: [
|
|
210
|
+
"No global attributes have been created yet. Create them first in",
|
|
211
|
+
" ",
|
|
212
|
+
/* @__PURE__ */ o(F, { href: "/cms/products/attributes", className: "font-medium text-primary underline-offset-4 hover:underline", children: "Attribute Management" }),
|
|
213
|
+
"."
|
|
214
|
+
] }) : /* @__PURE__ */ i("div", { className: "space-y-3", children: [
|
|
215
|
+
/* @__PURE__ */ i("div", { className: "space-y-2", children: [
|
|
216
|
+
/* @__PURE__ */ i("div", { className: "flex items-center justify-between gap-3", children: [
|
|
217
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-3", children: [
|
|
218
|
+
/* @__PURE__ */ o("span", { className: "text-xs uppercase font-bold text-muted-foreground tracking-wider leading-none", children: "Attributes" }),
|
|
219
|
+
/* @__PURE__ */ i(D, { variant: "outline", className: "text-[10px] px-1.5 h-4", children: [
|
|
220
|
+
h.length,
|
|
221
|
+
" variants"
|
|
222
|
+
] }),
|
|
223
|
+
/* @__PURE__ */ i(D, { variant: "secondary", className: "text-[10px] px-1.5 h-4", children: [
|
|
224
|
+
"Stock: ",
|
|
225
|
+
J
|
|
226
|
+
] })
|
|
227
|
+
] }),
|
|
228
|
+
/* @__PURE__ */ o(z, { asChild: !0, variant: "outline", size: "sm", className: "h-7 text-xs px-3", children: /* @__PURE__ */ o(F, { href: "/cms/products/attributes", children: "Manage" }) })
|
|
229
|
+
] }),
|
|
230
|
+
/* @__PURE__ */ o("div", { className: "grid gap-2 lg:grid-cols-2", children: c.map((e) => {
|
|
231
|
+
const r = g[e.id] || [];
|
|
232
|
+
return /* @__PURE__ */ i("div", { className: "flex items-center gap-3 rounded border p-2.5", children: [
|
|
233
|
+
/* @__PURE__ */ i("div", { className: "shrink-0 w-[100px]", children: [
|
|
234
|
+
/* @__PURE__ */ o("span", { className: "text-sm font-bold block leading-tight", children: q(e, m) }),
|
|
235
|
+
/* @__PURE__ */ i("span", { className: "text-[10px] text-muted-foreground leading-none", children: [
|
|
236
|
+
r.length,
|
|
237
|
+
" selected"
|
|
238
|
+
] })
|
|
239
|
+
] }),
|
|
240
|
+
/* @__PURE__ */ o("div", { className: "flex flex-wrap gap-1.5 flex-1", children: e.terms.map((t) => {
|
|
241
|
+
const n = r.includes(t.id);
|
|
242
|
+
return /* @__PURE__ */ o(
|
|
243
|
+
"button",
|
|
244
|
+
{
|
|
245
|
+
type: "button",
|
|
246
|
+
onClick: () => Y(e.id, t.id),
|
|
247
|
+
className: `rounded-full border px-2.5 py-0.5 text-[11px] font-medium transition-colors ${n ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground hover:border-primary/40"}`,
|
|
248
|
+
children: L(t, m)
|
|
249
|
+
},
|
|
250
|
+
t.id
|
|
251
|
+
);
|
|
252
|
+
}) })
|
|
253
|
+
] }, e.id);
|
|
254
|
+
}) })
|
|
255
|
+
] }),
|
|
256
|
+
h.length === 0 ? /* @__PURE__ */ o("div", { className: "rounded border border-dashed p-3 text-xs text-muted-foreground text-center", children: "Select terms above to generate variations." }) : /* @__PURE__ */ o("div", { className: "space-y-2", children: h.map((e) => {
|
|
257
|
+
const r = le({
|
|
258
|
+
currencies: d,
|
|
259
|
+
prices: e.prices || {},
|
|
260
|
+
salePrices: e.sale_prices || {},
|
|
261
|
+
fallbackPrice: e.price,
|
|
262
|
+
fallbackSalePrice: e.sale_price
|
|
263
|
+
});
|
|
264
|
+
return /* @__PURE__ */ i("div", { className: "rounded border p-3 space-y-2", children: [
|
|
265
|
+
/* @__PURE__ */ i("div", { className: "flex items-center justify-between gap-3", children: [
|
|
266
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
|
|
267
|
+
/* @__PURE__ */ o("span", { className: "text-sm font-bold", children: e.label }),
|
|
268
|
+
/* @__PURE__ */ o("span", { className: "text-xs text-muted-foreground", children: e.selected_options.map((t) => `${t.attribute_name}: ${t.term_value}`).join(" · ") })
|
|
269
|
+
] }),
|
|
270
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
|
|
271
|
+
/* @__PURE__ */ i("span", { children: [
|
|
272
|
+
"Reg: ",
|
|
273
|
+
W(e.price, k?.code || "USD")
|
|
274
|
+
] }),
|
|
275
|
+
/* @__PURE__ */ i("span", { children: [
|
|
276
|
+
"Sale:",
|
|
277
|
+
" ",
|
|
278
|
+
e.sale_price !== null && e.sale_price !== void 0 ? W(e.sale_price, k?.code || "USD") : "—"
|
|
279
|
+
] })
|
|
280
|
+
] })
|
|
281
|
+
] }),
|
|
282
|
+
/* @__PURE__ */ i("div", { className: "grid grid-cols-3 gap-2.5", children: [
|
|
283
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
|
|
284
|
+
/* @__PURE__ */ o(P, { htmlFor: `variant-sku-${e.combination_key}`, className: "text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0", children: "SKU" }),
|
|
285
|
+
/* @__PURE__ */ o(
|
|
286
|
+
U,
|
|
287
|
+
{
|
|
288
|
+
id: `variant-sku-${e.combination_key}`,
|
|
289
|
+
value: e.sku,
|
|
290
|
+
onChange: (t) => C(e.combination_key, "sku", t.target.value),
|
|
291
|
+
placeholder: "SKU",
|
|
292
|
+
className: "h-8 text-sm font-mono"
|
|
293
|
+
}
|
|
294
|
+
)
|
|
295
|
+
] }),
|
|
296
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
|
|
297
|
+
/* @__PURE__ */ o(P, { htmlFor: `variant-upc-${e.combination_key}`, className: "text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0", children: "UPC" }),
|
|
298
|
+
/* @__PURE__ */ o(
|
|
299
|
+
U,
|
|
300
|
+
{
|
|
301
|
+
id: `variant-upc-${e.combination_key}`,
|
|
302
|
+
value: e.upc ?? "",
|
|
303
|
+
onChange: (t) => C(e.combination_key, "upc", t.target.value),
|
|
304
|
+
placeholder: "—",
|
|
305
|
+
className: "h-8 text-sm font-mono"
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] }),
|
|
309
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
|
|
310
|
+
/* @__PURE__ */ o(P, { htmlFor: `variant-stock-${e.combination_key}`, className: "text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0", children: "Qty" }),
|
|
311
|
+
/* @__PURE__ */ o(
|
|
312
|
+
U,
|
|
313
|
+
{
|
|
314
|
+
id: `variant-stock-${e.combination_key}`,
|
|
315
|
+
type: "number",
|
|
316
|
+
min: "0",
|
|
317
|
+
value: e.stock_quantity,
|
|
318
|
+
onChange: (t) => C(
|
|
319
|
+
e.combination_key,
|
|
320
|
+
"stock_quantity",
|
|
321
|
+
t.target.value
|
|
322
|
+
),
|
|
323
|
+
className: "h-8 text-sm font-mono w-20"
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
] })
|
|
327
|
+
] }),
|
|
328
|
+
/* @__PURE__ */ o(
|
|
329
|
+
oe,
|
|
330
|
+
{
|
|
331
|
+
idPrefix: `variant-${e.combination_key}`,
|
|
332
|
+
currencies: d,
|
|
333
|
+
prices: r.prices,
|
|
334
|
+
salePrices: r.salePrices,
|
|
335
|
+
managedCurrencyCodes: N,
|
|
336
|
+
onPriceChange: (t, n) => V(
|
|
337
|
+
e.combination_key,
|
|
338
|
+
t,
|
|
339
|
+
"prices",
|
|
340
|
+
n
|
|
341
|
+
),
|
|
342
|
+
onSalePriceChange: (t, n) => V(
|
|
343
|
+
e.combination_key,
|
|
344
|
+
t,
|
|
345
|
+
"sale_prices",
|
|
346
|
+
n
|
|
347
|
+
),
|
|
348
|
+
onAutoFill: () => ee(e.combination_key),
|
|
349
|
+
helperText: N.length > 0 ? `Store-managed currencies derive from ${k?.code || "the base currency"}.` : void 0,
|
|
350
|
+
trailing: /* @__PURE__ */ o(
|
|
351
|
+
se,
|
|
352
|
+
{
|
|
353
|
+
idPrefix: `variant-${e.combination_key}`,
|
|
354
|
+
startAt: e.sale_start_at,
|
|
355
|
+
endAt: e.sale_end_at,
|
|
356
|
+
onChange: (t, n) => Z(e.combination_key, t, n),
|
|
357
|
+
bare: !0
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
),
|
|
362
|
+
/* @__PURE__ */ i("div", { className: "flex items-center gap-3 pt-1.5 border-t border-muted/30", children: [
|
|
363
|
+
e.main_image_url && /* @__PURE__ */ o("div", { className: "h-9 w-9 overflow-hidden rounded border bg-background shrink-0", children: /* @__PURE__ */ o(
|
|
364
|
+
"img",
|
|
365
|
+
{
|
|
366
|
+
src: e.main_image_url,
|
|
367
|
+
alt: `${e.label} image`,
|
|
368
|
+
className: "h-full w-full object-cover"
|
|
369
|
+
}
|
|
370
|
+
) }),
|
|
371
|
+
/* @__PURE__ */ o("span", { className: "text-xs uppercase font-bold text-muted-foreground tracking-wider shrink-0", children: "Image" }),
|
|
372
|
+
x.length > 0 ? /* @__PURE__ */ i(
|
|
373
|
+
"select",
|
|
374
|
+
{
|
|
375
|
+
className: "flex h-8 rounded-md border border-input bg-background px-2 py-1 text-sm min-w-[180px]",
|
|
376
|
+
value: e.main_media_id ?? "",
|
|
377
|
+
onChange: (t) => {
|
|
378
|
+
if (!t.target.value) {
|
|
379
|
+
j(e.combination_key);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
te(e.combination_key, t.target.value);
|
|
383
|
+
},
|
|
384
|
+
children: [
|
|
385
|
+
/* @__PURE__ */ o("option", { value: "", children: "Use parent image" }),
|
|
386
|
+
x.map((t, n) => /* @__PURE__ */ o("option", { value: t.media_id, children: t.alt?.trim() || `Gallery image ${n + 1}` }, t.media_id))
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
) : /* @__PURE__ */ o("span", { className: "text-xs text-muted-foreground", children: "Add gallery images first." }),
|
|
390
|
+
e.main_media_id && /* @__PURE__ */ o(
|
|
391
|
+
z,
|
|
392
|
+
{
|
|
393
|
+
type: "button",
|
|
394
|
+
variant: "ghost",
|
|
395
|
+
size: "sm",
|
|
396
|
+
className: "h-7 text-xs px-2 text-muted-foreground hover:text-destructive",
|
|
397
|
+
onClick: () => j(e.combination_key),
|
|
398
|
+
children: "Remove"
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
] })
|
|
402
|
+
] }, e.combination_key);
|
|
403
|
+
}) })
|
|
404
|
+
] });
|
|
405
|
+
}
|
|
406
|
+
export {
|
|
407
|
+
Ne as VariationsEditor
|
|
408
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("../../../../shared-inventory.cjs.js"),s=require("./InventoryTableClient.cjs.js");async function a(){const t=await n.getInventoryItems();return e.jsxs("div",{className:"p-8 space-y-6",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("h1",{className:"text-3xl font-bold",children:"Inventory"}),e.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."})]}),e.jsx(s.InventoryTableClient,{initialItems:t})]})}exports.InventoryPage=a;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsxs as t, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { getInventoryItems as a } from "../../../../shared-inventory.es.js";
|
|
3
|
+
import { InventoryTableClient as r } from "./InventoryTableClient.es.js";
|
|
4
|
+
async function l() {
|
|
5
|
+
const n = await a();
|
|
6
|
+
return /* @__PURE__ */ t("div", { className: "p-8 space-y-6", children: [
|
|
7
|
+
/* @__PURE__ */ t("div", { className: "space-y-2", children: [
|
|
8
|
+
/* @__PURE__ */ e("h1", { className: "text-3xl font-bold", children: "Inventory" }),
|
|
9
|
+
/* @__PURE__ */ e("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." })
|
|
10
|
+
] }),
|
|
11
|
+
/* @__PURE__ */ e(r, { initialItems: n })
|
|
12
|
+
] });
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
l as InventoryPage
|
|
16
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),d=require("react"),t=require("@nextblock-cms/ui"),y=require("lucide-react"),j=require("sonner"),S=require("./actions.cjs.js");function R(o){const i=String(o??"");return/[",\n]/.test(i)?`"${i.replace(/"/g,'""')}"`:i}function K(o){const i=["sku","stock","usage_type","product_titles","languages","statuses","parent_product_skus"],b=o.map(c=>[c.sku,c.stock,c.usageType,c.productTitles.join("|"),c.languages.join("|"),c.statuses.join("|"),c.parentProductSkus.join("|")]);return[i,...b].map(c=>c.map(p=>R(p)).join(",")).join(`
|
|
2
|
+
`)}function B(o){return o.usageType==="mixed"?"Shared SKU":o.usageType==="variant"?`Variant SKU ${o.sku}`:"Simple Product"}function L(o){return o.usageType==="variant"?"secondary":"outline"}function P({initialItems:o}){const[i,b]=d.useState(o),[c,p]=d.useState(()=>o.reduce((s,n)=>(s[n.key]=String(n.stock),s),{})),[k,T]=d.useState(""),[h,f]=d.useTransition(),[w,x]=d.useState(null),v=d.useRef(null),m=d.useMemo(()=>{const s=k.trim().toLowerCase();return s?i.filter(n=>n.sku.toLowerCase().includes(s)||n.productTitles.join(" ").toLowerCase().includes(s)||n.parentProductSkus.join(" ").toLowerCase().includes(s)||n.languages.join(" ").toLowerCase().includes(s)):i},[i,k]),C=()=>{const s=K(i),n=new Blob([s],{type:"text/csv;charset=utf-8;"}),r=URL.createObjectURL(n),l=document.createElement("a");l.href=r,l.download="inventory-export.csv",l.click(),URL.revokeObjectURL(r)},N=s=>{const n=c[s.key]??String(s.stock),r=Number.parseInt(n,10);if(!Number.isFinite(r)||r<0){j.toast.error("Stock must be a non-negative whole number.");return}x(s.key),f(async()=>{const l=await S.updateInventoryQuantityAction({sku:s.sku,stock:r});if(!l.success){j.toast.error(l.error||"Failed to update inventory."),x(null);return}const u=typeof l.stock=="number"?l.stock:r;b(a=>a.map(g=>g.key===s.key?{...g,stock:u}:g)),p(a=>({...a,[s.key]:String(u)})),x(null),j.toast.success(`Inventory updated for ${s.sku}.`)})},I=()=>{v.current?.click()},U=async s=>{const n=await s.text();x("import"),f(async()=>{const r=await S.importInventoryCsvAction(n);if(!r.success){j.toast.error(r.error||"Failed to import inventory CSV."),x(null);return}const l=r.items||[];b(l),p(l.reduce((u,a)=>(u[a.key]=String(a.stock),u),{})),x(null),j.toast.success(`Imported ${r.updatedCount||0} inventory updates.`)})};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex flex-col gap-3 rounded-xl border bg-card p-4",children:[e.jsxs("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",children:[e.jsxs("div",{className:"relative w-full lg:max-w-md",children:[e.jsx(y.Search,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx(t.Input,{value:k,onChange:s=>T(s.target.value),placeholder:"Search by SKU, product title, parent SKU, or language...",className:"pl-9"})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("input",{ref:v,type:"file",accept:".csv,text/csv",className:"hidden",onChange:s=>{const n=s.target.files?.[0];n&&U(n),s.currentTarget.value=""}}),e.jsxs(t.Button,{type:"button",variant:"outline",onClick:I,disabled:h,children:[e.jsx(y.Upload,{className:"mr-2 h-4 w-4"}),"Import CSV"]}),e.jsxs(t.Button,{type:"button",variant:"outline",onClick:C,disabled:h,children:[e.jsx(y.Download,{className:"mr-2 h-4 w-4"}),"Export CSV"]})]})]}),e.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."})]}),e.jsx("div",{className:"rounded-xl border bg-card",children:e.jsxs(t.Table,{children:[e.jsx(t.TableHeader,{children:e.jsxs(t.TableRow,{children:[e.jsx(t.TableHead,{children:"SKU"}),e.jsx(t.TableHead,{children:"Usage"}),e.jsx(t.TableHead,{children:"Linked Products"}),e.jsx(t.TableHead,{children:"Languages"}),e.jsx(t.TableHead,{children:"Status"}),e.jsx(t.TableHead,{className:"w-[160px]",children:"Quantity"}),e.jsx(t.TableHead,{className:"text-right",children:"Actions"})]})}),e.jsx(t.TableBody,{children:m.length>0?m.map(s=>{const n=c[s.key]??String(s.stock),r=Number.parseInt(n,10),l=Number.isFinite(r)&&r!==s.stock,u=w===s.key;return e.jsxs(t.TableRow,{children:[e.jsx(t.TableCell,{className:"font-mono text-sm",children:s.sku}),e.jsx(t.TableCell,{children:e.jsx(t.Badge,{variant:L(s),children:B(s)})}),e.jsx(t.TableCell,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"font-medium",children:s.productTitles.join(", ")}),s.usageType!=="product"?e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Parent SKU",s.parentProductSkus.length>1?"s":"",":"," ",e.jsx("span",{className:"font-mono",children:s.parentProductSkus.join(", ")})]}):null]})}),e.jsx(t.TableCell,{children:e.jsx("div",{className:"flex flex-wrap gap-1",children:s.languages.map(a=>e.jsx(t.Badge,{variant:"outline",children:a},`${s.key}:${a}`))})}),e.jsx(t.TableCell,{children:e.jsx("div",{className:"flex flex-wrap gap-1",children:s.statuses.map(a=>e.jsx(t.Badge,{variant:"outline",children:a},`${s.key}:${a}`))})}),e.jsx(t.TableCell,{children:e.jsx(t.Input,{type:"number",min:0,step:1,value:n,disabled:h,onChange:a=>p(g=>({...g,[s.key]:a.target.value})),className:"w-28"})}),e.jsx(t.TableCell,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(t.Button,{type:"button",size:"sm",variant:"ghost",disabled:!l||h,onClick:()=>p(a=>({...a,[s.key]:String(s.stock)})),children:[e.jsx(y.RotateCcw,{className:"mr-2 h-4 w-4"}),"Reset"]}),e.jsxs(t.Button,{type:"button",size:"sm",disabled:!l||h,onClick:()=>N(s),children:[e.jsx(y.Save,{className:"mr-2 h-4 w-4"}),u?"Saving...":"Save"]})]})})]},s.key)}):e.jsx(t.TableRow,{children:e.jsx(t.TableCell,{colSpan:7,className:"py-10 text-center text-muted-foreground",children:"No inventory rows matched your search."})})})]})})]})}exports.InventoryTableClient=P;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as a, jsx as t } from "react/jsx-runtime";
|
|
3
|
+
import { useState as v, useTransition as V, useRef as $, useMemo as B } from "react";
|
|
4
|
+
import { Input as j, Button as b, Table as D, TableHeader as F, TableRow as x, TableHead as p, TableBody as z, TableCell as u, Badge as w } from "@nextblock-cms/ui";
|
|
5
|
+
import { Search as A, Upload as _, Download as q, RotateCcw as E, Save as H } from "lucide-react";
|
|
6
|
+
import { toast as m } from "sonner";
|
|
7
|
+
import { importInventoryCsvAction as O, updateInventoryQuantityAction as Q } from "./actions.es.js";
|
|
8
|
+
function M(c) {
|
|
9
|
+
const i = String(c ?? "");
|
|
10
|
+
return /[",\n]/.test(i) ? `"${i.replace(/"/g, '""')}"` : i;
|
|
11
|
+
}
|
|
12
|
+
function G(c) {
|
|
13
|
+
const i = [
|
|
14
|
+
"sku",
|
|
15
|
+
"stock",
|
|
16
|
+
"usage_type",
|
|
17
|
+
"product_titles",
|
|
18
|
+
"languages",
|
|
19
|
+
"statuses",
|
|
20
|
+
"parent_product_skus"
|
|
21
|
+
], k = c.map((l) => [
|
|
22
|
+
l.sku,
|
|
23
|
+
l.stock,
|
|
24
|
+
l.usageType,
|
|
25
|
+
l.productTitles.join("|"),
|
|
26
|
+
l.languages.join("|"),
|
|
27
|
+
l.statuses.join("|"),
|
|
28
|
+
l.parentProductSkus.join("|")
|
|
29
|
+
]);
|
|
30
|
+
return [i, ...k].map((l) => l.map((h) => M(h)).join(",")).join(`
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
function J(c) {
|
|
34
|
+
return c.usageType === "mixed" ? "Shared SKU" : c.usageType === "variant" ? `Variant SKU ${c.sku}` : "Simple Product";
|
|
35
|
+
}
|
|
36
|
+
function W(c) {
|
|
37
|
+
return c.usageType === "variant" ? "secondary" : "outline";
|
|
38
|
+
}
|
|
39
|
+
function re({ initialItems: c }) {
|
|
40
|
+
const [i, k] = v(c), [l, h] = v(
|
|
41
|
+
() => c.reduce((e, n) => (e[n.key] = String(n.stock), e), {})
|
|
42
|
+
), [S, I] = v(""), [y, N] = V(), [U, g] = v(null), C = $(null), T = B(() => {
|
|
43
|
+
const e = S.trim().toLowerCase();
|
|
44
|
+
return e ? i.filter((n) => n.sku.toLowerCase().includes(e) || n.productTitles.join(" ").toLowerCase().includes(e) || n.parentProductSkus.join(" ").toLowerCase().includes(e) || n.languages.join(" ").toLowerCase().includes(e)) : i;
|
|
45
|
+
}, [i, S]), K = () => {
|
|
46
|
+
const e = G(i), n = new Blob([e], { type: "text/csv;charset=utf-8;" }), s = URL.createObjectURL(n), o = document.createElement("a");
|
|
47
|
+
o.href = s, o.download = "inventory-export.csv", o.click(), URL.revokeObjectURL(s);
|
|
48
|
+
}, L = (e) => {
|
|
49
|
+
const n = l[e.key] ?? String(e.stock), s = Number.parseInt(n, 10);
|
|
50
|
+
if (!Number.isFinite(s) || s < 0) {
|
|
51
|
+
m.error("Stock must be a non-negative whole number.");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
g(e.key), N(async () => {
|
|
55
|
+
const o = await Q({
|
|
56
|
+
sku: e.sku,
|
|
57
|
+
stock: s
|
|
58
|
+
});
|
|
59
|
+
if (!o.success) {
|
|
60
|
+
m.error(o.error || "Failed to update inventory."), g(null);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const d = typeof o.stock == "number" ? o.stock : s;
|
|
64
|
+
k(
|
|
65
|
+
(r) => r.map(
|
|
66
|
+
(f) => f.key === e.key ? {
|
|
67
|
+
...f,
|
|
68
|
+
stock: d
|
|
69
|
+
} : f
|
|
70
|
+
)
|
|
71
|
+
), h((r) => ({
|
|
72
|
+
...r,
|
|
73
|
+
[e.key]: String(d)
|
|
74
|
+
})), g(null), m.success(`Inventory updated for ${e.sku}.`);
|
|
75
|
+
});
|
|
76
|
+
}, P = () => {
|
|
77
|
+
C.current?.click();
|
|
78
|
+
}, R = async (e) => {
|
|
79
|
+
const n = await e.text();
|
|
80
|
+
g("import"), N(async () => {
|
|
81
|
+
const s = await O(n);
|
|
82
|
+
if (!s.success) {
|
|
83
|
+
m.error(s.error || "Failed to import inventory CSV."), g(null);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const o = s.items || [];
|
|
87
|
+
k(o), h(
|
|
88
|
+
o.reduce((d, r) => (d[r.key] = String(r.stock), d), {})
|
|
89
|
+
), g(null), m.success(`Imported ${s.updatedCount || 0} inventory updates.`);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
return /* @__PURE__ */ a("div", { className: "space-y-4", children: [
|
|
93
|
+
/* @__PURE__ */ a("div", { className: "flex flex-col gap-3 rounded-xl border bg-card p-4", children: [
|
|
94
|
+
/* @__PURE__ */ a("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between", children: [
|
|
95
|
+
/* @__PURE__ */ a("div", { className: "relative w-full lg:max-w-md", children: [
|
|
96
|
+
/* @__PURE__ */ t(A, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
97
|
+
/* @__PURE__ */ t(
|
|
98
|
+
j,
|
|
99
|
+
{
|
|
100
|
+
value: S,
|
|
101
|
+
onChange: (e) => I(e.target.value),
|
|
102
|
+
placeholder: "Search by SKU, product title, parent SKU, or language...",
|
|
103
|
+
className: "pl-9"
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
] }),
|
|
107
|
+
/* @__PURE__ */ a("div", { className: "flex flex-wrap gap-2", children: [
|
|
108
|
+
/* @__PURE__ */ t(
|
|
109
|
+
"input",
|
|
110
|
+
{
|
|
111
|
+
ref: C,
|
|
112
|
+
type: "file",
|
|
113
|
+
accept: ".csv,text/csv",
|
|
114
|
+
className: "hidden",
|
|
115
|
+
onChange: (e) => {
|
|
116
|
+
const n = e.target.files?.[0];
|
|
117
|
+
n && R(n), e.currentTarget.value = "";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
/* @__PURE__ */ a(b, { type: "button", variant: "outline", onClick: P, disabled: y, children: [
|
|
122
|
+
/* @__PURE__ */ t(_, { className: "mr-2 h-4 w-4" }),
|
|
123
|
+
"Import CSV"
|
|
124
|
+
] }),
|
|
125
|
+
/* @__PURE__ */ a(b, { type: "button", variant: "outline", onClick: K, disabled: y, children: [
|
|
126
|
+
/* @__PURE__ */ t(q, { className: "mr-2 h-4 w-4" }),
|
|
127
|
+
"Export CSV"
|
|
128
|
+
] })
|
|
129
|
+
] })
|
|
130
|
+
] }),
|
|
131
|
+
/* @__PURE__ */ t("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." })
|
|
132
|
+
] }),
|
|
133
|
+
/* @__PURE__ */ t("div", { className: "rounded-xl border bg-card", children: /* @__PURE__ */ a(D, { children: [
|
|
134
|
+
/* @__PURE__ */ t(F, { children: /* @__PURE__ */ a(x, { children: [
|
|
135
|
+
/* @__PURE__ */ t(p, { children: "SKU" }),
|
|
136
|
+
/* @__PURE__ */ t(p, { children: "Usage" }),
|
|
137
|
+
/* @__PURE__ */ t(p, { children: "Linked Products" }),
|
|
138
|
+
/* @__PURE__ */ t(p, { children: "Languages" }),
|
|
139
|
+
/* @__PURE__ */ t(p, { children: "Status" }),
|
|
140
|
+
/* @__PURE__ */ t(p, { className: "w-[160px]", children: "Quantity" }),
|
|
141
|
+
/* @__PURE__ */ t(p, { className: "text-right", children: "Actions" })
|
|
142
|
+
] }) }),
|
|
143
|
+
/* @__PURE__ */ t(z, { children: T.length > 0 ? T.map((e) => {
|
|
144
|
+
const n = l[e.key] ?? String(e.stock), s = Number.parseInt(n, 10), o = Number.isFinite(s) && s !== e.stock, d = U === e.key;
|
|
145
|
+
return /* @__PURE__ */ a(x, { children: [
|
|
146
|
+
/* @__PURE__ */ t(u, { className: "font-mono text-sm", children: e.sku }),
|
|
147
|
+
/* @__PURE__ */ t(u, { children: /* @__PURE__ */ t(w, { variant: W(e), children: J(e) }) }),
|
|
148
|
+
/* @__PURE__ */ t(u, { children: /* @__PURE__ */ a("div", { className: "space-y-1", children: [
|
|
149
|
+
/* @__PURE__ */ t("p", { className: "font-medium", children: e.productTitles.join(", ") }),
|
|
150
|
+
e.usageType !== "product" ? /* @__PURE__ */ a("p", { className: "text-xs text-muted-foreground", children: [
|
|
151
|
+
"Parent SKU",
|
|
152
|
+
e.parentProductSkus.length > 1 ? "s" : "",
|
|
153
|
+
":",
|
|
154
|
+
" ",
|
|
155
|
+
/* @__PURE__ */ t("span", { className: "font-mono", children: e.parentProductSkus.join(", ") })
|
|
156
|
+
] }) : null
|
|
157
|
+
] }) }),
|
|
158
|
+
/* @__PURE__ */ t(u, { children: /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1", children: e.languages.map((r) => /* @__PURE__ */ t(w, { variant: "outline", children: r }, `${e.key}:${r}`)) }) }),
|
|
159
|
+
/* @__PURE__ */ t(u, { children: /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1", children: e.statuses.map((r) => /* @__PURE__ */ t(w, { variant: "outline", children: r }, `${e.key}:${r}`)) }) }),
|
|
160
|
+
/* @__PURE__ */ t(u, { children: /* @__PURE__ */ t(
|
|
161
|
+
j,
|
|
162
|
+
{
|
|
163
|
+
type: "number",
|
|
164
|
+
min: 0,
|
|
165
|
+
step: 1,
|
|
166
|
+
value: n,
|
|
167
|
+
disabled: y,
|
|
168
|
+
onChange: (r) => h((f) => ({
|
|
169
|
+
...f,
|
|
170
|
+
[e.key]: r.target.value
|
|
171
|
+
})),
|
|
172
|
+
className: "w-28"
|
|
173
|
+
}
|
|
174
|
+
) }),
|
|
175
|
+
/* @__PURE__ */ t(u, { className: "text-right", children: /* @__PURE__ */ a("div", { className: "flex justify-end gap-2", children: [
|
|
176
|
+
/* @__PURE__ */ a(
|
|
177
|
+
b,
|
|
178
|
+
{
|
|
179
|
+
type: "button",
|
|
180
|
+
size: "sm",
|
|
181
|
+
variant: "ghost",
|
|
182
|
+
disabled: !o || y,
|
|
183
|
+
onClick: () => h((r) => ({
|
|
184
|
+
...r,
|
|
185
|
+
[e.key]: String(e.stock)
|
|
186
|
+
})),
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ t(E, { className: "mr-2 h-4 w-4" }),
|
|
189
|
+
"Reset"
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
),
|
|
193
|
+
/* @__PURE__ */ a(
|
|
194
|
+
b,
|
|
195
|
+
{
|
|
196
|
+
type: "button",
|
|
197
|
+
size: "sm",
|
|
198
|
+
disabled: !o || y,
|
|
199
|
+
onClick: () => L(e),
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ t(H, { className: "mr-2 h-4 w-4" }),
|
|
202
|
+
d ? "Saving..." : "Save"
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
] }) })
|
|
207
|
+
] }, e.key);
|
|
208
|
+
}) : /* @__PURE__ */ t(x, { children: /* @__PURE__ */ t(u, { colSpan: 7, className: "py-10 text-center text-muted-foreground", children: "No inventory rows matched your search." }) }) })
|
|
209
|
+
] }) })
|
|
210
|
+
] });
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
re as InventoryTableClient
|
|
214
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("next/cache"),m=require("@nextblock-cms/db/server"),d=require("../../../../shared-inventory.cjs.js");function p(t){const e=[];let o=[],r="",a=!1;for(let n=0;n<t.length;n+=1){const s=t[n],c=t[n+1];if(s==='"'){a&&c==='"'?(r+='"',n+=1):a=!a;continue}if(s===","&&!a){o.push(r),r="";continue}if((s===`
|
|
2
|
+
`||s==="\r")&&!a){s==="\r"&&c===`
|
|
3
|
+
`&&(n+=1),(r.length>0||o.length>0)&&(o.push(r),e.push(o)),o=[],r="";continue}r+=s}return(r.length>0||o.length>0)&&(o.push(r),e.push(o)),e.filter(n=>n.some(s=>s.trim().length>0))}function v(t){return t.sku}async function I(t){try{const e=Math.max(0,Math.trunc(t.stock));return await d.setSharedInventoryQuantity({sku:t.sku,stock:e}),u.revalidatePath("/cms/products"),u.revalidatePath("/cms/products/inventory"),{success:!0,itemKey:v(t),stock:e}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Failed to update inventory."}}}async function g(t){try{const e=p(t);if(e.length<2)return{success:!1,error:"The CSV file is empty."};const[o,...r]=e,a=o.map(i=>i.trim().toLowerCase()),n=a.indexOf("sku"),s=a.indexOf("stock");if(n===-1||s===-1)return{success:!1,error:"The CSV format is invalid. Please import a file exported from the Inventory page."};const c=m.getServiceRoleSupabaseClient();let h=0;for(const i of r){const l=(i[n]||"").trim(),f=Number.parseInt((i[s]||"").trim(),10);if(l){if(!Number.isFinite(f)||f<0)return{success:!1,error:`Invalid stock value for SKU "${l}".`};await d.setSharedInventoryQuantity({sku:l,stock:f},c),h+=1}}const y=await d.getInventoryItems(c);return u.revalidatePath("/cms/products"),u.revalidatePath("/cms/products/inventory"),{success:!0,updatedCount:h,items:y}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Failed to import inventory CSV."}}}exports.importInventoryCsvAction=g;exports.updateInventoryQuantityAction=I;
|