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}