Add post-buy transaction result share popover #365

Closed
opened 2026-07-07 02:38:46 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-07-07 02:38:46 +00:00 (Migrated from gitlab.com)

Parent

Child of #363 — Improve top of funnel marketing and shareability.

Current codebase

Why needed

The BUY button triggers unusually dense consequences (timer, ranks, BP, prizes, rivals displaced). Today those appear as fleeting multi-toast lines optimized for feedback, not sharing. A single closable transaction-result card turns each buy into a screenshot-ready advertisement — compact, legible, mobile-first — while respecting anti–cognitive-overload copy rules from #363.

Constraints / guardrails

  • Scope: Play surface / only; do not block buy submit or wallet flow; popover is dismissible and must not trap focus permanently.
  • Indexer-first: Card content upgrades from preview → indexed buy via existing useArenaBuyEffectToasts head-resolution pattern; no new RPC mirrors · INV-FRONTEND-301-INDEXER-FIRST-DISPLAY.
  • Anti cognitive overload: Max ~5–7 scannable rows; short labels; emoji only where they aid scanning (not decoration); no paragraph walls · align with frontend-content-audit § play.
  • Screenshot fit: Entire card (header + effect rows + optional share action) must fit in one viewport screenshot on 390×844 mobile, 768×1024 tablet, and 1280×800 desktop without clipping critical copy.
  • Motion / a11y: Respect prefers-reduced-motion; role="dialog" or role="status" with accessible dismiss; do not auto-dismiss before user can read/share (unlike current 4s toast stack).
  • Branding: Yield Omega / Time Arena framing only; no forbidden legacy sale/TimeCurve copy.
  • Level-up / WYWA: Coordinate stacking order with LevelUpCelebrationPopover and WYWA modal — no more than one celebratory overlay at a time.

Relevant files

Area Files
Buy session useArenaSaleSession.ts, ArenaSimplePage.tsx
Effect data arenaBuyProjectedEffects.ts, arenaBuyEffectToastLines.ts, timeArenaBuyPreview.ts, timeArenaUx.ts
Current toast UI ArenaEffectToastStack.tsx, useArenaBuyEffectToasts.ts
Styles frontend/src/styles/yieldomega-glass-arena.css, frontend/src/index.css
Indexer types frontend/src/lib/indexerApi.ts (BuyItem)
Tests arenaBuyProjectedEffects.test.ts, ArenaSimplePage.test.tsx, e2e/anvil-arena-03-wallet-writes.spec.ts, e2e/anvil-arena-05-play-feel.spec.ts
Share copy referralShareCopyFeedback.ts
  1. Structured result model

    • Add buildArenaBuyShareSummary(buy, context) returning a fixed schema: { headline, rows: { icon?, label, value }[], txHash?, shareText? } covering timer delta, rank/podium movement (when inferable from indexer head), BP earned, prizes/settlements triggered, rivals displaced, XP/level if applicable.
    • Reuse buildArenaBuyActualEffectLines internals but collapse into grouped rows (not one toast per line).
  2. UI — closable popover card

    • New component (e.g. ArenaBuyResultSharePopover) portaled near checkout; opens on buy success; close button + backdrop tap + Escape.
    • Optional actions: Copy summary (plain-text tweet-style), Copy link (permalink to tx on explorer or future event page if available).
    • Replace or gate ArenaEffectToastStack so users get one card instead of stacked ephemeral toasts (keep toast path behind flag only if needed for rollback).
  3. Copy / emoji guidelines

    • Headline example pattern: ⏱ +2m 14s · 🏆 Last Buyer · +120 BP — tune in implementation.
    • Omit zero/no-op rows; truncate long rival lists to top displacement + count.
  4. Screenshot verification artifact

    • Add Playwright (or Vitest + @playwright/test screenshot) captures at three viewports asserting bounding box height ≤ viewport and text legibility (no font-size below existing arena minimums).

