This commit is contained in:
Barry Gitarts 2018-11-23 17:02:22 -05:00
commit ccefe4bcf6
4 changed files with 106 additions and 84 deletions

View File

@ -28,7 +28,7 @@ function isSpotifyLink(text) {
// https://gist.github.com/takien/4077195#
function getYoutubeId(url) {
var ID = '';
let ID = '';
url = url.replace(/(>|<)/gi,'').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
if(url[2] !== undefined) {
ID = url[2].split(/[^0-9a-z_\-]/i);
@ -45,12 +45,12 @@ const MessageRender = ({ message }) => (
message[2] === "`" && SyntaxLookup[message.slice(0,2)]
? <SyntaxHighlighter language={SyntaxLookup[message.slice(0,2)]} style={atomDark}>{message.slice(3)}</SyntaxHighlighter>
: <Linkify><span style={{ wordWrap: 'break-word', whiteSpace: 'pre-line' }}>{message}</span></Linkify>
)
);
class ChatBox extends PureComponent {
state = {
imgUrl: null
}
};
componentDidMount() {
const { message } = this.props;
@ -66,7 +66,7 @@ class ChatBox extends PureComponent {
const imgUrl = URL.createObjectURL(blob);
const image = `data:image/png;base64,${content.toString('base64')}`;
this.setState({ imgUrl });
}
};
render() {
const { username, message, pubkey } = this.props;
@ -101,7 +101,7 @@ class ChatBox extends PureComponent {
/>
</ListItem>
}
{!!imgUrl && <img src={imgUrl} alt='ipfs-image' style={{ width: '100%' }}/>}
{!!imgUrl && <img src={imgUrl} alt='ipfs' style={{ width: '100%' }}/>}
</Fragment>
)
};

View File

@ -3,10 +3,16 @@ import React, { Fragment, PureComponent, createRef } from 'react';
import { Formik } from 'formik';
import autoscroll from 'autoscroll-react';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import Avatar from '@material-ui/core/Avatar';
import ListItemText from '@material-ui/core/ListItemText';
import Divider from '@material-ui/core/Divider';
import Grid from '@material-ui/core/Grid';
import TextField from '@material-ui/core/TextField';
import Dropzone from 'react-dropzone';
import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
import ChatBox from './ChatBox';
import ChatHeader from './ChatHeader';
import { uploadFileAndSend } from '../utils/ipfs';
@ -32,7 +38,7 @@ class WhoIsTyping extends PureComponent {
const userList = this.whoIsTyping();
return (
<div>
{!userList.length ? "" : userList.join(',' ) + " is typing"}
{!userList.length ? "" : `${userList.join(',')} is typing`}
</div>
)
}
@ -45,8 +51,8 @@ function onDrop(acceptedFiles, rejectedFiles, ipfs, sendMessage) {
const keyDownHandler = (e, typingEvent, setValue, value) => {
if(e.shiftKey && e.keyCode === 13) {
e.preventDefault()
const cursor = e.target.selectionStart
e.preventDefault();
const cursor = e.target.selectionStart;
const newValue = `${value.slice(0, cursor)}\n${value.slice(cursor)}`;
setValue('chatInput', newValue);
}
@ -56,85 +62,102 @@ const keyDownHandler = (e, typingEvent, setValue, value) => {
form.dispatchEvent(new Event("submit"));
}
typingEvent(e)
}
};
const AutoScrollList = autoscroll(List);
const formStyle = { display: 'flex', justifyContent: 'center', alignItems: 'center', flexBasis: '10%' };
const listStyle = { overflow: 'scroll', flexBasis: '76%' };
const listStyle = { overflowY: 'auto', flexBasis: '76%', position: 'absolute', top: '72px', left: 0, right: 0, bottom: '67px' };
const ChatRoomForm = createRef();
const ChatRoom = ({ messages, sendMessage, currentChannel, usersTyping, typingEvent, channelUsers, allUsers, ipfs }) => (
<div style={{ height: '100vh' }}>
<Dropzone
onDrop={(a, r) => { onDrop(a,r,ipfs,sendMessage) } }
disableClick
style={{ position: 'relative', height: '100%' }}
activeStyle={{ backgroundColor: 'grey', outline: '5px dashed lightgrey', alignSelf: 'center', outlineOffset: '-10px' }}>
<Grid
container
direction="column"
justify="flex-start"
alignItems="stretch"
style={{ height: '100%' }}
>
<ChatHeader currentChannel={currentChannel}/>
<Divider />
<AutoScrollList style={listStyle}>
{messages[currentChannel] && messages[currentChannel].map((message) => (
<Fragment key={message.data.payload}>
<ChatBox {...message} ipfs={ipfs} />
<li>
<Divider />
</li>
</Fragment>
))}
</AutoScrollList>
<Formik
initialValues={{ chatInput: '' }}
onSubmit={(values, { setSubmitting, resetForm }) => {
const { chatInput } = values;
sendMessage(chatInput);
resetForm();
setSubmitting(false);
}}
<Grid container style={{ height: '100vh'}}>
<Grid xs={8} item >
<Dropzone
onDrop={(a, r) => { onDrop(a,r,ipfs,sendMessage) } }
disableClick
style={{ position: 'relative', height: '100%' }}
activeStyle={{ backgroundColor: 'grey', outline: '5px dashed lightgrey', alignSelf: 'center', outlineOffset: '-10px' }}>
<Grid
container
direction="column"
justify="flex-start"
alignItems="stretch"
style={{ height: '100%' }}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
setFieldValue
}) => (
<div>
<form onSubmit={handleSubmit} style={formStyle} ref={ChatRoomForm}>
<TextField
id="chatInput"
multiline
style={{ width: 'auto', flexGrow: '0.95', margin: '2px 0 0 0' }}
label="Type a message..."
type="text"
name="chatInput"
margin="normal"
variant="outlined"
fullWidth
onChange={handleChange}
onKeyDown={(e) => keyDownHandler(e, typingEvent, setFieldValue, values.chatInput)}
onBlur={handleBlur}
value={values.chatInput || ''}
/>
{errors.chatInput && touched.chatInput && errors.chatInput}
</form>
<WhoIsTyping
currentChannel={currentChannel}
usersTyping={usersTyping}
users={allUsers} />
</div>
)}
</Formik>
</Grid>
</Dropzone>
</div>
<ChatHeader currentChannel={currentChannel}/>
<Divider />
<AutoScrollList style={listStyle}>
{messages[currentChannel] && messages[currentChannel].map((message) => (
<Fragment key={message.data.payload}>
<ChatBox {...message} ipfs={ipfs} />
<li>
<Divider />
</li>
</Fragment>
))}
</AutoScrollList>
<Formik
initialValues={{ chatInput: '' }}
onSubmit={(values, { setSubmitting, resetForm }) => {
const { chatInput } = values;
sendMessage(chatInput);
resetForm();
setSubmitting(false);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
setFieldValue
}) => (
<div className="chat-input" style={{position: 'absolute', bottom: 0, left: 0, right: 0, paddingBottom: 10}}>
<form onSubmit={handleSubmit} style={formStyle} ref={ChatRoomForm}>
<TextField
id="chatInput"
multiline
style={{ width: 'auto', flexGrow: '0.95', margin: '2px 0 0 0' }}
label="Type a message..."
type="text"
name="chatInput"
margin="normal"
variant="outlined"
fullWidth
onChange={handleChange}
onKeyDown={(e) => keyDownHandler(e, typingEvent, setFieldValue, values.chatInput)}
onBlur={handleBlur}
value={values.chatInput || ''}
/>
{errors.chatInput && touched.chatInput && errors.chatInput}
</form>
<WhoIsTyping
currentChannel={currentChannel}
usersTyping={usersTyping}
users={allUsers} />
</div>
)}
</Formik>
</Grid>
</Dropzone>
</Grid>
<Grid xs={4} item style={{overflow: 'auto'}}>
<List>
{Object.keys(channelUsers).map(user => (
<ListItem button key={user}>
<span className="dot" style={{"height": "10px", "width": "11px", "background-color": (allUsers[user].online ? "lightgreen" : "lightgrey"), "border-radius": "50%", "margin-right": "10px"}}/>
<ListItemAvatar>
<Avatar>
<Jazzicon diameter={40} seed={jsNumberForAddress(user)} />
</Avatar>
</ListItemAvatar>
<ListItemText primary={allUsers[user].username} />
</ListItem>
))}
</List>
</Grid>
</Grid>
);
export default ChatRoom;

View File

@ -4,7 +4,6 @@ import StatusJS from 'status-js-api';
import IPFS from 'ipfs';
import { isNil } from 'lodash';
import Grid from '@material-ui/core/Grid';
import routes from '../constants/routes';
import ChatRoom from './ChatRoom';
import ContextPanel from './ContextPanel';
import Login from './Login';
@ -60,7 +59,7 @@ export default class Home extends PureComponent<Props> {
this.keyringController.exportAccount(account)
.then(key => { status.connect(URL, `0x${key}`) })
.then(() => { this.onConnect() })
}
};
onConnect = () => {
const { currentChannel } = this.state;

View File

@ -11,7 +11,7 @@
"build-renderer": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
"dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && cross-env START_HOT=1 yarn start-renderer-dev",
"flow": "flow",
"flow-typed": "rimraf flow-typed/npm && flow-typed install --overwrite || true",
"flow-typed": "cross-env rimraf flow-typed/npm && flow-typed install --overwrite || true",
"lint": "cross-env NODE_ENV=development eslint --cache --format=pretty .",
"lint-fix": "yarn --silent lint --fix; exit 0",
"lint-styles": "stylelint --ignore-path .eslintignore '**/*.*(css|scss)' --syntax scss",