Skip to content

Commit 7e4ec82

Browse files
authored
Merge pull request #14 from kavalerov/fix/add-ably-chat
Change to Ably Chat SDK
2 parents 7e17fa2 + c852583 commit 7e4ec82

File tree

4 files changed

+154
-46
lines changed

4 files changed

+154
-46
lines changed

components/Chat.jsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
'use client';
22

33
import * as Ably from 'ably';
4-
import { AblyProvider, ChannelProvider } from 'ably/react';
4+
import { ChatClient } from '@ably/chat';
5+
import { ChatClientProvider, ChatRoomProvider } from '@ably/chat/react';
56
import ChatBox from './ChatBox.jsx';
67

8+
const roomOptions = {
9+
history: { limit: 50 },
10+
};
11+
712
export default function Chat() {
8-
const client = new Ably.Realtime({ authUrl: '/api' });
13+
const realtimeClient = new Ably.Realtime({ authUrl: '/api' });
14+
const chatClient = new ChatClient(realtimeClient);
915

1016
return (
11-
<AblyProvider client={client}>
12-
<ChannelProvider channelName="chat-demo">
17+
<ChatClientProvider client={chatClient}>
18+
<ChatRoomProvider id="chat-demo" options={roomOptions}>
1319
<ChatBox />
14-
</ChannelProvider>
15-
</AblyProvider>
20+
</ChatRoomProvider>
21+
</ChatClientProvider>
1622
);
1723
}

components/ChatBox.jsx

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,47 @@
1-
import React, { useEffect, useState } from 'react';
2-
import { useChannel } from 'ably/react';
1+
import React, { useEffect, useState, useRef } from 'react';
2+
import { useMessages } from '@ably/chat/react';
33
import styles from './ChatBox.module.css';
44

55
export default function ChatBox() {
6-
let inputBox = null;
7-
let messageEnd = null;
6+
const inputBox = useRef(null);
7+
const messageEndRef = useRef(null);
88

99
const [messageText, setMessageText] = useState('');
10-
const [receivedMessages, setMessages] = useState([]);
10+
const [messages, setMessages] = useState([]);
1111
const messageTextIsEmpty = messageText.trim().length === 0;
1212

13-
const { channel, ably } = useChannel('chat-demo', (message) => {
14-
const history = receivedMessages.slice(-199);
15-
setMessages([...history, message]);
13+
const { send: sendMessage } = useMessages({
14+
listener: (payload) => {
15+
const newMessage = payload.message;
16+
setMessages((prevMessages) => {
17+
if (prevMessages.some((existingMessage) => existingMessage.isSameAs(newMessage))) {
18+
return prevMessages;
19+
}
20+
21+
const index = prevMessages.findIndex((existingMessage) => existingMessage.after(newMessage));
22+
23+
const newMessages = [...prevMessages];
24+
if (index === -1) {
25+
newMessages.push(newMessage);
26+
} else {
27+
newMessages.splice(index, 0, newMessage);
28+
}
29+
return newMessages;
30+
});
31+
},
1632
});
1733

18-
const sendChatMessage = (messageText) => {
19-
channel.publish({ name: 'chat-message', data: messageText });
20-
setMessageText('');
21-
inputBox.focus();
34+
const sendChatMessage = async (text) => {
35+
if (!sendMessage) {
36+
return;
37+
}
38+
try {
39+
await sendMessage({ text: text });
40+
setMessageText('');
41+
inputBox.current?.focus();
42+
} catch (error) {
43+
console.error('Error sending message:', error);
44+
}
2245
};
2346

2447
const handleFormSubmission = (event) => {
@@ -27,43 +50,37 @@ export default function ChatBox() {
2750
};
2851

2952
const handleKeyPress = (event) => {
30-
if (event.charCode !== 13 || messageTextIsEmpty) {
53+
if (event.key !== 'Enter' || event.shiftKey) {
3154
return;
3255
}
33-
sendChatMessage(messageText);
3456
event.preventDefault();
57+
sendChatMessage(messageText);
3558
};
3659

37-
const messages = receivedMessages.map((message, index) => {
38-
const author = message.connectionId === ably.connection.id ? 'me' : 'other';
60+
const messageElements = messages.map((message, index) => {
61+
const key = message.serial ?? index;
3962
return (
40-
<span key={index} className={styles.message} data-author={author}>
41-
{message.data}
63+
<span key={key} className={styles.message}>
64+
{message.text}
4265
</span>
4366
);
4467
});
4568

4669
useEffect(() => {
47-
messageEnd.scrollIntoView({ behaviour: 'smooth' });
48-
});
70+
messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });
71+
}, [messages]);
4972

5073
return (
5174
<div className={styles.chatHolder}>
5275
<div className={styles.chatText}>
53-
{messages}
54-
<div
55-
ref={(element) => {
56-
messageEnd = element;
57-
}}
58-
></div>
76+
{messageElements}
77+
<div ref={messageEndRef}></div>
5978
</div>
6079
<form onSubmit={handleFormSubmission} className={styles.form}>
6180
<textarea
62-
ref={(element) => {
63-
inputBox = element;
64-
}}
81+
ref={inputBox}
6582
value={messageText}
66-
placeholder="Type a message..."
83+
placeholder={'Type a message...'}
6784
onChange={(e) => setMessageText(e.target.value)}
6885
onKeyPress={handleKeyPress}
6986
className={styles.textarea}

package-lock.json

Lines changed: 93 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"format:check": "prettier --check --ignore-path .gitignore app components"
1313
},
1414
"dependencies": {
15-
"ably": "^2.0.4",
15+
"@ably/chat": "^0.6.0",
16+
"ably": "2.8.0",
1617
"next": "^14.2.3",
1718
"react": "^18.2.0",
1819
"react-dom": "^18.2.0"

0 commit comments

Comments
 (0)