- Instead of entering a hard-to-calculate rate like 0.00773, users now enter a real sample (e.g. receipt=1000 KES, claimed=7.73 USD) - The system computes the rate automatically: 7.73 / 1000 = 0.00773 - Users can get the sample values from their payment app notification - Much more intuitive, especially for currencies with small exchange rates
151 lines
8.4 KiB
HTML
151 lines
8.4 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>Dashboard - ExpenseFlow</title>
|
|
<link rel="manifest" href="/manifest.json">
|
|
<link rel="stylesheet" href="/static/css/style.css">
|
|
<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">ExpenseFlow</h1>
|
|
<a href="/" class="btn btn-secondary btn-sm"
|
|
hx-post="/logout" hx-target="body" hx-push-url="true"
|
|
hx-confirm="Are you sure you want to logout?">Logout</a>
|
|
</header>
|
|
|
|
<main class="main-content">
|
|
<div class="dashboard-header">
|
|
<h2>My Events</h2>
|
|
<button class="btn btn-primary"
|
|
onclick="document.getElementById('create-event-form').classList.toggle('hidden')">
|
|
+ New Event
|
|
</button>
|
|
</div>
|
|
|
|
<div id="create-event-form" class="hidden" style="margin-bottom: 1.5rem;">
|
|
<div class="card" style="padding: 1rem;">
|
|
<form hx-post="/events" hx-target="body" hx-push-url="true">
|
|
<div class="form-group">
|
|
<label for="name">Event Name</label>
|
|
<input type="text" id="name" name="name" placeholder="e.g., WebSummit 2026" required>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="base_currency">Claim Currency</label>
|
|
<select id="base_currency" name="base_currency" required>
|
|
<option value="EUR">EUR - Euro</option>
|
|
<option value="USD" selected>USD - US Dollar</option>
|
|
<option value="GBP">GBP - British Pound</option>
|
|
<option value="KES">KES - Kenyan Shilling</option>
|
|
<option value="CHF">CHF - Swiss Franc</option>
|
|
<option value="SEK">SEK - Swedish Krona</option>
|
|
<option value="NOK">NOK - Norwegian Krone</option>
|
|
<option value="PLN">PLN - Polish Zloty</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="card" style="padding: 0.75rem; background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 0.5rem; margin-bottom: 0.5rem;">
|
|
<div style="font-size: 0.875rem; font-weight: 600; color: #166534; margin-bottom: 0.5rem;">
|
|
💱 Conversion Sample
|
|
</div>
|
|
<p style="font-size: 0.8rem; color: #4b5563; margin-bottom: 0.75rem;">
|
|
Enter a real receipt amount and what you were actually charged in your claim currency.
|
|
The exchange rate is calculated automatically. Check your payment app/bank notification for the exact converted amount.
|
|
</p>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="sample_receipt_amount">Receipt Amount</label>
|
|
<input type="number" id="sample_receipt_amount" name="sample_receipt_amount" step="0.01" min="0.01" placeholder="e.g. 1000" required inputmode="decimal">
|
|
</div>
|
|
<div class="form-group" style="flex: 0 0 120px;">
|
|
<label for="sample_receipt_currency">Currency</label>
|
|
<select id="sample_receipt_currency" name="sample_receipt_currency" required>
|
|
<option value="KES" selected>KES</option>
|
|
<option value="USD">USD</option>
|
|
<option value="EUR">EUR</option>
|
|
<option value="GBP">GBP</option>
|
|
<option value="JPY">JPY</option>
|
|
<option value="CHF">CHF</option>
|
|
<option value="SEK">SEK</option>
|
|
<option value="NOK">NOK</option>
|
|
<option value="DKK">DKK</option>
|
|
<option value="PLN">PLN</option>
|
|
<option value="ZAR">ZAR</option>
|
|
<option value="NGN">NGN</option>
|
|
<option value="TZS">TZS</option>
|
|
<option value="UGX">UGX</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="sample_claim_amount">What you claimed / were charged</label>
|
|
<input type="number" id="sample_claim_amount" name="sample_claim_amount" step="0.01" min="0.01" placeholder="e.g. 7.73" required inputmode="decimal">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary btn-block">Create Event</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="event-list">
|
|
{{if .Events}}
|
|
<div class="event-grid">
|
|
{{range .Events}}
|
|
<div class="card event-card">
|
|
<div class="event-card-header">
|
|
<h3 class="event-card-name">{{.Name}}</h3>
|
|
<span id="status-badge-{{.ID}}" class="badge badge-{{.Status}}">{{.Status}}</span>
|
|
</div>
|
|
<div class="event-card-meta">
|
|
<span>Created: {{.CreatedAt}}</span>
|
|
<span>Claim in: {{.BaseCurrency}} @ {{printf "%.6f" .ExchangeRate}}</span>
|
|
</div>
|
|
<div class="event-card-actions">
|
|
{{if eq .Status "open"}}
|
|
<a href="/events/{{.ID}}/expenses" class="btn btn-primary btn-sm"
|
|
hx-get="/events/{{.ID}}/expenses" hx-target="body" hx-push-url="true">
|
|
Add Expenses
|
|
</a>
|
|
{{else}}
|
|
<button class="btn btn-secondary btn-sm"
|
|
hx-put="/events/{{.ID}}/reopen"
|
|
hx-target="#status-badge-{{.ID}}"
|
|
hx-swap="outerHTML">
|
|
Reopen
|
|
</button>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{else}}
|
|
<div class="empty-state">
|
|
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
<polyline points="14 2 14 8 20 8"/>
|
|
<line x1="12" y1="18" x2="12" y2="12"/>
|
|
<line x1="9" y1="15" x2="15" y2="15"/>
|
|
</svg>
|
|
<h3>No Events Yet</h3>
|
|
<p>Create your first event to start tracking expenses.</p>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
// Toggle hidden class
|
|
document.querySelector('button[onclick]')?.addEventListener('click', function() {
|
|
// handled inline
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|