Show level locks only on the next unlock tier on play #334

Closed
opened 2026-06-19 04:27:42 +00:00 by PlasticDigits · 10 comments
PlasticDigits commented 2026-06-19 04:27:42 +00:00 (Migrated from gitlab.com)

Parent

Gap analysis follow-up from #331.

Current codebase

  • Level-gated UI wraps podiums, timer carousel, side chips, WarBow, and wallet card via LockedUntilLevel (frontend/src/components/LockedUntilLevel.tsx).
  • Unlock matrix: FEATURE_UNLOCK_LEVEL in frontend/src/lib/arenaProgression.ts (L1 Last Buy → L5 WarBow flag).
  • Play route (ArenaSimplePage.tsx) locks carousel slides, timer panel, and buy surfaces when requiredLevel > playerLevel.
  • Side chips (ArenaPodiumTimerChip.tsx), carousel (ArenaTimerPodiumCarousel.tsx), grid (ArenaSimplePodiumSection.tsx), and wallet card (ArenaCharmCredCard.tsx · lockWalletSurface) each independently show lock overlays for all levels above the player's current level.
  • Parent #331 review explicitly rejected increasing UX complexity (live strips, badges, side-card changes); approved only narrowing lock visibility.

Why needed

New wallets at Level 1 currently see lock overlays on L2–L5 surfaces simultaneously, increasing visual noise and obscuring the single next action. Approved fix: show locks only on the immediate next level (e.g. at L1, lock L2 targets only; L3–L5 surfaces stay unlocked visually or show without lock chrome).

Constraints / guardrails

  • VISUAL: Must comply with Cyberminimalist Glass System (INV-FRONTEND-290-CYBER-GLASS-SHELL, docs/frontend/design.md).
  • Verification must include screenshots uploaded to this issue demonstrating compliance on desktop, tablet, and mobile.
  • Do not add new panels, live activity strips, side-card layout changes, or WarBow prominence changes — parent rejected those.
  • Preserve #299 progression gates: mechanics remain locked onchain; only visual lock chrome narrows.
  • Keep LockedUntilLevel as the shared primitive; prefer a single helper like shouldShowLevelLock(playerLevel, requiredLevel) → requiredLevel === playerLevel + 1 (edge: L5 cap, disconnected wallet).
  • Indexer-first; no RPC mirrors.

Relevant files

Path Role
frontend/src/lib/arenaProgression.ts Unlock levels, helper candidate
frontend/src/components/LockedUntilLevel.tsx Lock overlay primitive
frontend/src/pages/arena/ArenaSimplePage.tsx Timer panel / carousel locks
frontend/src/pages/arena/ArenaTimerPodiumCarousel.tsx Carousel slide locks
frontend/src/pages/arena/ArenaPodiumTimerChip.tsx Side-rail chip locks
frontend/src/pages/arena/ArenaCharmCredCard.tsx Wallet surface lock
frontend/src/pages/arena/ArenaSimplePodiumSection.tsx Podium section locks (AUDIT/play shared patterns)
frontend/src/index.css Lock overlay tokens
  1. Add nextUnlockLevel(playerLevel): number | null (returns min(playerLevel+1, 5) or null at L5).
  2. Replace requiredLevel > playerLevel lock predicates with requiredLevel === nextUnlockLevel(playerLevel) across play-route consumers.
  3. For levels beyond next: render content normally but keep disabled/onchain-gated actions where applicable (buttons still respect isFeatureUnlocked).
  4. Disconnected wallet: retain "Connect wallet" lock only on primary buy/timer surfaces, not on all future tiers.
  5. Update existing unit tests (ArenaTimerChips.test.tsx, carousel lock tests) to match new policy.

Acceptance criteria

  • Level-1 wallet sees at most one level-lock overlay on play route (L2 next), not L3–L5 lock chrome.
  • Level-4 wallet sees lock only on L5 (WarBow flag) surfaces.
  • Level-5 wallet: no progression lock overlays (feature gates still enforce mechanics).
  • Cyberminimalist glass styling preserved; no new competing focal elements.
  • Screenshots attached to issue: desktop ≥1024px, tablet ~768px, mobile ~390px.
  • cd frontend && npm run typecheck && npm run lint && npm test passes.

Test plan

Command Path
cd frontend && npm run typecheck && npm run lint && npm test frontend/src/lib/arenaProgression.test.ts, carousel/chip lock tests
cd frontend && CI=1 npm run test:e2e -- --workers=5 e2e/anvil-arena-01-mount.spec.ts frontend/e2e/

Add Vitest cases for shouldShowLevelLock / next-level policy at L1–L5 and disconnected wallet.

Attack / abuse test plan

  • UI-only change; confirm locked buy buttons still cannot submit txs when isFeatureUnlocked is false (no regression allowing premature WarBow/booster actions).
  • No new localStorage secrets or PII.

Verification criteria

  • Manual: fresh Anvil wallet at L1 — carousel/side chips show single lock tier.
  • Screenshots on issue for three breakpoints.
  • MR checklist: frontend unit tests → PASS.
