67 lines
3.4 KiB
HTML
67 lines
3.4 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Customer service — account review</title>
|
|
<style>
|
|
body { font-family: -apple-system, sans-serif; margin: 2rem; max-width: 960px; color: #171a26; }
|
|
h1 { font-size: 1.3rem; }
|
|
label { font-size: 0.8rem; font-weight: 600; display: block; margin-top: 0.6rem; }
|
|
input { padding: 0.4rem 0.55rem; }
|
|
button { margin-top: 0.8rem; padding: 0.4rem 0.8rem; }
|
|
table { border-collapse: collapse; width: 100%; margin-top: 0.6rem; }
|
|
th, td { border-bottom: 1px solid #e5e7f0; padding: 0.4rem 0.5rem; text-align: left; font-size: 0.88rem; }
|
|
.muted { color: #6b7186; }
|
|
.card { border: 1px solid #e5e7f0; border-radius: 10px; padding: 1rem; margin: 1rem 0; }
|
|
.stat { font-size: 1.4rem; font-weight: 800; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Customer service</h1>
|
|
<p class="muted">Review prepaid balance, credits, usage, and payments. Credits go to account-balance over NATS.</p>
|
|
<div class="card">
|
|
<label>Customer id</label>
|
|
<input id="id" value="cust_1" />
|
|
<button onclick="review()">Review</button>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Add credit</h3>
|
|
<label>Cents</label><input id="cents" type="number" value="500" />
|
|
<label>Reason</label><input id="reason" value="goodwill" />
|
|
<label>Agent</label><input id="agent" value="cs" />
|
|
<button onclick="credit()">Apply credit</button>
|
|
</div>
|
|
<div id="out"></div>
|
|
<script>
|
|
const fmt = (c) => (c < 0 ? '-$' : '$') + (Math.abs(c || 0) / 100).toFixed(2);
|
|
const rows = (list, cols) =>
|
|
(list || [])
|
|
.map((r) => '<tr>' + cols.map((c) => `<td>${r[c] ?? ''}</td>`).join('') + '</tr>')
|
|
.join('') || '<tr><td colspan="8" class="muted">none</td></tr>';
|
|
async function review() {
|
|
const id = document.getElementById('id').value.trim();
|
|
const st = await (await fetch('/review/' + encodeURIComponent(id))).json();
|
|
document.getElementById('out').innerHTML = `
|
|
<div class="card"><div class="muted">Prepaid</div><div class="stat">${fmt(st.prepaidCents)}</div>
|
|
<p class="muted">source ${st.source || 'unknown'}</p></div>
|
|
<div class="card"><h3>Credits</h3><table><thead><tr><th>cents</th><th>reason</th><th>agent</th><th>at</th></tr></thead>
|
|
<tbody>${rows(st.credits, ['cents','reason','agent','at'])}</tbody></table></div>
|
|
<div class="card"><h3>Usage</h3><table><thead><tr><th>endpoint</th><th>cents</th><th>at</th></tr></thead>
|
|
<tbody>${rows(st.usage, ['endpointId','cents','at'])}</tbody></table></div>
|
|
<div class="card"><h3>Payments</h3><table><thead><tr><th>cents</th><th>kind</th><th>reason</th><th>at</th></tr></thead>
|
|
<tbody>${rows(st.payments, ['cents','kind','reason','at'])}</tbody></table></div>`;
|
|
}
|
|
async function credit() {
|
|
const body = {
|
|
customerId: document.getElementById('id').value.trim(),
|
|
cents: Number(document.getElementById('cents').value),
|
|
reason: document.getElementById('reason').value,
|
|
agent: document.getElementById('agent').value,
|
|
};
|
|
await fetch('/credits', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
|
|
await review();
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|