Class: CrmNavbarBroadcaster
- Inherits:
-
Object
- Object
- CrmNavbarBroadcaster
- Defined in:
- app/services/crm_navbar_broadcaster.rb
Overview
Broadcasts a refreshed navbar fragment (a single badge or the user's
presence dot) to one user's personal notification stream.
All fragments are user-specific: the SMS badge for user A reflects A's
watch list, not B's. We therefore broadcast to the per-user channel
notifications:#{user.id} (already subscribed by the CRM layout).
To eliminate wasted renders, every broadcast first checks
CrmNavbarLiveUsers.live? — if the user isn't currently sitting on a CRM
page, no template render or Redis publish happens.
This class only does the render + publish. Coalescing (collapsing bursts
of broadcast requests for the same user/badge into one) is the worker's
job; see CrmNavbarRefreshWorker.
Constant Summary collapse
- BADGES =
Each badge declares the partial that renders just its fragment and the
DOM id the broadcast targets. Adding a new live navbar element is a
matter of adding a row here and creating the partial.attributes:is an optional hash passed through to the rendered
<turbo-stream>tag. Use it to opt a fragment into Turbo 8's morph
behavior (method: :morph) when node identity must be preserved
because something else (Bootstrap component, Stimulus value cache,
focus state, ...) holds a reference to it. { # Unified counter for the navbar's Communications offcanvas (sms + # voicemail + email). Replaced the per-channel :sms/:voicemail/:email # entries when those three dropdowns were merged into one panel; the # CrmNavbarFanoutWorker translates incoming sms/voicemail/email events # to this badge so writes still trigger a live refresh. communications: { partial: 'menus/crm_nav_communications_badge', target: 'crm-nav-communications-badge' }, pinned: { partial: 'menus/crm_nav_pinned_badge', target: 'crm-nav-pinned-badge' }, # `method: :morph` so the broadcast updates the existing # `#my-presence-info` button's attributes/children in place instead of # swapping the node out. The button is a Bootstrap Dropdown toggle and # Bootstrap caches its menu reference on the toggle node on first # construction; a node-level replace mid-transition leaves the cached # instance pointing at a detached element and the next click no-ops # until the user clicks again. Morph keeps the toggle node — and # therefore the cached Dropdown instance — alive. presence_dot: { partial: 'menus/crm_nav_presence_dot', target: 'my-presence-info', attributes: { method: :morph } } }.freeze
Class Method Summary collapse
Class Method Details
.refresh(user, badge:) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/services/crm_navbar_broadcaster.rb', line 47 def refresh(user, badge:) cfg = BADGES.fetch(badge.to_sym) return false unless CrmNavbarLiveUsers.live?(user.id) Turbo::StreamsChannel.broadcast_replace_to( stream_name_for(user), target: cfg[:target], partial: cfg[:partial], locals: { user: user }, attributes: cfg.fetch(:attributes, {}) ) true end |
.stream_name_for(user) ⇒ Object
61 62 63 |
# File 'app/services/crm_navbar_broadcaster.rb', line 61 def stream_name_for(user) "notifications:#{user.id}" end |