diff --git a/src/apps/dashboard/static/apps/scripts/game-kit.js b/src/apps/dashboard/static/apps/scripts/game-kit.js index 8a0571f..1369eed 100644 --- a/src/apps/dashboard/static/apps/scripts/game-kit.js +++ b/src/apps/dashboard/static/apps/scripts/game-kit.js @@ -7,7 +7,6 @@ if (dialog.hasAttribute('open')) { dialog.removeAttribute('open'); btn.classList.remove('active'); - clearSelection(); return; } fetch(btn.dataset.kitUrl, { @@ -30,7 +29,6 @@ if (e.key === 'Escape' && dialog.hasAttribute('open')) { dialog.removeAttribute('open'); btn.classList.remove('active'); - clearSelection(); } }); @@ -42,7 +40,6 @@ if (e.target.closest('button.token-rails')) return; dialog.removeAttribute('open'); btn.classList.remove('active'); - clearSelection(); }); // Inject token_id before token-rails form submits @@ -90,9 +87,5 @@ }); } - function clearSelection() { - window._kitTokenId = null; - var slot = document.querySelector('.token-slot'); - if (slot) slot.classList.remove('ready'); - } + }()); diff --git a/src/apps/epic/views.py b/src/apps/epic/views.py index cb5c287..8654cff 100644 --- a/src/apps/epic/views.py +++ b/src/apps/epic/views.py @@ -29,6 +29,7 @@ def _gate_context(room, user): carte_token = None carte_slots_claimed = 0 carte_nvm_slot_number = None + carte_next_slot_number = None if user.is_authenticated: user_reserved_slot = slots.filter(gamer=user, status=GateSlot.RESERVED).first() user_filled_slot = slots.filter(gamer=user, status=GateSlot.FILLED).first() @@ -43,6 +44,10 @@ def _gate_context(room, user): ).order_by("-slot_number").first() if nvm_slot: carte_nvm_slot_number = nvm_slot.slot_number + # Only the very next empty slot gets an OK button + next_slot = slots.filter(status=GateSlot.EMPTY).order_by("slot_number").first() + if next_slot: + carte_next_slot_number = next_slot.slot_number carte_active = carte_token is not None eligible = ( user.is_authenticated @@ -70,6 +75,7 @@ def _gate_context(room, user): "carte_active": carte_active, "carte_slots_claimed": carte_slots_claimed, "carte_nvm_slot_number": carte_nvm_slot_number, + "carte_next_slot_number": carte_next_slot_number, } @@ -231,6 +237,9 @@ def release_slot(request, room_id): slot.debited_token_type = None slot.debited_token_expires_at = None slot.save() + if room.gate_status == Room.OPEN: + room.gate_status = Room.GATHERING + room.save() return redirect("epic:gatekeeper", room_id=room_id) diff --git a/src/functional_tests/test_trinket_carte_blanche.py b/src/functional_tests/test_trinket_carte_blanche.py index c83012e..74e54a0 100644 --- a/src/functional_tests/test_trinket_carte_blanche.py +++ b/src/functional_tests/test_trinket_carte_blanche.py @@ -301,7 +301,7 @@ class CarteBlancheTest(FunctionalTest): ) self.wait_for(lambda: get_circle(2).find_element(By.CSS_SELECTOR, ".drop-token-btn")) - # 17. Click NVM on circle 2 → returns to OK; circle 3 still has OK + # 17. Click NVM on circle 2 → circle 2 regains OK; circle 3 loses it (strict n+1) # Circle 1 still filled; return panel still glowing; lease name still present self.wait_for( lambda: get_circle(1).find_element(By.CSS_SELECTOR, ".slot-release-btn") @@ -311,7 +311,9 @@ class CarteBlancheTest(FunctionalTest): self.assertTrue( self.browser.find_element(By.CSS_SELECTOR, ".token-slot.claimed").is_displayed() ) - self.wait_for(lambda: get_circle(2).find_element(By.CSS_SELECTOR, ".drop-token-btn")) + self.assertEqual( + len(get_circle(2).find_elements(By.CSS_SELECTOR, ".drop-token-btn")), 0 + ) # 18. Fill circles 2 → 6 sequentially; verify each subsequent OK appears for i in range(1, 6): diff --git a/src/static_src/scss/_room.scss b/src/static_src/scss/_room.scss index a89eeff..b69f093 100644 --- a/src/static_src/scss/_room.scss +++ b/src/static_src/scss/_room.scss @@ -299,22 +299,11 @@ body:has(.gate-overlay) { justify-content: center; } - .drop-token-btn { - position: absolute; - inset: 0; - border-radius: 50%; - width: 100%; - height: 100%; - background: transparent; - border: none; - box-shadow: - 0.05rem 0.05rem 0.5rem rgba(0, 0, 0, 1), - ; - font-size: 0; - cursor: pointer; + // CARTE drop-target circle — matches .reserved appearance + &:has(.drop-token-btn) { + background: rgba(var(--terUser), 0.2); &:hover { - background: rgba(var(--quaUser), 0.15); box-shadow: -0.1rem -0.1rem 1rem rgba(var(--ninUser), 1), -0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 1), diff --git a/src/templates/apps/gameboard/_partials/_gatekeeper.html b/src/templates/apps/gameboard/_partials/_gatekeeper.html index ab93a9f..12e268e 100644 --- a/src/templates/apps/gameboard/_partials/_gatekeeper.html +++ b/src/templates/apps/gameboard/_partials/_gatekeeper.html @@ -66,11 +66,11 @@ {% endif %} - {% elif carte_active and slot.status == 'EMPTY' and slot.slot_number <= carte_slots_claimed|add:1 %} + {% elif carte_active and slot.status == 'EMPTY' and slot.slot_number == carte_next_slot_number %}
{% csrf_token %} - +
{% elif carte_active and slot.status == 'FILLED' and slot.slot_number == carte_nvm_slot_number %}
@@ -83,7 +83,7 @@ {% endfor %} {% if room.gate_status == 'OPEN' %} - + {% endif %} {% if request.user == room.owner %}