From 8f5c629300d8e8668d2db339148f550264fe1abf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:47:10 +0000 Subject: [PATCH] chore: sync storefront from monorepo Source: coded-letter/coded-letter-monorepo@d1f5f01060e5ae508c5d802a7a68ab15a6949ff8 --- apps/storefront/src/App.tsx | 10 ++++++- .../src/lib/productCardCurrency.test.ts | 21 ++++++++++++--- .../storefront/src/lib/productCardCurrency.ts | 27 +++++++++++++++---- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/storefront/src/App.tsx b/apps/storefront/src/App.tsx index a4756f5..33f061d 100644 --- a/apps/storefront/src/App.tsx +++ b/apps/storefront/src/App.tsx @@ -9,6 +9,7 @@ import { languageHomePath, resolveLanguageUrlAction, useCart, + useCurrency, useLanguage, useLayoutPreferences, useT, @@ -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"; @@ -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(); @@ -213,7 +216,12 @@ function ConnectedStorefrontChrome() { return ( <> + formatProductCardCurrency(product, formatBaseAmount)) ?? [] + : MOCK_PRODUCTS.slice(0, 4) + } primaryNavigation={hideCheckoutNavigation ? [] : headerNavigation} mobileNavigation={hideCheckoutNavigation ? [] : mobileNavigation} footerColumns={hideCheckoutNavigation ? [] : footerColumns} diff --git a/apps/storefront/src/lib/productCardCurrency.test.ts b/apps/storefront/src/lib/productCardCurrency.test.ts index a1a898e..cee43a5 100644 --- a/apps/storefront/src/lib/productCardCurrency.test.ts +++ b/apps/storefront/src/lib/productCardCurrency.test.ts @@ -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"); }); diff --git a/apps/storefront/src/lib/productCardCurrency.ts b/apps/storefront/src/lib/productCardCurrency.ts index bbbaf47..25fb2bf 100644 --- a/apps/storefront/src/lib/productCardCurrency.ts +++ b/apps/storefront/src/lib/productCardCurrency.ts @@ -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, + ), + })), }; }