Proyectos de Subversion LeadersLinked - Backend

Rev

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