diff --git a/invofi/apps/frontend/src/app/settings/page.tsx b/invofi/apps/frontend/src/app/settings/page.tsx index 23d18c14..c9fe7b09 100644 --- a/invofi/apps/frontend/src/app/settings/page.tsx +++ b/invofi/apps/frontend/src/app/settings/page.tsx @@ -9,6 +9,8 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { PageHeader } from '@/components/common/PageHeader'; import { useToast } from '@/components/ui/use-toast'; import { createClient } from '@/utils/supabase/client'; +import { useLocalStorage } from '@/hooks/useLocalStorage'; +import { DEFAULT_CURRENCY_STORAGE_KEY } from '@/lib/formatters'; import { EXPLORER_BASE, FINANCING_CONTRACT_ID, @@ -111,6 +113,10 @@ export default function SettingsPage() { const router = useRouter(); const { toast } = useToast(); const [loading, setLoading] = useState(false); + const [defaultCurrency, setDefaultCurrency] = useLocalStorage( + DEFAULT_CURRENCY_STORAGE_KEY, + 'XLM', + ); const handleSignOut = async () => { setLoading(true); @@ -172,6 +178,44 @@ export default function SettingsPage() { + + + Display + + +
+

Default display currency

+

+ Amounts shown without an explicit currency will use this preference. +

+
+ + +
+
+
+
+ Account diff --git a/invofi/apps/frontend/src/lib/formatters.test.ts b/invofi/apps/frontend/src/lib/formatters.test.ts index e7f93171..53c3ca6a 100644 --- a/invofi/apps/frontend/src/lib/formatters.test.ts +++ b/invofi/apps/frontend/src/lib/formatters.test.ts @@ -6,10 +6,16 @@ import { formatDuration, formatRelativeDate, formatWalletAddress, + DEFAULT_CURRENCY_STORAGE_KEY, } from './formatters'; +const STORAGE_KEY = DEFAULT_CURRENCY_STORAGE_KEY; + describe('formatters', () => { - afterEach(() => vi.useRealTimers()); + afterEach(() => { + vi.useRealTimers(); + window.localStorage.removeItem(STORAGE_KEY); + }); it('formats stroops as a two-decimal currency amount', () => { expect(formatAmount(12_345_678)).toBe('1.23 XLM'); @@ -17,6 +23,14 @@ describe('formatters', () => { expect(formatAmount(12_345_678, 'XLM')).toBe('1.23 XLM'); }); + it('respects the default display currency preference from localStorage', () => { + window.localStorage.setItem(STORAGE_KEY, '"USDC"'); + expect(formatAmount(12_345_678)).toBe('1.23 USDC'); + expect(formatAmount(0)).toBe('0.00 USDC'); + // explicit currency still overrides + expect(formatAmount(12_345_678, 'XLM')).toBe('1.23 XLM'); + }); + it('formats basis points and durations', () => { expect(formatBasisPoints(525)).toBe('5.25%'); expect(formatDuration(86_400)).toBe('1 day'); diff --git a/invofi/apps/frontend/src/lib/formatters.ts b/invofi/apps/frontend/src/lib/formatters.ts index bd46b90f..8e4c8fd9 100644 --- a/invofi/apps/frontend/src/lib/formatters.ts +++ b/invofi/apps/frontend/src/lib/formatters.ts @@ -1,11 +1,30 @@ import { STROOPS_PER_XLM } from './constants'; -export function formatAmount(stroops: string | number | bigint, currency: string = 'XLM'): string { +export const DEFAULT_CURRENCY_STORAGE_KEY = 'invofi-default-currency'; + +/** Read the user's preferred display currency from localStorage, defaulting to + * 'XLM' when none is stored or the environment has no Storage API. */ +export function getDefaultCurrency(): string { + if (typeof window === 'undefined') return 'XLM'; + try { + const stored = window.localStorage.getItem(DEFAULT_CURRENCY_STORAGE_KEY); + if (stored) { + const parsed = JSON.parse(stored) as string; + if (parsed === 'XLM' || parsed === 'USDC') return parsed; + } + } catch { + /* localStorage unavailable — use default */ + } + return 'XLM'; +} + +export function formatAmount(stroops: string | number | bigint, currency?: string): string { const units = Number(stroops) / STROOPS_PER_XLM; + const cur = currency || getDefaultCurrency(); return new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, - }).format(units) + ` ${currency}`; + }).format(units) + ` ${cur}`; } export function formatBasisPoints(bps: number | bigint | string): string {