ClubLedger/static/index.html
Claude fa4884bdb4
Add store-credit web app (FastAPI + SQLite)
- main.py: single-file backend with Member, LedgerEntry, Product models;
  endpoints for register, list/search members, topup (cashier), charge (bar,
  PIN-verified), transaction history, printable HTML statement, product CRUD.
  All monetary values stored as integers (pence). bcrypt PIN hashing.
  Admin-tunable CONFIG dict at top of file.
- static/index.html + style.css + app.js: three-view SPA (Members, Cashier,
  Bar) with member search, product search with member-price support, and
  XSS-safe rendering throughout.
- requirements.txt: fastapi, uvicorn, bcrypt only.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 05:21:01 +00:00

129 lines
4.5 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ClubLedger</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<nav>
<span class="brand" id="navBrand">ClubLedger</span>
<button class="nav-btn active" data-view="members">Members</button>
<button class="nav-btn" data-view="cashier">Cashier</button>
<button class="nav-btn" data-view="bar">Bar</button>
</nav>
<!-- ===================== MEMBERS VIEW ===================== -->
<div id="view-members" class="view">
<div class="panel">
<h2>Register New Member</h2>
<form id="registerForm">
<div class="form-row">
<label>Member Number</label>
<input type="text" id="reg-number" placeholder="e.g. 001" required>
</div>
<div class="form-row">
<label>Full Name</label>
<input type="text" id="reg-name" placeholder="Name" required>
</div>
<div class="form-row">
<label>PIN</label>
<input type="password" id="reg-pin" placeholder="Min 4 digits" required>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
<div id="registerMsg" class="msg"></div>
</div>
<div class="panel">
<h2>Member Search</h2>
<div class="search-row">
<input type="text" id="memberSearch" placeholder="Search name or number…">
<button class="btn" onclick="searchMembers()">Search</button>
</div>
<table id="memberTable" class="data-table">
<thead><tr><th>#</th><th>Name</th><th>Balance</th><th>Joined</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<!-- ===================== CASHIER VIEW ===================== -->
<div id="view-cashier" class="view hidden">
<div class="panel">
<h2>Top Up Account</h2>
<div class="search-row">
<input type="text" id="cashierSearch" placeholder="Search member…">
<button class="btn" onclick="cashierSearchMembers()">Search</button>
</div>
<div id="cashierMemberList" class="member-pick-list"></div>
<div id="cashierForm" class="hidden">
<div class="selected-member-box" id="cashierSelected"></div>
<div class="form-row">
<label>Amount (<span class="currency-unit"></span>)</label>
<input type="number" id="cashierAmount" placeholder="e.g. 1000" min="1" step="1">
</div>
<div class="form-row">
<label>Staff Name</label>
<input type="text" id="cashierStaff" placeholder="Your name">
</div>
<div class="form-row">
<label>Note (optional)</label>
<input type="text" id="cashierNote" placeholder="">
</div>
<button class="btn btn-primary" onclick="doTopup()">Top Up</button>
<button class="btn" onclick="clearCashierSelection()">Cancel</button>
</div>
<div id="cashierMsg" class="msg"></div>
</div>
</div>
<!-- ===================== BAR VIEW ===================== -->
<div id="view-bar" class="view hidden">
<div class="panel">
<h2>Charge Account</h2>
<div class="search-row">
<input type="text" id="barSearch" placeholder="Search member…">
<button class="btn" onclick="barSearchMembers()">Search</button>
</div>
<div id="barMemberList" class="member-pick-list"></div>
<div id="barForm" class="hidden">
<div class="selected-member-box" id="barSelected"></div>
<!-- Product search -->
<div class="form-row">
<label>Product Search</label>
<input type="text" id="barProductSearch" placeholder="Search products…" oninput="barProductLookup()">
</div>
<div id="barProductResults" class="product-results"></div>
<div class="form-row">
<label>Amount (<span class="currency-unit"></span>)</label>
<input type="number" id="barAmount" placeholder="e.g. 350" min="1" step="1">
</div>
<div class="form-row">
<label>PIN</label>
<input type="password" id="barPin" placeholder="Member PIN" maxlength="20">
</div>
<div class="form-row">
<label>Staff Name</label>
<input type="text" id="barStaff" placeholder="Your name">
</div>
<div class="form-row">
<label>Note (optional)</label>
<input type="text" id="barNote" placeholder="">
</div>
<button class="btn btn-danger" onclick="doCharge()">Charge</button>
<button class="btn" onclick="clearBarSelection()">Cancel</button>
</div>
<div id="barMsg" class="msg"></div>
</div>
</div>
<script src="/static/app.js"></script>
</body>
</html>