Referrals: visible confirmation for copy/share (R6 silent clipboard UX) #86

Closed
opened 2026-04-28 05:38:51 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-04-28 05:38:51 +00:00 (Migrated from gitlab.com)

Summary

Share-link clipboard writes on /referrals succeed, but confirmation can feel silent to users (easy to double-click, thinking nothing happened).

Current behavior (ReferralRegisterSection.tsx): on successful navigator.clipboard.writeText, each Copy button swaps label Copy → Copied for 2s. E2E expects this (anvil-referrals.spec.ts).

Remaining UX gaps:

  • Low contrast / easy to miss — especially next to long URLs or on small viewports.
  • No confirmation when clipboard is unavailable — early return with no status (copy callback); users get zero feedback.
  • Optional: screen reader — ensure copied state is announced (aria-live or temporary aria-label).
  1. Primary: Add a toast or inline banner (“Copied to clipboard”) when a share URL is copied, using existing app toast/status patterns if any; otherwise a small fixed or inline message for ~2s.
  2. Minimum: Keep button Copy → Copied but add aria-live="polite" on the button or a sibling region so assistive tech + sighted users get a clearer signal; optionally append “!” (“Copied!”) for scan-ability.
  3. Failure path: If clipboard.writeText is missing or rejects, show StatusMessage / inline error (“Could not copy — select the link manually”) instead of silent no-op.

Acceptance criteria

  • After a successful copy from Your share links, the user sees obvious confirmation (toast or persistent-enough inline Copied! state ≥ ~2s; may stack with existing button label change).
  • Double-click scenario: second click within the window still yields clear feedback (idempotent toast ok; no confusing duplicate errors).
  • Clipboard denied / unsupported: user sees actionable feedback, not silence.
  • Playwright: anvil-referrals.spec.ts updated if selectors/assertions depend on Copy-only UI; keep register + clipboard happy-path green under bash scripts/e2e-anvil.sh.

Docs / files to update

Cross-link: GitLab #64 rows R6.

Sub-issue?

Optional separate sub-issue: “Clipboard fallback + telemetry-free error copy UX” (mobile Safari / non-secure context, document.execCommand('copy') fallback policy). Flag for maintainer: file as child of this issue only if you want scoped review; otherwise keep in this issue as an acceptance bullet.

## Summary Share-link **clipboard** writes on `/referrals` succeed, but confirmation can feel **silent** to users (easy to **double-click**, thinking nothing happened). Current behavior ([`ReferralRegisterSection.tsx`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/referrals/ReferralRegisterSection.tsx)): on successful `navigator.clipboard.writeText`, each Copy button swaps label **Copy → Copied** for **2s**. E2E expects this ([`anvil-referrals.spec.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/e2e/anvil-referrals.spec.ts)). Remaining UX gaps: - **Low contrast / easy to miss** — especially next to long URLs or on small viewports. - **No confirmation when clipboard is unavailable** — early return with no status ([`copy` callback](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/referrals/ReferralRegisterSection.tsx)); users get zero feedback. - Optional: **screen reader** — ensure copied state is announced (`aria-live` or temporary `aria-label`). ## Recommended solution 1. **Primary:** Add a **toast** or **inline banner** (“Copied to clipboard”) when a share URL is copied, using existing app toast/status patterns if any; otherwise a small **fixed or inline** message for ~2s. 2. **Minimum:** Keep button **Copy → Copied** but add **`aria-live="polite"`** on the button or a sibling region so assistive tech + sighted users get a clearer signal; optionally append **“!”** (“Copied!”) for scan-ability. 3. **Failure path:** If `clipboard.writeText` is missing or rejects, show **`StatusMessage`** / inline error (“Could not copy — select the link manually”) instead of silent no-op. ## Acceptance criteria - [ ] After a successful copy from **Your share links**, the user sees **obvious** confirmation (toast **or** persistent-enough inline **Copied!** state ≥ ~2s; may stack with existing button label change). - [ ] **Double-click** scenario: second click within the window still yields clear feedback (idempotent toast ok; no confusing duplicate errors). - [ ] **Clipboard denied / unsupported:** user sees **actionable** feedback, not silence. - [ ] **Playwright:** [`anvil-referrals.spec.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/e2e/anvil-referrals.spec.ts) updated if selectors/assertions depend on Copy-only UI; keep register + clipboard happy-path green under `bash scripts/e2e-anvil.sh`. ## Docs / files to update - [`frontend/src/pages/referrals/ReferralRegisterSection.tsx`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/referrals/ReferralRegisterSection.tsx) — copy UX + optional error branch. - [`frontend/e2e/anvil-referrals.spec.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/e2e/anvil-referrals.spec.ts) — assertions for new confirmation UI. - [`skills/verify-yo-referrals-surface/SKILL.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/skills/verify-yo-referrals-surface/SKILL.md) row **R6** — describe expected confirmation (screenshot/recording notes). - [`docs/testing/invariants-and-business-logic.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/invariants-and-business-logic.md) — referrals / #64 manual row if behavior is now explicitly toast+button. Cross-link: GitLab [#64](https://gitlab.com/PlasticDigits/yieldomega/-/issues/64) rows **R6**. ## Sub-issue? **Optional separate sub-issue:** “Clipboard fallback + telemetry-free error copy UX” (mobile Safari / non-secure context, `document.execCommand('copy')` fallback policy). **Flag for maintainer:** file as child of this issue only if you want scoped review; otherwise keep in this issue as an acceptance bullet.
PlasticDigits commented 2026-04-28 06:03:22 +00:00 (Migrated from gitlab.com)

