- Restructure hierarchy: Month → Event → Expense (new months table, FK) - Add MonthHandler with CRUD, monthly reports, dropdown create form - Events now scoped under months with extended ownership chain - AI extraction: 16 specific expense categories (Airfare, Meals, etc.) - UI: category dropdown, button-consistent cards, centered mobile shell on desktop - Dashboard/month views show claim totals per card - Description field now mandatory, forms simplified - Months sorted by name chronologically (latest first)
118 lines
6.8 KiB
HTML
118 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="theme-color" content="#10b981">
|
|
<title>NextExpense</title>
|
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
|
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
|
<link rel="manifest" href="/manifest.json">
|
|
<link rel="stylesheet" href="/static/css/style.css?v=5">
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
|
</head>
|
|
<body>
|
|
<div class="app-shell">
|
|
<header class="app-header">
|
|
<h1 class="app-title"><img src="/static/favicon.svg" width="24" height="24" alt="" style="vertical-align: middle; margin-right: 0.5rem;">NextExpense</h1>
|
|
<div style="display: flex; gap: 0.5rem;">
|
|
<button class="btn btn-secondary btn-sm" style="font-size: 0.75rem;"
|
|
hx-get="/profile" hx-target="body" hx-push-url="true">Profile</button>
|
|
<button class="btn btn-secondary btn-sm" style="font-size: 0.75rem;"
|
|
hx-post="/logout" hx-target="body" hx-push-url="true">Logout</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="main-content">
|
|
<div class="dashboard-header">
|
|
<h2>My Months</h2>
|
|
<button class="btn btn-primary btn-sm"
|
|
onclick="document.getElementById('create-form').classList.toggle('hidden')">
|
|
+ New
|
|
</button>
|
|
</div>
|
|
|
|
<div id="create-form" class="hidden" style="margin-bottom: 1rem;">
|
|
<div class="card" style="padding: 1rem;">
|
|
<h3 style="margin-bottom: 1rem;">New Month</h3>
|
|
<form hx-post="/months" hx-target="body" hx-push-url="true">
|
|
<div class="form-row" style="gap: 1rem;">
|
|
<div style="flex: 2;">
|
|
<label class="form-label">Month</label>
|
|
<select name="month" required style="width: 100%; padding: 0.6rem; border: 1px solid var(--color-border); border-radius: 0.375rem; background: #1e293b; color: #f8fafc; font-size: 0.9rem;">
|
|
<option value="">Select</option>
|
|
<option value="January">January</option>
|
|
<option value="February">February</option>
|
|
<option value="March">March</option>
|
|
<option value="April">April</option>
|
|
<option value="May">May</option>
|
|
<option value="June">June</option>
|
|
<option value="July">July</option>
|
|
<option value="August">August</option>
|
|
<option value="September">September</option>
|
|
<option value="October">October</option>
|
|
<option value="November">November</option>
|
|
<option value="December">December</option>
|
|
</select>
|
|
</div>
|
|
<div style="flex: 1;">
|
|
<label class="form-label">Year</label>
|
|
<select name="year" required style="width: 100%; padding: 0.6rem; border: 1px solid var(--color-border); border-radius: 0.375rem; background: #1e293b; color: #f8fafc; font-size: 0.9rem;">
|
|
<option value="">Select</option>
|
|
<option value="2024">2024</option>
|
|
<option value="2025">2025</option>
|
|
<option value="2026" selected>2026</option>
|
|
<option value="2027">2027</option>
|
|
<option value="2028">2028</option>
|
|
<option value="2029">2029</option>
|
|
<option value="2030">2030</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary btn-block">Create Month</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="month-list">
|
|
{{if .Months}}
|
|
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
|
{{range .Months}}
|
|
<div class="month-card" style="display: flex; align-items: center; justify-content: space-between; background: var(--color-card); border: 1px solid var(--color-border); border-left: 4px solid var(--color-primary); border-radius: 0.5rem; padding: 0.75rem 1rem;">
|
|
<div>
|
|
<div style="font-weight: 500; color: var(--color-text);">{{.Month.Name}}</div>
|
|
<div style="font-size: 0.75rem; color: var(--color-text-muted);">{{.Month.CreatedAt}}</div>
|
|
</div>
|
|
{{if .Total}}
|
|
<div style="text-align: right; margin-right: 0.75rem;">
|
|
<div style="font-size: 0.7rem; color: var(--color-text-muted);">claim</div>
|
|
<div style="font-weight: 600; color: var(--color-primary); font-size: 0.95rem;">{{printf "%.2f" .Total}}</div>
|
|
</div>
|
|
{{end}}
|
|
<div style="display: flex; gap: 0.5rem;">
|
|
<button class="btn btn-primary btn-sm"
|
|
hx-get="/months/{{.Month.ID}}" hx-target="body" hx-push-url="true">
|
|
Open
|
|
</button>
|
|
<button class="btn btn-secondary btn-sm"
|
|
hx-get="/months/{{.Month.ID}}/edit"
|
|
hx-target="#create-form"
|
|
hx-swap="innerHTML"
|
|
onclick="document.getElementById('create-form').classList.remove('hidden')"
|
|
style="font-size: 0.75rem;">
|
|
Edit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{else}}
|
|
<div class="empty-state" style="text-align: center; padding: 3rem; color: #94a3b8;">
|
|
<p>No months yet. Create one to get started.</p>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</body>
|
|
</html>
|