Chat fixes

This commit is contained in:
Kalle 2026-03-11 20:59:41 +02:00
parent b063b9300a
commit d884cb3f3b
5 changed files with 70 additions and 28 deletions

View File

@ -4,7 +4,11 @@ import * as React from "react";
import { useMatches, useRevalidator } from "react-router";
import { logger } from "~/utils/logger";
import { soundPath } from "~/utils/urls";
import type { RoomInfo, ServerRoomInfo } from "./chat-provider-types";
import type {
RoomInfo,
RoomMetadata,
ServerRoomInfo,
} from "./chat-provider-types";
import type { ChatMessage, ChatUser } from "./chat-types";
import { messageTypeToSound, soundEnabled, soundVolume } from "./chat-utils";
import { ChatContext } from "./useChatContext";
@ -161,7 +165,7 @@ function ChatProviderInner({
return;
}
// CHAT_HISTORY response
// CHAT_HISTORY response (also returned by SUBSCRIBE with metadata)
if (parsed.event === "CHAT_HISTORY" && Array.isArray(parsed.messages)) {
const chatCode = parsed.chatCode as string;
const messages = parsed.messages as ChatMessage[];
@ -169,6 +173,30 @@ function ChatProviderInner({
...prev,
[chatCode]: messages,
}));
if (parsed.metadata) {
const metadata = parsed.metadata as RoomMetadata;
const newRoom: RoomInfo = {
chatCode,
header: metadata.header,
subtitle: metadata.subtitle ?? "",
url: metadata.url ?? "",
participantUserIds: metadata.participantUserIds,
expiresAt: metadata.expiresAt,
lastMessageTimestamp: messages.at(-1)?.timestamp ?? 0,
totalMessageCount: messages.length,
};
setRooms((prev) => {
const exists = prev.some((r) => r.chatCode === chatCode);
if (exists) return prev;
return [...prev, newRoom];
});
if (metadata.chatUsers) {
setChatUsersCache((prev) => ({ ...prev, ...metadata.chatUsers }));
}
}
return;
}
@ -379,6 +407,8 @@ function ChatProviderInner({
setSidebarOpen,
subscribe,
unsubscribe,
setRooms,
setMessagesByRoom,
});
const contextValue = React.useMemo(
@ -422,6 +452,9 @@ function ChatProviderInner({
);
}
// xxx: bug: when viewing as non-participant can't go back to list view
// xxx: bug: room should close automatically if non-participant and leaves the route
// xxx: bug: route loading state should show before room metadata loads
function useChatRouteSync({
rooms,
userId,
@ -429,6 +462,8 @@ function useChatRouteSync({
setSidebarOpen,
subscribe,
unsubscribe,
setRooms,
setMessagesByRoom,
}: {
rooms: RoomInfo[];
userId: number;
@ -436,6 +471,10 @@ function useChatRouteSync({
setSidebarOpen: (open: boolean) => void;
subscribe: (chatCode: string) => void;
unsubscribe: (chatCode: string) => void;
setRooms: React.Dispatch<React.SetStateAction<RoomInfo[]>>;
setMessagesByRoom: React.Dispatch<
React.SetStateAction<Record<string, ChatMessage[]>>
>;
}) {
const matches = useMatches();
const subscribedRoomRef = React.useRef<string | null>(null);
@ -451,38 +490,31 @@ function useChatRouteSync({
}
}
if (!chatCode) {
// Leaving a chat route: unsubscribe from staff-subscribed rooms
if (subscribedRoomRef.current) {
unsubscribe(subscribedRoomRef.current);
subscribedRoomRef.current = null;
}
return;
const previousSubscribed = subscribedRoomRef.current;
// Clean up previous non-participant subscription if chatCode changed
if (previousSubscribed && previousSubscribed !== chatCode) {
unsubscribe(previousSubscribed);
setRooms((prev) => prev.filter((r) => r.chatCode !== previousSubscribed));
setMessagesByRoom((prev) => {
const { [previousSubscribed]: _, ...rest } = prev;
return rest;
});
subscribedRoomRef.current = null;
}
if (!chatCode) return;
const room = rooms.find((r) => r.chatCode === chatCode);
const isParticipant = room?.participantUserIds.includes(userId);
if (room) {
const isParticipant = room.participantUserIds.includes(userId);
if (isParticipant) {
setActiveRoom(chatCode);
setSidebarOpen(true);
} else {
// Staff/TO viewing: subscribe temporarily
subscribe(chatCode);
subscribedRoomRef.current = chatCode;
setActiveRoom(chatCode);
setSidebarOpen(true);
}
if (!isParticipant && subscribedRoomRef.current !== chatCode) {
subscribe(chatCode);
subscribedRoomRef.current = chatCode;
}
return () => {
if (subscribedRoomRef.current) {
unsubscribe(subscribedRoomRef.current);
subscribedRoomRef.current = null;
}
};
setActiveRoom(chatCode);
setSidebarOpen(true);
}, [
matches,
rooms,
@ -491,5 +523,7 @@ function useChatRouteSync({
setSidebarOpen,
subscribe,
unsubscribe,
setRooms,
setMessagesByRoom,
]);
}

View File

@ -45,6 +45,8 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
return {
post,
// xxx: only chatCode if permissions
chatCode: post.chatCode,
anyUserPrefersNoScreen:
await UserRepository.anyUserPrefersNoScreen(participantIds),
tournamentMapPool: post.mapsTournament

View File

@ -67,5 +67,7 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
})
: null,
rawReportedWeapons,
// xxx: only chatCode if permissions
chatCode: match.chatCode,
};
};

View File

@ -57,6 +57,8 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
? []
: groups,
ownGroup,
// xxx: only chatCode if permissions
chatCode: ownGroup?.chatCode,
likes: ownGroup
? await SQGroupRepository.allLikesByGroupId(ownGroup.id)
: {

View File

@ -119,5 +119,7 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
matchIsOver,
endedEarly,
noScreen,
// xxx: only chatCode if permissions
chatCode: match.chatCode,
};
};