diff --git a/web/src/Components/Pages/ChatPage/ChatPage.jsx b/web/src/Components/Pages/ChatPage/ChatPage.jsx new file mode 100644 index 0000000..4f545b2 --- /dev/null +++ b/web/src/Components/Pages/ChatPage/ChatPage.jsx @@ -0,0 +1,607 @@ +import React, { useRef, useEffect } from "react"; +import { + Card, + Input, + Avatar, + Badge, + Typography, + Space, + Button, + Tag, + Empty, + Upload, + Drawer, + Row, + Col, + Collapse, + List, + Select, + Divider, +} from "antd"; +import { + SendOutlined, + PaperClipOutlined, + SearchOutlined, + TeamOutlined, + UserOutlined, + MessageOutlined, + InfoCircleOutlined, + FileOutlined, + FilterOutlined, +} from "@ant-design/icons"; +import useChatPage from "./useChatPage.js"; + +const { TextArea } = Input; +const { Title, Text } = Typography; + +const ChatPage = () => { + const { + selectedChat, + messages, + messageText, + setMessageText, + searchQuery, + setSearchQuery, + selectedCourse, + setSelectedCourse, + selectedGroup, + setSelectedGroup, + selectedTopic, + setSelectedTopic, + courses, + groups, + topics, + currentUser, + handleSelectChat, + handleSendMessage, + handleFileUpload, + filteredChatList, + infoDrawerVisible, + setInfoDrawerVisible, + chatParticipants, + } = useChatPage(); + + const messagesEndRef = useRef(null); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + return ( +
+ {/* Заголовок */} +
+ + <MessageOutlined style={{ marginRight: 12 }} /> + Мессенджер + +
+ + + {/* Левая колонка — список чатов */} + + + {/* Поиск и фильтры */} +
+ } + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + allowClear + size="large" + style={{ marginBottom: 12 }} + /> + + + + Фильтры + {(selectedCourse || selectedGroup || selectedTopic) && ( + + )} + + ), + children: ( + + + + + + + + {(selectedCourse || selectedGroup || selectedTopic) && ( + + )} + + ), + } + ]} + /> +
+ + {/* Список чатов */} +
+ {filteredChatList.length === 0 ? ( + + ) : ( + filteredChatList.map((chat) => ( +
handleSelectChat(chat.id)} + style={{ + padding: "14px 20px", + borderBottom: "1px solid #f0f0f0", + background: selectedChat?.id === chat.id ? "#e6f7ff" : "transparent", + cursor: "pointer", + transition: "all 0.2s", + }} + onMouseEnter={(e) => { + if (selectedChat?.id !== chat.id) e.currentTarget.style.background = "#f9f9f9"; + }} + onMouseLeave={(e) => { + if (selectedChat?.id !== chat.id) e.currentTarget.style.background = "transparent"; + }} + > +
+ + : } + style={{ + backgroundColor: chat.type === "group" ? "#52c41a" : "#1890ff", + flexShrink: 0 + }} + /> + +
+
+ {chat.name} +
+
+ {chat.lastMessage || "Нет сообщений"} +
+ + {chat.course && {chat.course}} + {chat.group && {chat.group}} + {chat.topic && {chat.topic}} + +
+
+ {new Date(chat.lastActivity).toLocaleTimeString("ru-RU", { + hour: "2-digit", + minute: "2-digit", + })} +
+
+
+ )) + )} +
+
+ + + {/* Правая колонка — чат */} + + {selectedChat ? ( + + {/* Шапка чата */} +
+
+
+ : } + style={{ + backgroundColor: selectedChat.type === "group" ? "#52c41a" : "#1890ff", + flexShrink: 0 + }} + /> +
+ + {selectedChat.name} + + + {selectedChat.course && {selectedChat.course}} + {selectedChat.group && {selectedChat.group}} + {selectedChat.topic && {selectedChat.topic}} + +
+
+ +
+
+ + {/* Сообщения */} +
+ {messages.length === 0 ? ( + + ) : ( + messages.map((msg) => { + const isOwn = msg.senderId === currentUser.id; + return ( +
+
+ {!isOwn && ( + + {msg.senderName[0].toUpperCase()} + + )} +
+ {!isOwn && ( + + {msg.senderName} + + )} +
+ {msg.text} + {msg.attachment && ( +
+ } + color={isOwn ? "default" : "blue"} + style={{ + background: isOwn ? "rgba(255,255,255,0.2)" : undefined, + borderColor: isOwn ? "rgba(255,255,255,0.3)" : undefined, + color: isOwn ? "#fff" : undefined + }} + > + {msg.attachment} + +
+ )} +
+ + {msg.timestamp} + +
+
+
+ ); + }) + )} +
+
+ + {/* Поле ввода */} +
+
+ +