Rev 15805 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
import {axios} from "../../../utils";
import React, { useEffect, useRef } from "react";
import { useState } from "react";
import styles from "./chat.module.scss";
import { useForm } from "react-hook-form";
import Emojione from "./emojione/Emojione";
import FileModal from "./fileModal/FileModal";
import Messages from "./messages/Messages";
const permittedFiles =
"video/mp4, video/mpeg, video/webm, application/pdf, image/jpeg, image/png, image/jpg";
const Chat = (props) => {
// props destructuring
const {
url_get_all_messages,
url_send,
url_upload,
url_close,
url_mark_seen,
type,
} = props.entity;
// react hook form
const { handleSubmit, register } = useForm();
// states
const [messages, setMessages] = useState([]);
const [newMessages, setNewMessages] = useState([]);
const [showEmojione, setShowEmojione] = useState(false);
const [selectedFile, setSelectedFile] = useState("");
const [pages, setPages] = useState(1);
const [currentPage, setCurrentPage] = useState(1);
const [oldMessages, setOldMessages] = useState([]);
// refs
const bottomToScroll = useRef(null);
const inputTextEl = useRef(null);
const fileInputEl = useRef(null);
const loadMoreEl = useRef();
const divToScroll = useRef(null);
const [urlSearch, setUrlSearch] = useState(url_get_all_messages || '')
let heartBeatInterval;
// useEffects
useEffect(() => {
/* setInterval */
clearInterval(heartBeatInterval);
heartBeatInterval = setInterval(() => {
chatHeartbeat();
}, 800);
return () => {
clearInterval(heartBeatInterval);
};
}, [newMessages, oldMessages]);
// infiniteScroll
useEffect(() => {
const options = {
root: null,
rootMargin: "0px",
threshold: 1.0,
};
const observer = new IntersectionObserver(handleObserver, options);
if (loadMoreEl.current) {
observer.observe(loadMoreEl.current);
}
return () => {
observer.disconnect();
};
}, [pages]);
useEffect(() => {
loadOldMessages();
}, [currentPage]);
useEffect(async () => {
const resData = (await axios.post(url_mark_seen)).data;
(resData);
}, []);
// useEffect(() => {
// shouldScrollToBottom.current = true;
// }, [newMessages]);
// useEffect(() => {
// setMessages([...oldMessages, ...newMessages]);
// ("before scroll");
// }, [newMessages, oldMessages]);
// useEffect(() => {
// if (shouldScrollToBottom.current) {
// scrollToBottom();
// shouldScrollToBottom.current = false;
// }
// }, [shouldScrollToBottom.current]);
// heartbeat function
const chatHeartbeat = async () => {
axios.get(url_get_all_messages).then((response) => {
const resData = response.data;
const isNewProp = url_get_all_messages !== urlSearch
if (resData.success) {
const updatedNewMessages = resData.data.items.slice();
let newNewMessages = [];
updatedNewMessages.map((updatedNewMessage) => {
const existInNewMessages = newMessages.findIndex(
(newMessage) => newMessage.id === updatedNewMessage.id
);
if (existInNewMessages === -1) {
newNewMessages = [updatedNewMessage, ...newNewMessages];
setPages(resData.data.pages);
}
});
if (newNewMessages.length > 0) {
setNewMessages((prevState) => [...prevState, ...newNewMessages]);
}
}
});
};
// utilsFunctions
const scrollToBottom = () => {
("scrolled");
const element = bottomToScroll.current;
const divToScrollEl = divToScroll.current;
divToScrollEl.scrollIntoView({ behavior: "smooth" });
};
const onClickEmoji = (event) => {
const shortname = event.currentTarget.dataset.shortname;
const currentText = inputTextEl.current.value;
let cursorPosition = inputTextEl.current.selectionStart;
const textBehind = currentText.substring(0, cursorPosition);
const textForward = currentText.substring(cursorPosition);
inputTextEl.current.value = `${textBehind}${shortname}${textForward}`;
inputTextEl.current.focus();
inputTextEl.current.setSelectionRange(
cursorPosition + shortname.length,
cursorPosition + shortname.length
);
};
const handleUploadFile = (e) => {
const file = e.target.files[0];
if (file) {
setSelectedFile(file);
}
};
const removeSelectedFile = () => {
setSelectedFile("");
};
const handleObserver = async (entities) => {
const target = entities[0];
if (target.isIntersecting) {
if (currentPage < pages) {
setCurrentPage((prevState) => prevState + 1);
bottomToScroll.current.scrollBy(0, 200);
}
}
};
const loadOldMessages = async () => {
if (currentPage < pages && currentPage > 1) {
}
await axios
.get(url_get_all_messages, {
params: {
page: currentPage,
},
})
.then(async (response) => {
const resData = response.data;
if (resData.success) {
if (resData.data.page > 1) {
setOldMessages([
...resData.data.items.slice().reverse(),
...oldMessages,
]);
}
}
});
};
// on send message
const onHandleSubmit = (data, event) => {
const formData = new FormData();
Object.entries(data).map(([key, value]) => {
formData.append(key, value);
});
event.target.reset();
axios.post(url_send, formData).then((response) => {
setShowEmojione(false);
});
};
// on send file
const handleSendFile = () => {
const formData = new FormData();
formData.append("file", selectedFile);
axios.post(url_upload, formData).then(async (response) => {
const resData = response.data;
if (resData.success) {
setSelectedFile("");
setShowEmojione(false);
}
});
};
return (
<div className={styles.chat}>
<div className={styles.messagesContainer} ref={bottomToScroll}>
<div className={styles.messageWrapper}>
{currentPage < pages && (
<p ref={loadMoreEl} style={{ marginTop: ".5rem" }}>
Cargando...
</p>
)}
<Messages
oldMessages={oldMessages}
newMessages={newMessages}
onScrollToBottom={scrollToBottom}
chatType={type}
/>
{/* {messages.map((message) => (
<Message message={message} />
))} */}
<div ref={divToScroll}></div>
</div>
</div>
<div className={styles.chatInputContainer}>
{showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
<form
onSubmit={handleSubmit(onHandleSubmit)}
encType="multipart/form-data"
>
<button
type="button"
className={`${styles.inputIcon} ti-clip icon uploadFile`}
id="uploadFile"
onClick={() => {
fileInputEl.current.click();
}}
></button>
<button
type="button"
className={`${styles.inputIcon} ti-face-smile icon btn-emoji`}
id="toggle-emoji"
onClick={() => {
setShowEmojione(!showEmojione);
}}
></button>
<input
type="file"
name="file"
id="file"
ref={(e) => {
fileInputEl.current = e;
}}
accept={permittedFiles}
hidden
onChange={handleUploadFile}
/>
<textarea
className={styles.chatInput}
id="message"
name="message"
placeholder="Escribe un mensaje"
rows="1"
ref={inputTextEl}
></textarea>
<button type="submit" href="#" className={styles.sendBtn}>
Enviar
</button>
</form>
</div>
{selectedFile && (
<FileModal
file={selectedFile}
onCancel={removeSelectedFile}
onSend={handleSendFile}
/>
)}
</div>
);
};
export default Chat;