added new start page
This commit is contained in:
148
src/pages/ChatPage.jsx
Normal file
148
src/pages/ChatPage.jsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { useChats } from "../hooks/useChats";
|
||||
import { useChatSocket } from "../hooks/useChatSocket";
|
||||
import { getPostForChat } from "../stores/chatPostStore";
|
||||
import { setActiveChatId } from "../stores/activeChatStore";
|
||||
import { useUnread } from "../context/UnreadContext";
|
||||
import { API_URL } from "../config/authConstants";
|
||||
import Picker from "@emoji-mart/react";
|
||||
import emojiData from "@emoji-mart/data";
|
||||
|
||||
export default function ChatPage() {
|
||||
const { chatId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { fetchMessages, markAsRead } = useChats();
|
||||
const { clearChatUnread } = useUnread();
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [input, setInput] = useState("");
|
||||
const [showEmoji, setShowEmoji] = useState(false);
|
||||
const messagesEndRef = useRef(null);
|
||||
const emojiPickerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClick = (e) => {
|
||||
if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target)) {
|
||||
setShowEmoji(false);
|
||||
}
|
||||
};
|
||||
document.addEventListener("mousedown", handleClick);
|
||||
return () => document.removeEventListener("mousedown", handleClick);
|
||||
}, []);
|
||||
|
||||
const myUserId = (() => {
|
||||
try { return JSON.parse(localStorage.getItem("user"))?.id; }
|
||||
catch { return null; }
|
||||
})();
|
||||
|
||||
const handleIncoming = useCallback((msg) => {
|
||||
setMessages((prev) => [...prev, msg]);
|
||||
}, []);
|
||||
|
||||
const { sendMessage, connected } = useChatSocket(chatId, handleIncoming);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId) {
|
||||
setActiveChatId(chatId);
|
||||
fetchMessages(chatId).then(setMessages);
|
||||
markAsRead(chatId);
|
||||
clearChatUnread(chatId);
|
||||
}
|
||||
return () => setActiveChatId(null);
|
||||
}, [chatId, fetchMessages, markAsRead, clearChatUnread]);
|
||||
|
||||
useEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}, [messages]);
|
||||
|
||||
const handleSend = (e) => {
|
||||
e.preventDefault();
|
||||
if (!input.trim()) return;
|
||||
sendMessage(input);
|
||||
setInput("");
|
||||
};
|
||||
|
||||
const handleEmojiSelect = (emoji) => {
|
||||
setInput((prev) => prev + emoji.native);
|
||||
};
|
||||
|
||||
const post = getPostForChat(chatId);
|
||||
const postImg = post?.images?.[0] ? `${API_URL}${post.images[0]}` : null;
|
||||
|
||||
return (
|
||||
<div className="f-app">
|
||||
<div className="chat-page">
|
||||
<div className="chat-header">
|
||||
<button className="chat-back-btn" onClick={() => navigate("/chats")}>
|
||||
←
|
||||
</button>
|
||||
<div className="chat-header-avatar">
|
||||
{postImg ? (
|
||||
<img src={postImg} alt="" className="chat-header-avatar-img" />
|
||||
) : (
|
||||
post?.emoji || "📋"
|
||||
)}
|
||||
</div>
|
||||
<div className="chat-header-title">{post?.title || "Чат"}</div>
|
||||
<div className={`chat-status${connected ? " connected" : ""}`}>
|
||||
{connected ? "В сети" : "Отключено"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="chat-messages">
|
||||
{messages.length === 0 && (
|
||||
<div className="chat-empty">Нет сообщений</div>
|
||||
)}
|
||||
{messages.map((m) => (
|
||||
<div
|
||||
key={m.id}
|
||||
className={`chat-bubble${m.senderId === myUserId ? " mine" : ""}`}
|
||||
>
|
||||
{m.content}
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
<div className="chat-input-area">
|
||||
{showEmoji && (
|
||||
<div className="chat-emoji-picker" ref={emojiPickerRef}>
|
||||
<Picker
|
||||
data={emojiData}
|
||||
onEmojiSelect={handleEmojiSelect}
|
||||
theme="dark"
|
||||
previewPosition="none"
|
||||
skinTonePosition="none"
|
||||
searchPosition="sticky"
|
||||
maxSearchResults={30}
|
||||
perLine={8}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSend} className="chat-input-row">
|
||||
<input
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="Сообщение..."
|
||||
className="chat-input"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className={`chat-emoji-btn${showEmoji ? " active" : ""}`}
|
||||
onClick={() => setShowEmoji((v) => !v)}
|
||||
>
|
||||
😊
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="chat-send-btn"
|
||||
disabled={!connected}
|
||||
>
|
||||
➤
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user