File size: 14,440 Bytes
a0fda44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
import React from "react";
import useTime from "../../../hooks/useTime";
import MessageCheck from "../../globals/MessageCheck";
import { useDispatch, useSelector } from "react-redux";
import { modalActions } from "../../../store/modalSlice";
import useModalBestPosition from "../../../hooks/useModalBestPosition";
import useChat from "../../../hooks/useChat";
import { chatListActions } from "../../../store/chatListSlice";
import Image from "../../globals/Image";
import { useEffect } from "react";
import { chatActions } from "../../../store/chatSlice";
import { useState } from "react";

function ChatItem({ chatData }) {
  // Chat options visibility
  const chatOptionVisible = useSelector(
    (state) => state.modalReducer.payload.chatRoomId === chatData.chatRoomId
  );

  // To know if chatItem was clicked to make chat room visible
  const [chatItemClicked, setChatItemClicked] = useState();

  const activeChat = useSelector(
    (state) => state.chatReducer.currentChatRoom._id === chatData.chatRoomId
  );

  const chatRoomShown = useSelector((state) => state.chatReducer.active);

  // Chat mode of user i.e Typing, recording
  const chatMode = useSelector((state) => {
    const chatIndex = state.chatListReducer.findIndex(
      (chat) => chat.chatRoomId === chatData.chatRoomId
    );

    return state.chatListReducer[chatIndex]?.mode;
  });

  // Currently logged in user id
  const userId = useSelector((state) => state.userReducer.user._id);

  // Set chat room function
  const { setChatRoom } = useChat(chatData, "chatList");

  // Format latest message date
  const formattedDate = useTime(chatData.latestMessage.timeSent);

  const dispatch = useDispatch();

  // returns function to get the best position for a modal
  const getBestModalPostion = useModalBestPosition();

  // Elements data to help with getting best position
  const elemData = {
    modalData: {
      width: 140,
      height: 80,
    },
    overlayId: "side-bar",
  };

  // show options handler
  const showOptions = (event) => {
    event.preventDefault();
    const positions = getBestModalPostion(event, elemData);
    dispatch(
      modalActions.openModal({
        type: "chatOptions",
        payload: chatData,
        positions,
      })
    );
  };

  // On mobile, enable holding down to show options
  const timeoutToShowOptions = (event) => {
    const timer = setTimeout(() => {
      showOptions(event);
    }, 250);

    event.currentTarget.addEventListener("mouseup", () => {
      clearTimeout(timer);
    });
  };

  useEffect(() => {
    if (activeChat && !chatItemClicked && chatRoomShown) {
      setChatRoom({ disableSettingChatRoomActive: true });
    }

    if (chatItemClicked) {
      setChatItemClicked(false);
    }
  }, [chatRoomShown]);

  return (
    <div
      onClick={() => {
        setChatRoom();
        setChatItemClicked(true);
      }}
      onContextMenu={showOptions}
      onMouseDown={timeoutToShowOptions}
      className={`p-[1rem] rounded-[1.5rem] not-selectable flex gap-[1rem] text-secondary-text group h-[75px] cursor-default ${
        activeChat
          ? "bg-cta-icon !text-white sm:bg-transparent"
          : "hover:bg-secondary-light-text"
      } ${
        chatOptionVisible &&
        `${
          activeChat ? "sm:bg-secondary-light-text" : "bg-secondary-light-text"
        }`
      }`}
    >
      {/* Avatar */}
      <Image
        src={chatData.profile.avatar}
        alt={chatData.profile.name || chatData.profile.username}
        className="w-[5.5rem] h-[5.5rem] rounded-full"
      />
      {/* Details */}
      <div className="flex-grow overflow-hidden">
        {/* Title */}
        <div
          className={`flex justify-between text-primary-text font-medium ${
            activeChat && "!text-white sm:!text-primary-text"
          }`}
        >
          <span>{chatData.profile.name || chatData.profile.username}</span>

          {/* Message check */}
          <span className="flex items-center gap-[.5rem]">
            {chatData.latestMessage.sender === userId && (
              <MessageCheck
                readStatus={chatData.latestMessage.readStatus}
                deliveredStatus={chatData.latestMessage.deliveredStatus}
                className={`${
                  activeChat && "!stroke-white sm:!stroke-secondary-text"
                }`}
              />
            )}
            <span className="text-[1.4rem] font-normal">{formattedDate}</span>
          </span>
        </div>

        {/* Subtitle */}
        <div className="flex justify-between">
          {/* Chat mode status */}
          {chatMode && (
            <span
              className={`text-cta-icon italic font-normal ${
                activeChat && "!text-white sm:!text-cta-icon"
              }`}
            >
              {chatMode} {chatMode === "recording" && "audio"}...
            </span>
          )}

          {/* Default without chatMode active */}
          {!chatMode && (
            <>
              {/* Latest text */}
              <span
                className={`flex-grow truncate text-primary-text overflow-y-hidden text-overflow-wrap ${
                  activeChat && "!text-white sm:!text-primary-text"
                }`}
              >
                {!(chatData.roomType === "Private") &&
                  !!chatData.latestMessage.sender && (
                    <span>{chatData.latestMessage.sender}: </span>
                  )}
                {chatData.latestMessage.messageType === "text" && (
                  <span
                    dangerouslySetInnerHTML={{
                      __html: chatData.latestMessage.message,
                    }}
                  ></span>
                )}

                {chatData.latestMessage.messageType === "image" && (
                  <span className="flex items-center gap-[.5rem]">
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="1em"
                      height="1em"
                      preserveAspectRatio="xMidYMid meet"
                      viewBox="0 0 24 24"
                    >
                      <path
                        fill="none"
                        stroke="currentColor"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth="1.5"
                        d="m2.25 15.75l5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0a.375.375 0 0 1 .75 0Z"
                        className={`stroke-secondary-text !fill-transparent ${
                          activeChat &&
                          "!stroke-white sm:!stroke-secondary-text"
                        }`}
                      />
                    </svg>
                    Photo
                  </span>
                )}

                {chatData.latestMessage.messageType === "voice" && (
                  <span className="flex items-center gap-[.5rem]">
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="1em"
                      height="1em"
                      preserveAspectRatio="xMidYMid meet"
                      viewBox="0 0 32 32"
                    >
                      <path
                        fill="currentColor"
                        d="M23 14v3a7 7 0 0 1-14 0v-3H7v3a9 9 0 0 0 8 8.94V28h-4v2h10v-2h-4v-2.06A9 9 0 0 0 25 17v-3Z"
                        className={`stroke-secondary-text !fill-transparent ${
                          activeChat &&
                          "!stroke-white sm:!stroke-secondary-text"
                        }`}
                      />
                      <path
                        fill="currentColor"
                        d="M16 22a5 5 0 0 0 5-5V7a5 5 0 0 0-10 0v10a5 5 0 0 0 5 5Z"
                        className={`stroke-secondary-text !fill-transparent ${
                          activeChat &&
                          "!stroke-white sm:!stroke-secondary-text"
                        }`}
                      />
                    </svg>
                    Voice Note
                  </span>
                )}

                {chatData.latestMessage.messageType === "call" && (
                  <span className="flex items-center gap-[.5rem] capitalize">
                    {chatData.latestMessage.callDetails.callType ===
                      "voice" && (
                      <svg
                        xmlns="http://www.w3.org/2000/svg"
                        width="1em"
                        height="1em"
                        preserveAspectRatio="xMidYMid meet"
                        viewBox="0 0 32 32"
                        className="w-[2rem] h-[2rem]"
                      >
                        <path
                          fill="currentColor"
                          d="M26 29h-.17C6.18 27.87 3.39 11.29 3 6.23A3 3 0 0 1 5.76 3h5.51a2 2 0 0 1 1.86 1.26L14.65 8a2 2 0 0 1-.44 2.16l-2.13 2.15a9.37 9.37 0 0 0 7.58 7.6l2.17-2.15a2 2 0 0 1 2.17-.41l3.77 1.51A2 2 0 0 1 29 20.72V26a3 3 0 0 1-3 3ZM6 5a1 1 0 0 0-1 1v.08C5.46 12 8.41 26 25.94 27a1 1 0 0 0 1.06-.94v-5.34l-3.77-1.51l-2.87 2.85l-.48-.06c-8.7-1.09-9.88-9.79-9.88-9.88l-.06-.48l2.84-2.87L11.28 5Z"
                          className={`stroke-secondary-text !fill-transparent ${
                            activeChat &&
                            "!stroke-white sm:!stroke-secondary-text"
                          }`}
                        />
                      </svg>
                    )}
                    {chatData.latestMessage.callDetails.callType ===
                      "video" && (
                      <svg
                        xmlns="http://www.w3.org/2000/svg"
                        width="1em"
                        height="1em"
                        preserveAspectRatio="xMidYMid meet"
                        viewBox="0 0 32 32"
                        className="w-[2rem] h-[2rem]"
                      >
                        <path
                          fill="currentColor"
                          d="M2 8v16h22v-3.375l4.563 2.28l1.437.72V8.375l-1.438.72L24 11.374V8H2zm2 2h18v12H4V10zm24 1.625v8.75l-4-2v-4.75l4-2z"
                          className={`stroke-secondary-text !fill-transparent ${
                            activeChat &&
                            "!stroke-white sm:!stroke-secondary-text"
                          }`}
                        />
                      </svg>
                    )}
                    {chatData.latestMessage.callDetails.callType} call
                  </span>
                )}
              </span>

              {/* When user has a message pinned and also has an unread message, the unread message indicator takes precedence */}
              <span className="">
                {chatData.unreadMessagesCount ? (
                  <span className="flex items-center justify-center rounded-full text-white bg-cta-icon min-w-[2.5rem] min-h-[2.5rem] px-[.8rem]">
                    {chatData.unreadMessagesCount}
                  </span>
                ) : (
                  chatData.pinned && (
                    <svg
                      width="25"
                      height="26"
                      viewBox="0 0 25 26"
                      fill="none"
                      xmlns="http://www.w3.org/2000/svg"
                    >
                      <path
                        d="M14.5187 6.5C14.5844 6.49988 14.6495 6.51272 14.7102 6.53777C14.771 6.56282 14.8262 6.5996 14.8727 6.646L19.8227 11.596C19.9164 11.6898 19.9691 11.8169 19.9691 11.9495C19.9691 12.0821 19.9164 12.2092 19.8227 12.303C19.3427 12.783 18.7507 12.891 18.3197 12.891C18.1427 12.891 17.9847 12.873 17.8597 12.852L14.7257 15.986C14.8082 16.3184 14.8617 16.6573 14.8857 16.999C14.9317 17.701 14.8537 18.686 14.1657 19.374C14.0719 19.4677 13.9448 19.5204 13.8122 19.5204C13.6796 19.5204 13.5524 19.4677 13.4587 19.374L10.6297 16.546L7.44768 19.728C7.25268 19.923 6.22868 20.63 6.03368 20.435C5.83868 20.24 6.54568 19.215 6.74068 19.021L9.92268 15.839L7.09468 13.01C7.00094 12.9162 6.94828 12.7891 6.94828 12.6565C6.94828 12.5239 7.00094 12.3968 7.09468 12.303C7.78268 11.615 8.76768 11.536 9.46968 11.583C9.81134 11.6069 10.1503 11.6605 10.4827 11.743L13.6167 8.61C13.5905 8.45772 13.5771 8.30351 13.5767 8.149C13.5767 7.719 13.6847 7.127 14.1657 6.646C14.2594 6.55253 14.3863 6.50003 14.5187 6.5V6.5ZM14.6407 8.612V8.61V8.612ZM14.6407 8.61V8.612C14.6696 8.69997 14.6734 8.79423 14.6519 8.88428C14.6304 8.97433 14.5842 9.05662 14.5187 9.122L10.9837 12.656C10.918 12.7214 10.8354 12.7673 10.7452 12.7884C10.655 12.8096 10.5606 12.8053 10.4727 12.776H10.4707L10.4567 12.772C10.3615 12.7435 10.2655 12.7182 10.1687 12.696C9.91712 12.6373 9.66133 12.5985 9.40368 12.58C8.98168 12.552 8.56768 12.588 8.22868 12.73L13.7387 18.239C13.8797 17.899 13.9157 17.486 13.8877 17.064C13.8622 16.7067 13.7978 16.3533 13.6957 16.01L13.6917 15.997V15.996C13.6621 15.9079 13.6577 15.8134 13.6789 15.723C13.7001 15.6325 13.7461 15.5498 13.8117 15.484L17.3477 11.949C17.4158 11.8805 17.5022 11.8332 17.5967 11.8128C17.6911 11.7924 17.7894 11.7997 17.8797 11.834L17.9757 11.856C18.0627 11.873 18.1837 11.89 18.3197 11.89C18.4337 11.89 18.5497 11.879 18.6627 11.85L14.6177 7.806C14.5887 7.919 14.5777 8.036 14.5777 8.149C14.5782 8.30438 14.599 8.45903 14.6397 8.609L14.6407 8.61Z"
                        className={`stroke-secondary-text fill-transparent ${
                          activeChat &&
                          "!stroke-white sm:!stroke-secondary-text"
                        }`}
                      />
                      <circle
                        cx="12.5"
                        cy="13"
                        r="12"
                        stroke="red"
                        className={`stroke-secondary-text ${
                          activeChat &&
                          "!stroke-white sm:!stroke-secondary-text"
                        }`}
                      />
                    </svg>
                  )
                )}
              </span>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

export default ChatItem;