Skip to content

modify the toast notification system to prevent spamming#293

Merged
rmyndharis merged 2 commits into
rmyndharis:mainfrom
quinton-8:feature/server-connection-loss-handling
Jun 21, 2026
Merged

modify the toast notification system to prevent spamming#293
rmyndharis merged 2 commits into
rmyndharis:mainfrom
quinton-8:feature/server-connection-loss-handling

Conversation

@quinton-8

@quinton-8 quinton-8 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Modify the toast notification system to prevent spamming multiple error notifications on the right side of the screen when the server is
stopped.

Description

Brief description of changes

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • Tests added/updated
  • Documentation updated
  • Lint passes
  • Self-reviewed

Screenshots (if applicable)

Related Issues

Closes #

@quinton-8

Copy link
Copy Markdown
Contributor Author

Suppressed Duplicate Errors in ToastProvider
In Toast.tsx, added logic to check if a connection error occurs (based
on the server offline state or connection failure messages such as "failed
to fetch" or 502/503 status).
• It now suppresses all incoming error/success/warning toasts when
offline.
• Instead, it displays exactly one persistent error toast titled
"Server Connection Lost" asking the user to start the server. This
toast stays open until connection is restored.

@rmyndharis rmyndharis left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @quinton-8 — appreciate the focus on toast spam, and the happy path (success/warning/info and normal errors) is correctly left untouched. A few things to address before merge:

1. (Blocking) setTimeout is called inside the setToasts updater. State updater functions must be side-effect-free — under React 18 Strict Mode the updater runs twice (so two timers fire), and if an update is replayed/batched the timer can fire for a toast that was never committed, which can leave the dedup in a stuck state. Please mirror the existing addToast structure: compute the id first, do the dedup guard inside the updater (return prev when it's a duplicate), and call setTimeout(() => removeToast(id), 6000) after setToasts, not inside it. (This is the "side effects outside state updates" pattern in the repo's known-issues list.)

2. Extract the dedup sentinel. 'Server Connection Lost' is a hardcoded string used as the dedup key; if it's ever translated, the dedup silently breaks. Please pull it into a module-level constant (or an i18n key).

3. (Optional / follow-up) Scope. This only dedups a fixed list of network-error strings; other rapidly-repeating errors still stack. A more general fix would be a (type, title) dedup inside addToast itself — happy to take that as a separate follow-up if you'd prefer to keep this PR focused.

Items 1 and 2 are needed to merge; 3 is a nice-to-have. Thanks!

@quinton-8

quinton-8 commented Jun 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

@rmyndharis

Copy link
Copy Markdown
Owner

Thanks @quinton-8 — deduping the connection-error toasts is a real UX win; a downed backend currently spams the screen. A few changes before merge:

  1. i18n — the strings here are hardcoded English ('Server Connection Lost', 'The backend server is unreachable...'); the dashboard is i18n'd across nine locales, so please move them into the locale files and use t(...).
  2. Side-effect in the state updatersetTimeout(() => removeToast(id), 6000) runs inside setToasts(prev => ...). Updaters should be pure; under React StrictMode this updater runs twice, so the timer is scheduled twice. Please move the auto-dismiss out of the updater (e.g. schedule it after the state update, or reuse the existing addToast duration path with a dedup guard).
  3. Dedup key — matching on the (now-localized) title is brittle; a stable flag like dedupeKey: 'connection-lost' would be sturdier.
  4. A small test for "a second connection error doesn't add a second toast" would lock this in.

Happy to re-review once those are in. Thanks!

@rmyndharis

Copy link
Copy Markdown
Owner

Hi @quinton-8 — thanks again for tackling the toast spam, this is a genuine UX win (a downed backend currently floods the screen). Circling back since the branch hasn't been updated yet. Two small things remain from the earlier review:

  1. Move the auto-dismiss out of the state updater. Right now setTimeout(() => removeToast(id), 6000) runs inside setToasts(prev => ...). Updaters need to stay side-effect-free — under React 18 StrictMode the updater runs twice, so the timer gets scheduled twice. The cleanest fix is to mirror the existing addToast (Toast.tsx lines 47-63): compute the id first, do the dedup guard inside the updater (return prev if it's a duplicate), then call setTimeout(() => removeToast(id), 6000) after setToasts.

  2. i18n + a stable dedup key. The component already uses useTranslation, and the dashboard ships nine locales under dashboard/src/i18n/locales/, so 'Server Connection Lost' and the body string should move into the locale files and be rendered via t(...). One gotcha: since the title doubles as the dedup key, translating it would silently break dedup — so it's sturdier to dedup on a stable flag (e.g. a dedupeKey: 'connection-lost' field) rather than the visible title.

If you have a moment to push those, I'll re-review right away. And no pressure at all — if you're tied up, I'm happy to take it from here and finish it off, since it's a small change. A quick unit test ("a second connection error doesn't add a second toast") would be a nice bonus but is optional. Thanks for the contribution!

@quinton-8

quinton-8 commented Jun 20, 2026 via email

Copy link
Copy Markdown
Contributor Author

rmyndharis pushed a commit to quinton-8/OpenWA that referenced this pull request Jun 21, 2026
…ollow-up rmyndharis#293)

Addresses the review on rmyndharis#293:
- Move the auto-dismiss setTimeout OUT of the setToasts updater. State updaters must be
  side-effect-free; under React Strict Mode they run twice, which would schedule two timers
  (and could fire for a toast that was never committed). Compute the id first, guard inside
  the updater, schedule the timer after.
- De-dupe on a stable `CONNECTION_LOST_DEDUPE_KEY` constant instead of the displayed title,
  so translating the title can never silently break de-duplication.
- i18n the "Server Connection Lost" title + message via a new `toast.connectionLost` key
  across all 8 bundled locales (es.json, added later on main, falls back to en until keyed).
- Extract the duplicated toast-id generation into a createToastId() helper.
@rmyndharis

Copy link
Copy Markdown
Owner

Hi @quinton-8 — thanks again for this, the connection-error de-dupe is a real UX win. Since we're lining up the next release and the branch hadn't been updated, I pushed a small follow-up commit to your branch to close out the two review items (hope that's alright — your authorship stays on the PR):

  • Side-effect out of the state updater — the auto-dismiss setTimeout now runs after setToasts, not inside it (updaters must be side-effect-free; Strict Mode runs them twice).
  • Stable de-dupe key — de-dupe now keys on a module-level CONNECTION_LOST_DEDUPE_KEY constant instead of the displayed title, so translating the title can't silently break it.
  • i18n — the title/message are now translated via a new toast.connectionLost key across all 8 bundled locales (the later-added es.json falls back to English until keyed).
  • Minor: extracted the duplicated toast-id generation into a createToastId() helper.

Build + lint are green. I left the optional generic (type, title) de-dupe (review item #3) out to keep this focused — happy to take that as a separate follow-up. Thanks for the contribution! 🙏

quinton-8 and others added 2 commits June 21, 2026 10:35
  error notifications on the right side of the screen when the server is
  stopped.
…ollow-up rmyndharis#293)

Addresses the review on rmyndharis#293:
- Move the auto-dismiss setTimeout OUT of the setToasts updater. State updaters must be
  side-effect-free; under React Strict Mode they run twice, which would schedule two timers
  (and could fire for a toast that was never committed). Compute the id first, guard inside
  the updater, schedule the timer after.
- De-dupe on a stable `CONNECTION_LOST_DEDUPE_KEY` constant instead of the displayed title,
  so translating the title can never silently break de-duplication.
- i18n the "Server Connection Lost" title + message via a new `toast.connectionLost` key
  across all 8 bundled locales (es.json, added later on main, falls back to en until keyed).
- Extract the duplicated toast-id generation into a createToastId() helper.
@rmyndharis rmyndharis force-pushed the feature/server-connection-loss-handling branch from eaaf85f to 44c72d9 Compare June 21, 2026 03:36
@rmyndharis rmyndharis merged commit a00ef43 into rmyndharis:main Jun 21, 2026
5 checks passed
rmyndharis added a commit that referenced this pull request Jun 21, 2026
Cut v0.4.7 — smart webhook filters (#379), WWEBJS_AUTH_TIMEOUT_MS (#383), toast anti-spam (#293), Postgres webhook-JSON crash fix (#385).
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.

3 participants