mentioned in commit 3ace423b81

mentioned in commit 3ace423b81a1e1152d5027cd8031ad1987f5bff4
PlasticDigits commented 2026-04-28 06:03:41 +00:00 (Migrated from gitlab.com)

mentioned in commit 4d9706e6fc

mentioned in commit 4d9706e6fc9078cfee6ccc19ca58df2cd38f14b9
PlasticDigits commented 2026-04-28 06:04:09 +00:00 (Migrated from gitlab.com)

Implemented on main (merge 4d9706e).

Summary: /referrals “Your share links” copy actions now show a green inline “Copied to clipboard!” banner (~2.6s, aria-live="polite" + role="status"), row buttons use Copy → Copied!, and clipboard missing / writeText rejection surfaces StatusMessage errors (manual-select guidance) instead of a silent no-op. Strings + TTL live in frontend/src/pages/referrals/referralShareCopyFeedback.ts. E2E asserts the banner + a second click while Copied! still refreshes confirmation.

Docs / cross-links: docs/testing/invariants-and-business-logic.md (R6 + summary row), docs/product/referrals.md, .cursor/skills/yieldomega-guardrails/SKILL.md, skills/verify-yo-referrals-surface/SKILL.md (R6).

@brouie — please verify when you can. Checklist:

  • Register (or use existing code), open Your share links, click Copy on the TimeCurve URL → green “Copied to clipboard!” appears and the button reads Copied! for ~2s.
  • Click the same row again while Copied! is visible → confirmation still appears (no silent double-click).
  • Copy the ?ref= row → same banner behavior; clipboard text matches the row.
  • (Optional) In a context without navigator.clipboard.writeText or after denying permission → error text tells you to select the link manually (not silence).

Issue left open per request.

Implemented on **main** (merge `4d9706e`). **Summary:** `/referrals` “Your share links” copy actions now show a **green inline “Copied to clipboard!”** banner (~2.6s, `aria-live="polite"` + `role="status"`), row buttons use **Copy → Copied!**, and **clipboard missing / `writeText` rejection** surfaces **`StatusMessage` errors** (manual-select guidance) instead of a silent no-op. Strings + TTL live in `frontend/src/pages/referrals/referralShareCopyFeedback.ts`. E2E asserts the banner + a **second click** while **Copied!** still refreshes confirmation. **Docs / cross-links:** `docs/testing/invariants-and-business-logic.md` (R6 + summary row), `docs/product/referrals.md`, `.cursor/skills/yieldomega-guardrails/SKILL.md`, `skills/verify-yo-referrals-surface/SKILL.md` (R6). @brouie — please verify when you can. **Checklist:** - [ ] Register (or use existing code), open **Your share links**, click **Copy** on the TimeCurve URL → **green “Copied to clipboard!”** appears and the button reads **Copied!** for ~2s. - [ ] Click the same row again while **Copied!** is visible → confirmation still appears (no silent double-click). - [ ] Copy the **?ref=** row → same banner behavior; clipboard text matches the row. - [ ] (Optional) In a context without `navigator.clipboard.writeText` or after denying permission → **error** text tells you to select the link manually (not silence). Issue left **open** per request.
Brouie commented 2026-04-28 07:24:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #85

mentioned in issue #85
Brouie commented 2026-04-28 08:02:24 +00:00 (Migrated from gitlab.com)

Verified end-to-end on 7b0f37d. All 3 mandatory checklist items pass.

Setup

