I have a comments subcollection that needs to be connected to my posts ("thoughts") however I'm unable to dynamically add the document id to my doc(). I'm currently leaving it blank because of no other solution. Therefore, it is generating a new document ID instead of joining on to its parent document.
doc(post.id) doesn't work because post isn't defined in my addComments or getComments and just doc(id) doesn't work because of the same reason.
Here's what it's currently doing
and here's what I want it to do. I manually entered the document id of this post for demonstration purposes:
Here's my fire.js
import FirebaseKeys from "./config/FirebaseKeys";
import firebase from "firebase/app";
import '@firebase/auth';
import 'firebase/database';
import '@firebase/firestore';
import "firebase/storage";
require("firebase/firestore");
class Fire {
constructor() {
firebase.initializeApp(FirebaseKeys);
}
getPosts = async (displayLatestPost) => {
const post = await this.firestore.collection('thoughts').orderBy('timestamp', 'desc').limit(10).get()
let postArray =[]
post.forEach((post) => {
postArray.push({id: post.id, ...post.data()})
})
displayLatestPost(postArray)
}
getComments = async (latestComment) => {
const fetchedComment = await this.firestore.collection('thoughts').doc().collection('comments').orderBy('timestamp', 'desc').limit(10).get()
let commentArray = []
fetchedComment.forEach((comment) => {
commentArray.push({id: comment.id, ...comment.data()})
})
console.log(" post id: " + post.id + "comment id: " + fetchedComment.id)
latestComment(commentArray)
}
addPost = async ({ thoughtTitle, thoughtText, localUri, photoURL, displayName}) => {
const remoteUri = await this.uploadPhotoAsync(localUri, `photos/${this.uid}/${Date.now()}`);
return new Promise((res, rej) => {
this.firestore
.collection("thoughts")
.add({
uid: this.uid,
displayName,
photoURL,
thoughtTitle,
thoughtText,
image: remoteUri,
timestamp: this.timestamp,
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
};
//comments
addComments = async ({ displayName, photoURL, commentText}) => {
console.log("add a comment - post id:" )
return new Promise((res, rej) => {
this.firestore
.collection("thoughts")
.doc()
.collection('comments')
.add({
uid: this.uid,
displayName,
photoURL,
commentText,
timestamp: this.timestamp,
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
};
//comments
uploadPhotoAsync = (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
};
createUser = async user => {
let remoteUri = null;
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password);
let db = this.firestore.collection("users").doc(this.uid);
db.set({
displayName: user.displayName,
email: user.email,
photoURL: null
});
if (user.photoURL) {
remoteUri = await this.uploadPhotoAsync(user.photoURL, `avatars/${this.uid}`);
db.set({ photoURL: remoteUri }, { merge: true });
}
} catch (error) {
alert("Error: ", error);
}
};
updateProfile = async user => {
let remoteUri = null;
try {
let db = this.firestore.collection("users").doc(this.uid);
db.update({
displayName: user.displayName,
photoURL: user.photoURL
});
if (user.photoURL) {
remoteUri = await this.uploadPhotoAsync(user.photoURL, `avatars/${this.uid}`);
db.set({ photoURL: remoteUri }, { merge: true });
}
} catch (error) {
alert("Error: ", error);
}
}
signOut = () => {
firebase.auth().signOut();
};
get firestore() {
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
Here's the screen where the comment is added.
import React from "react";
import { View, StyleSheet, Text, Image, ScrollView, TextInput, FlatList,
TouchableOpacity} from "react-native";
import Fire from '../../Fire';
import CreatedAtText from '../../components/Text/CreatedAtText';
import Colors from '../../constants/Colors';
import moment from 'moment';
import ThoughtCommentItem from '../../components/Thought/ThoughtCommentItem';
import FloatingButton from '../../components/UI/FloatingButton';
export default class ThoughtDetailsScreen extends React.Component {
state = {
commentText: "",
latestComments: [],
user: {
photoURL: "",
displayName: ""
}
};
handleComment = () => {
Fire.shared
.addComments({ commentText: this.state.commentText.trim(), photoURL: this.state.user.photoURL, displayName: this.state.user.displayName })
.then(ref => {
this.setState({ commentText: ""});
})
.catch(error => {
alert(error);
});
};
displayLatestComment = (latestComments) => {
this.setState({latestComments: latestComments});
console.log("Latest Comments Details" + JSON.stringify(latestComments));
}
componentDidMount(){
Fire.shared.getComments(this.displayLatestComment);
}
unsubscribe = null;
componentDidMount() {
const user = this.props.uid || Fire.shared.uid;
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
}
componentWillUnmount() {
this.unsubscribe();
}
comment = () => {
console.log("comment button clicked ")
}
like = () => {
console.log("like button clicked ")
}
fave = () => {
console.log("fave button clicked ")
}
render(){
const thought = this.props.navigation.getParam('thought');
return(
<View style={styles.container}>
<ScrollView style={{flex:1}}>
<Text>{thought.thoughtTitle}</Text>
<Image style={styles.userAvatar} source={{uri: thought.photoURL}}/>
<CreatedAtText style={styles.timestamp}> {moment(thought.timestamp).fromNow()}</CreatedAtText>
<Text> User: {thought.displayName} </Text>
<Image style={styles.headerPhoto} source={{uri: thought.image}}/>
<Text>Main text: {thought.thoughtText}</Text>
<View style={styles.commentsDisplay}>
<FlatList
showsVerticalScrollIndicator={false}
keyExtractor={item => item.id}
style={styles.feed}
data={this.state.latestComments}
renderItem={({item,index}) => {
return (
<ThoughtCommentItem
photoURL={item.photoURL}
displayName={item.displayName}
timestamp={item.timestamp}
commentText={item.commentText}
onSelect={() => this.props.navigation.navigate('CommentDetails', {comment : item})}
/>
);
}
}
/>
</View>
<View style={styles.commentContainer}>
<TextInput
style={styles.commentBox}
placeholder="Add your thoughts about this!"
onChangeText={commentText =>this.setState({commentText})}
defaultValue={this.state.commentText}
/>
<Text onPress={this.handleComment} style={styles.commentButton}> Comment
</Text>
</View>
</ScrollView>
<FloatingButton style={styles.floatingbutton}
onSelectComment={this.comment}
onSelectLike={this.like}
onSelectFavorite={this.fave}
/>
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex:1
},
commentContainer:{
flexDirection: "row"
},
headerPhoto : {
height: 250,
width: 200
},
userAvatar: {
backgroundColor: Colors.subheadings,
borderColor: Colors.accent,
borderWidth:3.5,
backgroundColor: Colors.maintext,
marginEnd: 15,
width: 35,
height: 35,
borderRadius: 20,
},
floatingbutton:{
bottom: 70,
right: 60
},
commentButton: {
color: "#788eec",
fontWeight: "bold",
fontSize: 16
},
commentsDisplay: {
flex: 1,
backgroundColor: Colors.background
},
feed : {
marginHorizontal: 16
}
});