V 0.04
parent
f13f9bc99b
commit
c86523dcf4
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 772 KiB |
@ -0,0 +1,13 @@
|
||||
import { FC, PropsWithChildren } from 'react'
|
||||
import Sidebar from '../Messenger/Sidebar/Sidebar';
|
||||
|
||||
const Layout: FC<PropsWithChildren> = ({children}) => {
|
||||
return (
|
||||
<main className='flex h-screen'>
|
||||
<Sidebar/>
|
||||
{children}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
export default Layout;
|
||||
@ -0,0 +1,30 @@
|
||||
import { FC } from 'react'
|
||||
import { IChat } from '../../../models/IChat';
|
||||
import { Link } from 'react-router-dom';
|
||||
//import { useLocation } from 'react-router-dom';
|
||||
|
||||
interface ChatProps {
|
||||
data: IChat
|
||||
}
|
||||
|
||||
const Chat: FC<ChatProps>= ({data}) => {
|
||||
// const location = useLocation();
|
||||
|
||||
return (
|
||||
<Link to='/messenger' className={['p-5 flex w-full items-center relative hover:bg-gray-700', ''].join(' ')}>
|
||||
<div className={['w-12 h-12 min-w-[48px] mr-3 relative', data.isOnline ? 'before:absolute before:w-4 before:h-4 before:bg-green-400 before:rounded-full before:bottom-0 before:right-0 before:border-[3px] before:border-gray-800' : null].join(' ')}>
|
||||
<img className='rounded-full w-[inherit] h-[inherit]' src={data.avatar} alt="avatar"/>
|
||||
</div>
|
||||
<div className="flex flex-col items-start overflow-hidden">
|
||||
<h2 className='text-white font-medium mb-1'>{data.name + ' ' + data.sname}</h2>
|
||||
<p className='text-gray-500 text-sm max-w-[200px] whitespace-nowrap overflow-hidden text-ellipsis'>{data.lastmsg.msg}</p>
|
||||
</div>
|
||||
<span className="text-sm text-gray-500 absolute right-4 top-4">{data.lastmsg.time}</span>
|
||||
{data.unreaded > 0 &&
|
||||
<span className='bg-apricot rounded-full text-sm flex items-center justify-center min-w-[20px] text-gray-800 font-semibold h-5 absolute bottom-[22px] right-4'>{data.unreaded}</span>
|
||||
}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default Chat;
|
||||
@ -0,0 +1,25 @@
|
||||
import { FC } from 'react'
|
||||
import Input from '../../UI/Input';
|
||||
import { BsSearch } from '@react-icons/all-files/bs/BsSearch'
|
||||
import Chat from './Chat';
|
||||
import { useAppSelector } from '../../../hooks/redux';
|
||||
|
||||
const Chats: FC = () => {
|
||||
const { chats } = useAppSelector(state => state.MessengerSlice)
|
||||
|
||||
return (
|
||||
<div className='w-80 bg-gray-800 pt-10 pb-5 flex flex-col'>
|
||||
<div className="px-5 border-b-[1px] border-b-gray-700 pb-5 mb-2">
|
||||
<h1 className='text-white font-semibold text-2xl mb-4'>Chats</h1>
|
||||
<Input icon={<BsSearch/>} type='text' className='!py-2' placeholder='Search...'/>
|
||||
</div>
|
||||
<div className="flex flex-col overflow-y-auto custom-scroll">
|
||||
{chats.map(chat=>
|
||||
<Chat key={chat._id} data={chat}/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Chats;
|
||||
@ -0,0 +1,28 @@
|
||||
import { FC } from 'react';
|
||||
import MenuItem from './MenuItem';
|
||||
import { BsChatText } from '@react-icons/all-files/bs/BsChatText';
|
||||
import { BsTelephone } from '@react-icons/all-files/bs/BsTelephone'
|
||||
import { BsGear } from '@react-icons/all-files/bs/BsGear'
|
||||
import { useAppSelector } from '../../../hooks/redux';
|
||||
|
||||
const Menu: FC = () => {
|
||||
|
||||
const { user } = useAppSelector(state=> state.UserSlice);
|
||||
|
||||
return (
|
||||
<nav className='flex flex-col h-full items-center'>
|
||||
<ul className='border-b border-b-gray-600 pb-8 flex flex-col items-center'>
|
||||
<MenuItem to='/messenger'><BsChatText/></MenuItem>
|
||||
<MenuItem className='mb-0' to='/messenger/1'><BsTelephone/></MenuItem>
|
||||
</ul>
|
||||
<ul className='pt-8 flex flex-col flex-grow items-center'>
|
||||
<MenuItem to='/messenger/2'><BsGear/></MenuItem>
|
||||
</ul>
|
||||
<div className="w-9 h-9 rounded-full">
|
||||
<img src={user.avatar} className='w-[inherit] h-[inherit]' alt="avatar" />
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
export default Menu;
|
||||
@ -0,0 +1,19 @@
|
||||
import { FC, PropsWithChildren } from 'react'
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
interface MenuItemProps {
|
||||
to: string,
|
||||
className?: string
|
||||
}
|
||||
|
||||
const MenuItem: FC<PropsWithChildren<MenuItemProps>> = ({to, className, children}) => {
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<li className={['mb-6', className].join(' ')}><Link to={to} className={['text-white hover:text-apricot transition-all text-xl font-medium', location.pathname === to ? '!text-gray-800 block bg-apricot p-4 rounded-sm' : null].join(' ')}>{children}</Link></li>
|
||||
)
|
||||
}
|
||||
|
||||
export default MenuItem;
|
||||
@ -0,0 +1,15 @@
|
||||
import { FC } from 'react';
|
||||
import Logo from '../../../assets/logo_sm_white.png';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Menu from './Menu';
|
||||
|
||||
const Sidebar: FC = () => {
|
||||
return (
|
||||
<aside className='w-20 bg-gray-900 py-7 px-2 flex flex-col'>
|
||||
<Link to='/'><img className='w-14 mb-8' src={Logo} alt="logo"/></Link>
|
||||
<Menu/>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
export default Sidebar;
|
||||
@ -0,0 +1,11 @@
|
||||
import { Message } from "./Message";
|
||||
|
||||
export interface IChat {
|
||||
_id: string;
|
||||
name: string;
|
||||
sname: string;
|
||||
avatar: string;
|
||||
unreaded: number;
|
||||
lastmsg: Message;
|
||||
isOnline: boolean;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
export interface Message {
|
||||
_id: string;
|
||||
msg: string;
|
||||
time: string;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { FC } from 'react'
|
||||
import Layout from '../../components/Layouts/Messenger';
|
||||
import Chats from '../../components/Messenger/Chats/Chats';
|
||||
|
||||
const MessengerPage: FC = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<Chats/>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default MessengerPage;
|
||||
@ -0,0 +1,39 @@
|
||||
import { createSlice } from "@reduxjs/toolkit"
|
||||
import { IChat } from "../../models/IChat";
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
|
||||
export interface MessengerState {
|
||||
chats: IChat[];
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const initialState: MessengerState = {
|
||||
chats: [
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 1, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '23:14'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 4, isOnline: false, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '22:18'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '12:10'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: false, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '16:04'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '18:43'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 1, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '23:14'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 4, isOnline: false, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '22:18'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '12:10'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: false, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '16:04'}},
|
||||
{_id: faker.string.uuid(), name: faker.person.firstName(), sname: faker.person.lastName(), avatar: faker.internet.avatar(), unreaded: 0, isOnline: true, lastmsg: {_id: faker.string.uuid(), msg: faker.lorem.sentence(), time: '18:43'}}
|
||||
],
|
||||
isLoading: true
|
||||
}
|
||||
|
||||
export const messengerSlice = createSlice({
|
||||
name: 'messengerSlice',
|
||||
initialState,
|
||||
reducers: {
|
||||
storeLoad(state) {
|
||||
state.isLoading = false;
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default messengerSlice.reducer;
|
||||
Loading…
Reference in New Issue