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]);
Simply use this wherever you need to render the user's profile picture
and make sure you have this in your App() in App.js