@propeller-commerce/propeller-v2-react-ui 0.6.1 → 0.7.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/CHANGELOG.md +47 -0
- package/dist/index.cjs +523 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -1
- package/dist/index.d.ts +202 -1
- package/dist/index.js +522 -67
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -888,6 +888,25 @@ function useCart(options) {
|
|
|
888
888
|
}, [graphqlClient, language, configuration, user]);
|
|
889
889
|
return { cart, cartId, loading, error, checkoutAllowed, resolveCart, addItem, updateItemQuantity, updateItemNotes, deleteItem, addActionCode, removeActionCode, requestAuthorization, processCart, getCrossupsells, getMinQuantity, getStep };
|
|
890
890
|
}
|
|
891
|
+
function buildAddressInput(type, addr) {
|
|
892
|
+
return {
|
|
893
|
+
type,
|
|
894
|
+
firstName: addr.firstName || "",
|
|
895
|
+
lastName: addr.lastName || "",
|
|
896
|
+
street: addr.street || "",
|
|
897
|
+
postalCode: addr.postalCode || "",
|
|
898
|
+
city: addr.city || "",
|
|
899
|
+
...addr.company && { company: addr.company },
|
|
900
|
+
...addr.gender && { gender: addr.gender },
|
|
901
|
+
...addr.middleName && { middleName: addr.middleName },
|
|
902
|
+
...addr.number && { number: addr.number },
|
|
903
|
+
...addr.numberExtension && { numberExtension: addr.numberExtension },
|
|
904
|
+
...addr.country && { country: addr.country },
|
|
905
|
+
...addr.email && { email: addr.email },
|
|
906
|
+
...addr.mobile && { mobile: addr.mobile },
|
|
907
|
+
...addr.phone && { phone: addr.phone }
|
|
908
|
+
};
|
|
909
|
+
}
|
|
891
910
|
function useCheckout(options) {
|
|
892
911
|
const { graphqlClient, user, companyId } = options;
|
|
893
912
|
const language = options.language ?? "NL";
|
|
@@ -928,26 +947,9 @@ function useCheckout(options) {
|
|
|
928
947
|
if (!hasInvoice) {
|
|
929
948
|
const defaultInvoice = getUserDefaultAddress("invoice");
|
|
930
949
|
if (defaultInvoice) {
|
|
931
|
-
const input = {
|
|
932
|
-
type: propellerSdkV2.CartAddressType.INVOICE,
|
|
933
|
-
firstName: defaultInvoice.firstName || "",
|
|
934
|
-
lastName: defaultInvoice.lastName || "",
|
|
935
|
-
street: defaultInvoice.street || "",
|
|
936
|
-
postalCode: defaultInvoice.postalCode || "",
|
|
937
|
-
city: defaultInvoice.city || "",
|
|
938
|
-
company: defaultInvoice.company,
|
|
939
|
-
gender: defaultInvoice.gender,
|
|
940
|
-
middleName: defaultInvoice.middleName,
|
|
941
|
-
number: defaultInvoice.number,
|
|
942
|
-
numberExtension: defaultInvoice.numberExtension,
|
|
943
|
-
country: defaultInvoice.country,
|
|
944
|
-
email: defaultInvoice.email,
|
|
945
|
-
mobile: defaultInvoice.mobile,
|
|
946
|
-
phone: defaultInvoice.phone
|
|
947
|
-
};
|
|
948
950
|
updatedCart = await cartService.updateCartAddress({
|
|
949
951
|
id: updatedCart.cartId,
|
|
950
|
-
input,
|
|
952
|
+
input: buildAddressInput(propellerSdkV2.CartAddressType.INVOICE, defaultInvoice),
|
|
951
953
|
imageVariantFilters,
|
|
952
954
|
imageSearchFilters,
|
|
953
955
|
language
|
|
@@ -957,26 +959,9 @@ function useCheckout(options) {
|
|
|
957
959
|
if (!hasDelivery) {
|
|
958
960
|
const defaultDelivery = getUserDefaultAddress("delivery");
|
|
959
961
|
if (defaultDelivery) {
|
|
960
|
-
const input = {
|
|
961
|
-
type: propellerSdkV2.CartAddressType.DELIVERY,
|
|
962
|
-
firstName: defaultDelivery.firstName || "",
|
|
963
|
-
lastName: defaultDelivery.lastName || "",
|
|
964
|
-
street: defaultDelivery.street || "",
|
|
965
|
-
postalCode: defaultDelivery.postalCode || "",
|
|
966
|
-
city: defaultDelivery.city || "",
|
|
967
|
-
company: defaultDelivery.company,
|
|
968
|
-
gender: defaultDelivery.gender,
|
|
969
|
-
middleName: defaultDelivery.middleName,
|
|
970
|
-
number: defaultDelivery.number,
|
|
971
|
-
numberExtension: defaultDelivery.numberExtension,
|
|
972
|
-
country: defaultDelivery.country,
|
|
973
|
-
email: defaultDelivery.email,
|
|
974
|
-
mobile: defaultDelivery.mobile,
|
|
975
|
-
phone: defaultDelivery.phone
|
|
976
|
-
};
|
|
977
962
|
updatedCart = await cartService.updateCartAddress({
|
|
978
963
|
id: updatedCart.cartId,
|
|
979
|
-
input,
|
|
964
|
+
input: buildAddressInput(propellerSdkV2.CartAddressType.DELIVERY, defaultDelivery),
|
|
980
965
|
imageVariantFilters,
|
|
981
966
|
imageSearchFilters,
|
|
982
967
|
language
|
|
@@ -2498,6 +2483,140 @@ function useProductSearch(options) {
|
|
|
2498
2483
|
goToPage: pagination.goToPage
|
|
2499
2484
|
};
|
|
2500
2485
|
}
|
|
2486
|
+
function toMatch(item, language) {
|
|
2487
|
+
const isCluster = "clusterId" in item;
|
|
2488
|
+
const displayItem = isCluster ? item.defaultProduct : item;
|
|
2489
|
+
const productId = displayItem?.productId ?? item.productId;
|
|
2490
|
+
const clusterId = isCluster ? item.clusterId : void 0;
|
|
2491
|
+
const name = language && item.names?.find((n) => n.language === language)?.value || item.names?.[0]?.value || "Product";
|
|
2492
|
+
const netPrice = displayItem?.price?.net ?? 0;
|
|
2493
|
+
const grossPrice = displayItem?.price?.gross ?? 0;
|
|
2494
|
+
const minQuantity = Math.max(1, displayItem?.minimumQuantity ?? 1);
|
|
2495
|
+
const imageUrl = isCluster ? propellerV2CoreUi.getClusterImageUrl(item) : propellerV2CoreUi.getProductImageUrl(item);
|
|
2496
|
+
return {
|
|
2497
|
+
productId,
|
|
2498
|
+
clusterId,
|
|
2499
|
+
name,
|
|
2500
|
+
sku: item.sku || displayItem?.sku || "",
|
|
2501
|
+
netPrice,
|
|
2502
|
+
grossPrice,
|
|
2503
|
+
minQuantity,
|
|
2504
|
+
imageUrl
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
function useQuickOrder(options) {
|
|
2508
|
+
const {
|
|
2509
|
+
graphqlClient,
|
|
2510
|
+
user,
|
|
2511
|
+
companyId,
|
|
2512
|
+
configuration = {},
|
|
2513
|
+
onCartCreated,
|
|
2514
|
+
afterAddToCart
|
|
2515
|
+
} = options;
|
|
2516
|
+
const language = options.language || "NL";
|
|
2517
|
+
const searchLimit = options.searchLimit ?? 8;
|
|
2518
|
+
const [submitting, setSubmitting] = React6.useState(false);
|
|
2519
|
+
const [error, setError] = React6.useState(null);
|
|
2520
|
+
const searchProducts = React6.useCallback(
|
|
2521
|
+
async (term) => {
|
|
2522
|
+
const trimmed = term.trim();
|
|
2523
|
+
if (!trimmed || !graphqlClient) return [];
|
|
2524
|
+
try {
|
|
2525
|
+
const service = propellerV2CoreUi.createServices(graphqlClient).product;
|
|
2526
|
+
const input = {
|
|
2527
|
+
term: trimmed,
|
|
2528
|
+
language,
|
|
2529
|
+
page: 1,
|
|
2530
|
+
offset: searchLimit,
|
|
2531
|
+
statuses: [propellerSdkV2.ProductStatus.A, propellerSdkV2.ProductStatus.P, propellerSdkV2.ProductStatus.T, propellerSdkV2.ProductStatus.S],
|
|
2532
|
+
sortInputs: [{ field: propellerSdkV2.ProductSortField.RELEVANCE, order: propellerSdkV2.SortOrder.DESC }],
|
|
2533
|
+
searchFields: [
|
|
2534
|
+
{
|
|
2535
|
+
fieldNames: [
|
|
2536
|
+
propellerSdkV2.ProductSearchableField.SKU,
|
|
2537
|
+
propellerSdkV2.ProductSearchableField.NAME,
|
|
2538
|
+
propellerSdkV2.ProductSearchableField.KEYWORDS,
|
|
2539
|
+
propellerSdkV2.ProductSearchableField.CUSTOM_KEYWORDS
|
|
2540
|
+
],
|
|
2541
|
+
boost: 5
|
|
2542
|
+
},
|
|
2543
|
+
{
|
|
2544
|
+
fieldNames: [
|
|
2545
|
+
propellerSdkV2.ProductSearchableField.MANUFACTURER_CODE,
|
|
2546
|
+
propellerSdkV2.ProductSearchableField.EAN_CODE,
|
|
2547
|
+
propellerSdkV2.ProductSearchableField.BAR_CODE,
|
|
2548
|
+
propellerSdkV2.ProductSearchableField.SUPPLIER_CODE,
|
|
2549
|
+
propellerSdkV2.ProductSearchableField.PRODUCT_ID
|
|
2550
|
+
],
|
|
2551
|
+
boost: 1
|
|
2552
|
+
}
|
|
2553
|
+
]
|
|
2554
|
+
};
|
|
2555
|
+
const variables = {
|
|
2556
|
+
input,
|
|
2557
|
+
language,
|
|
2558
|
+
imageVariantFilters: configuration.imageVariantFiltersSmall
|
|
2559
|
+
};
|
|
2560
|
+
const result = await service.getProducts(variables);
|
|
2561
|
+
const items = result?.items ?? [];
|
|
2562
|
+
return items.map((it) => toMatch(it, language));
|
|
2563
|
+
} catch {
|
|
2564
|
+
return [];
|
|
2565
|
+
}
|
|
2566
|
+
},
|
|
2567
|
+
[graphqlClient, language, searchLimit, configuration]
|
|
2568
|
+
);
|
|
2569
|
+
const submit = React6.useCallback(
|
|
2570
|
+
async (lines) => {
|
|
2571
|
+
const valid = lines.filter((l) => l.productId && (l.quantity ?? 0) > 0);
|
|
2572
|
+
if (!valid.length) return { success: false, error: "No items to add" };
|
|
2573
|
+
if (!graphqlClient) return { success: false, error: "No GraphQL client" };
|
|
2574
|
+
setSubmitting(true);
|
|
2575
|
+
setError(null);
|
|
2576
|
+
try {
|
|
2577
|
+
const services = propellerV2CoreUi.createServices(graphqlClient);
|
|
2578
|
+
const cart = await initCart({
|
|
2579
|
+
services,
|
|
2580
|
+
user: user ?? null,
|
|
2581
|
+
companyId,
|
|
2582
|
+
language,
|
|
2583
|
+
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
2584
|
+
imageVariantFilters: configuration.imageVariantFiltersSmall,
|
|
2585
|
+
onCartCreated
|
|
2586
|
+
});
|
|
2587
|
+
const items = valid.map((l) => ({
|
|
2588
|
+
productId: l.productId,
|
|
2589
|
+
quantity: l.quantity,
|
|
2590
|
+
...l.clusterId ? { clusterId: l.clusterId } : {}
|
|
2591
|
+
}));
|
|
2592
|
+
const bulk = await services.cart.bulkUpdateCartItems({
|
|
2593
|
+
input: { cartId: cart.cartId, items }
|
|
2594
|
+
});
|
|
2595
|
+
const updated = await services.cart.getCart({
|
|
2596
|
+
cartId: cart.cartId,
|
|
2597
|
+
language,
|
|
2598
|
+
imageSearchFilters: configuration.imageSearchFiltersGrid,
|
|
2599
|
+
imageVariantFilters: configuration.imageVariantFiltersSmall
|
|
2600
|
+
});
|
|
2601
|
+
const finalCart = updated ?? cart;
|
|
2602
|
+
afterAddToCart?.(finalCart);
|
|
2603
|
+
return {
|
|
2604
|
+
success: true,
|
|
2605
|
+
cart: finalCart,
|
|
2606
|
+
added: (bulk?.created ?? 0) + (bulk?.updated ?? 0)
|
|
2607
|
+
};
|
|
2608
|
+
} catch (e) {
|
|
2609
|
+
const msg = e instanceof Error ? e.message : "Failed to add items to cart";
|
|
2610
|
+
setError(msg);
|
|
2611
|
+
return { success: false, error: msg };
|
|
2612
|
+
} finally {
|
|
2613
|
+
setSubmitting(false);
|
|
2614
|
+
}
|
|
2615
|
+
},
|
|
2616
|
+
[graphqlClient, user, companyId, language, configuration, onCartCreated, afterAddToCart]
|
|
2617
|
+
);
|
|
2618
|
+
return { submitting, error, searchProducts, submit };
|
|
2619
|
+
}
|
|
2501
2620
|
var inflightFetches3 = /* @__PURE__ */ new Set();
|
|
2502
2621
|
var STOREFRONT_STATUSES = [
|
|
2503
2622
|
propellerSdkV2.ProductStatus.A,
|
|
@@ -4931,6 +5050,7 @@ function AddToFavorite(rawProps) {
|
|
|
4931
5050
|
] }) }) : null });
|
|
4932
5051
|
}
|
|
4933
5052
|
var AddToFavorite_default = AddToFavorite;
|
|
5053
|
+
var EMAIL_PATTERN = "[^@\\s]+@[^@\\s.]+(?:\\.[^@\\s.]+)*\\.[A-Za-z]{2,}";
|
|
4934
5054
|
var AddressCardContext = React6__namespace.createContext(null);
|
|
4935
5055
|
function useAddressCardContext() {
|
|
4936
5056
|
const ctx = React6__namespace.useContext(AddressCardContext);
|
|
@@ -5376,10 +5496,7 @@ function AddressCard(rawProps) {
|
|
|
5376
5496
|
] }),
|
|
5377
5497
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
5378
5498
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5379
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5380
|
-
propellerV2CoreUi.getLabel(props.labels, "email", "Email"),
|
|
5381
|
-
" *"
|
|
5382
|
-
] }),
|
|
5499
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium mb-1", children: propellerV2CoreUi.getLabel(props.labels, "email", "Email") }),
|
|
5383
5500
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5384
5501
|
"input",
|
|
5385
5502
|
{
|
|
@@ -5389,7 +5506,7 @@ function AddressCard(rawProps) {
|
|
|
5389
5506
|
onChange: (e) => {
|
|
5390
5507
|
setEditEmail(e.target.value);
|
|
5391
5508
|
},
|
|
5392
|
-
|
|
5509
|
+
pattern: EMAIL_PATTERN
|
|
5393
5510
|
}
|
|
5394
5511
|
)
|
|
5395
5512
|
] }),
|
|
@@ -5669,10 +5786,7 @@ function AddressCard(rawProps) {
|
|
|
5669
5786
|
] }),
|
|
5670
5787
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
5671
5788
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5672
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5673
|
-
propellerV2CoreUi.getLabel(props.labels, "email", "Email"),
|
|
5674
|
-
" *"
|
|
5675
|
-
] }),
|
|
5789
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium mb-1", children: propellerV2CoreUi.getLabel(props.labels, "email", "Email") }),
|
|
5676
5790
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5677
5791
|
"input",
|
|
5678
5792
|
{
|
|
@@ -5682,7 +5796,7 @@ function AddressCard(rawProps) {
|
|
|
5682
5796
|
onChange: (e) => {
|
|
5683
5797
|
setEditEmail(e.target.value);
|
|
5684
5798
|
},
|
|
5685
|
-
|
|
5799
|
+
pattern: EMAIL_PATTERN
|
|
5686
5800
|
}
|
|
5687
5801
|
)
|
|
5688
5802
|
] }),
|
|
@@ -6385,7 +6499,7 @@ function CartItem(rawProps) {
|
|
|
6385
6499
|
}
|
|
6386
6500
|
return "#";
|
|
6387
6501
|
}
|
|
6388
|
-
function
|
|
6502
|
+
function getProductImageUrl6() {
|
|
6389
6503
|
return props.cartItem.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
|
|
6390
6504
|
}
|
|
6391
6505
|
function getProductSku3() {
|
|
@@ -6569,7 +6683,7 @@ function CartItem(rawProps) {
|
|
|
6569
6683
|
derived: {
|
|
6570
6684
|
name: getProductName5(),
|
|
6571
6685
|
sku: getProductSku3(),
|
|
6572
|
-
imageUrl:
|
|
6686
|
+
imageUrl: getProductImageUrl6(),
|
|
6573
6687
|
productUrl: getProductUrl2(),
|
|
6574
6688
|
isBundle: isBundleItem(),
|
|
6575
6689
|
bundleName: getBundleName(),
|
|
@@ -9543,7 +9657,7 @@ function GridToolbar(rawProps) {
|
|
|
9543
9657
|
const [currentSortOrder, setCurrentSortOrder] = React6.useState(propellerSdkV2.SortOrder.DESC);
|
|
9544
9658
|
const [currentOffset, setCurrentOffset] = React6.useState(12);
|
|
9545
9659
|
const [currentViewMode, setCurrentViewMode] = React6.useState("grid");
|
|
9546
|
-
function
|
|
9660
|
+
function getLabel55(key) {
|
|
9547
9661
|
const labels = props.labels || {};
|
|
9548
9662
|
return labels[key] !== void 0 ? labels[key] : DEFAULT_LABELS[key] || key;
|
|
9549
9663
|
}
|
|
@@ -9622,7 +9736,7 @@ function GridToolbar(rawProps) {
|
|
|
9622
9736
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-grid-toolbar__count text-sm text-muted-foreground font-medium", children: props.itemsFound > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
9623
9737
|
props.itemsFound,
|
|
9624
9738
|
"\xA0",
|
|
9625
|
-
props.itemsFound === 1 ?
|
|
9739
|
+
props.itemsFound === 1 ? getLabel55("productSingular") : getLabel55("productPlural")
|
|
9626
9740
|
] }) : null }),
|
|
9627
9741
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-grid-toolbar__controls flex flex-wrap items-center gap-3", children: [
|
|
9628
9742
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -9633,7 +9747,7 @@ function GridToolbar(rawProps) {
|
|
|
9633
9747
|
onChange: (e) => handleOffsetChange(parseInt(e.target.value)),
|
|
9634
9748
|
children: getOffsetOptions()?.map((n) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: n, children: [
|
|
9635
9749
|
n,
|
|
9636
|
-
|
|
9750
|
+
getLabel55("perPage")
|
|
9637
9751
|
] }, n))
|
|
9638
9752
|
}
|
|
9639
9753
|
),
|
|
@@ -9649,7 +9763,7 @@ function GridToolbar(rawProps) {
|
|
|
9649
9763
|
{
|
|
9650
9764
|
value: field,
|
|
9651
9765
|
disabled: field === "PRICE" && isPriceSortDisabled(),
|
|
9652
|
-
children:
|
|
9766
|
+
children: getLabel55(field)
|
|
9653
9767
|
},
|
|
9654
9768
|
field
|
|
9655
9769
|
))
|
|
@@ -9662,8 +9776,8 @@ function GridToolbar(rawProps) {
|
|
|
9662
9776
|
value: currentSortOrder,
|
|
9663
9777
|
onChange: (e) => handleSortOrderChange(e.target.value),
|
|
9664
9778
|
children: [
|
|
9665
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.ASC, children:
|
|
9666
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.DESC, children:
|
|
9779
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.ASC, children: getLabel55("ASC") }),
|
|
9780
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: propellerSdkV2.SortOrder.DESC, children: getLabel55("DESC") })
|
|
9667
9781
|
]
|
|
9668
9782
|
}
|
|
9669
9783
|
),
|
|
@@ -9673,7 +9787,7 @@ function GridToolbar(rawProps) {
|
|
|
9673
9787
|
type: "button",
|
|
9674
9788
|
className: "propeller-grid-toolbar__view-toggle h-9 w-9 flex items-center justify-center rounded-control border border-input bg-transparent hover:bg-accent hover:text-accent-foreground transition-colors",
|
|
9675
9789
|
onClick: (event) => handleViewChange(),
|
|
9676
|
-
title: currentViewMode === "grid" ?
|
|
9790
|
+
title: currentViewMode === "grid" ? getLabel55("switchToList") : getLabel55("switchToGrid"),
|
|
9677
9791
|
children: [
|
|
9678
9792
|
currentViewMode === "grid" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9679
9793
|
"svg",
|
|
@@ -9731,7 +9845,7 @@ function GridToolbar(rawProps) {
|
|
|
9731
9845
|
onClick: (event) => {
|
|
9732
9846
|
if (props.onClearFilters) props.onClearFilters();
|
|
9733
9847
|
},
|
|
9734
|
-
children:
|
|
9848
|
+
children: getLabel55("clearAll")
|
|
9735
9849
|
}
|
|
9736
9850
|
),
|
|
9737
9851
|
props.priceFilterMin !== void 0 || props.priceFilterMax !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -9742,7 +9856,7 @@ function GridToolbar(rawProps) {
|
|
|
9742
9856
|
if (props.onPriceFilterRemove) props.onPriceFilterRemove();
|
|
9743
9857
|
},
|
|
9744
9858
|
children: [
|
|
9745
|
-
|
|
9859
|
+
getLabel55("price"),
|
|
9746
9860
|
": \u20AC",
|
|
9747
9861
|
props.priceFilterMin ?? 0,
|
|
9748
9862
|
" \u2013 \u20AC",
|
|
@@ -9779,7 +9893,7 @@ var DEFAULT_LABELS2 = {
|
|
|
9779
9893
|
of: "of"
|
|
9780
9894
|
};
|
|
9781
9895
|
function GridPagination(props) {
|
|
9782
|
-
function
|
|
9896
|
+
function getLabel55(key) {
|
|
9783
9897
|
const labels = props.labels || {};
|
|
9784
9898
|
return labels[key] !== void 0 ? labels[key] : DEFAULT_LABELS2[key] || key;
|
|
9785
9899
|
}
|
|
@@ -9852,15 +9966,15 @@ function GridPagination(props) {
|
|
|
9852
9966
|
className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--prev inline-flex items-center rounded-control border border-input bg-card px-4 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
|
|
9853
9967
|
disabled: currentPage === 1,
|
|
9854
9968
|
onClick: () => handlePageChange(currentPage - 1),
|
|
9855
|
-
children:
|
|
9969
|
+
children: getLabel55("previous")
|
|
9856
9970
|
}
|
|
9857
9971
|
),
|
|
9858
9972
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "propeller-grid-pagination__info px-2 text-sm font-medium text-muted-foreground", children: [
|
|
9859
|
-
|
|
9973
|
+
getLabel55("page"),
|
|
9860
9974
|
"\xA0",
|
|
9861
9975
|
currentPage,
|
|
9862
9976
|
"\xA0",
|
|
9863
|
-
|
|
9977
|
+
getLabel55("of"),
|
|
9864
9978
|
"\xA0",
|
|
9865
9979
|
totalPages
|
|
9866
9980
|
] }),
|
|
@@ -9871,7 +9985,7 @@ function GridPagination(props) {
|
|
|
9871
9985
|
className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--next inline-flex items-center rounded-control border border-input bg-card px-4 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
|
|
9872
9986
|
disabled: currentPage === totalPages,
|
|
9873
9987
|
onClick: () => handlePageChange(currentPage + 1),
|
|
9874
|
-
children:
|
|
9988
|
+
children: getLabel55("next")
|
|
9875
9989
|
}
|
|
9876
9990
|
)
|
|
9877
9991
|
] }) : null,
|
|
@@ -9883,7 +9997,7 @@ function GridPagination(props) {
|
|
|
9883
9997
|
className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--prev inline-flex items-center rounded-control border border-input bg-card px-3 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
|
|
9884
9998
|
disabled: currentPage === 1,
|
|
9885
9999
|
onClick: () => handlePageChange(currentPage - 1),
|
|
9886
|
-
children:
|
|
10000
|
+
children: getLabel55("previous")
|
|
9887
10001
|
}
|
|
9888
10002
|
),
|
|
9889
10003
|
getFullPages().map((item, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -9910,7 +10024,7 @@ function GridPagination(props) {
|
|
|
9910
10024
|
className: "propeller-grid-pagination__btn propeller-grid-pagination__btn--next inline-flex items-center rounded-control border border-input bg-card px-3 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-surface-hover disabled:opacity-40 disabled:cursor-not-allowed",
|
|
9911
10025
|
disabled: currentPage === totalPages,
|
|
9912
10026
|
onClick: () => handlePageChange(currentPage + 1),
|
|
9913
|
-
children:
|
|
10027
|
+
children: getLabel55("next")
|
|
9914
10028
|
}
|
|
9915
10029
|
)
|
|
9916
10030
|
] }) : null
|
|
@@ -10389,7 +10503,7 @@ function formatPrice9(price, currency) {
|
|
|
10389
10503
|
function getProductName2(product) {
|
|
10390
10504
|
return product.names?.[0]?.value || `Product ${product.productId}`;
|
|
10391
10505
|
}
|
|
10392
|
-
function
|
|
10506
|
+
function getProductImageUrl4(product) {
|
|
10393
10507
|
const media = product.media;
|
|
10394
10508
|
if (media?.images?.items && Array.isArray(media.images.items) && media.images.items.length > 0) {
|
|
10395
10509
|
const firstImage = media.images.items[0];
|
|
@@ -10418,7 +10532,7 @@ function ClusterOptions(props) {
|
|
|
10418
10532
|
(p) => p.productId.toString() === selectedProductId
|
|
10419
10533
|
);
|
|
10420
10534
|
if (selectedProduct) {
|
|
10421
|
-
previewImageUrl =
|
|
10535
|
+
previewImageUrl = getProductImageUrl4(selectedProduct);
|
|
10422
10536
|
previewName = getProductName2(selectedProduct);
|
|
10423
10537
|
previewPrice = formatPrice9(selectedProduct.price?.gross || 0, props.currency ?? "\u20AC");
|
|
10424
10538
|
}
|
|
@@ -13795,6 +13909,347 @@ function OrderList(rawProps) {
|
|
|
13795
13909
|
] });
|
|
13796
13910
|
}
|
|
13797
13911
|
var OrderList_default = OrderList;
|
|
13912
|
+
var ROW_SEQ = 0;
|
|
13913
|
+
function blankRow() {
|
|
13914
|
+
ROW_SEQ += 1;
|
|
13915
|
+
return {
|
|
13916
|
+
key: `qo-${ROW_SEQ}`,
|
|
13917
|
+
code: "",
|
|
13918
|
+
productId: null,
|
|
13919
|
+
name: "",
|
|
13920
|
+
netPrice: 0,
|
|
13921
|
+
quantity: 1,
|
|
13922
|
+
minQuantity: 1,
|
|
13923
|
+
matches: [],
|
|
13924
|
+
searching: false,
|
|
13925
|
+
searched: false
|
|
13926
|
+
};
|
|
13927
|
+
}
|
|
13928
|
+
function QuickOrderInner(props) {
|
|
13929
|
+
const {
|
|
13930
|
+
companyId,
|
|
13931
|
+
language = "NL",
|
|
13932
|
+
currency = "\u20AC",
|
|
13933
|
+
configuration,
|
|
13934
|
+
initialRows = 5,
|
|
13935
|
+
searchThreshold = 3,
|
|
13936
|
+
debounceMs = 300,
|
|
13937
|
+
parseSpreadsheet,
|
|
13938
|
+
templateUrl,
|
|
13939
|
+
maxUploadBytes = 2 * 1024 * 1024,
|
|
13940
|
+
maxUploadRows = 500,
|
|
13941
|
+
onCartCreated,
|
|
13942
|
+
afterAddToCart,
|
|
13943
|
+
onMissingCodes,
|
|
13944
|
+
className,
|
|
13945
|
+
labels
|
|
13946
|
+
} = props;
|
|
13947
|
+
const user = props.user ?? null;
|
|
13948
|
+
const graphqlClient = props.graphqlClient;
|
|
13949
|
+
const displayPrice = (n) => props.formatPrice ? props.formatPrice(n) : propellerV2CoreUi.formatPrice(n, { symbol: currency });
|
|
13950
|
+
const L = (key, fallback) => propellerV2CoreUi.getLabel(labels, key, fallback);
|
|
13951
|
+
const { submitting, searchProducts, submit } = useQuickOrder({
|
|
13952
|
+
graphqlClient,
|
|
13953
|
+
user,
|
|
13954
|
+
companyId,
|
|
13955
|
+
language,
|
|
13956
|
+
configuration,
|
|
13957
|
+
onCartCreated,
|
|
13958
|
+
afterAddToCart
|
|
13959
|
+
});
|
|
13960
|
+
const [rows, setRows] = React6.useState(
|
|
13961
|
+
() => Array.from({ length: Math.max(1, initialRows) }, blankRow)
|
|
13962
|
+
);
|
|
13963
|
+
const [missing, setMissing] = React6.useState([]);
|
|
13964
|
+
const [uploadError, setUploadError] = React6.useState(null);
|
|
13965
|
+
const [uploading, setUploading] = React6.useState(false);
|
|
13966
|
+
const [notice, setNotice] = React6.useState(null);
|
|
13967
|
+
const fileInputRef = React6.useRef(null);
|
|
13968
|
+
const searchTimers = React6.useRef({});
|
|
13969
|
+
const patchRow = React6.useCallback((key, patch) => {
|
|
13970
|
+
setRows((prev) => prev.map((r) => r.key === key ? { ...r, ...patch } : r));
|
|
13971
|
+
}, []);
|
|
13972
|
+
const onCodeInput = React6.useCallback(
|
|
13973
|
+
(key, value) => {
|
|
13974
|
+
patchRow(key, { code: value, productId: null, name: "", netPrice: 0, searched: false });
|
|
13975
|
+
setNotice(null);
|
|
13976
|
+
const timers = searchTimers.current;
|
|
13977
|
+
if (timers[key]) clearTimeout(timers[key]);
|
|
13978
|
+
if (value.trim().length < searchThreshold) {
|
|
13979
|
+
patchRow(key, { matches: [], searching: false, searched: false });
|
|
13980
|
+
return;
|
|
13981
|
+
}
|
|
13982
|
+
patchRow(key, { searching: true });
|
|
13983
|
+
timers[key] = setTimeout(async () => {
|
|
13984
|
+
const results = await searchProducts(value);
|
|
13985
|
+
patchRow(key, { matches: results, searching: false, searched: true });
|
|
13986
|
+
}, debounceMs);
|
|
13987
|
+
},
|
|
13988
|
+
[patchRow, searchProducts, searchThreshold, debounceMs]
|
|
13989
|
+
);
|
|
13990
|
+
const selectMatch = React6.useCallback(
|
|
13991
|
+
(key, match) => {
|
|
13992
|
+
const dup = rows.some((r) => r.key !== key && r.productId && r.code === match.sku);
|
|
13993
|
+
if (dup) {
|
|
13994
|
+
setNotice(L("alreadyInList", "Product is already in the list"));
|
|
13995
|
+
patchRow(key, { code: "", matches: [], productId: null, name: "", netPrice: 0, searched: false });
|
|
13996
|
+
return;
|
|
13997
|
+
}
|
|
13998
|
+
patchRow(key, {
|
|
13999
|
+
code: match.sku,
|
|
14000
|
+
productId: match.productId,
|
|
14001
|
+
clusterId: match.clusterId,
|
|
14002
|
+
name: match.name,
|
|
14003
|
+
netPrice: match.netPrice,
|
|
14004
|
+
quantity: match.minQuantity,
|
|
14005
|
+
minQuantity: match.minQuantity,
|
|
14006
|
+
matches: [],
|
|
14007
|
+
searching: false,
|
|
14008
|
+
searched: false
|
|
14009
|
+
});
|
|
14010
|
+
},
|
|
14011
|
+
[rows, patchRow, L]
|
|
14012
|
+
);
|
|
14013
|
+
const setQuantity = React6.useCallback(
|
|
14014
|
+
(key, raw) => {
|
|
14015
|
+
const n = parseInt(raw, 10);
|
|
14016
|
+
setRows(
|
|
14017
|
+
(prev) => prev.map(
|
|
14018
|
+
(r) => r.key === key ? { ...r, quantity: Number.isFinite(n) && n > 0 ? Math.max(r.minQuantity, n) : r.minQuantity } : r
|
|
14019
|
+
)
|
|
14020
|
+
);
|
|
14021
|
+
},
|
|
14022
|
+
[]
|
|
14023
|
+
);
|
|
14024
|
+
const addRow = React6.useCallback(() => setRows((prev) => [...prev, blankRow()]), []);
|
|
14025
|
+
const removeRow = React6.useCallback(
|
|
14026
|
+
(key) => setRows((prev) => prev.length > 1 ? prev.filter((r) => r.key !== key) : prev),
|
|
14027
|
+
[]
|
|
14028
|
+
);
|
|
14029
|
+
const resolvedCount = React6.useMemo(() => rows.filter((r) => r.productId).length, [rows]);
|
|
14030
|
+
const onFileChosen = React6.useCallback(
|
|
14031
|
+
async (file) => {
|
|
14032
|
+
if (!file || !parseSpreadsheet) return;
|
|
14033
|
+
setUploadError(null);
|
|
14034
|
+
setMissing([]);
|
|
14035
|
+
if (file.size > maxUploadBytes) {
|
|
14036
|
+
setUploadError(`File too large (max ${Math.round(maxUploadBytes / 1024 / 1024)} MB)`);
|
|
14037
|
+
return;
|
|
14038
|
+
}
|
|
14039
|
+
setUploading(true);
|
|
14040
|
+
try {
|
|
14041
|
+
let lines = await parseSpreadsheet(file);
|
|
14042
|
+
lines = lines.slice(0, maxUploadRows).map((l) => ({ code: String(l.code ?? "").trim(), quantity: Math.max(1, parseInt(String(l.quantity), 10) || 1) })).filter((l) => l.code.length > 0);
|
|
14043
|
+
if (!lines.length) {
|
|
14044
|
+
setUploadError("No valid rows found in the file");
|
|
14045
|
+
return;
|
|
14046
|
+
}
|
|
14047
|
+
const resolved = [];
|
|
14048
|
+
const notFound = [];
|
|
14049
|
+
for (const line of lines) {
|
|
14050
|
+
const matches = await searchProducts(line.code);
|
|
14051
|
+
const exact = matches.find((m) => m.sku.toLowerCase() === line.code.toLowerCase()) || matches[0];
|
|
14052
|
+
if (!exact) {
|
|
14053
|
+
notFound.push(line.code);
|
|
14054
|
+
continue;
|
|
14055
|
+
}
|
|
14056
|
+
if (resolved.some((r) => r.productId === exact.productId)) continue;
|
|
14057
|
+
const row = blankRow();
|
|
14058
|
+
resolved.push({
|
|
14059
|
+
...row,
|
|
14060
|
+
code: exact.sku,
|
|
14061
|
+
productId: exact.productId,
|
|
14062
|
+
clusterId: exact.clusterId,
|
|
14063
|
+
name: exact.name,
|
|
14064
|
+
netPrice: exact.netPrice,
|
|
14065
|
+
quantity: Math.max(exact.minQuantity, line.quantity),
|
|
14066
|
+
minQuantity: exact.minQuantity
|
|
14067
|
+
});
|
|
14068
|
+
}
|
|
14069
|
+
if (resolved.length) {
|
|
14070
|
+
setRows([...resolved, blankRow()]);
|
|
14071
|
+
}
|
|
14072
|
+
if (notFound.length) {
|
|
14073
|
+
setMissing(notFound);
|
|
14074
|
+
onMissingCodes?.(notFound);
|
|
14075
|
+
}
|
|
14076
|
+
} catch {
|
|
14077
|
+
setUploadError("Could not read the file");
|
|
14078
|
+
} finally {
|
|
14079
|
+
setUploading(false);
|
|
14080
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
14081
|
+
}
|
|
14082
|
+
},
|
|
14083
|
+
[parseSpreadsheet, maxUploadBytes, maxUploadRows, searchProducts, onMissingCodes]
|
|
14084
|
+
);
|
|
14085
|
+
const handleSubmit = React6.useCallback(async () => {
|
|
14086
|
+
const lines = rows.filter((r) => r.productId).map((r) => ({ productId: r.productId, quantity: r.quantity, clusterId: r.clusterId, code: r.code }));
|
|
14087
|
+
if (!lines.length) {
|
|
14088
|
+
setNotice(L("noItems", "Add at least one product before submitting"));
|
|
14089
|
+
return;
|
|
14090
|
+
}
|
|
14091
|
+
const res = await submit(lines);
|
|
14092
|
+
if (res.success) {
|
|
14093
|
+
setRows(Array.from({ length: Math.max(1, initialRows) }, blankRow));
|
|
14094
|
+
setMissing([]);
|
|
14095
|
+
setNotice(null);
|
|
14096
|
+
} else {
|
|
14097
|
+
setNotice(res.error ?? "Failed to add items to cart");
|
|
14098
|
+
}
|
|
14099
|
+
}, [rows, submit, initialRows, L]);
|
|
14100
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className ?? "propeller-quick-order", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col lg:flex-row gap-8", children: [
|
|
14101
|
+
parseSpreadsheet ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full lg:w-1/3", children: [
|
|
14102
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold mb-3 text-foreground", children: L("uploadTitle", "Upload Excel file") }),
|
|
14103
|
+
templateUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14104
|
+
"a",
|
|
14105
|
+
{
|
|
14106
|
+
href: templateUrl,
|
|
14107
|
+
target: "_blank",
|
|
14108
|
+
rel: "noopener nofollow",
|
|
14109
|
+
className: "text-primary hover:underline text-sm inline-block mb-4",
|
|
14110
|
+
children: L("downloadTemplate", "Download XLSX template")
|
|
14111
|
+
}
|
|
14112
|
+
) : null,
|
|
14113
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-3", children: L("uploadHint", "Column A: article no. / SKU \u2014 Column B: quantity. First two rows are ignored.") }),
|
|
14114
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14115
|
+
"input",
|
|
14116
|
+
{
|
|
14117
|
+
ref: fileInputRef,
|
|
14118
|
+
type: "file",
|
|
14119
|
+
accept: ".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel",
|
|
14120
|
+
className: "block w-full text-sm text-muted-foreground file:mr-3 file:py-2 file:px-4 file:rounded file:border-0 file:bg-primary file:text-primary-foreground hover:file:bg-primary/90",
|
|
14121
|
+
onChange: (e) => onFileChosen(e.target.files?.[0]),
|
|
14122
|
+
disabled: uploading
|
|
14123
|
+
}
|
|
14124
|
+
),
|
|
14125
|
+
uploading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2", children: L("upload", "Uploading\u2026") }) : null,
|
|
14126
|
+
uploadError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive mt-2", children: uploadError }) : null
|
|
14127
|
+
] }) : null,
|
|
14128
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
14129
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold mb-3 text-foreground", children: L("title", "Add your products manually") }),
|
|
14130
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:grid grid-cols-12 gap-2 px-2 pb-2 text-xs font-medium text-muted-foreground border-b border-border", children: [
|
|
14131
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: L("colCode", "Article no. / SKU") }),
|
|
14132
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: L("colName", "Product name") }),
|
|
14133
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: L("colPrice", "excl. VAT") }),
|
|
14134
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-1", children: L("colQuantity", "Qty") }),
|
|
14135
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2 text-right", children: L("colTotal", "Total") }),
|
|
14136
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-1" })
|
|
14137
|
+
] }),
|
|
14138
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-2 items-center py-2 relative", children: [
|
|
14139
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-3 relative", children: [
|
|
14140
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14141
|
+
"input",
|
|
14142
|
+
{
|
|
14143
|
+
type: "text",
|
|
14144
|
+
value: r.code,
|
|
14145
|
+
onChange: (e) => onCodeInput(r.key, e.target.value),
|
|
14146
|
+
readOnly: !!r.productId,
|
|
14147
|
+
placeholder: L("colCode", "Article no. / SKU"),
|
|
14148
|
+
className: "w-full rounded border border-input bg-background px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
14149
|
+
}
|
|
14150
|
+
),
|
|
14151
|
+
(r.searching || r.matches.length > 0 || r.searched) && !r.productId ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "absolute z-20 mt-1 w-[320px] max-w-[90vw] bg-card border border-border rounded shadow-lg max-h-72 overflow-auto", children: r.searching ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm text-muted-foreground", children: "\u2026" }) : r.matches.length ? r.matches.map((m) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14152
|
+
"button",
|
|
14153
|
+
{
|
|
14154
|
+
type: "button",
|
|
14155
|
+
onClick: () => selectMatch(r.key, m),
|
|
14156
|
+
className: "flex items-center gap-2 w-full text-left px-3 py-2 hover:bg-muted text-sm",
|
|
14157
|
+
children: [
|
|
14158
|
+
m.imageUrl ? (
|
|
14159
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
14160
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: m.imageUrl, alt: "", width: 32, height: 32, className: "rounded object-cover" })
|
|
14161
|
+
) : null,
|
|
14162
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex-1", children: [
|
|
14163
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-foreground", children: m.name }),
|
|
14164
|
+
m.sku ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "block text-xs text-muted-foreground", children: [
|
|
14165
|
+
"SKU: ",
|
|
14166
|
+
m.sku
|
|
14167
|
+
] }) : null
|
|
14168
|
+
] })
|
|
14169
|
+
]
|
|
14170
|
+
}
|
|
14171
|
+
) }, `${r.key}-${m.productId}`)) : /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm text-muted-foreground", children: L("noResults", "No results found") }) }) : null
|
|
14172
|
+
] }),
|
|
14173
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-6 md:col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14174
|
+
"input",
|
|
14175
|
+
{
|
|
14176
|
+
type: "text",
|
|
14177
|
+
value: r.name,
|
|
14178
|
+
disabled: true,
|
|
14179
|
+
className: "w-full rounded border border-input bg-muted/40 px-2 py-1.5 text-sm text-muted-foreground"
|
|
14180
|
+
}
|
|
14181
|
+
) }),
|
|
14182
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3 md:col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14183
|
+
"input",
|
|
14184
|
+
{
|
|
14185
|
+
type: "text",
|
|
14186
|
+
value: r.productId ? displayPrice(r.netPrice) : "",
|
|
14187
|
+
disabled: true,
|
|
14188
|
+
className: "w-full rounded border border-input bg-muted/40 px-2 py-1.5 text-sm text-muted-foreground"
|
|
14189
|
+
}
|
|
14190
|
+
) }),
|
|
14191
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3 md:col-span-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14192
|
+
"input",
|
|
14193
|
+
{
|
|
14194
|
+
type: "number",
|
|
14195
|
+
min: r.minQuantity,
|
|
14196
|
+
step: 1,
|
|
14197
|
+
value: r.productId ? r.quantity : "",
|
|
14198
|
+
disabled: !r.productId,
|
|
14199
|
+
onChange: (e) => setQuantity(r.key, e.target.value),
|
|
14200
|
+
onKeyDown: (e) => {
|
|
14201
|
+
if (["e", "E", "+", "-", "."].includes(e.key)) e.preventDefault();
|
|
14202
|
+
},
|
|
14203
|
+
className: "w-full rounded border border-input bg-background px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:bg-muted/40"
|
|
14204
|
+
}
|
|
14205
|
+
) }),
|
|
14206
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-9 md:col-span-2 text-right text-sm text-foreground whitespace-nowrap", children: r.productId ? displayPrice(r.netPrice * r.quantity) : "" }),
|
|
14207
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3 md:col-span-1 flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14208
|
+
"button",
|
|
14209
|
+
{
|
|
14210
|
+
type: "button",
|
|
14211
|
+
onClick: () => removeRow(r.key),
|
|
14212
|
+
"aria-label": L("remove", "Remove"),
|
|
14213
|
+
className: "text-muted-foreground hover:text-destructive p-1",
|
|
14214
|
+
children: "\u2715"
|
|
14215
|
+
}
|
|
14216
|
+
) })
|
|
14217
|
+
] }, r.key)) }),
|
|
14218
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14219
|
+
"button",
|
|
14220
|
+
{
|
|
14221
|
+
type: "button",
|
|
14222
|
+
onClick: addRow,
|
|
14223
|
+
className: "mt-3 text-primary hover:underline text-sm font-medium",
|
|
14224
|
+
children: [
|
|
14225
|
+
"+ ",
|
|
14226
|
+
L("addRow", "Add more rows")
|
|
14227
|
+
]
|
|
14228
|
+
}
|
|
14229
|
+
),
|
|
14230
|
+
missing.length ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-destructive mt-4", children: [
|
|
14231
|
+
L("missingCodes", "The following products were not added:"),
|
|
14232
|
+
" ",
|
|
14233
|
+
missing.join(", ")
|
|
14234
|
+
] }) : null,
|
|
14235
|
+
notice ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive mt-2", children: notice }) : null,
|
|
14236
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end mt-6 pt-4 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14237
|
+
"button",
|
|
14238
|
+
{
|
|
14239
|
+
type: "button",
|
|
14240
|
+
onClick: handleSubmit,
|
|
14241
|
+
disabled: submitting || resolvedCount === 0,
|
|
14242
|
+
className: "bg-primary text-primary-foreground px-6 py-2.5 rounded font-medium hover:bg-primary/90 transition disabled:opacity-50 disabled:cursor-not-allowed",
|
|
14243
|
+
children: submitting ? L("adding", "Adding\u2026") : L("addToCart", "Add to cart")
|
|
14244
|
+
}
|
|
14245
|
+
) })
|
|
14246
|
+
] })
|
|
14247
|
+
] }) });
|
|
14248
|
+
}
|
|
14249
|
+
function QuickOrder(rawProps) {
|
|
14250
|
+
const props = useInfraProps(rawProps);
|
|
14251
|
+
return /* @__PURE__ */ jsxRuntime.jsx(QuickOrderInner, { ...props });
|
|
14252
|
+
}
|
|
13798
14253
|
function OrderShipments(props) {
|
|
13799
14254
|
const [activeShipment, setActiveShipment] = React6.useState(null);
|
|
13800
14255
|
const shipments = props.order?.shipments || [];
|
|
@@ -18271,6 +18726,7 @@ exports.PropellerDepsProvider = PropellerDepsProvider;
|
|
|
18271
18726
|
exports.PropellerProvider = PropellerProvider;
|
|
18272
18727
|
exports.PurchaseAuthorizationConfigurator = PurchaseAuthorizationConfigurator_default;
|
|
18273
18728
|
exports.PurchaseAuthorizationRequests = PurchaseAuthorizationRequests_default;
|
|
18729
|
+
exports.QuickOrder = QuickOrder;
|
|
18274
18730
|
exports.QuoteActions = QuoteActions_default;
|
|
18275
18731
|
exports.RegisterForm = RegisterForm_default;
|
|
18276
18732
|
exports.SearchBar = SearchBar_default;
|
|
@@ -18301,6 +18757,7 @@ exports.usePropellerDeps = usePropellerDeps;
|
|
|
18301
18757
|
exports.usePropellerScope = usePropellerScope;
|
|
18302
18758
|
exports.usePurchaseAuthorizationConfigurator = usePurchaseAuthorizationConfigurator;
|
|
18303
18759
|
exports.usePurchaseAuthorizationRequests = usePurchaseAuthorizationRequests;
|
|
18760
|
+
exports.useQuickOrder = useQuickOrder;
|
|
18304
18761
|
exports.useRequiredPropellerDeps = useRequiredPropellerDeps;
|
|
18305
18762
|
exports.useResolvedProps = useResolvedProps;
|
|
18306
18763
|
exports.useServices = useServices;
|