Sea Select FLIP: source the card-back from the seat's deck, not equipped_deck — TDD
The sea-stage FLIP no-op'd in the gameroom because `_sea_stage.html` rendered the back-img from `request.user.equipped_deck.back_image_url` — but `select_role` NULLS OUT the user's equipped_deck once it's contributed to the room's seats (views.py:1148), so in the Sea Select phase the deck was None → no back-img element → sea.js's FLIP handler short-circuits on the missing `.sig-stage-card-back-img` sibling. (my_sea worked: solo, no contribution.) - `_sea_stage.html` now renders the back-img from a `sea_back_image_url` ctx var instead of `request.user.equipped_deck` - gameroom: `_role_select_context` sets it from the SEAT's contributed deck (`_canonical_seat.deck_variant`, when it has card images) - my_sea: the my_sea view sets it from the user's own equipped deck - ITs: image seat-deck renders `.sig-stage-card-back-img`; text seat-deck omits it Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4162,19 +4162,24 @@ class PickSeaUnifiedFeltTest(TestCase):
|
|||||||
content = self.client.get(self.url).content.decode()
|
content = self.client.get(self.url).content.decode()
|
||||||
self.assertIn("room-menu-sea", content)
|
self.assertIn("room-menu-sea", content)
|
||||||
|
|
||||||
def test_sea_stage_renders_back_img_for_image_deck(self):
|
def test_sea_stage_renders_back_img_from_seat_deck(self):
|
||||||
"""The sea-stage FLIP reveals the card back. The back-img now renders for
|
"""The sea-stage FLIP reveals the card back. The back-img is sourced from
|
||||||
ANY image-equipped deck WITH a back image (polarized or not) — dropping
|
the SEAT's contributed deck (NOT request.user.equipped_deck, which
|
||||||
the old `not is_polarized` gate — so the Gravity/Levity draw can show a
|
select_role nulls out → the back silently never rendered + FLIP no-op'd)
|
||||||
polarity-tinted back (user-spec 2026-06-07)."""
|
and renders for any image-equipped deck w. a back (user-flagged
|
||||||
|
2026-06-07)."""
|
||||||
minch = DeckVariant.objects.get(slug="minchiate-fiorentine-1860-1890")
|
minch = DeckVariant.objects.get(slug="minchiate-fiorentine-1860-1890")
|
||||||
founder = self.gamers[0]
|
self.pc_seat.deck_variant = minch
|
||||||
founder.unlocked_decks.add(minch)
|
self.pc_seat.save(update_fields=["deck_variant"])
|
||||||
founder.equipped_deck = minch
|
|
||||||
founder.save(update_fields=["equipped_deck"])
|
|
||||||
content = self.client.get(self.url).content.decode()
|
content = self.client.get(self.url).content.decode()
|
||||||
self.assertIn("sig-stage-card-back-img", content)
|
self.assertIn("sig-stage-card-back-img", content)
|
||||||
|
|
||||||
|
def test_sea_stage_no_back_img_for_text_seat_deck(self):
|
||||||
|
"""Earthman (text-mode, no card images) → no back-img element (FLIP is a
|
||||||
|
no-op for text decks, by design)."""
|
||||||
|
content = self.client.get(self.url).content.decode()
|
||||||
|
self.assertNotIn("sig-stage-card-back-img", content)
|
||||||
|
|
||||||
def test_always_two_deck_stacks_gravity_and_levity(self):
|
def test_always_two_deck_stacks_gravity_and_levity(self):
|
||||||
"""Unlike my_sea / Sig Select, the room Sea Select ALWAYS shows BOTH the
|
"""Unlike my_sea / Sig Select, the room Sea Select ALWAYS shows BOTH the
|
||||||
Gravity + Levity stacks — the gamer draws from either populated half
|
Gravity + Levity stacks — the gamer draws from either populated half
|
||||||
|
|||||||
@@ -680,6 +680,15 @@ def _role_select_context(room, user, seat_param=None):
|
|||||||
)
|
)
|
||||||
# 6-card Celtic Cross is complete at 6 placed cards.
|
# 6-card Celtic Cross is complete at 6 placed cards.
|
||||||
ctx["hand_complete"] = len(_sea_hand) >= 6
|
ctx["hand_complete"] = len(_sea_hand) >= 6
|
||||||
|
# Sea-stage FLIP card-back — sourced from the SEAT's contributed deck,
|
||||||
|
# NOT request.user.equipped_deck (which `select_role` nulls out once
|
||||||
|
# the deck is contributed to the room → the back-img silently never
|
||||||
|
# rendered in the gameroom + FLIP no-op'd). User-flagged 2026-06-07.
|
||||||
|
_back_deck = _canonical_seat.deck_variant if _canonical_seat else None
|
||||||
|
ctx["sea_back_image_url"] = (
|
||||||
|
_back_deck.back_image_url
|
||||||
|
if (_back_deck and _back_deck.has_card_images) else ""
|
||||||
|
)
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|||||||
@@ -372,6 +372,14 @@ def my_sea(request):
|
|||||||
"significator_reversed": sig_reversed,
|
"significator_reversed": sig_reversed,
|
||||||
"default_spread": default_spread,
|
"default_spread": default_spread,
|
||||||
"reversals_pct": 25,
|
"reversals_pct": 25,
|
||||||
|
# Sea-stage FLIP card-back — my_sea is solo (no deck contribution), so the
|
||||||
|
# user's OWN equipped deck is the right source (the gameroom uses the
|
||||||
|
# seat's contributed deck instead; see _sea_stage.html).
|
||||||
|
"sea_back_image_url": (
|
||||||
|
request.user.equipped_deck.back_image_url
|
||||||
|
if (request.user.equipped_deck and request.user.equipped_deck.has_card_images)
|
||||||
|
else ""
|
||||||
|
),
|
||||||
"sea_deck_data": (
|
"sea_deck_data": (
|
||||||
_my_sea_deck_data(request.user, exclude_id=sig_card.id if sig_card else None)
|
_my_sea_deck_data(request.user, exclude_id=sig_card.id if sig_card else None)
|
||||||
if user_has_sig else {"levity": [], "gravity": []}
|
if user_has_sig else {"levity": [], "gravity": []}
|
||||||
|
|||||||
@@ -43,20 +43,19 @@
|
|||||||
</div>
|
</div>
|
||||||
{% comment %}
|
{% comment %}
|
||||||
back-img + FLIP btn. FLIP reveals the card back. Renders for ANY
|
back-img + FLIP btn. FLIP reveals the card back. Renders for ANY
|
||||||
image-equipped deck that has a back image — INCLUDING polarized decks
|
image-equipped deck w. a back image — INCLUDING polarized decks
|
||||||
(user-spec 2026-06-07): the Sea Select phase tints the back per the
|
(user-spec 2026-06-07): the Sea Select phase tints the back per the
|
||||||
drawn card's polarity (`.sea-stage--gravity` / `--levity`, see
|
drawn card's polarity (`.sea-stage--gravity` / `--levity`, see
|
||||||
`_card-deck.scss`), so the same back-art reads distinctly for the two
|
`_card-deck.scss`), so the same back-art reads distinctly for the two
|
||||||
stacks (was previously gated to non-polarized decks, where it never
|
stacks. `sea_back_image_url` is set by each caller from the RIGHT
|
||||||
rendered for the room's Gravity/Levity draw). The FLIP btn renders
|
deck: the gameroom uses the SEAT's contributed deck (NOT
|
||||||
unconditionally; sea.js's handler no-ops when no back-img sibling
|
request.user.equipped_deck, which select_role nulls out → the back
|
||||||
exists (text decks). Multi-user gameroom limitation: the src is the
|
silently never rendered + FLIP no-op'd); my_sea uses the user's
|
||||||
VIEWER's deck-back — correct for the sea (each gamer draws their own),
|
equipped deck. FLIP btn renders unconditionally; sea.js's handler
|
||||||
parked for the general multi-user case.
|
no-ops when no back-img sibling exists (text decks).
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
{% if request.user.is_authenticated and request.user.equipped_deck.has_card_images and request.user.equipped_deck.back_image_url %}
|
{% if sea_back_image_url %}
|
||||||
<img class="sig-stage-card-back-img" alt=""
|
<img class="sig-stage-card-back-img" alt="" src="{{ sea_back_image_url }}">
|
||||||
src="{{ request.user.equipped_deck.back_image_url }}">
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button class="btn btn-reveal sea-stage-flip-btn" type="button" aria-label="Flip card">FLIP</button>
|
<button class="btn btn-reveal sea-stage-flip-btn" type="button" aria-label="Flip card">FLIP</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user