My Sea iter 4b: MySeaDraw persistence + LOCK HAND POST + DEL guard + Brief banner; rewrite obsolete spread-switch FT; fix bud-panel CI race on gatekeeper FT — Sprint 5 iter 4b of My Sea roadmap — TDD
Iter 4b lands server persistence of the iter-4a client-side hand. New MySeaDraw model (FK user, spread, hand JSONField in draw order, sig snapshot, created_at) w. 1/24h quota window; new endpoints /gameboard/my-sea/lock (POST, 409 on quota-active, 400 on partial hand) + /gameboard/my-sea/delete (POST, idempotent). LOCK HAND now collects the in-progress hand from DOM, POSTs, and on success un-hides a Brief banner inline (no page reload — preserves iter-4a FT picker refs). DEL post-LOCK opens #id_my_sea_del_portal w. uniform 'Are you sure?' copy; CONFIRM POSTs delete + reloads to landing. Brief banner carries the next-free-draw timestamp + a NVM dismiss. Saved-draw render bypasses the sign-gate via _resolve_sig (sig snapshot on the draw is used even if user.significator was cleared later) + bypasses the landing phase (the saved hand IS what the user came to see). Per-position slot rendering extracted to _my_sea_slot.html. DRY follow-up: card_dict() extracted to apps.epic.utils — gameroom sea_deck + my-sea _my_sea_deck_data now share one source of truth (prevents drift like the iter-4a-follow-up Major Arcana fix from recurring). Pipeline #316 fixes bundled: (a) functional_tests.test_game_my_sea.MySeaCardDrawTest.test_switching_spread_resets_in_progress_hand was obsoleted by the iter-4a follow-up's spread-lock-after-first-draw — the test premise (mid-draw spread switching resets hand) no longer matches behavior (switching is blocked outright). Rewrote as test_first_draw_locks_spread_combobox, which pins .sea-select--locked after first draw + verifies DEL releases it. (b) functional_tests.test_game_room_gatekeeper.GatekeeperTest.test_second_gamer_drops_token_into_open_slot failed in CI on ElementNotInteractableException when clicking #id_bud_panel .btn.btn-confirm — the bud panel's scaleX(0)→scaleX(1) 0.2s CSS transition wasn't settled by click-time, so Selenium read scroll-into-view against a near-zero-width target. Added a wait_for on getBoundingClientRect().width > 100 so the click waits for the animation to finish. Local passes consistently; CI was 1+ frame slower than the implicit 'find element' wait. Tests: 1085 IT/UT green in 55s; 35 my_sea FTs green in 5m; new ITs in MySeaDrawModelTest (8), MySeaLockHandViewTest (7), MySeaDeleteDrawViewTest (5), MySeaViewWithSavedDrawTest (9); new FTs in MySeaLockHandTest (5). Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -503,3 +503,76 @@ body.page-gameboard {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
// ── Iter 4b: Brief banner + DEL guard portal ─────────────────────────────────
|
||||
|
||||
// Brief banner — Look!-formatted strip above the picker whenever a saved
|
||||
// draw occupies the user's free-quota slot. Shape mirrors .my-sea-sign-
|
||||
// gate but sized as a banner (full-width, single line + actions row).
|
||||
.my-sea-brief {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
margin: 0.5rem 0 1rem;
|
||||
background-color: rgba(var(--secUser), 0.65);
|
||||
border: 0.1rem solid rgba(var(--terUser), 0.6);
|
||||
border-radius: 0.4rem;
|
||||
color: rgba(var(--terUser), 1);
|
||||
font-size: 0.95rem;
|
||||
|
||||
&[hidden] { display: none; }
|
||||
|
||||
.my-sea-brief__line {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.my-sea-brief__timestamp {
|
||||
font-weight: bold;
|
||||
color: rgba(var(--ninUser), 1);
|
||||
}
|
||||
|
||||
.my-sea-brief__nvm {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
// DEL guard portal — fixed-position centered modal w. a uniform
|
||||
// 'Are you sure?' prompt. CONFIRM POSTs to /gameboard/my-sea/delete;
|
||||
// NVM closes the portal. The Brief banner above carries the quota-
|
||||
// specific copy so this stays free of conditional text.
|
||||
.my-sea-del-portal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
|
||||
&[hidden] { display: none; }
|
||||
|
||||
.my-sea-del-portal__panel {
|
||||
background-color: rgba(var(--secUser), 0.95);
|
||||
border: 0.15rem solid rgba(var(--terUser), 0.8);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.25rem 1.75rem;
|
||||
min-width: 18rem;
|
||||
text-align: center;
|
||||
color: rgba(var(--terUser), 1);
|
||||
}
|
||||
|
||||
.my-sea-del-portal__line {
|
||||
margin: 0 0 1rem;
|
||||
font-size: 1.05rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.my-sea-del-portal__actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user