diff --git a/src/components/BeerBreweryComments/CommentCardBody.tsx b/src/components/BeerBreweryComments/CommentCardBody.tsx index 11e0636..f7ae738 100644 --- a/src/components/BeerBreweryComments/CommentCardBody.tsx +++ b/src/components/BeerBreweryComments/CommentCardBody.tsx @@ -1,9 +1,9 @@ import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import { FC, useState } from 'react'; import { useInView } from 'react-intersection-observer'; import { z } from 'zod'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import CommentContentBody from './CommentContentBody'; import EditCommentBody from './EditCommentBody'; diff --git a/src/components/BeerBreweryComments/CommentCardDropdown.tsx b/src/components/BeerBreweryComments/CommentCardDropdown.tsx index a163b46..25f548a 100644 --- a/src/components/BeerBreweryComments/CommentCardDropdown.tsx +++ b/src/components/BeerBreweryComments/CommentCardDropdown.tsx @@ -1,7 +1,7 @@ import UserContext from '@/contexts/UserContext'; import { Dispatch, SetStateAction, FC, useContext } from 'react'; import { FaEllipsisH } from 'react-icons/fa'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import { z } from 'zod'; interface CommentCardDropdownProps { diff --git a/src/components/BeerBreweryComments/CommentContentBody.tsx b/src/components/BeerBreweryComments/CommentContentBody.tsx index f0e7bf1..8665e0f 100644 --- a/src/components/BeerBreweryComments/CommentContentBody.tsx +++ b/src/components/BeerBreweryComments/CommentContentBody.tsx @@ -4,7 +4,7 @@ import { format } from 'date-fns'; import { Dispatch, FC, SetStateAction, useContext } from 'react'; import { Rating } from 'react-daisyui'; import Link from 'next/link'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import { z } from 'zod'; import CommentCardDropdown from './CommentCardDropdown'; diff --git a/src/components/BeerBreweryComments/EditCommentBody.tsx b/src/components/BeerBreweryComments/EditCommentBody.tsx index 9190d47..f9439e4 100644 --- a/src/components/BeerBreweryComments/EditCommentBody.tsx +++ b/src/components/BeerBreweryComments/EditCommentBody.tsx @@ -4,8 +4,8 @@ import { Rating } from 'react-daisyui'; import { useForm, SubmitHandler } from 'react-hook-form'; import { z } from 'zod'; import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; diff --git a/src/components/BeerById/BeerCommentForm.tsx b/src/components/BeerById/BeerCommentForm.tsx index 9f71bc2..9f58b50 100644 --- a/src/components/BeerById/BeerCommentForm.tsx +++ b/src/components/BeerById/BeerCommentForm.tsx @@ -1,6 +1,6 @@ import sendCreateBeerCommentRequest from '@/requests/BeerComment/sendCreateBeerCommentRequest'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { zodResolver } from '@hookform/resolvers/zod'; import { FunctionComponent } from 'react'; @@ -8,13 +8,13 @@ import { useForm, SubmitHandler } from 'react-hook-form'; import { z } from 'zod'; import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; import CommentForm from '../ui/CommentForm'; interface BeerCommentFormProps { - beerPost: z.infer; + beerPost: z.infer; mutate: ReturnType['mutate']; } diff --git a/src/components/BeerById/BeerInfoHeader.tsx b/src/components/BeerById/BeerInfoHeader.tsx index f53a2f3..639cad3 100644 --- a/src/components/BeerById/BeerInfoHeader.tsx +++ b/src/components/BeerById/BeerInfoHeader.tsx @@ -4,14 +4,14 @@ import { FC, useContext } from 'react'; import UserContext from '@/contexts/UserContext'; import { FaRegEdit } from 'react-icons/fa'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; import useGetBeerPostLikeCount from '@/hooks/data-fetching/beer-likes/useBeerPostLikeCount'; import useTimeDistance from '@/hooks/utilities/useTimeDistance'; import BeerPostLikeButton from './BeerPostLikeButton'; interface BeerInfoHeaderProps { - beerPost: z.infer; + beerPost: z.infer; } const BeerInfoHeader: FC = ({ beerPost }) => { diff --git a/src/components/BeerById/BeerPostCommentsSection.tsx b/src/components/BeerById/BeerPostCommentsSection.tsx index 1329d5b..8143923 100644 --- a/src/components/BeerById/BeerPostCommentsSection.tsx +++ b/src/components/BeerById/BeerPostCommentsSection.tsx @@ -1,19 +1,19 @@ import UserContext from '@/contexts/UserContext'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; import { useRouter } from 'next/router'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import BeerCommentForm from './BeerCommentForm'; import LoadingComponent from './LoadingComponent'; import CommentsComponent from '../ui/CommentsComponent'; interface BeerPostCommentsSectionProps { - beerPost: z.infer; + beerPost: z.infer; } const BeerPostCommentsSection: FC = ({ beerPost }) => { diff --git a/src/components/BeerById/BeerRecommendations.tsx b/src/components/BeerById/BeerRecommendations.tsx index 5be84b4..ca08e46 100644 --- a/src/components/BeerById/BeerRecommendations.tsx +++ b/src/components/BeerById/BeerRecommendations.tsx @@ -3,12 +3,12 @@ import { FC, MutableRefObject, useRef } from 'react'; import { useInView } from 'react-intersection-observer'; import { z } from 'zod'; import useBeerRecommendations from '@/hooks/data-fetching/beer-posts/useBeerRecommendations'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import debounce from 'lodash/debounce'; import BeerRecommendationLoadingComponent from './BeerRecommendationLoadingComponent'; const BeerRecommendationsSection: FC<{ - beerPost: z.infer; + beerPost: z.infer; }> = ({ beerPost }) => { const PAGE_SIZE = 10; diff --git a/src/components/BeerIndex/BeerCard.tsx b/src/components/BeerIndex/BeerCard.tsx index 9092126..168dcb1 100644 --- a/src/components/BeerIndex/BeerCard.tsx +++ b/src/components/BeerIndex/BeerCard.tsx @@ -1,13 +1,13 @@ import Link from 'next/link'; import { FC, useContext } from 'react'; import Image from 'next/image'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; import UserContext from '@/contexts/UserContext'; import useGetBeerPostLikeCount from '@/hooks/data-fetching/beer-likes/useBeerPostLikeCount'; import BeerPostLikeButton from '../BeerById/BeerPostLikeButton'; -const BeerCard: FC<{ post: z.infer }> = ({ post }) => { +const BeerCard: FC<{ post: z.infer }> = ({ post }) => { const { user } = useContext(UserContext); const { mutate, likeCount, isLoading } = useGetBeerPostLikeCount(post.id); diff --git a/src/components/BreweryById/BreweryBeerSection.tsx b/src/components/BreweryById/BreweryBeerSection.tsx index 5400277..89cd266 100644 --- a/src/components/BreweryById/BreweryBeerSection.tsx +++ b/src/components/BreweryById/BreweryBeerSection.tsx @@ -1,5 +1,5 @@ import UseBeerPostsByBrewery from '@/hooks/data-fetching/beer-posts/useBeerPostsByBrewery'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import Link from 'next/link'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { useInView } from 'react-intersection-observer'; diff --git a/src/components/BreweryById/BreweryCommentForm.tsx b/src/components/BreweryById/BreweryCommentForm.tsx index 469caed..fcaf4ee 100644 --- a/src/components/BreweryById/BreweryCommentForm.tsx +++ b/src/components/BreweryById/BreweryCommentForm.tsx @@ -1,6 +1,6 @@ import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import { zodResolver } from '@hookform/resolvers/zod'; import { FC } from 'react'; import { useForm, SubmitHandler } from 'react-hook-form'; diff --git a/src/components/BreweryById/BreweryCommentsSection.tsx b/src/components/BreweryById/BreweryCommentsSection.tsx index e0dbb41..8afaae9 100644 --- a/src/components/BreweryById/BreweryCommentsSection.tsx +++ b/src/components/BreweryById/BreweryCommentsSection.tsx @@ -1,8 +1,8 @@ import UserContext from '@/contexts/UserContext'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; import LoadingComponent from '../BeerById/LoadingComponent'; diff --git a/src/components/BreweryById/BreweryInfoHeader.tsx b/src/components/BreweryById/BreweryInfoHeader.tsx index 3c7badb..86e13e6 100644 --- a/src/components/BreweryById/BreweryInfoHeader.tsx +++ b/src/components/BreweryById/BreweryInfoHeader.tsx @@ -1,7 +1,7 @@ import UserContext from '@/contexts/UserContext'; import useGetBreweryPostLikeCount from '@/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount'; import useTimeDistance from '@/hooks/utilities/useTimeDistance'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { format } from 'date-fns'; import { FC, useContext } from 'react'; diff --git a/src/components/BreweryIndex/BreweryCard.tsx b/src/components/BreweryIndex/BreweryCard.tsx index a9779e8..adcc592 100644 --- a/src/components/BreweryIndex/BreweryCard.tsx +++ b/src/components/BreweryIndex/BreweryCard.tsx @@ -1,6 +1,6 @@ import UserContext from '@/contexts/UserContext'; import useGetBreweryPostLikeCount from '@/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { FC, useContext } from 'react'; import Link from 'next/link'; import { z } from 'zod'; diff --git a/src/components/BreweryPost/CreateBreweryPostForm.tsx b/src/components/BreweryPost/CreateBreweryPostForm.tsx new file mode 100644 index 0000000..969e119 --- /dev/null +++ b/src/components/BreweryPost/CreateBreweryPostForm.tsx @@ -0,0 +1,284 @@ +import sendUploadBreweryImagesRequest from '@/requests/BreweryImage/sendUploadBreweryImageRequest'; +import sendCreateBreweryPostRequest from '@/requests/BreweryPost/sendCreateBreweryPostRequest'; +import CreateBreweryPostSchema from '@/services/BreweryPost/schema/CreateBreweryPostSchema'; +import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema'; +import createErrorToast from '@/util/createErrorToast'; +import { Tab } from '@headlessui/react'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { AddressAutofillRetrieveResponse } from '@mapbox/search-js-core'; +import dynamic from 'next/dynamic'; +import { useRouter } from 'next/router'; +import { FC, Fragment } from 'react'; + +import { + useForm, + SubmitHandler, + FieldError, + UseFormRegister, + FieldErrors, + UseFormSetValue, +} from 'react-hook-form'; +import toast from 'react-hot-toast'; +import { z } from 'zod'; +import FormError from '../ui/forms/FormError'; +import FormInfo from '../ui/forms/FormInfo'; +import FormLabel from '../ui/forms/FormLabel'; +import FormSegment from '../ui/forms/FormSegment'; +import FormTextArea from '../ui/forms/FormTextArea'; +import FormTextInput from '../ui/forms/FormTextInput'; +import Button from '../ui/forms/Button'; + +const AddressAutofill = dynamic( + // @ts-ignore + () => import('@mapbox/search-js-react').then((mod) => mod.AddressAutofill), + { ssr: false }, +); +const CreateBreweryPostWithImagesSchema = CreateBreweryPostSchema.merge( + UploadImageValidationSchema, +); + +const InfoSection: FC<{ + register: UseFormRegister>; + errors: FieldErrors>; + isSubmitting: boolean; +}> = ({ register, errors, isSubmitting }) => { + return ( + <> + + Name + {errors.name?.message} + + + + + + Description + {errors.description?.message} + + + + + + Date Established + {errors.dateEstablished?.message} + + + + + + Images + {(errors.images as FieldError | undefined)?.message} + + + + + + ); +}; + +const LocationSection: FC<{ + register: UseFormRegister>; + errors: FieldErrors>; + isSubmitting: boolean; + setValue: UseFormSetValue>; +}> = ({ register, errors, isSubmitting, setValue }) => { + const onAutoCompleteChange = (address: string) => { + setValue('address', address); + }; + + const onAutoCompleteRetrieve = (address: AddressAutofillRetrieveResponse) => { + const { country, region, place } = address.features[0].properties as unknown as { + country?: string; + region?: string; + place?: string; + }; + + setValue('country', country); + setValue('region', region); + setValue('city', place!); + }; + + return ( + <> + + Address + {errors.address?.message} + + + + + + +
+
+ + City + {errors.city?.message} + + + + +
+
+ + Region + {errors.region?.message} + + + + +
+
+ + Country + {errors.country?.message} + + + + + + ); +}; + +const CreateBreweryPostForm: FC = () => { + const { + register, + handleSubmit, + reset, + setValue, + formState: { errors, isSubmitting }, + } = useForm>({ + resolver: zodResolver(CreateBreweryPostWithImagesSchema), + }); + + const router = useRouter(); + + const onSubmit: SubmitHandler< + z.infer + > = async (data) => { + const loadingToast = toast.loading('Creating brewery...'); + try { + if (!(data.images instanceof FileList)) { + return; + } + const breweryPost = await sendCreateBreweryPostRequest(data); + await sendUploadBreweryImagesRequest({ breweryPost, images: data.images }); + await router.push(`/breweries/${breweryPost.id}`); + toast.remove(loadingToast); + toast.success('Created brewery.'); + } catch (error) { + toast.remove(loadingToast); + createErrorToast(error); + reset(); + } + }; + + return ( +
{ + const fieldErrors = Object.keys(error).length; + + toast.error(`Form submission failed.`); + toast.error(`You have ${fieldErrors} errors in your form.`); + })} + className="form-control" + autoComplete="off" + > + + + + Information + + + Location + + + + + + + + + + + +
+ +
+
+ ); +}; + +export default CreateBreweryPostForm; diff --git a/src/components/CreateBeerPostForm.tsx b/src/components/CreateBeerPostForm.tsx index b0b76df..beea095 100644 --- a/src/components/CreateBeerPostForm.tsx +++ b/src/components/CreateBeerPostForm.tsx @@ -4,10 +4,10 @@ import router from 'next/router'; import { FunctionComponent } from 'react'; import { useForm, SubmitHandler, FieldError } from 'react-hook-form'; import { z } from 'zod'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import CreateBeerPostValidationSchema from '@/services/BeerPost/schema/CreateBeerPostValidationSchema'; import sendCreateBeerPostRequest from '@/requests/BeerPost/sendCreateBeerPostRequest'; -import UploadImageValidationSchema from '@/services/types/ImageSchema/UploadImageValidationSchema'; +import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema'; import sendUploadBeerImagesRequest from '@/requests/BeerImage/sendUploadBeerImageRequest'; import toast from 'react-hot-toast'; diff --git a/src/hooks/data-fetching/beer-comments/useBeerPostComments.ts b/src/hooks/data-fetching/beer-comments/useBeerPostComments.ts index 32e39ba..320f167 100644 --- a/src/hooks/data-fetching/beer-comments/useBeerPostComments.ts +++ b/src/hooks/data-fetching/beer-comments/useBeerPostComments.ts @@ -1,4 +1,4 @@ -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { z } from 'zod'; import useSWRInfinite from 'swr/infinite'; diff --git a/src/hooks/data-fetching/beer-posts/useBeerPostSearch.ts b/src/hooks/data-fetching/beer-posts/useBeerPostSearch.ts index d07e606..85caf98 100644 --- a/src/hooks/data-fetching/beer-posts/useBeerPostSearch.ts +++ b/src/hooks/data-fetching/beer-posts/useBeerPostSearch.ts @@ -1,4 +1,4 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import useSWR from 'swr'; import { z } from 'zod'; /** @@ -23,7 +23,7 @@ const useBeerPostSearch = (query: string | undefined) => { } const json = await response.json(); - const result = z.array(beerPostQueryResult).parse(json); + const result = z.array(BeerPostQueryResult).parse(json); return result; }, diff --git a/src/hooks/data-fetching/beer-posts/useBeerPosts.ts b/src/hooks/data-fetching/beer-posts/useBeerPosts.ts index 67a23c9..10c45f6 100644 --- a/src/hooks/data-fetching/beer-posts/useBeerPosts.ts +++ b/src/hooks/data-fetching/beer-posts/useBeerPosts.ts @@ -1,4 +1,4 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import useSWRInfinite from 'swr/infinite'; import { z } from 'zod'; @@ -34,7 +34,7 @@ const useBeerPosts = ({ pageSize }: { pageSize: number }) => { throw new Error('API response validation failed'); } - const parsedPayload = z.array(beerPostQueryResult).safeParse(parsed.data.payload); + const parsedPayload = z.array(BeerPostQueryResult).safeParse(parsed.data.payload); if (!parsedPayload.success) { throw new Error('API response validation failed'); } diff --git a/src/hooks/data-fetching/beer-posts/useBeerPostsByBrewery.ts b/src/hooks/data-fetching/beer-posts/useBeerPostsByBrewery.ts index c1627fb..9ac5619 100644 --- a/src/hooks/data-fetching/beer-posts/useBeerPostsByBrewery.ts +++ b/src/hooks/data-fetching/beer-posts/useBeerPostsByBrewery.ts @@ -1,4 +1,4 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import useSWRInfinite from 'swr/infinite'; import { z } from 'zod'; @@ -40,7 +40,7 @@ const UseBeerPostsByBrewery = ({ pageSize, breweryId }: UseBeerPostsByBreweryPar throw new Error('API response validation failed'); } - const parsedPayload = z.array(beerPostQueryResult).safeParse(parsed.data.payload); + const parsedPayload = z.array(BeerPostQueryResult).safeParse(parsed.data.payload); if (!parsedPayload.success) { throw new Error('API response validation failed'); } diff --git a/src/hooks/data-fetching/beer-posts/useBeerRecommendations.ts b/src/hooks/data-fetching/beer-posts/useBeerRecommendations.ts index 5e5cc53..181c1bc 100644 --- a/src/hooks/data-fetching/beer-posts/useBeerRecommendations.ts +++ b/src/hooks/data-fetching/beer-posts/useBeerRecommendations.ts @@ -1,11 +1,11 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import useSWRInfinite from 'swr/infinite'; import { z } from 'zod'; interface UseBeerRecommendationsParams { pageSize: number; - beerPost: z.infer; + beerPost: z.infer; } /** @@ -40,7 +40,7 @@ const UseBeerPostsByBrewery = ({ pageSize, beerPost }: UseBeerRecommendationsPar throw new Error('API response validation failed'); } - const parsedPayload = z.array(beerPostQueryResult).safeParse(parsed.data.payload); + const parsedPayload = z.array(BeerPostQueryResult).safeParse(parsed.data.payload); if (!parsedPayload.success) { throw new Error('API response validation failed'); } diff --git a/src/hooks/data-fetching/brewery-comments/useBreweryPostComments.ts b/src/hooks/data-fetching/brewery-comments/useBreweryPostComments.ts index d90dc1a..59e7803 100644 --- a/src/hooks/data-fetching/brewery-comments/useBreweryPostComments.ts +++ b/src/hooks/data-fetching/brewery-comments/useBreweryPostComments.ts @@ -1,4 +1,4 @@ -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { z } from 'zod'; import useSWRInfinite from 'swr/infinite'; diff --git a/src/hooks/data-fetching/brewery-posts/useBreweryMapPagePosts.ts b/src/hooks/data-fetching/brewery-posts/useBreweryMapPagePosts.ts index ca91166..544fd10 100644 --- a/src/hooks/data-fetching/brewery-posts/useBreweryMapPagePosts.ts +++ b/src/hooks/data-fetching/brewery-posts/useBreweryMapPagePosts.ts @@ -1,4 +1,4 @@ -import BreweryPostMapQueryResult from '@/services/BreweryPost/types/BreweryPostMapQueryResult'; +import BreweryPostMapQueryResult from '@/services/BreweryPost/schema/BreweryPostMapQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import useSWRInfinite from 'swr/infinite'; import { z } from 'zod'; diff --git a/src/hooks/data-fetching/brewery-posts/useBreweryPosts.ts b/src/hooks/data-fetching/brewery-posts/useBreweryPosts.ts index afc74dc..7ce0517 100644 --- a/src/hooks/data-fetching/brewery-posts/useBreweryPosts.ts +++ b/src/hooks/data-fetching/brewery-posts/useBreweryPosts.ts @@ -1,4 +1,4 @@ -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import useSWRInfinite from 'swr/infinite'; import { z } from 'zod'; diff --git a/src/pages/api/beer-comments/[id].ts b/src/pages/api/beer-comments/[id].ts index f5130b8..6357632 100644 --- a/src/pages/api/beer-comments/[id].ts +++ b/src/pages/api/beer-comments/[id].ts @@ -5,7 +5,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import ServerError from '@/config/util/ServerError'; import DBClient from '@/prisma/DBClient'; import findBeerCommentById from '@/services/BeerComment/findBeerCommentById'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import editBeerCommentById from '@/services/BeerComment/editBeerCommentById'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; diff --git a/src/pages/api/beers/[id]/comments/index.ts b/src/pages/api/beers/[id]/comments/index.ts index bd44ae4..33afa40 100644 --- a/src/pages/api/beers/[id]/comments/index.ts +++ b/src/pages/api/beers/[id]/comments/index.ts @@ -10,8 +10,8 @@ import { createRouter } from 'next-connect'; import { z } from 'zod'; import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; import { NextApiResponse } from 'next'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; interface CreateCommentRequest extends UserExtendedNextApiRequest { body: z.infer; diff --git a/src/pages/api/beers/[id]/images/index.ts b/src/pages/api/beers/[id]/images/index.ts index 40575da..1ade6cf 100644 --- a/src/pages/api/beers/[id]/images/index.ts +++ b/src/pages/api/beers/[id]/images/index.ts @@ -13,7 +13,7 @@ import { z } from 'zod'; import ServerError from '@/config/util/ServerError'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import addBeerImageToDB from '@/services/BeerImage/addBeerImageToDB'; -import ImageMetadataValidationSchema from '@/services/types/ImageSchema/ImageMetadataValidationSchema'; +import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema'; const { storage } = cloudinaryConfig; diff --git a/src/pages/api/beers/search.ts b/src/pages/api/beers/search.ts index fc77a1b..4e6e19d 100644 --- a/src/pages/api/beers/search.ts +++ b/src/pages/api/beers/search.ts @@ -5,7 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { createRouter } from 'next-connect'; import { z } from 'zod'; import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; const SearchSchema = z.object({ search: z.string().min(1), @@ -18,7 +18,7 @@ interface SearchAPIRequest extends NextApiRequest { const search = async (req: SearchAPIRequest, res: NextApiResponse) => { const { search: query } = req.query; - const beers: z.infer[] = + const beers: z.infer[] = await DBClient.instance.beerPost.findMany({ select: { id: true, diff --git a/src/pages/api/breweries/[id]/beers/index.ts b/src/pages/api/breweries/[id]/beers/index.ts index aa1f0b3..8104171 100644 --- a/src/pages/api/breweries/[id]/beers/index.ts +++ b/src/pages/api/breweries/[id]/beers/index.ts @@ -1,7 +1,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiRequest, NextApiResponse } from 'next'; import { createRouter } from 'next-connect'; @@ -18,7 +18,7 @@ const getAllBeersByBrewery = async ( // eslint-disable-next-line @typescript-eslint/naming-convention const { page_size, page_num, id } = req.query; - const beers: z.infer[] = + const beers: z.infer[] = await DBClient.instance.beerPost.findMany({ where: { breweryId: id }, take: parseInt(page_size, 10), diff --git a/src/pages/api/breweries/[id]/comments/index.ts b/src/pages/api/breweries/[id]/comments/index.ts index b8ea448..e13eebb 100644 --- a/src/pages/api/breweries/[id]/comments/index.ts +++ b/src/pages/api/breweries/[id]/comments/index.ts @@ -13,9 +13,9 @@ import { z } from 'zod'; import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; import { NextApiResponse } from 'next'; -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import getAllBreweryComments from '@/services/BreweryComment/getAllBreweryComments'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import createNewBreweryComment from '@/services/BreweryComment/createNewBreweryComment'; interface CreateCommentRequest extends UserExtendedNextApiRequest { diff --git a/src/pages/api/breweries/[id]/images/index.ts b/src/pages/api/breweries/[id]/images/index.ts index ac6f652..780c5a4 100644 --- a/src/pages/api/breweries/[id]/images/index.ts +++ b/src/pages/api/breweries/[id]/images/index.ts @@ -12,7 +12,7 @@ import { NextApiResponse } from 'next'; import { z } from 'zod'; import ServerError from '@/config/util/ServerError'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; -import ImageMetadataValidationSchema from '@/services/types/ImageSchema/ImageMetadataValidationSchema'; +import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema'; import addBreweryImageToDB from '@/services/BreweryImage/addBreweryImageToDB'; const { storage } = cloudinaryConfig; diff --git a/src/pages/api/breweries/[id]/index.ts b/src/pages/api/breweries/[id]/index.ts new file mode 100644 index 0000000..b04a52e --- /dev/null +++ b/src/pages/api/breweries/[id]/index.ts @@ -0,0 +1,91 @@ +import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; +import { UserExtendedNextApiRequest } from '@/config/auth/types'; +import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { NextApiResponse } from 'next'; +import { createRouter, NextHandler } from 'next-connect'; +import { z } from 'zod'; +import ServerError from '@/config/util/ServerError'; +import DBClient from '@/prisma/DBClient'; +import getBreweryPostById from '@/services/BreweryPost/getBreweryPostById'; +import EditBreweryPostValidationSchema from '@/services/BreweryPost/schema/EditBreweryPostValidationSchema'; + +interface BreweryPostRequest extends UserExtendedNextApiRequest { + query: { id: string }; +} + +interface EditBreweryPostRequest extends BreweryPostRequest { + body: z.infer; +} + +const checkIfBreweryPostOwner = async ( + req: BreweryPostRequest, + res: NextApiResponse, + next: NextHandler, +) => { + const user = req.user!; + const { id } = req.query; + + const breweryPost = await getBreweryPostById(id); + if (!breweryPost) { + throw new ServerError('Brewery post not found', 404); + } + + if (breweryPost.postedBy.id !== user.id) { + throw new ServerError('You are not the owner of this brewery post', 403); + } + + next(); +}; + +const editBreweryPost = async ( + req: EditBreweryPostRequest, + res: NextApiResponse>, +) => { + const { + body, + query: { id }, + } = req; + + await DBClient.instance.breweryPost.update({ + where: { id }, + data: body, + }); + + res.status(200).json({ + message: 'Brewery post updated successfully', + success: true, + statusCode: 200, + }); +}; + +const deleteBreweryPost = async (req: BreweryPostRequest, res: NextApiResponse) => { + const { + query: { id }, + } = req; + + const deleted = await DBClient.instance.beerPost.delete({ + where: { id }, + }); + + if (!deleted) { + throw new ServerError('Brewery post not found', 404); + } + + res.status(200).json({ + message: 'Brewery post deleted successfully', + success: true, + statusCode: 200, + }); +}; +const router = createRouter< + EditBreweryPostRequest, + NextApiResponse> +>(); + +router.put(getCurrentUser, checkIfBreweryPostOwner, editBreweryPost); +router.delete(getCurrentUser, checkIfBreweryPostOwner, deleteBreweryPost); + +const handler = router.handler(NextConnectOptions); + +export default handler; diff --git a/src/pages/api/breweries/create.ts b/src/pages/api/breweries/create.ts index 7133307..07308f1 100644 --- a/src/pages/api/breweries/create.ts +++ b/src/pages/api/breweries/create.ts @@ -6,7 +6,7 @@ import { NextApiResponse } from 'next'; import { z } from 'zod'; import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; -import CreateBreweryPostSchema from '@/services/BreweryPost/types/CreateBreweryPostSchema'; +import CreateBreweryPostSchema from '@/services/BreweryPost/schema/CreateBreweryPostSchema'; import createNewBreweryPost from '@/services/BreweryPost/createNewBreweryPost'; import geocode from '@/config/mapbox/geocoder'; import ServerError from '@/config/util/ServerError'; diff --git a/src/pages/api/breweries/map/index.ts b/src/pages/api/breweries/map/index.ts index 7d9fdd8..1016221 100644 --- a/src/pages/api/breweries/map/index.ts +++ b/src/pages/api/breweries/map/index.ts @@ -1,6 +1,6 @@ import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import DBClient from '@/prisma/DBClient'; -import BreweryPostMapQueryResult from '@/services/BreweryPost/types/BreweryPostMapQueryResult'; +import BreweryPostMapQueryResult from '@/services/BreweryPost/schema/BreweryPostMapQueryResult'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiRequest, NextApiResponse } from 'next'; diff --git a/src/pages/api/brewery-comments/[id].ts b/src/pages/api/brewery-comments/[id].ts index b72479e..e343f90 100644 --- a/src/pages/api/brewery-comments/[id].ts +++ b/src/pages/api/brewery-comments/[id].ts @@ -4,7 +4,7 @@ import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import ServerError from '@/config/util/ServerError'; import DBClient from '@/prisma/DBClient'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; diff --git a/src/pages/beers/[id]/edit.tsx b/src/pages/beers/[id]/edit.tsx index a55e933..ba86060 100644 --- a/src/pages/beers/[id]/edit.tsx +++ b/src/pages/beers/[id]/edit.tsx @@ -4,17 +4,17 @@ import React from 'react'; import withPageAuthRequired from '@/util/withPageAuthRequired'; import getBeerPostById from '@/services/BeerPost/getBeerPostById'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import EditBeerPostForm from '@/components/EditBeerPostForm'; import FormPageLayout from '@/components/ui/forms/FormPageLayout'; import { BiBeer } from 'react-icons/bi'; import { z } from 'zod'; interface EditPageProps { - beerPost: z.infer; + beerPost: z.infer; } -const EditPage: NextPage = ({ beerPost }) => { +const EditBeerPostPage: NextPage = ({ beerPost }) => { const pageTitle = `Edit \u201c${beerPost.name}\u201d`; return ( @@ -44,7 +44,7 @@ const EditPage: NextPage = ({ beerPost }) => { ); }; -export default EditPage; +export default EditBeerPostPage; export const getServerSideProps = withPageAuthRequired( async (context, session) => { diff --git a/src/pages/beers/[id]/index.tsx b/src/pages/beers/[id]/index.tsx index 4138520..97db821 100644 --- a/src/pages/beers/[id]/index.tsx +++ b/src/pages/beers/[id]/index.tsx @@ -4,7 +4,7 @@ import Image from 'next/image'; import getBeerPostById from '@/services/BeerPost/getBeerPostById'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; @@ -21,7 +21,7 @@ const [BeerInfoHeader, BeerPostCommentsSection, BeerRecommendations] = [ ]; interface BeerPageProps { - beerPost: z.infer; + beerPost: z.infer; } const BeerByIdPage: NextPage = ({ beerPost }) => { diff --git a/src/pages/breweries/[id]/beers/create.tsx b/src/pages/breweries/[id]/beers/create.tsx index 545ebcf..d914053 100644 --- a/src/pages/breweries/[id]/beers/create.tsx +++ b/src/pages/breweries/[id]/beers/create.tsx @@ -3,7 +3,7 @@ import FormPageLayout from '@/components/ui/forms/FormPageLayout'; import withPageAuthRequired from '@/util/withPageAuthRequired'; import DBClient from '@/prisma/DBClient'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { BeerType } from '@prisma/client'; import { NextPage } from 'next'; import { BiBeer } from 'react-icons/bi'; diff --git a/src/pages/breweries/[id]/edit.tsx b/src/pages/breweries/[id]/edit.tsx new file mode 100644 index 0000000..d8eb4f2 --- /dev/null +++ b/src/pages/breweries/[id]/edit.tsx @@ -0,0 +1,55 @@ +import FormPageLayout from '@/components/ui/forms/FormPageLayout'; +import getBreweryPostById from '@/services/BreweryPost/getBreweryPostById'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; +import withPageAuthRequired from '@/util/withPageAuthRequired'; +import { NextPage } from 'next'; +import Head from 'next/head'; +import { BiBeer } from 'react-icons/bi'; +import { z } from 'zod'; + +interface EditPageProps { + breweryPost: z.infer; +} + +const EditBreweryPostPage: NextPage = ({ breweryPost }) => { + const pageTitle = `Edit \u201c${breweryPost.name}\u201d`; + + return ( + <> + + {pageTitle} + + + + + <> + + + ); +}; + +export default EditBreweryPostPage; + +export const getServerSideProps = withPageAuthRequired( + async (context, session) => { + const breweryPostId = context.params?.id as string; + const breweryPost = await getBreweryPostById(breweryPostId); + + const { id: userId } = session; + + if (!breweryPost) { + return { notFound: true }; + } + + const isBreweryPostOwner = breweryPost.postedBy.id === userId; + + return isBreweryPostOwner + ? { props: { breweryPost: JSON.parse(JSON.stringify(breweryPost)) } } + : { redirect: { destination: `/breweries/${breweryPostId}`, permanent: false } }; + }, +); diff --git a/src/pages/breweries/[id]/index.tsx b/src/pages/breweries/[id]/index.tsx index 30b8c2e..3af2f4d 100644 --- a/src/pages/breweries/[id]/index.tsx +++ b/src/pages/breweries/[id]/index.tsx @@ -1,5 +1,5 @@ import getBreweryPostById from '@/services/BreweryPost/getBreweryPostById'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { GetServerSideProps, NextPage } from 'next'; import { z } from 'zod'; diff --git a/src/pages/breweries/create.tsx b/src/pages/breweries/create.tsx index 7e32d09..d8cd0ec 100644 --- a/src/pages/breweries/create.tsx +++ b/src/pages/breweries/create.tsx @@ -1,115 +1,12 @@ -import Button from '@/components/ui/forms/Button'; -import FormError from '@/components/ui/forms/FormError'; -import FormInfo from '@/components/ui/forms/FormInfo'; -import FormLabel from '@/components/ui/forms/FormLabel'; import FormPageLayout from '@/components/ui/forms/FormPageLayout'; -import FormSegment from '@/components/ui/forms/FormSegment'; -import FormTextArea from '@/components/ui/forms/FormTextArea'; -import FormTextInput from '@/components/ui/forms/FormTextInput'; - -import createErrorToast from '@/util/createErrorToast'; import withPageAuthRequired from '@/util/withPageAuthRequired'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { zodResolver } from '@hookform/resolvers/zod'; -import type { AddressAutofillRetrieveResponse } from '@mapbox/search-js-core'; import { GetServerSideProps, NextPage } from 'next'; import Head from 'next/head'; -import { FieldError, SubmitHandler, useForm } from 'react-hook-form'; -import toast from 'react-hot-toast'; + import { FaBeer } from 'react-icons/fa'; -import { z } from 'zod'; -import dynamic from 'next/dynamic'; -import { useRouter } from 'next/router'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; -import CreateBreweryPostSchema from '@/services/BreweryPost/types/CreateBreweryPostSchema'; -import UploadImageValidationSchema from '@/services/types/ImageSchema/UploadImageValidationSchema'; -import sendUploadBreweryImagesRequest from '@/requests/BreweryImage/sendUploadBreweryImageRequest'; - -const AddressAutofill = dynamic( - () => import('@mapbox/search-js-react').then((mod) => mod.AddressAutofill), - { ssr: false }, -); -const CreateBreweryPostWithImagesSchema = CreateBreweryPostSchema.merge( - UploadImageValidationSchema, -); - -const sendCreateBreweryPostRequest = async ( - data: z.infer, -) => { - const response = await fetch('/api/breweries/create', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - if (!parsed.success) { - throw new Error('API response parsing failed'); - } - - const parsedPayload = BreweryPostQueryResult.safeParse(parsed.data.payload); - if (!parsedPayload.success) { - throw new Error('API response payload parsing failed'); - } - - return parsedPayload.data; -}; +import CreateBreweryPostForm from '@/components/BreweryPost/CreateBreweryPostForm'; const CreateBreweryPage: NextPage = () => { - const { - register, - handleSubmit, - reset, - setValue, - formState: { errors, isSubmitting }, - } = useForm>({ - resolver: zodResolver(CreateBreweryPostWithImagesSchema), - }); - - const router = useRouter(); - - const onSubmit: SubmitHandler< - z.infer - > = async (data) => { - const loadingToast = toast.loading('Creating brewery...'); - try { - if (!(data.images instanceof FileList)) { - return; - } - const breweryPost = await sendCreateBreweryPostRequest(data); - await sendUploadBreweryImagesRequest({ breweryPost, images: data.images }); - await router.push(`/breweries/${breweryPost.id}`); - toast.remove(loadingToast); - toast.success('Created brewery.'); - } catch (error) { - toast.remove(loadingToast); - reset(); - createErrorToast(error); - } - }; - - const onAutoCompleteChange = (address: string) => { - setValue('address', address); - }; - - const onAutoCompleteRetrieve = (address: AddressAutofillRetrieveResponse) => { - const { country, region, place } = address.features[0].properties as unknown as { - country?: string; - region?: string; - place?: string; - }; - - setValue('country', country); - setValue('region', region); - setValue('city', place!); - }; - return ( <> @@ -123,150 +20,7 @@ const CreateBreweryPage: NextPage = () => { headingText="Create Brewery" headingIcon={FaBeer} > -
-
- - Name - {errors.name?.message} - - - - - - Description - {errors.description?.message} - - - - - - Date Established - {errors.dateEstablished?.message} - - - - - - Images - - {(errors.images as FieldError | undefined)?.message} - - - - - -
- -
- - Address - {errors.address?.message} - - - - - - - -
-
- - City - {errors.city?.message} - - - - -
-
- - Region - {errors.region?.message} - - - - -
-
- - Country - {errors.country?.message} - - - - -
-
- -
-
+ diff --git a/src/pages/breweries/index.tsx b/src/pages/breweries/index.tsx index 275e318..f9aa78a 100644 --- a/src/pages/breweries/index.tsx +++ b/src/pages/breweries/index.tsx @@ -3,7 +3,7 @@ import LoadingCard from '@/components/ui/LoadingCard'; import Spinner from '@/components/ui/Spinner'; import UserContext from '@/contexts/UserContext'; import useBreweryPosts from '@/hooks/data-fetching/brewery-posts/useBreweryPosts'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { NextPage } from 'next'; import Head from 'next/head'; import { useContext, MutableRefObject, useRef } from 'react'; diff --git a/src/pages/breweries/map.tsx b/src/pages/breweries/map.tsx index 826a62a..aa6236d 100644 --- a/src/pages/breweries/map.tsx +++ b/src/pages/breweries/map.tsx @@ -7,7 +7,7 @@ import LocationMarker from '@/components/ui/LocationMarker'; import Link from 'next/link'; import Head from 'next/head'; import useGeolocation from '@/hooks/utilities/useGeolocation'; -import BreweryPostMapQueryResult from '@/services/BreweryPost/types/BreweryPostMapQueryResult'; +import BreweryPostMapQueryResult from '@/services/BreweryPost/schema/BreweryPostMapQueryResult'; import { z } from 'zod'; import useBreweryMapPagePosts from '@/hooks/data-fetching/brewery-posts/useBreweryMapPagePosts'; import ControlPanel from '@/components/ui/maps/ControlPanel'; diff --git a/src/requests/BeerComment/sendCreateBeerCommentRequest.ts b/src/requests/BeerComment/sendCreateBeerCommentRequest.ts index 0874ec9..13c4146 100644 --- a/src/requests/BeerComment/sendCreateBeerCommentRequest.ts +++ b/src/requests/BeerComment/sendCreateBeerCommentRequest.ts @@ -1,5 +1,5 @@ -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { z } from 'zod'; diff --git a/src/requests/BeerImage/sendUploadBeerImageRequest.ts b/src/requests/BeerImage/sendUploadBeerImageRequest.ts index 0d8f662..5146358 100644 --- a/src/requests/BeerImage/sendUploadBeerImageRequest.ts +++ b/src/requests/BeerImage/sendUploadBeerImageRequest.ts @@ -1,8 +1,8 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; interface SendUploadBeerImagesRequestArgs { - beerPost: z.infer; + beerPost: z.infer; images: FileList; } diff --git a/src/requests/BeerPost/sendCreateBeerPostRequest.ts b/src/requests/BeerPost/sendCreateBeerPostRequest.ts index 0671038..58ca229 100644 --- a/src/requests/BeerPost/sendCreateBeerPostRequest.ts +++ b/src/requests/BeerPost/sendCreateBeerPostRequest.ts @@ -1,4 +1,4 @@ -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import CreateBeerPostValidationSchema from '@/services/BeerPost/schema/CreateBeerPostValidationSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { z } from 'zod'; @@ -24,7 +24,7 @@ const sendCreateBeerPostRequest = async ( throw new Error(message); } - const parsedPayload = beerPostQueryResult.safeParse(payload); + const parsedPayload = BeerPostQueryResult.safeParse(payload); if (!parsedPayload.success) { throw new Error('Invalid API response payload'); diff --git a/src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts b/src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts index 8312d32..0f356a9 100644 --- a/src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts +++ b/src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts @@ -1,5 +1,5 @@ -import CommentQueryResult from '@/services/types/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/types/CommentSchema/CreateCommentValidationSchema'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { z } from 'zod'; diff --git a/src/requests/BreweryImage/sendUploadBreweryImageRequest.ts b/src/requests/BreweryImage/sendUploadBreweryImageRequest.ts index 31f833b..7875d68 100644 --- a/src/requests/BreweryImage/sendUploadBreweryImageRequest.ts +++ b/src/requests/BreweryImage/sendUploadBreweryImageRequest.ts @@ -1,4 +1,4 @@ -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { z } from 'zod'; interface SendUploadBeerImagesRequestArgs { diff --git a/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts b/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts new file mode 100644 index 0000000..2da3ed5 --- /dev/null +++ b/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts @@ -0,0 +1,34 @@ +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; +import CreateBreweryPostSchema from '@/services/BreweryPost/schema/CreateBreweryPostSchema'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +const sendCreateBreweryPostRequest = async ( + data: z.infer, +) => { + const response = await fetch('/api/breweries/create', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('API response parsing failed'); + } + + const parsedPayload = BreweryPostQueryResult.safeParse(parsed.data.payload); + if (!parsedPayload.success) { + throw new Error('API response payload parsing failed'); + } + + return parsedPayload.data; +}; + +export default sendCreateBreweryPostRequest; diff --git a/src/services/BeerComment/createNewBeerComment.ts b/src/services/BeerComment/createNewBeerComment.ts index edd4825..50fb141 100644 --- a/src/services/BeerComment/createNewBeerComment.ts +++ b/src/services/BeerComment/createNewBeerComment.ts @@ -1,6 +1,6 @@ import DBClient from '@/prisma/DBClient'; import { z } from 'zod'; -import CreateCommentValidationSchema from '../types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '../schema/CommentSchema/CreateCommentValidationSchema'; const CreateNewBeerCommentServiceSchema = CreateCommentValidationSchema.extend({ userId: z.string().cuid(), diff --git a/src/services/BeerComment/getAllBeerComments.ts b/src/services/BeerComment/getAllBeerComments.ts index a3582ef..c414ed1 100644 --- a/src/services/BeerComment/getAllBeerComments.ts +++ b/src/services/BeerComment/getAllBeerComments.ts @@ -1,10 +1,10 @@ import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; -import CommentQueryResult from '../types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '../schema/CommentSchema/CommentQueryResult'; const getAllBeerComments = async ( - { id }: Pick, 'id'>, + { id }: Pick, 'id'>, { pageSize, pageNum = 0 }: { pageSize: number; pageNum?: number }, ) => { const skip = (pageNum - 1) * pageSize; diff --git a/src/services/BeerImage/addBeerImageToDB.ts b/src/services/BeerImage/addBeerImageToDB.ts index 8cff61b..f99fc83 100644 --- a/src/services/BeerImage/addBeerImageToDB.ts +++ b/src/services/BeerImage/addBeerImageToDB.ts @@ -1,7 +1,7 @@ import DBClient from '@/prisma/DBClient'; import { BeerImage } from '@prisma/client'; import { z } from 'zod'; -import ImageMetadataValidationSchema from '../types/ImageSchema/ImageMetadataValidationSchema'; +import ImageMetadataValidationSchema from '../schema/ImageSchema/ImageMetadataValidationSchema'; interface ProcessImageDataArgs { files: Express.Multer.File[]; diff --git a/src/services/BeerPost/createNewBeerPost.ts b/src/services/BeerPost/createNewBeerPost.ts index 1b8d3f1..b116510 100644 --- a/src/services/BeerPost/createNewBeerPost.ts +++ b/src/services/BeerPost/createNewBeerPost.ts @@ -1,6 +1,6 @@ import DBClient from '@/prisma/DBClient'; import { z } from 'zod'; -import beerPostQueryResult from './schema/BeerPostQueryResult'; +import BeerPostQueryResult from './schema/BeerPostQueryResult'; import CreateBeerPostValidationSchema from './schema/CreateBeerPostValidationSchema'; const CreateBeerPostWithUserSchema = CreateBeerPostValidationSchema.extend({ @@ -16,7 +16,7 @@ const createNewBeerPost = async ({ breweryId, userId, }: z.infer) => { - const newBeerPost: z.infer = + const newBeerPost: z.infer = await DBClient.instance.beerPost.create({ data: { name, diff --git a/src/services/BeerPost/getAllBeerPosts.ts b/src/services/BeerPost/getAllBeerPosts.ts index 8b1ca2e..6ec4e29 100644 --- a/src/services/BeerPost/getAllBeerPosts.ts +++ b/src/services/BeerPost/getAllBeerPosts.ts @@ -1,5 +1,5 @@ import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; const prisma = DBClient.instance; @@ -7,7 +7,7 @@ const prisma = DBClient.instance; const getAllBeerPosts = async (pageNum: number, pageSize: number) => { const skip = (pageNum - 1) * pageSize; - const beerPosts: z.infer[] = await prisma.beerPost.findMany( + const beerPosts: z.infer[] = await prisma.beerPost.findMany( { select: { id: true, diff --git a/src/services/BeerPost/getBeerPostById.ts b/src/services/BeerPost/getBeerPostById.ts index e133a6d..dda9e33 100644 --- a/src/services/BeerPost/getBeerPostById.ts +++ b/src/services/BeerPost/getBeerPostById.ts @@ -1,11 +1,11 @@ import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; const prisma = DBClient.instance; const getBeerPostById = async (id: string) => { - const beerPost: z.infer | null = + const beerPost: z.infer | null = await prisma.beerPost.findFirst({ select: { id: true, diff --git a/src/services/BeerPost/schema/BeerPostQueryResult.ts b/src/services/BeerPost/schema/BeerPostQueryResult.ts index 3641066..a92cf97 100644 --- a/src/services/BeerPost/schema/BeerPostQueryResult.ts +++ b/src/services/BeerPost/schema/BeerPostQueryResult.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -const beerPostQueryResult = z.object({ +const BeerPostQueryResult = z.object({ id: z.string(), name: z.string(), brewery: z.object({ id: z.string(), name: z.string() }), @@ -15,4 +15,4 @@ const beerPostQueryResult = z.object({ createdAt: z.coerce.date(), }); -export default beerPostQueryResult; +export default BeerPostQueryResult; diff --git a/src/services/BreweryComment/createNewBreweryComment.ts b/src/services/BreweryComment/createNewBreweryComment.ts index c89fa07..c1b5ebd 100644 --- a/src/services/BreweryComment/createNewBreweryComment.ts +++ b/src/services/BreweryComment/createNewBreweryComment.ts @@ -1,6 +1,6 @@ import DBClient from '@/prisma/DBClient'; import { z } from 'zod'; -import CreateCommentValidationSchema from '../types/CommentSchema/CreateCommentValidationSchema'; +import CreateCommentValidationSchema from '../schema/CommentSchema/CreateCommentValidationSchema'; const CreateNewBreweryCommentServiceSchema = CreateCommentValidationSchema.extend({ userId: z.string().cuid(), diff --git a/src/services/BreweryComment/getAllBreweryComments.ts b/src/services/BreweryComment/getAllBreweryComments.ts index 175eb5e..44f9203 100644 --- a/src/services/BreweryComment/getAllBreweryComments.ts +++ b/src/services/BreweryComment/getAllBreweryComments.ts @@ -1,10 +1,10 @@ import DBClient from '@/prisma/DBClient'; -import beerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; +import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult'; import { z } from 'zod'; -import CommentQueryResult from '../types/CommentSchema/CommentQueryResult'; +import CommentQueryResult from '../schema/CommentSchema/CommentQueryResult'; const getAllBreweryComments = async ( - { id }: Pick, 'id'>, + { id }: Pick, 'id'>, { pageSize, pageNum = 0 }: { pageSize: number; pageNum?: number }, ) => { const skip = (pageNum - 1) * pageSize; diff --git a/src/services/BreweryImage/addBreweryImageToDB.ts b/src/services/BreweryImage/addBreweryImageToDB.ts index 92d7100..e4b5499 100644 --- a/src/services/BreweryImage/addBreweryImageToDB.ts +++ b/src/services/BreweryImage/addBreweryImageToDB.ts @@ -1,7 +1,7 @@ import DBClient from '@/prisma/DBClient'; import { BreweryImage } from '@prisma/client'; import { z } from 'zod'; -import ImageMetadataValidationSchema from '../types/ImageSchema/ImageMetadataValidationSchema'; +import ImageMetadataValidationSchema from '../schema/ImageSchema/ImageMetadataValidationSchema'; interface ProcessImageDataArgs { files: Express.Multer.File[]; diff --git a/src/services/BreweryPost/createNewBreweryPost.ts b/src/services/BreweryPost/createNewBreweryPost.ts index c24ed4c..360fc6e 100644 --- a/src/services/BreweryPost/createNewBreweryPost.ts +++ b/src/services/BreweryPost/createNewBreweryPost.ts @@ -1,7 +1,7 @@ import DBClient from '@/prisma/DBClient'; import { z } from 'zod'; -import CreateBreweryPostSchema from './types/CreateBreweryPostSchema'; -import BreweryPostQueryResult from './types/BreweryPostQueryResult'; +import CreateBreweryPostSchema from './schema/CreateBreweryPostSchema'; +import BreweryPostQueryResult from './schema/BreweryPostQueryResult'; const CreateNewBreweryPostWithUserAndLocationSchema = CreateBreweryPostSchema.omit({ address: true, diff --git a/src/services/BreweryPost/getAllBreweryPosts.ts b/src/services/BreweryPost/getAllBreweryPosts.ts index a1a6b97..82312a5 100644 --- a/src/services/BreweryPost/getAllBreweryPosts.ts +++ b/src/services/BreweryPost/getAllBreweryPosts.ts @@ -1,5 +1,5 @@ import DBClient from '@/prisma/DBClient'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { z } from 'zod'; diff --git a/src/services/BreweryPost/getBreweryPostById.ts b/src/services/BreweryPost/getBreweryPostById.ts index 3bb1ecb..f3e978b 100644 --- a/src/services/BreweryPost/getBreweryPostById.ts +++ b/src/services/BreweryPost/getBreweryPostById.ts @@ -1,5 +1,5 @@ import DBClient from '@/prisma/DBClient'; -import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult'; +import BreweryPostQueryResult from '@/services/BreweryPost/schema/BreweryPostQueryResult'; import { z } from 'zod'; const prisma = DBClient.instance; diff --git a/src/services/BreweryPost/types/BreweryPostMapQueryResult.ts b/src/services/BreweryPost/schema/BreweryPostMapQueryResult.ts similarity index 100% rename from src/services/BreweryPost/types/BreweryPostMapQueryResult.ts rename to src/services/BreweryPost/schema/BreweryPostMapQueryResult.ts diff --git a/src/services/BreweryPost/types/BreweryPostQueryResult.ts b/src/services/BreweryPost/schema/BreweryPostQueryResult.ts similarity index 100% rename from src/services/BreweryPost/types/BreweryPostQueryResult.ts rename to src/services/BreweryPost/schema/BreweryPostQueryResult.ts diff --git a/src/services/BreweryPost/types/CreateBreweryPostSchema.ts b/src/services/BreweryPost/schema/CreateBreweryPostSchema.ts similarity index 100% rename from src/services/BreweryPost/types/CreateBreweryPostSchema.ts rename to src/services/BreweryPost/schema/CreateBreweryPostSchema.ts diff --git a/src/services/BreweryPost/schema/EditBreweryPostValidationSchema.ts b/src/services/BreweryPost/schema/EditBreweryPostValidationSchema.ts new file mode 100644 index 0000000..705fe97 --- /dev/null +++ b/src/services/BreweryPost/schema/EditBreweryPostValidationSchema.ts @@ -0,0 +1,13 @@ +import { z } from 'zod'; +import CreateBreweryPostSchema from './CreateBreweryPostSchema'; + +const EditBreweryPostValidationSchema = CreateBreweryPostSchema.extend({ + id: z.string().cuid(), +}).omit({ + address: true, + city: true, + region: true, + country: true, +}); + +export default EditBreweryPostValidationSchema; diff --git a/src/services/types/CommentSchema/CommentQueryResult.ts b/src/services/schema/CommentSchema/CommentQueryResult.ts similarity index 100% rename from src/services/types/CommentSchema/CommentQueryResult.ts rename to src/services/schema/CommentSchema/CommentQueryResult.ts diff --git a/src/services/types/CommentSchema/CreateCommentValidationSchema.ts b/src/services/schema/CommentSchema/CreateCommentValidationSchema.ts similarity index 100% rename from src/services/types/CommentSchema/CreateCommentValidationSchema.ts rename to src/services/schema/CommentSchema/CreateCommentValidationSchema.ts diff --git a/src/services/types/ImageSchema/ImageMetadataValidationSchema.ts b/src/services/schema/ImageSchema/ImageMetadataValidationSchema.ts similarity index 100% rename from src/services/types/ImageSchema/ImageMetadataValidationSchema.ts rename to src/services/schema/ImageSchema/ImageMetadataValidationSchema.ts diff --git a/src/services/types/ImageSchema/UploadImageValidationSchema.ts b/src/services/schema/ImageSchema/UploadImageValidationSchema.ts similarity index 100% rename from src/services/types/ImageSchema/UploadImageValidationSchema.ts rename to src/services/schema/ImageSchema/UploadImageValidationSchema.ts