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' ;
33import styles from './ChatBox.module.css' ;
44
55export 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 }
0 commit comments