SocialEventHandlers.ts raw
1 import {
2 UserFollowed,
3 UserUnfollowed,
4 UserMuted,
5 UserUnmuted,
6 MuteVisibilityChanged,
7 FollowListPublished,
8 MuteListPublished
9 } from '@/domain/social/events'
10 import { EventHandler, eventDispatcher } from '@/domain/shared'
11
12 /**
13 * Handlers for social domain events
14 *
15 * These handlers coordinate cross-context updates when social events occur.
16 * They bridge the Social context with Feed, Notification, and Cache contexts.
17 */
18
19 /**
20 * Callback type for feed refresh requests
21 */
22 export type FeedRefreshCallback = () => void
23
24 /**
25 * Callback type for content refiltering requests
26 */
27 export type RefilterCallback = () => void
28
29 /**
30 * Callback type for profile prefetch requests
31 */
32 export type PrefetchProfileCallback = (pubkey: string) => void
33
34 /**
35 * Service callbacks that can be injected for cross-context coordination
36 */
37 export interface SocialHandlerCallbacks {
38 onFeedRefreshNeeded?: FeedRefreshCallback
39 onRefilterNeeded?: RefilterCallback
40 onPrefetchProfile?: PrefetchProfileCallback
41 }
42
43 let callbacks: SocialHandlerCallbacks = {}
44
45 /**
46 * Set the callbacks for cross-context coordination
47 * Call this during provider initialization
48 */
49 export function setSocialHandlerCallbacks(newCallbacks: SocialHandlerCallbacks): void {
50 callbacks = { ...callbacks, ...newCallbacks }
51 }
52
53 /**
54 * Clear all callbacks (for cleanup/testing)
55 */
56 export function clearSocialHandlerCallbacks(): void {
57 callbacks = {}
58 }
59
60 /**
61 * Handler for user followed events
62 * Coordinates with:
63 * - Feed context: Add followed user's content to timeline
64 * - Cache context: Prefetch followed user's profile and notes
65 */
66 export const handleUserFollowed: EventHandler<UserFollowed> = async (event) => {
67 console.debug('[SocialEventHandler] User followed:', {
68 actor: event.actor.formatted,
69 followed: event.followed.formatted,
70 petname: event.petname
71 })
72
73 // Prefetch the followed user's profile for better UX
74 if (callbacks.onPrefetchProfile) {
75 callbacks.onPrefetchProfile(event.followed.hex)
76 }
77 }
78
79 /**
80 * Handler for user unfollowed events
81 * Can be used to:
82 * - Update feed context to exclude unfollowed user's content
83 * - Clean up cached data for unfollowed user
84 */
85 export const handleUserUnfollowed: EventHandler<UserUnfollowed> = async (event) => {
86 console.debug('[SocialEventHandler] User unfollowed:', {
87 actor: event.actor.formatted,
88 unfollowed: event.unfollowed.formatted
89 })
90
91 // Future: Dispatch to feed context to update content sources
92 }
93
94 /**
95 * Handler for user muted events
96 * Coordinates with:
97 * - Feed context: Refilter timeline to hide muted user's content
98 * - Notification context: Filter notifications from muted user
99 * - DM context: Update DM filtering
100 */
101 export const handleUserMuted: EventHandler<UserMuted> = async (event) => {
102 console.debug('[SocialEventHandler] User muted:', {
103 actor: event.actor.formatted,
104 muted: event.muted.formatted,
105 visibility: event.visibility
106 })
107
108 // Trigger immediate refiltering of current timeline
109 if (callbacks.onRefilterNeeded) {
110 callbacks.onRefilterNeeded()
111 }
112 }
113
114 /**
115 * Handler for user unmuted events
116 * Coordinates with:
117 * - Feed context: Refilter timeline to show unmuted user's content
118 * - Notification context: Restore notifications from unmuted user
119 */
120 export const handleUserUnmuted: EventHandler<UserUnmuted> = async (event) => {
121 console.debug('[SocialEventHandler] User unmuted:', {
122 actor: event.actor.formatted,
123 unmuted: event.unmuted.formatted
124 })
125
126 // Trigger refiltering to restore unmuted user's content
127 if (callbacks.onRefilterNeeded) {
128 callbacks.onRefilterNeeded()
129 }
130 }
131
132 /**
133 * Handler for mute visibility changed events
134 */
135 export const handleMuteVisibilityChanged: EventHandler<MuteVisibilityChanged> = async (event) => {
136 console.debug('[SocialEventHandler] Mute visibility changed:', {
137 actor: event.actor.formatted,
138 target: event.target.formatted,
139 from: event.from,
140 to: event.to
141 })
142 }
143
144 /**
145 * Handler for follow list published events
146 * Coordinates with:
147 * - Feed context: Refresh following feed with new list
148 * - Cache context: Invalidate author caches
149 */
150 export const handleFollowListPublished: EventHandler<FollowListPublished> = async (event) => {
151 console.debug('[SocialEventHandler] Follow list published:', {
152 owner: event.owner.formatted,
153 followingCount: event.followingCount
154 })
155
156 // Trigger feed refresh to reflect new following list
157 if (callbacks.onFeedRefreshNeeded) {
158 callbacks.onFeedRefreshNeeded()
159 }
160 }
161
162 /**
163 * Handler for mute list published events
164 * Coordinates with:
165 * - Feed context: Refilter timeline with new mute list
166 * - Notification context: Update notification filtering
167 */
168 export const handleMuteListPublished: EventHandler<MuteListPublished> = async (event) => {
169 console.debug('[SocialEventHandler] Mute list published:', {
170 owner: event.owner.formatted,
171 publicMuteCount: event.publicMuteCount,
172 privateMuteCount: event.privateMuteCount
173 })
174
175 // Trigger refiltering with updated mute list
176 if (callbacks.onRefilterNeeded) {
177 callbacks.onRefilterNeeded()
178 }
179 }
180
181 /**
182 * Register all social event handlers with the event dispatcher
183 */
184 export function registerSocialEventHandlers(): void {
185 eventDispatcher.on('social.user_followed', handleUserFollowed)
186 eventDispatcher.on('social.user_unfollowed', handleUserUnfollowed)
187 eventDispatcher.on('social.user_muted', handleUserMuted)
188 eventDispatcher.on('social.user_unmuted', handleUserUnmuted)
189 eventDispatcher.on('social.mute_visibility_changed', handleMuteVisibilityChanged)
190 eventDispatcher.on('social.follow_list_published', handleFollowListPublished)
191 eventDispatcher.on('social.mute_list_published', handleMuteListPublished)
192 }
193
194 /**
195 * Unregister all social event handlers
196 */
197 export function unregisterSocialEventHandlers(): void {
198 eventDispatcher.off('social.user_followed', handleUserFollowed)
199 eventDispatcher.off('social.user_unfollowed', handleUserUnfollowed)
200 eventDispatcher.off('social.user_muted', handleUserMuted)
201 eventDispatcher.off('social.user_unmuted', handleUserUnmuted)
202 eventDispatcher.off('social.mute_visibility_changed', handleMuteVisibilityChanged)
203 eventDispatcher.off('social.follow_list_published', handleFollowListPublished)
204 eventDispatcher.off('social.mute_list_published', handleMuteListPublished)
205 }
206