Acceptance criteria

  • After every successful wallet buy on /, a closable popover card appears summarizing that transaction's consequences in one compact panel.
  • Card states everything the one button accomplished when data exists: timer change, rank/podium effects, BP, prizes/settlements, rivals displaced, XP/level — omitting empty sections.
  • Copy follows anti–cognitive-overload rules; emoji used sparingly and purposefully.
  • Card fits fully in one screenshot on mobile, tablet, and desktop test viewports; verified by automated screenshot tests checked into repo.
  • Card upgrades from preview snapshot to indexer-confirmed values when head buy row arrives (same wallet).
  • Dismiss does not break subsequent buys; reduced-motion path has no essential-only animation.
  • Does not overlap level-up celebration or WYWA modal destructively.

Test plan

Layer Command / artifact Expect
Unit cd frontend && npm run typecheck && npm run lint && npm test PASS — summary builder, popover component, wiring tests
Static wiring ArenaSimplePage.test.tsx / arenaVisualUxHooks.test.ts PASS — documents hook + popover integration
Layout Extend mobileBuyEffectToastLayout.test.ts or new layout test for popover clearance above mobile nav + album dock PASS
E2E Anvil bash scripts/e2e-anvil.sh (or targeted anvil-arena-03-wallet-writes.spec.ts) with --workers=5 PASS — buy → popover visible → dismiss
Screenshot E2E New spec capturing 390×844, 768×1024, 1280×800 after buy PASS — full card visible, legible, no clip
Manual / Rabby Optional headed check per rabby-cloud-agent-qa.md for real signing PASS — same card after Rabby buy

Attack / abuse test plan

  • Clipboard: handle missing navigator.clipboard gracefully (mirror referral copy errors); no secret leakage in share text.
  • Share text: only public onchain/indexer facts; no wallet private data.
  • Rapid buys: queue or replace card cleanly; no unbounded DOM stack / memory from repeated buys.
  • Indexed spoofing: card must not trust client-side preview after indexer head resolves for viewer wallet (prevent stale boast if head buy differs).

Verification criteria

  • cd frontend && npm run typecheck && npm run lint && npm test — PASS
  • Anvil E2E buy flow shows and dismisses share popover — PASS
  • Screenshot tests at three viewports committed and passing in CI — PASS
  • Manual review: one screenshot per form factor shows entire card, direct copy, no filler — PASS
