Skip to content

Instantly share code, notes, and snippets.

@MohammedALREAI
Created May 6, 2021 16:17
Show Gist options
  • Save MohammedALREAI/6e49e9dc4842d61080e26a6d2f4deb29 to your computer and use it in GitHub Desktop.
Save MohammedALREAI/6e49e9dc4842d61080e26a6d2f4deb29 to your computer and use it in GitHub Desktop.
chat js
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