@pagamio/frontend-commons-lib 0.8.337 → 0.8.338
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.
|
@@ -18,4 +18,4 @@ export interface ProductCardProps {
|
|
|
18
18
|
}) => React.ReactNode;
|
|
19
19
|
onNavigate?: (productUrl: string) => void;
|
|
20
20
|
}
|
|
21
|
-
export declare function ProductCard({ product, onAddToCart, isAddingToCart,
|
|
21
|
+
export declare function ProductCard({ product, onAddToCart, isAddingToCart, basePath, featured, linkSuffix, currency, renderLink, onNavigate, }: ProductCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,14 +4,17 @@ import { cn } from '../../helpers/utils';
|
|
|
4
4
|
import { formatPrice } from '../../helpers/utils';
|
|
5
5
|
import ImageComponent from '../ui/ImageComponent';
|
|
6
6
|
const LOW_STOCK_THRESHOLD = 5;
|
|
7
|
-
export function ProductCard({ product, onAddToCart, isAddingToCart,
|
|
7
|
+
export function ProductCard({ product, onAddToCart, isAddingToCart, basePath = '/shop', featured = false, linkSuffix, currency = 'ZAR', renderLink, onNavigate, }) {
|
|
8
8
|
// Non-stock products (services / fees / digital goods) have no
|
|
9
9
|
// StockItem rows by design — they're always available
|
|
10
10
|
const isNonStock = product.isStockItem === false;
|
|
11
11
|
const hasStock = isNonStock || product.totalStock > 0;
|
|
12
12
|
const isLowStock = !isNonStock && hasStock && product.totalStock <= LOW_STOCK_THRESHOLD;
|
|
13
13
|
const isBackorderable = product.allowBackorders === true;
|
|
14
|
-
|
|
14
|
+
// `storeId` is informational only — the backend auto-picks a fulfillment
|
|
15
|
+
// store when one isn't explicitly supplied. The CTA stays enabled as
|
|
16
|
+
// long as the product has stock (or is back-orderable).
|
|
17
|
+
const canAddToCart = hasStock || isBackorderable;
|
|
15
18
|
const hasVariants = product.variants && product.variants.length > 0;
|
|
16
19
|
const priceDisplay = (() => {
|
|
17
20
|
if (!hasVariants) {
|
|
@@ -39,8 +42,6 @@ export function ProductCard({ product, onAddToCart, isAddingToCart, storeId, bas
|
|
|
39
42
|
}
|
|
40
43
|
return (_jsx("a", { href: productUrl, className: className, tabIndex: tabIndex, "aria-label": ariaLabel, children: children }));
|
|
41
44
|
};
|
|
42
|
-
// CTA state — kept identical to the previous behaviour so production code
|
|
43
|
-
// paths (backorder, select-store, sold-out, adding spinner) still work.
|
|
44
45
|
const ctaDisabled = hasVariants ? !hasStock && !isBackorderable : !canAddToCart || !!isAddingToCart;
|
|
45
46
|
const ctaLabel = hasVariants
|
|
46
47
|
? !hasStock && !isBackorderable
|
|
@@ -48,13 +49,11 @@ export function ProductCard({ product, onAddToCart, isAddingToCart, storeId, bas
|
|
|
48
49
|
: 'Options'
|
|
49
50
|
: isAddingToCart
|
|
50
51
|
? 'Adding…'
|
|
51
|
-
:
|
|
52
|
-
? '
|
|
53
|
-
:
|
|
54
|
-
? '
|
|
55
|
-
:
|
|
56
|
-
? 'Backorder'
|
|
57
|
-
: 'Sold Out';
|
|
52
|
+
: hasStock
|
|
53
|
+
? 'Add to cart'
|
|
54
|
+
: isBackorderable
|
|
55
|
+
? 'Backorder'
|
|
56
|
+
: 'Sold Out';
|
|
58
57
|
return (_jsxs("article", { className: cn('group flex h-full flex-col overflow-hidden bg-background', 'rounded-lg border', 'hover:shadow-md', featured ? 'border-foreground shadow-md' : 'border-border'), children: [_jsxs(LinkWrapper, { className: "relative block aspect-square w-full overflow-hidden bg-muted", tabIndex: -1, ariaLabel: `View ${product.name}`, children: [product.imageUrl ? (_jsx(ImageComponent, { src: product.imageUrl, alt: product.name, fill: true, className: "object-cover", sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw" })) : (_jsx("div", { className: "flex h-full w-full items-center justify-center bg-muted text-muted-foreground", children: _jsx("svg", { className: "h-8 w-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) })), featured && hasStock && (_jsx("span", { className: "absolute left-2 top-2 z-10 rounded-md bg-foreground px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-background", children: "Popular" })), !hasStock && isBackorderable && (_jsx("span", { className: "absolute left-2 top-2 z-10 rounded-md bg-warning px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-white", children: "Backorder" })), !hasStock && !isBackorderable && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center bg-black/40 text-[11px] font-bold uppercase tracking-wide text-white", children: "Out of stock" }))] }), _jsxs("section", { className: "flex flex-1 flex-col gap-1 p-3", children: [_jsxs(LinkWrapper, { className: "contents", children: [_jsx("span", { className: "text-base font-bold leading-none text-foreground", children: priceDisplay }), _jsx("span", { className: "line-clamp-2 min-h-[2.5rem] text-sm leading-snug text-foreground transition-colors group-hover:text-primary", children: product.name })] }), isLowStock && _jsxs("span", { className: "text-[10px] font-medium text-warning", children: ["Only ", product.totalStock, " left"] }), _jsxs("button", { type: "button", disabled: ctaDisabled, onClick: (e) => {
|
|
59
58
|
e.preventDefault();
|
|
60
59
|
e.stopPropagation();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.338",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|