Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 3 additions & 13 deletions hooks/comments/useCommentList.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useCallback, useEffect, useState } from "react";
import { collection, getDocs, orderBy, query, where } from "firebase/firestore";
import { firestore } from "@/firebase/clientApp";
import { Post } from "@/types/post";
import useCustomToast from "@/hooks/useCustomToast";
import { Comment } from "../../types/comment";
import { getComments as getCommentsLib } from "@/lib/comments/getComments";

/**
* Loads comments for the selected post and keeps them in local state.
Expand All @@ -19,17 +18,8 @@ const useCommentList = (selectedPost: Post | null) => {
if (!selectedPost) return;
setCommentFetchLoading(true);
try {
const commentsQuery = query(
collection(firestore, "comments"),
where("postId", "==", selectedPost.id),
orderBy("createdAt", "desc")
);
const commentDocs = await getDocs(commentsQuery);
const mappedComments = commentDocs.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setComments(mappedComments as Comment[]);
const comments = await getCommentsLib(selectedPost.id!);
setComments(comments);
} catch (error: any) {
console.log("getPostComments error", error);
showToast({
Expand Down
47 changes: 11 additions & 36 deletions hooks/comments/useCreateComment.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import { Dispatch, SetStateAction, useState } from "react";
import { User } from "firebase/auth";
import {
collection,
doc,
increment,
serverTimestamp,
Timestamp,
writeBatch,
} from "firebase/firestore";
import { firestore } from "@/firebase/clientApp";
import { postStateAtom } from "@/atoms/postsAtom";
import { Post } from "@/types/post";
import { useSetAtom } from "jotai";
import useCustomToast from "@/hooks/useCustomToast";
import { Comment } from "../../types/comment";
import { createComment } from "@/lib/comments/createComment";

/**
* Creates a new comment or reply on the selected post and updates counts.
Expand All @@ -30,39 +22,22 @@ const useCreateComment = (
const showToast = useCustomToast();
const [createLoading, setCreateLoading] = useState(false);

const createComment = async (
const onCreateComment = async (
user: User,
commentText: string,
parentId?: string
) => {
if (!selectedPost) return;
setCreateLoading(true);
try {
const batch = writeBatch(firestore);

const commentDocRef = doc(collection(firestore, "comments"));
const newComment: Comment = {
id: commentDocRef.id,
creatorId: user.uid,
creatorDisplayText: user.email!.split("@")[0],
communityId: selectedPost.communityId,
postId: selectedPost.id!,
postTitle: selectedPost.title,
text: commentText,
createdAt: serverTimestamp() as Timestamp,
parentId: parentId || undefined,
};

if (!parentId) delete newComment.parentId;

batch.set(commentDocRef, newComment);

const postDocRef = doc(firestore, "posts", selectedPost.id!);
batch.update(postDocRef, {
numberOfComments: increment(1),
});

await batch.commit();
const newComment = await createComment(
user,
selectedPost.communityId,
selectedPost.id!,
selectedPost.title,
commentText,
parentId
);

setComments((prev) => [newComment, ...prev]);
setPostState((prev) => ({
Expand All @@ -85,7 +60,7 @@ const useCreateComment = (
};

return {
createComment,
createComment: onCreateComment,
createLoading,
};
};
Expand Down
21 changes: 4 additions & 17 deletions hooks/comments/useDeleteComment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Dispatch, SetStateAction, useState } from "react";
import { doc, increment, writeBatch } from "firebase/firestore";
import { firestore } from "@/firebase/clientApp";
import { postStateAtom } from "@/atoms/postsAtom";
import { useSetAtom } from "jotai";
import useCustomToast from "@/hooks/useCustomToast";
import { Comment } from "../../types/comment";
import { deleteComment } from "@/lib/comments/deleteComment";

/**
* Deletes a comment and its replies while syncing counts on the parent post.
Expand All @@ -19,11 +18,9 @@ const useDeleteComment = (
const showToast = useCustomToast();
const [deleteLoadingId, setDeleteLoadingId] = useState("");

const deleteComment = async (comment: Comment) => {
const onDeleteComment = async (comment: Comment) => {
setDeleteLoadingId(comment.id);
try {
const batch = writeBatch(firestore);

const getDescendantIds = (parentId: string): string[] => {
const children = comments.filter((c) => c.parentId === parentId);
let ids = children.map((c) => c.id);
Expand All @@ -36,17 +33,7 @@ const useDeleteComment = (
const descendantIds = getDescendantIds(comment.id);
const allIdsToDelete = [comment.id, ...descendantIds];

allIdsToDelete.forEach((id) => {
const commentDocRef = doc(firestore, "comments", id);
batch.delete(commentDocRef);
});

const postDocRef = doc(firestore, "posts", comment.postId);
batch.update(postDocRef, {
numberOfComments: increment(-allIdsToDelete.length),
});

await batch.commit();
await deleteComment(comment.id, comment.postId, descendantIds);

setComments((prev) =>
prev.filter((item) => !allIdsToDelete.includes(item.id))
Expand All @@ -72,7 +59,7 @@ const useDeleteComment = (
};

return {
deleteComment,
deleteComment: onDeleteComment,
deleteLoadingId,
};
};
Expand Down
43 changes: 9 additions & 34 deletions hooks/community/useCommunitiesFeed.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { firestore } from "@/firebase/clientApp";
import useCustomToast from "@/hooks/useCustomToast";
import {
collection,
DocumentData,
getDocs,
limit,
orderBy,
query,
QueryDocumentSnapshot,
startAfter,
} from "firebase/firestore";
import { DocumentData, QueryDocumentSnapshot } from "firebase/firestore";
import { useEffect, useState } from "react";
import { Community } from "@/types/community";
import { getCommunities as getCommunitiesLib } from "@/lib/community/getCommunities";

type UseCommunitiesFeedProps = {
limitValue?: number;
Expand Down Expand Up @@ -39,32 +30,16 @@ const useCommunitiesFeed = ({
if (loading) return;
setLoading(true);
try {
let communityQuery;
if (initial) {
communityQuery = query(
collection(firestore, "communities"),
orderBy("numberOfMembers", "desc"),
limit(limitValue)
);
} else {
if (!lastVisible || !isPagination) return;
communityQuery = query(
collection(firestore, "communities"),
orderBy("numberOfMembers", "desc"),
startAfter(lastVisible),
limit(limitValue)
);
if (!initial && (!lastVisible || !isPagination)) {
setLoading(false);
return;
}

const communityDocs = await getDocs(communityQuery);
const fetchedCommunities = communityDocs.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
const { communities: fetchedCommunities, newLastVisible } =
await getCommunitiesLib(limitValue, initial ? null : lastVisible);

if (communityDocs.docs.length < limitValue) setNoMoreCommunities(true);
if (communityDocs.docs.length > 0)
setLastVisible(communityDocs.docs[communityDocs.docs.length - 1]);
if (fetchedCommunities.length < limitValue) setNoMoreCommunities(true);
if (newLastVisible) setLastVisible(newLastVisible);

setCommunities((prev) =>
initial
Expand Down
85 changes: 12 additions & 73 deletions hooks/community/useCommunityImage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { communityStateAtom } from "@/atoms/communitiesAtom";
import { firestore, storage } from "@/firebase/clientApp";
import { collection, doc, getDoc, getDocs, updateDoc } from "firebase/firestore";
import { deleteObject, getDownloadURL, ref, uploadString } from "firebase/storage";
import { useSetAtom } from "jotai";
import { useState } from "react";
import useCustomToast from "../useCustomToast";
import { Community } from "@/types/community";
import { updateCommunityImage } from "@/lib/community/updateCommunityImage";
import { deleteCommunityImage } from "@/lib/community/deleteCommunityImage";

/**
* Uploads or removes a community image while syncing snippets and local state.
Expand All @@ -17,44 +16,15 @@ const useCommunityImage = (communityData: Community) => {
const showToast = useCustomToast();
const [uploadingImage, setUploadingImage] = useState(false);

const updateImage = async (selectedFile: string) => {
const onUpdateImage = async (selectedFile: string) => {
if (!selectedFile) return;
setUploadingImage(true);

try {
const imageRef = ref(storage, `communities/${communityData.id}/image`);
await uploadString(imageRef, selectedFile, "data_url");
const downloadURL = await getDownloadURL(imageRef);
await updateDoc(doc(firestore, "communities", communityData.id), {
imageURL: downloadURL,
});

const usersSnapshot = await getDocs(collection(firestore, "users"));
usersSnapshot.forEach(async (userDoc) => {
const communitySnippetDoc = await getDoc(
doc(
firestore,
"users",
userDoc.id,
"communitySnippets",
communityData.id
)
);
if (communitySnippetDoc.exists()) {
await updateDoc(
doc(
firestore,
"users",
userDoc.id,
"communitySnippets",
communityData.id
),
{
imageURL: downloadURL,
}
);
}
});
const downloadURL = await updateCommunityImage(
communityData.id,
selectedFile
);

setCommunityStateValue((prev) => ({
...prev,
Expand Down Expand Up @@ -88,40 +58,9 @@ const useCommunityImage = (communityData: Community) => {
}
};

const deleteCommunityImage = async () => {
const onDeleteCommunityImage = async () => {
try {
const imageRef = ref(storage, `communities/${communityData.id}/image`);
await deleteObject(imageRef);
await updateDoc(doc(firestore, "communities", communityData.id), {
imageURL: "",
});

const usersSnapshot = await getDocs(collection(firestore, "users"));
usersSnapshot.forEach(async (userDoc) => {
const communitySnippetDoc = await getDoc(
doc(
firestore,
"users",
userDoc.id,
"communitySnippets",
communityData.id
)
);
if (communitySnippetDoc.exists()) {
await updateDoc(
doc(
firestore,
"users",
userDoc.id,
"communitySnippets",
communityData.id
),
{
imageURL: "",
}
);
}
});
await deleteCommunityImage(communityData.id);

setCommunityStateValue((prev) => ({
...prev,
Expand All @@ -144,7 +83,7 @@ const useCommunityImage = (communityData: Community) => {
}),
}));
} catch (error) {
console.log("Error: onDeleteImage", error);
console.log("Error: onDeleteCommunityImage", error);
showToast({
title: "Image not Deleted",
description: "There was an error deleting the image",
Expand All @@ -154,8 +93,8 @@ const useCommunityImage = (communityData: Community) => {
};

return {
updateImage,
deleteCommunityImage,
updateImage: onUpdateImage,
deleteCommunityImage: onDeleteCommunityImage,
uploadingImage,
};
};
Expand Down
7 changes: 2 additions & 5 deletions hooks/community/useCommunityPrivacy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { communityStateAtom } from "@/atoms/communitiesAtom";
import { Community } from "@/types/community";
import { firestore } from "@/firebase/clientApp";
import { doc, updateDoc } from "firebase/firestore";
import { useSetAtom } from "jotai";
import useCustomToast from "../useCustomToast";
import { updateCommunityPrivacy } from "@/lib/community/updateCommunityPrivacy";

/**
* Updates a community's privacy type and mirrors the change in local state.
Expand All @@ -16,9 +15,7 @@ const useCommunityPrivacy = (communityData: Community) => {

const updatePrivacyType = async (privacyType: string) => {
try {
await updateDoc(doc(firestore, "communities", communityData.id), {
privacyType,
});
await updateCommunityPrivacy(communityData.id, privacyType);
setCommunityStateValue((prev) => ({
...prev,
currentCommunity: {
Expand Down
Loading
Loading