room gate-view: reuse the gatekeeper token-slot modal — CONT GAME → hex when satisfied / rails-renew when lapsed — TDD
Redesign of the room gate-view per user-spec 2026-05-31: drop the custom
seat-circle + countdown; render the EXACT gatekeeper modal instead
(title panel + animated status-dots + token-slot rails + roles panel).
- roles-panel .btn-primary is CONT GAME (→ table hex, same target as the
gear NVM) while the viewer's seat cost is current; absent once it
lapses, reappears after renewal re-satisfies the cost
- .gate-status-text: "<n> Token(s) Deposited" (literal "(s)" + the shared
. . . . dots loop) when satisfied; "Please Deposit Token" when not.
<n> = the room's deposited (FILLED) slot count
- token slot: .claimed (static rails) when current; .active rails that
POST to renew_token when lapsed
- seat circle + time-remaining removed — the hex's own .fa-chair carries
seat status & user/seat tooltips land next sprint
- room_gate view trimmed to {room, cost_current, deposited_count,
page_class}
- tests: RoomGateViewTest reworked (9) — CONT GAME→hex + deposited-count
status + no renew-form when current; "Please Deposit Token" + renew
rails + no CONT GAME when lapsed; NVM→hex; page-room; no seat/countdown
markup. 510 epic tests green
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2633,26 +2633,46 @@ class RoomGateViewTest(TestCase):
|
||||
self.client.force_login(self.owner)
|
||||
self.url = reverse("epic:room_gate", args=[self.room.id])
|
||||
|
||||
def _lapse(self):
|
||||
# Backdate the seat into the renewal-grace window (cost lapsed, seat
|
||||
# still FILLED) so the gate-view renders its renew state.
|
||||
self.slot.filled_at = timezone.now() - timedelta(days=8)
|
||||
self.slot.save()
|
||||
|
||||
def test_renders_200_even_when_table_status_set(self):
|
||||
# gatekeeper would 302 to the room; the gate-view must render mid-game.
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_shows_viewer_own_seat_circle(self):
|
||||
def test_cost_current_shows_cont_game_to_hex(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertContains(response, 'data-slot="1"')
|
||||
self.assertContains(response, "PC") # slot 1 role label
|
||||
self.assertContains(response, "id_room_cont_game_btn")
|
||||
self.assertContains(response, "CONT")
|
||||
self.assertContains(response, reverse("epic:room", args=[self.room.id]))
|
||||
|
||||
def test_shows_time_remaining_data_attr(self):
|
||||
def test_cost_current_status_shows_deposited_count(self):
|
||||
# One filled slot (the owner's) → "1 Token(s) Deposited" (literal "(s)").
|
||||
response = self.client.get(self.url)
|
||||
self.assertContains(response, "data-cost-until=")
|
||||
self.assertContains(response, "id_room_gate_remaining")
|
||||
self.assertContains(response, "1 Token(s) Deposited")
|
||||
|
||||
def test_renew_button_posts_to_renew_endpoint(self):
|
||||
def test_cost_current_has_no_renew_form(self):
|
||||
# Rails are static (claimed) while the cost is current — renewing is a
|
||||
# lapsed-state affordance only.
|
||||
response = self.client.get(self.url)
|
||||
self.assertNotContains(
|
||||
response, reverse("epic:renew_token", args=[self.room.id]))
|
||||
|
||||
def test_cost_lapsed_shows_please_deposit_and_renew_rails(self):
|
||||
self._lapse()
|
||||
response = self.client.get(self.url)
|
||||
self.assertContains(response, "Please Deposit Token")
|
||||
self.assertContains(
|
||||
response, reverse("epic:renew_token", args=[self.room.id]))
|
||||
self.assertContains(response, "RENEW")
|
||||
|
||||
def test_cost_lapsed_hides_cont_game(self):
|
||||
self._lapse()
|
||||
response = self.client.get(self.url)
|
||||
self.assertNotContains(response, "id_room_cont_game_btn")
|
||||
|
||||
def test_nvm_returns_to_room_hex(self):
|
||||
response = self.client.get(self.url)
|
||||
@@ -2663,12 +2683,13 @@ class RoomGateViewTest(TestCase):
|
||||
response = self.client.get(self.url)
|
||||
self.assertIn("page-room", response.context["page_class"])
|
||||
|
||||
def test_no_seat_viewer_still_renders(self):
|
||||
stranger = User.objects.create(email="stranger@test.io")
|
||||
self.client.force_login(stranger)
|
||||
def test_no_seat_circle_or_countdown_rendered(self):
|
||||
# Seat circle + countdown removed (user-spec) — the hex .fa-chair + the
|
||||
# next-sprint user/seat tooltips carry that info.
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, "id_room_renew_btn")
|
||||
self.assertNotContains(response, "room-gate-seat")
|
||||
self.assertNotContains(response, "data-cost-until")
|
||||
self.assertNotContains(response, "id_room_gate_remaining")
|
||||
|
||||
|
||||
class RoomRenewTokenTest(TestCase):
|
||||
|
||||
Reference in New Issue
Block a user