diff --git a/src/composables/useNotifications.js b/src/composables/useNotifications.js index dccfc4d..41aff7f 100644 --- a/src/composables/useNotifications.js +++ b/src/composables/useNotifications.js @@ -65,16 +65,40 @@ export function useNotifications() { showToastFor(item); } - // Re-carrega notifs do DB e dispara toast pras system_alert não-lidas - // que ainda não foram vistas nesta sessão. Usado no mount, no visibilitychange - // e no polling de fallback pro caso de Realtime perder eventos. + // Re-carrega notifs do DB e dispara toast AGREGADO pras system_alert + // não-lidas ainda não vistas nesta sessão. Se tiver várias, mostra só + // a mais recente com sufixo "(+N outros alertas)" no detail pra evitar + // enxurrada de toasts ao voltar pra aba / recarregar. Eventos novos via + // Realtime continuam aparecendo individualmente (showToastFor direto). async function refreshAndMaybeAlert() { if (!ownerId) return; await store.load(ownerId); - for (const item of store.items || []) { - if (item.type !== 'system_alert') continue; - if (item.read_at || item.archived) continue; - showToastFor(item); + + const pending = (store.items || []) + .filter((i) => i.type === 'system_alert' && !i.read_at && !i.archived && !alertedIds.has(i.id)); + + if (pending.length === 0) return; + + // Marca os demais como já "alertados" nesta sessão pra não redisparar + // nos próximos ticks de polling/visibility — eles continuam no sininho. + const newest = pending[0]; // store.items já vem ordenado por created_at DESC + for (let i = 1; i < pending.length; i++) { + alertedIds.add(pending[i].id); + } + + if (pending.length > 1) { + const extra = pending.length - 1; + const suffix = ` • +${extra} outro${extra === 1 ? '' : 's'} alerta${extra === 1 ? '' : 's'} no sino`; + const patched = { + ...newest, + payload: { + ...(newest.payload || {}), + detail: `${newest.payload?.detail || ''}${suffix}` + } + }; + showToastFor(patched); + } else { + showToastFor(newest); } }