Files
sure/app/views/shared/notifications/_sync_toast.html.erb
Abhinav Dhiman cc070853b7 fix: Replace platform-wide broadcast_refresh with sync toast (#1964)
* fix: Replace platform-wide broadcast_refresh with sync toast

Instead of calling family.broadcast_refresh on every sync completion
(which reloads the page for all connected family members), broadcast
a lightweight static toast to the existing notification-tray.

A new sync-toast Stimulus controller handles two cases:
- User is idle (no focused form): auto-reloads after 500ms
- User is mid-form: toast stays visible with a manual Refresh button

This prevents in-progress form state from being wiped when a background
sync fires (e.g. adding a transaction, filling an import form).

The toast partial contains no user-scoped data, so the Current.user nil
constraint in background jobs is no longer a concern.

* fix(a11y): add explicit button types and aria-label to sync toast controls

* fix(sync-toast): improve interaction detection and replace broadcast strategy

- Increase auto-refresh delay from 500ms to 2000ms
- Expand interaction detection to include contentEditable, dialogs, and role="dialog" elements
- Switch from broadcast_append_to to broadcast_replace_to with dedicated #sync-toast target
- Add explicit id="sync-toast" to partial for targeted replacement
- Move sync_toast i18n keys from defaults/en.yml to views/shared/en.yml

* fix(sync-toast): replace hardcoded white icon color with inverse token
2026-05-31 16:05:54 +02:00

24 lines
1.1 KiB
Plaintext

<div id="sync-toast"
data-controller="sync-toast element-removal"
class="relative flex gap-3 rounded-lg bg-container p-4 group w-full md:max-w-80 shadow-border-xs">
<div class="h-5 w-5 shrink-0 p-px text-primary">
<div class="flex h-full items-center justify-center rounded-full bg-info">
<%= icon "refresh-cw", size: "xs", color: "inverse" %>
</div>
</div>
<div class="space-y-1 flex-1">
<p class="text-primary text-sm font-medium"><%= t("shared.sync_toast.message") %></p>
<button type="button" class="text-xs text-info underline hover:opacity-80 transition-opacity"
data-action="click->sync-toast#refresh">
<%= t("shared.sync_toast.refresh") %>
</button>
</div>
<div class="absolute -top-2 -right-2">
<button type="button" class="p-0.5 hidden group-hover:inline-block border border-alpha-black-50 border-solid rounded-lg bg-container text-subdued cursor-pointer" aria-label="<%= t('defaults.common.close') %>" data-action="click->element-removal#remove">
<%= icon "x" %>
</button>
</div>
</div>