11// npm packages
22import React from 'react' ;
33
4+ // our packages
5+ import Message from './message' ;
6+
47export default class Chat extends React . Component {
58 constructor ( props ) {
69 super ( props ) ;
710
811 this . state = {
912 episode : props . episode ,
13+ connected : false ,
14+ username : undefined ,
15+ messages : [ ] ,
1016 } ;
1117 }
1218
1319 componentWillReceiveProps ( nextProps ) {
1420 if ( nextProps . episode && ( ! this . state . episode || nextProps . episode . _id !== this . state . episode . _id ) ) {
15- this . setState ( { episode : nextProps . episode } , ( ) => {
21+ this . setState ( { episode : nextProps . episode , messages : [ ] , connected : false } , ( ) => {
1622 this . connectToServer ( ) ;
1723 } ) ;
1824 }
1925 }
2026
27+ setUsername ( ) {
28+ const username = this . usernameInput . value ;
29+ this . setState ( { username} ) ;
30+ }
31+
2132 connectToServer ( ) {
2233 const { episode} = this . state ;
2334
@@ -26,34 +37,96 @@ export default class Chat extends React.Component {
2637 this . socket = new WebSocket ( url ) ;
2738
2839 // Connection opened
29- // this.socket.addEventListener('open', event => {
30- // this.socket.send('Hello Server!');
31- // });
40+ this . socket . addEventListener ( 'open' , ( ) => this . setState ( { connected : true } ) ) ;
3241
3342 // Listen for messages
3443 this . socket . addEventListener ( 'message' , event => {
35- console . log ( 'Message from server' , event . data ) ;
44+ const message = JSON . parse ( event . data ) ;
45+ console . log ( 'Message from server' , message ) ;
46+ const { messages : oldMessages } = this . state ;
47+ const messages = oldMessages . concat ( [ message ] ) . sort ( ( a , b ) => a . date < b . date ) ;
48+ this . setState ( { messages} ) ;
3649 } ) ;
3750 }
3851
52+ sendMessage ( ) {
53+ const message = this . messageInput . value ;
54+
55+ if ( ! message || message . length < 3 ) {
56+ return ;
57+ }
58+
59+ this . messageInput . value = '' ;
60+ this . socket . send ( JSON . stringify ( { user : this . state . username , message, date : new Date ( ) } ) ) ;
61+ }
62+
63+ handleMessageKey ( e ) {
64+ if ( e . key === 'Enter' ) {
65+ e . preventDefault ( ) ;
66+ this . sendMessage ( ) ;
67+ return false ;
68+ }
69+
70+ return true ;
71+ }
72+
3973 render ( ) {
74+ const { username, messages, connected} = this . state ;
75+
76+ if ( ! connected ) {
77+ return (
78+ < div className = "column" style = { { width : 340 , maxWidth : 340 , display : 'flex' , flexDirection : 'column' } } >
79+ Connecting..
80+ </ div >
81+ ) ;
82+ }
83+
4084 return (
4185 < div className = "column" style = { { width : 340 , maxWidth : 340 , display : 'flex' , flexDirection : 'column' } } >
42- < div className = "is-flex" style = { { flexGrow : 1 } } >
43- Chat history
44- </ div >
45- < div className = "is-flex" >
46- < div className = "field has-addons" style = { { flexGrow : 1 } } >
47- < p className = "control" style = { { flexGrow : 1 } } >
48- < input className = "input" type = "text" placeholder = "Send a message.." />
49- </ p >
50- < p className = "control" style = { { marginRight : 10 } } >
51- < a className = "button is-info" >
52- Send
53- </ a >
54- </ p >
55- </ div >
86+ < div className = "is-flex" style = { { flexGrow : 1 , flexDirection : 'column' } } >
87+ { messages . map ( ( m , i ) => < Message key = { `msg_${ i } ` } message = { m } /> ) }
5688 </ div >
89+ { username &&
90+ < div className = "is-flex" >
91+ < div className = "field has-addons" style = { { flexGrow : 1 } } >
92+ < p className = "control" style = { { flexGrow : 1 } } >
93+ < input
94+ className = "input"
95+ type = "text"
96+ placeholder = "Send a message.."
97+ ref = { m => {
98+ this . messageInput = m ;
99+ } }
100+ onKeyUp = { e => this . handleMessageKey ( e ) }
101+ />
102+ </ p >
103+ < p className = "control" style = { { marginRight : 10 } } >
104+ < a className = "button is-info" onClick = { ( ) => this . sendMessage ( ) } >
105+ Send
106+ </ a >
107+ </ p >
108+ </ div >
109+ </ div > }
110+ { ! username &&
111+ < div className = "is-flex" >
112+ < div className = "field has-addons" style = { { flexGrow : 1 } } >
113+ < p className = "control" style = { { flexGrow : 1 } } >
114+ < input
115+ className = "input"
116+ type = "text"
117+ placeholder = "Pick a username.."
118+ ref = { u => {
119+ this . usernameInput = u ;
120+ } }
121+ />
122+ </ p >
123+ < p className = "control" style = { { marginRight : 10 } } >
124+ < a className = "button is-primary" onClick = { ( ) => this . setUsername ( ) } >
125+ Set username
126+ </ a >
127+ </ p >
128+ </ div >
129+ </ div > }
57130 </ div >
58131 ) ;
59132 }
0 commit comments