Untitled

 avatar
unknown
plain_text
2 years ago
6.6 kB
5
Indexable
import React, { useState, useEffect, useRef } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';
import { faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import DOMPurify from 'dompurify';
const ChatMessage = (props) => {
  const { text, uid, fileUrl } = props.message;
  const messageClass = uid === firebase.auth().currentUser.uid ? 'sent' : 'received';
  const [username, setUsername] = useState(null);
  const [taggedText, setTaggedText] = useState(null);
  const [thumbnail, setThumbnail] = useState(null);
  const canvasRef = useRef(null);
  const handleDeleteClick = async () => {
    const confirmed = window.confirm("Are you sure you want to delete this message?");
    if (confirmed) {
      const db = firebase.firestore();
      await db.collection("messages").doc(props.id).delete();
    }
  };
  const createThumbnail = (videoUrl) => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    const video = document.createElement('video');
    video.src = videoUrl;
    video.addEventListener('loadeddata', () => {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      const dataURL = canvas.toDataURL();
      setThumbnail(dataURL);
    });
  };
  useEffect(() => {
    const fetchUsernameAndTaggedText = async () => {
      const usernameSnapshot = await firebase.database().ref(`users/${uid}/username`).once('value');
      const usernameData = usernameSnapshot.val();
      if (usernameData) {
        setUsername(usernameData);
      } else {
        setUsername(firebase.auth().displayName);
      }
  
      const tagRegex = /@([\w\s]+)/g;
      const matches = text ? text.match(tagRegex) : null;
      if (matches) {
        const replacedMatches = await Promise.all(matches.map(async (match) => {
          const username = match.trim().substring(1);
          const userRef = firebase.database().ref(`users`).orderByChild('username').equalTo(username);
          const snapshot = await userRef.once('value');
          const user = snapshot.val();
          if (user) {
            const uid = Object.keys(user)[0];
            return uid;
          } else {
            return null;
          }
        }));
        let currentIndex = 0;
        const newTaggedText = text.replace(tagRegex, (match) => {
          const uid = replacedMatches[currentIndex++];
          if (uid) {
            return `<a href="/profile/${uid}" style="color: blue;">${match}</a>`;
          } else {
            return match;
          }
        });
        const linkRegex = /(?:^|[^"'])(https?:\/\/[^\s"]+)(?=["']|$)/g;
        const newLinkedText = newTaggedText.replace(linkRegex, (match) => {
          return `<a href="${match}" style="color: blue;" target="_blank">${match}</a>`;
        });
        setTaggedText(newLinkedText);
  
        // code block to generate video thumbnail
        if (fileUrl && fileUrl.endsWith('.mp4')) {
          const video = document.createElement('video');
          video.preload = 'metadata';
          video.src = fileUrl;
          video.currentTime = 5;
          video.onseeked = () => {
            const canvas = document.createElement('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            const dataURL = canvas.toDataURL('image/png');
            setThumbnail(dataURL);
            video.remove();
          };
          // call createThumbnail function
          createThumbnail(fileUrl);
        }
  
      } else {
        const linkRegex = /(?:^|[^"'])(https?:\/\/[^\s"]+)(?=["']|$)/g;
        const newLinkedText = text ? text.replace(linkRegex, (match) => {
          return `<a href="${match}" style="color: blue;" target="_blank">${match}</a>`;
        }) : null;
        if (newLinkedText !== text) {
          setTaggedText(newLinkedText);
        } else {
          setTaggedText(text);
        }
      }
    };
    fetchUsernameAndTaggedText();
  }, [uid, text, taggedText, fileUrl]);  
    const usernameClass = messageClass === 'sent' ? 'username-sent' : 'username-received';
    const [showDelete, setShowDelete] = useState(false);
  
    const showDeleteButton = () => {
      if (uid === firebase.auth().currentUser.uid) {
        setShowDelete(true);
      }
    };
  
    const hideDeleteButton = () => {
      setShowDelete(false);
    };
    const sanitizedText = DOMPurify.sanitize(taggedText, { ALLOWED_TAGS: ['a'], ALLOWED_ATTR: ['href'] });
    const safeHTML = `<span class="${usernameClass}">${username}: </span>${sanitizedText.replace(/<a /g, '<a style="color: blue;" ')}`;//target="_blank" 
        return (
          <div
            className={`message ${messageClass}`}
            onMouseEnter={showDeleteButton}
            onMouseLeave={hideDeleteButton}
          >
            <div className="message-content">
              {username && taggedText && (
                <p
                  className="message-text"
                  dangerouslySetInnerHTML={{ __html: safeHTML }}
                />
              )}
              {fileUrl && (
                <>
                  {fileUrl.endsWith('.mp4') ? (
                    <a href={fileUrl} target="_blank" rel="noopener noreferrer">
                      {thumbnail ? (
                        <img src={thumbnail} alt="chat attachment" className="message-image-preview" />
                        ) : (
                        <div className="message-video-preview-placeholder">
                          <svg viewBox="0 0 24 24">
                            <path fill="none" d="M0 0h24v24H0V0z" />
                            <path fill="#ccc" d="M9 6v12l6-6z" />
                          </svg>
                        </div>
                      )}
                    </a>
                    ) : (
                    <a href={fileUrl} target="_blank" rel="noopener noreferrer">
                    <img src={fileUrl} alt="chat attachment" className="message-image-preview" />
                    </a>
                    )}
                </>
              )}
            </div>
            {showDelete && (
              <button className="delete-button" onClick={handleDeleteClick}>
                <FontAwesomeIcon icon={faTrash} />
              </button>
            )}
          </div>
        );
        
      };
  
export default ChatMessage
Editor is loading...