Introduce Angular Chat Component with SSE integration for real-time updates.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import {inject, Injectable, OnDestroy} from '@angular/core';
|
||||
import {Subject} from 'rxjs';
|
||||
import {AuthService} from '@services/auth.service';
|
||||
import {EventSourcePolyfill} from 'event-source-polyfill';
|
||||
|
||||
export interface ChatEvent {
|
||||
type: string;
|
||||
data: any;
|
||||
}
|
||||
|
||||
interface SsePayloadEvent {
|
||||
data: string;
|
||||
}
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class ChatService implements OnDestroy {
|
||||
private eventSource?: EventSourcePolyfill;
|
||||
private events$ = new Subject<ChatEvent>();
|
||||
private readonly authService: AuthService = inject(AuthService)
|
||||
|
||||
connect() {
|
||||
if (this.eventSource) {
|
||||
return; // already connected
|
||||
}
|
||||
|
||||
const jwt = this.authService.getJwt();
|
||||
if (!jwt) {
|
||||
//TODO [Stijn] [2026-07-18]: Error when no JWT available (log in?)
|
||||
return;
|
||||
}
|
||||
|
||||
const source = new EventSourcePolyfill('/api/chat/read/subscribe', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${jwt}`
|
||||
},
|
||||
heartbeatTimeout: 60000
|
||||
});
|
||||
|
||||
this.eventSource = source;
|
||||
|
||||
this.on(source, 'connected', (event) => {
|
||||
console.log('SSE connected:', event.data);
|
||||
});
|
||||
|
||||
this.on(source, 'chat-message', (event) => {
|
||||
this.events$.next({type: 'chat-message', data: JSON.parse(event.data)});
|
||||
});
|
||||
|
||||
source.onerror = (err) => {
|
||||
console.error('SSE error, polyfill will auto-reconnect:', err);
|
||||
};
|
||||
}
|
||||
|
||||
// single, deliberate escape hatch from the broken DOM/polyfill type overlap —
|
||||
// everything else in this file stays fully typed
|
||||
private on(source: EventSourcePolyfill, eventName: string, handler: (event: SsePayloadEvent) => void): void {
|
||||
(source as unknown as { addEventListener: (type: string, listener: (event: SsePayloadEvent) => void) => void })
|
||||
.addEventListener(eventName, handler);
|
||||
}
|
||||
|
||||
|
||||
onEvent() {
|
||||
return this.events$.asObservable();
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this.eventSource?.close();
|
||||
this.eventSource = undefined;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.disconnect();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user