FeedEventHandlers.ts raw

   1  import {
   2    FeedSwitched,
   3    ContentFilterUpdated,
   4    FeedRefreshed,
   5    NoteCreated,
   6    NoteDeleted,
   7    NoteReplied,
   8    UsersMentioned,
   9    TimelineEventsReceived,
  10    TimelineEOSED
  11  } from '@/domain/feed/events'
  12  import { EventHandler, eventDispatcher } from '@/domain/shared'
  13  
  14  /**
  15   * Handlers for Feed domain events
  16   *
  17   * These handlers coordinate cross-context updates when feed events occur.
  18   * They enable coordination between Feed, Social, Content, and UI contexts.
  19   */
  20  
  21  /**
  22   * Handler for feed switched events
  23   * Can be used to:
  24   * - Clear timeline caches for the old feed
  25   * - Prefetch content for the new feed
  26   * - Update URL/navigation state
  27   * - Log analytics
  28   */
  29  export const handleFeedSwitched: EventHandler<FeedSwitched> = async (event) => {
  30    console.debug('[FeedEventHandler] Feed switched:', {
  31      owner: event.owner?.formatted,
  32      fromType: event.fromType?.value ?? 'none',
  33      toType: event.toType.value,
  34      relaySetId: event.relaySetId
  35    })
  36  
  37    // Future: Clear old timeline cache
  38    // Future: Trigger new timeline fetch
  39    // Future: Update analytics
  40  }
  41  
  42  /**
  43   * Handler for content filter updated events
  44   * Can be used to:
  45   * - Re-filter current timeline with new settings
  46   * - Persist filter preferences
  47   * - Update filter indicators in UI
  48   */
  49  export const handleContentFilterUpdated: EventHandler<ContentFilterUpdated> = async (event) => {
  50    console.debug('[FeedEventHandler] Content filter updated:', {
  51      owner: event.owner.formatted,
  52      hideRepliesChanged: event.previousFilter.hideReplies !== event.newFilter.hideReplies,
  53      hideRepostsChanged: event.previousFilter.hideReposts !== event.newFilter.hideReposts,
  54      nsfwPolicyChanged: event.previousFilter.nsfwPolicy !== event.newFilter.nsfwPolicy
  55    })
  56  
  57    // Future: Trigger timeline re-filter
  58    // Future: Persist filter preferences
  59  }
  60  
  61  /**
  62   * Handler for feed refreshed events
  63   * Can be used to:
  64   * - Update last refresh timestamp display
  65   * - Trigger background data fetch
  66   * - Reset scroll position indicators
  67   */
  68  export const handleFeedRefreshed: EventHandler<FeedRefreshed> = async (event) => {
  69    console.debug('[FeedEventHandler] Feed refreshed:', {
  70      owner: event.owner?.formatted,
  71      feedType: event.feedType.value
  72    })
  73  
  74    // Future: Update refresh timestamp in UI
  75    // Future: Trigger stale data cleanup
  76  }
  77  
  78  /**
  79   * Handler for note created events
  80   * Can be used to:
  81   * - Add note to local timeline immediately (optimistic UI)
  82   * - Create notifications for mentioned users
  83   * - Update post count displays
  84   */
  85  export const handleNoteCreated: EventHandler<NoteCreated> = async (event) => {
  86    console.debug('[FeedEventHandler] Note created:', {
  87      author: event.author.formatted,
  88      noteId: event.noteId.hex,
  89      mentionCount: event.mentions.length,
  90      isReply: event.isReply,
  91      isQuote: event.isQuote
  92    })
  93  
  94    // Future: Add to local timeline if author is self
  95    // Future: Create mention notifications
  96  }
  97  
  98  /**
  99   * Handler for note deleted events
 100   * Can be used to:
 101   * - Remove note from all timelines
 102   * - Update reply counts on parent notes
 103   * - Clean up cached data
 104   */
 105  export const handleNoteDeleted: EventHandler<NoteDeleted> = async (event) => {
 106    console.debug('[FeedEventHandler] Note deleted:', {
 107      author: event.author.formatted,
 108      noteId: event.noteId.hex
 109    })
 110  
 111    // Future: Remove from timeline display
 112    // Future: Remove from caches
 113  }
 114  
 115  /**
 116   * Handler for note replied events
 117   * Can be used to:
 118   * - Increment reply count on parent note
 119   * - Create notification for parent note author
 120   * - Update thread view if open
 121   */
 122  export const handleNoteReplied: EventHandler<NoteReplied> = async (event) => {
 123    console.debug('[FeedEventHandler] Note replied:', {
 124      replier: event.replier.formatted,
 125      replyNoteId: event.replyNoteId.hex,
 126      originalNoteId: event.originalNoteId.hex,
 127      originalAuthor: event.originalAuthor.formatted
 128    })
 129  
 130    // Future: Increment reply count
 131    // Future: Create reply notification for parent author
 132    // Future: Update thread view
 133  }
 134  
 135  /**
 136   * Handler for users mentioned events
 137   * Can be used to:
 138   * - Create mention notifications for each mentioned user
 139   * - Highlight mentions in the source note
 140   */
 141  export const handleUsersMentioned: EventHandler<UsersMentioned> = async (event) => {
 142    console.debug('[FeedEventHandler] Users mentioned:', {
 143      author: event.author.formatted,
 144      noteId: event.noteId.hex,
 145      mentionedCount: event.mentionedPubkeys.length
 146    })
 147  
 148    // Future: Create mention notifications
 149  }
 150  
 151  /**
 152   * Handler for timeline events received
 153   * Can be used to:
 154   * - Update event cache
 155   * - Trigger profile/metadata fetches for new authors
 156   * - Update unread counts
 157   */
 158  export const handleTimelineEventsReceived: EventHandler<TimelineEventsReceived> = async (event) => {
 159    console.debug('[FeedEventHandler] Timeline events received:', {
 160      feedType: event.feedType.value,
 161      eventCount: event.eventCount,
 162      newestTimestamp: event.newestTimestamp.unix,
 163      isHistorical: event.isHistorical
 164    })
 165  
 166    // Future: Prefetch profiles for new authors
 167    // Future: Update new post indicators
 168  }
 169  
 170  /**
 171   * Handler for timeline EOSE (end of stored events)
 172   * Can be used to:
 173   * - Mark initial load as complete
 174   * - Switch from loading to live mode
 175   * - Update loading indicators
 176   */
 177  export const handleTimelineEOSED: EventHandler<TimelineEOSED> = async (event) => {
 178    console.debug('[FeedEventHandler] Timeline EOSE:', {
 179      feedType: event.feedType.value,
 180      totalEvents: event.totalEvents
 181    })
 182  
 183    // Future: Update loading state
 184    // Future: Show "up to date" indicator
 185  }
 186  
 187  /**
 188   * Register all feed event handlers with the event dispatcher
 189   */
 190  export function registerFeedEventHandlers(): void {
 191    eventDispatcher.on('feed.switched', handleFeedSwitched)
 192    eventDispatcher.on('feed.content_filter_updated', handleContentFilterUpdated)
 193    eventDispatcher.on('feed.refreshed', handleFeedRefreshed)
 194    eventDispatcher.on('feed.note_created', handleNoteCreated)
 195    eventDispatcher.on('feed.note_deleted', handleNoteDeleted)
 196    eventDispatcher.on('feed.note_replied', handleNoteReplied)
 197    eventDispatcher.on('feed.users_mentioned', handleUsersMentioned)
 198    eventDispatcher.on('feed.timeline_events_received', handleTimelineEventsReceived)
 199    eventDispatcher.on('feed.timeline_eosed', handleTimelineEOSED)
 200  }
 201  
 202  /**
 203   * Unregister all feed event handlers
 204   */
 205  export function unregisterFeedEventHandlers(): void {
 206    eventDispatcher.off('feed.switched', handleFeedSwitched)
 207    eventDispatcher.off('feed.content_filter_updated', handleContentFilterUpdated)
 208    eventDispatcher.off('feed.refreshed', handleFeedRefreshed)
 209    eventDispatcher.off('feed.note_created', handleNoteCreated)
 210    eventDispatcher.off('feed.note_deleted', handleNoteDeleted)
 211    eventDispatcher.off('feed.note_replied', handleNoteReplied)
 212    eventDispatcher.off('feed.users_mentioned', handleUsersMentioned)
 213    eventDispatcher.off('feed.timeline_events_received', handleTimelineEventsReceived)
 214    eventDispatcher.off('feed.timeline_eosed', handleTimelineEOSED)
 215  }
 216