diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index 7066584..c9abc8e 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -5,6 +5,14 @@ ### Ajouté - Tableau de budget : colonne du total de l'année précédente affichée comme première colonne de données pour servir de référence (#16) +### Corrigé +- Tableau de bord budget vs réel : les sous-catégories de niveau 3+ s'affichent maintenant sous leur parent au lieu d'en bas de la section (#23) + +### Modifié +- Tableau de bord : la légende du graphique circulaire s'affiche maintenant uniquement au survol, réduisant l'espace et donnant plus de place au tableau budget (#23) +- Tableau de bord : l'infobulle du graphique circulaire affiche maintenant le pourcentage en plus du montant (#23) +- Tableau de bord : disposition ajustée pour donner plus d'espace au tableau budget (ratio 2:3) (#23) + ## [0.6.3] ### Ajouté diff --git a/CHANGELOG.md b/CHANGELOG.md index edd44d6..f1935a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ ### Added - Budget table: previous year total column displayed as first data column for baseline reference (#16) +### Fixed +- Dashboard budget vs actual table: level 3+ subcategories now appear under their parent instead of at the bottom of the section (#23) + +### Changed +- Dashboard: pie chart legend now appears only on hover, reducing space and giving more room to the budget table (#23) +- Dashboard: pie chart tooltip now shows percentage alongside amount (#23) +- Dashboard: adjusted grid layout to give more space to the budget table (2:3 ratio) (#23) + ## [0.6.3] ### Added diff --git a/src/components/dashboard/CategoryPieChart.tsx b/src/components/dashboard/CategoryPieChart.tsx index 2fe8195..20f61e0 100644 --- a/src/components/dashboard/CategoryPieChart.tsx +++ b/src/components/dashboard/CategoryPieChart.tsx @@ -43,7 +43,7 @@ export default function CategoryPieChart({ } return ( -
+
{hiddenCategories.size > 0 && (
{t("charts.hiddenCategories")}: @@ -67,7 +67,7 @@ export default function CategoryPieChart({ )}
- + - new Intl.NumberFormat("en-CA", { style: "currency", currency: "CAD" }).format(Number(value)) - } + formatter={(value) => { + const amount = new Intl.NumberFormat("en-CA", { style: "currency", currency: "CAD" }).format(Number(value)); + const pct = total > 0 ? ` (${Math.round((Number(value) / total) * 100)}%)` : ""; + return `${amount}${pct}`; + }} contentStyle={{ backgroundColor: "var(--card)", border: "1px solid var(--border)", @@ -110,7 +112,7 @@ export default function CategoryPieChart({
-
+
{data.map((item, index) => { const isHidden = hiddenCategories.has(item.category_name); return ( diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx index d484fbf..3349e24 100644 --- a/src/pages/DashboardPage.tsx +++ b/src/pages/DashboardPage.tsx @@ -126,7 +126,7 @@ export default function DashboardPage() { ))}
-
+

{t("dashboard.expensesByCategory")}

{ - if (a.category_id === cat.id && !a.is_parent) return -1; - if (b.category_id === cat.id && !b.is_parent) return 1; - return a.category_name.localeCompare(b.category_name); + // Sort child rows while keeping depth-2 children grouped under their depth-1 parent + // Build groups: each depth-1 row optionally followed by its depth-2 children + const depth1Groups: { head: BudgetVsActualRow; children: BudgetVsActualRow[] }[] = []; + for (const row of allChildRows) { + if ((row.depth ?? 0) <= 1) { + depth1Groups.push({ head: row, children: [] }); + } + } + for (const row of allChildRows) { + if ((row.depth ?? 0) === 2) { + const parentGroup = depth1Groups.find((g) => g.head.category_id === row.parent_id); + if (parentGroup) parentGroup.children.push(row); + } + } + // Sort groups: "(direct)" first, then alphabetical by group name + depth1Groups.sort((a, b) => { + if (a.head.category_id === cat.id && !a.head.is_parent) return -1; + if (b.head.category_id === cat.id && !b.head.is_parent) return 1; + return a.head.category_name.localeCompare(b.head.category_name); }); - rows.push(...allChildRows); + // Flatten: each group's head followed by its children + for (const group of depth1Groups) { + rows.push(group.head, ...group.children); + } } } @@ -442,12 +459,8 @@ export async function getBudgetVsActualData( if (orderA !== orderB) return orderA - orderB; return (catA?.name ?? "").localeCompare(catB?.name ?? ""); } - // Within same group: sort by depth, then parent before children - if (a.is_parent !== b.is_parent && (a.depth ?? 0) === (b.depth ?? 0)) return a.is_parent ? -1 : 1; - if ((a.depth ?? 0) !== (b.depth ?? 0)) return (a.depth ?? 0) - (b.depth ?? 0); - if (a.parent_id && a.category_id === a.parent_id) return -1; - if (b.parent_id && b.category_id === b.parent_id) return 1; - return a.category_name.localeCompare(b.category_name); + // Within same group: preserve insertion order (already correctly structured) + return 0; }); return rows;