diff options
-rw-r--r-- | vnext/src/components/Chat.js | 72 | ||||
-rw-r--r-- | vnext/src/components/Contact.js | 16 | ||||
-rw-r--r-- | vnext/src/components/Contacts.js | 69 | ||||
-rw-r--r-- | vnext/src/components/MessageInput.js | 2 | ||||
-rw-r--r-- | vnext/src/components/PM.js | 22 | ||||
-rw-r--r-- | vnext/src/index.js | 6 |
6 files changed, 185 insertions, 2 deletions
diff --git a/vnext/src/components/Chat.js b/vnext/src/components/Chat.js new file mode 100644 index 00000000..79425c12 --- /dev/null +++ b/vnext/src/components/Chat.js @@ -0,0 +1,72 @@ +import React from 'react'; +import moment from 'moment'; + +import PM from './PM'; +import MessageInput from './MessageInput'; + +export default class Chat extends React.Component { + constructor(props) { + super(props); + + this.state = { + chats: [] + }; + this.loadChat = this.loadChat.bind(this); + } + componentWillMount() { + this.loadChat(this.props.match.params.user); + } + + loadChat(uname) { + const { hash } = this.props.visitor; + this.setState({ + chats: [] + }); + if (hash && uname) { + fetch(`https://api.juick.com/pm?uname=${uname}&hash=${hash}`) + .then(response => response.json()) + .then(jsonResponse => { + this.setState({ + chats: jsonResponse + }); + }); + } + } + + render() { + const { chats } = this.state; + const uname = this.props.match.params.user; + return ( + <div id="content"> + <article> + + { uname ? ( + <div className="chatroom"> + <ul style={chatStyle} ref="chats"> + { + chats.map((chat) => + <PM key={moment.utc(chat.timestamp).valueOf()} chat={chat} /> + ) + } + </ul> + <MessageInput data={{}} onSend={()=>{}}/> + </div> + ) : ( + <div className="chatroom no-selection"><p>No chat selected</p></div> + ) + } + </article> + </div> + ) + } +} + +const chatStyle = { + boxSizing: 'border-box', + padding: '0 20px', + overflowY: 'scroll', + height: '450px', + display: 'flex', + flexDirection: 'column-reverse', + width: '100%' +} diff --git a/vnext/src/components/Contact.js b/vnext/src/components/Contact.js new file mode 100644 index 00000000..0e969cc1 --- /dev/null +++ b/vnext/src/components/Contact.js @@ -0,0 +1,16 @@ +import React from 'react'; + +import Avatar from './Avatar'; + +export default class Contact extends React.Component { + + render() { + const { user } = this.props; + return ( + <React.Fragment> + <Avatar user={user} link={`/pm/${user.uname}`} /> + {user.uname }{ user.unreadCount && <span className="badge">{user.unreadCount}</span>} + </React.Fragment> + ); + } +} diff --git a/vnext/src/components/Contacts.js b/vnext/src/components/Contacts.js new file mode 100644 index 00000000..300e60eb --- /dev/null +++ b/vnext/src/components/Contacts.js @@ -0,0 +1,69 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; + + +import Contact from './Contact.js'; + +export default class Contacts extends React.Component { + constructor(props) { + super(props); + this.state = { + pms: [] + }; + } + componentWillMount() { + this.refreshChats(); + } + + refreshChats() { + fetch(`https://api.juick.com/groups_pms?hash=${this.props.visitor.hash}`) + .then(response => response.json()) + .then(jsonResponse => { + this.setState({ + isLoading: false, + pms: jsonResponse.pms + }); + }); + } + render() { + const { pms } = this.state; + const user = this.props.visitor; + return ( + <div style={wrapperStyle} className="msg-cont"> + <ul style={chatListStyle} ref="chats"> + { + pms && pms.map((chat) => + <li key={chat.uname} style={chatTitleStyle}> + <Contact key={chat.uname} user={chat} /> + </li> + ) + } + </ul> + </div> + ); + } +} + +const wrapperStyle = { + display: 'flex', + backgroundColor: '#fff' +} + +const chatListStyle = { + boxSizing: 'border-box', + padding: '0 20px', + overflowY: 'scroll', + display: 'flex', + alignItems: 'center', + flexDirection: 'column', + width: '100%' +} + +const chatTitleStyle = { + width: '100%', + padding: '3px 6px', + textAlign: 'left', + background: '#fff', + color: '#222', + borderBottom: '1px solid #eee' +}
\ No newline at end of file diff --git a/vnext/src/components/MessageInput.js b/vnext/src/components/MessageInput.js index 71802985..ef740e41 100644 --- a/vnext/src/components/MessageInput.js +++ b/vnext/src/components/MessageInput.js @@ -105,7 +105,7 @@ const activeStyle = { }; const inputBarStyle = { - border: '1px solid #DDD', + border: '1px solid #ddd', display: 'flex', alignItems: 'center', padding: '3px', diff --git a/vnext/src/components/PM.js b/vnext/src/components/PM.js new file mode 100644 index 00000000..44b81129 --- /dev/null +++ b/vnext/src/components/PM.js @@ -0,0 +1,22 @@ +import React from 'react'; + +import Avatar from './Avatar'; +import { format } from '../utils/embed'; + +export default function PM(props) { + const {chat} = props; + return ( + <li style={chatItemStyle}> + <Avatar user={chat.user} /> + <p dangerouslySetInnerHTML={{ __html: format(chat.body) }} /> + </li> + ); +} + +const chatItemStyle = { + padding: '5px 13px', + fontSize: '14px', + listStyle: 'none', + margin: '10px 0', + boxShadow: '0 0 3px rgba(0,0,0, 0.16)' +}
\ No newline at end of file diff --git a/vnext/src/index.js b/vnext/src/index.js index 88e44465..7ba41fc1 100644 --- a/vnext/src/index.js +++ b/vnext/src/index.js @@ -4,6 +4,8 @@ import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'; import Icon from './components/Icon'; import { Discover, Discussions, Blog, Tag, Home } from './components/Feeds'; import Settings from './components/Settings'; +import Contacts from './components/Contacts'; +import Chat from './components/Chat'; import Post from './components/Post'; import Thread from './components/Thread'; import LoginButton from './components/LoginButton'; @@ -135,6 +137,8 @@ class App extends React.Component { <Settings visitor={user} {...props} /> } /> <Route exact path="/post" render={(props) => <Post visitor={user} {...props} />} /> + <Route exact path="/pm" render={(props) => <Contacts visitor={user} {...props} />} /> + <Route exact path="/pm/:user" render={(props) => <Chat visitor={user} {...props} />} /> <Route exact path="/:user" render={(props) => <Blog visitor={user} {...props} />} /> <Route exact path="/tag/:tag" render={(props) => <Tag visitor={user} {...props} />} /> <Route exact path="/:user/:mid" render={(props) => <Thread visitor={user} {...props} />} /> @@ -151,7 +155,7 @@ class App extends React.Component { </Link> </li> <li> - <Link to="/pm/inbox"> + <Link to="/pm"> <Icon name="ei-envelope" size="s" />PM </Link> </li> |