@propeller-commerce/propeller-v2-react-ui 0.18.0 → 0.19.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 +102 -12
- package/dist/index.cjs +335 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -10
- package/dist/index.d.ts +103 -10
- package/dist/index.js +337 -219
- package/dist/index.js.map +1 -1
- package/dist/pure.cjs +18 -16
- package/dist/pure.cjs.map +1 -1
- package/dist/pure.d.cts +47 -1
- package/dist/pure.d.ts +47 -1
- package/dist/pure.js +19 -17
- package/dist/pure.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/pure.d.cts
CHANGED
|
@@ -252,9 +252,22 @@ interface OrderItemCardProps {
|
|
|
252
252
|
* This component is RSC-safe (no hooks, no context), so the host has to pass
|
|
253
253
|
* it — there is nothing to read it from. Without it a non-default storefront
|
|
254
254
|
* renders default-language names and, worse, default-language slugs in the
|
|
255
|
-
* links
|
|
255
|
+
* links.
|
|
256
256
|
*/
|
|
257
257
|
language?: string;
|
|
258
|
+
/**
|
|
259
|
+
* URL builders from the host's configuration. Supply them and the item link
|
|
260
|
+
* is generated the same way every other link on the storefront is — which is
|
|
261
|
+
* what carries the locale prefix. Without it the component falls back to a
|
|
262
|
+
* bare `/product/:id/:slug`, and on a prefixed storefront that link drops the
|
|
263
|
+
* visitor onto the default language.
|
|
264
|
+
*/
|
|
265
|
+
configuration?: {
|
|
266
|
+
urls?: {
|
|
267
|
+
getProductUrl?: (product: Product, language?: string) => string;
|
|
268
|
+
getClusterUrl?: (cluster: Cluster, language?: string) => string;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
258
271
|
/** Should the item title be a link to the PDP */
|
|
259
272
|
titleLinkable?: boolean;
|
|
260
273
|
/** Display a small thumbnail of the order item */
|
|
@@ -286,6 +299,15 @@ interface OrderItemCardProps {
|
|
|
286
299
|
/**
|
|
287
300
|
* Renders a single order line item as a table row (with optional indented
|
|
288
301
|
* child-item rows), showing image, SKU, quantity, discount and price.
|
|
302
|
+
*
|
|
303
|
+
* `orderItem.product` is optional and really can be absent: a product that is
|
|
304
|
+
* hidden, withdrawn or deleted from the catalog still appears on the orders and
|
|
305
|
+
* quotes it was sold on, but the API returns no product record for it. Every
|
|
306
|
+
* product-derived value below therefore falls back to the order item, which
|
|
307
|
+
* carries its own snapshot of the line — name, sku, quantity and prices — taken
|
|
308
|
+
* when the order was placed. Such a row renders as plain text: the placeholder
|
|
309
|
+
* thumbnail, the untranslated `orderItem.name` (there are no localized names to
|
|
310
|
+
* resolve), and no PDP link (there are no slugs to build one from).
|
|
289
311
|
*/
|
|
290
312
|
declare function OrderItemCard(props: OrderItemCardProps): React.JSX.Element;
|
|
291
313
|
|
|
@@ -297,6 +319,12 @@ declare function OrderItemCard(props: OrderItemCardProps): React.JSX.Element;
|
|
|
297
319
|
*/
|
|
298
320
|
|
|
299
321
|
interface OrderSummaryProps {
|
|
322
|
+
/**
|
|
323
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
324
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
325
|
+
* the language the shopper is reading.
|
|
326
|
+
*/
|
|
327
|
+
language?: string;
|
|
300
328
|
/** The order object from propeller-sdk-v2 */
|
|
301
329
|
order: any;
|
|
302
330
|
/** The CSS class for the order summary container */
|
|
@@ -360,6 +388,12 @@ declare function OrderSummary(props: OrderSummaryProps): React.JSX.Element;
|
|
|
360
388
|
*/
|
|
361
389
|
|
|
362
390
|
interface OrderTotalsProps {
|
|
391
|
+
/**
|
|
392
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
393
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
394
|
+
* the language the shopper is reading.
|
|
395
|
+
*/
|
|
396
|
+
language?: string;
|
|
363
397
|
/** The order/quote used to populate the summary data */
|
|
364
398
|
order: Order;
|
|
365
399
|
/** Order summary block title */
|
|
@@ -397,6 +431,12 @@ declare function OrderTotals(props: OrderTotalsProps): React.JSX.Element;
|
|
|
397
431
|
*/
|
|
398
432
|
|
|
399
433
|
interface ProductBulkPricesProps {
|
|
434
|
+
/**
|
|
435
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
436
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
437
|
+
* the language the shopper is reading.
|
|
438
|
+
*/
|
|
439
|
+
language?: string;
|
|
400
440
|
/**
|
|
401
441
|
* Bulk price tiers from the product.
|
|
402
442
|
* Obtain from `product.bulkPrices`.
|
|
@@ -473,6 +513,12 @@ declare function ProductDownloads(props: ProductDownloadsProps): React.JSX.Eleme
|
|
|
473
513
|
*/
|
|
474
514
|
|
|
475
515
|
interface ProductPriceProps {
|
|
516
|
+
/**
|
|
517
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
518
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
519
|
+
* the language the shopper is reading.
|
|
520
|
+
*/
|
|
521
|
+
language?: string;
|
|
476
522
|
/**
|
|
477
523
|
* ProductPrice object from the product.
|
|
478
524
|
* Obtain from `product.price`.
|
package/dist/pure.d.ts
CHANGED
|
@@ -252,9 +252,22 @@ interface OrderItemCardProps {
|
|
|
252
252
|
* This component is RSC-safe (no hooks, no context), so the host has to pass
|
|
253
253
|
* it — there is nothing to read it from. Without it a non-default storefront
|
|
254
254
|
* renders default-language names and, worse, default-language slugs in the
|
|
255
|
-
* links
|
|
255
|
+
* links.
|
|
256
256
|
*/
|
|
257
257
|
language?: string;
|
|
258
|
+
/**
|
|
259
|
+
* URL builders from the host's configuration. Supply them and the item link
|
|
260
|
+
* is generated the same way every other link on the storefront is — which is
|
|
261
|
+
* what carries the locale prefix. Without it the component falls back to a
|
|
262
|
+
* bare `/product/:id/:slug`, and on a prefixed storefront that link drops the
|
|
263
|
+
* visitor onto the default language.
|
|
264
|
+
*/
|
|
265
|
+
configuration?: {
|
|
266
|
+
urls?: {
|
|
267
|
+
getProductUrl?: (product: Product, language?: string) => string;
|
|
268
|
+
getClusterUrl?: (cluster: Cluster, language?: string) => string;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
258
271
|
/** Should the item title be a link to the PDP */
|
|
259
272
|
titleLinkable?: boolean;
|
|
260
273
|
/** Display a small thumbnail of the order item */
|
|
@@ -286,6 +299,15 @@ interface OrderItemCardProps {
|
|
|
286
299
|
/**
|
|
287
300
|
* Renders a single order line item as a table row (with optional indented
|
|
288
301
|
* child-item rows), showing image, SKU, quantity, discount and price.
|
|
302
|
+
*
|
|
303
|
+
* `orderItem.product` is optional and really can be absent: a product that is
|
|
304
|
+
* hidden, withdrawn or deleted from the catalog still appears on the orders and
|
|
305
|
+
* quotes it was sold on, but the API returns no product record for it. Every
|
|
306
|
+
* product-derived value below therefore falls back to the order item, which
|
|
307
|
+
* carries its own snapshot of the line — name, sku, quantity and prices — taken
|
|
308
|
+
* when the order was placed. Such a row renders as plain text: the placeholder
|
|
309
|
+
* thumbnail, the untranslated `orderItem.name` (there are no localized names to
|
|
310
|
+
* resolve), and no PDP link (there are no slugs to build one from).
|
|
289
311
|
*/
|
|
290
312
|
declare function OrderItemCard(props: OrderItemCardProps): React.JSX.Element;
|
|
291
313
|
|
|
@@ -297,6 +319,12 @@ declare function OrderItemCard(props: OrderItemCardProps): React.JSX.Element;
|
|
|
297
319
|
*/
|
|
298
320
|
|
|
299
321
|
interface OrderSummaryProps {
|
|
322
|
+
/**
|
|
323
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
324
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
325
|
+
* the language the shopper is reading.
|
|
326
|
+
*/
|
|
327
|
+
language?: string;
|
|
300
328
|
/** The order object from propeller-sdk-v2 */
|
|
301
329
|
order: any;
|
|
302
330
|
/** The CSS class for the order summary container */
|
|
@@ -360,6 +388,12 @@ declare function OrderSummary(props: OrderSummaryProps): React.JSX.Element;
|
|
|
360
388
|
*/
|
|
361
389
|
|
|
362
390
|
interface OrderTotalsProps {
|
|
391
|
+
/**
|
|
392
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
393
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
394
|
+
* the language the shopper is reading.
|
|
395
|
+
*/
|
|
396
|
+
language?: string;
|
|
363
397
|
/** The order/quote used to populate the summary data */
|
|
364
398
|
order: Order;
|
|
365
399
|
/** Order summary block title */
|
|
@@ -397,6 +431,12 @@ declare function OrderTotals(props: OrderTotalsProps): React.JSX.Element;
|
|
|
397
431
|
*/
|
|
398
432
|
|
|
399
433
|
interface ProductBulkPricesProps {
|
|
434
|
+
/**
|
|
435
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
436
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
437
|
+
* the language the shopper is reading.
|
|
438
|
+
*/
|
|
439
|
+
language?: string;
|
|
400
440
|
/**
|
|
401
441
|
* Bulk price tiers from the product.
|
|
402
442
|
* Obtain from `product.bulkPrices`.
|
|
@@ -473,6 +513,12 @@ declare function ProductDownloads(props: ProductDownloadsProps): React.JSX.Eleme
|
|
|
473
513
|
*/
|
|
474
514
|
|
|
475
515
|
interface ProductPriceProps {
|
|
516
|
+
/**
|
|
517
|
+
* Storefront language ('EN', 'NL', …). Decides the number format prices are
|
|
518
|
+
* rendered in — without it they fall back to Dutch separators regardless of
|
|
519
|
+
* the language the shopper is reading.
|
|
520
|
+
*/
|
|
521
|
+
language?: string;
|
|
476
522
|
/**
|
|
477
523
|
* ProductPrice object from the product.
|
|
478
524
|
* Obtain from `product.price`.
|
package/dist/pure.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildClusterJsonLd, safeJsonStringify, buildItemListJsonLd, buildProductJsonLd, getLabel, getLocalizedValue, isContentHidden, formatPrice, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
|
|
1
|
+
import { buildClusterJsonLd, safeJsonStringify, buildItemListJsonLd, buildProductJsonLd, getLabel, getLocalizedValue, isContentHidden, formatPrice, localeForLanguage, getCountryName } from '@propeller-commerce/propeller-v2-core-ui';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import { twMerge } from 'tailwind-merge';
|
|
4
4
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
@@ -247,20 +247,21 @@ var ItemStock_default = React.memo(ItemStock);
|
|
|
247
247
|
function getProductName(orderItem, language) {
|
|
248
248
|
return getLocalizedValue(orderItem?.product?.names, language, "") || orderItem?.name || "Unknown Product";
|
|
249
249
|
}
|
|
250
|
-
function getClusterUrl(orderItem, language) {
|
|
250
|
+
function getClusterUrl(orderItem, language, urls) {
|
|
251
251
|
const cluster = orderItem?.product?.cluster;
|
|
252
252
|
if (!cluster) return "";
|
|
253
253
|
const id = cluster.clusterId;
|
|
254
254
|
const slug = getLocalizedValue(cluster.slugs, language, "");
|
|
255
255
|
if (!id || !slug) return "";
|
|
256
|
-
return `/cluster/${id}/${slug}`;
|
|
256
|
+
return urls?.getClusterUrl?.(cluster, language) || `/cluster/${id}/${slug}`;
|
|
257
257
|
}
|
|
258
|
-
function getProductUrl(orderItem, language) {
|
|
259
|
-
const cu = getClusterUrl(orderItem, language);
|
|
258
|
+
function getProductUrl(orderItem, language, urls) {
|
|
259
|
+
const cu = getClusterUrl(orderItem, language, urls);
|
|
260
260
|
if (cu) return cu;
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
|
|
261
|
+
const product = orderItem?.product;
|
|
262
|
+
const id = product?.productId;
|
|
263
|
+
const slug = getLocalizedValue(product?.slugs, language, "");
|
|
264
|
+
if (id && slug) return urls?.getProductUrl?.(product, language) || `/product/${id}/${slug}`;
|
|
264
265
|
return "";
|
|
265
266
|
}
|
|
266
267
|
function OrderItemCard(props) {
|
|
@@ -277,7 +278,7 @@ function OrderItemCard(props) {
|
|
|
277
278
|
const productName = getProductName(item, props.language);
|
|
278
279
|
const productSku = item?.product?.sku || item?.sku || "";
|
|
279
280
|
const productImage = item?.product?.media?.images?.items?.[0]?.imageVariants?.[0]?.url || "";
|
|
280
|
-
const productUrl = getProductUrl(item, props.language);
|
|
281
|
+
const productUrl = getProductUrl(item, props.language, props.configuration?.urls);
|
|
281
282
|
const quantity = item?.quantity || 0;
|
|
282
283
|
const priceTotal = item?.priceTotal || 0;
|
|
283
284
|
const discount = item?.discount || 0;
|
|
@@ -290,7 +291,7 @@ function OrderItemCard(props) {
|
|
|
290
291
|
return props.formatPrice(price);
|
|
291
292
|
}
|
|
292
293
|
if (!price && price !== 0) return "-";
|
|
293
|
-
return formatPrice(price, { symbol: props.currency ?? "\u20AC" });
|
|
294
|
+
return formatPrice(price, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
|
|
294
295
|
}
|
|
295
296
|
const discountDisplay = discountPercentage > 0 ? `${formatItemPrice(discount)} (${discountPercentage.toFixed(2).replace(".", ",")}%)` : formatItemPrice(discount);
|
|
296
297
|
return /* @__PURE__ */ jsxs("tbody", { className: "propeller-order-item-card", children: [
|
|
@@ -369,11 +370,11 @@ function OrderItemCard(props) {
|
|
|
369
370
|
className: isChildItem ? "propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-2 text-right whitespace-nowrap text-sm text-muted-foreground" : "propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-4 text-right whitespace-nowrap",
|
|
370
371
|
children: (() => {
|
|
371
372
|
const PriceImpl = props.priceComponent;
|
|
372
|
-
if (PriceImpl) {
|
|
373
|
+
if (PriceImpl && item?.product?.price) {
|
|
373
374
|
return /* @__PURE__ */ jsx(
|
|
374
375
|
PriceImpl,
|
|
375
376
|
{
|
|
376
|
-
price: item
|
|
377
|
+
price: item.product.price,
|
|
377
378
|
currency: props.currency,
|
|
378
379
|
labels: props.labels
|
|
379
380
|
}
|
|
@@ -431,7 +432,7 @@ function OrderSummary(props) {
|
|
|
431
432
|
if (props.formatPrice) {
|
|
432
433
|
return props.formatPrice(price);
|
|
433
434
|
}
|
|
434
|
-
return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
|
|
435
|
+
return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
|
|
435
436
|
}
|
|
436
437
|
function numericDate(dateString) {
|
|
437
438
|
const d = new Date(dateString);
|
|
@@ -539,7 +540,7 @@ function OrderTotals(props) {
|
|
|
539
540
|
const postageData = props.order?.postageData;
|
|
540
541
|
function formatItemPrice(price) {
|
|
541
542
|
if (props.formatPrice) return props.formatPrice(price);
|
|
542
|
-
return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC" });
|
|
543
|
+
return formatPrice(price || 0, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
|
|
543
544
|
}
|
|
544
545
|
const subtotal = total?.gross || 0;
|
|
545
546
|
const hasDiscount = !!total && total.discountType !== OrderDiscountType.N && total.discountValue > 0;
|
|
@@ -667,7 +668,7 @@ function ProductBulkPrices(props) {
|
|
|
667
668
|
function getPrice(tier) {
|
|
668
669
|
const value = includeTax ? tier.net : tier.gross;
|
|
669
670
|
if (value === null || value === void 0) return "";
|
|
670
|
-
return formatPrice(value, { symbol: props.currency ?? "\u20AC" });
|
|
671
|
+
return formatPrice(value, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
|
|
671
672
|
}
|
|
672
673
|
function getQuantityLabel(tier, index) {
|
|
673
674
|
const discount = tier.discount;
|
|
@@ -678,13 +679,14 @@ function ProductBulkPrices(props) {
|
|
|
678
679
|
if (nextQty) return `${qty}\u2013${nextQty - 1}`;
|
|
679
680
|
return `${qty}+`;
|
|
680
681
|
}
|
|
682
|
+
const title = props.labels?.title ?? "Volume pricing";
|
|
681
683
|
return /* @__PURE__ */ jsx(Fragment, { children: !isHidden && hasItems ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
|
|
682
684
|
"div",
|
|
683
685
|
{
|
|
684
686
|
className: cn(`propeller-product-bulk-prices ${props.className || ""}`),
|
|
685
687
|
"data-include-tax": includeTax ? "true" : "false",
|
|
686
688
|
children: [
|
|
687
|
-
|
|
689
|
+
title ? /* @__PURE__ */ jsx("h3", { className: "propeller-product-bulk-prices__title text-base font-semibold text-foreground mb-3", children: title }) : null,
|
|
688
690
|
/* @__PURE__ */ jsx("div", { className: "propeller-product-bulk-prices__table-wrapper overflow-hidden rounded-container border border-border", children: /* @__PURE__ */ jsxs("table", { className: "propeller-product-bulk-prices__table w-full text-sm", children: [
|
|
689
691
|
/* @__PURE__ */ jsx("thead", { className: "propeller-product-bulk-prices__thead bg-muted/50", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
690
692
|
/* @__PURE__ */ jsx("th", { className: "propeller-product-bulk-prices__th propeller-product-bulk-prices__th--quantity px-4 py-2 text-left font-medium text-muted-foreground", children: getLabel(props.labels, "quantityFrom", "Qty from") }),
|
|
@@ -781,7 +783,7 @@ function ProductPriceDisplay(props) {
|
|
|
781
783
|
}
|
|
782
784
|
function formatPrice5(value) {
|
|
783
785
|
if (value === null || value === void 0) return "";
|
|
784
|
-
return formatPrice(value, { symbol: props.currency ?? "\u20AC" });
|
|
786
|
+
return formatPrice(value, { symbol: props.currency ?? "\u20AC", locale: localeForLanguage(props.language) });
|
|
785
787
|
}
|
|
786
788
|
function getOptionsTotal(useNet) {
|
|
787
789
|
const options = props.options || [];
|