Home: Renewal status tab with expiry card

- Check tab renamed Renewal status / Show renewal status
- Result card: expiry date, days left, renewal window open or opening date, position, balance, donations, server page link
- Terms FAQ 6 follows the new name
This commit is contained in:
2026-11-06 19:22:24 +01:00
parent a13b93b8e0
commit 40d9b4ed80
2 changed files with 66 additions and 26 deletions

View File

@@ -223,6 +223,19 @@ tbody tr:hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}
background:var(--accent-soft);color:var(--accent);font-family:var(--mono);font-size:12px;display:flex;align-items:center;justify-content:center} background:var(--accent-soft);color:var(--accent);font-family:var(--mono);font-size:12px;display:flex;align-items:center;justify-content:center}
.mini-steps b{display:block;color:var(--ink);font-size:13.5px;margin-bottom:2px} .mini-steps b{display:block;color:var(--ink);font-size:13.5px;margin-bottom:2px}
.side-link{color:var(--accent);text-decoration:none;font-weight:600} .side-link{color:var(--accent);text-decoration:none;font-weight:600}
/* Renewal status result */
.renewal-card{margin-top:14px;border:1px solid var(--line);border-radius:var(--radius);background:var(--bg);padding:18px 20px}
.rc-main{display:flex;flex-direction:column;gap:2px;margin-bottom:14px}
.rc-label{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.rc-date{font-family:var(--display);font-size:30px;font-weight:600;line-height:1.1;color:var(--ink)}
.rc-sub{font-size:13px;color:var(--muted)}
.rc-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 18px;font-size:13px}
.rc-grid div{display:flex;flex-direction:column;gap:2px;border-top:1px solid var(--line);padding-top:8px}
.rc-grid span{color:var(--muted)}
.rc-grid b{font-family:var(--mono);font-weight:600}
.rc-link{display:inline-block;margin-top:14px;color:var(--accent);text-decoration:none;font-weight:600;font-size:13px}
.rc-link:hover{text-decoration:underline}
.rc-open{color:var(--ok)}
.side-link:hover{text-decoration:underline} .side-link:hover{text-decoration:underline}
@media (max-width:1024px){ @media (max-width:1024px){
.panel-body{grid-template-columns:1fr} .panel-body{grid-template-columns:1fr}
@@ -438,15 +451,15 @@ footer a{color:var(--accent);text-decoration:none}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add a server <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>Add a server
</button> </button>
<button type="button" role="tab" aria-selected="false" data-mode="check"> <button type="button" role="tab" aria-selected="false" data-mode="check">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.5-4.5"/></svg>Check a server <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></svg>Renewal status
</button> </button>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="panel-form"> <div class="panel-form">
<h2 data-add>Add your Will Executor</h2> <h2 data-add>Add your Will Executor</h2>
<h2 data-check hidden>Check your Will Executor</h2> <h2 data-check hidden>Renewal status of your Will Executor</h2>
<p class="lead" data-add>Enter your server URL. It will appear in the list once your deposit is confirmed (typically about 30 minutes).</p> <p class="lead" data-add>Enter your server URL. It will appear in the list once your deposit is confirmed (typically about 30 minutes).</p>
<p class="lead" data-check hidden>Enter the exact URL of your server as it appears in the list. You get its position, balance and expiry date. Nothing is charged.</p> <p class="lead" data-check hidden>Enter the exact URL of your server as it appears in the list: you see its expiry date and when you can renew. Nothing is charged.</p>
<div class="form-row"> <div class="form-row">
<input type="text" id="url" placeholder="https://we.bitcoin-after.life"> <input type="text" id="url" placeholder="https://we.bitcoin-after.life">
</div> </div>
@@ -455,11 +468,27 @@ footer a{color:var(--accent);text-decoration:none}
</div> </div>
<div class="btn-row"> <div class="btn-row">
<button class="btn" id="submit" data-add>Add server</button> <button class="btn" id="submit" data-add>Add server</button>
<button class="btn" id="check" data-check hidden>Check server</button> <button class="btn" id="check" data-check hidden>Show renewal status</button>
</div> </div>
<div class="ok-line" id="iv-status"></div> <div class="ok-line" id="iv-status"></div>
<!-- Renewal status result: filled by the "Show renewal status" button. -->
<div class="renewal-card" id="renewal-card" hidden>
<div class="rc-main">
<span class="rc-label">Expiry date</span>
<b class="rc-date" id="rc-expiry">&mdash;</b>
<span class="rc-sub" id="rc-days">&mdash;</span>
</div>
<div class="rc-grid">
<div><span>Renewal window</span><b id="rc-window">&mdash;</b></div>
<div><span>Position</span><b id="rc-pos">&mdash;</b></div>
<div><span>Balance</span><b id="rc-balance">&mdash;</b></div>
<div><span>Donations</span><b id="rc-donations">&mdash;</b></div>
</div>
<a class="rc-link" id="rc-link" href="#">View the server page &rarr;</a>
</div>
<div class="terms-box" id="terms-box"> <div class="terms-box" id="terms-box">
<p class="lead">You are about to add this server:</p> <p class="lead">You are about to add this server:</p>
<p><a id="terms-url" href="#" target="_blank" rel="noopener" class="mono"></a></p> <p><a id="terms-url" href="#" target="_blank" rel="noopener" class="mono"></a></p>
@@ -503,9 +532,9 @@ footer a{color:var(--accent);text-decoration:none}
<div data-check hidden> <div data-check hidden>
<p class="side-title">What you get</p> <p class="side-title">What you get</p>
<ol class="mini-steps"> <ol class="mini-steps">
<li><b>Position in the list</b><span>and the server page with its WeTime activity</span></li> <li><b>Expiry date</b><span>shown only here and on the server page, not in the main table</span></li>
<li><b>Balance and donations</b><span>what the server has paid so far</span></li> <li><b>Renewal window</b><span>it opens 6 months before expiry; you see whether it is open or when it opens</span></li>
<li><b>Expiry date</b><span>shown only here and on the server page; the renewal window opens 6 months before</span></li> <li><b>Position, balance, donations</b><span>and a link to the server page with its WeTime activity</span></li>
</ol> </ol>
</div> </div>
<a class="side-link" href="/terms.html">How listing works (15 s) &rarr;</a> <a class="side-link" href="/terms.html">How listing works (15 s) &rarr;</a>
@@ -792,6 +821,7 @@ document.getElementById('check').addEventListener('click', async () => {
const status = document.getElementById('iv-status'); const status = document.getElementById('iv-status');
const inv = document.getElementById('invoice'); const inv = document.getElementById('invoice');
inv.classList.remove('show'); inv.classList.remove('show');
document.getElementById('terms-box').classList.remove('show');
document.getElementById('renewal-card').hidden = true; document.getElementById('renewal-card').hidden = true;
status.className = ''; status.className = '';
status.textContent = 'Checking…'; status.textContent = 'Checking…';
@@ -801,30 +831,39 @@ document.getElementById('check').addEventListener('click', async () => {
const list = await listResp.json(); const list = await listResp.json();
const idx = list.findIndex(d => normalizeUrl(d.url || '').toLowerCase() === url.toLowerCase()); const idx = list.findIndex(d => normalizeUrl(d.url || '').toLowerCase() === url.toLowerCase());
if (idx < 0) { if (idx < 0) {
status.className = 'err-line'; status.className = 'err-line';
status.textContent = `Not in the ${chain} list: no server with this exact URL. To list it, use the "Add a server" tab.`; status.textContent = `Not in the ${chain} list: no server with this exact URL. To list it, use the "Add a server" tab.`;
return; return;
} }
const d = list[idx]; const d = list[idx];
const infoResp = await fetch(`/weinfodata/${chain}/${d.id}`); const infoResp = await fetch(`/weinfodata/${chain}/${d.id}`);
const info = infoResp.ok ? await infoResp.json() : {}; const info = infoResp.ok ? await infoResp.json() : {};
const expiry = (info.expiry_date || '').slice(0, 10); // '2027-07-16 00:00:00' -> the date const expiry = (info.expiry_date || '').slice(0, 10); // '2027-07-16 00:00:00' -> the date
const bal = info.balance != null ? fmt(info.balance) : null; const bal = info.balance != null ? fmt(info.balance) : null;
const unc = info.unconfirmed_balance != null ? fmt(info.unconfirmed_balance) : null; const unc = info.unconfirmed_balance != null ? fmt(info.unconfirmed_balance) : null;
document.getElementById('iv-chain').textContent = info.chain || chain; // Renewal window: from 6 months before expiry (Terms, Section 1).
document.getElementById('iv-balance').textContent = bal ? (unc ? bal + ' (' + unc + ')' : bal) : '—'; let daysText = '—', windowText = '—', windowOpen = false;
document.getElementById('iv-donations').textContent = info.donation != null ? fmt(info.donation) : '—'; if (expiry) {
document.getElementById('iv-contact').textContent = '—'; const exp = new Date(expiry + 'T00:00:00Z');
document.getElementById('iv-url').textContent = d.url; const win = new Date(exp); win.setUTCMonth(win.getUTCMonth() - 6);
const weinfoEl = document.getElementById('iv-weinfo'); const days = Math.ceil((exp - Date.now()) / 86400000);
weinfoEl.href = `/weinfo/${chain}/${d.id}`; daysText = days > 0 ? `${days} days left` : 'expired';
weinfoEl.textContent = 'View page'; windowOpen = Date.now() >= win.getTime() && days > 0;
document.getElementById('iv-nextdep').textContent = expiry; windowText = windowOpen ? 'open now: you can renew' : `opens on ${win.toISOString().slice(0, 10)}`;
document.getElementById('iv-nextdep-row').style.display = 'flex'; }
document.getElementById('rc-expiry').textContent = expiry || '—';
document.getElementById('rc-days').textContent = daysText;
const winEl = document.getElementById('rc-window');
winEl.textContent = windowText;
winEl.className = windowOpen ? 'rc-open' : '';
document.getElementById('rc-pos').textContent = `#${idx + 1} of ${list.length}`;
document.getElementById('rc-balance').textContent = bal ? (unc ? bal + ' (' + unc + ')' : bal) : '—';
document.getElementById('rc-donations').textContent = info.donation != null ? fmt(info.donation) : '—';
document.getElementById('rc-link').href = `/weinfo/${chain}/${d.id}`; document.getElementById('rc-link').href = `/weinfo/${chain}/${d.id}`;
status.className = 'ok-line'; status.className = 'ok-line';
status.textContent = `Server is listed (#${idx + 1} of ${list.length}). Expiry: ${expiry}. Renewal opens 6 months before.`; status.textContent = windowOpen ? '✓ Listed. The renewal window is open.' : '✓ Listed.';
inv.classList.add('show'); const card = document.getElementById('renewal-card');
card.hidden = false;
card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} catch (err) { } catch (err) {
status.className = 'err-line'; status.className = 'err-line';
@@ -988,6 +1027,7 @@ document.getElementById('terms-accept').addEventListener('click', async function
const status = document.getElementById('iv-status'); const status = document.getElementById('iv-status');
status.className = ''; status.textContent = ''; status.className = ''; status.textContent = '';
document.getElementById('terms-box').classList.remove('show'); document.getElementById('terms-box').classList.remove('show');
document.getElementById('invoice').classList.remove('show');
document.getElementById('renewal-card').hidden = true; document.getElementById('renewal-card').hidden = true;
} }
tabs.forEach(b => b.addEventListener('click', () => setMode(b.dataset.mode))); tabs.forEach(b => b.addEventListener('click', () => setMode(b.dataset.mode)));

View File

@@ -256,7 +256,7 @@ footer a{color:var(--accent);text-decoration:none}
"name": "Where do I see my expiry date?", "name": "Where do I see my expiry date?",
"acceptedAnswer": { "acceptedAnswer": {
"@type": "Answer", "@type": "Answer",
"text": "On the home page, open the “Check a server” tab, enter the exact URL of your server as it appears in the list and press “Check server”. Nothing is charged: you get the server's position in the list, its balance and donations, and its expiry date; “View page” opens the server's detail page with its WeTime activity. The date is not shown in the main table, so you need the exact URL. Knowing it also tells you when your renewal window opens (6 months before). Since the price per day is fixed and public, the expiry date shows how much a server has paid: this is intentional transparency." "text": "On the home page, open the “Renewal status” tab, enter the exact URL of your server as it appears in the list and press “Show renewal status”. Nothing is charged: you see the expiry date, the days left, whether the renewal window is open (or when it opens), the position in the list, the balance and the donations, with a link to the server page. The date is not shown in the main table, so you need the exact URL. Knowing it also tells you when your renewal window opens (6 months before). Since the price per day is fixed and public, the expiry date shows how much a server has paid: this is intentional transparency."
} }
}, },
{ {
@@ -663,7 +663,7 @@ l-49 -25 -880 0 -880 0 -3 704 c-2 557 0 706 10 713 7 4 407 7 888 5 818 -2
</details> </details>
<details> <details>
<summary><span>Where do I see my expiry date?</span></summary> <summary><span>Where do I see my expiry date?</span></summary>
<p>On the home page, open the “Check a server” tab, enter the exact URL of your server as it appears in the list and press “Check server”. Nothing is charged: you get the server's position in the list, its balance and donations, and its expiry date; “View page” opens the server's detail page with its WeTime activity. The date is not shown in the main table, so you need the exact URL. Knowing it also tells you when your renewal window opens (6 months before). Since the price per day is fixed and public, the expiry date shows how much a server has paid: this is intentional transparency. <a href="/?mode=check">Open the Check tab &rarr;</a></p> <p>On the home page, open the “Renewal status” tab, enter the exact URL of your server as it appears in the list and press “Show renewal status”. Nothing is charged: you see the expiry date, the days left, whether the renewal window is open (or when it opens), the position in the list, the balance and the donations, with a link to the server page. The date is not shown in the main table, so you need the exact URL. Knowing it also tells you when your renewal window opens (6 months before). Since the price per day is fixed and public, the expiry date shows how much a server has paid: this is intentional transparency. <a href="/?mode=check">Open the Renewal status tab &rarr;</a></p>
</details> </details>
<details> <details>
<summary><span>How is the order of the list decided?</span></summary> <summary><span>How is the order of the list decided?</span></summary>