$ba; if ($cmp !== 0) { return $cmp; } return strcmp((string) ($a['name'] ?? ''), (string) ($b['name'] ?? '')); }); $nameById = []; foreach ($people as $p) { if (!empty($p['id'])) { $nameById[(string) $p['id']] = (string) ($p['name'] ?? ''); } } $expenses = normalizeExpensesList(readJsonFile('expenses.json')); usort($expenses, static function ($a, $b) { $da = (string) ($a['date'] ?? ''); $db = (string) ($b['date'] ?? ''); if ($db !== $da) { return strcmp($db, $da); } return strcmp((string) ($b['created_at'] ?? ''), (string) ($a['created_at'] ?? '')); }); $recentExpenses = array_slice($expenses, 0, 50); $today = gmdate('Y-m-d'); $currentMonth = gmdate('Y-m'); $bankRows = readJsonFile('bank_transactions.json'); if (!is_array($bankRows)) { $bankRows = []; } usort($bankRows, static function ($a, $b) { return strcmp((string) ($b['created_at'] ?? ''), (string) ($a['created_at'] ?? '')); }); $recentBank = array_slice($bankRows, 0, 80); $donatedByPersonThisMonth = []; foreach ($bankRows as $row) { if (!is_array($row)) { continue; } if ((string) ($row['type'] ?? '') !== 'charity_outflow') { continue; } $dateYmd = bankingYmd((string) ($row['created_at'] ?? '')); if (strpos($dateYmd, $currentMonth . '-') !== 0) { continue; } $pid = (string) ($row['person_id'] ?? ''); if ($pid === '') { continue; } $donatedByPersonThisMonth[$pid] = ($donatedByPersonThisMonth[$pid] ?? 0) + (float) ($row['amount'] ?? 0); } $activePersonId = (string) ($activePerson['id'] ?? ''); $activeBankPerson = null; foreach ($people as $p) { if (($p['id'] ?? '') === $activePersonId) { $activeBankPerson = $p; break; } } $activeChecking = is_numeric($activeBankPerson['checking_balance'] ?? null) ? (float) $activeBankPerson['checking_balance'] : 0.0; $activeSavings = is_numeric($activeBankPerson['savings_balance'] ?? null) ? (float) $activeBankPerson['savings_balance'] : 0.0; $activeCharityPending = is_numeric($activeBankPerson['charity_pending_balance'] ?? null) ? (float) $activeBankPerson['charity_pending_balance'] : 0.0; $activeCharityDonated = is_numeric($activeBankPerson['charity_donated_total'] ?? null) ? (float) $activeBankPerson['charity_donated_total'] : 0.0; ?>
Leaderboard and expenses use the family currency from Family settings.
| # | Name | Total = htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?> |
|---|---|---|
| = (int) $rank + 1 ?> | = sanitizeInput($p['name'] ?? '') ?> You | = htmlspecialchars(number_format($total, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> |
Add people in Family settings to see balances.
| # | Name | Checking | Savings | Charity pending | Donated total | Donation goal progress | Balance |
|---|---|---|---|---|---|---|---|
| = (int) $rank + 1 ?> | = sanitizeInput($p['name'] ?? '') ?> You | = htmlspecialchars(number_format($checkingBal, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars(number_format($savingsBal, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars(number_format($charityPending, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> | = htmlspecialchars(number_format($charityDonated, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> |
0): ?>
= htmlspecialchars(number_format($donatedThisMonth, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> / = htmlspecialchars(number_format($goal, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?>
No goal set
|
= htmlspecialchars(number_format($bal, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> |
Track your accounts and move money with one tap.
No bank transactions recorded yet.
| Date | Person | Type | Category | Note | Amount | |
|---|---|---|---|---|---|---|
| = sanitizeInput((string) ($row['created_at'] ?? '')) ?> | = sanitizeInput($nameById[$pid] ?? '') ?> | = sanitizeInput($type) ?> | = sanitizeInput((string) ($row['category'] ?? '')) ?> | = sanitizeInput((string) ($row['note'] ?? '')) ?> | = $amtSign ?>= htmlspecialchars(number_format($rawAmt, 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> |
Download your monthly statement as JSON or CSV.
Deducts from one person’s balance (e.g. spent allowance). Requires enough balance.
Switch to a verified Head of household to record expenses.
No expenses recorded yet.
| Date | Title | To | Amount |
|---|---|---|---|
| = sanitizeInput((string) ($ex['date'] ?? '')) ?> | = sanitizeInput((string) ($ex['title'] ?? '')) ?> | = sanitizeInput($nameById[(string) ($ex['assignee_id'] ?? '')] ?? '') ?> | −= htmlspecialchars(number_format((float) ($ex['value'] ?? 0), 2, '.', ''), ENT_QUOTES, 'UTF-8') ?> = htmlspecialchars($sym, ENT_QUOTES, 'UTF-8') ?> |