Created
May 6, 2021 16:17
-
-
Save MohammedALREAI/6e49e9dc4842d61080e26a6d2f4deb29 to your computer and use it in GitHub Desktop.
chat js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import FuseScrollbars from '@fuse/core/FuseScrollbars'; | |
import Avatar from '@material-ui/core/Avatar'; | |
import Icon from '@material-ui/core/Icon'; | |
import Paper from '@material-ui/core/Paper'; | |
import { makeStyles } from '@material-ui/core/styles'; | |
import Typography from '@material-ui/core/Typography'; | |
import clsx from 'clsx'; | |
import moment from 'moment/moment'; | |
import React, { useEffect, useRef, useState } from 'react'; | |
import { useDispatch, useSelector } from 'react-redux'; | |
import * as Actions from './store/actions'; | |
import ChatEditor from './ChatEditor'; | |
import ChatInformations from './ChatInformations'; | |
import ReactHtmlParser from 'react-html-parser'; | |
import VideoChatComponent from "app/main/apps/video-call/VideoChatComponent"; | |
import {useContainerDimensions} from 'app/main/components/tools/useResize'; | |
import {useHover} from 'app/main/components/tools/useHover'; | |
import { InlineIcon } from '@iconify/react'; | |
import baselineMoreHoriz from '@iconify-icons/ic/baseline-more-horiz'; | |
import Box from '@material-ui/core/Box'; | |
import Popover from '@material-ui/core/Popover'; | |
import PopupState, { bindTrigger, bindPopover } from 'material-ui-popup-state'; | |
import List from '@material-ui/core/List'; | |
import ListItem from '@material-ui/core/ListItem'; | |
import ListItemIcon from '@material-ui/core/ListItemIcon'; | |
import ListItemText from '@material-ui/core/ListItemText'; | |
import DraftsIcon from '@material-ui/icons/Drafts'; | |
import SendIcon from '@material-ui/icons/Send'; | |
import { HowToVoteRounded } from '@material-ui/icons'; | |
const useStyles = makeStyles(theme => ({ | |
moreOptionsContact: { | |
position: 'absolute', | |
right: '-16px', | |
}, | |
moreOptionsMe: { | |
position: 'absolute', | |
left: '-16px', | |
}, | |
infos:{ | |
background: 'white', | |
position: 'fixed', | |
height: '100%', | |
right: 0, | |
}, | |
messageRow: { | |
'&.contact': { | |
'& .bubble': { | |
backgroundColor: theme.palette.primary.main, | |
color: theme.palette.primary.contrastText, | |
borderTopLeftRadius: 5, | |
borderBottomLeftRadius: 5, | |
borderTopRightRadius: 20, | |
borderBottomRightRadius: 20, | |
maxWidth: '80%', | |
'& .time': { | |
marginLeft: 12 | |
} | |
}, | |
'&.first-of-group': { | |
'& .bubble': { | |
borderTopLeftRadius: 20 | |
} | |
}, | |
'&.last-of-group': { | |
'& .bubble': { | |
borderBottomLeftRadius: 20 | |
} | |
} | |
}, | |
'&.me': { | |
paddingLeft: 40, | |
'& .avatar': { | |
order: 2, | |
margin: '0 0 0 16px' | |
}, | |
'& .bubble': { | |
marginLeft: 'auto', | |
backgroundColor: theme.palette.grey[300], | |
color: theme.palette.getContrastText(theme.palette.grey[300]), | |
borderTopLeftRadius: 20, | |
borderBottomLeftRadius: 20, | |
borderTopRightRadius: 5, | |
borderBottomRightRadius: 5, | |
'& .time': { | |
justifyContent: 'flex-end', | |
right: 0, | |
marginRight: 12 | |
}, | |
maxWidth: '80%', | |
}, | |
'&.first-of-group': { | |
'& .bubble': { | |
borderTopRightRadius: 20 | |
} | |
}, | |
'&.last-of-group': { | |
'& .bubble': { | |
borderBottomRightRadius: 20 | |
} | |
} | |
}, | |
'&.contact + .me, &.me + .contact': { | |
paddingTop: 20, | |
marginTop: 20 | |
}, | |
'&.first-of-group': { | |
'& .bubble': { | |
borderTopLeftRadius: 20, | |
paddingTop: 13 | |
} | |
}, | |
'&.last-of-group': { | |
'& .bubble': { | |
borderBottomLeftRadius: 20, | |
paddingBottom: 13, | |
'& .time': { | |
display: 'flex' | |
} | |
} | |
} | |
}, | |
sendingMessageZone: { | |
background: theme.palette.background.white | |
} | |
})); | |
function Chat(props) { | |
const dispatch = useDispatch(); | |
const contacts = useSelector(({ chatApp }) => chatApp.contacts.entities); | |
const selectedContactId = useSelector(({ chatApp }) => chatApp.contacts.selectedContactId); | |
const chat = useSelector(({ chatApp }) => chatApp.chat); | |
const user = useSelector(({ chatApp }) => chatApp.user); | |
const [widthInfo, setWidthInfo] = useState('400px'); | |
const [showMoreOptions, setShowMoreOptions] = useState(false); | |
//const [hoverRef, isHovered] = useHover(); | |
const [hover,setHover]=React.useState({}) | |
const classes = useStyles(props); | |
const chatRef = useRef(null); | |
const [messageText, setMessageText] = useState(''); | |
const [showDots,setShowDots]=React.useState(false) | |
const chatInfosOpen = useSelector(({ chatApp }) => chatApp.sidebars.chatInfosOpen); | |
const componentRef = useRef() | |
const { width, } = useContainerDimensions(componentRef) | |
useEffect(() => { | |
if (chat) { | |
scrollToBottom(); | |
} | |
console.log("width:",width) | |
}, [chat, width]); | |
function scrollToBottom() { | |
chatRef.current.scrollTop = chatRef.current.scrollHeight; | |
} | |
function shouldShowContactAvatar(item, i) { | |
return ( | |
item.who === selectedContactId && | |
((chat.dialog[i + 1] && chat.dialog[i + 1].who !== selectedContactId) || !chat.dialog[i + 1]) | |
); | |
} | |
function isFirstMessageOfGroup(item, i) { | |
return i === 0 || (chat.dialog[i - 1] && chat.dialog[i - 1].who !== item.who); | |
} | |
function isLastMessageOfGroup(item, i) { | |
return i === chat.dialog.length - 1 || (chat.dialog[i + 1] && chat.dialog[i + 1].who !== item.who); | |
} | |
function onMessageSubmit(ev) { | |
ev.preventDefault(); | |
if (messageText === '') { | |
return; | |
} | |
dispatch(Actions.sendMessage(messageText, chat.id, user.id)).then(() => { | |
setMessageText(''); | |
}); | |
} | |
const [active, setActive] = useState(-1); | |
const [myItem ,setMyItem]=React.useState( { | |
currentItem: undefined, | |
isHover:Array(10).fill(false), | |
data:chat.dialog?chat.dialog :[] | |
}) | |
const showModel=(id)=> { | |
const currentItemId = id !== myItem.currentItem ? id : undefined | |
setMyItem({ currentItemId }) | |
}; | |
const mouseOver=(i) =>{ | |
return () => { | |
if (myItem.isHover[i] === true) { | |
return myItem; | |
} | |
let isHover = [...myItem.isHover] | |
isHover[i] = true; | |
setMyItem({ ...myItem, isHover }); | |
} | |
} | |
const mouseExit=()=> { | |
if (myItem.isHover === false) { | |
return myItem; | |
} | |
setMyItem({ ...myItem, isHover: false }); | |
} | |
return ( | |
<div className={clsx('flex flex-col relative', props.className)}> | |
<div style={{width: chatInfosOpen ? `calc(100% - ${widthInfo})` : '100%', | |
overflow:'overlay' | |
}}> | |
<FuseScrollbars ref={chatRef} | |
className="flex flex-1 flex-col md:flex-row container overflow-y-auto"> | |
{chat && chat.dialog.length > 0 ? ( | |
<> | |
<VideoChatComponent /> | |
<div className="flex flex-col flex flex-1 flex-col min-w-0 pt-16 px-16 ltr:pl-56 rtl:pr-56 pb-40"> | |
{chat.dialog.map((item, i) => { | |
const contact = | |
item.who === user.id ? user : contacts.find(_contact => _contact.id === item.who); | |
return ( | |
<div | |
key={item.time} | |
className={clsx( | |
classes.messageRow, | |
'flex flex-col flex-grow-0 flex-shrink-0 items-start justify-end relative px-16 pb-4', | |
{ me: item.who === user.id }, | |
{ contact: item.who !== user.id }, | |
{ 'first-of-group': isFirstMessageOfGroup(item, i) }, | |
{ 'last-of-group': isLastMessageOfGroup(item, i) }, | |
i + 1 === chat.dialog.length && 'pb-128' | |
)} | |
//ref={hoverRef} | |
onMouseOver={mouseOver(i)} | |
onMouseLeave={mouseExit} | |
isHover={myItem.isHover[i]} | |
> | |
{ shouldShowContactAvatar(item, i) && ( | |
<Avatar | |
className="avatar absolute ltr:left-0 rtl:right-0 m-0 -mx-32 bg-green" | |
src={contact.avatar} | |
/> | |
)} | |
<div className={`bubble flex relative items-center justify-center p-12 max-w-full bg-black ${i %2===0 ? "bg-red-200":"bg-green"}`}> | |
<div className="leading-tight whitespace-pre-wrap">{ReactHtmlParser(item.message)}</div> | |
{<div className={item.who !== user.id ? classes.moreOptionsContact : classes.moreOptionsMe}> | |
{ myItem.currentItem && | |
<PopupState variant="popover" popupId="demo-popup-popover"> | |
{(popupState) => ( | |
<div> | |
<InlineIcon icon={baselineMoreHoriz} color={"black"} {...bindTrigger(popupState)} /> | |
<Popover | |
{...bindPopover(popupState)} | |
anchorOrigin={{ | |
vertical: 'bottom', | |
horizontal: 'center', | |
}} | |
transformOrigin={{ | |
vertical: 'top', | |
horizontal: 'center', | |
}} | |
> | |
<Box p={2}> | |
<List | |
component="nav" | |
aria-labelledby="nested-list-subheader" | |
className={classes.root} | |
> | |
<ListItem button> | |
<ListItemIcon> | |
<SendIcon /> | |
</ListItemIcon> | |
<ListItemText primary="Reply" /> | |
</ListItem> | |
<ListItem button> | |
<ListItemIcon> | |
<DraftsIcon /> | |
</ListItemIcon> | |
<ListItemText primary="Forward" /> | |
</ListItem> | |
<ListItem button> | |
<ListItemIcon> | |
<SendIcon /> | |
</ListItemIcon> | |
<ListItemText primary="Delete" /> | |
</ListItem> | |
<ListItem button> | |
<ListItemIcon> | |
<DraftsIcon /> | |
</ListItemIcon> | |
<ListItemText primary="Select messages" /> | |
</ListItem> | |
</List> | |
</Box> | |
</Popover> | |
</div> | |
)} | |
</PopupState> | |
} | |
</div> | |
} | |
<Typography | |
className="time absolute hidden w-full text-11 mt-8 -mb-24 ltr:left-0 rtl:right-0 bottom-0 whitespace-no-wrap" | |
color="textSecondary" | |
> | |
{moment(item.time).format('MMMM Do YYYY, h:mm:ss a')} | |
</Typography> | |
</div> | |
</div> | |
); | |
})} | |
</div> | |
{chatInfosOpen && | |
<div className={clsx(classes.infos,"flex flex-wrap w-full md:w-1/4")}> | |
<div className="mb-32 w-full sm:w-1/2 md:w-full"> | |
<ChatInformations ref={componentRef} /> | |
</div> | |
</div> | |
} | |
</> | |
) : ( | |
<div className="flex flex-col flex-1"> | |
<div className="flex flex-col flex-1 items-center justify-center"> | |
<Icon className="text-128" color="disabled"> | |
chat | |
</Icon> | |
</div> | |
<Typography className="px-16 pb-24 text-center" color="textSecondary"> | |
Start a conversation by typing your message below. | |
</Typography> | |
</div> | |
)} | |
</FuseScrollbars> | |
</div> | |
{chat && ( | |
<form onSubmit={onMessageSubmit} | |
className={clsx(classes.sendingMessageZone, 'absolute bottom-0 right-0 left-0 py-16 px-8')} | |
style={{width: chatInfosOpen ? `calc(100% - ${widthInfo})` : '100%' }}> | |
<Paper className="flex items-center relative rounded-24" elevation={0} > | |
<ChatEditor /> | |
</Paper> | |
</form> | |
)} | |
</div> | |
); | |
} | |
export default Chat; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment