Update environment configurations for client and server, refactor ChatPopup to accept sessionId as a prop, enhance chat message handling with senderName and guestId, and improve error logging in chat message processing. Adjust useChatHistory and useWebRTC hooks for better state management and message retrieval.

This commit is contained in:
2025-10-30 19:27:35 +05:00
parent 1cacd070eb
commit 000c4caacb
11 changed files with 309 additions and 134 deletions
+62 -11
View File
@@ -1,25 +1,48 @@
import { useRef, useEffect, useState } from "react";
import SendIcon from "../icons/SendIcon";
import Button from "../ui/Button";
import { useMe } from "../../hooks/useAuth";
import clsx from "clsx";
import PopupWrapper from "../PopupWrapper";
import DraggableContainer from "../DraggableContainer";
import { useWebRTC } from "../../hooks/useWebRTC";
import { useChatHistory } from "../../hooks/useChatHistory";
import { useParams } from "react-router";
import { useMe } from "../../hooks/useAuth";
export default function ChatPopup() {
interface ChatPopupProps {
sessionId?: string;
}
export default function ChatPopup({ sessionId: sessionIdProp }: ChatPopupProps = {}) {
const headerRef = useRef<HTMLDivElement>(null);
const { id: sessionId } = useParams<{ id: string }>();
// Получаем sessionId из пропсов или из URL параметров
const { id: sessionIdFromParams } = useParams<{ id: string }>();
const sessionId = sessionIdProp || sessionIdFromParams;
const {
chatMessages: realtimeMessages,
sendMessage,
currentUserId,
} = useWebRTC();
// Получаем данные текущего пользователя (если авторизован)
const { data: user } = useMe();
// currentUserId содержит либо userId (если авторизован), либо guestId (если гость)
// Это и есть наш идентификатор для сравнения с senderId в сообщениях
const myIdentifier = currentUserId;
console.log("[ChatPopup] Rendering with sessionId:", sessionId);
console.log("[ChatPopup] My identifier:", myIdentifier, "isAuthenticated:", !!user);
// Загружаем историю через REST API
const { data: historyMessages = [], isLoading } = useChatHistory(sessionId);
const { data: historyMessages = [], isLoading, error } = useChatHistory(sessionId);
console.log("[ChatPopup] Chat history state:", {
historyMessages: historyMessages.length,
isLoading,
error,
realtimeMessages: realtimeMessages.length,
});
// Объединяем историю и realtime сообщения
const historyIds = new Set(historyMessages.map((m) => m.id));
@@ -28,8 +51,11 @@ export default function ChatPopup() {
);
const allMessages = [...historyMessages, ...newRealtimeMessages];
console.log("[ChatPopup] All messages count:", allMessages.length);
function onMessageSend(message: string) {
sendMessage(message);
// Передаем имя пользователя и флаг авторизации
sendMessage(message, user?.fullName, !!user);
}
return (
@@ -48,7 +74,7 @@ export default function ChatPopup() {
<div className="flex flex-col 2xl:h-[19.444vw] max-sm:h-[87.5dvh] 2xl:-m-[1.389vw] -m-5">
<MessageFeed
messages={allMessages}
currentUserId={currentUserId}
currentUserId={myIdentifier}
isLoading={isLoading}
/>
<MessageInput onMessageSend={onMessageSend} />
@@ -62,6 +88,7 @@ interface MessageFeedProps {
messages: Array<{
id: string;
senderId: string;
senderName?: string;
content: string;
timestamp: Date | string;
}>;
@@ -73,6 +100,14 @@ function MessageFeed({ messages, currentUserId, isLoading }: MessageFeedProps) {
const messagesEndRef = useRef<HTMLDivElement>(null);
const prevMessageCountRef = useRef(0);
console.log("[MessageFeed] Rendering with currentUserId:", currentUserId);
console.log("[MessageFeed] Messages:", messages.map(m => ({
id: m.id,
senderId: m.senderId,
isFromMe: m.senderId === currentUserId,
content: m.content.substring(0, 20)
})));
// Умный скролл - только при добавлении новых сообщений
useEffect(() => {
const currentCount = messages.length;
@@ -124,8 +159,18 @@ function MessageFeed({ messages, currentUserId, isLoading }: MessageFeedProps) {
}
)}
isFromMe={message.senderId === currentUserId}
senderName={message.senderName}
/>
))}
{/* <MessageItem content="test" timestamp="12:00" isFromMe={false} />
<MessageItem content="test123" timestamp="12:00" isFromMe={true} />
<MessageItem content="testqwe" timestamp="12:00" isFromMe={true} />
<MessageItem
content={`asdasdasd\nasdasda\nasdasd`}
timestamp="12:00"
isFromMe={false}
/> */}
<div ref={messagesEndRef} />
</div>
)}
@@ -137,11 +182,15 @@ interface MessageItemProps {
timestamp: string;
content: string;
isFromMe: boolean;
senderName?: string;
}
function MessageItem({ timestamp, content, isFromMe }: MessageItemProps) {
const { data: user } = useMe();
function MessageItem({
timestamp,
content,
isFromMe,
senderName,
}: MessageItemProps) {
return (
<div
className={clsx(
@@ -159,9 +208,11 @@ function MessageItem({ timestamp, content, isFromMe }: MessageItemProps) {
>
<div className="break-words text-s 2xl:space-y-[0.278vw] space-y-1">
{!isFromMe && (
<div className="caption-s text-[#7B60F3]">{user?.fullName}</div>
<div className="caption-s text-[#7B60F3]">
{senderName || "Guest"}
</div>
)}
<div>{content}</div>
<div className="whitespace-pre-wrap">{content}</div>
</div>
<span className="opacity-30 caption-xs">{timestamp}</span>
</div>
+1 -1
View File
@@ -33,7 +33,7 @@ function ControlsPopover({ session }: ControlsPopoverProps) {
function handleClickOpenChatPopup() {
setIsOpened(false);
setPopup(<ChatPopup />);
setPopup(<ChatPopup sessionId={session?.id} />);
}
function handleClickOpenParticipantsPopup() {
+22 -7
View File
@@ -10,22 +10,37 @@ interface ChatHistoryResponse {
}
export const useChatHistory = (sessionId: string | undefined, enabled = true) => {
console.log("[useChatHistory] Hook called with:", { sessionId, enabled, willExecute: enabled && !!sessionId });
return useQuery({
queryKey: ["chat-history", sessionId],
queryFn: async () => {
console.log("[useChatHistory] Fetching chat history for session:", sessionId);
if (!sessionId) {
console.error("[useChatHistory] Session ID is required but not provided");
throw new Error("Session ID is required");
}
const response = await api
.get(`sessions/${sessionId}/messages`)
.json<ChatHistoryResponse>();
try {
console.log("[useChatHistory] Making API request to:", `sessions/${sessionId}/messages`);
const response = await api
.get(`sessions/${sessionId}/messages`)
.json<ChatHistoryResponse>();
if (!response.success) {
throw new Error(response.error || "Failed to load chat history");
console.log("[useChatHistory] API response:", response);
if (!response.success) {
console.error("[useChatHistory] API returned error:", response.error);
throw new Error(response.error || "Failed to load chat history");
}
console.log("[useChatHistory] Successfully loaded", response.messages.length, "messages");
return response.messages;
} catch (error) {
console.error("[useChatHistory] Error fetching chat history:", error);
throw error;
}
return response.messages;
},
enabled: enabled && !!sessionId,
staleTime: 1000 * 60 * 5, // 5 минут - история считается актуальной
+2 -2
View File
@@ -202,9 +202,9 @@ export const useWebRTC = (roomId?: string, autoJoin = false) => {
setIsVideoMuted(!newState);
};
const sendMessage = (content: string) => {
const sendMessage = (content: string, senderName?: string, isAuthenticated?: boolean) => {
if (!webrtcServiceInstance) return;
webrtcServiceInstance.sendChatMessage(content);
webrtcServiceInstance.sendChatMessage(content, senderName, isAuthenticated);
};
const joinRoom = async (roomId: string) => {
+11 -4
View File
@@ -300,7 +300,9 @@ function setupSocketListeners() {
});
socket.on("chat-error", (error: { message: string }) => {
console.error("📨 Chat error:", error.message);
console.error("📨 Chat error received from server:", error);
console.error("📨 Error message:", error.message);
alert(`Ошибка при отправке сообщения: ${error.message}`);
callAllCallbacks("onError", new Error(error.message));
});
@@ -850,17 +852,22 @@ function updateSpeakingState(isSpeaking: boolean): void {
});
}
function sendChatMessage(content: string, userName?: string): void {
function sendChatMessage(content: string, senderName?: string, isAuthenticated?: boolean): void {
if (!state || !content.trim() || !state.roomId) return;
console.log("📤 Sending message via Socket.IO:", content);
// Определяем userId и guestId
const userId = isAuthenticated ? state.userId : null;
const guestId = !isAuthenticated ? state.userId : null;
// Отправляем сообщение через Socket.IO
state.socket.emit("chat-message", {
roomId: state.roomId,
userId: state.userId,
userId,
guestId,
content: content.trim(),
userName: userName || "Anonymous",
senderName: senderName || null,
});
}
+1 -1
View File
@@ -81,7 +81,7 @@ function SessionPage() {
function handleChatOpen() {
console.log("handleChatOpen");
setPopup(<ChatPopup />);
setPopup(<ChatPopup sessionId={id} />);
}
function handleParticipantsOpen() {