postmerge
This commit is contained in:
parent
8d0a6269e1
commit
b6134cc04a
17442
package-lock.json
generated
Normal file
17442
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,6 @@ import { MediaItem } from '../../../pages/types'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Icon } from '../../_shared/Icon'
|
||||||
import { Image } from '../../_shared/Image'
|
import { Image } from '../../_shared/Image'
|
||||||
import { CardTopic } from '../../Feed/CardTopic'
|
import { CardTopic } from '../../Feed/CardTopic'
|
||||||
import { Image } from '../../_shared/Image'
|
|
||||||
|
|
||||||
import styles from './AudioHeader.module.scss'
|
import styles from './AudioHeader.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { CommentDate } from '../CommentDate'
|
||||||
import { CommentRatingControl } from '../CommentRatingControl'
|
import { CommentRatingControl } from '../CommentRatingControl'
|
||||||
|
|
||||||
import styles from './Comment.module.scss'
|
import styles from './Comment.module.scss'
|
||||||
import { AuthorLink } from '../../Author/AhtorLink'
|
|
||||||
|
|
||||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
import type { Accessor, JSX } from 'solid-js'
|
import type { Accessor, JSX } from 'solid-js'
|
||||||
import { createContext, createSignal, onMount, useContext } from 'solid-js'
|
import { createContext, createEffect, createSignal, onMount, useContext } from 'solid-js'
|
||||||
import type { Chat, Message, MutationCreateMessageArgs } from '../graphql/types.gen'
|
import type { Chat, Message, MutationCreateMessageArgs } from '../graphql/types.gen'
|
||||||
import { inboxClient } from '../utils/apiClient'
|
import { inboxClient } from '../utils/apiClient'
|
||||||
import { loadMessages } from '../stores/inbox'
|
import { loadMessages } from '../stores/inbox'
|
||||||
import { MessageHandler, SSEMessage, useNotifications } from './notifications'
|
import { getToken } from '../graphql/privateGraphQLClient'
|
||||||
|
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||||
|
|
||||||
|
export interface SSEMessage {
|
||||||
|
id: string
|
||||||
|
entity: string
|
||||||
|
action: string
|
||||||
|
payload: any // Author | Shout | Reaction | Message
|
||||||
|
timestamp?: number
|
||||||
|
seen?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
type InboxContextType = {
|
type InboxContextType = {
|
||||||
chats: Accessor<Chat[]>
|
chats: Accessor<Chat[]>
|
||||||
|
@ -25,9 +35,6 @@ export function useInbox() {
|
||||||
export const InboxProvider = (props: { children: JSX.Element }) => {
|
export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
const [chats, setChats] = createSignal<Chat[]>([])
|
const [chats, setChats] = createSignal<Chat[]>([])
|
||||||
const [messages, setMessages] = createSignal<Message[]>([])
|
const [messages, setMessages] = createSignal<Message[]>([])
|
||||||
const {
|
|
||||||
actions: { setMessageHandler }
|
|
||||||
} = useNotifications()
|
|
||||||
|
|
||||||
const handleMessage = (sseMessage) => {
|
const handleMessage = (sseMessage) => {
|
||||||
console.log('[context.inbox]:', sseMessage)
|
console.log('[context.inbox]:', sseMessage)
|
||||||
|
@ -41,11 +48,34 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() =>
|
createEffect(async () => {
|
||||||
setMessageHandler((_h) => {
|
const token = getToken()
|
||||||
return handleMessage
|
if (token) {
|
||||||
})
|
await fetchEventSource('https://chat.discours.io/connect', {
|
||||||
)
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: token,
|
||||||
|
},
|
||||||
|
onmessage(event) {
|
||||||
|
const m: SSEMessage = JSON.parse(event.data)
|
||||||
|
console.log('[context.inbox] Received message:', m)
|
||||||
|
if (m.entity === 'chat' || m.entity == 'message') {
|
||||||
|
handleMessage(m)
|
||||||
|
} else {
|
||||||
|
console.debug(m)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onclose() {
|
||||||
|
console.log('[context.inbox] sse connection closed by server')
|
||||||
|
},
|
||||||
|
onerror(err) {
|
||||||
|
console.error('[context.inbox] sse connection closed by error', err)
|
||||||
|
throw new Error(err) // NOTE: simple hack to close the connection
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const loadChats = async () => {
|
const loadChats = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -73,7 +103,7 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
const currentChat = chats().find((chat) => chat.id === args.chat_id)
|
const currentChat = chats().find((chat) => chat.id === args.chat_id)
|
||||||
setChats((prev) => [
|
setChats((prev) => [
|
||||||
...prev.filter((c) => c.id !== currentChat.id),
|
...prev.filter((c) => c.id !== currentChat.id),
|
||||||
{ ...currentChat, updatedAt: message.createdAt }
|
{ ...currentChat, updatedAt: message.createdAt },
|
||||||
])
|
])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending message:', error)
|
console.error('Error sending message:', error)
|
||||||
|
@ -94,7 +124,7 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
createChat,
|
createChat,
|
||||||
loadChats,
|
loadChats,
|
||||||
getMessages,
|
getMessages,
|
||||||
sendMessage
|
sendMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
const value: InboxContextType = { chats, messages, actions }
|
const value: InboxContextType = { chats, messages, actions }
|
||||||
|
|
|
@ -12,27 +12,9 @@ import { apiBaseUrl } from '../utils/config'
|
||||||
import SSEService, { EventData } from '../utils/sseService'
|
import SSEService, { EventData } from '../utils/sseService'
|
||||||
|
|
||||||
import { useSession } from './session'
|
import { useSession } from './session'
|
||||||
import { Portal } from 'solid-js/web'
|
|
||||||
import { ShowIfAuthenticated } from '../components/_shared/ShowIfAuthenticated'
|
|
||||||
import { IDBPDatabase, openDB } from 'idb'
|
|
||||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|
||||||
import { getToken } from '../graphql/privateGraphQLClient'
|
|
||||||
import { Author, Message, Reaction, Shout } from '../graphql/types.gen'
|
|
||||||
|
|
||||||
export const PAGE_SIZE = 20
|
|
||||||
export interface SSEMessage {
|
|
||||||
id: string
|
|
||||||
entity: string
|
|
||||||
action: string
|
|
||||||
payload: any // Author | Shout | Reaction | Message
|
|
||||||
timestamp?: number
|
|
||||||
seen?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MessageHandler = (m: SSEMessage) => void
|
|
||||||
|
|
||||||
type NotificationsContextType = {
|
type NotificationsContextType = {
|
||||||
notificationEntities: Record<number, SSEMessage>
|
notificationEntities: Record<number, Notification>
|
||||||
unreadNotificationsCount: Accessor<number>
|
unreadNotificationsCount: Accessor<number>
|
||||||
sortedNotifications: Accessor<Notification[]>
|
sortedNotifications: Accessor<Notification[]>
|
||||||
loadedNotificationsCount: Accessor<number>
|
loadedNotificationsCount: Accessor<number>
|
||||||
|
@ -43,7 +25,6 @@ type NotificationsContextType = {
|
||||||
markNotificationAsRead: (notification: Notification) => Promise<void>
|
markNotificationAsRead: (notification: Notification) => Promise<void>
|
||||||
markAllNotificationsAsRead: () => Promise<void>
|
markAllNotificationsAsRead: () => Promise<void>
|
||||||
loadNotifications: (options: { limit: number; offset: number }) => Promise<Notification[]>
|
loadNotifications: (options: { limit: number; offset: number }) => Promise<Notification[]>
|
||||||
setMessageHandler: (h: MessageHandler) => void
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,17 +42,7 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
||||||
const [unreadNotificationsCount, setUnreadNotificationsCount] = createSignal(0)
|
const [unreadNotificationsCount, setUnreadNotificationsCount] = createSignal(0)
|
||||||
const [totalNotificationsCount, setTotalNotificationsCount] = createSignal(0)
|
const [totalNotificationsCount, setTotalNotificationsCount] = createSignal(0)
|
||||||
const { isAuthenticated, user } = useSession()
|
const { isAuthenticated, user } = useSession()
|
||||||
const [notificationEntities, setNotificationEntities] = createStore<Record<number, SSEMessage>>({})
|
const [notificationEntities, setNotificationEntities] = createStore<Record<number, Notification>>({})
|
||||||
const [db, setDb] = createSignal<Promise<IDBPDatabase<unknown>>>()
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
const dbx = openDB('notifications-db', 1, {
|
|
||||||
upgrade(indexedDb) {
|
|
||||||
indexedDb.createObjectStore('notifications')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
setDb(dbx)
|
|
||||||
})
|
|
||||||
|
|
||||||
const loadNotifications = async (options: { limit: number; offset?: number }) => {
|
const loadNotifications = async (options: { limit: number; offset?: number }) => {
|
||||||
const { notifications, totalUnreadCount, totalCount } = await apiClient.getNotifications(options)
|
const { notifications, totalUnreadCount, totalCount } = await apiClient.getNotifications(options)
|
||||||
|
@ -82,34 +53,17 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
setTotalNotificationsCount(totalCount)
|
setTotalNotificationsCount(totalCount)
|
||||||
setUnreadNotificationsCount(totalUnreadCount)
|
setUnreadNotificationsCount(totalUnreadCount)
|
||||||
setNotificationEntities(
|
setNotificationEntities(newNotificationEntities)
|
||||||
notifications.reduce((acc, notification) => {
|
|
||||||
acc[notification.id] = notification
|
|
||||||
return acc
|
|
||||||
}, {}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return notifications
|
return notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedNotifications = createMemo(() => {
|
const sortedNotifications = createMemo(() => {
|
||||||
return Object.values(notificationEntities).sort((a, b) => b.timestamp - a.timestamp)
|
return Object.values(notificationEntities).sort(
|
||||||
|
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const storeNotification = async (notification: SSEMessage) => {
|
|
||||||
console.log('[context.notifications] Storing notification:', notification)
|
|
||||||
|
|
||||||
const storage = await db()
|
|
||||||
const tx = storage.transaction('notifications', 'readwrite')
|
|
||||||
const store = tx.objectStore('notifications')
|
|
||||||
|
|
||||||
await store.put(notification, 'id')
|
|
||||||
await tx.done
|
|
||||||
loadNotifications()
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadedNotificationsCount = createMemo(() => Object.keys(notificationEntities).length)
|
const loadedNotificationsCount = createMemo(() => Object.keys(notificationEntities).length)
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (isAuthenticated()) {
|
if (isAuthenticated()) {
|
||||||
sseService.connect(`${apiBaseUrl}/subscribe/${user().id}`)
|
sseService.connect(`${apiBaseUrl}/subscribe/${user().id}`)
|
||||||
|
@ -124,42 +78,6 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
||||||
sseService.disconnect()
|
sseService.disconnect()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const [messageHandler, setMessageHandler] = createSignal<MessageHandler>(console.warn)
|
|
||||||
|
|
||||||
createEffect(async () => {
|
|
||||||
if (isAuthenticated()) {
|
|
||||||
loadNotifications()
|
|
||||||
|
|
||||||
await fetchEventSource('https://chat.discours.io/connect', {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: getToken(),
|
|
||||||
},
|
|
||||||
onmessage(event) {
|
|
||||||
const m: SSEMessage = JSON.parse(event.data)
|
|
||||||
console.log('[context.notifications] Received message:', m)
|
|
||||||
if (m.entity === 'chat' || m.entity == 'message') {
|
|
||||||
messageHandler()(m)
|
|
||||||
} else {
|
|
||||||
storeNotification({
|
|
||||||
...m,
|
|
||||||
id: event.id,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
seen: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onclose() {
|
|
||||||
console.log('[context.notifications] sse connection closed by server')
|
|
||||||
},
|
|
||||||
onerror(err) {
|
|
||||||
console.error('[context.notifications] sse connection closed by error', err)
|
|
||||||
throw new Error(err) // NOTE: simple hack to close the connection
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const markNotificationAsRead = async (notification: Notification) => {
|
const markNotificationAsRead = async (notification: Notification) => {
|
||||||
await apiClient.markNotificationAsRead(notification.id)
|
await apiClient.markNotificationAsRead(notification.id)
|
||||||
|
@ -180,7 +98,6 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setMessageHandler,
|
|
||||||
showNotificationsPanel,
|
showNotificationsPanel,
|
||||||
hideNotificationsPanel,
|
hideNotificationsPanel,
|
||||||
markNotificationAsRead,
|
markNotificationAsRead,
|
||||||
|
|
|
@ -115,7 +115,7 @@ main {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.scrollToNew {
|
.scrollToNew {
|
||||||
osition: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
bottom: 8px;
|
bottom: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -28,12 +28,11 @@ import type {
|
||||||
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
||||||
import { getToken, privateGraphQLClient, privateInboxGraphQLClient } from '../graphql/privateGraphQLClient'
|
import { getToken, privateGraphQLClient, privateInboxGraphQLClient } from '../graphql/privateGraphQLClient'
|
||||||
import topicsAll from '../graphql/query/topics-all'
|
import topicsAll from '../graphql/query/topics-all'
|
||||||
import mySession from '../graphql/mutation/my-session'
|
import topicsRandomQuery from '../graphql/query/topics-random'
|
||||||
import authLogoutQuery from '../graphql/mutation/auth-logout'
|
import authLogoutQuery from '../graphql/mutation/auth-logout'
|
||||||
import authRegisterMutation from '../graphql/mutation/auth-register'
|
import authRegisterMutation from '../graphql/mutation/auth-register'
|
||||||
import authSendLinkMutation from '../graphql/mutation/auth-send-link'
|
import authSendLinkMutation from '../graphql/mutation/auth-send-link'
|
||||||
import createChat from '../graphql/mutation/create-chat'
|
import authConfirmEmailMutation from '../graphql/mutation/auth-confirm-email'
|
||||||
import createMessage from '../graphql/mutation/create-chat-message'
|
|
||||||
import followMutation from '../graphql/mutation/follow'
|
import followMutation from '../graphql/mutation/follow'
|
||||||
import markAllNotificationsAsRead from '../graphql/mutation/mark-all-notifications-as-read'
|
import markAllNotificationsAsRead from '../graphql/mutation/mark-all-notifications-as-read'
|
||||||
import markNotificationAsRead from '../graphql/mutation/mark-notification-as-read'
|
import markNotificationAsRead from '../graphql/mutation/mark-notification-as-read'
|
||||||
|
@ -43,8 +42,6 @@ import reactionDestroy from '../graphql/mutation/reaction-destroy'
|
||||||
import reactionUpdate from '../graphql/mutation/reaction-update'
|
import reactionUpdate from '../graphql/mutation/reaction-update'
|
||||||
import unfollowMutation from '../graphql/mutation/unfollow'
|
import unfollowMutation from '../graphql/mutation/unfollow'
|
||||||
import updateProfile from '../graphql/mutation/update-profile'
|
import updateProfile from '../graphql/mutation/update-profile'
|
||||||
import { getToken, privateGraphQLClient } from '../graphql/privateGraphQLClient'
|
|
||||||
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
|
||||||
import shoutLoad from '../graphql/query/article-load'
|
import shoutLoad from '../graphql/query/article-load'
|
||||||
import shoutsLoadBy from '../graphql/query/articles-load-by'
|
import shoutsLoadBy from '../graphql/query/articles-load-by'
|
||||||
import authCheckEmailQuery from '../graphql/query/auth-check-email'
|
import authCheckEmailQuery from '../graphql/query/auth-check-email'
|
||||||
|
@ -58,17 +55,15 @@ import topicBySlug from '../graphql/query/topic-by-slug'
|
||||||
import reactionsLoadBy from '../graphql/query/reactions-load-by'
|
import reactionsLoadBy from '../graphql/query/reactions-load-by'
|
||||||
import authorsLoadBy from '../graphql/query/authors-load-by'
|
import authorsLoadBy from '../graphql/query/authors-load-by'
|
||||||
import chatMessagesLoadBy from '../graphql/query/chat-messages-load-by'
|
import chatMessagesLoadBy from '../graphql/query/chat-messages-load-by'
|
||||||
import loadRecipients from '../graphql/query/chat-recipients'
|
|
||||||
import myChats from '../graphql/query/chats-load'
|
import myChats from '../graphql/query/chats-load'
|
||||||
import draftsLoad from '../graphql/query/drafts-load'
|
import draftsLoad from '../graphql/query/drafts-load'
|
||||||
import myFeed from '../graphql/query/my-feed'
|
import myFeed from '../graphql/query/my-feed'
|
||||||
import loadRecipients from '../graphql/query/chat-recipients'
|
import loadRecipients from '../graphql/query/chat-recipients'
|
||||||
import updateProfile from '../graphql/mutation/update-profile'
|
import createArticle from '../graphql/mutation/article-create'
|
||||||
import updateArticle from '../graphql/mutation/article-update'
|
import updateArticle from '../graphql/mutation/article-update'
|
||||||
import deleteShout from '../graphql/mutation/article-delete'
|
import deleteShout from '../graphql/mutation/article-delete'
|
||||||
// import notifications from '../graphql/query/notifications'
|
import notifications from '../graphql/query/notifications'
|
||||||
// import markNotificationAsRead from '../graphql/mutation/mark-notification-as-read'
|
|
||||||
import markAllNotificationsAsRead from '../graphql/mutation/mark-all-notifications-as-read'
|
|
||||||
import markAsRead from '../graphql/mutation/chat-mark-as-read'
|
import markAsRead from '../graphql/mutation/chat-mark-as-read'
|
||||||
import createChat from '../graphql/mutation/chat-create'
|
import createChat from '../graphql/mutation/chat-create'
|
||||||
import updateChat from '../graphql/mutation/chat-update'
|
import updateChat from '../graphql/mutation/chat-update'
|
||||||
|
@ -371,8 +366,7 @@ export const apiClient = {
|
||||||
.toPromise()
|
.toPromise()
|
||||||
return resp.data.loadReactionsBy
|
return resp.data.loadReactionsBy
|
||||||
},
|
},
|
||||||
// TODO: store notifications in browser storage
|
|
||||||
/*
|
|
||||||
getNotifications: async (params: NotificationsQueryParams): Promise<NotificationsQueryResult> => {
|
getNotifications: async (params: NotificationsQueryParams): Promise<NotificationsQueryResult> => {
|
||||||
const resp = await privateGraphQLClient.query(notifications, { params }).toPromise()
|
const resp = await privateGraphQLClient.query(notifications, { params }).toPromise()
|
||||||
return resp.data.loadNotifications
|
return resp.data.loadNotifications
|
||||||
|
@ -384,10 +378,6 @@ export const apiClient = {
|
||||||
})
|
})
|
||||||
.toPromise()
|
.toPromise()
|
||||||
},
|
},
|
||||||
*/
|
|
||||||
markAllNotificationsAsRead: async (): Promise<void> => {
|
|
||||||
await privateGraphQLClient.mutation(markAllNotificationsAsRead, {}).toPromise()
|
|
||||||
},
|
|
||||||
|
|
||||||
markAllNotificationsAsRead: async (): Promise<void> => {
|
markAllNotificationsAsRead: async (): Promise<void> => {
|
||||||
await privateGraphQLClient.mutation(markAllNotificationsAsRead, {}).toPromise()
|
await privateGraphQLClient.mutation(markAllNotificationsAsRead, {}).toPromise()
|
||||||
|
|
|
@ -7,7 +7,4 @@ export const apiBaseUrl = 'https://v2.discours.io'
|
||||||
const defaultThumborUrl = 'https://images.discours.io'
|
const defaultThumborUrl = 'https://images.discours.io'
|
||||||
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl
|
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl
|
||||||
|
|
||||||
const defaultThumborUrl = 'https://images.discours.io'
|
|
||||||
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl
|
|
||||||
|
|
||||||
export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || ''
|
export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || ''
|
||||||
|
|
33
src/utils/sseService.ts
Normal file
33
src/utils/sseService.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
export type EventData = {
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class SSEService {
|
||||||
|
private eventSource: EventSource | null
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.eventSource = null
|
||||||
|
}
|
||||||
|
|
||||||
|
public connect(url: string): void {
|
||||||
|
this.eventSource = new EventSource(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnect(): void {
|
||||||
|
if (this.eventSource) {
|
||||||
|
this.eventSource.close()
|
||||||
|
this.eventSource = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscribeToEvent(eventName: string, callback: (eventData: EventData) => void): void {
|
||||||
|
if (this.eventSource) {
|
||||||
|
this.eventSource.addEventListener(eventName, (event: MessageEvent) => {
|
||||||
|
const data = JSON.parse(event.data)
|
||||||
|
callback(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SSEService
|
Loading…
Reference in New Issue
Block a user