## Parent Child of [#363 — Improve top of funnel marketing and shareability](https://gitlab.com/PlasticDigits/yieldomega/-/issues/363). ## Current codebase - **Post-buy feedback today ([#337](https://gitlab.com/PlasticDigits/yieldomega/-/issues/337)):** [`useArenaBuyEffectToasts`](frontend/src/pages/arena/useArenaBuyEffectToasts.ts) pushes up to four auto-dismissing lines via [`ArenaEffectToastStack`](frontend/src/pages/arena/ArenaEffectToastStack.tsx) (fixed overlay, staggered motion, 4s dismiss). Wired from [`ArenaSimplePage.tsx`](frontend/src/pages/arena/ArenaSimplePage.tsx) on successful buy. - **Effect line builders:** [`buildArenaBuyProjectedEffectLines`](frontend/src/pages/arena/arenaBuyProjectedEffects.ts) (pre-submit preview) and [`buildArenaBuyActualEffectLines`](frontend/src/pages/arena/arenaBuyProjectedEffects.ts) (indexer-confirmed buy row) produce separate pill strings: timer (`+Ns`), XP, BP breakdown, streak, flag, level transitions. - **Indexed buy fields available:** `BuyItem` / `ArenaBuyItem` in [`indexerApi.ts`](frontend/src/lib/indexerApi.ts) — `actual_seconds_added`, `new_deadline`, `timer_hard_reset`, BP columns, `flag_planted`, `buyer_active_defended_streak`, charm/doub paid, `tx_hash`, `block_timestamp`. - **Adjacent UX (do not conflate):** - [`LevelUpCelebrationPopover`](frontend/src/components/LevelUpCelebrationPopover.tsx) — feature unlock on level cross ([#335](https://gitlab.com/PlasticDigits/yieldomega/-/issues/335)) - [`WhileYouWereAwayModal`](frontend/src/components/WhileYouWereAwayModal.tsx) — absent-session summary ([#338](https://gitlab.com/PlasticDigits/yieldomega/-/issues/338)) - **Share/copy precedent:** [`ReferralRegisterSection.tsx`](frontend/src/pages/referrals/ReferralRegisterSection.tsx) + [`referralShareCopyFeedback.ts`](frontend/src/pages/referrals/referralShareCopyFeedback.ts) (clipboard + banner timing). - **Mobile layout tests:** [`mobileBuyEffectToastLayout.test.ts`](frontend/src/pages/arena/mobileBuyEffectToastLayout.test.ts) pins toast stack above bottom nav — any new popover must respect album dock + safe-area clearance. ## Why needed The BUY button triggers unusually dense consequences (timer, ranks, BP, prizes, rivals displaced). Today those appear as fleeting multi-toast lines optimized for feedback, not sharing. A single closable **transaction-result card** turns each buy into a screenshot-ready advertisement — compact, legible, mobile-first — while respecting anti–cognitive-overload copy rules from [#363](https://gitlab.com/PlasticDigits/yieldomega/-/issues/363). ## Constraints / guardrails - **Scope:** Play surface `/` only; do not block buy submit or wallet flow; popover is dismissible and must not trap focus permanently. - **Indexer-first:** Card content upgrades from preview → indexed buy via existing `useArenaBuyEffectToasts` head-resolution pattern; no new RPC mirrors · **`INV-FRONTEND-301-INDEXER-FIRST-DISPLAY`**. - **Anti cognitive overload:** Max ~5–7 scannable rows; short labels; emoji only where they aid scanning (not decoration); no paragraph walls · align with [frontend-content-audit § play](docs/testing/frontend-content-audit.md). - **Screenshot fit:** Entire card (header + effect rows + optional share action) must fit in **one viewport screenshot** on 390×844 mobile, 768×1024 tablet, and 1280×800 desktop without clipping critical copy. - **Motion / a11y:** Respect `prefers-reduced-motion`; `role="dialog"` or `role="status"` with accessible dismiss; do not auto-dismiss before user can read/share (unlike current 4s toast stack). - **Branding:** **Yield Omega** / Time Arena framing only; no forbidden legacy sale/TimeCurve copy. - **Level-up / WYWA:** Coordinate stacking order with `LevelUpCelebrationPopover` and WYWA modal — no more than one celebratory overlay at a time. ## Relevant files | Area | Files | |------|-------| | Buy session | [`useArenaSaleSession.ts`](frontend/src/pages/arena/useArenaSaleSession.ts), [`ArenaSimplePage.tsx`](frontend/src/pages/arena/ArenaSimplePage.tsx) | | Effect data | [`arenaBuyProjectedEffects.ts`](frontend/src/pages/arena/arenaBuyProjectedEffects.ts), [`arenaBuyEffectToastLines.ts`](frontend/src/pages/arena/arenaBuyEffectToastLines.ts), [`timeArenaBuyPreview.ts`](frontend/src/lib/timeArenaBuyPreview.ts), [`timeArenaUx.ts`](frontend/src/lib/timeArenaUx.ts) | | Current toast UI | [`ArenaEffectToastStack.tsx`](frontend/src/pages/arena/ArenaEffectToastStack.tsx), [`useArenaBuyEffectToasts.ts`](frontend/src/pages/arena/useArenaBuyEffectToasts.ts) | | Styles | [`frontend/src/styles/yieldomega-glass-arena.css`](frontend/src/styles/yieldomega-glass-arena.css), [`frontend/src/index.css`](frontend/src/index.css) | | Indexer types | [`frontend/src/lib/indexerApi.ts`](frontend/src/lib/indexerApi.ts) (`BuyItem`) | | Tests | [`arenaBuyProjectedEffects.test.ts`](frontend/src/pages/arena/arenaBuyProjectedEffects.test.ts), [`ArenaSimplePage.test.tsx`](frontend/src/pages/arena/ArenaSimplePage.test.tsx), [`e2e/anvil-arena-03-wallet-writes.spec.ts`](frontend/e2e/anvil-arena-03-wallet-writes.spec.ts), [`e2e/anvil-arena-05-play-feel.spec.ts`](frontend/e2e/anvil-arena-05-play-feel.spec.ts) | | Share copy | [`referralShareCopyFeedback.ts`](frontend/src/pages/referrals/referralShareCopyFeedback.ts) | ## Recommended direction 1. **Structured result model** - Add `buildArenaBuyShareSummary(buy, context)` returning a fixed schema: `{ headline, rows: { icon?, label, value }[], txHash?, shareText? }` covering timer delta, rank/podium movement (when inferable from indexer head), BP earned, prizes/settlements triggered, rivals displaced, XP/level if applicable. - Reuse `buildArenaBuyActualEffectLines` internals but **collapse** into grouped rows (not one toast per line). 2. **UI — closable popover card** - New component (e.g. `ArenaBuyResultSharePopover`) portaled near checkout; opens on buy success; close button + backdrop tap + Escape. - Optional actions: **Copy summary** (plain-text tweet-style), **Copy link** (permalink to tx on explorer or future event page if available). - Replace or gate `ArenaEffectToastStack` so users get one card instead of stacked ephemeral toasts (keep toast path behind flag only if needed for rollback). 3. **Copy / emoji guidelines** - Headline example pattern: `⏱ +2m 14s · 🏆 Last Buyer · +120 BP` — tune in implementation. - Omit zero/no-op rows; truncate long rival lists to top displacement + count. 4. **Screenshot verification artifact** - Add Playwright (or Vitest + `@playwright/test` screenshot) captures at three viewports asserting bounding box height ≤ viewport and text legibility (no `font-size` below existing arena minimums). ## Acceptance criteria - [ ] After every successful wallet buy on `/`, a **closable popover card** appears summarizing that transaction's consequences in one compact panel. - [ ] Card states everything the one button accomplished when data exists: timer change, rank/podium effects, BP, prizes/settlements, rivals displaced, XP/level — omitting empty sections. - [ ] Copy follows anti–cognitive-overload rules; emoji used sparingly and purposefully. - [ ] Card fits fully in one screenshot on mobile, tablet, and desktop test viewports; verified by automated screenshot tests checked into repo. - [ ] Card upgrades from preview snapshot to indexer-confirmed values when head buy row arrives (same wallet). - [ ] Dismiss does not break subsequent buys; reduced-motion path has no essential-only animation. - [ ] Does not overlap level-up celebration or WYWA modal destructively. ## Test plan | Layer | Command / artifact | Expect | |-------|-------------------|--------| | Unit | `cd frontend && npm run typecheck && npm run lint && npm test` | PASS — summary builder, popover component, wiring tests | | Static wiring | `ArenaSimplePage.test.tsx` / `arenaVisualUxHooks.test.ts` | PASS — documents hook + popover integration | | Layout | Extend `mobileBuyEffectToastLayout.test.ts` or new layout test for popover clearance above mobile nav + album dock | PASS | | E2E Anvil | `bash scripts/e2e-anvil.sh` (or targeted `anvil-arena-03-wallet-writes.spec.ts`) with `--workers=5` | PASS — buy → popover visible → dismiss | | Screenshot E2E | New spec capturing 390×844, 768×1024, 1280×800 after buy | PASS — full card visible, legible, no clip | | Manual / Rabby | Optional headed check per [rabby-cloud-agent-qa.md](docs/testing/rabby-cloud-agent-qa.md) for real signing | PASS — same card after Rabby buy | ## Attack / abuse test plan - **Clipboard:** handle missing `navigator.clipboard` gracefully (mirror referral copy errors); no secret leakage in share text. - **Share text:** only public onchain/indexer facts; no wallet private data. - **Rapid buys:** queue or replace card cleanly; no unbounded DOM stack / memory from repeated buys. - **Indexed spoofing:** card must not trust client-side preview after indexer head resolves for viewer wallet (prevent stale boast if head buy differs). ## Verification criteria - [ ] `cd frontend && npm run typecheck && npm run lint && npm test` — PASS - [ ] Anvil E2E buy flow shows and dismisses share popover — PASS - [ ] Screenshot tests at three viewports committed and passing in CI — PASS - [ ] Manual review: one screenshot per form factor shows entire card, direct copy, no filler — PASS
PlasticDigits commented 2026-07-07 02:39:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #363

