Skip to content

fix: duplicate "Are you sure?" dialogs after connecting a WordPress channel#1641

Open
giladresisi wants to merge 1 commit into
mainfrom
fix/are-you-sure-emitter-cleanup
Open

fix: duplicate "Are you sure?" dialogs after connecting a WordPress channel#1641
giladresisi wants to merge 1 commit into
mainfrom
fix/are-you-sure-emitter-cleanup

Conversation

@giladresisi

Copy link
Copy Markdown
Collaborator

What

After connecting a WordPress channel, the "Are you sure?" confirmation dialog (e.g. when deleting a channel) started appearing twice. Clicking Yes or No only dismissed one copy, leaving a duplicate stuck on screen. It affected every channel, not just WordPress, and only cleared after a full page refresh.

Why this matters

This is a confusing, broken-feeling UX on a common, destructive action (deleting channels). A user could think their click "didn't work", and a leftover dialog blocking the screen looks like the app is stuck — all triggered simply by having connected WordPress earlier in the session.

Why it only showed up after WordPress

Most channels finish connecting with a full page reload, which resets everything. WordPress finishes with an in-app navigation (no reload), and that difference left the confirmation dialog's internal listener subscribed twice, so it opened a duplicate. Full technical root-cause is in the commit message.

The fix

The confirmation dialog is opened by a component (DecisionEverywhere) that subscribed to an event emitter in a useEffect without cleanup, so it leaked a listener on every unmount/remount. This adds the missing cleanup, so exactly one listener is ever subscribed and only one dialog opens. Minimal change, preserves the existing design; per-dialog close behaviour is unchanged.

There is a documented known limitation in the commit message (this assumes a single mounted modal wrapper, which holds today); it's intentionally out of scope here.

🤖 Generated with Claude Code

areYouSure() opens its dialog indirectly: it emits an 'open' event on a
module-level decisionModalEmitter, and the mounted DecisionEverywhere
component listens for that event and opens the modal. DecisionEverywhere
subscribed in a useEffect with no cleanup, so every mount added another
listener that was never removed.

Most channel connect flows redirect via window.location.href, a full page
reload that recreates the module (and a fresh, empty emitter), so the leak
was never visible. WordPress connects with customFields, which returns to
the app via client-side router.push instead. That unmounts and remounts
MantineWrapper (and DecisionEverywhere) without a reload, leaving a second,
stale listener subscribed. A single areYouSure() call then fired both
listeners and opened two identical stacked dialogs; clicking a button
closed only the top one, so a duplicate stayed on screen for every channel
until a manual refresh.

Remove the leaked listener on unmount (off the exact handler we added) so
exactly one listener is subscribed at any time across mount/unmount cycles.

Known limitation: this relies on at most one DecisionEverywhere being
mounted at a time, which holds today because every MantineWrapper lives in
a mutually-exclusive route group (and embedded previews run in iframes). If
two MantineWrappers were ever mounted simultaneously in the same document,
two listeners would coexist and duplicates could return; that would need a
separate fix (e.g. opening the dialog directly on the store, or a stable
modal id).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@postiz-contribution postiz-contribution Bot added the contribution:approved Approved contributor label Jun 26, 2026
@postiz-contribution

Copy link
Copy Markdown

Contribution-checker quality warning
Heuristic score: 22/100 (low). This is a non-blocking warning surfaced by the project's quality settings.

Heuristics that flagged:

  • PR doesn't use the repo's PR template: 5 required checkbox items missing (max 1, match ≥80%)
  • Body adds too many extra headers beyond the template: 4 extra headers (>1)
  • AI watermark phrase: Matched: "Generated with Claude Code"
  • Commit message too long: Longest: 1678 chars

If this is a genuine contribution, please add detail to your PR description and tighten the diff scope before reviewers look at it.

@postiz-agent

postiz-agent Bot commented Jun 26, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution:approved Approved contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant