-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.jsx
131 lines (111 loc) · 4.3 KB
/
app.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import React, { useState, useEffect } from 'react';
import * as ReactDOM from 'react-dom'
import { initIHPBackend, DataSubscription } from 'ihp-datasync/ihp-datasync.js';
import { query, createRecord } from 'ihp-datasync/ihp-querybuilder.js';
import { useQuery } from 'ihp-datasync/ihp-datasync-react';
import { ensureIsUser, getCurrentUserId, useCurrentUser, logout } from 'ihp-backend';
function Chat() {
const messages = useQuery(query('messages').orderBy('createdAt'));
const user = useCurrentUser();
if (messages === null) {
return <LoadingIndicator/>;
}
return <div>
<AppNavbar/>
<div className="chat">
{groupMessages(messages)
.reverse()
.map(messages => <MessagesSection
messages={messages}
key={messages[0].id}
ownMessages={messages[0].userId === user.id}
/>
)
}
</div>
<NewChatMessage/>
</div>
}
function LoadingIndicator() {
return <div className="spinner-border text-primary" role="status">
<span className="sr-only">Loading...</span>
</div>;
}
class NewChatMessage extends React.Component {
constructor(props) {
super(props);
this.state = { body: '' };
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return <form onSubmit={this.handleSubmit} disabled={this.state.loading}>
<div className="form-group d-flex flex-row">
<input
type="text"
className="form-control"
placeholder="New message"
value={this.state.body}
onChange={event => this.setState({ body: event.target.value })}
disabled={this.state.loading}
/>
<button type="submit" className="btn btn-primary" disabled={this.state.loading}>Send</button>
</div>
</form>
}
async handleSubmit(event) {
const form = event.target;
event.preventDefault();
if (this.state.body === '') {
return;
}
this.setState({ loading: true });
await createRecord('messages', { body: this.state.body, userId: await getCurrentUserId() });
this.setState({ loading: false, body: '' });
}
}
function MessagesSection({ messages, ownMessages }) {
const className = (ownMessages ? "mine" : "yours") + " messages";
return <div className={className}>
{messages.map((message, index) => <ChatMessage message={message} key={message.id} isLast={index === (messages.length - 1)}/>)}
</div>
}
function ChatMessage({ message, isLast }) {
return <div className={"message" + (isLast ? " last" : "")}>{message.body}</div>
}
function AppNavbar() {
const user = useCurrentUser();
return <nav className="navbar navbar-expand-lg navbar-light bg-light mb-5">
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav ml-auto">
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{user?.email}
</a>
<div className="dropdown-menu" aria-labelledby="navbarDropdown">
<a className="dropdown-item" href="#" onClick={() => logout()}>Logout</a>
</div>
</li>
</ul>
</div>
</nav>
}
function groupMessages(messages) {
const messageSections = [];
for (const message of messages) {
let section = messageSections.length > 0 ? messageSections[messageSections.length - 1] : null;
if (section && section[0].userId === message.userId) {
section.push(message);
} else {
section = [message];
messageSections.push(section)
}
}
return messageSections;
}
initIHPBackend({
host: 'https://bufsdidjdjbvdrgxnnuwplssrfbxwkun.di1337.com'
});
(async () => {
await ensureIsUser();
ReactDOM.render(<Chat/>, document.getElementById('app'));
})();