Skip to content

Share dialog: graceful revert to last working link when a refetch fails #81

Description

@Alimedhat000

Problem

Follow-up to #78 (stale share-link fix). After #78, a failed permission refetch safely shows "No link available" — but that leaves the user stuck: the select keeps showing the failed mode, there's no link at all, and the only signal is a small error line. The user must manually figure out that switching back restores things.

Proposed behavior

When a permission-switch fetch fails:

  1. Revert the selection to the last confirmed permission (e.g. Edit fails → select snaps back to View).
  2. Restore the previous link instantly from cache so the dialog always shows a valid, copyable URL matching the select.
  3. Signal failure clearly: shake animation on the select trigger + red accent (~1.5s), keeping the existing error text line.

Design notes (from review discussion)

  • Model the state explicitly as two concepts in ShareButton:
    • confirmedPermission — the permission whose link is actually loaded (source of truth for what the Select displays at rest)
    • pendingPermission — the optimistic value shown while the fetch is in flight
    • Success: confirmed = pending. Failure: discard pending, snap back, fire the failure cue.
  • The revert path must apply the same requestId !== requestRef.current guard as the success path: if a failed request has been superseded (view→edit→view quickly), the late failure does nothing at all — no UI flicker, no stomping the newer confirmed choice.
  • Cache restore = keep a lastValid {permission, url} pair in the hook; on guarded failure, restore both and notify the component via callback so it can sync its select state.
  • Shake keyframe needs a small custom @keyframes / --animate-shake in client/src/index.css (tw-animate-css has no shake).

Out of scope (noted during review)

  • AbortController for superseded requests (wasted-work optimization, not correctness)
  • Debounce on rapid permission toggling

Relates to #48, #78.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions