Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 16004 | Rev 16226 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
15834 stevensc 1
import React, { useEffect, useRef, useState } from "react";
15801 stevensc 2
import { axios } from "../../../utils";
15834 stevensc 3
import { useForm } from "react-hook-form";
11347 nelberth 4
 
5
import Emojione from "./emojione/Emojione";
6
import FileModal from "./fileModal/FileModal";
15851 stevensc 7
import MessagesList from "./messages/MessagesList";
15834 stevensc 8
import AttachFileIcon from "@mui/icons-material/AttachFile";
9
import InsertEmoticonIcon from "@mui/icons-material/InsertEmoticon";
15835 stevensc 10
import SendIcon from "@mui/icons-material/Send";
11347 nelberth 11
 
15834 stevensc 12
import styles from "./chat.module.scss";
13
 
11347 nelberth 14
const permittedFiles =
15
  "video/mp4, video/mpeg, video/webm, application/pdf, image/jpeg, image/png, image/jpg";
16
 
15834 stevensc 17
const Chat = ({ entity }) => {
15839 stevensc 18
  const [oldMessages, setOldMessages] = useState([]);
15844 stevensc 19
  const [messages, setMessages] = useState([]);
15839 stevensc 20
  const [totalPages, setTotalPages] = useState(1);
21
  const [currentPage, setCurrentPage] = useState(1);
16004 stevensc 22
 
15839 stevensc 23
  const [loading, setLoading] = useState(false);
16004 stevensc 24
  const [isGettingMessages, setIsGettingMessages] = useState(false);
15839 stevensc 25
 
11347 nelberth 26
  const [showEmojione, setShowEmojione] = useState(false);
27
  const [selectedFile, setSelectedFile] = useState("");
28
 
16006 stevensc 29
  const { handleSubmit } = useForm();
15834 stevensc 30
 
16001 stevensc 31
  const scrollList = useRef(null);
11347 nelberth 32
  const inputTextEl = useRef(null);
33
  const fileInputEl = useRef(null);
15834 stevensc 34
 
35
  const {
36
    url_get_all_messages,
37
    url_send,
38
    url_upload,
39
    url_close,
40
    url_mark_seen,
41
    type,
42
  } = entity;
43
 
15844 stevensc 44
  // Get messages
45
  const getMessages = () => {
15839 stevensc 46
    setLoading(true);
47
    axios
48
      .get(url_get_all_messages)
49
      .then(({ data: response }) => {
50
        const { data, success } = response;
51
 
52
        if (!success) {
53
          return console.log("Ha ocurrido un error");
11347 nelberth 54
        }
15839 stevensc 55
 
56
        const messageResponse = [...data.items].reverse();
57
        const updatedMessages = messageResponse.reduce(
58
          (acum, updatedMessage) => {
59
            if (
60
              messages.findIndex(
61
                (message) => message.id === updatedMessage.id
62
              ) === -1
63
            ) {
64
              acum = [...acum, updatedMessage];
65
            }
66
            return acum;
67
          },
68
          []
69
        );
70
 
71
        if (updatedMessages.length > 0) {
15975 stevensc 72
          setMessages((prevMessages) => [...prevMessages, ...updatedMessages]);
15839 stevensc 73
          setTotalPages(data.pages);
16002 stevensc 74
          scrollTo(scrollList);
15839 stevensc 75
        }
76
      })
77
      .finally(() => setLoading(false));
11347 nelberth 78
  };
79
 
15851 stevensc 80
  const onIntersection = (entities) => {
15844 stevensc 81
    const target = entities[0];
15880 stevensc 82
    if (target.isIntersecting && currentPage < totalPages) {
16004 stevensc 83
      setIsGettingMessages(true);
15880 stevensc 84
      setCurrentPage((prevState) => prevState + 1);
16002 stevensc 85
      scrollTo(scrollList, 200);
15844 stevensc 86
    }
87
  };
88
 
15860 stevensc 89
  const getOldMessages = () => {
16004 stevensc 90
    setIsGettingMessages(true);
15844 stevensc 91
    axios
15860 stevensc 92
      .get(`${url_get_all_messages}?page=${currentPage}`)
15844 stevensc 93
      .then(({ data: response }) => {
94
        const { data, success } = response;
95
        if (success && data.page > 1) {
96
          setOldMessages([...data.items.slice().reverse(), ...oldMessages]);
97
        }
98
      })
16004 stevensc 99
      .finally(() => setIsGettingMessages(false));
15844 stevensc 100
  };
101
 
102
  //Utilitys
16001 stevensc 103
  const scrollTo = (element, distance) => {
104
    const divToScrollEl = element.current;
16003 stevensc 105
    const options = {
106
      top: distance,
107
      behavior: "smooth",
108
    };
109
 
16001 stevensc 110
    if (!distance) {
16003 stevensc 111
      divToScrollEl.scrollBy({ ...options, top: divToScrollEl.scrollHeight });
16001 stevensc 112
      return;
113
    }
16003 stevensc 114
    divToScrollEl.scrollBy(options);
11347 nelberth 115
  };
116
 
117
  const onClickEmoji = (event) => {
118
    const shortname = event.currentTarget.dataset.shortname;
15975 stevensc 119
    const currentText = inputTextEl.current.value;
15998 stevensc 120
    const cursorPosition = inputTextEl.current.selectionStart;
15975 stevensc 121
    const textBehind = currentText.substring(0, cursorPosition);
122
    const textForward = currentText.substring(cursorPosition);
15998 stevensc 123
    const unicode = emojione.shortnameToUnicode(shortname);
124
    inputTextEl.current.value = `${textBehind}${unicode}${textForward}`;
11347 nelberth 125
    inputTextEl.current.focus();
15975 stevensc 126
    inputTextEl.current.setSelectionRange(
15998 stevensc 127
      cursorPosition + unicode.length,
128
      cursorPosition + unicode.length
15975 stevensc 129
    );
11347 nelberth 130
  };
131
 
15880 stevensc 132
  const handleUploadFile = ({ target }) => {
133
    const file = target.files[0];
15975 stevensc 134
    if (!file) return;
15880 stevensc 135
    setSelectedFile(file);
11347 nelberth 136
  };
137
 
138
  const removeSelectedFile = () => {
139
    setSelectedFile("");
140
  };
141
 
15844 stevensc 142
  // On send
16001 stevensc 143
  const handleKeyDown = (e) => {
15999 stevensc 144
    if (e.key !== "Enter") return false;
16000 stevensc 145
    e.preventDefault();
15999 stevensc 146
    onHandleSubmit();
147
  };
148
 
15998 stevensc 149
  const onHandleSubmit = () => {
11347 nelberth 150
    const formData = new FormData();
15998 stevensc 151
    formData.append("message", emojione.toShort(inputTextEl.current.value));
152
    axios.post(url_send, formData).then(({ data: response }) => {
153
      const { data, success } = response;
154
      if (!success) {
155
        console.log("Ha ocurrido un error: " + data);
156
        return;
157
      }
158
      inputTextEl.current.value = "";
15943 stevensc 159
      setShowEmojione(false);
16002 stevensc 160
      scrollTo(scrollList);
15943 stevensc 161
    });
11347 nelberth 162
  };
163
 
164
  const handleSendFile = () => {
165
    const formData = new FormData();
166
    formData.append("file", selectedFile);
15880 stevensc 167
    axios.post(url_upload, formData).then(({ data: response }) => {
168
      const { success, data } = response;
169
      if (!success) {
170
        console.log("Ha ocurrido un error: " + data);
171
        return;
11347 nelberth 172
      }
15880 stevensc 173
      setSelectedFile("");
174
      setShowEmojione(false);
16002 stevensc 175
      scrollTo(scrollList);
11347 nelberth 176
    });
177
  };
178
 
15844 stevensc 179
  useEffect(() => {
180
    let timeInterval;
181
    if (loading) return;
182
    timeInterval = setTimeout(() => getMessages(), 2000);
183
 
184
    return () => {
185
      clearTimeout(timeInterval);
186
    };
15880 stevensc 187
  }, [loading]);
15844 stevensc 188
 
189
  useEffect(() => {
15880 stevensc 190
    setMessages([]);
191
    setOldMessages([]);
192
    setTotalPages(1);
193
    setCurrentPage(1);
194
  }, [entity]);
15844 stevensc 195
 
15880 stevensc 196
  useEffect(() => getOldMessages(), [currentPage]);
15844 stevensc 197
 
15880 stevensc 198
  useEffect(() => axios.post(url_mark_seen), []);
199
 
11347 nelberth 200
  return (
201
    <div className={styles.chat}>
16006 stevensc 202
      <div className={styles.chat_header}>
203
        <h2>{entity.name}</h2>
204
      </div>
16001 stevensc 205
      <MessagesList
206
        isLastPage={currentPage >= totalPages}
207
        messages={[...oldMessages, ...messages]}
208
        onIntersection={onIntersection}
209
        scrollRef={scrollList}
16004 stevensc 210
        isLoading={isGettingMessages}
16001 stevensc 211
      />
15805 stevensc 212
      <div className={styles.chat__input__container}>
11347 nelberth 213
        {showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
214
        <form
215
          onSubmit={handleSubmit(onHandleSubmit)}
216
          encType="multipart/form-data"
217
        >
218
          <button
219
            type="button"
15836 stevensc 220
            className={"btn " + styles.icon_btn}
15833 stevensc 221
            onClick={() => fileInputEl.current.click()}
222
          >
223
            <AttachFileIcon />
224
          </button>
11347 nelberth 225
          <button
226
            type="button"
15836 stevensc 227
            className={"btn " + styles.icon_btn}
15833 stevensc 228
            onClick={() => setShowEmojione(!showEmojione)}
229
          >
230
            <InsertEmoticonIcon />
231
          </button>
11347 nelberth 232
          <input
233
            type="file"
15833 stevensc 234
            ref={(e) => (fileInputEl.current = e)}
11347 nelberth 235
            accept={permittedFiles}
15833 stevensc 236
            onChange={handleUploadFile}
11347 nelberth 237
            hidden
238
          />
239
          <textarea
240
            className={styles.chatInput}
241
            placeholder="Escribe un mensaje"
16002 stevensc 242
            onKeyDown={handleKeyDown}
11347 nelberth 243
            ref={inputTextEl}
16002 stevensc 244
            rows="1"
15833 stevensc 245
          />
15836 stevensc 246
          <button type="submit" className={"btn " + styles.send_btn}>
15835 stevensc 247
            <SendIcon />
11347 nelberth 248
          </button>
249
        </form>
250
      </div>
251
      {selectedFile && (
252
        <FileModal
253
          file={selectedFile}
254
          onCancel={removeSelectedFile}
255
          onSend={handleSendFile}
256
        />
257
      )}
258
    </div>
259
  );
260
};
261
 
262
export default Chat;