Gonçalo Rodrigues 437fb5a2df refactor: consolidate nav from 15 items to 7
- Merge Sharing + Household → /people (tab switcher: sharing | household)
- Merge Accounts + Categories → /settings (tab switcher: accounts | categories)
- Add Analysis dropdown in nav: Reports, Projections, Tax, Net Worth, What If
- Add Settings dropdown in nav: Accounts & Categories, Import CSV, Import Guide
- Legacy GET /sharing, /household, /accounts, /categories redirect 301 to new URLs
- Remove Import and Import Guide as standalone nav links
- New People handler consolidates all people-related mutations (_action field)
- New Settings handler renders both account and category lists in one page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 18:33:15 +01:00

192 lines
8.4 KiB
HTML

{{template "base" .}}
{{define "content"}}
{{$d := .}}
<style>
.tab-bar { display:flex; gap:4px; border-bottom:2px solid var(--border); margin-bottom:24px; }
.tab-bar a { padding:8px 18px; font-size:0.9rem; font-weight:600; color:var(--muted); text-decoration:none; border-bottom:2px solid transparent; margin-bottom:-2px; transition:all 0.15s; }
.tab-bar a.active { color:var(--accent); border-bottom-color:var(--accent); }
.tab-bar a:hover:not(.active) { color:var(--text); }
.s-card { background:var(--card); border:1px solid var(--border); border-radius:12px; padding:22px 24px; margin-bottom:16px; }
.s-card h3 { margin:0 0 14px; font-size:0.95rem; font-weight:700; }
.form-row { display:flex; gap:10px; flex-wrap:wrap; }
.form-row input, .form-row select { flex:1; min-width:120px; padding:8px 12px; border:1px solid var(--border); border-radius:8px; background:var(--bg); color:var(--text); font-size:0.875rem; }
.btn { padding:8px 18px; border:none; border-radius:8px; font-size:0.875rem; font-weight:600; cursor:pointer; }
.btn-primary { background:var(--accent); color:#fff; }
.btn-danger { background:transparent; border:1px solid #f4433660; color:#f44336; font-size:0.8rem; padding:4px 10px; border-radius:6px; }
.btn-danger:hover { background:#f4433615; }
table { width:100%; border-collapse:collapse; font-size:0.875rem; }
th { text-align:left; padding:8px 12px; color:var(--muted); font-weight:600; border-bottom:2px solid var(--border); }
td { padding:10px 12px; border-bottom:1px solid var(--border); vertical-align:middle; }
tr:last-child td { border-bottom:none; }
.color-dot { display:inline-block; width:12px; height:12px; border-radius:50%; margin-right:6px; vertical-align:middle; }
.type-badge { display:inline-block; padding:2px 8px; border-radius:20px; font-size:0.72rem; font-weight:600; background:var(--bg); border:1px solid var(--border); color:var(--muted); }
.empty-state { padding:32px; text-align:center; color:var(--muted); font-size:0.875rem; }
</style>
<h1 style="margin:0 0 20px;">Settings</h1>
<div class="tab-bar">
<a href="/settings?tab=accounts" class="{{if eq $d.Tab "accounts"}}active{{end}}">Accounts</a>
<a href="/settings?tab=categories" class="{{if eq $d.Tab "categories"}}active{{end}}">Categories</a>
</div>
{{if eq $d.Tab "accounts"}}
<div class="s-card">
<h3>Add account</h3>
<form method="post" action="/accounts" id="add-account-form">
<div class="form-row">
<input type="text" name="name" placeholder="Account name" required>
<select name="type">
<option value="checking">Checking</option>
<option value="savings">Savings</option>
<option value="credit">Credit card</option>
<option value="securities">Securities</option>
</select>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</form>
</div>
<div class="s-card">
{{if $d.Accounts}}
<table>
<thead><tr><th>Name</th><th>Type</th><th></th></tr></thead>
<tbody>
{{range $d.Accounts}}
<tr>
<td style="font-weight:500;">{{.Name}}</td>
<td><span class="type-badge">{{.Type}}</span></td>
<td style="text-align:right;">
<button class="btn btn-danger" onclick="deleteAccount('{{.ID}}')">Delete</button>
</td>
</tr>
{{end}}
</tbody>
</table>
{{else}}
<div class="empty-state">No accounts yet — add one above.</div>
{{end}}
</div>
{{else}}{{/* categories tab */}}
<div class="s-card">
<h3>Add category</h3>
<form method="post" action="/categories" id="add-cat-form">
<div class="form-row">
<input type="text" name="name" placeholder="Category name" required>
<input type="number" name="budget_cents" placeholder="Monthly budget (cents)" min="0">
<input type="color" name="color" value="#6366f1" style="flex:0; width:44px; padding:4px; border-radius:8px; cursor:pointer;">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</form>
</div>
<div class="s-card">
{{if $d.Categories}}
<table>
<thead><tr><th>Category</th><th style="text-align:right;">Monthly Budget</th><th></th></tr></thead>
<tbody>
{{range $d.Categories}}
<tr id="cat-row-{{.ID}}">
<td>
<span class="color-dot" style="background:{{if .Color}}{{.Color}}{{else}}#9e9e9e{{end}};"></span>
<span id="cat-name-{{.ID}}">{{.Name}}</span>
</td>
<td style="text-align:right;">
{{if .BudgetCents}}
<span id="cat-budget-{{.ID}}">€{{cents .BudgetCents}}</span>
{{else}}
<span id="cat-budget-{{.ID}}" style="color:var(--muted);"></span>
{{end}}
<button onclick="editCat('{{.ID}}','{{.Name}}',{{.BudgetCents}},'{{.Color}}')"
style="margin-left:8px; background:none; border:none; cursor:pointer; color:var(--muted); font-size:0.85rem;"></button>
</td>
<td style="text-align:right;">
<button class="btn btn-danger" onclick="deleteCat('{{.ID}}')">Delete</button>
</td>
</tr>
{{end}}
</tbody>
</table>
{{else}}
<div class="empty-state">No categories yet — add one above.</div>
{{end}}
</div>
{{end}}
<!-- Edit category modal -->
<div id="edit-cat-modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); backdrop-filter:blur(4px); z-index:300; align-items:center; justify-content:center;">
<div class="s-card" style="width:380px; max-width:95vw; margin:0; box-shadow:var(--shadow-lg);">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;">
<span style="font-weight:700;">Edit Category</span>
<button onclick="closeEditCat()" style="background:none; border:none; cursor:pointer; color:var(--muted); font-size:1.1rem;"></button>
</div>
<div style="display:flex; flex-direction:column; gap:10px;">
<input id="edit-cat-name" type="text" placeholder="Name" style="padding:8px 12px; border:1px solid var(--border); border-radius:8px; background:var(--bg); color:var(--text);">
<input id="edit-cat-budget" type="number" placeholder="Budget (cents)" min="0" style="padding:8px 12px; border:1px solid var(--border); border-radius:8px; background:var(--bg); color:var(--text);">
<input id="edit-cat-color" type="color" style="width:100%; height:38px; padding:4px; border:1px solid var(--border); border-radius:8px; cursor:pointer;">
</div>
<div style="display:flex; gap:8px; justify-content:flex-end; margin-top:16px;">
<button onclick="closeEditCat()" class="btn" style="background:var(--bg); border:1px solid var(--border); color:var(--text);">Cancel</button>
<button onclick="saveEditCat()" class="btn btn-primary">Save</button>
</div>
</div>
</div>
<script>
let editingCatID = null;
function deleteAccount(id) {
if (!confirm('Delete this account?')) return;
fetch('/accounts/' + id, { method: 'DELETE' })
.then(r => { if (r.ok) location.reload(); });
}
function deleteCat(id) {
if (!confirm('Delete this category?')) return;
fetch('/categories/' + id, { method: 'DELETE' })
.then(r => { if (r.ok) location.reload(); });
}
function editCat(id, name, budgetCents, color) {
editingCatID = id;
document.getElementById('edit-cat-name').value = name;
document.getElementById('edit-cat-budget').value = budgetCents || '';
document.getElementById('edit-cat-color').value = color || '#6366f1';
document.getElementById('edit-cat-modal').style.display = 'flex';
}
function closeEditCat() {
document.getElementById('edit-cat-modal').style.display = 'none';
editingCatID = null;
}
function saveEditCat() {
if (!editingCatID) return;
const body = new URLSearchParams({
name: document.getElementById('edit-cat-name').value,
budget_cents: document.getElementById('edit-cat-budget').value || '0',
color: document.getElementById('edit-cat-color').value,
});
fetch('/categories/' + editingCatID, { method: 'PUT', body })
.then(r => { if (r.ok) { closeEditCat(); location.reload(); } });
}
// After adding account/category, redirect back to same tab
document.getElementById('add-account-form')?.addEventListener('submit', function(e) {
e.preventDefault();
fetch(this.action, { method: 'POST', body: new FormData(this) })
.then(r => { if (r.ok || r.redirected) location.reload(); });
});
document.getElementById('add-cat-form')?.addEventListener('submit', function(e) {
e.preventDefault();
fetch(this.action, { method: 'POST', body: new FormData(this) })
.then(r => { if (r.ok || r.redirected) location.reload(); });
});
</script>
{{end}}