diff --git a/jest/setup.js b/jest/setup.js index 0a3d20cc104dcb59cfda91384831c1326537e2e2..9beb63acc696ae9501f9d32cc3032c9e2d2a8726 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -18,6 +18,7 @@ jest.mock("@react-navigation/core", () => { useNavigation: () => ({ navigate: jest.fn(), dispatch: jest.fn(), + addListener: jest.fn(), }), }; }); diff --git a/src/components/ForumPost/ForumPost.tsx b/src/components/ForumPost/ForumPost.tsx index 1f42a11847054744ea6405bd138aecbd20c72106..61db1677d25e01987681cab3aa2607da8423f4f7 100644 --- a/src/components/ForumPost/ForumPost.tsx +++ b/src/components/ForumPost/ForumPost.tsx @@ -10,6 +10,9 @@ import { useNavigation } from "@react-navigation/core"; import { useEffect, useState } from "react"; import { getUser } from "../../service/firestore/user"; import { IUser } from "../../types/firestore/User"; +import { likeThread, unlikeThread } from "../../service/firestore/thread/like"; +import { useUser } from "../../hooks/reduxHooks"; +import { checkIsLiked } from "../../service/firestore/thread/checkIsLiked"; type props = { item: IThread; @@ -19,9 +22,12 @@ type props = { const ForumPost = ({ item }: props) => { const nav = useNavigation(); + const user = useUser(); const [userName, setUserName] = useState(""); const [userPic, setUserPic] = useState(""); const [isLike, setIslike] = useState(undefined); + const [commentQty, setCommentQty] = useState(item.commentCount); + const [likeQty, setLikeQty] = useState(item.likeCount); useEffect(() => { getUser(item.userId).then((res) => { @@ -29,6 +35,7 @@ const ForumPost = ({ item }: props) => { setUserName(data.firstName + " " + data.lastName); setUserPic(data.pic); }); + checkIsLiked(item.id, user.id).then((res) => setIslike(res)); }, []); const formatDate = () => { @@ -74,7 +81,7 @@ const ForumPost = ({ item }: props) => { - {item.pic && ( + {item.pic !== "" && ( { )} - {}}> + { + nav.navigate("Forum", { + screen: "ForumPostDetail", + params: { + post: item, + }, + }); + }} + > { /> - {item.commentCount} + {commentQty} - {}}> + { + if (!isLike) { + await likeThread(item.id, user.id); + setIslike(true); + setLikeQty(likeQty + 1); + } else if (isLike) { + await unlikeThread(item.id, user.id); + setIslike(false); + setLikeQty(likeQty - 1); + } + }} + > - {item.likeCount} + {likeQty} @@ -175,6 +203,9 @@ const styles = StyleSheet.create({ icon: { color: Colors.icon.tab.inactive, }, + iconLiked: { + color: Colors.icon.tab.active, + }, textIcon: { color: Colors.text.body, fontSize: 14, diff --git a/src/screens/ecosystem/EcosystemDetailScreen.tsx b/src/screens/ecosystem/EcosystemDetailScreen.tsx index 76f8c1fbf07c2d2b14505262d1c5f10b7ec1c7c9..a539671a3d402df8a84fd34bb4cd127eeda1a3e5 100644 --- a/src/screens/ecosystem/EcosystemDetailScreen.tsx +++ b/src/screens/ecosystem/EcosystemDetailScreen.tsx @@ -5,6 +5,7 @@ import { Alert, ActivityIndicator, TouchableOpacity, + FlatList, } from "react-native"; import { Text, View } from "../../components/Themed"; import Colors from "../../constants/Colors"; @@ -23,6 +24,9 @@ import RatingForm from "../../components/RatingForm"; import { rateEcosystem } from "../../service/functions/rateEcosystem"; import { getEcosystemRating } from "../../service/firestore/ecosystem/getEcosystemRating"; import { deleteEcosystem } from "../../service/functions/deleteEcosystem"; +import { IThread } from "../../types/firestore/thread"; +import { fetchPostsByEcosystemId } from "../../service/firestore/forum/fetchPostsByEcosystemId"; +import ForumPost from "../../components/ForumPost/ForumPost"; const EcosystemDetailScreen = ({ route, @@ -34,14 +38,18 @@ const EcosystemDetailScreen = ({ const [isFetched, setIsFetched] = useState(false); const [isRating, setIsRating] = useState(false); const [currentRating, setCurrentRating] = useState(0); + const [forumPosts, setForumPosts] = useState([]); useEffect(() => { - inEcosystem(id, user.id).then((res) => { - setIsInEcosystem(res); - setIsFetched(true); + return nav.addListener("focus", () => { + inEcosystem(id, user.id).then((res) => { + setIsInEcosystem(res); + setIsFetched(true); + }); + fetchPostsByEcosystemId(id).then((res) => setForumPosts(res)); + getEcosystemRating(id, user.id).then((res) => setCurrentRating(res)); }); - getEcosystemRating(id, user.id).then((res) => setCurrentRating(res)); - }, [id, user.id]); + }, [id, user.id, nav]); const alertFollow = () => { Alert.alert("Joined Ecosystem", "You have joined the ecosystem"); @@ -84,127 +92,151 @@ const EcosystemDetailScreen = ({ return ( - - - - - - {title} - - { - nav.navigate("Ecosystem", { - screen: "EcosystemMap", - params: { - headerTitle: title, - id: id, - }, - }); - }} - /> - - {(() => { - if (creatorId == user.id) { - return ( - { - nav.navigate("UpdateEcosystem", { - screen: "UpdateEcosystemScreen", - params: { - id, - }, - }); - }} - /> - ); - } - })()} - - - - - - {member} Anggota - - - - - - {rating.slice(0, 3)} + { + return ( + + - - - - {desc} - - {(() => { - if (creatorId == user.id) { - return null; - } else if (isInEcosystem && isFetched) { - return ( - - ); - } else if (!isInEcosystem && isFetched) { - return ( - - ); - } - })()} - - - setIsRating(!isRating)} - /> - - {isRating && ( - { - await rateEcosystem(id, user.id, currentRating); - }} - /> - )} - - {(() => { - if (creatorId == user.id) { - return ( - { - alertDelete(); - }} - /> - ); - } - })()} - - + ); + }} + ListHeaderComponent={() => { + return ( + <> + + + + + + {title} + + { + nav.navigate("Ecosystem", { + screen: "EcosystemMap", + params: { + headerTitle: title, + id: id, + }, + }); + }} + /> + + {(() => { + if (creatorId == user.id) { + return ( + { + nav.navigate("UpdateEcosystem", { + screen: "UpdateEcosystemScreen", + params: { + id, + }, + }); + }} + /> + ); + } + })()} + + + + + + {member} Anggota + + + + + + {rating.slice(0, 3)} + + + + + {desc} + + {(() => { + if (creatorId == user.id) { + return null; + } else if (isInEcosystem && isFetched) { + return ( + + ); + } else if (!isInEcosystem && isFetched) { + return ( + + ); + } + })()} + + + setIsRating(!isRating)} + /> + + {isRating && ( + { + await rateEcosystem(id, user.id, currentRating); + }} + /> + )} + + {(() => { + if (creatorId == user.id) { + return ( + { + alertDelete(); + }} + /> + ); + } + })()} + + + + ); + }} + /> { diff --git a/src/screens/forum/ForumPostDetailScreen.tsx b/src/screens/forum/ForumPostDetailScreen.tsx index b38f1204ea42de5f284afc7d0d81dcfbf76c037b..a96dec20a04ad3e1c4669e49edb2faedcb54a1a5 100644 --- a/src/screens/forum/ForumPostDetailScreen.tsx +++ b/src/screens/forum/ForumPostDetailScreen.tsx @@ -1,25 +1,38 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import * as React from "react"; -import { StyleSheet, View, FlatList, Text, ListRenderItem } from "react-native"; +import { StyleSheet, View, FlatList, Alert } from "react-native"; import Colors from "../../constants/Colors"; import Spacer from "../../components/Spacer/Spacer"; import { ForumStackScreenProps } from "../../types/navigation"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Divider } from "react-native-elements"; import IconForm from "../../components/Forms/IconForm"; import Comment from "../../components/ForumPost/Comment"; import { IThreadComment } from "../../types/firestore/threadComment"; import { IThread } from "../../types/firestore/thread"; import ForumPost from "../../components/ForumPost/ForumPost"; +import { fetchCommentsByPostId } from "../../service/firestore/forum/fetchCommentsByPostId"; +import { addComments } from "../../service/firestore/forum/addComment"; +import { useUser } from "../../hooks/reduxHooks"; +import { fetchComment } from "../../service/firestore/forum/fetchComment"; const ForumPostDetailScreen = ({ route, }: ForumStackScreenProps<"ForumPostDetail">) => { + const { post } = route.params; + const user = useUser(); const [formComment, setFormComment] = useState(""); const [listData, setListData] = useState([]); - const [forum, setForum] = useState(); + const [forum, setForum] = useState(post); - const handleSubmit = () => {}; + const fetchComments = async () => { + setListData(await fetchCommentsByPostId(forum.id)); + return; + }; + + useEffect(() => { + fetchComments().then(); + }, []); return ( @@ -32,11 +45,10 @@ const ForumPostDetailScreen = ({ ); }} - ItemSeparatorComponent={() => } ListHeaderComponent={ - {}} onUnLike={() => {}} /> + @@ -49,7 +61,13 @@ const ForumPostDetailScreen = ({ setText={setFormComment} placeholder={"Masukkan Komentar"} type={"comment"} - onPress={handleSubmit} + onPress={async () => { + fetchComment( + (await addComments(forum.id, formComment, user.id)).id + ).then((res) => listData.unshift(res)); + Alert.alert("Komentar berhasil ditambahkan"); + setFormComment(""); + }} /> @@ -71,9 +89,9 @@ const styles = StyleSheet.create({ commentContainer: { flex: 1, backgroundColor: Colors.background, - padding: 24, + paddingHorizontal: 24, + paddingVertical: 12, justifyContent: "center", - paddingBottom: 80, }, formComment: { backgroundColor: Colors.background, diff --git a/src/service/firestore/forum/addComment.ts b/src/service/firestore/forum/addComment.ts index dc4997aa44c8b420b98183614d58a70f839986b9..3fcade998fcccef365eec28fc5916721cda50d42 100644 --- a/src/service/firestore/forum/addComment.ts +++ b/src/service/firestore/forum/addComment.ts @@ -6,7 +6,7 @@ export const addComments = async ( userId: string ) => { const db = firebase.firestore(); - return await db.collection("threads_comments_" + getEnv()).add({ + return await db.collection("thread_comments_" + getEnv()).add({ threadId: threadId, timestamp: firebase.firestore.FieldValue.serverTimestamp(), content: comment, diff --git a/src/service/firestore/forum/fetchComment.ts b/src/service/firestore/forum/fetchComment.ts new file mode 100644 index 0000000000000000000000000000000000000000..95e3ea4d0d9474f36825fc0ff6562953a15ebf82 --- /dev/null +++ b/src/service/firestore/forum/fetchComment.ts @@ -0,0 +1,15 @@ +import firebase from "firebase"; +import { getEnv } from "../../../helpers/getEnv"; +import { IThreadComment } from "../../../types/firestore/threadComment"; + +export const fetchComment = async ( + commentId: string +): Promise => { + const db = firebase.firestore(); + + const query = db.collection("thread_comments_" + getEnv()).doc(commentId); + const snap = await query.get(); + + const comment = { ...(snap.data() as IThreadComment), id: snap.id }; + return comment; +}; diff --git a/src/types/navigation/ForumStack.ts b/src/types/navigation/ForumStack.ts index 589f79974073f24f7d06a21d20053545f4303ee0..02a0b82adfe101631618cc8013025d740da0725d 100644 --- a/src/types/navigation/ForumStack.ts +++ b/src/types/navigation/ForumStack.ts @@ -3,6 +3,7 @@ * https://reactnavigation.org/docs/typescript/ */ import { NativeStackScreenProps } from "@react-navigation/native-stack"; +import { IThread } from "../firestore/thread"; export type ForumStackParamList = { AddForumPost: { @@ -15,12 +16,7 @@ export type ForumStackParamList = { ForumPostDetail: { headerTitle?: string; id?: string; - title?: string; - content?: string; - image?: string; - comment?: string; - upvote?: string; - creatorId?: string; + post: IThread; }; };