diff --git a/components/BeerById/BeerCommentForm.tsx b/components/BeerById/BeerCommentForm.tsx index 9164279..8ad90bf 100644 --- a/components/BeerById/BeerCommentForm.tsx +++ b/components/BeerById/BeerCommentForm.tsx @@ -8,9 +8,7 @@ import { Rating } from 'react-daisyui'; import { useForm, SubmitHandler } from 'react-hook-form'; import { z } from 'zod'; -import { KeyedMutator } from 'swr'; -import BeerCommentQueryResult from '@/services/BeerComment/schema/BeerCommentQueryResult'; -import { useRouter } from 'next/router'; +import useBeerPostComments from '@/hooks/useBeerPostComments'; import Button from '../ui/forms/Button'; import FormError from '../ui/forms/FormError'; import FormInfo from '../ui/forms/FormInfo'; @@ -20,10 +18,7 @@ import FormTextArea from '../ui/forms/FormTextArea'; interface BeerCommentFormProps { beerPost: z.infer; - mutate: KeyedMutator<{ - comments: z.infer[]; - pageCount: number; - }>; + mutate: ReturnType['mutate']; } const BeerCommentForm: FunctionComponent = ({ @@ -45,7 +40,6 @@ const BeerCommentForm: FunctionComponent = ({ reset({ rating: 0, content: '' }); }, [reset]); - const router = useRouter(); const onSubmit: SubmitHandler> = async ( data, ) => { @@ -56,14 +50,8 @@ const BeerCommentForm: FunctionComponent = ({ rating: data.rating, beerPostId: beerPost.id, }); + await mutate(); reset(); - - const submitTasks: Promise[] = [ - router.push(`/beers/${beerPost.id}`, undefined, { scroll: false }), - mutate(), - ]; - - await Promise.all(submitTasks); }; const { errors } = formState; diff --git a/components/BeerById/BeerPostCommentsPaginationBar.tsx b/components/BeerById/BeerPostCommentsPaginationBar.tsx deleted file mode 100644 index 7bfa8bb..0000000 --- a/components/BeerById/BeerPostCommentsPaginationBar.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { FC } from 'react'; -import Link from 'next/link'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; -import { z } from 'zod'; - -import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'; - -interface BeerCommentsPaginationBarProps { - commentsPageNum: number; - commentsPageCount: number; - beerPost: z.infer; -} - -const BeerCommentsPaginationBar: FC = ({ - commentsPageNum, - commentsPageCount, - beerPost, -}) => ( -
-
- - - - - - - -
-
-); - -export default BeerCommentsPaginationBar; diff --git a/components/BeerById/BeerPostCommentsSection.tsx b/components/BeerById/BeerPostCommentsSection.tsx index 1f9d167..bfeb7c9 100644 --- a/components/BeerById/BeerPostCommentsSection.tsx +++ b/components/BeerById/BeerPostCommentsSection.tsx @@ -3,33 +3,58 @@ import UserContext from '@/contexts/userContext'; import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; -import { FC, useContext } from 'react'; +import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; import useBeerPostComments from '@/hooks/useBeerPostComments'; import { useRouter } from 'next/router'; +import { useInView } from 'react-intersection-observer'; import BeerCommentForm from './BeerCommentForm'; -import BeerCommentsPaginationBar from './BeerPostCommentsPaginationBar'; + import CommentCardBody from './CommentCardBody'; import NoCommentsCard from './NoCommentsCard'; import CommentLoadingCardBody from './CommentLoadingCardBody'; +import Spinner from '../ui/Spinner'; interface BeerPostCommentsSectionProps { beerPost: z.infer; } +const LoadingComponent: FC<{ length: number }> = ({ length }) => { + return ( + <> + {Array.from({ length }).map((_, i) => ( + + ))} +
+ +
+ + ); +}; + const BeerPostCommentsSection: FC = ({ beerPost }) => { const { user } = useContext(UserContext); const router = useRouter(); const { id } = beerPost; const pageNum = parseInt(router.query.comments_page as string, 10) || 1; - const pageSize = 5; + const PAGE_SIZE = 6; - const { comments, commentsPageCount, isLoading, mutate } = useBeerPostComments({ - id, - pageNum, - pageSize, + const { comments, isLoading, mutate, setSize, size, isLoadingMore, isAtEnd } = + useBeerPostComments({ + id, + pageNum, + pageSize: PAGE_SIZE, + }); + + const { ref } = useInView({ + delay: 3000, + onChange: (visible) => { + if (!visible || isAtEnd) return; + setSize(size + 1); + }, }); + const sectionRef: MutableRefObject = useRef(null); return (
@@ -44,17 +69,37 @@ const BeerPostCommentsSection: FC = ({ beerPost })
- {comments && !!comments.length && !!commentsPageCount && !isLoading && ( -
- {comments.map((comment) => ( - - ))} + {comments && !!comments.length && !isLoading && ( +
+ {comments.map((comment, index) => { + const isLastComment = index === comments.length - 1; - + return ( +
+ +
+ ); + })} + + {!!isLoadingMore && ( +
+ +
+ )} + + {isAtEnd && ( +
+ +
+ )}
)} @@ -62,15 +107,7 @@ const BeerPostCommentsSection: FC = ({ beerPost }) {isLoading && (
- {Array.from({ length: pageSize }).map((_, i) => ( - - ))} - - +
)}
diff --git a/components/BeerById/BeerPostLikeButton.tsx b/components/BeerById/BeerPostLikeButton.tsx index 07311ad..bc54a92 100644 --- a/components/BeerById/BeerPostLikeButton.tsx +++ b/components/BeerById/BeerPostLikeButton.tsx @@ -2,11 +2,12 @@ import useCheckIfUserLikesBeerPost from '@/hooks/useCheckIfUserLikesBeerPost'; import sendLikeRequest from '@/requests/sendLikeRequest'; import { FC, useEffect, useState } from 'react'; import { FaThumbsUp, FaRegThumbsUp } from 'react-icons/fa'; -import { KeyedMutator } from 'swr'; + +import useGetLikeCount from '@/hooks/useGetLikeCount'; const BeerPostLikeButton: FC<{ beerPostId: string; - mutateCount: KeyedMutator; + mutateCount: ReturnType['mutate']; }> = ({ beerPostId, mutateCount }) => { const { isLiked, mutate: mutateLikeStatus } = useCheckIfUserLikesBeerPost(beerPostId); const [loading, setLoading] = useState(true); diff --git a/components/BeerById/CommentCardBody.tsx b/components/BeerById/CommentCardBody.tsx index d9864d0..613fb0f 100644 --- a/components/BeerById/CommentCardBody.tsx +++ b/components/BeerById/CommentCardBody.tsx @@ -1,22 +1,23 @@ import UserContext from '@/contexts/userContext'; +import useBeerPostComments from '@/hooks/useBeerPostComments'; import useTimeDistance from '@/hooks/useTimeDistance'; import BeerCommentQueryResult from '@/services/BeerComment/schema/BeerCommentQueryResult'; import format from 'date-fns/format'; import Link from 'next/link'; -import { useContext } from 'react'; +import { FC, useContext } from 'react'; import { Rating } from 'react-daisyui'; import { FaEllipsisH } from 'react-icons/fa'; -import { KeyedMutator } from 'swr'; +import { useInView } from 'react-intersection-observer'; import { z } from 'zod'; -const CommentCardDropdown: React.FC<{ +interface CommentCardProps { comment: z.infer; - mutate: KeyedMutator<{ - comments: z.infer[]; - pageCount: number; - }>; -}> = ({ comment, mutate }) => { + mutate: ReturnType['mutate']; + ref?: ReturnType['ref']; +} + +const CommentCardDropdown: FC = ({ comment, mutate }) => { const { user } = useContext(UserContext); const isCommentOwner = user?.id === comment.postedBy.id; @@ -42,34 +43,25 @@ const CommentCardDropdown: React.FC<{ tabIndex={0} className="dropdown-content menu rounded-box w-52 bg-base-100 p-2 shadow" > - {isCommentOwner ? ( -
  • +
  • + {isCommentOwner ? ( -
  • - ) : ( -
  • + ) : ( -
  • - )} + )} + ); }; -const CommentCardBody: React.FC<{ - comment: z.infer; - - mutate: KeyedMutator<{ - comments: z.infer[]; - pageCount: number; - }>; -}> = ({ comment, mutate }) => { +const CommentCardBody: FC = ({ comment, mutate, ref }) => { const { user } = useContext(UserContext); const timeDistance = useTimeDistance(new Date(comment.createdAt)); return ( -
    +

    diff --git a/components/BeerById/CommentLoadingCardBody.tsx b/components/BeerById/CommentLoadingCardBody.tsx index 2d0e292..b662594 100644 --- a/components/BeerById/CommentLoadingCardBody.tsx +++ b/components/BeerById/CommentLoadingCardBody.tsx @@ -1,12 +1,14 @@ const CommentLoadingCardBody = () => { return ( -
    +
    -
    +
    +
    +
    diff --git a/components/ui/Navbar.tsx b/components/ui/Navbar.tsx index 47ebece..8a10573 100644 --- a/components/ui/Navbar.tsx +++ b/components/ui/Navbar.tsx @@ -68,7 +68,7 @@ const Navbar = () => {
    -
    +