Skip to content

fix: disable copy button while referral link is loading#177

Closed
nguyenlnp wants to merge 1 commit into
profullstack:masterfrom
nguyenlnp:fix/copy-empty-link-133
Closed

fix: disable copy button while referral link is loading#177
nguyenlnp wants to merge 1 commit into
profullstack:masterfrom
nguyenlnp:fix/copy-empty-link-133

Conversation

@nguyenlnp
Copy link
Copy Markdown
Contributor

Fix for #133 — Referral copy button copies empty link before invite link loads

Problem

On the Invite Friends dashboard, the referral link starts as an empty string until /api/referrals/code returns. The Copy button is enabled during that loading window, so a quick click can copy an empty string and show the user a successful copy state even though no invite link was copied.

Changes

  • Add loadingLink state — starts as true, set to false after loadCode() completes (regardless of success/failure)
  • Disable the Copy button when loadingLink is true or referralLink is empty (disabled={loadingLink || !referralLink})
  • Show loading text — button displays "Loading..." while the link is being fetched
  • Add handler guard in copyLink — early return if referralLink is empty, preventing clipboard write of empty string
  • Add disabled stylesdisabled:opacity-50 disabled:cursor-not-allowed for clear visual feedback
  • Add regression tests — 3 tests covering loading state, empty link after load, and successful copy

Testing

All 3 new tests pass:

  • ✅ Shows loading state on Copy button while referral link is loading
  • ✅ Disables Copy button when referral link is empty after loading
  • ✅ Copies referral link successfully after link loads

Fixes #133

…#133)

- Add loadingLink state to track when referral link is still loading
- Disable Copy button when loadingLink is true or referralLink is empty
- Show 'Loading...' text on Copy button during load
- Add guard in copyLink handler to prevent copying empty string
- Add disabled:opacity-50 and disabled:cursor-not-allowed styles
- Add regression tests for loading, empty link, and successful copy
@ralyodio ralyodio closed this May 23, 2026
@ralyodio ralyodio reopened this May 23, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR fixes a race condition where clicking Copy before the referral link had loaded would write an empty string to the clipboard. It introduces a loadingLink boolean, disables and relabels the Copy button during the fetch, adds a guard in copyLink, and covers the new behaviour with three focused tests.

  • page.tsx: loadingLink starts true and is set to false inside the .then() callback of loadCode(). If the fetch rejects at the network level (offline, DNS failure), the .then() is never reached, the flag stays true, and the button is permanently stuck in the disabled "Loading…" state.
  • page.test.tsx: New tests cover the happy-path loading state, empty-link-after-load, and successful copy, but the network-error path is not tested.

Confidence Score: 3/5

The change is a net improvement over the original behaviour, but it introduces a scenario where the Copy button can become permanently disabled if the network request fails at the transport level.

The loadingLink flag is only cleared inside the .then() callback, so a network-level fetch rejection (offline, DNS, timeout) leaves the flag permanently true and the button stuck in the disabled "Loading…" state for the lifetime of the page. Users experiencing a bad network connection would lose access to the Copy button entirely until they reload — the very audience most likely to hit slow API responses.

The .then() chain in page.tsx around loadCode() needs a .catch() or .finally() to handle network rejections. The test file would benefit from a corresponding network-error test case.

Important Files Changed

Filename Overview
src/app/dashboard/referrals/page.tsx Adds loadingLink state and disables the Copy button during fetch. A network-level rejection from loadCode() is not caught, so setLoadingLink(false) is never called and the button stays permanently disabled.
src/app/dashboard/referrals/page.test.tsx New test file covering loading state, empty-link-after-load, and successful copy. Does not cover the network-rejection path where fetch throws (which exposes the unhandled-rejection bug in page.tsx).

Sequence Diagram

sequenceDiagram
    participant Browser
    participant ReferralsPage
    participant API as /api/referrals/code

    ReferralsPage->>ReferralsPage: "loadingLink = true (mount)"
    ReferralsPage->>API: fetch("/api/referrals/code")
    Note over ReferralsPage: Copy button: disabled + "Loading..."

    alt Success (HTTP ok)
        API-->>ReferralsPage: "{ link, code }"
        ReferralsPage->>ReferralsPage: setReferralLink / setReferralCode
        ReferralsPage->>ReferralsPage: setLoadingLink(false)
        Note over ReferralsPage: Copy button: enabled + "Copy"
    else HTTP error (non-ok)
        API-->>ReferralsPage: "res.ok = false → returns null"
        ReferralsPage->>ReferralsPage: setLoadingLink(false)
        Note over ReferralsPage: Copy button: disabled (no link) + "Copy"
    else Network rejection (throws)
        API--xReferralsPage: fetch throws (offline / DNS)
        Note over ReferralsPage: .then() never called
        Note over ReferralsPage: loadingLink stays true forever
        Note over ReferralsPage: Copy button: permanently disabled + "Loading..."
    end

    Browser->>ReferralsPage: User clicks Copy
    alt referralLink is set
        ReferralsPage->>Browser: navigator.clipboard.writeText(link)
        ReferralsPage->>ReferralsPage: setCopied(true) → "Copied!"
    else referralLink is empty
        ReferralsPage->>ReferralsPage: early return (guard added by this PR)
    end
Loading

Comments Outside Diff (1)

  1. src/app/dashboard/referrals/page.tsx, line 52-58 (link)

    P1 If fetch("/api/referrals/code") throws a network-level error (DNS failure, offline, timeout), the async loadCode() function rejects and the .then() callback is never reached, so setLoadingLink(false) is never called. The button stays permanently in the "Loading…" / disabled state for the rest of the page's lifetime. loadCode only handles non-ok HTTP responses (returning null); it does not absorb network exceptions. Using .finally() ensures the flag is cleared regardless of how the promise settles.

Reviews (1): Last reviewed commit: "fix: disable copy button while referral ..." | Re-trigger Greptile

@ralyodio ralyodio closed this May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: referral copy button can copy an empty link before invite link loads

2 participants