diff --git a/src/atoms/postsAtom.ts b/src/atoms/postsAtom.ts index 0abcf0d..b875474 100644 --- a/src/atoms/postsAtom.ts +++ b/src/atoms/postsAtom.ts @@ -15,22 +15,23 @@ export type Post = { createdAt: Timestamp } +export type PostVote = { + id: string + postId: string + communityId: string + voteValue: number +} + interface PostState { selectedPost: Post | null posts: Post[] - // postVotes: PostVote[] - // postsCache: { - // [key: string]: Post[] - // } - // postUpdateRequired: boolean + postVotes: PostVote[] } export const defaultPostState: PostState = { selectedPost: null, posts: [], - // postVotes: [], - // postsCache: {}, - // postUpdateRequired: true, + postVotes: [], } export const postState = atom({ diff --git a/src/components/community/About.tsx b/src/components/community/About.tsx index 0e8b11f..e245fc6 100644 --- a/src/components/community/About.tsx +++ b/src/components/community/About.tsx @@ -1,4 +1,4 @@ -import { Community } from '@/src/atoms/communitiesAtom' +import { Community, communityState } from '@/src/atoms/communitiesAtom' import { Box, Button, @@ -12,14 +12,55 @@ import { Image, Spinner, } from '@chakra-ui/react' -import React from 'react' +import React, { useRef, useState } from 'react' import { HiOutlineDotsHorizontal } from 'react-icons/hi' +import { FaReddit } from 'react-icons/fa' +import { RiCakeLine } from 'react-icons/ri' +import Link from 'next/link' +import moment from 'moment' +import { useAuthState } from 'react-firebase-hooks/auth' +import { auth, firestore, storage } from '@/src/firebase/clientApp' +import useSelectFile from '@/src/hooks/useSelectFile' +import { useSetRecoilState } from 'recoil' +import { getDownloadURL, ref, uploadString } from 'firebase/storage' +import { doc, updateDoc } from 'firebase/firestore' type AboutProps = { communityData: Community } const About: React.FC = ({ communityData }) => { + const [user] = useAuthState(auth) + const selectedFileRef = useRef(null) + const { selectedFile, setSelectedFile, onSelectFile } = useSelectFile() + const [uploadingImage, setUploadingImage] = useState(false) + const setCommuityStateValue = useSetRecoilState(communityState) + + const onUpdateImage = async () => { + 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, + }) + console.log('HERE IS DOWNLOAD URL', downloadURL) + + setCommuityStateValue(prev => ({ + ...prev, + currentCommunity: { + ...prev.currentCommunity, + imageURL: downloadURL, + } as Community, + })) + } catch (error: any) { + console.log('onUpdateImage error', error.message) + } + setUploadingImage(false) + } return ( = ({ communityData }) => { + + + + + {communityData.numberOfMembers.toLocaleString()} + Members + + + 1 + Online + + + + + + {communityData?.createdAt && ( + + Created{' '} + {moment( + new Date(communityData.createdAt.seconds * 1000) + ).format('MMM DD, YYYY')} + + )} + + + + + {user?.uid === communityData.creatorId && ( + <> + + + Admin + + selectedFileRef.current?.click()} + > + Change Image + + {communityData?.imageURL || selectedFile ? ( + Community IMG + ) : ( + + )} + + {selectedFile && + (uploadingImage ? ( + + ) : ( + + Save Changes + + ))} + + + + )} + + ) } diff --git a/src/components/community/Header.tsx b/src/components/community/Header.tsx index 95dd38e..bee3eb5 100644 --- a/src/components/community/Header.tsx +++ b/src/components/community/Header.tsx @@ -21,11 +21,11 @@ const Header: React.FC = ({ communityData }) => { - {communityData.imageURL ? ( + {communityStateValue.currentCommunity?.imageURL ? ( Dan Abramov = ({ user }) => { - const resetCommunityState = useResetRecoilState(communityState) const setAuthModalState = useSetRecoilState(authModalState) const logout = async () => { await signOut(auth) - resetCommunityState() } return ( diff --git a/src/components/posts/NewPostForm.tsx b/src/components/posts/NewPostForm.tsx index 258961d..16cb93a 100644 --- a/src/components/posts/NewPostForm.tsx +++ b/src/components/posts/NewPostForm.tsx @@ -35,6 +35,7 @@ import ImageUpload from './postForm/ImageUpload' import { Post } from '@/src/atoms/postsAtom' import { firestore, storage } from '@/src/firebase/clientApp' import { ref, uploadString, getDownloadURL } from 'firebase/storage' +import useSelectFile from '@/src/hooks/useSelectFile' type NewPostFormProps = { user: User @@ -75,9 +76,9 @@ const NewPostForm: React.FC = ({ user }) => { title: '', body: '', }) - const [selectedFile, setSelectedFile] = useState() const [loading, setLoading] = useState(false) const [error, setError] = useState(false) + const { setSelectedFile, selectedFile, onSelectFile } = useSelectFile() const handleCreatePost = async () => { const { communityId } = router.query @@ -112,20 +113,6 @@ const NewPostForm: React.FC = ({ user }) => { setLoading(false) } - const onSelectImage = (event: React.ChangeEvent) => { - const reader = new FileReader() - - if (event.target.files?.[0]) { - reader.readAsDataURL(event.target.files[0]) - } - - reader.onload = readerEvent => { - if (readerEvent.target?.result) { - setSelectedFile(readerEvent.target.result as string) - } - } - } - const onTextChange = ( event: React.ChangeEvent ) => { @@ -164,7 +151,7 @@ const NewPostForm: React.FC = ({ user }) => { selectedFile={selectedFile} setSelectedFile={setSelectedFile} setSelectedTab={setSelectedTab} - onSelectImage={onSelectImage} + onSelectImage={onSelectFile} /> )} diff --git a/src/components/posts/PostItem.tsx b/src/components/posts/PostItem.tsx index a2e6592..37da171 100644 --- a/src/components/posts/PostItem.tsx +++ b/src/components/posts/PostItem.tsx @@ -26,14 +26,20 @@ import moment from 'moment' import { async } from '@firebase/util' import { log } from 'console' import { AiOutlineDelete } from 'react-icons/ai' +import { useRouter } from 'next/router' type PostItemProps = { post: Post userIsCreator: boolean userVoteValue?: number - onVote: () => {} + onVote: ( + event: React.MouseEvent, + post: Post, + vote: number, + communityId: string + ) => void onDeletePost: (post: Post) => Promise - onSelectPost: () => void + onSelectPost?: (post: Post) => void } const PostItem: React.FC = ({ @@ -46,10 +52,15 @@ const PostItem: React.FC = ({ }) => { const [loadingImage, setLoadingImage] = useState(true) const [loadingDelete, setLoadingDelete] = useState(false) + const router = useRouter() + const singlePostPage = !onSelectPost const [error, setError] = useState(false) - const handleDelete = async () => { + const handleDelete = async ( + event: React.MouseEvent + ) => { + event.stopPropagation() setLoadingDelete(true) try { const success = await onDeletePost(post) @@ -57,6 +68,9 @@ const PostItem: React.FC = ({ throw new Error('Failed to delete post') } console.log('Post was succesfuly delited') + if (singlePostPage) { + router.push(`/r/${post.communityId}`) + } } catch (error: any) { setError(error.message) console.log('deleteError', error) @@ -68,19 +82,19 @@ const PostItem: React.FC = ({ onSelectPost && onSelectPost(post)} > = ({ color={userVoteValue === 1 ? 'brand.100' : 'gray.400'} fontSize={22} cursor='pointer' - onClick={onVote} + onClick={event => onVote(event, post, 1, post.communityId)} /> {post.voteStatus} @@ -103,7 +117,7 @@ const PostItem: React.FC = ({ color={userVoteValue === -1 ? '#4379FF' : 'gray.400'} fontSize={22} cursor='pointer' - onClick={onVote} + onClick={event => onVote(event, post, -1, post.communityId)} /> diff --git a/src/components/posts/Posts.tsx b/src/components/posts/Posts.tsx index d0ba3b6..d50b2f1 100644 --- a/src/components/posts/Posts.tsx +++ b/src/components/posts/Posts.tsx @@ -1,14 +1,6 @@ import React, { useEffect, useState } from 'react' import { Community } from '@/src/atoms/communitiesAtom' -import { - collection, - doc, - getDoc, - getDocs, - orderBy, - query, - where, -} from 'firebase/firestore' +import { collection, getDocs, orderBy, query, where } from 'firebase/firestore' import { auth, firestore } from '@/src/firebase/clientApp' import usePosts from '@/src/hooks/usePosts' import { Post } from '@/src/atoms/postsAtom' @@ -68,7 +60,10 @@ const Posts: React.FC = ({ communityData }) => { key={item.id} post={item} userIsCreator={user?.uid === item.creatorId} - userVoteValue={undefined} + userVoteValue={ + postStateValue.postVotes.find(vote => vote.postId === item.id) + ?.voteValue + } onVote={onVote} onSelectPost={onSelectPost} onDeletePost={onDeletePost} diff --git a/src/components/posts/comments/CommentInput.tsx b/src/components/posts/comments/CommentInput.tsx new file mode 100644 index 0000000..ac4101e --- /dev/null +++ b/src/components/posts/comments/CommentInput.tsx @@ -0,0 +1,73 @@ +import { User } from 'firebase/auth' +import React from 'react' +import { Flex, Textarea, Button, Text } from '@chakra-ui/react' +import AuthButtons from '../../navbar/rightContent/AuthButtons' + +type CommentInputProps = { + commentText: string + setCommentText: (value: string) => void + user: User + createLoading: boolean + onCreateComment: (commentText: string) => void +} + +const CommentInput: React.FC = ({ + commentText, + setCommentText, + user, + createLoading, + onCreateComment, +}) => { + return ( + + {user ? ( + <> + + Comment as{' '} + + {user?.email?.split('@')[0]} + + +