diff --git a/src/client/components/CollectionView.tsx b/src/client/components/CollectionView.tsx index 06da1ba..d764378 100644 --- a/src/client/components/CollectionView.tsx +++ b/src/client/components/CollectionView.tsx @@ -235,6 +235,7 @@ export function CollectionView() { cropZoom={item.cropZoom} cropX={item.cropX} cropY={item.cropY} + priceCurrency={item.priceCurrency} /> ))} diff --git a/src/client/components/ItemCard.tsx b/src/client/components/ItemCard.tsx index abbca67..009e908 100644 --- a/src/client/components/ItemCard.tsx +++ b/src/client/components/ItemCard.tsx @@ -26,6 +26,7 @@ interface ItemCardProps { classification?: string; onClassificationCycle?: () => void; linkTo?: string | null; + priceCurrency?: string | null; } export function ItemCard({ @@ -48,6 +49,7 @@ export function ItemCard({ classification, onClassificationCycle, linkTo, + priceCurrency, }: ItemCardProps) { const { weight, price } = useFormatters(); const navigate = useNavigate(); @@ -232,7 +234,7 @@ export function ItemCard({ )} {priceCents != null && ( - {price(priceCents)} + {price(priceCents, priceCurrency)} )} diff --git a/src/client/hooks/useFormatters.ts b/src/client/hooks/useFormatters.ts index 77767c9..001addb 100644 --- a/src/client/hooks/useFormatters.ts +++ b/src/client/hooks/useFormatters.ts @@ -1,15 +1,47 @@ -import { formatPrice, formatWeight } from "../lib/formatters"; +import { + type Currency, + formatDualPrice, + formatPrice, + formatWeight, +} from "../lib/formatters"; import { useCurrency } from "./useCurrency"; +import { convertClientPrice, useExchangeRates } from "./useExchangeRates"; import { useLanguage } from "./useLanguage"; import { useWeightUnit } from "./useWeightUnit"; export function useFormatters() { const unit = useWeightUnit(); - const { currency } = useCurrency(); + const { currency, showConversions } = useCurrency(); const locale = useLanguage(); + const { data: ratesData } = useExchangeRates(); + const rates = ratesData?.rates; + return { weight: (grams: number | null) => formatWeight(grams, unit, locale), - price: (cents: number | null) => formatPrice(cents, currency, locale), + /** + * Format a price. If sourceCurrency differs from user's currency and + * showConversions is enabled, returns dual format: "€200.00 (~$218.00)". + * Otherwise returns price in source currency (or user's currency if no source given). + */ + price: ( + cents: number | null, + sourceCurrency?: Currency | string | null, + ) => { + if (cents == null) return "--"; + const source = (sourceCurrency as Currency) || currency; + if (showConversions && rates && source !== currency) { + const converted = convertClientPrice(cents, source, currency, rates); + const dual = formatDualPrice({ + sourceCents: cents, + sourceCurrency: source as Currency, + targetCurrency: currency, + convertedCents: converted, + locale, + }); + return `${dual.source} (${dual.converted})`; + } + return formatPrice(cents, source as Currency, locale); + }, unit, currency, locale, diff --git a/src/client/routes/setups/$setupId.tsx b/src/client/routes/setups/$setupId.tsx index f6741b8..a7caa50 100644 --- a/src/client/routes/setups/$setupId.tsx +++ b/src/client/routes/setups/$setupId.tsx @@ -358,6 +358,7 @@ function SetupDetailPage() { name={item.name} weightGrams={item.weightGrams} priceCents={item.priceCents} + priceCurrency={item.priceCurrency} quantity={item.quantity} categoryName={categoryName} categoryIcon={categoryIcon}