feat: add initial balance support to accounts, enhancing account management and balance calculations across components

This commit is contained in:
Julien Froidefond
2025-11-30 12:13:02 +01:00
parent c26ba9ddc6
commit 184a073bb1
13 changed files with 117 additions and 30 deletions

View File

@@ -14,6 +14,7 @@ import Link from "next/link";
import type { Account, Folder } from "@/lib/types";
import { accountTypeIcons, accountTypeLabels } from "./constants";
import { Checkbox } from "@/components/ui/checkbox";
import { getAccountBalance } from "@/lib/account-utils";
interface AccountCardProps {
account: Account;
@@ -37,10 +38,11 @@ export function AccountCard({
onSelect,
}: AccountCardProps) {
const Icon = accountTypeIcons[account.type];
const realBalance = getAccountBalance(account);
return (
<Card className={cn("relative", isSelected && "ring-2 ring-primary")}>
<CardHeader className="pb-1.5">
<CardHeader className="pb-0">
<div className="flex items-start justify-between">
<div className="flex items-center gap-2 flex-1">
{onSelect && (
@@ -89,14 +91,14 @@ export function AccountCard({
</DropdownMenu>
</div>
</CardHeader>
<CardContent className="pt-1.5">
<CardContent className="pt-1">
<div
className={cn(
"text-xl font-bold mb-1.5",
account.balance >= 0 ? "text-emerald-600" : "text-red-600"
realBalance >= 0 ? "text-emerald-600" : "text-red-600"
)}
>
{formatCurrency(account.balance)}
{formatCurrency(realBalance)}
</div>
<div className="flex items-center justify-between text-xs text-muted-foreground">
<Link

View File

@@ -24,6 +24,7 @@ interface AccountFormData {
type: Account["type"];
folderId: string;
externalUrl: string;
initialBalance: number;
}
interface AccountEditDialogProps {
@@ -99,6 +100,24 @@ export function AccountEditDialog({
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>Solde initial</Label>
<Input
type="number"
step="0.01"
value={formData.initialBalance}
onChange={(e) =>
onFormDataChange({
...formData,
initialBalance: parseFloat(e.target.value) || 0,
})
}
placeholder="0.00"
/>
<p className="text-xs text-muted-foreground">
Solde de départ pour équilibrer le compte
</p>
</div>
<div className="space-y-2">
<Label>Lien externe (portail banque)</Label>
<Input

View File

@@ -5,6 +5,7 @@ import { Progress } from "@/components/ui/progress";
import type { BankingData } from "@/lib/types";
import { cn } from "@/lib/utils";
import { Building2 } from "lucide-react";
import { getAccountBalance } from "@/lib/account-utils";
interface AccountsSummaryProps {
data: BankingData;
@@ -19,8 +20,8 @@ export function AccountsSummary({ data }: AccountsSummaryProps) {
};
const totalPositive = data.accounts
.filter((a) => a.balance > 0)
.reduce((sum, a) => sum + a.balance, 0);
.filter((a) => getAccountBalance(a) > 0)
.reduce((sum, a) => sum + getAccountBalance(a), 0);
if (data.accounts.length === 0) {
return (
@@ -49,9 +50,10 @@ export function AccountsSummary({ data }: AccountsSummaryProps) {
<CardContent>
<div className="space-y-4">
{data.accounts.map((account) => {
const realBalance = getAccountBalance(account);
const percentage =
totalPositive > 0
? Math.max(0, (account.balance / totalPositive) * 100)
? Math.max(0, (realBalance / totalPositive) * 100)
: 0;
return (
@@ -71,15 +73,15 @@ export function AccountsSummary({ data }: AccountsSummaryProps) {
<span
className={cn(
"font-semibold tabular-nums",
account.balance >= 0
realBalance >= 0
? "text-emerald-600"
: "text-red-600",
)}
>
{formatCurrency(account.balance)}
{formatCurrency(realBalance)}
</span>
</div>
{account.balance > 0 && (
{realBalance > 0 && (
<Progress value={percentage} className="h-1.5" />
)}
</div>

View File

@@ -3,13 +3,17 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { TrendingUp, TrendingDown, Wallet, CreditCard } from "lucide-react";
import type { BankingData } from "@/lib/types";
import { getAccountBalance } from "@/lib/account-utils";
interface OverviewCardsProps {
data: BankingData;
}
export function OverviewCards({ data }: OverviewCardsProps) {
const totalBalance = data.accounts.reduce((sum, acc) => sum + acc.balance, 0);
const totalBalance = data.accounts.reduce(
(sum, acc) => sum + getAccountBalance(acc),
0,
);
const thisMonth = new Date();
thisMonth.setDate(1);

View File

@@ -7,6 +7,7 @@ import { Building2, GripVertical, Pencil } from "lucide-react";
import { cn } from "@/lib/utils";
import Link from "next/link";
import type { Account } from "@/lib/types";
import { getAccountBalance } from "@/lib/account-utils";
interface DraggableAccountItemProps {
account: Account;
@@ -19,6 +20,7 @@ export function DraggableAccountItem({
onEditAccount,
formatCurrency,
}: DraggableAccountItemProps) {
const realBalance = getAccountBalance(account);
const {
attributes,
listeners,
@@ -71,10 +73,10 @@ export function DraggableAccountItem({
<span
className={cn(
"text-sm tabular-nums",
account.balance >= 0 ? "text-emerald-600" : "text-red-600"
realBalance >= 0 ? "text-emerald-600" : "text-red-600"
)}
>
{formatCurrency(account.balance)}
{formatCurrency(realBalance)}
</span>
<Button
variant="ghost"

View File

@@ -4,6 +4,7 @@ import { useState } from "react";
import { DraggableFolderItem } from "./draggable-folder-item";
import { DraggableAccountItem } from "./draggable-account-item";
import type { Folder as FolderType, Account } from "@/lib/types";
import { getAccountBalance } from "@/lib/account-utils";
interface FolderTreeItemProps {
folder: FolderType;
@@ -35,7 +36,10 @@ export function FolderTreeItem({
(folder.id === "folder-root" && a.folderId === null)
);
const childFolders = allFolders.filter((f) => f.parentId === folder.id);
const folderTotal = folderAccounts.reduce((sum, a) => sum + a.balance, 0);
const folderTotal = folderAccounts.reduce(
(sum, a) => sum + getAccountBalance(a),
0,
);
return (
<div>