## Parent Gap analysis follow-up from [#331](https://gitlab.com/PlasticDigits/yieldomega/-/issues/331). ## Current codebase - Level-gated UI wraps podiums, timer carousel, side chips, WarBow, and wallet card via `LockedUntilLevel` (`frontend/src/components/LockedUntilLevel.tsx`). - Unlock matrix: `FEATURE_UNLOCK_LEVEL` in `frontend/src/lib/arenaProgression.ts` (L1 Last Buy → L5 WarBow flag). - Play route (`ArenaSimplePage.tsx`) locks carousel slides, timer panel, and buy surfaces when `requiredLevel > playerLevel`. - Side chips (`ArenaPodiumTimerChip.tsx`), carousel (`ArenaTimerPodiumCarousel.tsx`), grid (`ArenaSimplePodiumSection.tsx`), and wallet card (`ArenaCharmCredCard.tsx` · `lockWalletSurface`) each independently show lock overlays for **all** levels above the player's current level. - Parent #331 review explicitly rejected increasing UX complexity (live strips, badges, side-card changes); **approved** only narrowing lock visibility. ## Why needed New wallets at Level 1 currently see lock overlays on L2–L5 surfaces simultaneously, increasing visual noise and obscuring the single next action. Approved fix: show locks **only on the immediate next level** (e.g. at L1, lock L2 targets only; L3–L5 surfaces stay unlocked visually or show without lock chrome). ## Constraints / guardrails - **VISUAL**: Must comply with **Cyberminimalist Glass System** (`INV-FRONTEND-290-CYBER-GLASS-SHELL`, `docs/frontend/design.md`). - Verification must include **screenshots uploaded to this issue** demonstrating compliance on **desktop, tablet, and mobile**. - Do **not** add new panels, live activity strips, side-card layout changes, or WarBow prominence changes — parent rejected those. - Preserve `#299` progression gates: mechanics remain locked onchain; only **visual lock chrome** narrows. - Keep `LockedUntilLevel` as the shared primitive; prefer a single helper like `shouldShowLevelLock(playerLevel, requiredLevel)` → `requiredLevel === playerLevel + 1` (edge: L5 cap, disconnected wallet). - Indexer-first; no RPC mirrors. ## Relevant files | Path | Role | |------|------| | `frontend/src/lib/arenaProgression.ts` | Unlock levels, helper candidate | | `frontend/src/components/LockedUntilLevel.tsx` | Lock overlay primitive | | `frontend/src/pages/arena/ArenaSimplePage.tsx` | Timer panel / carousel locks | | `frontend/src/pages/arena/ArenaTimerPodiumCarousel.tsx` | Carousel slide locks | | `frontend/src/pages/arena/ArenaPodiumTimerChip.tsx` | Side-rail chip locks | | `frontend/src/pages/arena/ArenaCharmCredCard.tsx` | Wallet surface lock | | `frontend/src/pages/arena/ArenaSimplePodiumSection.tsx` | Podium section locks (AUDIT/play shared patterns) | | `frontend/src/index.css` | Lock overlay tokens | ## Recommended direction 1. Add `nextUnlockLevel(playerLevel): number | null` (returns `min(playerLevel+1, 5)` or null at L5). 2. Replace `requiredLevel > playerLevel` lock predicates with `requiredLevel === nextUnlockLevel(playerLevel)` across play-route consumers. 3. For levels beyond next: render content normally but keep disabled/onchain-gated actions where applicable (buttons still respect `isFeatureUnlocked`). 4. Disconnected wallet: retain "Connect wallet" lock only on primary buy/timer surfaces, not on all future tiers. 5. Update existing unit tests (`ArenaTimerChips.test.tsx`, carousel lock tests) to match new policy. ## Acceptance criteria - [ ] Level-1 wallet sees at most **one** level-lock overlay on play route (L2 next), not L3–L5 lock chrome. - [ ] Level-4 wallet sees lock only on L5 (WarBow flag) surfaces. - [ ] Level-5 wallet: no progression lock overlays (feature gates still enforce mechanics). - [ ] Cyberminimalist glass styling preserved; no new competing focal elements. - [ ] Screenshots attached to issue: desktop ≥1024px, tablet ~768px, mobile ~390px. - [ ] `cd frontend && npm run typecheck && npm run lint && npm test` passes. ## Test plan | Command | Path | |---------|------| | `cd frontend && npm run typecheck && npm run lint && npm test` | `frontend/src/lib/arenaProgression.test.ts`, carousel/chip lock tests | | `cd frontend && CI=1 npm run test:e2e -- --workers=5 e2e/anvil-arena-01-mount.spec.ts` | `frontend/e2e/` | Add Vitest cases for `shouldShowLevelLock` / next-level policy at L1–L5 and disconnected wallet. ## Attack / abuse test plan - UI-only change; confirm locked buy buttons still cannot submit txs when `isFeatureUnlocked` is false (no regression allowing premature WarBow/booster actions). - No new localStorage secrets or PII. ## Verification criteria - Manual: fresh Anvil wallet at L1 — carousel/side chips show single lock tier. - Screenshots on issue for three breakpoints. - MR checklist: frontend unit tests → PASS.
PlasticDigits commented 2026-06-19 04:28:08 +00:00 (Migrated from gitlab.com)

