0

So when I user posts a comment I was thinking of storing their profile picture URL on the comment object so I can access it easily, but I figured that that would not work because if they change their profile picture or if they delete it, the comment will still contain their old URL, I've also tried storing the reference to the user in Firestore, but I'm not sure if I did it wrong or what because I kept running into errors.

TLDR - I'm asking if anyone knows a way to store and access a URL (that could change in the future) for a specific comment.

Sorry if I didn't clarify or explains things as well, I'm pretty new to React as you probably already can tell. And I can try to explain things better if anyone has any questions, so yeah thanks for reading this and thanks in advance.

import React, { useEffect, useState } from 'react';
import { postComment, deleteComment } from '../../store/actions/commentsActions';
import { connect, useSelector } from 'react-redux';
import { useFirestore } from 'react-redux-firebase';
import { useForm } from 'react-hook-form';
import { toast } from 'react-toastify';
import moment from 'moment';
import { ErrorCircle } from '@styled-icons/boxicons-solid/ErrorCircle';
import { Error } from  '@styled-icons/boxicons-solid/Error';

import { Modal } from '../../helpers/Modal';
import ProfilePlaceHolder from '../../assets/images/user.svg';

import Loading from '../../helpers/Loading';

export const Comments = (props) => {

    const { auth, match, history, commentError } = props;
    const slug = match.params.slug;
    const firestore = useFirestore();
    const profile = useSelector(state => state.firebase.profile);

    const { register, handleSubmit, reset } = useForm();

    const [comments, setComments] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect(() => {

        const listener = 
        firestore
        .collection('posts')
        .doc(slug)
        .collection('comments')
        .orderBy('createdAt', 'desc')
        .onSnapshot((snapshot) => {
            let _comments = [];
            snapshot.forEach(commentSnapshot => {
                const thisComment = commentSnapshot.data();
                _comments.push({commentData: thisComment, commentId: commentSnapshot.id});
            });
            setComments(_comments);
            setLoading(false);
        }, (error) => {
            console.log(error);
        });

        return () => listener();

    }, [firestore, slug]);

    const postComment = async (formData) => {

        if (auth.isEmpty) {
            toast.error('You are not authenticated ');
            return;
        }
        await props.postComment({formData, slug});
        reset();
    };

    const deleteComment = (commentId, authorId) => {

        const currentUserId = auth.uid;
        const commentUserId = authorId;

        if (!comments) {
            return;
        }

        if (currentUserId !== commentUserId) {
            toast.error('That\'s not your comment')
            return;
        }

        props.deleteComment({commentId, authorId, slug});  
    };

    const back = () => {
        history.goBack();
    };

    if (loading) {
        return <Loading />;
    };



    return (
        <div className='main' style={{ width: '600px', maxWidth: '90%' }}>
            { 
                commentError !== null ? (
                <span className='error-message'>
                    <ErrorCircle size='30' style={{ marginRight: 5 }} />
                    {commentError}
                </span> ) : null
            }
            <div className='long-container' onClick={back} style={{ cursor: 'pointer', height: '50px' }}>
                Commenting on the post: {slug}
            </div>
            <div className='long-container' style={{ padding: '10px 0' }}>
                <div>
                    <img 
                        src={profile.profilePictureURL ?? ProfilePlaceHolder} 
                        alt='Profile' 
                        className='profile-picture' 
                    />
                    <span className='usertag-span'>{auth?.displayName}</span>
                </div>
                <div>
                    <form onSubmit={handleSubmit(postComment)}>
                        <textarea 
                            name='content'
                            rows='3' 
                            disabled={!auth}
                            style={{ margin: '10px 0' }}
                            placeholder='Add to the conversation!'
                            ref={register({ required: true })}
                        /> 
                        <span style={{ width: '90%' }}>
                            <button>Comment</button>
                        </span>
                    </form>
                </div>
            </div>
            {comments.map((comment) =>
            <div key={comment.commentId} className='long-container' style={{ padding: '15px 0' }}>
                <div style={{ height: '30px' }}>
                    <img 
                        src={comment.commentData.authorProfilePicture ?? ProfilePlaceHolder} 
                        alt='Profile' 
                        className='profile-picture'
                    />
                    <div className='commentMetadata' style={{ flexDirection: 'column', alignItems: 'flex-start', justifyItems: 'center' }}>
                        <span className='usertag-span'>{comment.commentData.author}</span>
                        <span>{moment(comment.commentData.createdAt?.toDate()).fromNow()}</span>
                    </div>
                </div>
                <span className='commentText-span'>
                    {comment.commentData.content}
                </span>
                <span className='commentText-span' style={{ justifyContent: 'flex-end' }}>
                    { 
                        auth.uid === comment.commentData.authorId ?
                        (
                            <Modal 
                                buttonActionClassName='delete-button' 
                                visibleButtonClassName='delete-button'
                                modalContentHeaderBackgroundColor='#fa4949'
                                title='Confirm' 
                                modalContent='Are you sure you want to delete this comment?' 
                                emoji={<Error size='30' color='#f53d3d' style={{ marginRight: 10 }} />}
                                buttonActionName='Delete'
                                buttonAction={() => deleteComment(comment.commentId, comment.commentData.authorId)}
                            />
                        ) : null
                    }
                </span>
            </div>
            )}
        </div>
    )
}

