Proyectos de Subversion LeadersLinked - Backend

Rev

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