Browse Source

finished with pin contact and chat

unknown 1 year ago
parent
commit
a0566a82bf
34 changed files with 288 additions and 163 deletions
  1. 1 1
      .eslintcache
  2. 22 0
      src/api-data/index.ts
  3. 4 6
      src/components/AuthPage/Registration/index.tsx
  4. 4 3
      src/components/HomePage/CentralBar/ChatBar/ArrowBack/index.tsx
  5. 12 11
      src/components/HomePage/CentralBar/ChatBar/index.tsx
  6. 23 15
      src/components/HomePage/CentralBar/HeaderBar/PinnedBar/index.tsx
  7. 3 9
      src/components/HomePage/CentralBar/index.tsx
  8. 40 18
      src/components/HomePage/LeftBar/ChatsList/ChatItem/index.tsx
  9. 23 10
      src/components/HomePage/LeftBar/ChatsList/index.tsx
  10. 28 2
      src/components/HomePage/LeftBar/ContactsList/ContactItem/index.tsx
  11. 27 18
      src/components/HomePage/LeftBar/ContactsList/index.tsx
  12. 8 3
      src/components/HomePage/LeftBar/SearchLists/AudioList/index.tsx
  13. 8 3
      src/components/HomePage/LeftBar/SearchLists/FilesList/index.tsx
  14. 8 3
      src/components/HomePage/LeftBar/SearchLists/MediaList/index.tsx
  15. 8 3
      src/components/HomePage/LeftBar/SearchLists/TextList/index.tsx
  16. 9 3
      src/components/HomePage/LeftBar/SearchLists/VideoList/index.tsx
  17. 15 14
      src/components/HomePage/LeftBar/SearchLists/index.tsx
  18. 11 9
      src/components/HomePage/RightBar/CredentialsList/ProfileLists/index.tsx
  19. 13 14
      src/components/HomePage/RightBar/SearchList/index.tsx
  20. 7 5
      src/components/HomePage/index.tsx
  21. 1 1
      src/helpers/index.ts
  22. BIN
      src/img/clipart289625.png
  23. 0 5
      src/img/double-check-svgrepo-com.svg
  24. BIN
      src/img/telegram.png
  25. BIN
      src/img/videoPoster.png
  26. BIN
      src/img/wallpaper.jpg
  27. BIN
      src/img/wallpaperNight.jpg
  28. 1 1
      src/redux/authorization/operations/index.ts
  29. 3 2
      src/redux/authorization/selector/index.ts
  30. 2 1
      src/redux/chat/reducer/index.ts
  31. 3 2
      src/redux/contacts/selector/index.ts
  32. 1 0
      src/typescript/redux/chat/types.ts
  33. 2 1
      src/typescript/redux/chats/types.ts
  34. 1 0
      src/typescript/redux/contacts/types.ts

File diff suppressed because it is too large
+ 1 - 1
.eslintcache


+ 22 - 0
src/api-data/index.ts

@@ -160,6 +160,16 @@ const updateContact = async <T>(id:string,_id:string,name:string,lastName:string
   }
 };
 
+const pinContact = async <T>(id:string,pinned:boolean): Promise<T | undefined> => {
+  try {
+    const { data: { data } } = await axios.patch('/contacts/pin', { id, pinned });
+    return data
+  } catch (e) {
+    forbidden(e)
+    return undefined
+  }
+};
+
 const getContacts = async <T>(): Promise<T | undefined> => {
   try {
     const { data : {data} } = await axios.get('/contacts');
@@ -240,6 +250,16 @@ const typingChat = async <T>(id:string,typing:boolean): Promise<T | undefined> =
   }
 };
 
