burger sea sub-btn: wire .active = show_picker and not hand_complete (phase 1/3) — TDD
First slice of the "Sea sub-btn opens the spread modal" feature push.
## Server (apps/gameboard/views.py)
`my_sea` view now passes `sea_btn_active = show_picker and not hand_complete` in context. Picker phase w. cards still to draw → True; landing / sign-gate / hand-complete states → False. The condition mirrors the AUTO-DRAW-vs-GATE-VIEW state machine — sea_btn lights up exactly when AUTO DRAW is the live action btn, returns to inactive at the same moment AUTO DRAW becomes GATE VIEW + the deck FLIP gains .btn-disabled.
## Template (_partials/_burger.html)
`#id_sea_btn` conditionally renders the `.active` class:
```
<button id="id_sea_btn" type="button" class="burger-fan-btn{% if sea_btn_active %} active{% endif %}" ...>
```
Per the burger sub-btn CSS that landed in 894d65f, .active means opacity 1 + skip the --priRd inactive-click flash. The other 4 sub-btns (sky/earth/voice/text/...) remain inactive scaffolding for later sprints to wire one-by-one.
## Tests (apps/gameboard/tests/integrated/test_views.py)
3 new ITs on MySeaViewTest:
- `test_sea_btn_is_inactive_on_landing_phase` — fresh user / landing → no .active class.
- `test_sea_btn_is_active_on_picker_phase_with_partial_hand` — sig + 1-card MySeaDraw → .active class present.
- `test_sea_btn_returns_to_inactive_when_hand_complete` — 3-card spread w. all 3 positions drawn → hand_complete True → sea_btn back to inactive (regression guard for the GATE VIEW transition).
## Verification
All 12 MySeaViewTest green (+3 new). No JS / CSS touches — pure server + template change. Phase 2 (modal extraction + .sea-stacks relocate) + Phase 3 (--priYl glow handoff) land in follow-up commits.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1042,6 +1042,63 @@ class MySeaViewTest(TestCase):
|
|||||||
response = self.client.get(reverse("my_sea"))
|
response = self.client.get(reverse("my_sea"))
|
||||||
self.assertIn("location.href='/gameboard/'", response.content.decode())
|
self.assertIn("location.href='/gameboard/'", response.content.decode())
|
||||||
|
|
||||||
|
def test_sea_btn_is_inactive_on_landing_phase(self):
|
||||||
|
"""Sea sub-btn flips ACTIVE only when the user is in the picker
|
||||||
|
phase w. cards still to draw. Landing phase = inactive (default)."""
|
||||||
|
response = self.client.get(reverse("my_sea"))
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'<button id="id_sea_btn" type="button" class="burger-fan-btn" aria-label="Sea">',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sea_btn_is_active_on_picker_phase_with_partial_hand(self):
|
||||||
|
from apps.epic.models import personal_sig_cards, TarotCard
|
||||||
|
from apps.gameboard.models import MySeaDraw
|
||||||
|
sig = personal_sig_cards(self.user)[0]
|
||||||
|
self.user.significator = sig
|
||||||
|
self.user.save(update_fields=["significator"])
|
||||||
|
card = TarotCard.objects.exclude(pk=sig.pk).first()
|
||||||
|
MySeaDraw.objects.create(
|
||||||
|
user=self.user, spread="situation-action-outcome",
|
||||||
|
significator_id=sig.id,
|
||||||
|
hand=[{"position": "lay", "card_id": card.id,
|
||||||
|
"reversed": False, "polarity": "gravity"}],
|
||||||
|
)
|
||||||
|
response = self.client.get(reverse("my_sea"))
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'id="id_sea_btn" type="button" class="burger-fan-btn active"',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_sea_btn_returns_to_inactive_when_hand_complete(self):
|
||||||
|
"""3-card spread w. all 3 positions drawn → hand_complete True →
|
||||||
|
sea_btn returns to inactive (the AUTO DRAW btn becomes GATE VIEW
|
||||||
|
+ the deck FLIP gets .btn-disabled at this moment)."""
|
||||||
|
from apps.epic.models import personal_sig_cards, TarotCard
|
||||||
|
from apps.gameboard.models import MySeaDraw
|
||||||
|
sig = personal_sig_cards(self.user)[0]
|
||||||
|
self.user.significator = sig
|
||||||
|
self.user.save(update_fields=["significator"])
|
||||||
|
cards = list(TarotCard.objects.exclude(pk=sig.pk)[:3])
|
||||||
|
MySeaDraw.objects.create(
|
||||||
|
user=self.user, spread="situation-action-outcome",
|
||||||
|
significator_id=sig.id,
|
||||||
|
hand=[
|
||||||
|
{"position": "lay", "card_id": cards[0].id,
|
||||||
|
"reversed": False, "polarity": "gravity"},
|
||||||
|
{"position": "cross", "card_id": cards[1].id,
|
||||||
|
"reversed": False, "polarity": "gravity"},
|
||||||
|
{"position": "crown", "card_id": cards[2].id,
|
||||||
|
"reversed": False, "polarity": "gravity"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
response = self.client.get(reverse("my_sea"))
|
||||||
|
# active class absent
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'<button id="id_sea_btn" type="button" class="burger-fan-btn" aria-label="Sea">',
|
||||||
|
)
|
||||||
|
|
||||||
def test_gear_nvm_navs_to_my_sea_landing_on_picker_phase(self):
|
def test_gear_nvm_navs_to_my_sea_landing_on_picker_phase(self):
|
||||||
"""Picker-phase NVM = "back out of the spread to the table hex" →
|
"""Picker-phase NVM = "back out of the spread to the table hex" →
|
||||||
/gameboard/my-sea/ (the landing). User-spec'd 2026-05-26 so the
|
/gameboard/my-sea/ (the landing). User-spec'd 2026-05-26 so the
|
||||||
|
|||||||
@@ -348,6 +348,11 @@ def my_sea(request):
|
|||||||
"next_free_draw_at": next_free_draw_at,
|
"next_free_draw_at": next_free_draw_at,
|
||||||
"hand_complete": hand_complete,
|
"hand_complete": hand_complete,
|
||||||
"show_picker": show_picker,
|
"show_picker": show_picker,
|
||||||
|
# Sub-btn .active flag for the burger fan — Sea sub-btn lights up
|
||||||
|
# when the user is in the picker phase w. cards still to draw.
|
||||||
|
# As soon as hand_complete flips True (AUTO DRAW → GATE VIEW + the
|
||||||
|
# deck FLIP gets .btn-disabled) the Sea sub-btn returns to inactive.
|
||||||
|
"sea_btn_active": show_picker and not hand_complete,
|
||||||
"show_paid_draw": show_paid_draw,
|
"show_paid_draw": show_paid_draw,
|
||||||
"show_gate_view": show_gate_view,
|
"show_gate_view": show_gate_view,
|
||||||
"deposit_reserved": deposit_reserved,
|
"deposit_reserved": deposit_reserved,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<i class="fa-solid fa-earth-americas burger-fan-icon--on"></i>
|
<i class="fa-solid fa-earth-americas burger-fan-icon--on"></i>
|
||||||
<i class="fa-solid fa-ban burger-fan-icon--off"></i>
|
<i class="fa-solid fa-ban burger-fan-icon--off"></i>
|
||||||
</button>
|
</button>
|
||||||
<button id="id_sea_btn" type="button" class="burger-fan-btn" aria-label="Sea">
|
<button id="id_sea_btn" type="button" class="burger-fan-btn{% if sea_btn_active %} active{% endif %}" aria-label="Sea">
|
||||||
<i class="fa-solid fa-bridge-water burger-fan-icon--on"></i>
|
<i class="fa-solid fa-bridge-water burger-fan-icon--on"></i>
|
||||||
<i class="fa-solid fa-ban burger-fan-icon--off"></i>
|
<i class="fa-solid fa-ban burger-fan-icon--off"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user