-
Finished the planner end to end. Corrected rollover and yearly accounting, recurring targets, savings rules, and targeted dormant restorations. Added editing/deletion for income, expenses, targets, and categories. Rebuilt dashboard, analytics, calendar, settings, exports, authentication, and responsive mobile UI. Added original artwork at [financial-flow.png](/Users/tyemeclifford/Documents/GH/budget/public/assets/images/financial-flow.png), generated with built-in Imagegen using an abstract financial-momentum landscape prompt. Added [self-test.php](/Users/tyemeclifford/Documents/GH/budget/scripts/self-test.php). Verification passed: automated accounting/export tests, full browser workflow, responsive 390px layout, light/dark themes, and no console errors. Tested with FrankenPHP v1.12.4. Live Mailgun delivery was not attempted without credentials.
This commit is contained in:
+18
-9
@@ -2,16 +2,24 @@
|
||||
$totals = $yearly['totals'];
|
||||
$bestMonth = null;
|
||||
foreach ($yearly['months'] as $row) {
|
||||
$hasActivity = (float) $row['fresh_income'] !== 0.0
|
||||
|| (float) $row['rollover_in'] !== 0.0
|
||||
|| (float) $row['expenses'] !== 0.0
|
||||
|| (float) $row['planned'] !== 0.0
|
||||
|| (float) $row['dead_movement'] !== 0.0;
|
||||
if (!$hasActivity) {
|
||||
continue;
|
||||
}
|
||||
if ($bestMonth === null || $row['remaining'] > $bestMonth['remaining']) {
|
||||
$bestMonth = $row;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<section class="hero-grid comparison-metrics">
|
||||
<article class="metric-card card"><div class="metric-icon blue">Σ</div><p><?= (int) $yearly['year'] ?> resources</p><strong><?= h(Support::money($totals['gross_resources'], $symbol)) ?></strong><small>Across all twelve months</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon pink">↗</div><p><?= (int) $yearly['year'] ?> expenses</p><strong><?= h(Support::money($totals['expenses'], $symbol)) ?></strong><small><?= $totals['gross_resources'] > 0 ? number_format($totals['expenses'] / $totals['gross_resources'] * 100, 1) : '0.0' ?>% of resources</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon orange">◇</div><p>Moved dormant</p><strong><?= h(Support::money($totals['dead_movement'], $symbol)) ?></strong><small>Net dormant deposits</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon green">★</div><p>Strongest remainder</p><strong><?= h(Support::money($bestMonth['remaining'] ?? 0, $symbol)) ?></strong><small><?= $bestMonth ? h(date('F', strtotime($bestMonth['month'] . '-01'))) : 'No data' ?></small></article>
|
||||
<article class="metric-card card"><div class="metric-icon blue"><?= icon('wallet') ?></div><p><?= (int) $yearly['year'] ?> fresh income</p><strong><?= h(Support::money($totals['fresh_income'], $symbol)) ?></strong><small>Rollover excluded to avoid double-counting</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon pink"><?= icon('expense') ?></div><p><?= (int) $yearly['year'] ?> expenses</p><strong><?= h(Support::money($totals['expenses'], $symbol)) ?></strong><small><?= $totals['fresh_income'] > 0 ? number_format($totals['expenses'] / $totals['fresh_income'] * 100, 1) : '0.0' ?>% of fresh income</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon orange"><?= icon('vault') ?></div><p>Moved dormant</p><strong><?= h(Support::money($totals['dead_deposits'], $symbol)) ?></strong><small><?= h(Support::money($totals['dead_restorations'], $symbol)) ?> restored</small></article>
|
||||
<article class="metric-card card"><div class="metric-icon green"><?= icon('chart') ?></div><p>Strongest remainder</p><strong><?= h(Support::money($bestMonth['remaining'] ?? 0, $symbol)) ?></strong><small><?= $bestMonth ? h(date('F', strtotime($bestMonth['month'] . '-01'))) : 'No data' ?></small></article>
|
||||
</section>
|
||||
|
||||
<section class="content-grid comparison-grid">
|
||||
@@ -30,7 +38,7 @@ foreach ($yearly['months'] as $row) {
|
||||
<div>
|
||||
<p><span><i style="--dot:<?= h($category['color']) ?>"></i><?= h($category['category_name']) ?></span><strong><?= h(Support::money($category['spent'], $symbol)) ?></strong></p>
|
||||
<div class="progress-track"><span style="width:<?= h((string) $width) ?>%;--bar:<?= h($category['color']) ?>"></span></div>
|
||||
<?php if ((float) $category['monthly_limit'] > 0): ?><small><?= number_format($category['spent'] / $category['monthly_limit'] * 100, 0) ?>% of <?= h(Support::money($category['monthly_limit'], $symbol)) ?> category limit</small><?php endif; ?>
|
||||
<small><?php if ((float) $category['planned'] > 0): ?><?= number_format($category['spent'] / $category['planned'] * 100, 0) ?>% of <?= h(Support::money($category['planned'], $symbol)) ?> planned<?php elseif ((float) $category['monthly_limit'] > 0): ?><?= number_format($category['spent'] / $category['monthly_limit'] * 100, 0) ?>% of <?= h(Support::money($category['monthly_limit'], $symbol)) ?> category limit<?php else: ?>No target defined<?php endif; ?></small>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@@ -41,19 +49,20 @@ foreach ($yearly['months'] as $row) {
|
||||
<article class="card">
|
||||
<div class="card-heading">
|
||||
<div><p class="eyebrow">Statistical table</p><h2><?= (int) $yearly['year'] ?> monthly breakdown</h2></div>
|
||||
<label class="search-box"><span>⌕</span><input type="search" placeholder="Find a month…" data-table-search="year-table"></label>
|
||||
<label class="search-box"><?= icon('search') ?><input type="search" placeholder="Find a month…" data-table-search="year-table"></label>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table id="year-table">
|
||||
<thead><tr><th>Month</th><th>Resources</th><th>Planned</th><th>Expenses</th><th>Dormant</th><th>Remainder</th></tr></thead>
|
||||
<thead><tr><th>Month</th><th>Fresh income</th><th>Rollover</th><th>Planned</th><th>Expenses</th><th>Saved</th><th>Remainder</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($yearly['months'] as $row): ?>
|
||||
<tr>
|
||||
<td><a class="text-link" href="<?= h(url('comparisons', ['month' => $row['month']])) ?>"><?= h(date('F Y', strtotime($row['month'] . '-01'))) ?></a></td>
|
||||
<td><?= h(Support::money($row['gross_resources'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['fresh_income'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['rollover_in'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['planned'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['expenses'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['dead_movement'], $symbol)) ?></td>
|
||||
<td><?= h(Support::money($row['dead_deposits'], $symbol)) ?></td>
|
||||
<td class="<?= $row['remaining'] >= 0 ? 'green' : 'red' ?>"><strong><?= h(Support::money($row['remaining'], $symbol)) ?></strong></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
Reference in New Issue
Block a user