+const pinChat = async <T>(id:string,pinned:boolean): Promise<T | undefined> => {
+  try {
+    const { data: { data } } = await axios.patch('/chats/pin', { id,pinned});
+    return data
+  } catch (e) {
+    forbidden(e)
+    return undefined
+  }
+};
+
 const getChats = async <T>(): Promise<T | undefined> => {
   try {
     const { data: { data } } = await axios.get('/chats');
@@ -386,6 +406,7 @@ export {
   addContact,
   removeContact,
   updateContact,
+  pinContact,
   getContacts,
   startChat,
   removeChatForBoth,
@@ -394,6 +415,7 @@ export {
   sortChat,
   seenChat,
   typingChat,
+  pinChat,
   getChats,
   removeMessageById,
   removeSelectedMessagesById,

+ 4 - 6
src/components/AuthPage/Registration/index.tsx

@@ -122,17 +122,15 @@ const Registration = () => {
   }  
 
   const handleUpdateUser = async () => {
-    if (upload) {
-      dispatch(asyncCreateUser(name, lastName, upload))
-    }
-    if (selfie) {
-      fetch(selfie)
+    if (upload) return dispatch(asyncCreateUser(name, lastName, upload))
+    
+    if (selfie) return fetch(selfie)
        .then(res => res.blob())
         .then(blob => {
           const imgFile = new File([blob], "selfie", { type: "image/jpeg" })
           dispatch(asyncCreateUser(name, lastName, imgFile))
       })
-    }
+    dispatch(asyncCreateUser(name, lastName,null))
   }
 
   return (

+ 4 - 3
src/components/HomePage/CentralBar/ChatBar/ArrowBack/index.tsx

@@ -39,15 +39,16 @@ const useStyles = makeStyles({
 interface IArrowBack {
     isArrow: boolean,
     isNew: {new:number,mute:boolean},
-    handleScrollTo:() => void
+    handleScrollTo: () => void,
+    openPinned: boolean
 }
 
-const ArrowBack = ({ isArrow, handleScrollTo, isNew }: IArrowBack) => {
+const ArrowBack = ({ isArrow, handleScrollTo, isNew,openPinned }: IArrowBack) => {
     const classes = useStyles()
 
 return (
     <div className={classes.avatarArrowWrapper} style={{display: isArrow ? 'block' : 'none'}}>
-        <button onClick={handleScrollTo} style={{display: isNew.new ? 'block' : 'none',
+        <button onClick={handleScrollTo} style={{display: isNew.new&&!openPinned ? 'block' : 'none',
           background: isNew.mute ? '#a7aaa7' : '#0ac40a'}}
           className={classes.listSeenIcon}>{isNew.new}</button>
         <Avatar onClick={handleScrollTo} className={classes.avatarArrow}

+ 12 - 11
src/components/HomePage/CentralBar/ChatBar/index.tsx

@@ -1,5 +1,5 @@
 import { makeStyles } from "@material-ui/core/styles";
-import { useState, useEffect, useCallback } from "react";
+import { useState, useEffect, useCallback, useMemo } from "react";
 import { useSelector,useDispatch } from "react-redux";
 
 import ArrowBack from "./ArrowBack";
@@ -90,7 +90,7 @@ interface IChatBar {
 const ChatBar = ({chatDivRef,selectedArr,setSelectedArr,isSomeSelected,setIsSomeSelected,openPinned,pinnedMessagesMemo,handleUnpinAll}:IChatBar) => {
   const classes = useStyles();
   const dispatch = useDispatch()
-  const messages = useSelector(getMessagesMemo)
+  const messagesMemo = useSelector(getMessagesMemo)
   const userNumber = useSelector(getNumber)
   const { companionId,total,seen,mute } = useSelector(getChat)
   const scrollChat = useSelector(getScrollChat)
@@ -114,9 +114,9 @@ const ChatBar = ({chatDivRef,selectedArr,setSelectedArr,isSomeSelected,setIsSome
   const handleScroll = useCallback(({ target:{scrollHeight,scrollTop,clientHeight}}: any) => {
     const different = scrollHeight - Math.floor(scrollTop)
     const reached = different - clientHeight
-    if (total !== seen&&reached < 10) seenChat(companionId)
+    if (total !== seen&&reached < 10 && !openPinned) seenChat(companionId)
     setIsArrow(different === clientHeight ? false : true)
-  }, [total,seen, companionId])
+  }, [total,seen, companionId,openPinned])
   
   const debouncedHandleScroll = debounce(handleScroll, 300)
   
@@ -143,25 +143,26 @@ const ChatBar = ({chatDivRef,selectedArr,setSelectedArr,isSomeSelected,setIsSome
 
   useEffect(() => {
     const handleReset = () => {
-      if (chatDivRef.current) {
+      if (chatDivRef.current&&!openPinned) {
          const { scrollHeight, clientHeight } = chatDivRef.current
          if (total !== seen && scrollHeight === clientHeight) seenChat(companionId)
        }
     }
     const idInterval = setInterval(handleReset, refreshAppTime);
     return () => clearInterval(idInterval);
-  }, [total, seen, chatDivRef, companionId]);
-  
-  const renderArr = !openPinned?messages:pinnedMessagesMemo
+  }, [total, seen, chatDivRef, companionId,openPinned]);
   
+  const renderArr = useMemo(() => {
+    return !openPinned ? messagesMemo : pinnedMessagesMemo
+  },[messagesMemo,pinnedMessagesMemo,openPinned])
 
   return (
     <div className={classes.container} >
-      <ArrowBack isArrow={isArrow} isNew={isNew} handleScrollTo={handleScrollTo}/>
+      <ArrowBack isArrow={isArrow} isNew={isNew} handleScrollTo={handleScrollTo} openPinned={openPinned}/>
       <div id={companionId} ref={chatDivRef} onScroll={debouncedHandleScroll}
-        className={messages.length > 0 ? classes.messagesScroll : classes.messagesEmpty}>
+        className={messagesMemo.length > 0 ? classes.messagesScroll : classes.messagesEmpty}>
         <div className={classes.messagesBody}>
-        {messages.length > 0 ? renderArr.map(({ message, name, lastName, color,pinned,
+        {messagesMemo.length > 0 ? renderArr.map(({ message, name, lastName, color,pinned,
            createdAt,number, type,fullType,caption,emoji,emojiCompanion,_id }) => {
           let isTime
           if (!time) {

+ 23 - 15
src/components/HomePage/CentralBar/HeaderBar/PinnedBar/index.tsx

@@ -20,7 +20,7 @@ import { useState,useEffect} from 'react';
 
 import { TMessage } from '../../../../../typescript/redux/messages/types';
 import { getPinnedMessagesMemo } from '../../../../../redux/pinnedMessages/selector';
-import { firstLetter,slicedWord,prodAwsS3,copied,handleDownload } from '../../../../../helpers';
+import { prodAwsS3,copied,handleDownload } from '../../../../../helpers';
 import { pinMessageById } from '../../../../../api-data';
 
 const useStyles = makeStyles({
@@ -28,7 +28,8 @@ const useStyles = makeStyles({
     marginLeft: 20,
     display: 'flex',
     alignContent: 'center',
-    alignItems:'center'
+    alignItems: 'center',
+    position:'relative'
   },
   iconClose: {
     '&:hover': {
@@ -38,8 +39,19 @@ const useStyles = makeStyles({
   },
   listWrapper: {
     background: '#fdfdfd',
-    padding:0
+    padding: 0,
   },
+  listWrapperDashes: {
+    position: 'absolute',
+    top: 0,
+    width: 2,
+    height: '100%',
+    display: 'flex',
+    flexDirection: 'column',
+    justifyContent:'space-around',
+    flexWrap:'nowrap',
+    listStyle:'none'
+  },  
   overlay: {
     position: 'fixed',
     top: 0,
@@ -83,6 +95,8 @@ const PinnedBar = ({chatDivRef,handleOpenPinned}:IPinnedBar) => {
   const [openedPin, setOpenedPin] = useState<TMessage | null>(null)
   const [openedIndex, setOpenedIndex] = useState<number>(0)
   const [modal, setModal] = useState<boolean>(false)
+  const heightPerDash = 100/pinnedMessagesMemo.length
+  const heightOfDash = heightPerDash-((heightPerDash/100)*20)
   
   const handleActivePin = () => {
     const childNodes = chatDivRef.current.childNodes[0].childNodes
@@ -123,20 +137,14 @@ const PinnedBar = ({chatDivRef,handleOpenPinned}:IPinnedBar) => {
 
   return openedPin ?
     <Stack className={classes.container} direction="row">
+      <ul className={classes.listWrapperDashes}>
+        {pinnedMessagesMemo.length > 1 &&
+          pinnedMessagesMemo.map(({ _id }) =>
+          <li key={_id} style={{backgroundColor:openedPin._id === _id? "#00aeff":"#addbf0",
+            height: `${heightOfDash}%`}}></li>)}
+      </ul>      
       <ul className={classes.listWrapper}>
         <MenuItem onClick={handleActivePin}>
-          <ListItemIcon >
-            <Avatar alt={openedPin.name} src={openedPin.avatarUrl?`${prodAwsS3}/${openedPin.avatarUrl}`:undefined}
-              sx={{ background: openedPin.color, width: 44, height: 44 }}>
-              {!openedPin.avatarUrl&&`${firstLetter(openedPin.name)}${firstLetter(openedPin.lastName)}`}
-            </Avatar>
-          </ListItemIcon>           
-          <ListItemText style={{marginLeft:20}}
-            primary={`${firstLetter(openedPin.name)}${slicedWord(openedPin.name, 15, 1)}
-            ${firstLetter(openedPin.lastName)}${slicedWord(openedPin.lastName, 15, 1)}`}
-            primaryTypographyProps={{fontSize:16 }}
-            secondary={slicedWord(openedPin.message, 20, 1)}
-            secondaryTypographyProps={{fontSize: 12 }} />
           <ListItemText style={{marginLeft:20}}
             primary={`Pinned Message ${openedIndex + 1} of ${pinnedMessagesMemo.length}`}
             primaryTypographyProps={{ color: "#0379af",fontSize:16 }}

+ 3 - 9
src/components/HomePage/CentralBar/index.tsx

@@ -1,5 +1,4 @@
 import Grid from '@mui/material/Grid'
-import { makeStyles } from '@material-ui/core'
 import { useState,useEffect } from 'react'
 import { useSelector,useDispatch } from 'react-redux'
 
@@ -11,20 +10,15 @@ import { getOpenPinned } from '../../../redux/control/selector'
 import { actionOpenPinned } from '../../../redux/control/action'
 import { unpinAllMessagesById } from '../../../api-data'
 
-const useStyles = makeStyles({
-  chatBar: {
-    background: 'linear-gradient(to bottom right, #e7f097 , #b1e667,#f4f75e)',
-  },
-})
 
 interface ICentralBar {
   rightIsOpen: TRightIsOpen,
   chatDivRef: any | null,
   companionId: string,
+  backgroundImage: string,
 }
 
-const CentralBar = ({rightIsOpen,chatDivRef,companionId}:ICentralBar) => {
-  const classes = useStyles()
+const CentralBar = ({rightIsOpen,chatDivRef,companionId,backgroundImage}:ICentralBar) => {
   const dispatch = useDispatch()
   const pinnedMessagesMemo = useSelector(getPinnedMessagesMemo)
   const openPinned = useSelector(getOpenPinned)
@@ -55,7 +49,7 @@ const CentralBar = ({rightIsOpen,chatDivRef,companionId}:ICentralBar) => {
             handleClearSelect={handleClearSelect} setIsSomeSelected={setIsSomeSelected}
             openPinned={openPinned} pinnedMessagesMemo={pinnedMessagesMemo}/>
         </Grid>          
-        <Grid item lg={12} className={classes.chatBar}>
+        <Grid item lg={12} style={{backgroundImage}}>
           <ChatBar chatDivRef={chatDivRef} selectedArr={selectedArr} setSelectedArr={setSelectedArr}
             isSomeSelected={isSomeSelected} setIsSomeSelected={setIsSomeSelected}
             openPinned={openPinned} pinnedMessagesMemo={pinnedMessagesMemo} handleUnpinAll={handleUnpinAll}/>

+ 40 - 18
src/components/HomePage/LeftBar/ChatsList/ChatItem/index.tsx

@@ -12,8 +12,10 @@ import ListItemText from '@mui/material/ListItemText';
 import ListItemIcon from '@mui/material/ListItemIcon';
 import Badge from '@mui/material/Badge';
 import DoneAllIcon from '@mui/icons-material/DoneAll';
+import PushPinIcon from '@mui/icons-material/PushPin';
+import CloseIcon from '@mui/icons-material/Close';
 
-import { muteChat } from '../../../../../api-data';
+import { muteChat,pinChat } from '../../../../../api-data';
 import { TChat } from '../../../../../typescript/redux/chats/types';
 import { firstLetter, slicedWord, timeStampEU,prodAwsS3 } from '../../../../../helpers';
 import DeleteModal from './DeleteModal';
@@ -126,7 +128,7 @@ const useStyles = makeStyles({
     justifyContent: 'center',
     alignContent: 'center',
     fontSize: 12,
-    marginLeft: 'auto',
+    marginLeft: 10,
     '&:hover': {
       outline: 'solid 3px #3ee415',
     }
@@ -144,24 +146,21 @@ const useStyles = makeStyles({
     justifyContent: 'center',
     alignContent: 'center',
     fontSize: 12,
-    marginLeft: 'auto',
+    marginLeft: 10,
     '&:hover': {
       outline: 'solid 3px #cccbcb',
     }
   },
-  listItem_iconRightBtnHidden: {
-    background: 'inherit',
-    borderRadius: '50%',
-    border: 'none',
-    height: 24,
-    width: 24,
-    textAlign: 'center',
+  pinnedIcon: {
+    transform: 'rotate(45deg)',
+    color: '#a7aaa7',
+  },
+  listIconsRightContainer: {
+    marginLeft: 'auto',
     display: 'flex',
     alignItems: 'center',
     justifyContent: 'center',
     alignContent: 'center',
-    fontSize: 12,
-    marginLeft: 'auto', 
   },
   listItem_icon_time: {
     fontSize: 12,
@@ -185,14 +184,22 @@ const useStyles = makeStyles({
        clipPath: 'inset(0 -1ch 0 0)'
     },
   },
+  iconClose: {
+    '&:hover': {
+      transform: 'rotate(180deg)',
+      transition: 'all 250ms ease-out ',
+    }
+  },   
 })
 
 interface IChatItem {
   chat: TChat,
   handleListItemClick: (companionId: string) => void,
-  handleNewMsgs: (e: any,companionId: string) => void,
+  handleNewMsgs: (e: any, companionId: string) => void,
+  id: string,
+  pinned:boolean,
 }
-const  ChatItem = ({chat,handleListItemClick,handleNewMsgs}:IChatItem) => {
+const  ChatItem = ({chat,handleListItemClick,handleNewMsgs,id,pinned}:IChatItem) => {
   const classes = useStyles()
   const [anchorEl, setAnchorEl] = useState<any>(null);
   const [selected, setSelected] = useState<boolean>(false);
@@ -201,6 +208,10 @@ const  ChatItem = ({chat,handleListItemClick,handleNewMsgs}:IChatItem) => {
   const { name, lastName, avatarUrl, color, companionId, mute, seen, total, watched,
     typing, online, lastMessage, lastMessageCreatedAt, createdAt } = chat
 
+  const handlePin = (id: string, pinned:boolean) => {
+    pinChat(id,!pinned)
+    handleClose(undefined)
+  }
   const handleClose = (type: string | undefined): void => {
     if (type === 'mute') muteChat(companionId)
     if (type === 'delete') setModal(true)
@@ -244,10 +255,15 @@ const  ChatItem = ({chat,handleListItemClick,handleNewMsgs}:IChatItem) => {
               <Typography className={classes.listItem_icon_time} variant="h6" color="initial">
                 {timeStampEU(lastMessageCreatedAt?lastMessageCreatedAt:createdAt)}
               </Typography>
-            </div>
-            {lastMessage && total > seen ? <button onClick={(e) => handleNewMsgs(e,companionId)}
-            className={mute?classes.listItem_iconRightBtnMute:classes.listItem_iconRightBtn}>{total-seen}</button> :
-            <button  className={classes.listItem_iconRightBtnHidden}/>}
+          </div>
+          <div className={classes.listIconsRightContainer}>
+            {pinned && <PushPinIcon className={classes.pinnedIcon} fontSize='small' />}
+            {lastMessage && total > seen &&
+              <button onClick={(e) => handleNewMsgs(e, companionId)}
+                className={mute ? classes.listItem_iconRightBtnMute : classes.listItem_iconRightBtn}>
+                {total - seen}
+              </button>}            
+          </div>
           </ListItemIcon>            
         </ListItemButton>
       <StyledMenu
@@ -261,6 +277,12 @@ const  ChatItem = ({chat,handleListItemClick,handleNewMsgs}:IChatItem) => {
           {mute ? <NotificationsNoneIcon /> : <VolumeOffIcon />}
           {mute ? 'Unmute chat':'Mute chat'}
         </MenuItem>
+        <MenuItem onClick={() => handlePin(id,pinned)}>
+            {pinned ?
+              <CloseIcon className={classes.iconClose} /> :
+              <PushPinIcon />}
+             {pinned?'Unpin chat':'Pin chat'}
+        </MenuItem>         
         <MenuItem style={{color:'#f02a2a'}} onClick={() => handleClose('delete')}>
             <DeleteOutlineIcon style={{color:'#f02a2a'}}/>
             Delete chat

+ 23 - 10
src/components/HomePage/LeftBar/ChatsList/index.tsx

@@ -1,6 +1,6 @@
 import List from '@mui/material/List';
 import { makeStyles } from '@material-ui/core'
-import { useEffect,useRef,useCallback } from 'react';
+import { useEffect,useRef,useCallback,useMemo } from 'react';
 import { useSelector, useDispatch } from 'react-redux';
 
 import AlertInfo from '../../../reusableComponents/AlertInfo'
@@ -11,7 +11,7 @@ import { getChatMemo } from '../../../../redux/chat/selector'
 import { asyncGetChatById } from '../../../../redux/chat/operations'
 import { asyncGetChats } from '../../../../redux/chats/operations';
 import { actionRightIsOpen,actionScrollChat,actionOpenPinned } from '../../../../redux/control/action'
-import { TChats } from '../../../../typescript/redux/chats/types';
+import { TChats,TChat } from '../../../../typescript/redux/chats/types';
 import { prodBaseURL,refreshAppTime } from '../../../../helpers';
 
 const useStyles = makeStyles({
@@ -48,29 +48,41 @@ const ChatsList = ({sort}:IChatsList) => {
   const dispatch = useDispatch()
   const chatsRef = useRef<any>(null)
   const { total, chats } = useSelector(getStateMemo)
-  const chat = useSelector(getChatMemo)
+  const chat = useSelector(getChatMemo) 
   
   const handleListItemClick = (companionId: string) => {
     dispatch(actionRightIsOpen(''))
     dispatch(actionOpenPinned(false))
     dispatch(asyncGetChatById(companionId))
-    if(chat.companionId !== companionId) dispatch(actionScrollChat(true))
+    if(chat.companionId !== companionId) setTimeout(() => dispatch(actionScrollChat(true)), 500)
   }
 
   const handleNewMsgs = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, companionId: string) => {
     e.stopPropagation()
-    dispatch(actionScrollChat(true))
     dispatch(actionRightIsOpen(''))
     dispatch(actionOpenPinned(false))
     dispatch(asyncGetChatById(companionId))
+    setTimeout(() => dispatch(actionScrollChat(true)), 500)
   }
 
   const handleNotification = useCallback((companionId: string) => {
     dispatch(asyncGetChatById(companionId))
-    dispatch(actionScrollChat(true))
+    dispatch(actionOpenPinned(false))
+    dispatch(actionRightIsOpen(''))
+    setTimeout(() => dispatch(actionScrollChat(true)), 500)
   }, [dispatch])
 
-  const sortedChats: TChats = sortByRecent(chats, sort)
+  const sortedChats = useMemo((): TChats => {
+    const pinnedArr: any[] = []
+    const sortedAndFilteredArr: TChats = sortByRecent(chats, sort)
+      .filter((el: TChat) => {
+      if (el.pinned === true) {
+        pinnedArr.push(el)
+        return undefined
+      } else return el
+    })
+    return [...pinnedArr,...sortedAndFilteredArr]
+  },[chats,sort])
   
   useEffect(() => {
     const handleReset = () => dispatch(asyncGetChats())
@@ -88,18 +100,19 @@ const ChatsList = ({sort}:IChatsList) => {
         const newDifferent = chat.total - chat.seen
         if (newDifferent > oldDifferent && !chat.mute) {
           playNotificationWithoutPermission(`${prodBaseURL}/telegramReceive.mp3`)
-          notification(chat.name,() => handleNotification(chat.companionId))
+          notification(chat.name, () => handleNotification(chat.companionId))
         } 
       })
     }
     chatsRef.current = sortedChats
-  }, [chat,sortedChats,handleNotification])
+  }, [chat,sortedChats,handleNotification,dispatch])
 
   return total !== '0' ? (
     <List className={classes.list} component="nav"
       aria-label="main mailbox folders">
       {sortedChats.map((el) => <ChatItem key={el.number} chat={el}  
-      handleListItemClick={handleListItemClick} handleNewMsgs={handleNewMsgs} />)}
+        handleListItemClick={handleListItemClick} handleNewMsgs={handleNewMsgs}
+        id={el._id} pinned={el.pinned}/>)}
     </List>
   ):<AlertInfo name='You do not have Chats yet!' />;
 }

+ 28 - 2
src/components/HomePage/LeftBar/ContactsList/ContactItem/index.tsx

@@ -11,8 +11,10 @@ import Avatar from '@mui/material/Avatar';
 import ListItemText from '@mui/material/ListItemText';
 import ListItemIcon from '@mui/material/ListItemIcon';
 import ContentCopyIcon from '@mui/icons-material/ContentCopy';
+import PushPinIcon from '@mui/icons-material/PushPin';
+import CloseIcon from '@mui/icons-material/Close';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
-import {removeContact } from '../../../../../api-data';
+import {removeContact,pinContact } from '../../../../../api-data';
 import { actionRightIsOpen } from '../../../../../redux/control/action';
 import { TContact } from '../../../../../typescript/redux/contacts/types';
 import { TRightIsOpen } from '../../../../../typescript/redux/control/types';
@@ -86,14 +88,27 @@ const useStyles = makeStyles({
     justifyContent: 'flex-start',
     alignContent: 'center',
     alignItems:'center'
+  },
+  iconClose: {
+    '&:hover': {
+      transform: 'rotate(180deg)',
+      transition: 'all 250ms ease-out ',
+    }
+  },
+  pinnedIcon: {
+    marginLeft: 'auto',
+    transform: 'rotate(45deg)',
+    color: '#a7aaa7',
   },  
 })
 interface IContactItem {
   contact: TContact,
   handleListItemClick: (companionId: string) => void,
   rightIsOpen: TRightIsOpen,
+  id: string,
+  pinned: boolean
 }
-const  ContactItem = ({contact,handleListItemClick,rightIsOpen}:IContactItem) => {
+const  ContactItem = ({contact,handleListItemClick,rightIsOpen,id,pinned}:IContactItem) => {
   const classes = useStyles()
   const dispatch = useDispatch()
   const [anchorEl, setAnchorEl] = useState<any>(null);
@@ -102,6 +117,10 @@ const  ContactItem = ({contact,handleListItemClick,rightIsOpen}:IContactItem) =>
   const open = Boolean(anchorEl);
   const { name, lastName, avatarUrl, color, companionId,createdAt, number,_id } = contact
 
+  const handlePin = (id: string, pinned:boolean) => {
+    pinContact(id,!pinned)
+    handleClose(undefined)
+  }
   const handleClose = (type: string | undefined): void => {
     if (type === 'copy') copied('Number')
     if (type === 'delete') setModal(true)
@@ -140,6 +159,7 @@ const  ContactItem = ({contact,handleListItemClick,rightIsOpen}:IContactItem) =>
         <ListItemText primary={`${firstLetter(name)}${slicedWord(name, 15, 1)}
           ${firstLetter(lastName)}${slicedWord(lastName, 15, 1)}`}
           secondary={`Registered since ${timeStampEU(createdAt)}`} />
+        {pinned && <PushPinIcon className={classes.pinnedIcon} fontSize='small' />}
       </ListItemButton>      
       <StyledMenu
         id="demo-positioned-menu"
@@ -154,6 +174,12 @@ const  ContactItem = ({contact,handleListItemClick,rightIsOpen}:IContactItem) =>
              Copy number
           </MenuItem>
         </CopyToClipboard>
+        <MenuItem onClick={() => handlePin(id,pinned)}>
+            {pinned ?
+              <CloseIcon className={classes.iconClose} /> :
+              <PushPinIcon />}
+             {pinned?'Unpin contact':'Pin contact'}
+        </MenuItem>         
         <MenuItem style={{color:'#f02a2a'}} onClick={() => handleClose('delete')}>
             <DeleteOutlineIcon style={{color:'#f02a2a'}}/>
             Delete contact

+ 27 - 18
src/components/HomePage/LeftBar/ContactsList/index.tsx

@@ -1,11 +1,11 @@
 import List from '@mui/material/List';
 import { makeStyles } from '@material-ui/core'
 import { useSelector, useDispatch } from 'react-redux';
-import { useEffect } from 'react';
+import { useEffect,useMemo } from 'react';
 
 import AlertInfo from '../../../reusableComponents/AlertInfo'
 import ContactItem from './ContactItem';
-import { getState } from '../../../../redux/contacts/selector'
+import { getStateMemo } from '../../../../redux/contacts/selector'
 import { asyncGetContacts } from '../../../../redux/contacts/operations';
 import { asyncStartChatById } from '../../../../redux/chat/operations'
 import { getRightIsOpen } from '../../../../redux/control/selector'
@@ -48,19 +48,9 @@ interface IContactList {
 const  ContactsList = ({value,handleClick,sort,date,setDisabled} : IContactList) => {
   const classes = useStyles()
   const dispatch = useDispatch()
-  const { total, contacts } = useSelector(getState)
+  const { total, contacts } = useSelector(getStateMemo)
   const rightIsOpen = useSelector(getRightIsOpen)
 
-  const filteredContacts = ():TContacts => handleSort('name', contacts, sort).filter((el:TContact) => {
-    const credentials = el.name + ' ' + el.lastName
-      if (!date) {
-        return credentials.toLowerCase().includes(value.toLowerCase())
-      } else if (credentials.toLowerCase().includes(value.toLowerCase())
-        && timeStampFilter(date) === timeStampFilter(el.createdAt)) {
-        return el
-    }
-  })
-
   const handleListItemClick = (companionId: string) => {
     handleClick()
     dispatch(actionRightIsOpen(''))
@@ -68,8 +58,6 @@ const  ContactsList = ({value,handleClick,sort,date,setDisabled} : IContactList)
     dispatch(asyncStartChatById(companionId))
   }
 
-  const arr = filteredContacts()
-
   useEffect(() => {
     dispatch(actionLeftIsOpen('contacts'))
   }, [dispatch])    
@@ -83,14 +71,35 @@ const  ContactsList = ({value,handleClick,sort,date,setDisabled} : IContactList)
     handleReset()
     const idInterval = setInterval(handleReset, refreshAppTime);
     return () => clearInterval(idInterval);
-  }, [dispatch]);   
+  }, [dispatch]);
+
+  const filteredContacts = useMemo((): TContacts => {
+    const pinnedArr: any[] = []
+    const sortedAndFilteredArr: TContacts = handleSort('name', contacts, sort)
+      .filter((el: TContact) => {
+      const credentials = el.name + ' ' + el.lastName
+        if (!date) {
+          return credentials.toLowerCase().includes(value.toLowerCase())
+        } else if (credentials.toLowerCase().includes(value.toLowerCase())
+          && timeStampFilter(date) === timeStampFilter(el.createdAt)) {
+        return el
+      } else return undefined
+    }).filter((el: TContact) => {
+      if (el.pinned === true) {
+        pinnedArr.push(el)
+        return undefined
+      } else return el
+    })
+    return [...pinnedArr,...sortedAndFilteredArr]
+  },[contacts,date,value,sort])  
   
   return total !== '0' ? (
     <List
       className={classes.list} component="nav"
       aria-label="main mailbox folders">
-      {arr.length > 0 ? arr.map((contact) => <ContactItem key={contact.number}
-        contact={contact} handleListItemClick={handleListItemClick} rightIsOpen={rightIsOpen}/>) :
+      {filteredContacts.length > 0 ? filteredContacts.map((contact) => <ContactItem key={contact.number}
+        contact={contact} handleListItemClick={handleListItemClick}
+        rightIsOpen={rightIsOpen} id={contact._id} pinned={contact.pinned} />) :
         <AlertInfo name={`Can not find Contact by request : ${value}`} />}
       </List>
   ):<AlertInfo name='You do not have Contact yet!' />;

+ 8 - 3
src/components/HomePage/LeftBar/SearchLists/AudioList/index.tsx

@@ -5,7 +5,7 @@ import ListItemAvatar from '@mui/material/ListItemAvatar';
 import LibraryMusicIcon from '@mui/icons-material/LibraryMusic';
 import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
-import { useEffect } from 'react';
+import { useEffect, useMemo } from 'react';
 
 import AlertInfo from '../../../../reusableComponents/AlertInfo';
 import { timeStampEU,handleDownload,filteredMessages,handleSort,prodAwsS3 } from '../../../../../helpers'
@@ -60,8 +60,13 @@ interface IAudioList {
 
 const AudioList = ({ messagesMemo,value,date,sort,setDisabled,handleScrollToTheMessage }: IAudioList) => {
   const classes = useStyles()
-  const filtered =  messagesMemo.filter(({type}) => type === 'audio')
-  const filteredAndSorted = filteredMessages(handleSort('createdAt', filtered, sort), date,value)
+
+  const filtered =  useMemo(() => {
+    return messagesMemo.filter(({type}:{type:string}) => type === 'audio')
+    }, [messagesMemo])
+  const filteredAndSorted = useMemo(() => {
+    return filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  },[filtered,sort,date,value])  
   
   useEffect(() => {
     setDisabled(filtered.length > 0?false:true)

+ 8 - 3
src/components/HomePage/LeftBar/SearchLists/FilesList/index.tsx

@@ -5,7 +5,7 @@ import ListItemAvatar from '@mui/material/ListItemAvatar';
 import FolderIcon from '@mui/icons-material/Folder';
 import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
-import { useEffect } from 'react';
+import { useEffect,useMemo } from 'react';
 
 import AlertInfo from '../../../../reusableComponents/AlertInfo';
 import { timeStampEU,handleDownload,filteredMessages,handleSort,prodAwsS3 } from '../../../../../helpers'
@@ -60,8 +60,13 @@ interface IFilesList {
 
 const FilesList = ({ messagesMemo,value,date,sort,setDisabled,handleScrollToTheMessage }: IFilesList) => {
   const classes = useStyles()
-  const filtered =  messagesMemo.filter(({type}) => type !== 'text')
-  const filteredAndSorted = filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+
+  const filtered =  useMemo(() => {
+    return messagesMemo.filter(({type}:{type:string}) => type !== 'text')
+    }, [messagesMemo])
+  const filteredAndSorted = useMemo(() => {
+    return filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  },[filtered,sort,date,value])
   
   useEffect(() => {
     setDisabled(filtered.length > 0?false:true)

+ 8 - 3
src/components/HomePage/LeftBar/SearchLists/MediaList/index.tsx

@@ -1,6 +1,6 @@
 import ImageList from '@mui/material/ImageList';
 import { makeStyles } from '@material-ui/core'
-import { useEffect } from 'react';
+import { useEffect,useMemo } from 'react';
 
 import MediaListItem from './MediaListItem';
 import AlertInfo from '../../../../reusableComponents/AlertInfo';
@@ -43,8 +43,13 @@ interface IMediaList {
 
 const MediaList = ({ messagesMemo,value,date,sort,setDisabled,handleScrollToTheMessage }: IMediaList) => {
   const classes = useStyles()
-  const filtered =  messagesMemo.filter(({type}) => type === 'image')
-  const filteredAndSorted = filteredMessages(handleSort('createdAt', filtered, sort), date, value)
+
+  const filtered =  useMemo(() => {
+    return messagesMemo.filter(({type}:{type:string}) => type === 'image')
+    }, [messagesMemo])
+  const filteredAndSorted = useMemo(() => {
+    return filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  },[filtered,sort,date,value])
   
   useEffect(() => {
     setDisabled(filtered.length > 0?false:true)

+ 8 - 3
src/components/HomePage/LeftBar/SearchLists/TextList/index.tsx

@@ -7,7 +7,7 @@ import Divider from '@mui/material/Divider';
 import ContentCopyIcon from '@mui/icons-material/ContentCopy';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 import { makeStyles } from '@material-ui/core'
-import { useEffect } from 'react';
+import { useEffect,useMemo } from 'react';
 
 import AlertInfo from '../../../../reusableComponents/AlertInfo';
 import { timeStampEU,firstLetter,copied,filteredMessages,handleSort,prodAwsS3 } from '../../../../../helpers'
@@ -62,8 +62,13 @@ interface ITextList {
 
 const TextList = ({ messagesMemo,value,date,sort,setDisabled,handleScrollToTheMessage }: ITextList) => {
   const classes = useStyles()
-  const filtered =  messagesMemo.filter(({type}) => type === 'text')
-  const filteredAndSorted = filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+
+  const filtered =  useMemo(() => {
+    return messagesMemo.filter(({type}:{type:string}) => type === 'text')
+    }, [messagesMemo])
+  const filteredAndSorted = useMemo(() => {
+    return filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  },[filtered,sort,date,value])
   
   useEffect(() => {
     setDisabled(filtered.length > 0?false:true)

+ 9 - 3
src/components/HomePage/LeftBar/SearchLists/VideoList/index.tsx

@@ -5,7 +5,7 @@ import ListItemAvatar from '@mui/material/ListItemAvatar';
 import VideoLibraryIcon from '@mui/icons-material/VideoLibrary';
 import Divider from '@mui/material/Divider';
 import { makeStyles } from '@material-ui/core'
-import { useEffect } from 'react';
+import { useEffect,useMemo } from 'react';
 
 import AlertInfo from '../../../../reusableComponents/AlertInfo';
 import { timeStampEU,handleDownload,filteredMessages,handleSort,prodAwsS3 } from '../../../../../helpers'
@@ -60,8 +60,14 @@ interface IVideoList {
 
 const VideoList = ({ messagesMemo,value,date,sort,setDisabled,handleScrollToTheMessage }: IVideoList) => {
   const classes = useStyles()
-  const filtered =  messagesMemo.filter(({type}) => type === 'video')
-  const filteredAndSorted = filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  
+  const filtered =  useMemo(() => {
+    return messagesMemo.filter(({type}:{type:string}) => type === 'video')
+    }, [messagesMemo])
+  const filteredAndSorted = useMemo(() => {
+    return filteredMessages(handleSort('createdAt', filtered, sort),date,value)
+  },[filtered,sort,date,value])
+  
   useEffect(() => {
     setDisabled(filtered.length > 0?false:true)
   }, [filtered, setDisabled])

+ 15 - 14
src/components/HomePage/LeftBar/SearchLists/index.tsx

@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect,useMemo } from 'react';
 import { useDispatch,useSelector } from 'react-redux';
 import { makeStyles } from '@material-ui/core'
 
@@ -17,7 +17,6 @@ import { sortByRecent,timeStampFilter,refreshAppTime } from '../../../../helpers
 import { asyncStartChatById } from '../../../../redux/chat/operations';
 import { getPinnedMessagesMemo } from '../../../../redux/pinnedMessages/selector';
 import { actionLeftIsOpen,actionRightIsOpen,actionOpenPinned } from '../../../../redux/control/action';
-import { TChats } from '../../../../typescript/redux/chats/types';
 
 const useStyles = makeStyles({
 container: {
@@ -67,7 +66,7 @@ const SearchLists = ({ value,setValue,sort,date,setDate,setDisabled,chatDivRef}:
     const { chats, total } = useSelector(getStateMemo)
     const messagesMemo = useSelector(getAllMessagesMemo)
     const pinnedMessagesMemo = useSelector(getPinnedMessagesMemo)
-    const {leftIsOpen,rightIsOpen,openPinned} = useSelector(getState)
+    const { leftIsOpen,rightIsOpen,openPinned } = useSelector(getState)
     const [isActive, setIsActive] = useState<number>(0)
     const handleIsActive = (newValue: number): void => {
       setIsActive(newValue)
@@ -114,16 +113,6 @@ const SearchLists = ({ value,setValue,sort,date,setDate,setDisabled,chatDivRef}:
       }, 3000)
       }
     }  
-    const filteredChats = (arr: TChats) => arr.filter((el) => {
-      const credentials = el.name + ' ' + el.lastName
-      if (!date) {
-         return credentials.toLowerCase().includes(value.toLowerCase())
-      } else if (credentials.toLowerCase().includes(value.toLowerCase())
-        &&timeStampFilter(date) === timeStampFilter(el.lastMessageCreatedAt ?
-        el.lastMessageCreatedAt : el.createdAt)) {
-        return el
-      }
-    })
   
     useEffect(() => {
        setDate('')
@@ -155,7 +144,19 @@ const SearchLists = ({ value,setValue,sort,date,setDate,setDisabled,chatDivRef}:
     }, [leftIsOpen,dispatch]);
     
   
-    const filteredAndSorted = filteredChats(sortByRecent(chats,sort))
+  const filteredAndSorted = useMemo(() => {
+      return sortByRecent(chats,sort).filter((el) => {
+      const credentials = el.name + ' ' + el.lastName
+      if (!date) {
+         return credentials.toLowerCase().includes(value.toLowerCase())
+      } else if (credentials.toLowerCase().includes(value.toLowerCase())
+        &&timeStampFilter(date) === timeStampFilter(el.lastMessageCreatedAt ?
+        el.lastMessageCreatedAt : el.createdAt)) {
+        return el
+      } else return undefined
+    })
+  }, [chats, date, value, sort])
+  
     return (
     <>
         <div className={classes.container}>

+ 11 - 9
src/components/HomePage/RightBar/CredentialsList/ProfileLists/index.tsx

@@ -1,4 +1,4 @@
-import { useState,useEffect } from 'react';
+import { useState,useEffect,useMemo } from 'react';
 import { useSelector } from 'react-redux';
 import { makeStyles } from '@material-ui/core'
 
@@ -12,7 +12,7 @@ import { getPinnedMessagesMemo } from '../../../../../redux/pinnedMessages/selec
 import { getMessagesMemo } from '../../../../../redux/messages/selector'
 import { handleSort } from '../../../../../helpers';
 import { getChat } from '../../../../../redux/chat/selector'
-import { TMessages } from '../../../../../typescript/redux/messages/types'
+import { TMessages,TMessage } from '../../../../../typescript/redux/messages/types'
 
 const useStyles = makeStyles({
 container: {
@@ -46,6 +46,8 @@ underline: {
   },
 })
 
+const filterBy = ['text', 'image', 'text', 'audio', 'video']
+
 interface IProfileLists {
   setDisabled: React.Dispatch<boolean>,
   chatDivRef: any | null,
@@ -56,8 +58,9 @@ const ProfileLists = ({setDisabled,chatDivRef}:IProfileLists) => {
     const { sort } = useSelector(getChat)
     const openPinned = useSelector(getOpenPinned)
     const messagesMemo = useSelector(getMessagesMemo)
-    const pinnedMessages = useSelector(getPinnedMessagesMemo)
+    const pinnedMessagesMemo = useSelector(getPinnedMessagesMemo)
     const [isActive, setIsActive] = useState<number>(0)
+  
     const handleIsActive = (newValue: number): void => setIsActive(newValue)
     const handleScrollToTheMessage = (_id: string) => {
       const childNodes = chatDivRef.current.childNodes[0].childNodes
@@ -70,18 +73,17 @@ const ProfileLists = ({setDisabled,chatDivRef}:IProfileLists) => {
           toScrollNode.style.boxShadow = 'unset'
         }, 2000)
       }
-    }
-    const filterBy = ['text', 'image', 'text', 'audio', 'video']
+  }
   
-    const sorted: TMessages = handleSort('createdAt', !openPinned?messagesMemo:pinnedMessages, sort)
-    const filteredAndSorted = sorted.filter((el) => {
+  const filteredAndSorted: TMessages = useMemo(() => handleSort('createdAt', !openPinned ? messagesMemo : pinnedMessagesMemo, sort)
+    .filter((el:TMessage) => {
       if (isActive !== 0) {
         if(el.type === filterBy[isActive]) return el
       } else {
         if(el.type !== filterBy[isActive]) return el
       }
-    })
-  
+    }),[isActive,messagesMemo,openPinned,pinnedMessagesMemo,sort])
+
     useEffect(() => {
       setDisabled(filteredAndSorted.length > 0?false:true)
     }, [filteredAndSorted, setDisabled])

+ 13 - 14
src/components/HomePage/RightBar/SearchList/index.tsx

@@ -1,6 +1,6 @@
 import { makeStyles } from '@material-ui/core'
 import { useSelector } from 'react-redux'
-import React, { useState } from 'react'
+import { useState,useMemo } from 'react'
 import List from '@mui/material/List';
 import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
@@ -10,12 +10,12 @@ import Typography from '@mui/material/Typography';
 import Divider from '@mui/material/Divider';
 import Search from './Search'
 import AlertInfo from "../../../reusableComponents/AlertInfo";
-import { getMessages } from '../../../../redux/messages/selector'
+import { getMessagesMemo } from '../../../../redux/messages/selector'
 import { getOpenPinned } from '../../../../redux/control/selector';
 import { getPinnedMessagesMemo } from '../../../../redux/pinnedMessages/selector'
 import { getChat } from '../../../../redux/chat/selector'
 import { timeStampEU, timeStampFilter, firstLetter, slicedWord, handleSort,prodAwsS3 } from '../../../../helpers'
-import { TMessages } from '../../../../typescript/redux/messages/types';
+import { TMessages,TMessage } from '../../../../typescript/redux/messages/types';
 
 const useStyles = makeStyles({
   container: {
@@ -59,8 +59,8 @@ const SearchList= ({chatDivRef}:ISearchList) => {
     const classes = useStyles()
     const { sort } = useSelector(getChat)
     const openPinned = useSelector(getOpenPinned)
-    const messages = useSelector(getMessages)
-    const pinnedMessages = useSelector(getPinnedMessagesMemo)
+    const messagesMemo = useSelector(getMessagesMemo)
+    const pinnedMessagesMemo = useSelector(getPinnedMessagesMemo)
     const [value, setValue] = useState<string>('')
     const [date, setDate] = useState<any>('');
     const handleSearch = (e: React.ChangeEvent<HTMLInputElement>): void => setValue(e.target.value)
@@ -76,26 +76,25 @@ const SearchList= ({chatDivRef}:ISearchList) => {
         }, 2000)
       }
     }
-
-    const filteredMessages = (arr:TMessages) => arr.filter((el) => {
+  
+  const filteredAndSorted: TMessages = useMemo(() => handleSort('createdAt', !openPinned ? messagesMemo : pinnedMessagesMemo, sort)
+    .filter((el: TMessage) => {
       if (!date) {
         return el.message.toLowerCase().includes(value.toLowerCase())
       } else if (el.message.toLowerCase().includes(value.toLowerCase())
         && timeStampFilter(date) === timeStampFilter(el.createdAt)) {
         return el
-      }
-    })
-  
-  const arr: TMessages = filteredMessages(handleSort('createdAt', !openPinned?messages:pinnedMessages, sort))
+      } return undefined
+    }),[messagesMemo,date,sort,value,openPinned,pinnedMessagesMemo]) 
   
 return (
    <div className={classes.container}>
     <Search handleSearch={handleSearch} value={value}
       setDate={setDate} date={date} />
-     <div className={messages.length > 0 ?classes.list:undefined}>
-      {messages.length > 0 ? arr.length > 0 ?
+     <div className={messagesMemo.length > 0 ?classes.list:undefined}>
+      {messagesMemo.length > 0 ? filteredAndSorted.length > 0 ?
         <List sx={{ width: '100%' }}>
-          {arr.map(({ name, lastName, avatarUrl, color, message, createdAt,_id }) =>
+          {filteredAndSorted.map(({ name, lastName, avatarUrl, color, message, createdAt,_id }) =>
           <div key={createdAt}>
               <ListItem onClick={() => handleScrollToTheMessage(_id)}
                 alignItems="flex-start" className={classes.listItem}>

+ 7 - 5
src/components/HomePage/index.tsx

@@ -7,6 +7,9 @@ import CentralBar from './CentralBar'
 import RightBar from './RightBar'
 import { getRightIsOpen } from '../../redux/control/selector'
 import { getChatMemo } from '../../redux/chat/selector'
+import { getNightMode } from '../../redux/authorization/selector'
+import wallpaper from '../../img/wallpaper.jpg'
+import wallpaperNight from '../../img/wallpaperNight.jpg'
 
 
 const useStyles = makeStyles({
@@ -17,16 +20,15 @@ const useStyles = makeStyles({
   centralAndRight: {
     display:'flex'
   },
-  centralBar: {
-    background: 'linear-gradient(to bottom right, #e7f097 , #b1e667,#f4f75e)',
-  },  
 })
 
 const HomePage = () => {
   const classes = useStyles()
   const rightIsOpen = useSelector(getRightIsOpen)
   const chatDivRef = useRef<any | null>(null)
+  const nightMode = useSelector(getNightMode)
   const { companionId } = useSelector(getChatMemo)
+  const backgroundImage =  `url(${nightMode ? wallpaperNight : wallpaper})`
  
 return (
     <Grid className={classes.container} container spacing={0} >
@@ -34,10 +36,10 @@ return (
       {companionId ?
       <Grid item lg={9} className={classes.centralAndRight}>
         <CentralBar rightIsOpen={rightIsOpen} chatDivRef={chatDivRef}
-          companionId={companionId} />
+          companionId={companionId} backgroundImage={backgroundImage}/>
         <RightBar rightIsOpen={rightIsOpen} chatDivRef={chatDivRef} />
       </Grid> :
-      <Grid item lg={9} className={classes.centralBar}/>}
+      <Grid item lg={9} style={{backgroundImage}}/>}
     </Grid>
     )
 }

+ 1 - 1
src/helpers/index.ts

@@ -120,7 +120,7 @@ const handleSort = (sortBy: string, data: any,sort:boolean): any => {
       }
       return 0;
     });
-};
+}
 
 const sortByRecent = (chats:TChats,sort:boolean) => [...chats].sort((a, b) => {
   const aCreatedAt = a.lastMessageCreatedAt ? a.lastMessageCreatedAt : a.createdAt

BIN
src/img/clipart289625.png


+ 0 - 5
src/img/double-check-svgrepo-com.svg

@@ -1,5 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" fill="#03bd03" xmlns="http://www.w3.org/2000/svg">
-<path d="M1.5 12.5L5.57574 16.5757C5.81005 16.8101 6.18995 16.8101 6.42426 16.5757L9 14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
-<path d="M16 7L12 11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
-<path d="M7 12L11.5757 16.5757C11.8101 16.8101 12.1899 16.8101 12.4243 16.5757L22 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
-</svg>

BIN
src/img/telegram.png


BIN
src/img/videoPoster.png


BIN
src/img/wallpaper.jpg


BIN
src/img/wallpaperNight.jpg


+ 1 - 1
src/redux/authorization/operations/index.ts

@@ -9,7 +9,7 @@ import {
 import { setToken, loginUser, logoutUser, updateCredentials, updateUserAvatar, currentUser } from '../../../api-data';
 import { IAuthorizationState } from '../../../typescript/redux/authorization/interfaces'
 
-const asyncCreateUser = (name:string, lastName: string,file:object) => async (dispatch:any) => {
+const asyncCreateUser = (name:string, lastName: string,file:object | null) => async (dispatch:any) => {
   try {
     const data = await updateCredentials<{token:string}>({ name, lastName, originalName:name, originalLastName:lastName})
     if(data&&data.token) dispatch(actionLogInSuccess(data.token))    

+ 3 - 2
src/redux/authorization/selector/index.ts

@@ -7,7 +7,8 @@ const getLastName = (state: IState) => state.authorization.lastName;
 const getCountry = (state: IState) => state.authorization.country;
 const getAvatarUrl = (state: IState) => state.authorization.avatarUrl;
 const getId = (state: IState) => state.authorization._id;
-const getSort= (state:IState) => state.authorization.sort;
+const getSort = (state: IState) => state.authorization.sort;
+const getNightMode = (state: IState) => state.authorization.nightMode;
 const getAuthorizationState= (state:IState) => state.authorization;
 
-export { getToken,getNumber,getName,getLastName,getCountry,getAvatarUrl,getId,getSort,getAuthorizationState };
+export { getToken,getNumber,getName,getLastName,getCountry,getAvatarUrl,getId,getSort,getNightMode,getAuthorizationState };

+ 2 - 1
src/redux/chat/reducer/index.ts

@@ -27,7 +27,8 @@ const initialState: TChat = {
      watched: false,
      typing: false,
      number: '',
-     country:'',
+     country: '',
+     pinned: false,
      _id: '',
      companionId: '',
      owner: '',

+ 3 - 2
src/redux/contacts/selector/index.ts

@@ -5,8 +5,9 @@ const getTotal = (state: IState) => state.contacts.total;
 const getLimit = (state:IState) => state.contacts.limit;
 const getPage = (state: IState) => state.contacts.page;
 const getContacts = (state: IState) => state.contacts.contacts;
-const getState = (state: IState) => state.contacts;
+const getState = (state: IState) => state.contacts; 
 
 const getContactsMemo = createSelector([getContacts], state => state);
+const getStateMemo = createSelector([getState], state => state);
 
-export { getTotal,getLimit,getPage,getContacts,getState,getContactsMemo };
+export { getTotal,getLimit,getPage,getContacts,getState,getContactsMemo,getStateMemo };

+ 1 - 0
src/typescript/redux/chat/types.ts

@@ -17,6 +17,7 @@ export type TChat = {
   typing: boolean,
   number: string,
   country: string,
+  pinned: boolean,
   _id: string,
   companionId: string,
   owner: any,

+ 2 - 1
src/typescript/redux/chats/types.ts

@@ -15,7 +15,8 @@ export type TChat = {
   total: number,
   watched: boolean,
   typing: boolean,
-  number:string,
+  number: string,
+  pinned: boolean,
   _id: string,
   companionId: string,
   owner: any,

+ 1 - 0
src/typescript/redux/contacts/types.ts

@@ -9,6 +9,7 @@ export type TContact = {
   lastName: string,
   name: string,
   number: string,
+  pinned: boolean,
   owner: {
     _id: string,
   },