mentioned in issue #363
PlasticDigits commented 2026-07-07 04:22:09 +00:00 (Migrated from gitlab.com)

mentioned in commit 785cd4b74f

mentioned in commit 785cd4b74f92750098a9bd883cfe26c6f58f408d
PlasticDigits commented 2026-07-07 04:22:31 +00:00 (Migrated from gitlab.com)

mentioned in merge request !536

mentioned in merge request !536
PlasticDigits commented 2026-07-07 06:32:34 +00:00 (Migrated from gitlab.com)

mentioned in commit 2a7ad1d3a9

mentioned in commit 2a7ad1d3a926e05852661edaa0a52bca9c0a7fcc
PlasticDigits commented 2026-07-07 06:36:54 +00:00 (Migrated from gitlab.com)

mentioned in commit d8a779f26e

mentioned in commit d8a779f26e2ac9db4a5ffa77f2715ecb66f25290
PlasticDigits commented 2026-07-07 06:53:08 +00:00 (Migrated from gitlab.com)

Verification — #365 post-buy transaction result share popover

Verified on main @ d8a779f2 (merged MR for #365). No repo changes required.

Acceptance criteria

Item Result How verified
Closable popover card after successful wallet buy on / PASS PLAYWRIGHT_SPECS=e2e/anvil-arena-03-wallet-writes.spec.ts bash scripts/e2e-anvil.sh — test DOUB buy shows post-buy result share popover on /
Card summarizes timer, rank, BP, XP/level, WarBow; omits empty sections PASS arenaBuyShareSummary.test.ts, arenaBuyProjectedEffects.test.ts; manual review of screenshot fixtures
Anti–cognitive-overload copy; purposeful emoji PASS Screenshot review (docs/testing/screenshots/issue-365/{mobile,tablet,desktop}.png); headline + ≤7 grouped rows
Card fits one viewport screenshot (390×844, 768×1024, 1280×800) PASS CI=1 npm run test:e2e -- --workers=1 e2e/buy-result-share-screenshots.spec.ts — 3/3 bounding-box asserts
Preview upgrades to indexer-confirmed values for viewer head buy PASS arenaBuyShareSummary.test.ts (upgrades to indexer-confirmed); useArenaBuyResultSharePopover.ts head-resolution effect
Dismiss (× / backdrop / Escape) does not break subsequent buys; reduced-motion path PASS Anvil E2E dismiss test; ArenaBuyResultSharePopover.test.tsx; hook skips chime when reduceMotion
No destructive overlap with level-up celebration or WYWA PASS useArenaBuyResultSharePopover.ts celebrationActive deferral; ArenaSimplePage wiring

Test plan / invariants

Command Result
cd frontend && npm run typecheck && npm run lint && npm test PASS — 160 files, 896 tests
CI=1 npm run test:e2e -- --workers=1 e2e/buy-result-share-screenshots.spec.ts PASS — 3/3
PLAYWRIGHT_SPECS=e2e/anvil-arena-03-wallet-writes.spec.ts bash scripts/e2e-anvil.sh PASS — 3/3 (includes popover show + dismiss)
mobileBuyResultShareLayout.test.ts PASS — album dock + safe-area clearance
ArenaSimplePage.test.tsx / arenaVisualUxHooks.test.ts wiring PASS
Manual screenshot review (mobile / tablet / desktop) PASS — full card visible, direct copy, no filler
Rabby headed buy (optional per test plan) SKIP — mock Anvil E2E covers buy → popover → dismiss; Rabby not required for #365 sign-off

Attack / abuse checks (code + unit tests)

  • Clipboard graceful fallback: PASS (referralShareCopyFeedback pattern in popover)
  • Share text public facts only: PASS (buildArenaBuyShareSummary shareText)
  • Rapid buys replace card (no DOM stack): PASS (showCard replaces state; pendingRef single slot)
  • Indexed head overrides stale preview: PASS (lastResolvedBuyIdRef + findViewerBuyAtHead)

Follow-ups

  • Full bash scripts/e2e-anvil.sh currently has unrelated failures on anvil-arena-01-mount (AUDIT nav expects /arena/protocol, lands on /audit) and anvil-arena-05-play-feel (arena-xp-hero missing) — pre-existing route/UX drift outside #365 scope.

Closing as verified.

## Verification — #365 post-buy transaction result share popover Verified on `main` @ `d8a779f2` (merged MR for #365). No repo changes required. ### Acceptance criteria | Item | Result | How verified | |------|--------|--------------| | Closable popover card after successful wallet buy on `/` | **PASS** | `PLAYWRIGHT_SPECS=e2e/anvil-arena-03-wallet-writes.spec.ts bash scripts/e2e-anvil.sh` — test *DOUB buy shows post-buy result share popover on /* | | Card summarizes timer, rank, BP, XP/level, WarBow; omits empty sections | **PASS** | `arenaBuyShareSummary.test.ts`, `arenaBuyProjectedEffects.test.ts`; manual review of screenshot fixtures | | Anti–cognitive-overload copy; purposeful emoji | **PASS** | Screenshot review (`docs/testing/screenshots/issue-365/{mobile,tablet,desktop}.png`); headline + ≤7 grouped rows | | Card fits one viewport screenshot (390×844, 768×1024, 1280×800) | **PASS** | `CI=1 npm run test:e2e -- --workers=1 e2e/buy-result-share-screenshots.spec.ts` — 3/3 bounding-box asserts | | Preview upgrades to indexer-confirmed values for viewer head buy | **PASS** | `arenaBuyShareSummary.test.ts` (*upgrades to indexer-confirmed*); `useArenaBuyResultSharePopover.ts` head-resolution effect | | Dismiss (× / backdrop / Escape) does not break subsequent buys; reduced-motion path | **PASS** | Anvil E2E dismiss test; `ArenaBuyResultSharePopover.test.tsx`; hook skips chime when `reduceMotion` | | No destructive overlap with level-up celebration or WYWA | **PASS** | `useArenaBuyResultSharePopover.ts` `celebrationActive` deferral; `ArenaSimplePage` wiring | ### Test plan / invariants | Command | Result | |---------|--------| | `cd frontend && npm run typecheck && npm run lint && npm test` | **PASS** — 160 files, 896 tests | | `CI=1 npm run test:e2e -- --workers=1 e2e/buy-result-share-screenshots.spec.ts` | **PASS** — 3/3 | | `PLAYWRIGHT_SPECS=e2e/anvil-arena-03-wallet-writes.spec.ts bash scripts/e2e-anvil.sh` | **PASS** — 3/3 (includes popover show + dismiss) | | `mobileBuyResultShareLayout.test.ts` | **PASS** — album dock + safe-area clearance | | `ArenaSimplePage.test.tsx` / `arenaVisualUxHooks.test.ts` wiring | **PASS** | | Manual screenshot review (mobile / tablet / desktop) | **PASS** — full card visible, direct copy, no filler | | Rabby headed buy (optional per test plan) | **SKIP** — mock Anvil E2E covers buy → popover → dismiss; Rabby not required for #365 sign-off | ### Attack / abuse checks (code + unit tests) - Clipboard graceful fallback: **PASS** (`referralShareCopyFeedback` pattern in popover) - Share text public facts only: **PASS** (`buildArenaBuyShareSummary` shareText) - Rapid buys replace card (no DOM stack): **PASS** (`showCard` replaces state; `pendingRef` single slot) - Indexed head overrides stale preview: **PASS** (`lastResolvedBuyIdRef` + `findViewerBuyAtHead`) ### Follow-ups - Full `bash scripts/e2e-anvil.sh` currently has unrelated failures on `anvil-arena-01-mount` (AUDIT nav expects `/arena/protocol`, lands on `/audit`) and `anvil-arena-05-play-feel` (`arena-xp-hero` missing) — pre-existing route/UX drift outside #365 scope. Closing as verified.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-07 06:53:09 +00:00
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#365
No description provided.