aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vnext/src/components/Chat.js72
-rw-r--r--vnext/src/components/Contact.js16
-rw-r--r--vnext/src/components/Contacts.js69
-rw-r--r--vnext/src/components/MessageInput.js2
-rw-r--r--vnext/src/components/PM.js22
-rw-r--r--vnext/src/index.js6
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>