Update formatCurrency to use currency code from UserSettings

Changes:
- Updated formatCurrency function:
  - Added currencyCode parameter with EUR default
  - Implemented Intl.NumberFormat for proper currency formatting
  - Added fallback for invalid currency codes
- Updated component hierarchy to pass currency:
  - HomePage: Fetch userSettings and pass to MonthLocationList
  - MonthLocationList: Accept and pass currency to child components
  - LocationCard: Accept currency prop and use in formatCurrency
  - MonthCard: Accept currency prop and use in formatCurrency
  - ViewLocationCard: Pass currency from userSettings to formatCurrency
- Removed hardcoded $ symbols, now using proper currency formatting

All currency amounts now display with the user's selected currency code
from their settings, using locale-appropriate formatting (hr-HR).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-11-22 23:04:42 +01:00
parent 4655b342f2
commit c025c6f2ce
6 changed files with 38 additions and 20 deletions

View File

@@ -1,8 +1,20 @@
export const formatCurrency = (amount:number) => { export const formatCurrency = (amount: number, currencyCode: string = "EUR") => {
// format number wirh 2 decimal places and a thousand separator // format number with 2 decimal places and a thousand separator
// amount is in cents // amount is in cents
const formattedAmount = (amount/100).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'); const amountInUnits = amount / 100;
return(formattedAmount);
// Use Intl.NumberFormat for proper currency formatting
try {
return new Intl.NumberFormat('hr-HR', {
style: 'currency',
currency: currencyCode,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(amountInUnits);
} catch (e) {
// Fallback if invalid currency code
console.error(`Invalid currency code: ${currencyCode}`, e);
}
} }
/** /**

View File

@@ -1,5 +1,6 @@
import { fetchAllLocations } from '@/app/lib/actions/locationActions'; import { fetchAllLocations } from '@/app/lib/actions/locationActions';
import { fetchAvailableYears } from '@/app/lib/actions/monthActions'; import { fetchAvailableYears } from '@/app/lib/actions/monthActions';
import { getUserSettings } from '@/app/lib/actions/userSettingsActions';
import { BillingLocation, YearMonth } from '@/app/lib/db-types'; import { BillingLocation, YearMonth } from '@/app/lib/db-types';
import { FC } from 'react'; import { FC } from 'react';
import { MonthLocationList } from '@/app/ui/MonthLocationList'; import { MonthLocationList } from '@/app/ui/MonthLocationList';
@@ -35,6 +36,7 @@ export const HomePage:FC<HomePageProps> = async ({ searchParams }) => {
const currentYear = Number(searchParams?.year) || new Date().getFullYear(); const currentYear = Number(searchParams?.year) || new Date().getFullYear();
const locations = await fetchAllLocations(currentYear); const locations = await fetchAllLocations(currentYear);
const userSettings = await getUserSettings();
// group locations by month // group locations by month
const months = locations.reduce((acc, location) => { const months = locations.reduce((acc, location) => {
@@ -69,7 +71,7 @@ export const HomePage:FC<HomePageProps> = async ({ searchParams }) => {
} }); } });
return ( return (
<MonthLocationList availableYears={availableYears} months={months} /> <MonthLocationList availableYears={availableYears} months={months} userSettings={userSettings} />
); );
} }

View File

@@ -11,10 +11,11 @@ import { useLocale, useTranslations } from "next-intl";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
export interface LocationCardProps { export interface LocationCardProps {
location: BillingLocation location: BillingLocation;
currency?: string | null;
} }
export const LocationCard:FC<LocationCardProps> = ({location}) => { export const LocationCard:FC<LocationCardProps> = ({location, currency}) => {
const { _id, name, yearMonth, bills, seenByTenant } = location; const { _id, name, yearMonth, bills, seenByTenant } = location;
console.log("seenByTenant:", seenByTenant); console.log("seenByTenant:", seenByTenant);
@@ -59,7 +60,7 @@ export const LocationCard:FC<LocationCardProps> = ({location}) => {
monthlyExpense > 0 ? monthlyExpense > 0 ?
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<BanknotesIcon className="h-5 w-5" /> <BanknotesIcon className="h-5 w-5" />
{ t("payed-total-label") } <strong>${formatCurrency(monthlyExpense)}</strong> { t("payed-total-label") } <strong>{formatCurrency(monthlyExpense, currency ?? "EUR")}</strong>
</div> </div>
: null : null
} }

View File

@@ -10,11 +10,12 @@ export interface MonthCardProps {
yearMonth: YearMonth, yearMonth: YearMonth,
children?: React.ReactNode, children?: React.ReactNode,
monthlyExpense:number, monthlyExpense:number,
currency?: string | null,
expanded?:boolean, expanded?:boolean,
onToggle: (yearMonth:YearMonth) => void onToggle: (yearMonth:YearMonth) => void
} }
export const MonthCard:FC<MonthCardProps> = ({ yearMonth, children, monthlyExpense, expanded, onToggle }) => { export const MonthCard:FC<MonthCardProps> = ({ yearMonth, children, monthlyExpense, currency, expanded, onToggle }) => {
const elRef = useRef<HTMLDivElement>(null); const elRef = useRef<HTMLDivElement>(null);
const t = useTranslations("home-page.month-card"); const t = useTranslations("home-page.month-card");
@@ -38,7 +39,7 @@ export const MonthCard:FC<MonthCardProps> = ({ yearMonth, children, monthlyExpen
{ {
monthlyExpense>0 ? monthlyExpense>0 ?
<p className="text-xs font-medium"> <p className="text-xs font-medium">
{t("payed-total-label")} <strong>{ formatCurrency(monthlyExpense) }</strong> {t("payed-total-label")} <strong>{ formatCurrency(monthlyExpense, currency ?? "EUR") }</strong>
</p> : null </p> : null
} }
</div> </div>

View File

@@ -7,7 +7,7 @@ import { MonthCard } from "./MonthCard";
import Pagination from "./Pagination"; import Pagination from "./Pagination";
import { LocationCard } from "./LocationCard"; import { LocationCard } from "./LocationCard";
import { PrintButton } from "./PrintButton"; import { PrintButton } from "./PrintButton";
import { BillingLocation, YearMonth } from "../lib/db-types"; import { BillingLocation, UserSettings, YearMonth } from "../lib/db-types";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { ToastContainer, toast } from 'react-toastify'; import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.css';
@@ -30,11 +30,13 @@ export interface MonthLocationListProps {
monthlyExpense: number; monthlyExpense: number;
}; };
}; };
userSettings?: UserSettings | null;
} }
export const MonthLocationList:React.FC<MonthLocationListProps > = ({ export const MonthLocationList:React.FC<MonthLocationListProps > = ({
availableYears, availableYears,
months, months,
userSettings,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@@ -97,7 +99,7 @@ export const MonthLocationList:React.FC<MonthLocationListProps > = ({
return( return(
<> <>
<MonthCard yearMonth={currentYearMonth} key={`month-${currentYearMonth}`} monthlyExpense={0} onToggle={() => {}} expanded={true} > <MonthCard yearMonth={currentYearMonth} key={`month-${currentYearMonth}`} monthlyExpense={0} currency={userSettings?.currency} onToggle={() => {}} expanded={true} >
<AddLocationButton yearMonth={currentYearMonth} /> <AddLocationButton yearMonth={currentYearMonth} />
</MonthCard> </MonthCard>
</>) </>)
@@ -122,10 +124,10 @@ export const MonthLocationList:React.FC<MonthLocationListProps > = ({
<AddMonthButton yearMonth={getNextYearMonth(monthsArray[0][1].locations[0].yearMonth)} /> <AddMonthButton yearMonth={getNextYearMonth(monthsArray[0][1].locations[0].yearMonth)} />
{ {
monthsArray.map(([monthKey, { yearMonth, locations, monthlyExpense }], monthIx) => monthsArray.map(([monthKey, { yearMonth, locations, monthlyExpense }], monthIx) =>
<MonthCard yearMonth={yearMonth} key={`month-${monthKey}`} monthlyExpense={monthlyExpense} expanded={ yearMonth.month === expandedMonth } onToggle={handleMonthToggle} > <MonthCard yearMonth={yearMonth} key={`month-${monthKey}`} monthlyExpense={monthlyExpense} currency={userSettings?.currency} expanded={ yearMonth.month === expandedMonth } onToggle={handleMonthToggle} >
{ {
yearMonth.month === expandedMonth ? yearMonth.month === expandedMonth ?
locations.map((location, ix) => <LocationCard key={`location-${location._id}`} location={location} />) locations.map((location, ix) => <LocationCard key={`location-${location._id}`} location={location} currency={userSettings?.currency} />)
: null : null
} }
<div className="flex gap-2 justify-center"> <div className="flex gap-2 justify-center">

View File

@@ -52,7 +52,7 @@ export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettin
{ {
monthlyExpense > 0 ? monthlyExpense > 0 ?
<p className="text-[1.2rem]"> <p className="text-[1.2rem]">
{ t("payed-total-label") } <strong>${formatCurrency(monthlyExpense)}</strong> { t("payed-total-label") } <strong>{formatCurrency(monthlyExpense, userSettings?.currency)}</strong>
</p> </p>
: null : null
} }