Untitled
unknown
plain_text
2 years ago
5.1 kB
2
Indexable
import React, { useEffect, useRef, useState } from 'react'; import firebase from 'firebase/app'; import { useCollectionData } from 'react-firebase-hooks/firestore'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPaperPlane, faFile, faSpinner } from '@fortawesome/free-solid-svg-icons'; import ChatMessage from './ChatMessage'; import 'firebase/storage'; import './ChatRoom.css'; function ChatRoom() { const auth = firebase.auth(); const firestore = firebase.firestore(); const database = firebase.database(); const fileInputRef = useRef(null); const dummy = useRef(); const messagesRef = firestore.collection('messages'); const query = messagesRef.orderBy('createdAt'); const [messages] = useCollectionData(query, { idField: 'id' }); const [formValue, setFormValue] = useState(''); const [isSending, setIsSending] = useState(false); const [isLoadingFile, setIsLoadingFile] = useState(false); const [username, setUsername] = useState(null); const [selectedFile, setSelectedFile] = useState(null); const scrollToBottom = () => { dummy.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(() => { let isMounted = true; scrollToBottom(); const fetchUsername = async () => { const uid = auth.currentUser.uid; const usernameRef = database.ref(`users/${uid}/username`); const usernameSnapshot = await usernameRef.once('value'); let username = usernameSnapshot.val(); if (!username) { const user = auth.currentUser; username = user.displayName || user.email; usernameRef.set(username); } if (isMounted) { setUsername(username); } }; if (auth.currentUser) { fetchUsername(); } return () => { isMounted = false; }; }, [auth, database]); const handleFileClick = () => { if (fileInputRef.current) { fileInputRef.current.focus(); } }; const handleSendMessage = async (e) => { e.preventDefault(); setIsSending(true); const { uid, photoURL, displayName, email } = auth.currentUser; if (selectedFile && selectedFile.length > 0) { setIsLoadingFile(true); const fileSize = selectedFile && selectedFile[0] && selectedFile[0].size / 1024 / 1024; // convert to MB if (fileSize > 2) { alert('Maximum file size should be 2MB'); setIsSending(false); setIsLoadingFile(false); return; } } const storageRef = firebase.storage().ref(); for (let i = 0; selectedFile && i < selectedFile.length; i++) { const file = selectedFile[i]; const newFile = new File([file], `${Date.now()}-${file.name}`); const fileRef = storageRef.child(newFile.name); await fileRef.put(newFile); const fileUrl = await fileRef.getDownloadURL(); await messagesRef.add({ fileUrl, createdAt: firebase.firestore.FieldValue.serverTimestamp(), uid, photoURL, username, displayName, email, }); } setSelectedFile(null); // clear selected file after upload setIsLoadingFile(false); if (formValue.trim() !== '') { if (formValue.length > 200) { alert('Word limit is 200'); setIsSending(false); return; } await messagesRef.add({ text: formValue, createdAt: firebase.firestore.FieldValue.serverTimestamp(), uid, photoURL, username, displayName, email, }); setFormValue(''); } scrollToBottom(); setIsSending(false); // reset the isSending state after the message is sent }; return ( <> <main> {messages && messages.map((msg, index, pool) => { const prev = pool[index - 1]; const next = pool[index + 1]; return ( <ChatMessage key={msg.id} message={msg} id={msg.id} uid={msg.uid} neighbour={{ prev, next }} /> ); })} <span ref={dummy}></span> </main> <form onSubmit={handleSendMessage}> <input value={formValue} onChange={(e) => setFormValue(e.target.value)} placeholder="Type a message" /> <label className='fileicon'> {/* use the ref to the file input element */} <input type="file" ref={fileInputRef} onChange={(e) => setSelectedFile(e.target.files)} hidden multiple /> <FontAwesomeIcon icon={faFile} onClick={handleFileClick} /> </label> <button className="chat-message-button" type="submit" disabled={isLoadingFile || (!selectedFile && (!formValue || isSending))} > {isLoadingFile ? ( <FontAwesomeIcon icon={faSpinner} spin /> ) : ( <FontAwesomeIcon icon={faPaperPlane} /> )} </button> </form> </> ); } export default ChatRoom
Editor is loading...