Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 16002 | Rev 16004 | 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);
16002 stevensc 72
          scrollTo(scrollList);
15839 stevensc 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);
16002 stevensc 82
      scrollTo(scrollList, 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;
16003 stevensc 102
    const options = {
103
      top: distance,
104
      behavior: "smooth",
105
    };
106
 
16001 stevensc 107
    if (!distance) {
16003 stevensc 108
      divToScrollEl.scrollBy({ ...options, top: divToScrollEl.scrollHeight });
16001 stevensc 109
      return;
110
    }
16003 stevensc 111
    divToScrollEl.scrollBy(options);
11347 nelberth 112
  };
113
 
114
  const onClickEmoji = (event) => {
115
    const shortname = event.currentTarget.dataset.shortname;
15975 stevensc 116
    const currentText = inputTextEl.current.value;
15998 stevensc 117
    const cursorPosition = inputTextEl.current.selectionStart;
15975 stevensc 118
    const textBehind = currentText.substring(0, cursorPosition);
119
    const textForward = currentText.substring(cursorPosition);
15998 stevensc 120
    const unicode = emojione.shortnameToUnicode(shortname);
121
    inputTextEl.current.value = `${textBehind}${unicode}${textForward}`;
11347 nelberth 122
    inputTextEl.current.focus();
15975 stevensc 123
    inputTextEl.current.setSelectionRange(
15998 stevensc 124
      cursorPosition + unicode.length,
125
      cursorPosition + unicode.length
15975 stevensc 126
    );
11347 nelberth 127
  };
128
 
15880 stevensc 129
  const handleUploadFile = ({ target }) => {
130
    const file = target.files[0];
15975 stevensc 131
    if (!file) return;
15880 stevensc 132
    setSelectedFile(file);
11347 nelberth 133
  };
134
 
135
  const removeSelectedFile = () => {
136
    setSelectedFile("");
137
  };
138
 
15844 stevensc 139
  // On send
16001 stevensc 140
  const handleKeyDown = (e) => {
15999 stevensc 141
    if (e.key !== "Enter") return false;
16000 stevensc 142
    e.preventDefault();
15999 stevensc 143
    onHandleSubmit();
144
  };
145
 
15998 stevensc 146
  const onHandleSubmit = () => {
11347 nelberth 147
    const formData = new FormData();
15998 stevensc 148
    formData.append("message", emojione.toShort(inputTextEl.current.value));
149
    axios.post(url_send, formData).then(({ data: response }) => {
150
      const { data, success } = response;
151
      if (!success) {
152
        console.log("Ha ocurrido un error: " + data);
153
        return;
154
      }
155
      inputTextEl.current.value = "";
15943 stevensc 156
      setShowEmojione(false);
16002 stevensc 157
      scrollTo(scrollList);
15943 stevensc 158
    });
11347 nelberth 159
  };
160
 
161
  const handleSendFile = () => {
162
    const formData = new FormData();
163
    formData.append("file", selectedFile);
15880 stevensc 164
    axios.post(url_upload, formData).then(({ data: response }) => {
165
      const { success, data } = response;
166
      if (!success) {
167
        console.log("Ha ocurrido un error: " + data);
168
        return;
11347 nelberth 169
      }
15880 stevensc 170
      setSelectedFile("");
171
      setShowEmojione(false);
16002 stevensc 172
      scrollTo(scrollList);
11347 nelberth 173
    });
174
  };
175
 
15844 stevensc 176
  useEffect(() => {
177
    let timeInterval;
178
    if (loading) return;
179
    timeInterval = setTimeout(() => getMessages(), 2000);
180
 
181
    return () => {
182
      clearTimeout(timeInterval);
183
    };
15880 stevensc 184
  }, [loading]);
15844 stevensc 185
 
186
  useEffect(() => {
15880 stevensc 187
    setMessages([]);
188
    setOldMessages([]);
189
    setTotalPages(1);
190
    setCurrentPage(1);
191
  }, [entity]);
15844 stevensc 192
 
15880 stevensc 193
  useEffect(() => getOldMessages(), [currentPage]);
15844 stevensc 194
 
15880 stevensc 195
  useEffect(() => axios.post(url_mark_seen), []);
196
 
11347 nelberth 197
  return (
198
    <div className={styles.chat}>
16001 stevensc 199
      <MessagesList
200
        isLastPage={currentPage >= totalPages}
201
        messages={[...oldMessages, ...messages]}
202
        onIntersection={onIntersection}
203
        scrollRef={scrollList}
204
      />
15805 stevensc 205
      <div className={styles.chat__input__container}>
11347 nelberth 206
        {showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
207
        <form
208
          onSubmit={handleSubmit(onHandleSubmit)}
209
          encType="multipart/form-data"
210
        >
211
          <button
212
            type="button"
15836 stevensc 213
            className={"btn " + styles.icon_btn}
15833 stevensc 214
            onClick={() => fileInputEl.current.click()}
215
          >
216
            <AttachFileIcon />
217
          </button>
11347 nelberth 218
          <button
219
            type="button"
15836 stevensc 220
            className={"btn " + styles.icon_btn}
15833 stevensc 221
            onClick={() => setShowEmojione(!showEmojione)}
222
          >
223
            <InsertEmoticonIcon />
224
          </button>
11347 nelberth 225
          <input
226
            type="file"
15833 stevensc 227
            ref={(e) => (fileInputEl.current = e)}
11347 nelberth 228
            accept={permittedFiles}
15833 stevensc 229
            onChange={handleUploadFile}
11347 nelberth 230
            hidden
231
          />
232
          <textarea
233
            className={styles.chatInput}
234
            placeholder="Escribe un mensaje"
16002 stevensc 235
            onKeyDown={handleKeyDown}
11347 nelberth 236
            ref={inputTextEl}
16002 stevensc 237
            rows="1"
15833 stevensc 238
          />
15836 stevensc 239
          <button type="submit" className={"btn " + styles.send_btn}>
15835 stevensc 240
            <SendIcon />
11347 nelberth 241
          </button>
242
        </form>
243
      </div>
244
      {selectedFile && (
245
        <FileModal
246
          file={selectedFile}
247
          onCancel={removeSelectedFile}
248
          onSend={handleSendFile}
249
        />
250
      )}
251
    </div>
252
  );
253
};
254
 
255
export default Chat;