-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathindex.js
143 lines (129 loc) · 4.8 KB
/
index.js
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
132
133
134
135
136
137
138
139
140
141
142
143
import Head from 'next/head'
import styles from '@/styles/Home.module.css'
import Script from 'next/script';
import { useState, useEffect, useRef } from 'react';
import Members from '@/components/Members'
import Messages from '@/components/Messages'
import Input from '@/components/Input'
import TypingIndicator from '@/components/TypingIndicator'
function randomName() {
const adjectives = [
'autumn', 'hidden', 'bitter', 'misty', 'silent', 'empty', 'dry', 'dark',
'summer', 'icy', 'delicate', 'quiet', 'white', 'cool', 'spring', 'winter',
'patient', 'twilight', 'dawn', 'crimson', 'wispy', 'weathered', 'blue',
'billowing', 'broken', 'cold', 'damp', 'falling', 'frosty', 'green', 'long',
'late', 'lingering', 'bold', 'little', 'morning', 'muddy', 'old', 'red',
'rough', 'still', 'small', 'sparkling', 'shy', 'wandering',
'withered', 'wild', 'black', 'young', 'holy', 'solitary', 'fragrant',
'aged', 'snowy', 'proud', 'floral', 'restless', 'divine', 'polished',
'ancient', 'purple', 'lively', 'nameless'
];
const nouns = [
'waterfall', 'river', 'breeze', 'moon', 'rain', 'wind', 'sea', 'morning',
'snow', 'lake', 'sunset', 'pine', 'shadow', 'leaf', 'dawn', 'glitter',
'forest', 'hill', 'cloud', 'meadow', 'sun', 'glade', 'bird', 'brook',
'butterfly', 'bush', 'dew', 'dust', 'field', 'fire', 'flower', 'firefly',
'feather', 'grass', 'haze', 'mountain', 'night', 'pond', 'darkness',
'snowflake', 'silence', 'sound', 'sky', 'shape', 'surf', 'thunder',
'violet', 'water', 'wildflower', 'wave', 'water', 'resonance', 'sun',
'wood', 'dream', 'cherry', 'tree', 'fog', 'frost', 'voice', 'paper', 'frog',
'smoke', 'star'
];
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
const noun = nouns[Math.floor(Math.random() * nouns.length)];
return adjective + noun;
}
function randomColor() {
return '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16);
}
let drone = null
export default function Home() {
const [messages, setMessages] = useState([]);
const [members, setMembers] = useState([]);
const [me, setMe] = useState({
username: randomName(),
color: randomColor(),
});
const messagesRef = useRef();
messagesRef.current = messages;
const membersRef = useRef();
membersRef.current = members;
const meRef = useRef();
meRef.current = me;
function connectToScaledrone() {
drone = new window.Scaledrone('YOUR-CHANNEL-ID', {
data: meRef.current,
});
drone.on('open', error => {
if (error) {
return console.error(error);
}
meRef.current.id = drone.clientId;
setMe(meRef.current);
});
const room = drone.subscribe('observable-room');
room.on('message', message => {
const {data, member} = message;
if (typeof data === 'object' && typeof data.typing === 'boolean') {
const newMembers = [...membersRef.current];
const index = newMembers.findIndex(m => m.id === member.id);
newMembers[index].typing = data.typing;
setMembers(newMembers);
} else {
setMessages([...messagesRef.current, message]);
}
});
room.on('members', members => {
setMembers(members);
});
room.on('member_join', member => {
setMembers([...membersRef.current, member]);
});
room.on('member_leave', ({id}) => {
const index = membersRef.current.findIndex(m => m.id === id);
const newMembers = [...membersRef.current];
newMembers.splice(index, 1);
setMembers(newMembers);
});
}
useEffect(() => {
if (drone === null) {
connectToScaledrone();
}
}, []);
function onSendMessage(message) {
drone.publish({
room: 'observable-room',
message
});
}
function onChangeTypingState(isTyping) {
drone.publish({
room: 'observable-room',
message: {typing: isTyping}
});
}
return (
<>
<Head>
<title>Scaledrone Chat App</title>
<meta name='description' content='Your brand-new chat app!' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<script type='text/javascript' src='https://cdn.scaledrone.com/scaledrone.min.js' />
<link rel='icon' href='/favicon.ico' />
</Head>
<main className={styles.app}>
<div className={styles.appContent}>
<Members members={members} me={me}/>
<Messages messages={messages} me={me}/>
<TypingIndicator members={members.filter(m => m.typing && m.id !== me.id)}/>
<Input
onSendMessage={onSendMessage}
onChangeTypingState={onChangeTypingState}
/>
<a className={styles.upsell} href='https://www.scaledrone.com/blog/tutorial-build-a-reactjs-chat-app/'>Real-time React chat using Scaledrone. See full tutorial →</a>
</div>
</main>
</>
)
}