feat: add total balance calculation and display in account management; update account card to show calculated balance
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 1m26s

This commit is contained in:
Julien Froidefond
2025-12-20 11:30:26 +01:00
parent 4e1e623f93
commit 376bc8f84e
8 changed files with 367 additions and 56 deletions

View File

@@ -29,6 +29,7 @@ interface AccountCardProps {
account: Account;
folder?: Folder;
transactionCount: number;
calculatedBalance?: number;
onEdit: (account: Account) => void;
onDelete: (accountId: string) => void;
formatCurrency: (amount: number) => string;
@@ -42,6 +43,7 @@ export function AccountCard({
account,
folder,
transactionCount,
calculatedBalance,
onEdit,
onDelete,
formatCurrency,
@@ -53,6 +55,8 @@ export function AccountCard({
const isMobile = useIsMobile();
const Icon = accountTypeIcons[account.type];
const realBalance = getAccountBalance(account);
const hasBalanceDifference = calculatedBalance !== undefined &&
Math.abs(account.balance - calculatedBalance) > 0.01;
const {
attributes,
@@ -172,21 +176,35 @@ export function AccountCard({
className={cn(isMobile ? "px-2 pb-2 pt-1" : "pt-1", compact && "pt-0")}
>
<div className="flex items-center justify-between gap-1.5">
<div
className={cn(
"font-bold truncate",
compact
? isMobile
? "text-sm"
: "text-lg"
: isMobile
? "text-base"
: "text-xl",
!compact && !isMobile && "mb-1.5",
realBalance >= 0 ? "text-emerald-600" : "text-red-600",
<div className="flex-1 min-w-0">
<div
className={cn(
"font-bold truncate",
compact
? isMobile
? "text-sm"
: "text-lg"
: isMobile
? "text-base"
: "text-xl",
!compact && !isMobile && "mb-1.5",
realBalance >= 0 ? "text-emerald-600" : "text-red-600",
)}
>
{formatCurrency(realBalance)}
</div>
{!compact && calculatedBalance !== undefined && (
<div className="flex items-center gap-2 mt-0.5">
<span className="text-xs text-muted-foreground">
Calculé: {formatCurrency(calculatedBalance)}
</span>
{hasBalanceDifference && (
<span className="text-xs text-destructive font-semibold">
(diff: {formatCurrency(account.balance - calculatedBalance)})
</span>
)}
</div>
)}
>
{formatCurrency(realBalance)}
</div>
{compact && (
<Link

View File

@@ -25,6 +25,7 @@ interface AccountFormData {
folderId: string;
externalUrl: string;
initialBalance: number;
totalBalance: number;
}
interface AccountEditDialogProps {
@@ -101,21 +102,42 @@ export function AccountEditDialog({
</Select>
</div>
<div className="space-y-2">
<Label>Solde initial</Label>
<Label>Solde total</Label>
<Input
type="number"
step="0.01"
value={formData.initialBalance}
value={formData.totalBalance}
onChange={(e) =>
onFormDataChange({
...formData,
initialBalance: parseFloat(e.target.value) || 0,
totalBalance: parseFloat(e.target.value) || 0,
})
}
placeholder="0.00"
/>
<p className="text-xs text-muted-foreground">
Solde de départ pour équilibrer le compte
Solde total du compte (balance + solde initial)
</p>
</div>
<div className="space-y-2">
<Label>Solde initial</Label>
<Input
type="number"
step="0.01"
value={formData.initialBalance}
onChange={(e) => {
const newInitialBalance = parseFloat(e.target.value) || 0;
onFormDataChange({
...formData,
initialBalance: newInitialBalance,
// Ajuster le solde total pour maintenir la cohérence
totalBalance: formData.totalBalance,
});
}}
placeholder="0.00"
/>
<p className="text-xs text-muted-foreground">
Solde de départ pour équilibrer le compte. Le balance sera calculé automatiquement (solde total - solde initial).
</p>
</div>
<div className="space-y-2">