const mapDispatchToProps = (dispatch) => {
  return {
    postComment: (comment) => dispatch(postComment(comment)),
    deleteComment: (commentToDelete) => dispatch(deleteComment(commentToDelete)) 
  }
} 

const mapStateToProps = (state) => {
    return {
        auth: state.firebase.auth,
        commentError: state.commentsReducer.commentError,
    }
} 

export default connect(mapStateToProps, mapDispatchToProps)(Comments);

This is also something I tried which I mentioned, but didn't exactly work, heh

    useEffect(() => {

        const listener = firestore
        .collection('posts')
        .doc(slug)
        .collection('comments')
        .onSnapshot((snapshot) => {
            let _comments = [];
            snapshot.forEach(commentSnapshot => {
            _comments.push(commentSnapshot.data());
            setComments(_comments);

            });

            _comments.map((comment) => { 
                return comment.authorRef.get().then(snapshot => {

                    const { name, profilePictureURL } = snapshot.data();
                    setAuthorInfo({ name, profilePictureURL });
                    if (snapshot.data()) {
                        console.log(authorInfo.profilePictureURL)
                    }

            }) })

        }, (error) => {
            console.log(error);
        });

        return () => listener();

    }, [firestore, slug, comments, authorInfo]);
Xurify
  • 71
  • 2
  • 8

3 Answers3

1

I'm not a expert with React but maybe using DocumentReference could be helpful to refer to the URL stored in Firestore. Here you could find the docs to make this work. I imagine that the URL is linked with the user ID, so you can also use this to get the image URL.

Puteri
  • 3,348
  • 4
  • 12
  • 27
  • Thanks for leaving a comment, and yeah, I stored a document reference, but I didn't implement things correct, I'm not sure how I would put the reference in the same object with the comment data. Here's the code where I tried to do that: https://pastebin.com/bmdVqRdb – Xurify Apr 03 '20 at 02:10
  • 1
    I'm not familiarized with React but maybe [this](https://stackoverflow.com/questions/46878913/cloud-firestore-how-to-fetch-a-document-reference-inside-my-collection-query-an) can help you. – Puteri Apr 04 '20 at 00:22
  • Yep, thanks Fernando this is what I was talking about, I'll read through it – Xurify Apr 04 '20 at 15:58
0

I'm not sure if you can get information for a Firebase user that isn't the current logged in user.

What I suggest is storing info for each of your users in your database, then every time a user is logged in, you can update your database if necessary. Then when showing a user's comment, you lookup the picture in your database for that user.

Ace
  • 1,028
  • 2
  • 10
  • 22
  • Comments are only for authenticated users, but could you show me your idea in code if you don't mind? and I appreciate you trying to help me – Xurify Apr 03 '20 at 02:06
  • There's not much to show in code, it's mostly how you structure your data. What I am saying is that, when you get your comments from firestore, a property of that comment data should be the uid of the user that made the comment, instead of the profile pic. Once you have that uid, you can look up the picture from firestore, where you would have a `users` collection to store user data. And to ensure the picture is up to date, everytime a user logs in, you can update their profile pic in firestore if it changed. – Ace Apr 03 '20 at 02:16
0

Simply use this wherever you need to render the user's profile picture

<img src={auth.photo} />

and make sure you have this in your App() in App.js

useEffect(() => {
    auth.onAuthStateChanged((authUser) => {
      console.log("user is ", authUser);
      if(authUser){
        dispatch(login({
          uid: authUser.uid,
          photo: authUser.photoURL,
          email: authUser.email,
          displayName: authUser.displayName,
        }))
      }
      else{
        dispatch(logout());
      }
    })
  }, [dispatch])