Compare commits

..

1 Commits

Author SHA1 Message Date
data
55d9681774 prevent empty messages or user 2019-07-14 16:46:59 +02:00
7 changed files with 83 additions and 210 deletions

View File

@ -1,9 +0,0 @@
.avatar .username {
display: none;
}
.avatar:hover .username {
display: block;
position: absolute;
z-index: 1;
float: left;
}

View File

@ -7,7 +7,6 @@
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" type="text/css" href="css/custom.css" />
<title>app</title>
</head>

View File

@ -1,13 +1,10 @@
import React from 'react'
import { Card } from 'react-bootstrap'
import Messages from './Messages'
import MessageEntry from './MessageEntry'
import ControlPanel from './ControlPanel'
import { Form, Row, Col, Button, Card, ListGroup, Image } from 'react-bootstrap'
//import ScrollToBottom from 'react-scroll-to-bottom'
import userImage from '../assets/default-user-image.png'
import uuid from 'uuid'
import socket from '../socket'
class Chat extends React.Component {
@ -21,10 +18,11 @@ class Chat extends React.Component {
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
this.handleKey = this.handleKey.bind(this)
this.toggleNick = this.toggleNick.bind(this)
}
componentDidMount() {
this.scrollToBottom()
socket.on('typing', () => this.toggleTyping())
socket.on('message', message => {
this.addMessage(message)
@ -35,69 +33,107 @@ class Chat extends React.Component {
socket.on('connect', () => {
console.log('Connected!')
this.setState({
user: { socketId: socket.id, userImage },
userNick: socket.id,
})
this.setState({ user: { socketId: socket.id } })
})
socket.on('disconnect', () => {
console.log('Disconnected!')
this.setState({ user: { socketId: 'You' } })
})
}
handleKey(e) {
socket.emit('typing')
componentDidUpdate() {
this.scrollToBottom()
}
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: 'smooth' })
}
handleChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
handleSubmit(e) {
e.preventDefault()
if (this.state.text === '') {
return
}
const message = { socketId: socket.id, id: uuid(), text: this.state.text }
const messages = this.state.messages.concat(message)
this.setState({ messages, text: '' })
socket.emit('message', message)
}
toggleTyping() {
if (this.state.typing) return
this.setState({ typing: true })
setTimeout(() => this.setState({ typing: false }), 2000)
}
handleKey(e) {
socket.emit('typing')
}
addMessage(message) {
const messages = this.state.messages.concat(message)
this.setState({ messages })
}
toggleNick() {
this.setState({ editNick: !this.state.editNick })
handleSubmit(e) {
e.preventDefault()
if (this.state.user.socketId === '' || this.state.text === '') {
return
}
const message = {
userId: this.state.user.socketId,
id: uuid(),
text: this.state.text,
}
const messages = this.state.messages.concat(message)
this.setState({ messages, text: '' })
socket.emit('message', message)
}
render() {
return (
<Card style={{ height: '90vh' }} className="mt-5">
<Messages
user={this.state.user}
messages={this.state.messages}
messagesEnd={this.messagesEnd}
/>
<MessageEntry
handleSubmit={this.handleSubmit}
handleChange={this.handleChange}
handleKey={this.handleKey}
text={this.state.text}
/>
<ControlPanel
typing={this.state.typing}
userNick={this.state.userNick}
userImage={userImage}
handleChange={this.handleChange}
editNick={this.editNick}
toggleNick={this.toggleNick}
/>
<Card className="mt-5">
<Card.Body style={{ height: '60vh' }}>
<ListGroup style={{ height: '100%', overflowY: 'hidden' }}>
{this.state.messages.map(msg => (
<ListGroup.Item key={uuid()} className="my-2">
<Image
className={`mx-2 ${
socket.id === this.state.user.socketId ? 'float-right' : ''
}`}
style={{ height: '24px' }}
src={userImage}
/>
{msg.userId}: {msg.text}
</ListGroup.Item>
))}
<div
style={{ float: 'left', clear: 'both' }}
ref={el => {
this.messagesEnd = el
}}
/>
</ListGroup>
</Card.Body>
<Card.Body>
<Form onSubmit={this.handleSubmit}>
<Form.Group as={Row}>
<Col xs={9} sm={10}>
<Form.Control
name="text"
autoComplete="off"
value={this.state.text}
onChange={this.handleChange}
onKeyDown={this.handleKey}
/>
</Col>
<Col xs={1} sm={2}>
<Button
type="submit"
variant="dark"
onSubmit={this.handleSubmit}
>
Send
</Button>
</Col>
</Form.Group>
</Form>
{this.state.typing ? (
<div style={{ height: '2em' }}>Someone is typing...</div>
) : (
<div style={{ height: '2em' }} />
)}
</Card.Body>
</Card>
)
}

View File

@ -1,36 +0,0 @@
import React from 'react'
import { Card, Image, Row, Col } from 'react-bootstrap'
const ControlPanel = props => {
const {
typing,
userNick,
userImage,
handleChange,
editNick,
toggleNick,
} = props
return (
<Card.Body>
<Row>
<Col>{typing ? 'Someone is typing...' : ''}</Col>
<Col>
<div variant="secondary" onClick={toggleNick}>
<div className="float-right">
<Image style={{ height: '24px' }} src={userImage} />
</div>
<input
value={userNick}
name="userNick"
onChange={handleChange}
className={editNick ? '' : 'plaintext'}
onSubmit={toggleNick}
/>
</div>
</Col>
</Row>
</Card.Body>
)
}
export default ControlPanel

View File

@ -1,30 +0,0 @@
import React from 'react'
import { Card, Form, Row, Col, Button } from 'react-bootstrap'
const MessageEntry = props => {
const { handleSubmit, handleChange, handleKey, text } = props
return (
<Card.Body>
<Form onSubmit={handleSubmit}>
<Form.Group as={Row}>
<Col xs={9} sm={10} md={10} lg={10}>
<Form.Control
name="text"
autoComplete="off"
value={text}
onChange={handleChange}
onKeyDown={handleKey}
/>
</Col>
<Col xs={1} sm={2} md={2} lg={2}>
<Button type="submit" variant="dark" onSubmit={handleSubmit}>
Send
</Button>
</Col>
</Form.Group>
</Form>
</Card.Body>
)
}
export default MessageEntry

View File

@ -1,52 +0,0 @@
import React from 'react'
import { Card, ListGroup } from 'react-bootstrap'
import SingleMessage from './SingleMessage'
import uuid from 'uuid'
class Messages extends React.Component {
constructor() {
super()
this.state = {}
}
componentDidMount() {
this.scrollToBottom()
}
componentDidUpdate() {
this.scrollToBottom()
}
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: 'smooth' })
}
render() {
const { user, messages } = this.props
return (
<Card.Body style={{ height: '60%' }}>
<ListGroup style={{ height: '100%', overflowY: 'hidden' }}>
{messages.map(msg => {
return (
<SingleMessage
key={uuid()}
user={user}
socketId={msg.socketId}
text={msg.text}
/>
)
})}
<div
style={{ float: 'left', clear: 'both' }}
ref={el => {
this.messagesEnd = el
}}
/>
</ListGroup>
</Card.Body>
)
}
}
export default Messages

View File

@ -1,35 +0,0 @@
import React from 'react'
import { ListGroup, Image } from 'react-bootstrap'
const SingleMessage = props => {
const { user, socketId, text } = props
if (user.socketId === socketId)
return (
<ListGroup.Item className="my-2">
<div className="p-2 bg-dark text-white float-right">
{text}
<div className="time_date">00:00 AM | July 14</div>
</div>
</ListGroup.Item>
)
return (
<ListGroup.Item className="my-2">
<div className="avatar float-left">
<Image
className="m-3"
style={{ height: '24px' }}
src={user.userImage}
/>
<span className="username p-2 bg-white border border-secondary">
{user.socketId}
</span>
</div>
<div className="p-2 bg-light text-dark float-left">
{text}
<div className="time_date">00:00 AM | July 14</div>
</div>
</ListGroup.Item>
)
}
export default SingleMessage