1+
2+ <div id =" chat-container" >
3+ <div id =" search-container" >
4+ <input type =" text" placeholder =" Search" />
5+ </div >
6+
7+ <div class =" new-message-container" onclick =" openModal()" >
8+ <a href =" #" >+</a >
9+ </div >
10+
11+ <div id =" chat-title" >
12+ <span id =" conversation-partner" ></span >
13+ <img src =" ./images/trash.png" alt =" Delete Conversation" />
14+ </div >
15+
16+ <!-- placeholder div if no messages are in messages area -->
17+ <div id =" chat-message-list" >
18+ <div class =" nothing" >select a conversation</div >
19+ </div >
20+
21+ <!-- send message form -->
22+ <form id =" chat-form" method =" post" enctype =" multipart/form-data" >
23+ <label for =" attachment" ><img src =" ./images/attachment.png" alt =" Add Attachment" /></label >
24+ <input type =" file" multiple name =" attachment" class =" hide" id =" attachment" />
25+ <input type =" text" name =" message" placeholder =" Type a message" autocomplete =" off" />
26+ </form >
27+
28+ </div >
29+ <% - include (' ./partials/add-conversation-modal.ejs' ); %>
30+
31+ <!-- import socket io client from cdn -->
32+ <script src =" https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.min.js" ></script >
33+
34+ <script >
35+ const form = document .querySelector (' #chat-form' );
36+ const messageContainer = document .querySelector (' #chat-message-list' );
37+ const chatTitleContainer = document .querySelector (' #conversation-partner' );
38+ const loggedinUserId = ' <%= loggedInUser.userid %>' ;
39+ const loggedinUserName = ' <%= loggedInUser.username %>' ;
40+ let participant = null ; // selected conversation participant object
41+ let current_conversation_id; // selected conversation id
42+
43+
44+ // socket initialization
45+ const socket = io (' <%= process.env.APP_URL %>' );
46+
47+
48+ // handle new/live incoming message from socket
49+ socket .on (" new_message" , data => {
50+ // only respond if current conversation is open in any client
51+ if (data .message .conversation_id == current_conversation_id) {
52+ // message class
53+ const messageClass = data .message .sender .id === loggedinUserId ? ' you-message' : ' other-message' ;
54+
55+ const senderAvatar = data .message .sender .avatar ? ` <img src="./uploads/avatars/${ data .message .sender .avatar } " alt="${ data .message .sender .name } " />` : ` <img src="./images/nophoto.png" alt="${ data .message .sender .name } " />` ;
56+ // message attachments
57+ let attachments = ' <div class="attachments">' ;
58+ if (data .message .attachment && data .message .attachment .length > 0 ) {
59+ data .message .attachment .forEach (attachment => {
60+ attachments += ` <img src="./uploads/attachments/${ attachment} " /> ` ;
61+ });
62+ }
63+ attachments += ' </div>' ;
64+ let messageHTML;
65+ // do not show avatar for loggedin user
66+ if (data .message .sender .id == loggedinUserId) {
67+ messageHTML = ` <div class="message-row ${ messageClass} "><div class="message-content">
68+ <div class="message-text">${ data .message .message } </div>
69+ ${ attachments}
70+ <div class="message-time">${ moment (data .message .date_time ).fromNow ()} </div>
71+ </div></div>` ;
72+ } else {
73+ messageHTML = ` <div class="message-row ${ messageClass} "><div class="message-content">
74+ ${ senderAvatar}
75+ <div class="message-text">${ data .message .message } </div>
76+ ${ attachments}
77+ <div class="message-time">${ moment (data .message .date_time ).fromNow ()} </div>
78+ </div></div>` ;
79+ }
80+ // append the inoming message to message area as last item
81+ document .querySelector (' #chat-message-list > .message-row:first-child' ).insertAdjacentHTML (' beforeBegin' , messageHTML);
82+ }
83+ });
84+
85+
86+ // get messages of a conversation
87+ async function getMessages (conversation_id , current_conversation_name ){
88+ // messages failure toast
89+ const messagesFailureToast = Toastify ({
90+ text: " Error loading messages!" ,
91+ duration: 1000 ,
92+ });
93+ let response = await fetch (` /inbox/messages/${ conversation_id} ` );
94+ const result = await response .json ();
95+ if (! result .errors && result .data ) {
96+ form .style .visibility = ' visible' ;
97+
98+ const {data , user , conversation_id } = result;
99+ participant = data .participant ;
100+ current_conversation_id = conversation_id;
101+ if (data .messages ) {
102+ let allMessages = ' ' ;
103+ if (data .messages .length > 0 ) {
104+ data .messages .forEach ((message ) => {
105+ let senderAvatar = message .sender .avatar ? ` ./uploads/avatars/${ message .sender .avatar } ` : ' ./images/nophoto.png' ;
106+ const messageClass = message .sender .id === loggedinUserId ? ' you-message' : ' other-message' ;
107+ const showAvatar = message .sender .id === loggedinUserId ? ' ' : ` <img src="${ senderAvatar} " alt="${ message .sender .name } " />` ;
108+ // message attachments
109+ let attachments = ' <div class="attachments">' ;
110+ if (message .attachment && message .attachment .length > 0 ) {
111+ message .attachment .forEach (attachment => {
112+ attachments += ` <img src="./uploads/attachments/${ attachment} " /> ` ;
113+ });
114+ }
115+ attachments += ' </div>' ;
116+ // final message html
117+ let messageHTML = ` <div class="message-row ${ messageClass} "><div class="message-content">
118+ ${ showAvatar}
119+ <div class="message-text">${ message .text } </div>
120+ ${ attachments}
121+ <div class="message-time">${ moment (message .date_time ).fromNow ()} </div>
122+ </div></div>` ;
123+ allMessages += messageHTML;
124+ messageContainer .innerHTML = allMessages;
125+ });
126+ } else if (data .messages .length === 0 ) {
127+ messageContainer .innerHTML = ' <div class="message-row"></div>' ;
128+ }
129+ chatTitleContainer .textContent = current_conversation_name;
130+ }
131+ } else {
132+ messagesFailureToast .showToast ();
133+ }
134+ }
135+
136+
137+
138+ // message sending
139+ form .onsubmit = async function (event ) {
140+ event .preventDefault ();
141+ const sendMessageFailureToast = Toastify ({
142+ text: " Error sending message" ,
143+ duration: 1000 ,
144+ });
145+ // prepare the form data
146+ const formData = new FormData (form);
147+ formData .append (' receiverId' , participant .id );
148+ formData .append (' receiverName' , participant .name );
149+ formData .append (' avatar' , participant .avatar || ' ' );
150+ formData .append (' conversationId' , current_conversation_id);
151+ // send the request to server
152+ let response = await fetch (" /inbox/message" , {
153+ method: " POST" ,
154+ body: formData,
155+ });
156+ // get response
157+ let result = await response .json ();
158+ if (! result .errors ) {
159+ form .reset (); // reset the form
160+ } else {
161+ sendMessageFailureToast .showToast ();
162+ }
163+ }
164+
165+
166+
167+ </script >
168+ </body >
169+ </html >
0 commit comments