navbar: GATE VIEW swaps for CONT GAME on room pages (page-room) → room gate-view — TDD
Phase 0 of the room GATE VIEW + seat-renewal sprint. Mirrors the my-sea treatment: on any room page the self-referential CONT GAME is replaced by a GATE VIEW button that opens the room's renewal gate-view. - `room_view` page_class → "page-gameboard page-room"; the bare gameboard listing stays "page-gameboard" (no page-room) so CONT GAME persists there for returning to a recent room. - `_navbar.html` GATE VIEW branch fires on `page-my-sea` OR `page-room`; onclick routes, in precedence: page-room → epic:room_gate (room in context); my-sea-visit → visitor gate; else owner's sea gate. One consolidated branch (DRY) instead of two near-identical button blocks. Tests: RoomNavbarGateViewTest (4) — room page shows GATE VIEW not CONT GAME, links to room_gate, gate-view page also shows it, page-room marker present. 826 epic+gameboard ITs green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2730,3 +2730,35 @@ class RoomRenewTokenTest(TestCase):
|
||||
def test_renew_get_redirects(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
|
||||
class RoomNavbarGateViewTest(TestCase):
|
||||
"""Navbar swaps CONT GAME → GATE VIEW on room pages (mirror my-sea),
|
||||
routing to the room gate-view. The gameboard listing keeps CONT GAME
|
||||
(no `page-room` marker)."""
|
||||
|
||||
def setUp(self):
|
||||
self.owner = User.objects.create(email="owner@test.io", username="owner")
|
||||
self.room = Room.objects.create(
|
||||
name="Nav Room", owner=self.owner,
|
||||
gate_status=Room.OPEN, table_status=Room.ROLE_SELECT,
|
||||
)
|
||||
self.client.force_login(self.owner)
|
||||
|
||||
def test_room_page_shows_gate_view_not_cont_game(self):
|
||||
response = self.client.get(reverse("epic:room", args=[self.room.id]))
|
||||
self.assertContains(response, "id_navbar_gate_view_btn")
|
||||
self.assertNotContains(response, 'id="id_cont_game"')
|
||||
|
||||
def test_gate_view_btn_links_to_room_gate(self):
|
||||
response = self.client.get(reverse("epic:room", args=[self.room.id]))
|
||||
self.assertContains(
|
||||
response, reverse("epic:room_gate", args=[self.room.id]))
|
||||
|
||||
def test_room_gate_page_also_shows_gate_view(self):
|
||||
response = self.client.get(reverse("epic:room_gate", args=[self.room.id]))
|
||||
self.assertContains(response, "id_navbar_gate_view_btn")
|
||||
|
||||
def test_room_page_carries_page_room_marker(self):
|
||||
response = self.client.get(reverse("epic:room", args=[self.room.id]))
|
||||
self.assertIn("page-room", response.context["page_class"])
|
||||
|
||||
@@ -449,7 +449,11 @@ def room_view(request, room_id):
|
||||
room = Room.objects.get(id=room_id)
|
||||
ctx = _role_select_context(room, request.user)
|
||||
ctx["room"] = room
|
||||
ctx["page_class"] = "page-gameboard"
|
||||
# `page-room` drives the navbar GATE VIEW swap (mirrors my-sea's
|
||||
# `page-my-sea`) so the table page reaches the renewal gate-view instead
|
||||
# of a self-referential CONT GAME. The bare gameboard listing stays
|
||||
# `page-gameboard` (no page-room) → keeps CONT GAME.
|
||||
ctx["page_class"] = "page-gameboard page-room"
|
||||
# Reversal-rate hint label under DRAW SEA's SPREAD select — same helper as
|
||||
# sea_partial so the value tracks any future per-user override automatically.
|
||||
ctx["stack_reversal_pct"] = int(round(stack_reversal_probability(request.user, room) * 100))
|
||||
|
||||
@@ -21,27 +21,31 @@
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% if 'page-my-sea' in page_class %}
|
||||
{% if 'page-my-sea' in page_class or 'page-room' in page_class %}
|
||||
{# Sprint 6 iter 6b — on any my-sea page (landing/picker or #}
|
||||
{# the gatekeeper itself), CONT GAME swaps for GATE VIEW so #}
|
||||
{# the user can always reach the token-deposit gatekeeper #}
|
||||
{# (regardless of quota state). `<button>` (not `<a>`) #}
|
||||
{# because UA-default fonts differ + `.btn` doesn't reset #}
|
||||
{# font-family — anchors render serif, buttons stay sans- #}
|
||||
{# serif (locked via the in-hex GATE VIEW fix in iter 4c). #}
|
||||
{# Direct child of `.container-fluid` (no form wrapper) so #}
|
||||
{# the `> #id_navbar_gate_view_btn` SCSS pin (top-center in #}
|
||||
{# landscape) matches; inline onclick handles navigation — #}
|
||||
{# no confirm guard since GATE VIEW is non-destructive nav. #}
|
||||
{# On a my_sea_VISIT page (incl. its gate, whose page_class also #}
|
||||
{# carries `page-my-sea-visit`), GATE VIEW must open THIS owner's #}
|
||||
{# visitor gatekeeper — not the viewer's own sea gate. `owner` is #}
|
||||
{# in context on those pages. #}
|
||||
{# (regardless of quota state). 2026-05-31: extended to room #}
|
||||
{# pages (`page-room`, set by room_view + room_gate) — the #}
|
||||
{# 3rd-person table reaches the renewal gate-view the same #}
|
||||
{# way, instead of a self-referential CONT GAME. `<button>` #}
|
||||
{# (not `<a>`) because UA-default fonts differ + `.btn` #}
|
||||
{# doesn't reset font-family — anchors render serif, buttons #}
|
||||
{# stay sans-serif (locked via the in-hex GATE VIEW fix in #}
|
||||
{# iter 4c). Direct child of `.container-fluid` (no form #}
|
||||
{# wrapper) so the `> #id_navbar_gate_view_btn` SCSS pin #}
|
||||
{# (top-center in landscape) matches; inline onclick handles #}
|
||||
{# navigation — no confirm guard since GATE VIEW is #}
|
||||
{# non-destructive nav. #}
|
||||
{# Targets, in precedence order: a room page → that room's #}
|
||||
{# gate-view (`room` is in context); a my_sea_VISIT page #}
|
||||
{# (incl. its gate) → THIS owner's visitor gatekeeper #}
|
||||
{# (`owner` in context); else the owner's own sea gate. #}
|
||||
<button
|
||||
id="id_navbar_gate_view_btn"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
onclick="window.location.href='{% if 'page-my-sea-visit' in page_class %}{% url 'my_sea_visit_gate' owner.id %}{% else %}{% url 'my_sea_gate' %}{% endif %}'"
|
||||
onclick="window.location.href='{% if 'page-room' in page_class %}{% url 'epic:room_gate' room.id %}{% elif 'page-my-sea-visit' in page_class %}{% url 'my_sea_visit_gate' owner.id %}{% else %}{% url 'my_sea_gate' %}{% endif %}'"
|
||||
>
|
||||
GATE<br>VIEW
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user