@propeller-commerce/propeller-v2-react-ui 0.21.0 → 0.23.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 +78 -0
- package/dist/index.cjs +170 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -12
- package/dist/index.d.ts +94 -12
- package/dist/index.js +172 -56
- package/dist/index.js.map +1 -1
- package/dist/pure.cjs +6 -14
- package/dist/pure.cjs.map +1 -1
- package/dist/pure.d.cts +12 -0
- package/dist/pure.d.ts +12 -0
- package/dist/pure.js +7 -15
- package/dist/pure.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,84 @@ once it reaches 1.0. Until then (the `0.x` line) the public API may change
|
|
|
8
8
|
between minor versions; breaking changes are called out below and in
|
|
9
9
|
[MIGRATION.md](./MIGRATION.md).
|
|
10
10
|
|
|
11
|
+
## [0.23.0] - 2026-09-24
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **A machine listed in one language could not be opened.** 0.21.0 stopped the
|
|
16
|
+
listing from narrowing to a single language, so an NL-only installation
|
|
17
|
+
appears in an EN tree and is linked by its NL slug — but `machine(slug:)`
|
|
18
|
+
resolves a slug **only** in the language it was authored in, so following
|
|
19
|
+
that link asked for `machine(slug: "<NL slug>", language: "EN")` and got
|
|
20
|
+
`SPARE_PARTS_MACHINE_NOT_FOUND_ERROR`. The page then showed a title derived
|
|
21
|
+
from the slug, no parts and no error: the bug moved one click deeper instead
|
|
22
|
+
of going away. `useSpareParts` now tries the tree language, then the
|
|
23
|
+
storefront language, then any locales given in the new `machineLanguages`
|
|
24
|
+
option, and upper-cases each (the API matches case exactly — `nl` misses
|
|
25
|
+
where `NL` hits). A slug that resolves in none of them sets the new
|
|
26
|
+
`notFound` flag, and `MachineGrid` renders "This machine could not be found."
|
|
27
|
+
instead of an empty listing. A fully-translated shop still costs exactly one
|
|
28
|
+
request, and a non-"not found" failure is never retried or reported as a
|
|
29
|
+
missing machine. (PWP-993)
|
|
30
|
+
|
|
31
|
+
- **"Qty in machine" and "Search parts…" stayed English in a translated shop.**
|
|
32
|
+
Both were read from `toolbarLabels`, which is forwarded verbatim to
|
|
33
|
+
`GridToolbar` — so they belonged to no toolbar dictionary, and a shop that
|
|
34
|
+
translated its `GridToolbar` keys properly still got English. They now come
|
|
35
|
+
from `machineCardLabels` (the grid's own label bag, alongside `loading`,
|
|
36
|
+
`noMachines` and the new `machineNotFound`), falling back to `toolbarLabels`
|
|
37
|
+
so hosts that already set them keep working. (PWP-995a)
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `MachineGrid.machineLanguages` / `useSpareParts.machineLanguages` — the
|
|
42
|
+
locales to try when a machine slug does not resolve in the tree language.
|
|
43
|
+
- `useSpareParts().notFound` — the slug resolved in none of the candidate
|
|
44
|
+
languages, as distinct from "resolved but has no parts".
|
|
45
|
+
- `machineCardLabels.machineNotFound` — copy for that state.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## [0.22.0] - 2026-09-24
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **Media language is matched case-insensitively.** The API lowercases
|
|
53
|
+
`documents[].language` while leaving `alt[].language` as uploaded, so
|
|
54
|
+
`ProductDownloads` matched the label but never the file and served
|
|
55
|
+
`documents[0]` — the Dutch PDF under an English label. `ProductVideos` had
|
|
56
|
+
the identical comparison and worked only by data luck. Also fixed in
|
|
57
|
+
`useProductSearch.filterByLanguage`, where a case mismatch dropped **every**
|
|
58
|
+
product from the grid, and in `DefaultProductImage`. (PWP-984)
|
|
59
|
+
- **`checkoutAllowed` is usable, and fails closed.** It read the raw `companyId`
|
|
60
|
+
option rather than the resolved one, so a contact acting for their own company
|
|
61
|
+
matched no authorization config and every cart reported as within limit; and it
|
|
62
|
+
evaluated its own cart state, which stays null when the consumer only seeds a
|
|
63
|
+
`cartId`. The hook now hydrates a seeded cart, and reports `false` while that
|
|
64
|
+
is in flight rather than `true`. (PWP-988)
|
|
65
|
+
- **The place-order button is gated on the authorization limit.** An over-limit
|
|
66
|
+
purchaser opening checkout directly got an ungated button and a backend
|
|
67
|
+
rejection; `CartOverview` now shows an `authorizationRequired` message
|
|
68
|
+
instead, using the same predicate as the cart summary. (PWP-988)
|
|
69
|
+
- **Semi-closed surfaces no longer flash their logged-out state** for a signed-in
|
|
70
|
+
visitor while the profile loads. Every `isContentHidden` call site passes the
|
|
71
|
+
provider’s `isAuthenticated` (core-ui 0.9.0+). (PWP-989)
|
|
72
|
+
- **The cart sidebar slides again.** The overflow fix named only `transform` in
|
|
73
|
+
its transition, but Tailwind v4 emits `translate-x-*` as the `translate`
|
|
74
|
+
property, so the panel jumped. (PWP-1002)
|
|
75
|
+
- **Header triggers inherit their colour.** `AccountIconAndMenu` and
|
|
76
|
+
`CompanySwitcher` hardcoded `text-white`, which broke light headers;
|
|
77
|
+
`text-foreground` then broke dark ones. Both now use `text-inherit`, with the
|
|
78
|
+
hover tint derived from `currentColor`. (PWP-1005)
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- `CompanySwitcher` accepts `triggerClassName`; it had no class prop at all.
|
|
83
|
+
- `ProductInfo` accepts `cartId`, `createCart` and `onCartCreated`, and forwards
|
|
84
|
+
them to both the injected and the default add-to-cart. It declared none of
|
|
85
|
+
them, so the PDP’s add-to-cart always failed for a visitor without a cart.
|
|
86
|
+
`ProductCard` forwards the same to an injected component. (PWP-986)
|
|
87
|
+
- `CartOverview` resolves `user` and `companyId` from `PropellerProvider`.
|
|
88
|
+
|
|
11
89
|
## [0.21.0] - 2026-09-23
|
|
12
90
|
|
|
13
91
|
`MachineGrid` stops losing rows, and becomes usable in a translated or
|
package/dist/index.cjs
CHANGED
|
@@ -767,10 +767,29 @@ function useCart(options) {
|
|
|
767
767
|
const [loading, setLoading] = React6.useState(false);
|
|
768
768
|
const [error, setError] = React6.useState(null);
|
|
769
769
|
const notesTimers = React6.useRef({});
|
|
770
|
-
|
|
771
|
-
(
|
|
772
|
-
|
|
773
|
-
|
|
770
|
+
React6.useEffect(() => {
|
|
771
|
+
if (!graphqlClient || !cartId || cart) return;
|
|
772
|
+
let cancelled = false;
|
|
773
|
+
(async () => {
|
|
774
|
+
try {
|
|
775
|
+
const fetched = await propellerV2CoreUi.createServices(graphqlClient).cart.getCart({
|
|
776
|
+
cartId,
|
|
777
|
+
imageSearchFilters: imageSearchFilters(),
|
|
778
|
+
imageVariantFilters: imageVariantFilters(),
|
|
779
|
+
language
|
|
780
|
+
});
|
|
781
|
+
if (!cancelled && fetched) setCart(fetched);
|
|
782
|
+
} catch {
|
|
783
|
+
}
|
|
784
|
+
})();
|
|
785
|
+
return () => {
|
|
786
|
+
cancelled = true;
|
|
787
|
+
};
|
|
788
|
+
}, [graphqlClient, cartId, cart, language, imageSearchFilters, imageVariantFilters]);
|
|
789
|
+
const checkoutAllowed = React6.useMemo(() => {
|
|
790
|
+
if (cartId && !cart) return false;
|
|
791
|
+
return propellerV2CoreUi.isCheckoutAllowed(user, resolvedCompanyId, cart);
|
|
792
|
+
}, [user, resolvedCompanyId, cart, cartId]);
|
|
774
793
|
function getMinQuantity(product) {
|
|
775
794
|
const min = product?.minimumQuantity;
|
|
776
795
|
return min && min > 0 ? min : 1;
|
|
@@ -1591,7 +1610,8 @@ var INFRA_KEYS = [
|
|
|
1591
1610
|
"includeTax",
|
|
1592
1611
|
"currency",
|
|
1593
1612
|
"configuration",
|
|
1594
|
-
"portalMode"
|
|
1613
|
+
"portalMode",
|
|
1614
|
+
"isAuthenticated"
|
|
1595
1615
|
];
|
|
1596
1616
|
function useInfraProps(props) {
|
|
1597
1617
|
const ctx = usePropellerContext();
|
|
@@ -2268,10 +2288,11 @@ function useProductSearch(options) {
|
|
|
2268
2288
|
const isLoading = !isControlled && internalLoading;
|
|
2269
2289
|
function filterByLanguage(products, lang) {
|
|
2270
2290
|
if (!lang) return products;
|
|
2291
|
+
const target = lang.toUpperCase();
|
|
2271
2292
|
return products.filter((p) => {
|
|
2272
2293
|
const names = p.names || p.names || [];
|
|
2273
2294
|
if (!names || names.length === 0) return true;
|
|
2274
|
-
return names.some((n) => n.language ===
|
|
2295
|
+
return names.some((n) => (n.language || "").toUpperCase() === target);
|
|
2275
2296
|
});
|
|
2276
2297
|
}
|
|
2277
2298
|
const fetchProducts = React6.useCallback(async () => {
|
|
@@ -2761,6 +2782,40 @@ function useQuickOrder(options) {
|
|
|
2761
2782
|
);
|
|
2762
2783
|
return { submitting, error, searchProducts, submit };
|
|
2763
2784
|
}
|
|
2785
|
+
|
|
2786
|
+
// src/composables/shared/utils/machineLanguage.ts
|
|
2787
|
+
var MACHINE_NOT_FOUND = "SPARE_PARTS_MACHINE_NOT_FOUND_ERROR";
|
|
2788
|
+
function isMachineNotFound(error) {
|
|
2789
|
+
const entries = error?.errors;
|
|
2790
|
+
if (!Array.isArray(entries)) return false;
|
|
2791
|
+
return entries.some(
|
|
2792
|
+
(e) => e?.extensions?.code === MACHINE_NOT_FOUND || /no machine found for slug and language/i.test(e?.message ?? "")
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
function machineLanguageCandidates(machineLanguage, language, extra) {
|
|
2796
|
+
const ordered = [machineLanguage, language, ...extra ?? []];
|
|
2797
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2798
|
+
const out = [];
|
|
2799
|
+
for (const raw of ordered) {
|
|
2800
|
+
const value = raw?.trim().toUpperCase();
|
|
2801
|
+
if (!value || seen.has(value)) continue;
|
|
2802
|
+
seen.add(value);
|
|
2803
|
+
out.push(value);
|
|
2804
|
+
}
|
|
2805
|
+
return out;
|
|
2806
|
+
}
|
|
2807
|
+
async function resolveMachineAcrossLanguages(candidates, fetchOne) {
|
|
2808
|
+
for (const language of candidates) {
|
|
2809
|
+
try {
|
|
2810
|
+
return { machine: await fetchOne(language), language };
|
|
2811
|
+
} catch (error) {
|
|
2812
|
+
if (!isMachineNotFound(error)) throw error;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
return null;
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
// src/composables/react/useSpareParts.ts
|
|
2764
2819
|
var inflightFetches3 = /* @__PURE__ */ new Set();
|
|
2765
2820
|
var STOREFRONT_STATUSES = [
|
|
2766
2821
|
propellerSdkV2.ProductStatus.A,
|
|
@@ -2777,6 +2832,8 @@ function useSpareParts(options) {
|
|
|
2777
2832
|
const [itemsFound, setItemsFound] = React6.useState(0);
|
|
2778
2833
|
const [internalLoading, setInternalLoading] = React6.useState(false);
|
|
2779
2834
|
const [internalPage, setInternalPage] = React6.useState(1);
|
|
2835
|
+
const [notFound, setNotFound] = React6.useState(false);
|
|
2836
|
+
const machineLanguagesKey = (options.machineLanguages ?? []).join(",");
|
|
2780
2837
|
const currentPage = options.page ?? internalPage;
|
|
2781
2838
|
const [totalPages, setTotalPages] = React6.useState(1);
|
|
2782
2839
|
const fetchIdRef = React6.useRef(0);
|
|
@@ -2842,17 +2899,35 @@ function useSpareParts(options) {
|
|
|
2842
2899
|
const filterAvailableAttributeInput = {
|
|
2843
2900
|
isSearchable: true
|
|
2844
2901
|
};
|
|
2845
|
-
const
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2902
|
+
const resolved = await resolveMachineAcrossLanguages(
|
|
2903
|
+
machineLanguageCandidates(
|
|
2904
|
+
options.machineLanguage,
|
|
2905
|
+
options.language,
|
|
2906
|
+
options.machineLanguages
|
|
2907
|
+
),
|
|
2908
|
+
(language) => service.getMachine({
|
|
2909
|
+
slug: options.slug,
|
|
2910
|
+
// The machine tree's language, NOT the parts' — see `machineLanguage`.
|
|
2911
|
+
language,
|
|
2912
|
+
sparePartsMachineProductSearchInput,
|
|
2913
|
+
filterAvailableAttributeInput,
|
|
2914
|
+
priceCalculateProductInput,
|
|
2915
|
+
imageSearchFilters: options.configuration?.imageSearchFiltersGrid,
|
|
2916
|
+
imageVariantFilters: options.configuration?.imageVariantFiltersMedium
|
|
2917
|
+
})
|
|
2918
|
+
);
|
|
2855
2919
|
if (thisId !== fetchIdRef.current) return;
|
|
2920
|
+
if (!resolved) {
|
|
2921
|
+
setNotFound(true);
|
|
2922
|
+
setInternalParts([]);
|
|
2923
|
+
setChildMachines([]);
|
|
2924
|
+
setItemsFound(0);
|
|
2925
|
+
options.onItemsFoundChange?.(0);
|
|
2926
|
+
setTotalPages(1);
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
setNotFound(false);
|
|
2930
|
+
const machine = resolved.machine;
|
|
2856
2931
|
const partsResponse = machine?.sparePartProducts;
|
|
2857
2932
|
const items = partsResponse?.items ?? [];
|
|
2858
2933
|
setInternalParts(items);
|
|
@@ -2894,6 +2969,7 @@ function useSpareParts(options) {
|
|
|
2894
2969
|
options.term,
|
|
2895
2970
|
options.language,
|
|
2896
2971
|
options.machineLanguage,
|
|
2972
|
+
machineLanguagesKey,
|
|
2897
2973
|
options.taxZone,
|
|
2898
2974
|
options.companyId,
|
|
2899
2975
|
options.textFilters,
|
|
@@ -2914,6 +2990,7 @@ function useSpareParts(options) {
|
|
|
2914
2990
|
options.term,
|
|
2915
2991
|
options.language,
|
|
2916
2992
|
options.machineLanguage,
|
|
2993
|
+
machineLanguagesKey,
|
|
2917
2994
|
options.companyId,
|
|
2918
2995
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2919
2996
|
JSON.stringify(options.textFilters ?? []),
|
|
@@ -2939,7 +3016,8 @@ function useSpareParts(options) {
|
|
|
2939
3016
|
currentPage,
|
|
2940
3017
|
totalPages,
|
|
2941
3018
|
fetchParts,
|
|
2942
|
-
goToPage
|
|
3019
|
+
goToPage,
|
|
3020
|
+
notFound: !isControlled && notFound
|
|
2943
3021
|
};
|
|
2944
3022
|
}
|
|
2945
3023
|
var inflightFetches4 = /* @__PURE__ */ new Set();
|
|
@@ -4228,7 +4306,7 @@ function AccountIconAndMenu(rawProps) {
|
|
|
4228
4306
|
onClick: (event) => handleIconClick(),
|
|
4229
4307
|
"aria-label": propellerV2CoreUi.getLabel(props.labels, "accountLabel", "Account"),
|
|
4230
4308
|
"data-open": menuOpen ? "true" : "false",
|
|
4231
|
-
className: cn(`propeller-account-menu__trigger inline-flex items-center gap-2 px-3 py-2 rounded-control text-sm font-medium transition-colors text-
|
|
4309
|
+
className: cn(`propeller-account-menu__trigger inline-flex items-center gap-2 px-3 py-2 rounded-control text-sm font-medium transition-colors text-inherit${props.iconClassName ? " " + props.iconClassName : ""}`),
|
|
4232
4310
|
children: [
|
|
4233
4311
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4234
4312
|
"svg",
|
|
@@ -7640,7 +7718,8 @@ function CartIconAndSidebar(rawProps) {
|
|
|
7640
7718
|
] });
|
|
7641
7719
|
}
|
|
7642
7720
|
var CartIconAndSidebar_default = CartIconAndSidebar;
|
|
7643
|
-
function CartOverview(
|
|
7721
|
+
function CartOverview(rawProps) {
|
|
7722
|
+
const props = useInfraProps(rawProps);
|
|
7644
7723
|
const [reference, setReference] = React6.useState("");
|
|
7645
7724
|
const [notes, setNotes] = React6.useState("");
|
|
7646
7725
|
const [termsAccepted, setTermsAccepted] = React6.useState(false);
|
|
@@ -7650,6 +7729,7 @@ function CartOverview(props) {
|
|
|
7650
7729
|
const showReference = props.showReference !== false;
|
|
7651
7730
|
const showTermsAndConditions = props.showTermsAndConditions !== false;
|
|
7652
7731
|
const showPurchaseButton = props.showPurchaseButton !== false;
|
|
7732
|
+
const overLimit = propellerV2CoreUi.isOverAuthorizationLimit(props.user, props.companyId, props.cart);
|
|
7653
7733
|
const invoiceAddress = props.cart?.invoiceAddress;
|
|
7654
7734
|
const deliveryAddress = props.cart?.deliveryAddress;
|
|
7655
7735
|
const getCountryName = (code) => propellerV2CoreUi.getCountryName(code, props.countries);
|
|
@@ -7789,7 +7869,12 @@ function CartOverview(props) {
|
|
|
7789
7869
|
] });
|
|
7790
7870
|
})() })
|
|
7791
7871
|
] }) : null,
|
|
7792
|
-
showPurchaseButton ? /* @__PURE__ */ jsxRuntime.
|
|
7872
|
+
showPurchaseButton && overLimit ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "propeller-cart-overview__authorization-required text-sm text-muted-foreground mt-2", children: propellerV2CoreUi.getLabel(
|
|
7873
|
+
props.labels,
|
|
7874
|
+
"authorizationRequired",
|
|
7875
|
+
"This order exceeds your authorization limit. Request authorization from the cart to continue."
|
|
7876
|
+
) }) : null,
|
|
7877
|
+
showPurchaseButton && !overLimit ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7793
7878
|
"button",
|
|
7794
7879
|
{
|
|
7795
7880
|
type: "button",
|
|
@@ -8164,6 +8249,7 @@ var RESOLVE_SPEC = {
|
|
|
8164
8249
|
currency: { infra: "currency", default: "\u20AC" },
|
|
8165
8250
|
user: { infra: "user", default: null },
|
|
8166
8251
|
portalMode: { infra: "portalMode" },
|
|
8252
|
+
isAuthenticated: { infra: "isAuthenticated" },
|
|
8167
8253
|
columns: { grid: "columns", default: 3 },
|
|
8168
8254
|
showPrice: { grid: "showPrice" },
|
|
8169
8255
|
showStock: { grid: "showStock" },
|
|
@@ -8207,7 +8293,7 @@ function ClusterCard(rawProps) {
|
|
|
8207
8293
|
const textLabelValues = resolveAttributeValues(cluster, props.textLabels).map((value) => ({
|
|
8208
8294
|
value
|
|
8209
8295
|
}));
|
|
8210
|
-
const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
8296
|
+
const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
8211
8297
|
const defaultProductInventory = contentHidden ? void 0 : cluster?.defaultProduct?.inventory;
|
|
8212
8298
|
const useTax = props.includeTax !== void 0 ? !!props.includeTax : false;
|
|
8213
8299
|
const priceObj = contentHidden ? void 0 : cluster?.defaultProduct?.price;
|
|
@@ -8634,7 +8720,7 @@ function LoginToOrderButton(props) {
|
|
|
8634
8720
|
var LoginToOrderButton_default = LoginToOrderButton;
|
|
8635
8721
|
function ProductPriceDisplay(props) {
|
|
8636
8722
|
function isHidden2() {
|
|
8637
|
-
return propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
8723
|
+
return propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
8638
8724
|
}
|
|
8639
8725
|
function formatPrice17(value) {
|
|
8640
8726
|
if (value === null || value === void 0) return "";
|
|
@@ -8726,6 +8812,7 @@ var RESOLVE_SPEC2 = {
|
|
|
8726
8812
|
language: { infra: "language", default: "NL" },
|
|
8727
8813
|
includeTax: { infra: "includeTax" },
|
|
8728
8814
|
portalMode: { infra: "portalMode" },
|
|
8815
|
+
isAuthenticated: { infra: "isAuthenticated" },
|
|
8729
8816
|
configuration: { infra: "configuration" },
|
|
8730
8817
|
// Same entry ClusterCard has always had. Without it a shop priced in
|
|
8731
8818
|
// anything but euros had no route to the cards at all: the grid resolved the
|
|
@@ -8784,7 +8871,7 @@ function ProductCardRoot(rawProps) {
|
|
|
8784
8871
|
const language = props.language || "NL";
|
|
8785
8872
|
const product = props.product;
|
|
8786
8873
|
const isRow = props.columns === 1;
|
|
8787
|
-
const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
8874
|
+
const contentHidden = propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
8788
8875
|
const showStock = !!props.showStock && !contentHidden;
|
|
8789
8876
|
const showCta = props.allowAddToCart !== false || contentHidden;
|
|
8790
8877
|
const name = getProductName(product, language);
|
|
@@ -9081,6 +9168,7 @@ function ProductCardPrice(props) {
|
|
|
9081
9168
|
currency: resolved.currency,
|
|
9082
9169
|
language: resolved.language,
|
|
9083
9170
|
portalMode: resolved.portalMode,
|
|
9171
|
+
isAuthenticated: resolved.isAuthenticated,
|
|
9084
9172
|
user: resolved.user,
|
|
9085
9173
|
showLoginPrompt: false
|
|
9086
9174
|
}
|
|
@@ -9088,7 +9176,7 @@ function ProductCardPrice(props) {
|
|
|
9088
9176
|
}
|
|
9089
9177
|
function ProductCardAddToCart(props) {
|
|
9090
9178
|
const { product, resolved } = useProductCard();
|
|
9091
|
-
if (propellerV2CoreUi.isContentHidden(resolved.portalMode, resolved.user)) {
|
|
9179
|
+
if (propellerV2CoreUi.isContentHidden(resolved.portalMode, resolved.user, resolved.isAuthenticated)) {
|
|
9092
9180
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9093
9181
|
LoginToOrderButton_default,
|
|
9094
9182
|
{
|
|
@@ -9109,9 +9197,13 @@ function ProductCardAddToCart(props) {
|
|
|
9109
9197
|
allowIncrDecr: resolved.allowIncrDecr,
|
|
9110
9198
|
showModal: resolved.showModal,
|
|
9111
9199
|
enableStockValidation: resolved.enableStockValidation,
|
|
9200
|
+
onAddToCart: resolved.onAddToCart,
|
|
9112
9201
|
afterAddToCart: resolved.afterAddToCart,
|
|
9113
9202
|
onProceedToCheckout: resolved.onProceedToCheckout,
|
|
9114
9203
|
onRequestQuoteClick: resolved.onRequestQuoteClick,
|
|
9204
|
+
createCart: resolved.createCart,
|
|
9205
|
+
onCartCreated: resolved.onCartCreated,
|
|
9206
|
+
includeTax: resolved.includeTax,
|
|
9115
9207
|
labels: resolved.addToCartLabels
|
|
9116
9208
|
}
|
|
9117
9209
|
);
|
|
@@ -9234,7 +9326,7 @@ function ProductGrid(rawProps) {
|
|
|
9234
9326
|
}
|
|
9235
9327
|
function showAddToCart() {
|
|
9236
9328
|
const allow = props.allowAddToCart !== false;
|
|
9237
|
-
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user) && allow;
|
|
9329
|
+
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated) && allow;
|
|
9238
9330
|
}
|
|
9239
9331
|
function getSkeletonItems() {
|
|
9240
9332
|
const cols = props.columns || 3;
|
|
@@ -9512,7 +9604,7 @@ function GridFilters(rawProps) {
|
|
|
9512
9604
|
}
|
|
9513
9605
|
function showAvailability() {
|
|
9514
9606
|
if (!props.showAvailabilityFilter) return false;
|
|
9515
|
-
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
9607
|
+
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
9516
9608
|
}
|
|
9517
9609
|
function getFilterName(filter) {
|
|
9518
9610
|
return filter?.attributeDescription?.name || "";
|
|
@@ -10067,7 +10159,7 @@ function GridToolbar(rawProps) {
|
|
|
10067
10159
|
return badges;
|
|
10068
10160
|
}
|
|
10069
10161
|
function isPriceSortDisabled() {
|
|
10070
|
-
return propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
10162
|
+
return propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
10071
10163
|
}
|
|
10072
10164
|
function getAvailabilityLabel() {
|
|
10073
10165
|
const qty = props.minStock;
|
|
@@ -10469,13 +10561,14 @@ function MachineGrid(rawProps) {
|
|
|
10469
10561
|
// node query threads through useSpareParts.
|
|
10470
10562
|
imageVariantFilters: configuration?.imageVariantFiltersMedium
|
|
10471
10563
|
});
|
|
10472
|
-
const { displayParts, childMachines, isLoading: partsLoading, currentPage, totalPages } = useSpareParts({
|
|
10564
|
+
const { displayParts, childMachines, isLoading: partsLoading, currentPage, totalPages, notFound } = useSpareParts({
|
|
10473
10565
|
graphqlClient: props.graphqlClient,
|
|
10474
10566
|
// Idle at the root (no slug).
|
|
10475
10567
|
slug: isRoot ? void 0 : currentSlug,
|
|
10476
10568
|
term: term || void 0,
|
|
10477
10569
|
language,
|
|
10478
10570
|
machineLanguage,
|
|
10571
|
+
machineLanguages: rawProps.machineLanguages,
|
|
10479
10572
|
taxZone: props.taxZone,
|
|
10480
10573
|
user: props.user,
|
|
10481
10574
|
companyId: props.companyId,
|
|
@@ -10499,6 +10592,7 @@ function MachineGrid(rawProps) {
|
|
|
10499
10592
|
onMachineChange: setMachine
|
|
10500
10593
|
});
|
|
10501
10594
|
const machineName = machine ? propellerV2CoreUi.getLocalizedValue(machine.name, machineLanguage) : slugToLabel(currentSlug);
|
|
10595
|
+
const machineLabel = (key, fallback) => rawProps.machineCardLabels?.[key] ?? rawProps.toolbarLabels?.[key] ?? fallback;
|
|
10502
10596
|
const partProducts = React6.useMemo(
|
|
10503
10597
|
() => displayParts.map((p) => p.product).filter(Boolean),
|
|
10504
10598
|
[displayParts]
|
|
@@ -10573,6 +10667,12 @@ function MachineGrid(rawProps) {
|
|
|
10573
10667
|
] });
|
|
10574
10668
|
}
|
|
10575
10669
|
const hasParts = itemsFound > 0 || partProducts.length > 0;
|
|
10670
|
+
if (notFound && !partsLoading) {
|
|
10671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rawProps.className, children: [
|
|
10672
|
+
/* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "propeller-breadcrumbs mb-6", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex flex-wrap items-center gap-2 text-sm text-foreground-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: basePath, className: "hover:text-primary", children: rawProps.rootTitle ?? "Machines" }) }) }) }),
|
|
10673
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-12 text-center text-foreground-subtle", children: machineLabel("machineNotFound", "This machine could not be found.") })
|
|
10674
|
+
] });
|
|
10675
|
+
}
|
|
10576
10676
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rawProps.className, children: [
|
|
10577
10677
|
/* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "propeller-breadcrumbs mb-6", children: /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "flex flex-wrap items-center gap-2 text-sm text-foreground-subtle", children: [
|
|
10578
10678
|
/* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: basePath, className: "hover:text-primary", children: rawProps.rootTitle ?? "Machines" }) }),
|
|
@@ -10625,7 +10725,9 @@ function MachineGrid(rawProps) {
|
|
|
10625
10725
|
{
|
|
10626
10726
|
defaultValue: term,
|
|
10627
10727
|
onSubmit: submitSearch,
|
|
10628
|
-
|
|
10728
|
+
searchLabel: machineLabel("searchParts", "Search parts\u2026"),
|
|
10729
|
+
searchAriaLabel: machineLabel("searchParts", "Search parts"),
|
|
10730
|
+
buttonLabel: propellerV2CoreUi.getLabel(rawProps.toolbarLabels, "search", "Search")
|
|
10629
10731
|
},
|
|
10630
10732
|
term
|
|
10631
10733
|
),
|
|
@@ -10676,7 +10778,7 @@ function MachineGrid(rawProps) {
|
|
|
10676
10778
|
const qty = quantityBySku.get(product.sku);
|
|
10677
10779
|
if (!qty) return null;
|
|
10678
10780
|
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "propeller-spare-part__quantity text-sm text-foreground-subtle", children: [
|
|
10679
|
-
|
|
10781
|
+
machineLabel("quantityInMachine", "Qty in machine"),
|
|
10680
10782
|
": ",
|
|
10681
10783
|
qty
|
|
10682
10784
|
] });
|
|
@@ -10708,8 +10810,8 @@ function MachinePartsSearch(props) {
|
|
|
10708
10810
|
onKeyDown: (e) => {
|
|
10709
10811
|
if (e.key === "Enter") submit();
|
|
10710
10812
|
},
|
|
10711
|
-
placeholder: props.
|
|
10712
|
-
"aria-label": props.
|
|
10813
|
+
placeholder: props.searchLabel,
|
|
10814
|
+
"aria-label": props.searchAriaLabel,
|
|
10713
10815
|
className: "w-full rounded border border-border bg-background px-3 py-2"
|
|
10714
10816
|
}
|
|
10715
10817
|
),
|
|
@@ -10719,7 +10821,7 @@ function MachinePartsSearch(props) {
|
|
|
10719
10821
|
type: "button",
|
|
10720
10822
|
onClick: submit,
|
|
10721
10823
|
className: "rounded bg-primary px-4 py-2 text-primary-foreground",
|
|
10722
|
-
children: props.
|
|
10824
|
+
children: props.buttonLabel
|
|
10723
10825
|
}
|
|
10724
10826
|
)
|
|
10725
10827
|
] });
|
|
@@ -10920,7 +11022,7 @@ function ClusterOptions(rawProps) {
|
|
|
10920
11022
|
const language = props.language;
|
|
10921
11023
|
const options = props.options || [];
|
|
10922
11024
|
const sel = selectedProductIds;
|
|
10923
|
-
const hidePrices = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
11025
|
+
const hidePrices = propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
10924
11026
|
return options.filter((option) => option.hidden !== propellerSdkV2.YesNo.Y).map((option) => {
|
|
10925
11027
|
const idStr = option.id.toString();
|
|
10926
11028
|
const selectedProductId = sel[idStr] || "";
|
|
@@ -11104,7 +11206,11 @@ function CompanySwitcher(props) {
|
|
|
11104
11206
|
type: "button",
|
|
11105
11207
|
"aria-haspopup": "listbox",
|
|
11106
11208
|
"aria-label": propellerV2CoreUi.getLabel(props.labels, "switchCompanyAriaLabel", "Switch company"),
|
|
11107
|
-
className:
|
|
11209
|
+
className: cn(
|
|
11210
|
+
// `text-inherit`: this sits in the host's header, which may be dark or
|
|
11211
|
+
// light. See the note on AccountIconAndMenu's trigger.
|
|
11212
|
+
`propeller-company-switcher__trigger flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium transition-colors text-inherit${props.triggerClassName ? " " + props.triggerClassName : ""}`
|
|
11213
|
+
),
|
|
11108
11214
|
onClick: (event) => toggleDropdown(),
|
|
11109
11215
|
"aria-expanded": isOpen,
|
|
11110
11216
|
children: [
|
|
@@ -15079,7 +15185,7 @@ function PriceToggle(props) {
|
|
|
15079
15185
|
var PriceToggle_default = PriceToggle;
|
|
15080
15186
|
function ProductBulkPrices(props) {
|
|
15081
15187
|
const includeTax = !!props.includeTax;
|
|
15082
|
-
const isHidden2 = propellerV2CoreUi.isContentHidden(props.portalMode, props.user);
|
|
15188
|
+
const isHidden2 = propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated);
|
|
15083
15189
|
function getTierQuantity(tier) {
|
|
15084
15190
|
const discount = tier.discount;
|
|
15085
15191
|
return discount?.quantityFrom ?? tier.quantity ?? null;
|
|
@@ -15626,14 +15732,10 @@ function ProductDownloads(props) {
|
|
|
15626
15732
|
const hasItems = items.length > 0;
|
|
15627
15733
|
const lang = props.language || "NL";
|
|
15628
15734
|
function getDocumentUrl(doc) {
|
|
15629
|
-
|
|
15630
|
-
const match = docs.find((d) => d.language === lang);
|
|
15631
|
-
return match?.originalUrl || docs?.[0]?.originalUrl || "";
|
|
15735
|
+
return propellerV2CoreUi.resolveLanguageEntry(doc.documents, lang)?.originalUrl || "";
|
|
15632
15736
|
}
|
|
15633
15737
|
function getDocumentName(doc) {
|
|
15634
|
-
|
|
15635
|
-
const match = alts.find((a) => a.language === lang);
|
|
15636
|
-
return match?.value || alts?.[0]?.value || "Download";
|
|
15738
|
+
return propellerV2CoreUi.getLanguageString(doc.alt, lang, "Download");
|
|
15637
15739
|
}
|
|
15638
15740
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(`propeller-product-downloads ${props.className || ""}`), children: [
|
|
15639
15741
|
hasItems ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "propeller-product-downloads__title text-base font-semibold text-foreground mb-3", children: propellerV2CoreUi.getLabel(props.labels, "title", "Downloads") }) : null,
|
|
@@ -15839,12 +15941,14 @@ function ProductGallery(props) {
|
|
|
15839
15941
|
var ProductGallery_default = ProductGallery;
|
|
15840
15942
|
function pickImageUrl(mediaItems, target) {
|
|
15841
15943
|
if (!mediaItems || mediaItems.length === 0) return null;
|
|
15944
|
+
const targetUpper = (target || "").toUpperCase();
|
|
15945
|
+
const langMatches = (value) => (value || "").toUpperCase() === targetUpper;
|
|
15842
15946
|
for (const m of mediaItems) {
|
|
15843
|
-
const match = m.imageVariants?.find((v) => v.language
|
|
15947
|
+
const match = m.imageVariants?.find((v) => langMatches(v.language) && v.url);
|
|
15844
15948
|
if (match?.url) return match.url;
|
|
15845
15949
|
}
|
|
15846
15950
|
for (const m of mediaItems) {
|
|
15847
|
-
const match = m.images?.find((i) => i.language
|
|
15951
|
+
const match = m.images?.find((i) => langMatches(i.language) && i.originalUrl);
|
|
15848
15952
|
if (match?.originalUrl) return match.originalUrl;
|
|
15849
15953
|
}
|
|
15850
15954
|
for (const m of mediaItems) {
|
|
@@ -16172,6 +16276,7 @@ function ProductInfoPrice(props = {}) {
|
|
|
16172
16276
|
currency: derived.currency,
|
|
16173
16277
|
taxZone: derived.taxZone,
|
|
16174
16278
|
portalMode: derived.portalMode,
|
|
16279
|
+
isAuthenticated: resolved.isAuthenticated,
|
|
16175
16280
|
user: derived.user,
|
|
16176
16281
|
labels: derived.labels,
|
|
16177
16282
|
className: props.className
|
|
@@ -16181,7 +16286,7 @@ function ProductInfoPrice(props = {}) {
|
|
|
16181
16286
|
function ProductInfoStock(props = {}) {
|
|
16182
16287
|
const { product, resolved, derived } = useProductInfoContext();
|
|
16183
16288
|
if (!product.inventory) return null;
|
|
16184
|
-
if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user)) return null;
|
|
16289
|
+
if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user, resolved.isAuthenticated)) return null;
|
|
16185
16290
|
const Injected = resolved.stockComponent;
|
|
16186
16291
|
if (Injected) {
|
|
16187
16292
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -16208,7 +16313,7 @@ function ProductInfoStock(props = {}) {
|
|
|
16208
16313
|
}
|
|
16209
16314
|
function ProductInfoAddToCart(props = {}) {
|
|
16210
16315
|
const { product, resolved, derived } = useProductInfoContext();
|
|
16211
|
-
if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user)) {
|
|
16316
|
+
if (propellerV2CoreUi.isContentHidden(derived.portalMode, resolved.user, resolved.isAuthenticated)) {
|
|
16212
16317
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16213
16318
|
LoginToOrderButton_default,
|
|
16214
16319
|
{
|
|
@@ -16220,7 +16325,18 @@ function ProductInfoAddToCart(props = {}) {
|
|
|
16220
16325
|
}
|
|
16221
16326
|
const Injected = resolved.addToCartComponent;
|
|
16222
16327
|
if (Injected) {
|
|
16223
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16328
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16329
|
+
Injected,
|
|
16330
|
+
{
|
|
16331
|
+
product,
|
|
16332
|
+
cartId: resolved.cartId,
|
|
16333
|
+
createCart: resolved.createCart,
|
|
16334
|
+
onCartCreated: resolved.onCartCreated,
|
|
16335
|
+
includeTax: derived.useTax,
|
|
16336
|
+
labels: derived.labels,
|
|
16337
|
+
className: props.className
|
|
16338
|
+
}
|
|
16339
|
+
);
|
|
16224
16340
|
}
|
|
16225
16341
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16226
16342
|
AddToCart_default,
|
|
@@ -16229,6 +16345,9 @@ function ProductInfoAddToCart(props = {}) {
|
|
|
16229
16345
|
user: derived.user,
|
|
16230
16346
|
currency: derived.currency,
|
|
16231
16347
|
product,
|
|
16348
|
+
cartId: resolved.cartId,
|
|
16349
|
+
createCart: resolved.createCart,
|
|
16350
|
+
onCartCreated: resolved.onCartCreated,
|
|
16232
16351
|
configuration: resolved.configuration,
|
|
16233
16352
|
companyId: resolved.companyId,
|
|
16234
16353
|
includeTax: derived.useTax,
|
|
@@ -16282,6 +16401,7 @@ function ProductInfoBulkPrices(props = {}) {
|
|
|
16282
16401
|
bulkPrices: product.bulkPrices,
|
|
16283
16402
|
includeTax: derived.useTax,
|
|
16284
16403
|
portalMode: derived.portalMode,
|
|
16404
|
+
isAuthenticated: resolved.isAuthenticated,
|
|
16285
16405
|
user: derived.user,
|
|
16286
16406
|
taxZone: derived.taxZone,
|
|
16287
16407
|
currency: derived.currency,
|
|
@@ -16444,7 +16564,7 @@ function ProductSlider(rawProps) {
|
|
|
16444
16564
|
}
|
|
16445
16565
|
function showAddToCart() {
|
|
16446
16566
|
const allow = props.allowAddToCart !== false;
|
|
16447
|
-
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user) && allow;
|
|
16567
|
+
return !propellerV2CoreUi.isContentHidden(props.portalMode, props.user, props.isAuthenticated) && allow;
|
|
16448
16568
|
}
|
|
16449
16569
|
function isCluster(item) {
|
|
16450
16570
|
return "clusterId" in item && !("productId" in item);
|
|
@@ -16748,14 +16868,10 @@ function ProductVideos(props) {
|
|
|
16748
16868
|
const hasItems = items.length > 0;
|
|
16749
16869
|
const lang = props.language || "NL";
|
|
16750
16870
|
function getVideoUri(video) {
|
|
16751
|
-
|
|
16752
|
-
const match = vids.find((v) => v.language === lang);
|
|
16753
|
-
return match?.uri || vids?.[0]?.uri || "";
|
|
16871
|
+
return propellerV2CoreUi.getLanguageUri(video.videos, lang, "");
|
|
16754
16872
|
}
|
|
16755
16873
|
function getVideoTitle(video) {
|
|
16756
|
-
|
|
16757
|
-
const match = alts.find((a) => a.language === lang);
|
|
16758
|
-
return match?.value || alts?.[0]?.value || "Video";
|
|
16874
|
+
return propellerV2CoreUi.getLanguageString(video.alt, lang, "Video");
|
|
16759
16875
|
}
|
|
16760
16876
|
function isEmbeddable(uri) {
|
|
16761
16877
|
return uri.includes("youtube.com") || uri.includes("youtu.be") || uri.includes("vimeo.com");
|