Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion apps/storefront/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
languageHomePath,
resolveLanguageUrlAction,
useCart,
useCurrency,
useLanguage,
useLayoutPreferences,
useT,
Expand Down Expand Up @@ -42,6 +43,7 @@ import { submitNewsletterSubmission } from "./lib/submissions";
import { isBackendConfigured, STOREFRONT_BACKEND_PROFILE } from "@funky/sdk";
import { useIncrementalData } from "@funky/sdk/react";
import { getFeaturedProducts } from "./lib/commerce";
import { formatProductCardCurrency } from "./lib/productCardCurrency";
import { mountCmsScripts } from "./lib/pageScripts";
import { getExistingSubscription, getPushPreferences, subscribeToPush, unsubscribeFromPush } from "./lib/push";
import { lazy, Suspense, useCallback, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from "react";
Expand Down Expand Up @@ -87,6 +89,7 @@ function ConnectedStorefrontChrome() {
const { data, isLoading: navigationLoading, error: navigationError } = useNavigationData();
const location = useLocation();
const { languageCode, languageBackendCode, configuredLanguageCodes } = useLanguage();
const { formatBaseAmount } = useCurrency();
const { path: checkoutPath } = useResolvedStorefrontPath("checkout", "/checkout", languageCode);
const t = useT();
const { showToast } = useToast();
Expand Down Expand Up @@ -213,7 +216,12 @@ function ConnectedStorefrontChrome() {
return (
<>
<StorefrontChromeMockup
featuredProducts={isBackendConfigured ? featuredProducts ?? [] : MOCK_PRODUCTS.slice(0, 4)}
featuredProducts={
isBackendConfigured
? featuredProducts?.map((product) =>
formatProductCardCurrency(product, formatBaseAmount)) ?? []
: MOCK_PRODUCTS.slice(0, 4)
}
primaryNavigation={hideCheckoutNavigation ? [] : headerNavigation}
mobileNavigation={hideCheckoutNavigation ? [] : mobileNavigation}
footerColumns={hideCheckoutNavigation ? [] : footerColumns}
Expand Down
21 changes: 17 additions & 4 deletions apps/storefront/src/lib/productCardCurrency.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,28 @@ test("formats a backend product price range in the selected currency", () => {
);

assert.equal(product.priceRangeLabel, "PLN 40 – PLN 80");
assert.equal(product.priceLabel, "PLN 40 – PLN 80");
});

test("preserves non-range product pricing", () => {
test("formats simple, sale, and variation labels in the selected currency", () => {
const product = {
id: "simple-product",
name: "Simple product",
id: "priced-product",
name: "Priced product",
priceLabel: "€10,00",
priceAmount: 10,
compareAtPriceLabel: "€12,00",
compareAtPriceAmount: 12,
variations: [{
id: "variation",
attributes: {},
priceLabel: "€11,00",
priceAmount: 11,
inStock: true,
}],
};
const formatted = formatProductCardCurrency(product, (amount) => `PLN ${amount * 4}`);

assert.equal(formatProductCardCurrency(product, String), product);
assert.equal(formatted.priceLabel, "PLN 40");
assert.equal(formatted.compareAtPriceLabel, "PLN 48");
assert.equal(formatted.variations?.[0].priceLabel, "PLN 44");
});
27 changes: 22 additions & 5 deletions apps/storefront/src/lib/productCardCurrency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,33 @@ export function formatProductCardCurrency(
product: ProductCardData,
formatBaseAmount: (amount: number) => string,
): ProductCardData {
if (!product.priceRangeLabel) return product;

const formatLabel = (label: string | undefined, amount: number | undefined) => {
const resolvedAmount = amount ?? (label ? parseLocalizedPrice(label) ?? undefined : undefined);
return resolvedAmount === undefined ? label : formatBaseAmount(resolvedAmount);
};
const rangeAmounts = product.priceRangeLabel
.split(/\s+[–—-]\s+/)
?.split(/\s+[–—-]\s+/)
.map(parseLocalizedPrice)
.filter((amount): amount is number => amount !== null);
if (rangeAmounts.length < 2) return product;
const priceRangeLabel = rangeAmounts && rangeAmounts.length >= 2
? rangeAmounts.map(formatBaseAmount).join(" – ")
: product.priceRangeLabel;
const priceLabel = product.priceLabel === product.priceRangeLabel && priceRangeLabel
? priceRangeLabel
: formatLabel(product.priceLabel, product.priceAmount) || "";

return {
...product,
priceRangeLabel: rangeAmounts.map(formatBaseAmount).join(" – "),
priceLabel,
compareAtPriceLabel: formatLabel(product.compareAtPriceLabel, product.compareAtPriceAmount),
priceRangeLabel,
variations: product.variations?.map((variation) => ({
...variation,
priceLabel: formatLabel(variation.priceLabel, variation.priceAmount) || "",
compareAtPriceLabel: formatLabel(
variation.compareAtPriceLabel,
variation.compareAtPriceAmount,
),
})),
};
}
Loading