Gate-view pos-1 lockout: thread the acting ?seat through the GATE VIEW nav — TDD
The GATE VIEW buttons (navbar + room.html lapsed-cost) linked to room_gate
with no ?seat, so _viewer_current_slot fell back to owned[0] (pos 1). On the
gate view a CARTE multi-seat gamer acting at pos 2+ saw pos 1 wrongly flagged
me-current AND href-less — the one circle you could never switch back to.
Fix (option a): _role_select_context + _gate_context now both expose
current_slot; both GATE VIEW buttons append ?seat={{ current_slot }} on
page-room. The gate view's current now matches the table → pos 1 becomes
me-also (switch href) when acting elsewhere, the occupied seat correctly
carries no href. _gate_context computes current_slot once and reuses it for
gate_positions.
3 ITs in CarteTrayFollowsSelectedSeatTest (button carries acting seat;
default targets lowest owned; gate page re-carries seat + pos 1 is me-also).
911 epic+gameboard ITs green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -884,6 +884,41 @@ class CarteTrayFollowsSelectedSeatTest(TestCase):
|
||||
response = self.client.get(self.room_url + "?seat=6")
|
||||
self.assertIsNone(response.context["my_tray_sig"])
|
||||
|
||||
def test_gate_view_button_carries_acting_seat(self):
|
||||
# Regression (gate-view pos-1 lockout): the GATE VIEW buttons linked
|
||||
# to room_gate with NO ?seat, so the gate view fell back to owned[0]
|
||||
# (pos 1) → pos 1 was always me-current + never got a switch href:
|
||||
# the one seat you could never return to. The acting ?seat must ride
|
||||
# the gate-view nav so the gate view's current matches the table.
|
||||
gate_url = reverse("epic:room_gate", kwargs={"room_id": self.room.id})
|
||||
response = self.client.get(self.room_url + "?seat=4")
|
||||
self.assertEqual(response.context["current_slot"], 4)
|
||||
self.assertContains(response, f"{gate_url}?seat=4")
|
||||
|
||||
def test_gate_view_button_default_targets_lowest_owned(self):
|
||||
# No ?seat on the table → the gate button carries the lowest owned
|
||||
# slot (current_slot), keeping the table + gate views in agreement.
|
||||
gate_url = reverse("epic:room_gate", kwargs={"room_id": self.room.id})
|
||||
response = self.client.get(self.room_url)
|
||||
self.assertEqual(response.context["current_slot"], 1)
|
||||
self.assertContains(response, f"{gate_url}?seat=1")
|
||||
|
||||
def test_gate_page_exposes_and_re_carries_acting_seat(self):
|
||||
# The gate page's own navbar GATE VIEW re-click must keep the acting
|
||||
# seat → _gate_context exposes current_slot too, and pos 1 is now
|
||||
# me-also (switchable) while pos 4 is me-current — no lockout.
|
||||
gate_url = reverse("epic:room_gate", kwargs={"room_id": self.room.id})
|
||||
response = self.client.get(gate_url + "?seat=4")
|
||||
self.assertEqual(response.context["current_slot"], 4)
|
||||
self.assertContains(response, f"{gate_url}?seat=4")
|
||||
by_slot = {
|
||||
p["slot"].slot_number: p
|
||||
for p in response.context["gate_positions"]
|
||||
}
|
||||
self.assertEqual(by_slot[4]["state_class"], "tt-pos-me-current")
|
||||
self.assertTrue(by_slot[1]["is_me_also"])
|
||||
self.assertEqual(by_slot[1]["state_class"], "tt-pos-me-also")
|
||||
|
||||
|
||||
class PickRolesViewTest(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -336,6 +336,7 @@ def _expire_lapsed_seats(room):
|
||||
|
||||
def _gate_context(room, user, seat_param=None):
|
||||
_expire_reserved_slots(room)
|
||||
current_slot = _viewer_current_slot(room, user, seat_param)
|
||||
slots = room.gate_slots.order_by("slot_number")
|
||||
pending_slot = slots.filter(status=GateSlot.RESERVED).first()
|
||||
user_reserved_slot = None
|
||||
@@ -390,9 +391,10 @@ def _gate_context(room, user, seat_param=None):
|
||||
"carte_slots_claimed": carte_slots_claimed,
|
||||
"carte_nvm_slot_number": carte_nvm_slot_number,
|
||||
"carte_next_slot_number": carte_next_slot_number,
|
||||
"gate_positions": _gate_positions(
|
||||
room, user, _viewer_current_slot(room, user, seat_param)
|
||||
),
|
||||
# Acting seat — exposed so the gate page's own GATE VIEW re-click
|
||||
# re-carries ?seat (keeps the seat-switch context across reloads).
|
||||
"current_slot": current_slot,
|
||||
"gate_positions": _gate_positions(room, user, current_slot),
|
||||
"starter_roles": [],
|
||||
}
|
||||
|
||||
@@ -486,6 +488,11 @@ def _role_select_context(room, user, seat_param=None):
|
||||
role_select_deck_id = seat_w_deck.deck_variant_id
|
||||
ctx = {
|
||||
"card_stack_state": card_stack_state,
|
||||
# The viewer's acting seat (?seat slot, else lowest owned). Threaded
|
||||
# onto the GATE VIEW nav so the gate view's current matches the table
|
||||
# — without it the gate view falls back to owned[0] (pos 1), locking
|
||||
# pos 1 as a never-switchable me-current circle.
|
||||
"current_slot": current_slot,
|
||||
"equipped_deck_id": role_select_deck_id,
|
||||
"starter_roles": starter_roles,
|
||||
"assigned_seats": assigned_seats,
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
{# family]] #}
|
||||
<button id="id_room_gate_view_btn" type="button"
|
||||
class="btn btn-primary"
|
||||
onclick="window.location.href='{% url 'epic:room_gate' room.id %}'">GATE<br>VIEW</button>
|
||||
onclick="window.location.href='{% url 'epic:room_gate' room.id %}{% if current_slot %}?seat={{ current_slot }}{% endif %}'">GATE<br>VIEW</button>
|
||||
{% else %}
|
||||
{% if room.table_status == "SKY_SELECT" %}
|
||||
{% if sky_confirmed %}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
id="id_navbar_gate_view_btn"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
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 %}'"
|
||||
onclick="window.location.href='{% if 'page-room' in page_class %}{% url 'epic:room_gate' room.id %}{% if current_slot %}?seat={{ current_slot }}{% endif %}{% 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