room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
{% extends "core/base.html" %}
|
|
|
|
|
{% load static %}
|
|
|
|
|
{% load lyric_extras %}
|
|
|
|
|
|
|
|
|
|
{% block title_text %}Game Gate{% endblock title_text %}
|
|
|
|
|
{% block header_text %}<span>Game</span><span>Gate</span>{% endblock header_text %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
2026-05-31 23:21:58 -04:00
|
|
|
{# Room renewal gate-view (sprint 2026-05-31) — reuses the EXACT gatekeeper #}
|
|
|
|
|
{# token-slot modal (`_gatekeeper.html` chrome: title panel + status-dots + #}
|
|
|
|
|
{# token-slot rails + roles panel), reachable mid-game. Unlike the #}
|
|
|
|
|
{# gatekeeper (which redirects to the table once table_status is set), GATE #}
|
|
|
|
|
{# VIEW routes here at any time so a seated gamer can renew. #}
|
|
|
|
|
{# • cost current → roles-panel `.btn-primary` is CONT GAME (→ table hex, #}
|
|
|
|
|
{# same target as the gear NVM); status "<n> Token(s) Deposited . . . .".#}
|
|
|
|
|
{# • cost lapsed → no CONT GAME; the rails go active to RENEW; status #}
|
|
|
|
|
{# "Please Deposit Token . . . .". Renewing re-satisfies the cost and #}
|
|
|
|
|
{# the CONT GAME btn reappears. #}
|
|
|
|
|
{# No seat circle / countdown here — the table hex's own `.fa-chair` shows #}
|
|
|
|
|
{# seat status, and user/seat tooltips land next sprint (user-spec). #}
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
<div class="room-page room-gate-page" data-room-id="{{ room.id }}">
|
|
|
|
|
<div id="id_gate_wrapper" class="room-gate-wrapper">
|
|
|
|
|
<div class="gate-backdrop"></div>
|
|
|
|
|
<div class="gate-overlay room-gate-overlay">
|
|
|
|
|
<div class="gate-modal room-gate-modal" role="dialog" aria-label="Renewal Gate">
|
|
|
|
|
|
|
|
|
|
<div class="gate-title-panel">
|
|
|
|
|
<header class="gate-header">
|
|
|
|
|
<h1>{{ room.name }}</h1>
|
|
|
|
|
<div class="gate-status-wrap">
|
2026-05-31 23:21:58 -04:00
|
|
|
<span class="gate-status-text">{% if cost_current %}{{ deposited_count }} Token(s) Deposited{% else %}Please Deposit Token{% endif %}</span>
|
|
|
|
|
<span class="status-dots" aria-hidden="true">
|
|
|
|
|
<span></span><span></span><span></span><span></span>
|
|
|
|
|
</span>
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="gate-top-row">
|
|
|
|
|
<div class="gate-main-panel">
|
2026-05-31 23:21:58 -04:00
|
|
|
{# Cost current → claimed (static rails, token in the slot). #}
|
|
|
|
|
{# Cost lapsed → active rails that POST to renew_token. #}
|
|
|
|
|
<div class="token-slot{% if cost_current %} claimed{% else %} active{% endif %}">
|
|
|
|
|
{% if not cost_current %}
|
|
|
|
|
<form method="POST" action="{% url 'epic:renew_token' room.id %}" style="display:contents">
|
|
|
|
|
{% csrf_token %}
|
|
|
|
|
<button type="submit" class="token-rails" aria-label="Insert token to renew">
|
|
|
|
|
<span class="rail"></span>
|
|
|
|
|
<span class="rail"></span>
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
{% else %}
|
|
|
|
|
<div class="token-rails">
|
|
|
|
|
<span class="rail"></span>
|
|
|
|
|
<span class="rail"></span>
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
<div class="token-panel">
|
|
|
|
|
<div class="token-denomination">1</div>
|
|
|
|
|
<span class="token-insert-label">INSERT TOKEN TO PLAY</span>
|
|
|
|
|
<span class="token-return-label">PUSH TO RETURN</span>
|
|
|
|
|
</div>
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="gate-roles-panel">
|
2026-05-31 23:21:58 -04:00
|
|
|
{% if cost_current %}
|
|
|
|
|
{# CONT GAME — same destination as the gear NVM (the table #}
|
|
|
|
|
{# hex). Non-destructive nav, so no confirm guard. Only #}
|
|
|
|
|
{# rendered while the token cost is satisfied. #}
|
|
|
|
|
<button type="button"
|
|
|
|
|
id="id_room_cont_game_btn"
|
|
|
|
|
class="launch-game-btn btn btn-primary"
|
|
|
|
|
onclick="window.location.href='{% url 'epic:room' room.id %}'">CONT<br>GAME</button>
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
{% endif %}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{# NVM nav-backs one step to the table hex (not out to /gameboard/). #}
|
|
|
|
|
{% url 'epic:room' room.id as nvm_url %}
|
|
|
|
|
{% include "apps/gameboard/_partials/_room_gear.html" with nvm_url=nvm_url %}
|
|
|
|
|
{% include "apps/gameboard/_partials/_burger.html" %}
|
|
|
|
|
</div>
|
|
|
|
|
{% endblock content %}
|
|
|
|
|
|
|
|
|
|
{% block scripts %}
|
|
|
|
|
<script src="{% static 'apps/dashboard/note.js' %}"></script>
|
|
|
|
|
<script src="{% static 'apps/epic/burger-btn.js' %}"></script>
|
|
|
|
|
<script>
|
2026-05-31 23:21:58 -04:00
|
|
|
{# Status-dots animation — identical loop to _gatekeeper.html so the #}
|
|
|
|
|
{# "Token(s) Deposited . . . ." / "Please Deposit Token . . . ." status #}
|
|
|
|
|
{# pulses the same way as the gather-flow gatekeeper. #}
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
(function () {
|
2026-05-31 23:21:58 -04:00
|
|
|
clearInterval(window._gateDots);
|
|
|
|
|
var wrap = document.querySelector('.status-dots');
|
|
|
|
|
if (!wrap) return;
|
|
|
|
|
var dots = wrap.querySelectorAll('span');
|
|
|
|
|
var n = 0;
|
|
|
|
|
window._gateDots = setInterval(function () {
|
|
|
|
|
if (!document.contains(wrap)) { clearInterval(window._gateDots); return; }
|
|
|
|
|
dots.forEach(function (d, i) { d.textContent = i < n ? '.' : ''; });
|
|
|
|
|
n = (n + 1) % 5;
|
|
|
|
|
}, 400);
|
room gate-view: mid-game renewal area (room_gate) + renew_token endpoint + _room_gear nvm_url — TDD
Phase 4 of the room GATE VIEW + seat-renewal sprint. The 3rd-person
mirror of my_sea_gate: a gate-view a seated gamer can open at any time
to check token TIME REMAINING or RENEW, reachable even mid-game (the
gatekeeper redirects to the table once table_status is set — this view
does not).
- `room_gate` view + `room/<uuid>/gate/view/` URL — renders the viewer's
own seat/position circle, a live time-remaining ticker (counts down to
cost_current_until, then to grace_expires_at in renewal grace), and a
RENEW affordance. page_class carries `page-room` (drives the navbar
GATE VIEW in Phase 0). No seat → "no seat" copy, no RENEW btn.
- `renew_token` view + `room/<uuid>/gate/renew` URL — re-deposits a token
into the viewer's already-FILLED slot via the existing `debit_token`
(resets filled_at=now → restarts the cost-current window). Reuses
select_token / debit_token wholesale; distinct from confirm_token,
which needs a RESERVED slot. 402 when token-depleted; no-op redirect
when the user holds no filled slot (already auto-BYE'd).
- `room_gate.html` — reuses the gatekeeper's .gate-overlay/.gate-modal
chrome (hand-rolled like my_sea_gate, inner content differs) + an
inline countdown ticker mirroring the status-dots IIFE.
- DRY: `_room_gear.html` now takes an `nvm_url` param (default the
gameboard listing — room.html's own gear unchanged); the gate-view
passes the table-hex URL so NVM returns to the hex, mirroring
_my_sea_gear's contract.
Tests: RoomGateViewTest (7) + RoomRenewTokenTest (6) — renders mid-game,
own seat circle, data-cost-until, RENEW posts to renew_token, NVM→hex,
page-room marker, no-seat render; renew resets filled_at + consumes FREE
+ records SLOT_FILLED, no-slot/GET redirects, 402 when depleted. 504
epic tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:55:17 -04:00
|
|
|
}());
|
|
|
|
|
</script>
|
|
|
|
|
{% endblock scripts %}
|