Replace servers with channels in chat functionality: refactored UI components, service logic, and message model to support channels (SERVER, DM, PARTY, GAC).
This commit is contained in:
@@ -9,8 +9,8 @@ export class NotificationService {
|
||||
this.getStoredNotificationSettings()
|
||||
);
|
||||
|
||||
public notify(server: string) {
|
||||
if (!this.isNotificationEnabled(server)) {
|
||||
public notify(channel: string) {
|
||||
if (!this.isNotificationEnabled(channel)) {
|
||||
return;
|
||||
}
|
||||
this.playSound();
|
||||
@@ -38,23 +38,23 @@ export class NotificationService {
|
||||
});
|
||||
}
|
||||
|
||||
public isNotificationEnabled(server: string): boolean {
|
||||
return this._notificationEnabled()[server];
|
||||
public isNotificationEnabled(channel: string): boolean {
|
||||
return this._notificationEnabled()[channel];
|
||||
}
|
||||
|
||||
public enableNotifications(server: string) {
|
||||
this.setNotificationEnabled(server, true);
|
||||
public enableNotifications(channel: string) {
|
||||
this.setNotificationEnabled(channel, true);
|
||||
this.enableSound()
|
||||
}
|
||||
|
||||
public disableNotifications(server: string) {
|
||||
this.setNotificationEnabled(server, false);
|
||||
public disableNotifications(channel: string) {
|
||||
this.setNotificationEnabled(channel, false);
|
||||
}
|
||||
|
||||
private setNotificationEnabled(server: string, enabled: boolean) {
|
||||
private setNotificationEnabled(channel: string, enabled: boolean) {
|
||||
const notificationSettings = {
|
||||
...this._notificationEnabled(),
|
||||
[server]: enabled
|
||||
[channel]: enabled
|
||||
};
|
||||
|
||||
this._notificationEnabled.set(notificationSettings);
|
||||
|
||||
@@ -4,7 +4,7 @@ import {EventSourcePolyfill} from 'event-source-polyfill';
|
||||
import {ChatMessage} from '@pages/altitude/chat/objects/chat-message.object';
|
||||
import {RawChatMessage} from '@pages/altitude/chat/objects/raw-chat-message.object';
|
||||
import {normalizeComponent} from '@pages/altitude/chat/mini-message/normalize.util';
|
||||
import {ChatServer} from '@pages/altitude/chat/objects/chat-server.object';
|
||||
import {ChatChannel} from '@pages/altitude/chat/objects/chat-channel.object';
|
||||
import {NotificationService} from '@pages/altitude/chat/service/chat-notification.service';
|
||||
|
||||
interface SsePayloadEvent {
|
||||
@@ -17,11 +17,18 @@ export class ChatService implements OnDestroy {
|
||||
private readonly notificationService: NotificationService = inject(NotificationService);
|
||||
private readonly authService: AuthService = inject(AuthService)
|
||||
private readonly _messages = signal<ChatMessage[]>([])
|
||||
public readonly messages = computed(() => this._messages().filter((message) => message.server === this._selectedServer()).sort((a, b) => b.timestamp - a.timestamp));
|
||||
private readonly _servers = signal<ChatServer[]>([])
|
||||
public readonly servers = computed(() => this._servers().sort((a, b) => a.server.localeCompare(b.server)));
|
||||
private readonly _selectedServer = signal<string>('');
|
||||
public readonly selectedServer = this._selectedServer.asReadonly()
|
||||
private readonly _channels = signal<ChatChannel[]>([])
|
||||
public readonly channels = computed(() => this._channels().sort((a, b) => a.name.localeCompare(b.name)));
|
||||
private readonly _selectedChannel = signal<ChatChannel | null>(null);
|
||||
public readonly selectedChannel = this._selectedChannel.asReadonly()
|
||||
|
||||
public readonly messages = computed(() => {
|
||||
const selected = this._selectedChannel();
|
||||
if (!selected) return [];
|
||||
return this._messages()
|
||||
.filter((message) => message.channelName === selected.name && message.channelType === selected.type)
|
||||
.sort((a, b) => b.timestamp - a.timestamp);
|
||||
});
|
||||
|
||||
connect() {
|
||||
if (this.eventSource) {
|
||||
@@ -50,14 +57,17 @@ export class ChatService implements OnDestroy {
|
||||
this.on(source, 'chat', (event) => {
|
||||
const chatMessages = this.processChatMessages(event);
|
||||
chatMessages.forEach((message) => {
|
||||
const find = this.servers().find(server => message.server === server.server && message.server !== this._selectedServer());
|
||||
const selected = this._selectedChannel();
|
||||
const isSelected = selected && selected.name === message.channelName && selected.type === message.channelType;
|
||||
|
||||
const find = this._channels().find(channel => message.channelName === channel.name && message.channelType === channel.type && !isSelected);
|
||||
if (find) {
|
||||
find.unreadMessages++;
|
||||
}
|
||||
})
|
||||
new Set(chatMessages.map(message => message.server))
|
||||
.forEach((server) => {
|
||||
this.notificationService.notify(server);
|
||||
new Set(chatMessages.map(message => `${message.channelType}:${message.channelName}`))
|
||||
.forEach((channelKeyStr) => {
|
||||
this.notificationService.notify(channelKeyStr);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,30 +78,56 @@ export class ChatService implements OnDestroy {
|
||||
|
||||
private processChatMessages(event: SsePayloadEvent): ChatMessage[] {
|
||||
const raw = JSON.parse(event.data) as RawChatMessage[];
|
||||
const messages: ChatMessage[] = raw.map((m) => ({
|
||||
...m,
|
||||
messageJson: normalizeComponent(JSON.parse(m.messageJson)),
|
||||
}));
|
||||
const messages: ChatMessage[] = raw.map((m) => {
|
||||
const message: ChatMessage = {
|
||||
...m,
|
||||
messageJson: normalizeComponent(JSON.parse(m.messageJson)),
|
||||
};
|
||||
const channelKey = this.getChannelKey(message);
|
||||
message.channelName = channelKey.name;
|
||||
message.channelType = channelKey.type;
|
||||
return message;
|
||||
});
|
||||
this._messages.update((old) => [...old, ...messages]);
|
||||
|
||||
//TODO [Stijn] [2026-07-19]: Handle servers by getting them from backend
|
||||
messages.map((message) => message.server).forEach((server) => {
|
||||
const found = this._servers().find(existing => existing.server === server);
|
||||
messages.forEach((message) => {
|
||||
const found = this._channels().find(existing => existing.name === message.channelName && existing.type === message.channelType);
|
||||
if (!found) {
|
||||
this._servers.update((old) => [...old, {server: server, unreadMessages: 0}]);
|
||||
this._channels.update((old) => [...old, {
|
||||
name: message.channelName!,
|
||||
type: message.channelType!,
|
||||
unreadMessages: 0
|
||||
}]);
|
||||
}
|
||||
})
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public selectServer(server: string) {
|
||||
this._selectedServer.set(server);
|
||||
this._servers.update((old) =>
|
||||
old.map((chatServer) =>
|
||||
chatServer.server === server
|
||||
? {...chatServer, unreadMessages: 0}
|
||||
: chatServer
|
||||
private getChannelKey(message: ChatMessage): { name: string, type: ChatChannel['type'] } {
|
||||
if (message.type === 'GAC') {
|
||||
return {name: 'Global Admin Chat', type: 'GAC'};
|
||||
}
|
||||
if (message.type === 'PARTY') {
|
||||
return {name: message.channel, type: 'PARTY'};
|
||||
}
|
||||
if (message.type === 'MSG') {
|
||||
const uuid = this.authService.getUuid();
|
||||
if (message.uuid === uuid) {
|
||||
return {name: message.receiver, type: 'DM'};
|
||||
}
|
||||
return {name: message.uuid, type: 'DM'};
|
||||
}
|
||||
return {name: message.server, type: 'SERVER'};
|
||||
}
|
||||
|
||||
public selectChannel(channel: ChatChannel) {
|
||||
this._selectedChannel.set(channel);
|
||||
this._channels.update((old) =>
|
||||
old.map((c) =>
|
||||
c.name === channel.name && c.type === channel.type
|
||||
? {...c, unreadMessages: 0}
|
||||
: c
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user