Files
python-tdd/src/static_src/scss/_wallet-tokens.scss

150 lines
3.4 KiB
SCSS
Raw Normal View History

.token {
position: relative;
display: inline-block;
cursor: help;
color: rgba(var(--terUser), 1);
.token-tooltip {
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
}
&:hover .token-tooltip {
display: block; // legacy fallback; .tt is JS-portal-only (no CSS hover)
}
}
.token--empty {
cursor: help;
> i { opacity: 0.4; }
}
// Aperture foundation lives universally in _base.scss; nothing
// wallet-specific to override.
.wallet-page {
position: relative;
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.wallet-tokens {
display: flex;
flex-direction: column;
overflow: visible;
.token-row {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-evenly;
overflow: visible;
}
.token {
font-size: 1.5rem;
}
.token:hover .token-tooltip { display: none; }
}
#id_payment_methods {
overflow-y: auto;
}
@media (max-width: 768px) {
.token .token-tooltip {
width: 13rem;
max-width: 90vw;
left: 0;
transform: none;
}
.wallet-tokens .token-tooltip {
left: 50%;
transform: translateX(-50%);
}
}
feat: wallet Shop applet — tile grid + BUY-ITEM microbutton + Stripe.js wiring — Chunk 4 of [[project-wallet-shop-expansion]]. The shop applet (slug `wallet-shop`, seeded in Chunk 2) now renders the catalog as a horizontal grid of `.shop-tile` icons: `tithe-1` ($1, fa-piggy-bank), `tithe-5` ($4, fa-piggy-bank w. `×5` badge), `band-1` ($20, fa-ring). Each tile hosts a hover-portaled tooltip carrying name + description + price + a `.tt-microbutton-portal` w. a `.btn-primary` BUY ITEM button — clicking opens `#id_guard_portal` w. "Buy {name} for ${price}?" prompt; confirming triggers Stripe.js confirmCardPayment then POSTs to /shop/confirm + reloads. Items where the user's owned-count has hit `max_owned` (eg. BAND, owned=1, cap=1) render w. `.btn-disabled` + × glyph + "Already owned" microtooltip text — visible-but-unbuyable per the locked decision. View context — `wallet` view + `toggle_wallet_applets` view both pass `shop_items` (decorated w. per-user `.available` via the new `_shop_items_for(user)` helper) + `default_payment_method_id` + `stripe_publishable_key`. SCSS — `.wallet-shop` (flex column wrapping `.shop-grid` flex row), `.shop-tile` (inline-flex tooltip target), `.shop-badge` (2rem circle, --quaUser glyph on --quiUser bg, top-right corner per spec), `.tt-microbutton-portal` (column-flex, BUY btn + 'Already owned' caption styling). JS in `wallet-shop.js` exposes a singleton `WalletShop` module (matching the project's `Brief` / `SeaDeal` / `StageCard` module pattern) w. a tested `initWalletShop()` method — uses event delegation on the shop root (so portal-relocated buy btns still hit the handler) + a DOM-keyed `data-shop-wired` flag (not a module-level boolean) so per-test fixture rebuilds re-wire cleanly. Wired into `wallet.html` after `wallet.js`. **TDD** — 5 Jasmine specs in `WalletShopSpec.js`: T1 click-on-enabled-BUY opens guard w. correct prompt; T2 click-on-disabled-BUY no-op; T3 onConfirm POSTs `shop_item_slug` to `/shop/buy`; T4 init idempotent (calling twice doesn't double-wire); T5 missing-root no-throw. **2 Jasmine traps caught**: (a) `spyOn(window, 'fetch')` collides if another spec already spied on fetch — switched to save+restore via per-test `_origFetch` capture; (b) T3 async pollution — sync assertion passed, `afterEach` restored `window.Stripe=undefined`, then `_doBuy`'s async continuation hit `Stripe(pubKey)` and threw "Unhandled promise rejection". Fixed by T3-local fetch mock returning a never-resolving promise so the chain pauses at the first await. **3 new FTs** in `test_dash_wallet.py`: tiles + icons + ×5 badge + tooltip prose; BUY click opens guard portal + NVM dismisses; BAND-already-owned shows disabled BUY w. 'Already owned' microtext (reads via `textContent` since `.tt` is `display: none`). FT trap caught: `TransactionTestCase` wipes both migration-seeded Applets + ShopItems → setUp must re-seed both manually (mirrors `test_shop_views.py`'s `_seed_starting_items` pattern). 1208 IT/UT + 9 wallet FTs + 5 Jasmine specs green Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:15:05 -04:00
// ── Wallet Shop applet ───────────────────────────────────────────────────────
// Mimics `.wallet-tokens` (horizontal row of tooltipped icons) but each tile
// carries an admin-defined catalog item + an optional `.shop-badge` (eg "×5"
// for the bundle) + a BUY-ITEM microbutton hosted in the tooltip portal.
// JS wiring lives in `apps/dashboard/static/apps/dashboard/wallet-shop.js`.
.wallet-shop {
display: flex;
flex-direction: column;
overflow: visible;
.shop-grid {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-evenly;
gap: 1rem;
overflow: visible;
}
}
.shop-tile {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: rgba(var(--terUser), 1);
cursor: help;
}
// ×5 badge — top-right corner, --quaUser glyph on --quiUser bg, 2rem circle.
// Per-locked spec from [[project-wallet-shop-expansion]].
.shop-badge {
position: absolute;
top: -0.5rem;
right: -0.75rem;
width: 2rem;
height: 2rem;
border-radius: 50%;
background: rgba(var(--quiUser), 1);
color: rgba(var(--quaUser), 1);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
font-weight: 700;
pointer-events: none;
}
// Microtooltip — the buy-btn lives inside the main tooltip portal, styled
// like Game Kit's `#id_mini_tooltip_portal` (Equipped/Unequipped/In-Use).
// Hover persistence (cursor moves from tile → portal → microbutton without
// dismissing the tooltip) is handled by `wallet-shop.js`.
.tt-microbutton-portal {
margin-top: 0.5rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
.tt-buy-btn {
font-size: 0.75rem;
padding: 0.25rem 0.75rem;
}
.tt-already-owned {
font-size: 0.7rem;
margin: 0;
color: rgba(var(--terUser), 0.85);
}
}