Added online for contacts. Updated chat
This commit is contained in:
parent
5929303523
commit
b379a2a98c
@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import { useSocket } from "../../../hooks/useSocket";
|
import { useSocket } from "../../../hooks/useSocket";
|
||||||
import "./styles/ChatTab.css";
|
import "./styles/ChatTab.css";
|
||||||
|
import PlayerManager from "../../../services/PlayerManager";
|
||||||
|
|
||||||
const ChatTab = () => {
|
const ChatTab = () => {
|
||||||
const { socket } = useSocket();
|
const { socket } = useSocket();
|
||||||
@ -13,8 +14,16 @@ const ChatTab = () => {
|
|||||||
const [showSidebar, setShowSidebar] = useState(true);
|
const [showSidebar, setShowSidebar] = useState(true);
|
||||||
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
|
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
|
||||||
const [confirmUnfriend, setConfirmUnfriend] = useState(null);
|
const [confirmUnfriend, setConfirmUnfriend] = useState(null);
|
||||||
|
const [onlineList, setOnlineList] = useState(
|
||||||
|
PlayerManager.onlinePlayers || [],
|
||||||
|
);
|
||||||
|
|
||||||
const messagesEndRef = useRef(null);
|
const messagesEndRef = useRef(null);
|
||||||
|
const activeChatRef = useRef(activeChat);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
activeChatRef.current = activeChat;
|
||||||
|
}, [activeChat]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
@ -30,17 +39,34 @@ const ChatTab = () => {
|
|||||||
if (!socket) return;
|
if (!socket) return;
|
||||||
|
|
||||||
socket.emit("friend:get_list");
|
socket.emit("friend:get_list");
|
||||||
|
|
||||||
if (activeChat === "global") {
|
if (activeChat === "global") {
|
||||||
socket.emit("chat:get_global_history");
|
socket.emit("chat:get_global_history");
|
||||||
|
} else {
|
||||||
|
socket.emit("chat:get_private_history", { friendId: activeChat });
|
||||||
}
|
}
|
||||||
|
}, [socket, activeChat]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!socket) return;
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setOnlineList([...PlayerManager.onlinePlayers]);
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
const handleNewMessage = (msg) => {
|
const handleNewMessage = (msg) => {
|
||||||
if (
|
const currentActive = activeChatRef.current;
|
||||||
(activeChat === "global" && msg.type === "global") ||
|
const isGlobalMatch = currentActive === "global" && msg.type === "global";
|
||||||
(activeChat !== "global" &&
|
const isPrivateMatch =
|
||||||
(msg.senderId === activeChat || msg.receiverId === activeChat))
|
currentActive !== "global" &&
|
||||||
) {
|
msg.type === "private" &&
|
||||||
setMessages((prev) => [...prev, msg]);
|
(msg.senderId === currentActive || msg.receiverId === currentActive);
|
||||||
|
|
||||||
|
if (isGlobalMatch || isPrivateMatch) {
|
||||||
|
setMessages((prev) => {
|
||||||
|
if (prev.some((m) => m.id === msg.id)) return prev;
|
||||||
|
return [...prev, msg];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,16 +76,19 @@ const ChatTab = () => {
|
|||||||
|
|
||||||
socket.on("chat:new_message", handleNewMessage);
|
socket.on("chat:new_message", handleNewMessage);
|
||||||
socket.on("chat:global_history", handleHistory);
|
socket.on("chat:global_history", handleHistory);
|
||||||
|
socket.on("chat:private_history", handleHistory);
|
||||||
socket.on("player:search_results", handleSearchResults);
|
socket.on("player:search_results", handleSearchResults);
|
||||||
socket.on("friend:list", handleFriendList);
|
socket.on("friend:list", handleFriendList);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
socket.off("chat:new_message", handleNewMessage);
|
socket.off("chat:new_message", handleNewMessage);
|
||||||
socket.off("chat:global_history", handleHistory);
|
socket.off("chat:global_history", handleHistory);
|
||||||
|
socket.off("chat:private_history", handleHistory);
|
||||||
socket.off("player:search_results", handleSearchResults);
|
socket.off("player:search_results", handleSearchResults);
|
||||||
socket.off("friend:list", handleFriendList);
|
socket.off("friend:list", handleFriendList);
|
||||||
};
|
};
|
||||||
}, [socket, activeChat]);
|
}, [socket]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
@ -110,6 +139,10 @@ const ChatTab = () => {
|
|||||||
return friend ? friend.username : "UNKNOWN_PILOT";
|
return friend ? friend.username : "UNKNOWN_PILOT";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isFriendOnline = (username) => {
|
||||||
|
return onlineList.includes(username);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`chat-container ${isMobile ? "mobile" : ""}`}>
|
<div className={`chat-container ${isMobile ? "mobile" : ""}`}>
|
||||||
{confirmUnfriend && (
|
{confirmUnfriend && (
|
||||||
@ -148,7 +181,6 @@ const ChatTab = () => {
|
|||||||
onChange={handleSearch}
|
onChange={handleSearch}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{searchResults.length > 0 && (
|
{searchResults.length > 0 && (
|
||||||
<div className="search-results-dropdown">
|
<div className="search-results-dropdown">
|
||||||
{searchResults.map((player) => (
|
{searchResults.map((player) => (
|
||||||
@ -194,7 +226,7 @@ const ChatTab = () => {
|
|||||||
onClick={() => selectChat(friend.id)}
|
onClick={() => selectChat(friend.id)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`status-dot ${friend.online ? "online" : "offline"}`}
|
className={`status-dot ${isFriendOnline(friend.username) ? "online" : "offline"}`}
|
||||||
></div>
|
></div>
|
||||||
<span>{friend.username}</span>
|
<span>{friend.username}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -49,7 +49,31 @@ class ChatManager {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async getPrivateHistory(myId, friendId, limit = 50) {
|
||||||
|
try {
|
||||||
|
return await Message.findAll({
|
||||||
|
where: {
|
||||||
|
type: "private",
|
||||||
|
[Op.or]: [
|
||||||
|
{ senderId: myId, receiverId: friendId },
|
||||||
|
{ senderId: friendId, receiverId: myId },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
limit,
|
||||||
|
order: [["createdAt", "ASC"]],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Player,
|
||||||
|
as: "sender",
|
||||||
|
attributes: ["username"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Private History Error:", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
async searchPlayers(query, excludeId) {
|
async searchPlayers(query, excludeId) {
|
||||||
try {
|
try {
|
||||||
return await Player.findAll({
|
return await Player.findAll({
|
||||||
|
|||||||
@ -14,7 +14,6 @@ module.exports = (io, socket) => {
|
|||||||
socket.emit("chat:global_history", formattedHistory);
|
socket.emit("chat:global_history", formattedHistory);
|
||||||
});
|
});
|
||||||
socket.on("chat:get_global_history", async () => {
|
socket.on("chat:get_global_history", async () => {
|
||||||
console.log(`Player ${socket.player?.id} requested chat history`);
|
|
||||||
const history = await chatManager.getGlobalHistory();
|
const history = await chatManager.getGlobalHistory();
|
||||||
|
|
||||||
const formattedHistory = history.map((m) => ({
|
const formattedHistory = history.map((m) => ({
|
||||||
@ -28,10 +27,12 @@ module.exports = (io, socket) => {
|
|||||||
|
|
||||||
socket.emit("chat:global_history", formattedHistory);
|
socket.emit("chat:global_history", formattedHistory);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("chat:send_message", async (payload) => {
|
socket.on("chat:send_message", async (payload) => {
|
||||||
try {
|
try {
|
||||||
const senderId = socket.user?.id;
|
const senderId = socket.user?.id;
|
||||||
if (!senderId) return;
|
if (!senderId) return;
|
||||||
|
|
||||||
const messageData = await chatManager.saveMessage({
|
const messageData = await chatManager.saveMessage({
|
||||||
content: payload.content,
|
content: payload.content,
|
||||||
type: payload.type || "global",
|
type: payload.type || "global",
|
||||||
@ -42,20 +43,36 @@ module.exports = (io, socket) => {
|
|||||||
if (messageData.type === "global") {
|
if (messageData.type === "global") {
|
||||||
io.emit("chat:new_message", messageData);
|
io.emit("chat:new_message", messageData);
|
||||||
} else {
|
} else {
|
||||||
console.log(payload.receiverId);
|
|
||||||
socket
|
socket
|
||||||
.to(`user_${payload.receiverId}`)
|
.to(`user_${payload.receiverId}`)
|
||||||
.emit("chat:new_message", messageData);
|
.emit("chat:new_message", messageData);
|
||||||
socket.emit("chat:new_message", messageData);
|
socket.emit("chat:new_message", messageData);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
socket.emit("error", { message: "CHAT_SEND_ERROR" });
|
socket.emit("error", { message: "CHAT_SEND_ERROR" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("chat:get_private_history", async ({ friendId }) => {
|
||||||
|
const myId = socket.user?.id;
|
||||||
|
|
||||||
|
if (!myId || !friendId) return;
|
||||||
|
|
||||||
|
const history = await chatManager.getPrivateHistory(myId, friendId);
|
||||||
|
const formattedHistory = history.map((m) => ({
|
||||||
|
id: m.id,
|
||||||
|
content: m.content,
|
||||||
|
senderName: m.sender?.username || "Unknown",
|
||||||
|
senderId: m.senderId,
|
||||||
|
receiverId: m.receiverId,
|
||||||
|
createdAt: m.createdAt,
|
||||||
|
type: m.type,
|
||||||
|
}));
|
||||||
|
socket.emit("chat:private_history", formattedHistory);
|
||||||
|
});
|
||||||
socket.on("player:search", async ({ query }) => {
|
socket.on("player:search", async ({ query }) => {
|
||||||
const senderId = socket.player?.id;
|
const senderId = socket.user?.id;
|
||||||
if (!query || !senderId) return;
|
if (!query || !senderId) return;
|
||||||
|
|
||||||
const results = await chatManager.searchPlayers(query, senderId);
|
const results = await chatManager.searchPlayers(query, senderId);
|
||||||
|
|||||||
@ -63,7 +63,7 @@ module.exports = async (io, socket) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.broadcast.emit("player:joined", { username: playerRaw.username });
|
socket.broadcast.emit("player:joined", { username: playerRaw.username });
|
||||||
|
socket.join(`user_${socket.user.id}`);
|
||||||
socket.on("player:get_dashboard", async () => {
|
socket.on("player:get_dashboard", async () => {
|
||||||
try {
|
try {
|
||||||
const p = await Player.findByPk(userId);
|
const p = await Player.findByPk(userId);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user