diff --git a/README.md b/README.md index 2585e65..c54d2ea 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Ararat International School - платформа по обучению игры - Express.js - Mongo DB +#### V 0.05 +- [Messenger] Добавлена заглушка когда чат не выбран +- [Messenger] Чаты теперь открываются по маршруту /messenger/chat/:id +- [Messenger] Создана страница чата +- [Messenger] Убран лишний re-render у Layout по переходу между чатами + #### V 0.04 - Пункт Мессенджер теперь ведет по пути /messenger - [Messenger] Добавлен sidebar diff --git a/client/package-lock.json b/client/package-lock.json index dc5e306..2d61cae 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -16,6 +16,7 @@ "@types/uniqid": "^5.3.2", "axios": "^1.4.0", "body-scroll-lock": "^4.0.0-beta.0", + "date-fns": "^2.30.0", "framer-motion": "^10.13.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -1755,6 +1756,21 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/client/package.json b/client/package.json index 0389738..09f3259 100644 --- a/client/package.json +++ b/client/package.json @@ -18,6 +18,7 @@ "@types/uniqid": "^5.3.2", "axios": "^1.4.0", "body-scroll-lock": "^4.0.0-beta.0", + "date-fns": "^2.30.0", "framer-motion": "^10.13.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/client/public/chat-pattern.webp b/client/public/chat-pattern.webp new file mode 100644 index 0000000..61408ea Binary files /dev/null and b/client/public/chat-pattern.webp differ diff --git a/client/src/App.tsx b/client/src/App.tsx index 30b439e..55b025d 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -5,10 +5,11 @@ import IndexPage from "./pages/IndexPage" import LoginPage from "./pages/LoginPage" import RegisterPage from "./pages/RegisterPage" import MessengerPage from "./pages/Messenger/MessengerPage" +import ChatPage from "./pages/Messenger/ChatPage" import { BrowserRouter, Routes, Route } from 'react-router-dom' import { checkAuth, userSlice } from "./store/reducers/UserSlice"; import { useAppDispatch, useAppSelector } from "./hooks/redux" - +import Layout from "./components/Layouts/Messenger" function App() { const {isLoading} = useAppSelector(state => state.UserSlice); @@ -35,7 +36,8 @@ function App() { }/> }/> }/> - }/> + }/> + }/> ) diff --git a/client/src/components/Messenger/Chat/Chat.tsx b/client/src/components/Messenger/Chat/Chat.tsx new file mode 100644 index 0000000..c7eac16 --- /dev/null +++ b/client/src/components/Messenger/Chat/Chat.tsx @@ -0,0 +1,43 @@ +import { FC, useRef, useEffect } from 'react' +import TopInfo from './TopInfo'; +import Message from './Message'; +import EmptyChat from './EmptyChat'; +import SendMessage from './SendMessage'; +import { useAppSelector } from '../../../hooks/redux'; + +const Chat: FC = () => { + const messagesEndRef = useRef(null) + const { user } = useAppSelector(state => state.UserSlice) + const { chat } = useAppSelector(state => state.MessengerSlice) + useEffect(() => { + if(messagesEndRef.current) { + messagesEndRef.current.scrollIntoView() + } + }, [chat.messages]) + + + return ( +
+ +
+
0 ? 'mt-10' : 'h-full justify-center'].join(' ')}> + {chat.messages.length > 0 + ? + <> + {chat.messages.map(message=> + + )} +
+ + : + + } + +
+
+ +
+ ) +} + +export default Chat; \ No newline at end of file diff --git a/client/src/components/Messenger/Chat/EmptyChat.tsx b/client/src/components/Messenger/Chat/EmptyChat.tsx new file mode 100644 index 0000000..99fe18f --- /dev/null +++ b/client/src/components/Messenger/Chat/EmptyChat.tsx @@ -0,0 +1,13 @@ +import {FC} from 'react' +import { IoChatbubblesOutline } from '@react-icons/all-files/io5/IoChatbubblesOutline' + +const EmptyChat: FC = () => { + return ( +
+
+

Dialog is Empty

+
+ ) +} + +export default EmptyChat; \ No newline at end of file diff --git a/client/src/components/Messenger/Chat/Message.tsx b/client/src/components/Messenger/Chat/Message.tsx new file mode 100644 index 0000000..72e9eb2 --- /dev/null +++ b/client/src/components/Messenger/Chat/Message.tsx @@ -0,0 +1,33 @@ +import { FC } from 'react' +import { IMessage } from '../../../models/IMessage' +import { User } from '../../../models/User'; +import format from 'date-fns/format'; +import { BsCheckAll } from '@react-icons/all-files/bs/BsCheckAll' +import Avatar from '../../UI/Avatar'; + +interface MessageProps { + msg: IMessage; + user?: User; + isMe: boolean; +} + +const Message: FC = ({msg, user, isMe}) => { + return ( +
+ +
+

{user?.name} {user?.sname}

+

{msg.msg}

+
+

{format(msg.time, 'H:mm')}

+ {isMe && + + } +
+ +
+
+ ) +} + +export default Message; \ No newline at end of file diff --git a/client/src/components/Messenger/Chat/SendMessage.tsx b/client/src/components/Messenger/Chat/SendMessage.tsx new file mode 100644 index 0000000..9b305d8 --- /dev/null +++ b/client/src/components/Messenger/Chat/SendMessage.tsx @@ -0,0 +1,28 @@ +import { FC, useState } from 'react' +import Textarea from './Textarea'; +import IcoButton from '../../UI/IcoButton'; +import { BsMic } from '@react-icons/all-files/bs/BsMic'; +import { VscSend } from '@react-icons/all-files/vsc/VscSend'; +import {BsEmojiSmile} from '@react-icons/all-files/bs/BsEmojiSmile'; +import {ImAttachment} from '@react-icons/all-files/im/ImAttachment'; + +const SendMessage: FC = () => { + const [msg, setMsg] = useState(''); + return ( +
+
+ } className='!px-3 !py-2'/> + } className='!px-3 !py-2'/> +
+ + ) +} + +export default Textarea; \ No newline at end of file diff --git a/client/src/components/Messenger/Chat/TopInfo.tsx b/client/src/components/Messenger/Chat/TopInfo.tsx new file mode 100644 index 0000000..e7805f9 --- /dev/null +++ b/client/src/components/Messenger/Chat/TopInfo.tsx @@ -0,0 +1,38 @@ +import { FC } from 'react' +import { User } from '../../../models/User'; +import Avatar from '../../UI/Avatar'; +import IcoButton from '../../UI/IcoButton'; +import formatDistanceToNow from 'date-fns/formatDistanceToNow'; +import { BsTelephone } from '@react-icons/all-files/bs/BsTelephone'; +import { BsCameraVideo } from '@react-icons/all-files/bs/BsCameraVideo'; + +interface TopInfoProps { + data: User; +} + +const TopInfo: FC = ({data}) => { + return ( +
+
+ +
+

{data.name} {data.sname}

+

+ {data.online + ? + 'online' + : + formatDistanceToNow(data.lastOnline, {addSuffix: true}) + } +

+
+
+
+ } className='mr-2'/> + }/> +
+
+ ) +} + +export default TopInfo; \ No newline at end of file diff --git a/client/src/components/Messenger/Chats/Chat.tsx b/client/src/components/Messenger/Chats/Chat.tsx index 78692c4..54f894d 100644 --- a/client/src/components/Messenger/Chats/Chat.tsx +++ b/client/src/components/Messenger/Chats/Chat.tsx @@ -1,25 +1,26 @@ import { FC } from 'react' import { IChat } from '../../../models/IChat'; import { Link } from 'react-router-dom'; -//import { useLocation } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; +import format from 'date-fns/format'; interface ChatProps { data: IChat } const Chat: FC= ({data}) => { - // const location = useLocation(); + const { userid } = useParams(); return ( - +
avatar

{data.name + ' ' + data.sname}

-

{data.lastmsg.msg}

+

{data.lastmsg.msg}

- {data.lastmsg.time} + {format(data.lastmsg.time, 'H:mm')} {data.unreaded > 0 && {data.unreaded} } diff --git a/client/src/components/Messenger/Sidebar/Menu.tsx b/client/src/components/Messenger/Sidebar/Menu.tsx index bd9362e..244a6f1 100644 --- a/client/src/components/Messenger/Sidebar/Menu.tsx +++ b/client/src/components/Messenger/Sidebar/Menu.tsx @@ -12,7 +12,7 @@ const Menu: FC = () => { return (