@@ -27,6 +27,7 @@ import { URL } from "../../utils/axios/axiosInstance";
27
27
import { clearImages } from "../../store/actions/resetAction" ;
28
28
import { IoIosCloseCircle } from "react-icons/io" ;
29
29
import EmojiPicker , { EmojiStyle , Theme } from "emoji-picker-react" ;
30
+ import { Empty } from "antd" ;
30
31
31
32
const LiveChat = ( ) => {
32
33
const [ messages , setMessages ] = useState ( [ ] ) ;
@@ -71,7 +72,7 @@ const LiveChat = () => {
71
72
if ( user ) {
72
73
setCurrentUserId ( user . id ) ;
73
74
setIsLoggedIn ( true ) ;
74
- } else {
75
+ } else {
75
76
setIsLoggedIn ( false ) ;
76
77
setIsChatOpen ( false ) ;
77
78
setIsMinimized ( false ) ;
@@ -86,33 +87,33 @@ const LiveChat = () => {
86
87
} , [ images ] ) ;
87
88
88
89
useEffect ( ( ) => {
89
- if ( isLoggedIn ) {
90
+ if ( isLoggedIn ) {
90
91
const newSocket = io ( `${ URL } /chats` , {
91
92
auth : {
92
93
token : localStorage . getItem ( "token" ) ,
93
94
} ,
94
95
} ) ;
95
-
96
+
96
97
setSocket ( newSocket ) ;
97
-
98
+
98
99
newSocket . on ( "connect" , ( ) => {
99
100
newSocket . emit ( "requestPastMessages" ) ;
100
101
} ) ;
101
-
102
+
102
103
newSocket . on ( "userJoined" , ( data ) => {
103
104
setUsers ( ( prevUsers ) => [ ...prevUsers , data . user ] ) ;
104
105
} ) ;
105
-
106
+
106
107
newSocket . on ( "userLeft" , ( data ) => {
107
108
setUsers ( ( prevUsers ) =>
108
109
prevUsers . filter ( ( user ) => user . id !== data . user . id )
109
110
) ;
110
111
} ) ;
111
-
112
+
112
113
newSocket . on ( "chatMessage" , ( data ) => {
113
114
if ( isNotificationEnabled && ( ! isChatOpen || isMinimized ) ) {
114
115
notificationRef . current . play ( ) ;
115
- }
116
+ }
116
117
const newMessage = {
117
118
id : Date . now ( ) ,
118
119
userId : data . user . id ,
@@ -123,7 +124,6 @@ const LiveChat = () => {
123
124
} ;
124
125
setMessages ( ( prevMessages ) => [ ...prevMessages , newMessage ] ) ;
125
126
if ( data . user . id !== currentUserId ) {
126
-
127
127
if (
128
128
! lastReadTimestamp ||
129
129
new Date ( newMessage . timestamp ) > lastReadTimestamp
@@ -132,7 +132,7 @@ const LiveChat = () => {
132
132
}
133
133
}
134
134
} ) ;
135
-
135
+
136
136
newSocket . on ( "pastMessages" , ( data ) => {
137
137
const oldMessages = data . map ( ( msg ) => ( {
138
138
id : msg . id || Date . now ( ) ,
@@ -144,15 +144,15 @@ const LiveChat = () => {
144
144
} ) ) ;
145
145
setMessages ( oldMessages ) ;
146
146
} ) ;
147
-
147
+
148
148
newSocket . on ( "connect_error" , ( error ) => {
149
149
if ( error . message === "Authentication error" ) {
150
150
console . log ( "Authentication error detected. Closing chat." ) ;
151
151
setIsLoggedIn ( false ) ;
152
152
}
153
153
console . log ( "connection error" , error ) ;
154
154
} ) ;
155
-
155
+
156
156
return ( ) => {
157
157
newSocket . disconnect ( ) ;
158
158
} ;
@@ -211,11 +211,14 @@ const LiveChat = () => {
211
211
}
212
212
} , [ dispatch ] ) ;
213
213
214
- useEffect ( ( ) => {
215
- if ( messages . length > 0 && isChatOpen ) {
216
- lastMessageRef . current ?. scrollIntoView ( { behavior :"smooth" , block :"end" } )
214
+ useEffect ( ( ) => {
215
+ if ( messages . length > 0 && isChatOpen ) {
216
+ lastMessageRef . current ?. scrollIntoView ( {
217
+ behavior : "smooth" ,
218
+ block : "end" ,
219
+ } ) ;
217
220
}
218
- } , [ messages , isChatOpen ] ) ;
221
+ } , [ messages , isChatOpen ] ) ;
219
222
const handleChangeMessage = ( event ) => {
220
223
setCurrentMessage ( event . target . value ) ;
221
224
} ;
@@ -237,7 +240,7 @@ const LiveChat = () => {
237
240
) ;
238
241
input . focus ( ) ;
239
242
} , 0 ) ;
240
- setIsEmojiPickerOpen ( ( prev ) => ! prev )
243
+ setIsEmojiPickerOpen ( ( prev ) => ! prev ) ;
241
244
}
242
245
} ;
243
246
@@ -317,7 +320,6 @@ const LiveChat = () => {
317
320
} ;
318
321
} , [ isChatOpen , messages ] ) ;
319
322
320
-
321
323
useEffect ( ( ) => {
322
324
const chatContainer = chatMessagesRef . current ;
323
325
if ( isChatOpen && chatContainer ) {
@@ -438,83 +440,96 @@ const LiveChat = () => {
438
440
{ ! isMinimized && (
439
441
< >
440
442
< div className = "chat-messages" ref = { chatMessagesRef } >
441
- { messages . map ( ( msg , index ) => {
442
- let textImage = [ ] ;
443
- let messageText = msg . text ;
444
- const isFirstUnread =
445
- isUnread ( msg . timestamp ) &&
446
- ( index === 0 || ! isUnread ( messages [ index - 1 ] ?. timestamp ) ) ;
447
- if ( messageText ?. includes ( " + " ) ) {
448
- const [ imagesPart , ...messageParts ] =
449
- messageText . split ( " + " ) ;
450
- textImage = imagesPart
451
- . split ( ", " )
452
- . filter ( ( url ) => url . startsWith ( "http" ) ) ;
453
- messageText = messageParts . join ( " + " ) ;
454
- }
455
-
456
- return (
457
- < React . Fragment key = { msg . id } >
458
- { isFirstUnread && (
459
- < div className = "unread-badge-container" >
460
- < span className = "unread-badge" > New</ span >
461
- </ div >
462
- ) }
463
- < div
464
- className = { `chat-message ${ isUnread ( msg . timestamp ) ? "unread" : "" } ${
465
- msg . userId === currentUserId
466
- ? "chat-message-right"
467
- : "chat-message-left"
468
- } `}
469
- >
470
- < div className = "profile-image" >
471
- < img
472
- src = { msg . profileImage }
473
- alt = "User profile"
474
- className = "user-profile-img"
475
- />
476
- </ div >
477
- < div className = "message-content" >
478
- < span className = "username" >
479
- { msg . username ?. toLowerCase ( ) }
480
- </ span >
481
- < span style = { { marginBottom : ".5rem" } } >
482
- { messageText }
483
- </ span >
484
- { ( msg . images ?. length > 0 || textImage . length > 0 ) && (
485
- < div className = "images-container" >
486
- { ( msg . images || textImage ) . map (
487
- ( image : string , idx : number ) => (
488
- < div key = { idx } className = "imageDisplay" >
489
- < img
490
- src = { image }
491
- alt = { `Image ${ idx } ` }
492
- onClick = { ( ) => handleImageClick ( image ) }
493
- />
494
- < GrZoomIn
495
- className = "zoomIn"
496
- onClick = { ( ) => handleImageClick ( image ) }
497
- />
498
- </ div >
499
- )
500
- ) }
501
- </ div >
443
+ { messages . length > 0 ? (
444
+ messages . map ( ( msg , index ) => {
445
+ let textImage = [ ] ;
446
+ let messageText = msg . text ;
447
+ const isFirstUnread =
448
+ isUnread ( msg . timestamp ) &&
449
+ ( index === 0 ||
450
+ ! isUnread ( messages [ index - 1 ] ?. timestamp ) ) ;
451
+ if ( messageText ?. includes ( " + " ) ) {
452
+ const [ imagesPart , ...messageParts ] =
453
+ messageText . split ( " + " ) ;
454
+ textImage = imagesPart
455
+ . split ( ", " )
456
+ . filter ( ( url ) => url . startsWith ( "http" ) ) ;
457
+ messageText = messageParts . join ( " + " ) ;
458
+ }
459
+
460
+ return (
461
+ < React . Fragment key = { msg . id } >
462
+ { isFirstUnread && (
463
+ < div className = "unread-badge-container" >
464
+ < span className = "unread-badge" > New</ span >
465
+ </ div >
466
+ ) }
467
+ < div
468
+ className = { `chat-message ${ isUnread ( msg . timestamp ) ? "unread" : "" } ${
469
+ msg . userId === currentUserId
470
+ ? "chat-message-right"
471
+ : "chat-message-left"
472
+ } `}
473
+ >
474
+ < div className = "profile-image" >
475
+ < img
476
+ src = { msg . profileImage }
477
+ alt = "User profile"
478
+ className = "user-profile-img"
479
+ />
480
+ </ div >
481
+ < div className = "message-content" >
482
+ < span className = "username" >
483
+ { msg . username ?. toLowerCase ( ) }
484
+ </ span >
485
+ < span style = { { marginBottom : ".5rem" } } >
486
+ { messageText }
487
+ </ span >
488
+ { ( msg . images ?. length > 0 ||
489
+ textImage . length > 0 ) && (
490
+ < div className = "images-container" >
491
+ { ( msg . images || textImage ) . map (
492
+ ( image : string , idx : number ) => (
493
+ < div key = { idx } className = "imageDisplay" >
494
+ < img
495
+ src = { image }
496
+ alt = { `Image ${ idx } ` }
497
+ onClick = { ( ) => handleImageClick ( image ) }
498
+ />
499
+ < GrZoomIn
500
+ className = "zoomIn"
501
+ onClick = { ( ) => handleImageClick ( image ) }
502
+ />
503
+ </ div >
504
+ )
505
+ ) }
506
+ </ div >
507
+ ) }
508
+ < span className = "timestamp" >
509
+ { new Date ( msg . timestamp )
510
+ . toLocaleTimeString ( [ ] , {
511
+ hour : "2-digit" ,
512
+ minute : "2-digit" ,
513
+ hour12 : true ,
514
+ } )
515
+ . toUpperCase ( ) }
516
+ </ span >
517
+ </ div >
518
+ { index === messages . length - 1 && (
519
+ < div ref = { lastMessageRef } />
502
520
) }
503
- < span className = "timestamp" >
504
- { new Date ( msg . timestamp )
505
- . toLocaleTimeString ( [ ] , {
506
- hour : "2-digit" ,
507
- minute : "2-digit" ,
508
- hour12 : true ,
509
- } )
510
- . toUpperCase ( ) }
511
- </ span >
512
521
</ div >
513
- { index === messages . length - 1 && < div ref = { lastMessageRef } /> }
514
- </ div >
515
- </ React . Fragment >
516
- ) ;
517
- } ) }
522
+ </ React . Fragment >
523
+ ) ;
524
+ } )
525
+ ) : (
526
+ < div className = "no-chats-message" >
527
+ < Empty
528
+ image = { Empty . PRESENTED_IMAGE_SIMPLE }
529
+ description = { "No chats available. Start a conversation🤖" }
530
+ />
531
+ </ div >
532
+ ) }
518
533
</ div >
519
534
< div className = "chat-inputs" >
520
535
{ allImages && allImages . length > 0 && (
@@ -538,7 +553,7 @@ const LiveChat = () => {
538
553
) }
539
554
< div className = "chat-input" >
540
555
< input
541
- className = "input"
556
+ className = "input"
542
557
type = "text"
543
558
value = { currentMessage }
544
559
onChange = { handleChangeMessage }
@@ -571,7 +586,6 @@ const LiveChat = () => {
571
586
theme = { Theme . DARK }
572
587
emojiStyle = { EmojiStyle . GOOGLE }
573
588
onEmojiClick = { handleEmojiClick }
574
-
575
589
/>
576
590
</ div >
577
591
< input
0 commit comments