Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
55d9681774 |
@ -1,9 +0,0 @@
|
|||||||
.avatar .username {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.avatar:hover .username {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
float: left;
|
|
||||||
}
|
|
@ -7,7 +7,6 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/custom.css" />
|
|
||||||
|
|
||||||
<title>app</title>
|
<title>app</title>
|
||||||
</head>
|
</head>
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Card } from 'react-bootstrap'
|
import { Form, Row, Col, Button, Card, ListGroup, Image } from 'react-bootstrap'
|
||||||
|
//import ScrollToBottom from 'react-scroll-to-bottom'
|
||||||
import Messages from './Messages'
|
|
||||||
import MessageEntry from './MessageEntry'
|
|
||||||
import ControlPanel from './ControlPanel'
|
|
||||||
|
|
||||||
import userImage from '../assets/default-user-image.png'
|
import userImage from '../assets/default-user-image.png'
|
||||||
|
|
||||||
import uuid from 'uuid'
|
import uuid from 'uuid'
|
||||||
|
|
||||||
import socket from '../socket'
|
import socket from '../socket'
|
||||||
|
|
||||||
class Chat extends React.Component {
|
class Chat extends React.Component {
|
||||||
@ -21,10 +18,11 @@ class Chat extends React.Component {
|
|||||||
this.handleSubmit = this.handleSubmit.bind(this)
|
this.handleSubmit = this.handleSubmit.bind(this)
|
||||||
this.handleChange = this.handleChange.bind(this)
|
this.handleChange = this.handleChange.bind(this)
|
||||||
this.handleKey = this.handleKey.bind(this)
|
this.handleKey = this.handleKey.bind(this)
|
||||||
this.toggleNick = this.toggleNick.bind(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.scrollToBottom()
|
||||||
|
|
||||||
socket.on('typing', () => this.toggleTyping())
|
socket.on('typing', () => this.toggleTyping())
|
||||||
socket.on('message', message => {
|
socket.on('message', message => {
|
||||||
this.addMessage(message)
|
this.addMessage(message)
|
||||||
@ -35,69 +33,107 @@ class Chat extends React.Component {
|
|||||||
|
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
console.log('Connected!')
|
console.log('Connected!')
|
||||||
this.setState({
|
this.setState({ user: { socketId: socket.id } })
|
||||||
user: { socketId: socket.id, userImage },
|
|
||||||
userNick: socket.id,
|
|
||||||
})
|
})
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
console.log('Disconnected!')
|
||||||
|
this.setState({ user: { socketId: 'You' } })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKey(e) {
|
componentDidUpdate() {
|
||||||
socket.emit('typing')
|
this.scrollToBottom()
|
||||||
|
}
|
||||||
|
scrollToBottom = () => {
|
||||||
|
this.messagesEnd.scrollIntoView({ behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange(e) {
|
handleChange(e) {
|
||||||
this.setState({ [e.target.name]: e.target.value })
|
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() {
|
toggleTyping() {
|
||||||
if (this.state.typing) return
|
if (this.state.typing) return
|
||||||
this.setState({ typing: true })
|
this.setState({ typing: true })
|
||||||
setTimeout(() => this.setState({ typing: false }), 2000)
|
setTimeout(() => this.setState({ typing: false }), 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleKey(e) {
|
||||||
|
socket.emit('typing')
|
||||||
|
}
|
||||||
addMessage(message) {
|
addMessage(message) {
|
||||||
const messages = this.state.messages.concat(message)
|
const messages = this.state.messages.concat(message)
|
||||||
this.setState({ messages })
|
this.setState({ messages })
|
||||||
}
|
}
|
||||||
|
handleSubmit(e) {
|
||||||
toggleNick() {
|
e.preventDefault()
|
||||||
this.setState({ editNick: !this.state.editNick })
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Card style={{ height: '90vh' }} className="mt-5">
|
<Card className="mt-5">
|
||||||
<Messages
|
<Card.Body style={{ height: '60vh' }}>
|
||||||
user={this.state.user}
|
<ListGroup style={{ height: '100%', overflowY: 'hidden' }}>
|
||||||
messages={this.state.messages}
|
{this.state.messages.map(msg => (
|
||||||
messagesEnd={this.messagesEnd}
|
<ListGroup.Item key={uuid()} className="my-2">
|
||||||
|
<Image
|
||||||
|
className={`mx-2 ${
|
||||||
|
socket.id === this.state.user.socketId ? 'float-right' : ''
|
||||||
|
}`}
|
||||||
|
style={{ height: '24px' }}
|
||||||
|
src={userImage}
|
||||||
/>
|
/>
|
||||||
<MessageEntry
|
{msg.userId}: {msg.text}
|
||||||
handleSubmit={this.handleSubmit}
|
</ListGroup.Item>
|
||||||
handleChange={this.handleChange}
|
))}
|
||||||
handleKey={this.handleKey}
|
<div
|
||||||
text={this.state.text}
|
style={{ float: 'left', clear: 'both' }}
|
||||||
|
ref={el => {
|
||||||
|
this.messagesEnd = el
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<ControlPanel
|
</ListGroup>
|
||||||
typing={this.state.typing}
|
</Card.Body>
|
||||||
userNick={this.state.userNick}
|
<Card.Body>
|
||||||
userImage={userImage}
|
<Form onSubmit={this.handleSubmit}>
|
||||||
handleChange={this.handleChange}
|
<Form.Group as={Row}>
|
||||||
editNick={this.editNick}
|
<Col xs={9} sm={10}>
|
||||||
toggleNick={this.toggleNick}
|
<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>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
Loading…
x
Reference in New Issue
Block a user