feat: DM infrastructure overhaul + volume sliders + LiveKit dynamic URL

- Add DM edit/delete endpoints (REST + WebSocket)
- Add DM typing indicators with real-time broadcast
- Fix volume sliders to control LiveKit mic/speaker
- Fix Send Message button on user profile popout
- Add New DM modal with user search
- Fix message pagination (SQL cursor instead of in-memory)
- Guard optional attachments on DM messages
- Dynamic LiveKit URL from request Host header
- DM sidebar auto-sorts by most recent message
This commit is contained in:
Jannis Braun
2026-02-18 17:29:39 +01:00
parent 4f65ea9c86
commit 7168149d98
31 changed files with 1189 additions and 136 deletions
+17 -4
View File
@@ -114,12 +114,22 @@ export const useChatStore = create<ChatState>((set, get) => ({
},
editMessage: async (messageId: string, content: string) => {
await api.messages.update(messageId, { content });
const isDm = useUIStore.getState().showDms;
if (isDm) {
await api.dm.updateMessage(messageId, { content });
} else {
await api.messages.update(messageId, { content });
}
// Update will arrive via WebSocket
},
deleteMessage: async (messageId: string) => {
await api.messages.delete(messageId);
const isDm = useUIStore.getState().showDms;
if (isDm) {
await api.dm.deleteMessage(messageId);
} else {
await api.messages.delete(messageId);
}
// Deletion will arrive via WebSocket
},
@@ -135,12 +145,15 @@ export const useChatStore = create<ChatState>((set, get) => ({
},
updateMessage: (message: MessageWithUser) => {
// DM messages have dmChannelId instead of channelId — check both
const channelKey = message.channelId || (message as any).dmChannelId;
if (!channelKey) return;
set((state) => {
const newMessages = new Map(state.messages);
const current = newMessages.get(message.channelId);
const current = newMessages.get(channelKey);
if (!current) return state;
newMessages.set(
message.channelId,
channelKey,
current.map(m => m.id === message.id ? message : m),
);
return { messages: newMessages };