room ?seat=N seat-switch: CARTE gamer previews an owned seat's card-stack — data-active-slot + ineligible .fa-ban when it's not the table's turn — TDD

Workstream B of the position-circle tooltips sprint.

_role_select_context consumes ?seat=N (threaded from room_view): a multi-seat (CARTE) gamer previews a specific owned seat. The card-stack's active slot becomes that seat; it stays 'eligible' only when the previewed seat is also the table's current turn (lowest unassigned seat), else it renders the ineligible .fa-ban. Strictly additive — a one-seat gamer never passes ?seat, and an unowned/garbage param is ignored, so the normal role-select flow (RoleSelectRenderingTest) is untouched.

Tests: CarteSeatSwitchTest.test_switching_seat_loads_that_seats_role_view FT green; 2 new render ITs (seat-param-previews + no-seat-keeps-canonical); RoleSelectRenderingTest still green.

[[project-position-circle-tooltips]]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-01 12:29:08 -04:00
parent 30246cc94a
commit d190b37149
3 changed files with 38 additions and 1 deletions

View File

@@ -428,6 +428,27 @@ def _role_select_context(room, user, seat_param=None):
if user.is_authenticated else []
)
active_slot = active_seat.slot_number if active_seat else None
# CARTE seat-switch (?seat=N): a multi-seat gamer previews a specific owned
# seat. The card-stack's active slot becomes that seat; it stays "eligible"
# (role-pickable now) only when the previewed seat is also the table's
# current turn (the lowest unassigned seat), else it shows the ineligible
# .fa-ban. No-op for the normal flow — a one-seat gamer never passes ?seat,
# and an unowned/garbage param is ignored.
if seat_param and user.is_authenticated and card_stack_state is not None:
try:
_seat_n = int(seat_param)
except (TypeError, ValueError):
_seat_n = None
if _seat_n is not None and room.table_seats.filter(
gamer=user, slot_number=_seat_n
).exists():
active_slot = _seat_n
_turn = unassigned.first() if unassigned.exists() else None
card_stack_state = (
"eligible"
if _turn is not None and _turn.slot_number == _seat_n
else "ineligible"
)
_my_role = assigned_seats[0].role if assigned_seats else None
# `equipped_deck_id` gates the JS role-select guard (role-select.js L165).
# Falls back to ANY of the user's seats in this room w. deck_variant set