diff --git a/web/src/pages/settings/RebalancePage.tsx b/web/src/pages/settings/RebalancePage.tsx index 8bd0846..131aa1e 100644 --- a/web/src/pages/settings/RebalancePage.tsx +++ b/web/src/pages/settings/RebalancePage.tsx @@ -71,22 +71,33 @@ export default function RebalancePage() { push("err", "Amount exceeds available budget"); return; } - const baseSum = sum(others.map((o) => o.targetCents)) || others.length; - const next = rows.map((r) => ({ ...r })); - let distributed = 0; - others.forEach((o) => { - const share = Math.floor((remaining * (o.targetCents || 1)) / baseSum); - const idx = next.findIndex((n) => n.id === o.id); - next[idx].targetCents = share; - distributed += share; + + const weightSum = others.reduce((s, o) => s + (o.percent || 1), 0) || others.length; + const provisional = others.map((o) => { + const exact = (remaining * (o.percent || 1)) / weightSum; + const base = Math.floor(exact); + return { id: o.id, base, frac: exact - base }; + }); + let distributed = provisional.reduce((s, p) => s + p.base, 0); + let leftover = remaining - distributed; + provisional + .slice() + .sort((a, b) => b.frac - a.frac) + .forEach((p) => { + if (leftover > 0) { + p.base += 1; + leftover -= 1; + } + }); + + const next = rows.map((r) => ({ ...r })); + provisional.forEach((p) => { + const idx = next.findIndex((n) => n.id === p.id); + if (idx >= 0) next[idx].targetCents = p.base; }); - const leftover = remaining - distributed; - if (leftover > 0) { - const firstIdx = next.findIndex((n) => n.id !== adjustId); - if (firstIdx >= 0) next[firstIdx].targetCents += leftover; - } const targetIdx = next.findIndex((n) => n.id === adjustId); - next[targetIdx].targetCents = desired; + if (targetIdx >= 0) next[targetIdx].targetCents = desired; + setRows(next); }; @@ -115,28 +126,28 @@ export default function RebalancePage() { if (isLoading || !data) return
Redistribute your current variable pool without changing future income percentages.
| Category | -Current | -Percent | -Target | +Category | +Current | +Percent | +Target |
|---|---|---|---|---|---|---|---|
| - {row.name} {row.isSavings ? Savings : null} + | |||||||
| + {row.name} + {row.isSavings ? Savings : null} | -${(row.balanceCents / 100).toFixed(2)} | -{row.percent}% | -+ | ${(row.balanceCents / 100).toFixed(2)} | +{row.percent}% | +
|