mentioned in issue #331

mentioned in issue #331
PlasticDigits commented 2026-06-19 06:22:21 +00:00 (Migrated from gitlab.com)

mentioned in merge request !507

mentioned in merge request !507
PlasticDigits commented 2026-06-19 06:22:27 +00:00 (Migrated from gitlab.com)

Verification — issue #334

Verified on branch issue-334-next-tier-level-locks → MR !507.

Results

Criterion Result How verified
L1: single progression lock (L2), not L3–L5 chrome PASS Anvil stack + Playwright on play /: only arena-timer-chip-lock-1 (Time Booster / L2) among tier chips; L3/L4 chip locks absent
L4: lock only on L5 WarBow flag surfaces PASS shouldShowLevelLock(4,5) unit test; showWarbowFlagLevelLock in ArenaWarbowHeroPanel
L5: no progression lock overlays PASS nextUnlockLevel(5) → null; shouldShowLevelLock(5,*) → false
Glass styling preserved, no new focal elements PASS Screenshots below
Screenshots desktop / tablet / mobile PASS Attached
typecheck / lint / npm test PASS 701 tests
E2E mount smoke PASS ANVIL_E2E=1 CI=1 npm run test:e2e -- --workers=5 e2e/anvil-arena-01-mount.spec.ts

Note: Fresh L1 wallets still show two primary-surface activation locks (wallet card + Last Buy chip, both “Locked until Level 1”) until first CHARM buy — unchanged from pre-#334 behavior and separate from the L2–L5 tier-progression noise this issue targets.

Screenshots (L1 connected wallet, play route)

Desktop (1280px)

issue-334-play-l1-desktop

Tablet (768px)

issue-334-play-l1-tablet

Mobile (390px)

issue-334-play-l1-mobile

MR !507 opened for merge; issue left open pending MR merge.

## Verification — issue #334 Verified on branch `issue-334-next-tier-level-locks` → MR !507. ### Results | Criterion | Result | How verified | |-----------|--------|--------------| | L1: single progression lock (L2), not L3–L5 chrome | **PASS** | Anvil stack + Playwright on play `/`: only `arena-timer-chip-lock-1` (Time Booster / L2) among tier chips; L3/L4 chip locks absent | | L4: lock only on L5 WarBow flag surfaces | **PASS** | `shouldShowLevelLock(4,5)` unit test; `showWarbowFlagLevelLock` in `ArenaWarbowHeroPanel` | | L5: no progression lock overlays | **PASS** | `nextUnlockLevel(5)` → null; `shouldShowLevelLock(5,*)` → false | | Glass styling preserved, no new focal elements | **PASS** | Screenshots below | | Screenshots desktop / tablet / mobile | **PASS** | Attached | | `typecheck` / `lint` / `npm test` | **PASS** | 701 tests | | E2E mount smoke | **PASS** | `ANVIL_E2E=1 CI=1 npm run test:e2e -- --workers=5 e2e/anvil-arena-01-mount.spec.ts` | **Note:** Fresh L1 wallets still show **two primary-surface activation locks** (wallet card + Last Buy chip, both “Locked until Level 1”) until first CHARM buy — unchanged from pre-#334 behavior and separate from the L2–L5 tier-progression noise this issue targets. ### Screenshots (L1 connected wallet, play route) **Desktop (1280px)** ![issue-334-play-l1-desktop](/uploads/24a3fac2845c26a7e372f7be369bdadb/issue-334-play-l1-desktop.png) **Tablet (768px)** ![issue-334-play-l1-tablet](/uploads/8f3d4f9c5653485e3938eafb4757c280/issue-334-play-l1-tablet.png) **Mobile (390px)** ![issue-334-play-l1-mobile](/uploads/a951c7053119b42323f34e86eff5d99a/issue-334-play-l1-mobile.png) MR !507 opened for merge; issue left open pending MR merge.
PlasticDigits commented 2026-06-19 06:32:35 +00:00 (Migrated from gitlab.com)

mentioned in commit 3d6d3b217c

mentioned in commit 3d6d3b217c9ccef95cac31badc724e36c40e410c
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-19 06:32:35 +00:00
PlasticDigits commented 2026-06-19 10:58:46 +00:00 (Migrated from gitlab.com)

mentioned in commit 916025477a

mentioned in commit 916025477a294aaf3cd285404c2c775c9fb7427d
PlasticDigits commented 2026-06-19 10:59:42 +00:00 (Migrated from gitlab.com)

mentioned in merge request !514

mentioned in merge request !514
PlasticDigits commented 2026-06-19 11:07:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #339

mentioned in issue #339
PlasticDigits commented 2026-06-19 11:55:54 +00:00 (Migrated from gitlab.com)

mentioned in merge request !515

mentioned in merge request !515
PlasticDigits commented 2026-06-19 13:31:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #340

mentioned in issue #340
PlasticDigits commented 2026-07-02 12:52:18 +00:00 (Migrated from gitlab.com)

mentioned in commit 0c307de8a5

mentioned in commit 0c307de8a50011235c42edc6843c1b6cc94be4d2
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#334
No description provided.