@propeller-commerce/propeller-v2-react-ui 0.28.0 → 0.29.0
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/CHANGELOG.md +63 -0
- package/dist/index.cjs +121 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +122 -67
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1381,9 +1381,7 @@ interface UseProductInfoReturn {
|
|
|
1381
1381
|
*
|
|
1382
1382
|
* @remarks
|
|
1383
1383
|
* GraphQL integration: services are built per-call via `createServices(graphqlClient)`.
|
|
1384
|
-
* `fetchProduct`
|
|
1385
|
-
* (`OrderlistService`, only when a user + company are present, to resolve price-tier
|
|
1386
|
-
* orderlist ids), then `services.product.getProduct()` (`ProductService`) with
|
|
1384
|
+
* `fetchProduct` calls `services.product.getProduct()` (`ProductService`) with
|
|
1387
1385
|
* `priceCalculateProductInput` / `userBulkPriceProductInput` for per-user pricing.
|
|
1388
1386
|
* `fetchCluster` runs `services.cluster.getClusterConfig()` then
|
|
1389
1387
|
* `services.cluster.getCluster()` (`ClusterService`), passing the config-derived
|
|
@@ -1918,8 +1916,8 @@ declare function useMachines(options: UseMachinesOptions): UseMachinesReturn;
|
|
|
1918
1916
|
*
|
|
1919
1917
|
* Responsibilities:
|
|
1920
1918
|
* - fetchCrossupsells: CrossupsellService with priceCalculateProductInput + extract productTo/clusterTo
|
|
1921
|
-
* - fetchProducts:
|
|
1922
|
-
*
|
|
1919
|
+
* - fetchProducts: one `category.products` batch call over `baseCategoryId`
|
|
1920
|
+
* (the flat `products` resolver ignores orderlist scoping), priced per user
|
|
1923
1921
|
* - Scroll position tracking for responsive sliding
|
|
1924
1922
|
*/
|
|
1925
1923
|
|
|
@@ -1949,6 +1947,8 @@ interface UseProductSliderOptions {
|
|
|
1949
1947
|
/** The channel's anonymous user, seeded by the host. Scopes logged-out
|
|
1950
1948
|
* listings exactly like the SSR seed does. */
|
|
1951
1949
|
anonymousUserId?: number;
|
|
1950
|
+
/** Catalog root. Required for orderlist-scoped fetching — see the remarks. */
|
|
1951
|
+
baseCategoryId?: number;
|
|
1952
1952
|
imageSearchFiltersGrid?: MediaImageProductSearchInput;
|
|
1953
1953
|
imageVariantFiltersMedium?: TransformationsInput;
|
|
1954
1954
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1381,9 +1381,7 @@ interface UseProductInfoReturn {
|
|
|
1381
1381
|
*
|
|
1382
1382
|
* @remarks
|
|
1383
1383
|
* GraphQL integration: services are built per-call via `createServices(graphqlClient)`.
|
|
1384
|
-
* `fetchProduct`
|
|
1385
|
-
* (`OrderlistService`, only when a user + company are present, to resolve price-tier
|
|
1386
|
-
* orderlist ids), then `services.product.getProduct()` (`ProductService`) with
|
|
1384
|
+
* `fetchProduct` calls `services.product.getProduct()` (`ProductService`) with
|
|
1387
1385
|
* `priceCalculateProductInput` / `userBulkPriceProductInput` for per-user pricing.
|
|
1388
1386
|
* `fetchCluster` runs `services.cluster.getClusterConfig()` then
|
|
1389
1387
|
* `services.cluster.getCluster()` (`ClusterService`), passing the config-derived
|
|
@@ -1918,8 +1916,8 @@ declare function useMachines(options: UseMachinesOptions): UseMachinesReturn;
|
|
|
1918
1916
|
*
|
|
1919
1917
|
* Responsibilities:
|
|
1920
1918
|
* - fetchCrossupsells: CrossupsellService with priceCalculateProductInput + extract productTo/clusterTo
|
|
1921
|
-
* - fetchProducts:
|
|
1922
|
-
*
|
|
1919
|
+
* - fetchProducts: one `category.products` batch call over `baseCategoryId`
|
|
1920
|
+
* (the flat `products` resolver ignores orderlist scoping), priced per user
|
|
1923
1921
|
* - Scroll position tracking for responsive sliding
|
|
1924
1922
|
*/
|
|
1925
1923
|
|
|
@@ -1949,6 +1947,8 @@ interface UseProductSliderOptions {
|
|
|
1949
1947
|
/** The channel's anonymous user, seeded by the host. Scopes logged-out
|
|
1950
1948
|
* listings exactly like the SSR seed does. */
|
|
1951
1949
|
anonymousUserId?: number;
|
|
1950
|
+
/** Catalog root. Required for orderlist-scoped fetching — see the remarks. */
|
|
1951
|
+
baseCategoryId?: number;
|
|
1952
1952
|
imageSearchFiltersGrid?: MediaImageProductSearchInput;
|
|
1953
1953
|
imageVariantFiltersMedium?: TransformationsInput;
|
|
1954
1954
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { getLabel, getLocalizedValue, formatPrice, localeForLanguage, getClusterSku, getClusterImageUrl, isContentHidden, getProductSku, getProductImageUrl, createServices, isCheckoutAllowed, err, ok, formatSurcharge, deriveUserMode, isContact, isCustomer, getAddresses, attributeNameMatches, getAttributeDisplayName, filterProductsBySelections, extractAttributeValues, buildInventoryFilter, findPurchaserPac, isOverAuthorizationLimit, MIN_STOCK_THRESHOLD, getNettedBonusItems, getLanguageString, collectAttributeValues, getCountryName, resolveLanguageEntry, getLanguageUri } from '@propeller-commerce/propeller-v2-core-ui';
|
|
2
|
+
import { getLabel, getLocalizedValue, formatPrice, localeForLanguage, getClusterSku, getClusterImageUrl, isContentHidden, getProductSku, getProductImageUrl, createServices, isCheckoutAllowed, err, ok, formatSurcharge, deriveUserMode, isContact, isCustomer, getAddresses, resolveOrderableQuantity, attributeNameMatches, getAttributeDisplayName, filterProductsBySelections, extractAttributeValues, buildInventoryFilter, findPurchaserPac, isOverAuthorizationLimit, MIN_STOCK_THRESHOLD, getNettedBonusItems, getLanguageString, collectAttributeValues, getCountryName, resolveLanguageEntry, getLanguageUri } from '@propeller-commerce/propeller-v2-core-ui';
|
|
3
3
|
export * from '@propeller-commerce/propeller-v2-core-ui';
|
|
4
4
|
import * as React6 from 'react';
|
|
5
5
|
import { createContext, useState, useContext, useRef, useCallback, useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
@@ -600,6 +600,14 @@ function useAuth(options) {
|
|
|
600
600
|
}, [graphqlClient]);
|
|
601
601
|
return { loading, error, login, magicLogin, createMagicToken, registerContact, registerCustomer, forgotPassword };
|
|
602
602
|
}
|
|
603
|
+
var CART_NOT_FOUND = "CART_NOT_FOUND_ERROR";
|
|
604
|
+
function isCartNotFound(error) {
|
|
605
|
+
const entries = error?.errors;
|
|
606
|
+
if (!Array.isArray(entries)) return false;
|
|
607
|
+
return entries.some(
|
|
608
|
+
(e) => e?.extensions?.code === CART_NOT_FOUND || /cart:?\s*\S+\s+not found/i.test(e?.message ?? "")
|
|
609
|
+
);
|
|
610
|
+
}
|
|
603
611
|
async function initCart(config) {
|
|
604
612
|
const {
|
|
605
613
|
services,
|
|
@@ -739,6 +747,11 @@ function useCart(options) {
|
|
|
739
747
|
setCreatedCartId(c.cartId);
|
|
740
748
|
cartIdRef.current = c.cartId;
|
|
741
749
|
}, []);
|
|
750
|
+
const forgetCart = useCallback(() => {
|
|
751
|
+
setCart(null);
|
|
752
|
+
setCreatedCartId("");
|
|
753
|
+
cartIdRef.current = "";
|
|
754
|
+
}, []);
|
|
742
755
|
const imageSearchFilters = useCallback(
|
|
743
756
|
() => configuration?.imageSearchFiltersGrid ?? DEFAULT_IMAGE_SEARCH_FILTERS,
|
|
744
757
|
[configuration]
|
|
@@ -822,13 +835,28 @@ function useCart(options) {
|
|
|
822
835
|
} else return err("No cart ID provided");
|
|
823
836
|
}
|
|
824
837
|
const service = createServices(graphqlClient).cart;
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
838
|
+
const input = { productId: opts.product.productId, quantity: opts.quantity, ...opts.cluster?.clusterId !== void 0 && { clusterId: opts.cluster.clusterId }, ...childItemInputs && { childItems: childItemInputs }, ...opts.notes && { notes: opts.notes }, ...opts.price !== void 0 && { price: opts.price } };
|
|
839
|
+
let resultCart;
|
|
840
|
+
try {
|
|
841
|
+
resultCart = await service.addItemToCart({
|
|
842
|
+
id: resolvedCartId,
|
|
843
|
+
input,
|
|
844
|
+
language,
|
|
845
|
+
imageSearchFilters: imageSearchFilters(),
|
|
846
|
+
imageVariantFilters: imageVariantFilters()
|
|
847
|
+
});
|
|
848
|
+
} catch (e) {
|
|
849
|
+
if (!isCartNotFound(e) || !opts.createCart) throw e;
|
|
850
|
+
forgetCart();
|
|
851
|
+
const fresh = await resolveCart();
|
|
852
|
+
resultCart = await service.addItemToCart({
|
|
853
|
+
id: fresh.cartId,
|
|
854
|
+
input,
|
|
855
|
+
language,
|
|
856
|
+
imageSearchFilters: imageSearchFilters(),
|
|
857
|
+
imageVariantFilters: imageVariantFilters()
|
|
858
|
+
});
|
|
859
|
+
}
|
|
832
860
|
rememberCart(resultCart);
|
|
833
861
|
const addedItem = resultCart.items?.find((i) => i.productId === opts.product.productId) ?? null;
|
|
834
862
|
opts.afterAddToCart?.(resultCart, addedItem);
|
|
@@ -840,7 +868,7 @@ function useCart(options) {
|
|
|
840
868
|
} finally {
|
|
841
869
|
setLoading(false);
|
|
842
870
|
}
|
|
843
|
-
}, [graphqlClient, cartId, language, configuration, resolveCart, rememberCart, imageSearchFilters, imageVariantFilters]);
|
|
871
|
+
}, [graphqlClient, cartId, language, configuration, resolveCart, rememberCart, forgetCart, imageSearchFilters, imageVariantFilters]);
|
|
844
872
|
const addItems = useCallback(async (items) => {
|
|
845
873
|
const added = [];
|
|
846
874
|
let lastCart = null;
|
|
@@ -2126,19 +2154,8 @@ function useProductInfo(options) {
|
|
|
2126
2154
|
setLoading(true);
|
|
2127
2155
|
setError(null);
|
|
2128
2156
|
try {
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
if (options.orderlistIds && options.orderlistIds.length > 0) {
|
|
2132
|
-
orderlistIds = options.orderlistIds;
|
|
2133
|
-
applyOrderlists = options.applyOrderlists !== false;
|
|
2134
|
-
} else if (options.applyOrderlists === false) {
|
|
2135
|
-
applyOrderlists = false;
|
|
2136
|
-
} else if (options.user && options.companyId) {
|
|
2137
|
-
const orderlistService = createServices(graphqlClient).orderlist;
|
|
2138
|
-
const searchInput = { companyIds: [options.companyId] };
|
|
2139
|
-
const orderlists = await orderlistService.getOrderlists(searchInput);
|
|
2140
|
-
orderlistIds = (orderlists?.items ?? []).map((ol) => ol.id);
|
|
2141
|
-
}
|
|
2157
|
+
const orderlistIds = options.orderlistIds ?? [];
|
|
2158
|
+
const applyOrderlists = options.applyOrderlists !== false;
|
|
2142
2159
|
const service = createServices(graphqlClient).product;
|
|
2143
2160
|
const attributeInput = buildAttributeInput2();
|
|
2144
2161
|
const variables = {
|
|
@@ -2349,7 +2366,7 @@ function useProductSearch(options) {
|
|
|
2349
2366
|
const orderlistScope = options.orderlistIds && options.orderlistIds.length > 0 ? {
|
|
2350
2367
|
applyOrderlists: options.applyOrderlists !== false,
|
|
2351
2368
|
orderlistIds: options.orderlistIds
|
|
2352
|
-
} : { applyOrderlists: false };
|
|
2369
|
+
} : options.applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2353
2370
|
const categoryProductSearchInput = {
|
|
2354
2371
|
language: lang,
|
|
2355
2372
|
page: pagination.currentPage,
|
|
@@ -2479,7 +2496,7 @@ function useProductSearch(options) {
|
|
|
2479
2496
|
const orderlistScope = options.orderlistIds && options.orderlistIds.length > 0 ? {
|
|
2480
2497
|
applyOrderlists: options.applyOrderlists !== false,
|
|
2481
2498
|
orderlistIds: options.orderlistIds
|
|
2482
|
-
} : { applyOrderlists: false };
|
|
2499
|
+
} : options.applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2483
2500
|
const userId = resolveListingUserId(options.user, configuration);
|
|
2484
2501
|
const contactId = options.user && "contactId" in options.user ? options.user.contactId : void 0;
|
|
2485
2502
|
const customerId = options.user && "customerId" in options.user ? options.user.customerId : void 0;
|
|
@@ -2655,7 +2672,7 @@ function useQuickOrder(options) {
|
|
|
2655
2672
|
if (!catId) return [];
|
|
2656
2673
|
try {
|
|
2657
2674
|
const service = createServices(graphqlClient).category;
|
|
2658
|
-
const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : { applyOrderlists: false };
|
|
2675
|
+
const orderlistScope = orderlistIds && orderlistIds.length > 0 ? { applyOrderlists: applyOrderlists !== false, orderlistIds } : applyOrderlists === false ? { applyOrderlists: false } : {};
|
|
2659
2676
|
const userId = resolveListingUserId(user, configuration);
|
|
2660
2677
|
const contactId = user && "contactId" in user ? user.contactId : void 0;
|
|
2661
2678
|
const customerId = user && "customerId" in user ? user.customerId : void 0;
|
|
@@ -3264,28 +3281,33 @@ function useProductSlider(options) {
|
|
|
3264
3281
|
}
|
|
3265
3282
|
}
|
|
3266
3283
|
if (!productIds.length && !clusterIds.length) return items;
|
|
3284
|
+
const catId = configuration.baseCategoryId;
|
|
3285
|
+
if (!catId) return items;
|
|
3267
3286
|
const userId = resolveUserId();
|
|
3268
3287
|
const companyId = resolveCompanyId();
|
|
3269
|
-
const
|
|
3288
|
+
const categoryProductSearchInput = {
|
|
3270
3289
|
...productIds.length && { productIds },
|
|
3271
3290
|
...clusterIds.length && { clusterIds },
|
|
3272
3291
|
language,
|
|
3273
3292
|
page: 1,
|
|
3274
3293
|
offset: 50,
|
|
3275
3294
|
statuses: [ProductStatus.A, ProductStatus.P, ProductStatus.T, ProductStatus.S],
|
|
3295
|
+
hidden: false,
|
|
3276
3296
|
...userId !== void 0 && { userId },
|
|
3277
3297
|
...companyId !== void 0 && { companyId }
|
|
3278
3298
|
};
|
|
3279
3299
|
const filterAvailableAttributeInput = { isSearchable: true };
|
|
3280
3300
|
const variables = {
|
|
3281
|
-
|
|
3301
|
+
categoryId: catId,
|
|
3302
|
+
language,
|
|
3303
|
+
categoryProductSearchInput,
|
|
3304
|
+
filterAvailableAttributeInput,
|
|
3282
3305
|
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
3283
|
-
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3284
|
-
filterAvailableAttributeInput
|
|
3306
|
+
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3285
3307
|
};
|
|
3286
3308
|
try {
|
|
3287
|
-
const response = await createServices(graphqlClient).
|
|
3288
|
-
const resolved = response?.items ?? [];
|
|
3309
|
+
const response = await createServices(graphqlClient).category.getCategory(variables);
|
|
3310
|
+
const resolved = response?.products?.items ?? [];
|
|
3289
3311
|
const allowed = /* @__PURE__ */ new Set();
|
|
3290
3312
|
for (const r of resolved) {
|
|
3291
3313
|
const id = r.productId ?? r.clusterId;
|
|
@@ -3341,10 +3363,17 @@ function useProductSlider(options) {
|
|
|
3341
3363
|
setLoading(true);
|
|
3342
3364
|
setError(null);
|
|
3343
3365
|
try {
|
|
3344
|
-
const
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3366
|
+
const catId = configuration.baseCategoryId;
|
|
3367
|
+
if (!catId) {
|
|
3368
|
+
setProducts([]);
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3371
|
+
const service = createServices(graphqlClient).category;
|
|
3372
|
+
const userId = resolveUserId();
|
|
3373
|
+
const companyId = resolveCompanyId();
|
|
3374
|
+
const categoryProductSearchInput = {
|
|
3375
|
+
...productIds.length && { productIds },
|
|
3376
|
+
...clusterIds.length && { clusterIds },
|
|
3348
3377
|
language,
|
|
3349
3378
|
page: 1,
|
|
3350
3379
|
offset: 50,
|
|
@@ -3353,17 +3382,24 @@ function useProductSlider(options) {
|
|
|
3353
3382
|
ProductStatus.P,
|
|
3354
3383
|
ProductStatus.T,
|
|
3355
3384
|
ProductStatus.S
|
|
3356
|
-
]
|
|
3385
|
+
],
|
|
3386
|
+
hidden: false,
|
|
3387
|
+
...userId !== void 0 && { userId },
|
|
3388
|
+
...companyId !== void 0 && { companyId }
|
|
3357
3389
|
};
|
|
3358
3390
|
const filterAvailableAttributeInput = { isSearchable: true };
|
|
3359
3391
|
const variables = {
|
|
3360
|
-
|
|
3392
|
+
categoryId: catId,
|
|
3393
|
+
language,
|
|
3394
|
+
categoryProductSearchInput,
|
|
3395
|
+
priceCalculateProductInput: buildPriceInput(),
|
|
3396
|
+
filterAvailableAttributeInput,
|
|
3361
3397
|
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
3362
|
-
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3363
|
-
filterAvailableAttributeInput
|
|
3398
|
+
imageVariantFilters: configuration.imageVariantFiltersMedium
|
|
3364
3399
|
};
|
|
3365
|
-
const response = await service.
|
|
3366
|
-
|
|
3400
|
+
const response = await service.getCategory(variables);
|
|
3401
|
+
const productsResponse = response?.products;
|
|
3402
|
+
setProducts(productsResponse?.items ?? []);
|
|
3367
3403
|
} catch (e) {
|
|
3368
3404
|
setError(e instanceof Error ? e.message : "Failed to fetch products");
|
|
3369
3405
|
setProducts([]);
|
|
@@ -4807,10 +4843,7 @@ function AddToCart(rawProps) {
|
|
|
4807
4843
|
setToastVisible(false);
|
|
4808
4844
|
}
|
|
4809
4845
|
function snapQuantity(value) {
|
|
4810
|
-
|
|
4811
|
-
const step = getStep(props.product);
|
|
4812
|
-
if (value <= min) return min;
|
|
4813
|
-
return Math.round((value - min) / step) * step + min;
|
|
4846
|
+
return resolveOrderableQuantity(value, getMinQuantity(props.product), getStep(props.product));
|
|
4814
4847
|
}
|
|
4815
4848
|
function increment() {
|
|
4816
4849
|
setQuantityDraft(null);
|
|
@@ -6919,6 +6952,7 @@ function CartItem(rawProps) {
|
|
|
6919
6952
|
companyId: props.companyId
|
|
6920
6953
|
});
|
|
6921
6954
|
const [quantity, setQuantity] = useState(() => props.cartItem.quantity || 1);
|
|
6955
|
+
const [quantityDraft, setQuantityDraft] = useState(() => null);
|
|
6922
6956
|
const [notes, setNotes] = useState(() => props.cartItem.notes || "");
|
|
6923
6957
|
const [loading, setLoading] = useState(() => false);
|
|
6924
6958
|
const [deleting, setDeleting] = useState(() => false);
|
|
@@ -7042,6 +7076,34 @@ function CartItem(rawProps) {
|
|
|
7042
7076
|
setLoading(false);
|
|
7043
7077
|
}
|
|
7044
7078
|
}
|
|
7079
|
+
function handleQuantityDecrement() {
|
|
7080
|
+
setQuantityDraft(null);
|
|
7081
|
+
const orderable = resolveOrderableQuantity(quantity, minQuantity, step);
|
|
7082
|
+
if (orderable !== quantity) {
|
|
7083
|
+
handleQuantityChange(orderable);
|
|
7084
|
+
return;
|
|
7085
|
+
}
|
|
7086
|
+
if (quantity - step >= minQuantity) handleQuantityChange(quantity - step);
|
|
7087
|
+
}
|
|
7088
|
+
function handleQuantityIncrement() {
|
|
7089
|
+
setQuantityDraft(null);
|
|
7090
|
+
const orderable = resolveOrderableQuantity(quantity, minQuantity, step);
|
|
7091
|
+
handleQuantityChange(orderable === quantity ? quantity + step : orderable);
|
|
7092
|
+
}
|
|
7093
|
+
function handleQuantityInput(raw) {
|
|
7094
|
+
setQuantityDraft(raw);
|
|
7095
|
+
const val = parseInt(raw, 10);
|
|
7096
|
+
if (!isNaN(val) && val >= minQuantity) {
|
|
7097
|
+
handleQuantityChange(resolveOrderableQuantity(val, minQuantity, step));
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
function handleQuantityBlur() {
|
|
7101
|
+
if (quantityDraft === null) return;
|
|
7102
|
+
const val = parseInt(quantityDraft, 10);
|
|
7103
|
+
setQuantityDraft(null);
|
|
7104
|
+
const orderable = resolveOrderableQuantity(val, minQuantity, step);
|
|
7105
|
+
if (orderable !== quantity) handleQuantityChange(orderable);
|
|
7106
|
+
}
|
|
7045
7107
|
function handleNoteChange(note) {
|
|
7046
7108
|
setNotes(note);
|
|
7047
7109
|
if (props.onNoteChange) {
|
|
@@ -7144,7 +7206,8 @@ function CartItem(rawProps) {
|
|
|
7144
7206
|
deleting,
|
|
7145
7207
|
crossupsells,
|
|
7146
7208
|
visibleCrossupsells: getVisibleCrossupsells(),
|
|
7147
|
-
addingCrossupsellId
|
|
7209
|
+
addingCrossupsellId,
|
|
7210
|
+
quantityDraft
|
|
7148
7211
|
},
|
|
7149
7212
|
helpers: {
|
|
7150
7213
|
getBundleItemName,
|
|
@@ -7157,6 +7220,10 @@ function CartItem(rawProps) {
|
|
|
7157
7220
|
},
|
|
7158
7221
|
handlers: {
|
|
7159
7222
|
onQuantityChange: handleQuantityChange,
|
|
7223
|
+
onQuantityDecrement: handleQuantityDecrement,
|
|
7224
|
+
onQuantityIncrement: handleQuantityIncrement,
|
|
7225
|
+
onQuantityInput: handleQuantityInput,
|
|
7226
|
+
onQuantityBlur: handleQuantityBlur,
|
|
7160
7227
|
onNoteChange: handleNoteChange,
|
|
7161
7228
|
onDelete: handleDelete,
|
|
7162
7229
|
onTitleClick: (e) => props.onTitleClick?.(e, props.cartItem),
|
|
@@ -7471,7 +7538,7 @@ function CartItemQuantity(props = {}) {
|
|
|
7471
7538
|
{
|
|
7472
7539
|
type: "button",
|
|
7473
7540
|
className: "propeller-cart-item__decrement px-2.5 h-full text-muted-foreground hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors rounded-l-control select-none",
|
|
7474
|
-
onClick:
|
|
7541
|
+
onClick: handlers.onQuantityDecrement,
|
|
7475
7542
|
disabled: derived.quantity <= derived.minQuantity || state.loading,
|
|
7476
7543
|
children: "-"
|
|
7477
7544
|
}
|
|
@@ -7483,13 +7550,9 @@ function CartItemQuantity(props = {}) {
|
|
|
7483
7550
|
className: "propeller-cart-item__quantity w-10 text-center text-sm bg-transparent border-x border-input h-full focus:ring-0 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
7484
7551
|
min: derived.minQuantity,
|
|
7485
7552
|
step: derived.step,
|
|
7486
|
-
value: derived.quantity,
|
|
7487
|
-
onChange: (e) =>
|
|
7488
|
-
|
|
7489
|
-
if (!isNaN(val) && val >= derived.minQuantity) {
|
|
7490
|
-
handlers.onQuantityChange(Math.round((val - derived.minQuantity) / derived.step) * derived.step + derived.minQuantity);
|
|
7491
|
-
}
|
|
7492
|
-
}
|
|
7553
|
+
value: state.quantityDraft ?? derived.quantity,
|
|
7554
|
+
onChange: (e) => handlers.onQuantityInput(e.target.value),
|
|
7555
|
+
onBlur: handlers.onQuantityBlur
|
|
7493
7556
|
}
|
|
7494
7557
|
),
|
|
7495
7558
|
/* @__PURE__ */ jsx(
|
|
@@ -7497,7 +7560,7 @@ function CartItemQuantity(props = {}) {
|
|
|
7497
7560
|
{
|
|
7498
7561
|
type: "button",
|
|
7499
7562
|
className: "propeller-cart-item__increment px-2.5 h-full text-muted-foreground hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors rounded-r-control select-none",
|
|
7500
|
-
onClick:
|
|
7563
|
+
onClick: handlers.onQuantityIncrement,
|
|
7501
7564
|
disabled: state.loading,
|
|
7502
7565
|
children: "+"
|
|
7503
7566
|
}
|
|
@@ -7511,13 +7574,9 @@ function CartItemQuantity(props = {}) {
|
|
|
7511
7574
|
className: props.className ?? "propeller-cart-item__quantity w-14 h-9 text-center text-sm border border-input rounded-control focus:ring-2 focus:ring-primary focus:border-transparent [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
7512
7575
|
min: derived.minQuantity,
|
|
7513
7576
|
step: derived.step,
|
|
7514
|
-
value: derived.quantity,
|
|
7515
|
-
onChange: (e) =>
|
|
7516
|
-
|
|
7517
|
-
if (!isNaN(val) && val >= derived.minQuantity) {
|
|
7518
|
-
handlers.onQuantityChange(Math.round((val - derived.minQuantity) / derived.step) * derived.step + derived.minQuantity);
|
|
7519
|
-
}
|
|
7520
|
-
}
|
|
7577
|
+
value: state.quantityDraft ?? derived.quantity,
|
|
7578
|
+
onChange: (e) => handlers.onQuantityInput(e.target.value),
|
|
7579
|
+
onBlur: handlers.onQuantityBlur
|
|
7521
7580
|
}
|
|
7522
7581
|
);
|
|
7523
7582
|
}
|
|
@@ -14775,10 +14834,6 @@ function RequestPriceButton(props) {
|
|
|
14775
14834
|
}
|
|
14776
14835
|
var RequestPriceButton_default = RequestPriceButton;
|
|
14777
14836
|
var ROW_SEQ = 0;
|
|
14778
|
-
function snapToStep(value, min, step) {
|
|
14779
|
-
if (!Number.isFinite(value) || value <= min) return min;
|
|
14780
|
-
return Math.round((value - min) / (step || 1)) * (step || 1) + min;
|
|
14781
|
-
}
|
|
14782
14837
|
function blankRow() {
|
|
14783
14838
|
ROW_SEQ += 1;
|
|
14784
14839
|
return {
|
|
@@ -14898,7 +14953,7 @@ function QuickOrderInner(props) {
|
|
|
14898
14953
|
const n = parseInt(raw, 10);
|
|
14899
14954
|
setRows(
|
|
14900
14955
|
(prev) => prev.map(
|
|
14901
|
-
(r) => r.key === key ? { ...r, quantity:
|
|
14956
|
+
(r) => r.key === key ? { ...r, quantity: resolveOrderableQuantity(n, r.minQuantity, r.step) } : r
|
|
14902
14957
|
)
|
|
14903
14958
|
);
|
|
14904
14959
|
},
|