import UserContext from '@/contexts/UserContext'; import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm, SubmitHandler } from 'react-hook-form'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; import toast from 'react-hot-toast'; import LoadingComponent from '../BeerById/LoadingComponent'; import CommentsComponent from '../ui/CommentsComponent'; import CommentForm from '../ui/CommentForm'; interface BreweryBeerSectionProps { breweryPost: z.infer; } interface BreweryCommentFormProps { breweryPost: z.infer; mutate: ReturnType['mutate']; } const BreweryCommentValidationSchemaWithId = CreateCommentValidationSchema.extend({ breweryPostId: z.string(), }); const sendCreateBreweryCommentRequest = async ({ content, rating, breweryPostId, }: z.infer) => { const response = await fetch(`/api/breweries/${breweryPostId}/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content, rating }), }); if (!response.ok) { throw new Error(response.statusText); } const data = await response.json(); const parsedResponse = APIResponseValidationSchema.safeParse(data); if (!parsedResponse.success) { throw new Error('Invalid API response'); } const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); if (!parsedPayload.success) { throw new Error('Invalid API response payload'); } return parsedPayload.data; }; const BreweryCommentForm: FC = ({ breweryPost, mutate }) => { const { register, handleSubmit, formState, watch, reset, setValue } = useForm< z.infer >({ defaultValues: { rating: 0 }, resolver: zodResolver(CreateCommentValidationSchema), }); const onSubmit: SubmitHandler> = async ( data, ) => { await sendCreateBreweryCommentRequest({ content: data.content, rating: data.rating, breweryPostId: breweryPost.id, }); await mutate(); toast.loading('Created new comment.'); reset(); }; return ( ); }; const BreweryCommentsSection: FC = ({ breweryPost }) => { const { user } = useContext(UserContext); const PAGE_SIZE = 4; const { isLoading, setSize, size, isLoadingMore, isAtEnd, mutate, comments: breweryComments, } = useBreweryPostComments({ id: breweryPost.id, pageSize: PAGE_SIZE }); const commentSectionRef: MutableRefObject = useRef(null); const handleDeleteRequest = async (commentId: string) => { const response = await fetch(`/api/brewery-comments/${commentId}`, { method: 'DELETE', }); if (!response.ok) { throw new Error(response.statusText); } }; const handleEditRequest = async ( commentId: string, data: z.infer, ) => { const response = await fetch(`/api/brewery-comments/${commentId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: data.content, rating: data.rating }), }); if (!response.ok) { throw new Error(response.statusText); } }; return (
{user ? ( ) : (
Log in to leave a comment.
)}
{ /** * If the comments are loading, show a loading component. Otherwise, show the * comments. */ isLoading ? (
) : ( ) }
); }; export default BreweryCommentsSection;