Live local Anvil stack with VITE_REFERRAL_REGISTRY_ADDRESS wired, MetaMask Imported Account 4 (0x90F79bf6...b906) connected after switching from Account 1 mid-session. Registered code 'qatest3' onchain via the page's CL8Y BURN -> REGISTER A CODE flow (1 CL8Y burn confirmed, post-register state showed 'This wallet has a code' + 'Your share links' panel with both row variants populated).

Test 1 — TimeCurve URL row

Clicked Copy on the http://localhost:5173/timecurve/qatest3 row.

PASS:

  • Green inline 'Copied to clipboard!' banner appeared above the rows
  • Row button text flipped Copy -> Copied! for ~2 seconds
  • No silent no-op

Test 2 — Second click while still 'Copied!'

While the 'Copied!' state was still visible from Test 1, clicked the same TimeCurve URL Copy button a second time.

PASS:

  • Confirmation banner refreshed (TTL reset, not a silent double-click)
  • Button stayed in 'Copied!' state through the second confirm cycle

This matches the dev's spec: 'a second click while Copied! still refreshes confirmation'.

Test 3 — ?ref= URL row

Clicked Copy on the http://localhost:5173/?ref=qatest3 row.

PASS:

  • Same green 'Copied to clipboard!' banner
  • Same Copy -> Copied! transition
  • Clipboard text matched the row content (verified via paste)

Test 4 — clipboard error path

Skipped per dev's '(Optional)' marker. Engineering a navigator.clipboard.writeText rejection in Chrome without a custom test harness isn't trivial; the StatusMessage error path is covered by the e2e suite and source review of frontend/src/pages/referrals/referralShareCopyFeedback.ts shows the rejection branch wired to the same StatusMessage component used elsewhere on the page (so visible-error contract is consistent).

Side observation — incidentally validates #85

The 'Links that count' panel lede on this same /referrals page renders the post-#85 copy: 'Pending referral codes use key yieldomega.ref.v1 in localStorage and sessionStorage; after you register, your share-link code is cached per wallet under yieldomega.myrefcode.v1. plus your lowercased wallet address (localStorage only).' Good cross-link for live #85 validation.

Closing #86.

cc @PlasticDigits

Verified end-to-end on 7b0f37d. All 3 mandatory checklist items pass. ## Setup Live local Anvil stack with VITE_REFERRAL_REGISTRY_ADDRESS wired, MetaMask Imported Account 4 (0x90F79bf6...b906) connected after switching from Account 1 mid-session. Registered code 'qatest3' onchain via the page's CL8Y BURN -> REGISTER A CODE flow (1 CL8Y burn confirmed, post-register state showed 'This wallet has a code' + 'Your share links' panel with both row variants populated). ## Test 1 — TimeCurve URL row Clicked Copy on the http://localhost:5173/timecurve/qatest3 row. PASS: - Green inline 'Copied to clipboard!' banner appeared above the rows - Row button text flipped Copy -> Copied! for ~2 seconds - No silent no-op ## Test 2 — Second click while still 'Copied!' While the 'Copied!' state was still visible from Test 1, clicked the same TimeCurve URL Copy button a second time. PASS: - Confirmation banner refreshed (TTL reset, not a silent double-click) - Button stayed in 'Copied!' state through the second confirm cycle This matches the dev's spec: 'a second click while Copied! still refreshes confirmation'. ## Test 3 — ?ref= URL row Clicked Copy on the http://localhost:5173/?ref=qatest3 row. PASS: - Same green 'Copied to clipboard!' banner - Same Copy -> Copied! transition - Clipboard text matched the row content (verified via paste) ## Test 4 — clipboard error path Skipped per dev's '(Optional)' marker. Engineering a navigator.clipboard.writeText rejection in Chrome without a custom test harness isn't trivial; the StatusMessage error path is covered by the e2e suite and source review of frontend/src/pages/referrals/referralShareCopyFeedback.ts shows the rejection branch wired to the same StatusMessage component used elsewhere on the page (so visible-error contract is consistent). ## Side observation — incidentally validates #85 The 'Links that count' panel lede on this same /referrals page renders the post-#85 copy: 'Pending referral codes use key yieldomega.ref.v1 in localStorage and sessionStorage; after you register, your share-link code is cached per wallet under yieldomega.myrefcode.v1. plus your lowercased wallet address (localStorage only).' Good cross-link for live #85 validation. Closing #86. cc @PlasticDigits
Brouie (Migrated from gitlab.com) closed this issue 2026-04-28 08:02:44 +00:00
Brouie commented 2026-04-30 03:15:16 +00:00 (Migrated from gitlab.com)

mentioned in issue #93

mentioned in issue #93
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#86
No description provided.