From 7c4a4bde80f49c628af5abb6bcf6d1af23bdc1b2 Mon Sep 17 00:00:00 2001 From: Aaron William Po Date: Wed, 27 Dec 2023 20:42:37 -0500 Subject: [PATCH] Refactor: update beer post api requests --- src/components/CreateBeerPostForm.tsx | 25 +++- src/components/EditBeerPostForm.tsx | 19 ++- src/controllers/images/beer-images/index.ts | 2 +- .../images/brewery-images/index.ts | 2 +- src/controllers/images/types/index.ts | 2 +- src/controllers/posts/breweries/index.ts | 12 +- .../posts/breweries/types/index.ts | 2 +- .../posts/beer-post/deleteBeerPostRequest.ts | 29 ---- src/requests/posts/beer-post/index.ts | 134 ++++++++++++++++++ .../beer-post/sendCreateBeerPostRequest.ts | 67 --------- .../beer-post/sendEditBeerPostRequest.ts | 42 ------ src/requests/posts/beer-post/types/index.ts | 31 ++++ 12 files changed, 208 insertions(+), 159 deletions(-) delete mode 100644 src/requests/posts/beer-post/deleteBeerPostRequest.ts create mode 100644 src/requests/posts/beer-post/index.ts delete mode 100644 src/requests/posts/beer-post/sendCreateBeerPostRequest.ts delete mode 100644 src/requests/posts/beer-post/sendEditBeerPostRequest.ts create mode 100644 src/requests/posts/beer-post/types/index.ts diff --git a/src/components/CreateBeerPostForm.tsx b/src/components/CreateBeerPostForm.tsx index 42bea2e..3b21043 100644 --- a/src/components/CreateBeerPostForm.tsx +++ b/src/components/CreateBeerPostForm.tsx @@ -1,18 +1,20 @@ +import { FunctionComponent } from 'react'; +import router from 'next/router'; import { zodResolver } from '@hookform/resolvers/zod'; import { BeerStyle } from '@prisma/client'; -import router from 'next/router'; -import { FunctionComponent } from 'react'; +import toast from 'react-hot-toast'; import { useForm, SubmitHandler, FieldError } from 'react-hook-form'; import { z } from 'zod'; + import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; import CreateBeerPostValidationSchema from '@/services/posts/beer-post/schema/CreateBeerPostValidationSchema'; -import sendCreateBeerPostRequest from '@/requests/posts/beer-post/sendCreateBeerPostRequest'; import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema'; -import sendUploadBeerImagesRequest from '@/requests/images/beer-image/sendUploadBeerImageRequest'; - -import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; + +import { sendCreateBeerPostRequest } from '@/requests/posts/beer-post'; +import sendUploadBeerImagesRequest from '@/requests/images/beer-image/sendUploadBeerImageRequest'; + import Button from './ui/forms/Button'; import FormError from './ui/forms/FormError'; import FormInfo from './ui/forms/FormInfo'; @@ -53,7 +55,16 @@ const CreateBeerPostForm: FunctionComponent = ({ try { const loadingToast = toast.loading('Creating beer post...'); - const beerPost = await sendCreateBeerPostRequest(data); + const beerPost = await sendCreateBeerPostRequest({ + body: { + name: data.name, + description: data.description, + abv: data.abv, + ibu: data.ibu, + }, + breweryId: data.breweryId, + styleId: data.styleId, + }); await sendUploadBeerImagesRequest({ beerPost, images: data.images }); await router.push(`/beers/${beerPost.id}`); toast.dismiss(loadingToast); diff --git a/src/components/EditBeerPostForm.tsx b/src/components/EditBeerPostForm.tsx index 3f6ed0b..c735de3 100644 --- a/src/components/EditBeerPostForm.tsx +++ b/src/components/EditBeerPostForm.tsx @@ -6,10 +6,13 @@ import { z } from 'zod'; import { useForm, SubmitHandler } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; -import deleteBeerPostRequest from '@/requests/posts/beer-post/deleteBeerPostRequest'; import EditBeerPostValidationSchema from '@/services/posts/beer-post/schema/EditBeerPostValidationSchema'; -import sendEditBeerPostRequest from '@/requests/posts/beer-post/sendEditBeerPostRequest'; + import createErrorToast from '@/util/createErrorToast'; +import { + sendEditBeerPostRequest, + sendDeleteBeerPostRequest, +} from '@/requests/posts/beer-post'; import Button from './ui/forms/Button'; import FormError from './ui/forms/FormError'; import FormInfo from './ui/forms/FormInfo'; @@ -35,7 +38,15 @@ const EditBeerPostForm: FC = ({ previousValues }) => { const onSubmit: SubmitHandler = async (data) => { try { const loadingToast = toast.loading('Editing beer post...'); - await sendEditBeerPostRequest(data); + await sendEditBeerPostRequest({ + beerPostId: data.id, + body: { + name: data.name, + abv: data.abv, + ibu: data.ibu, + description: data.description, + }, + }); await router.push(`/beers/${data.id}`); toast.success('Edited beer post.'); toast.dismiss(loadingToast); @@ -48,7 +59,7 @@ const EditBeerPostForm: FC = ({ previousValues }) => { const onDelete = async () => { try { const loadingToast = toast.loading('Deleting beer post...'); - await deleteBeerPostRequest(previousValues.id); + await sendDeleteBeerPostRequest({ beerPostId: previousValues.id }); toast.dismiss(loadingToast); await router.push('/beers'); toast.success('Deleted beer post.'); diff --git a/src/controllers/images/beer-images/index.ts b/src/controllers/images/beer-images/index.ts index 0a1d5c1..bc6a003 100644 --- a/src/controllers/images/beer-images/index.ts +++ b/src/controllers/images/beer-images/index.ts @@ -20,7 +20,7 @@ export const processBeerImageData = async ( } const beerImages = await addBeerImagesService({ - beerPostId: req.query.id, + beerPostId: req.query.postId, userId: user!.id, body, files, diff --git a/src/controllers/images/brewery-images/index.ts b/src/controllers/images/brewery-images/index.ts index a7a4a3c..24453d6 100644 --- a/src/controllers/images/brewery-images/index.ts +++ b/src/controllers/images/brewery-images/index.ts @@ -18,7 +18,7 @@ export const processBreweryImageData = async ( } const breweryImages = await addBreweryImagesService({ - breweryPostId: req.query.id, + breweryPostId: req.query.postId, userId: user!.id, body, files, diff --git a/src/controllers/images/types/index.ts b/src/controllers/images/types/index.ts index 8d4b308..d79a389 100644 --- a/src/controllers/images/types/index.ts +++ b/src/controllers/images/types/index.ts @@ -4,7 +4,7 @@ import { z } from 'zod'; export interface UploadImagesRequest extends UserExtendedNextApiRequest { files?: Express.Multer.File[]; - query: { id: string }; + query: { postId: string }; body: z.infer; } diff --git a/src/controllers/posts/breweries/index.ts b/src/controllers/posts/breweries/index.ts index 4e5cdfd..3f1001c 100644 --- a/src/controllers/posts/breweries/index.ts +++ b/src/controllers/posts/breweries/index.ts @@ -167,9 +167,9 @@ export const checkIfBreweryPostOwner = async ( next: NextHandler, ) => { const user = req.user!; - const { id } = req.query; + const { postId } = req.query; - const breweryPost = await getBreweryPostByIdService({ breweryPostId: id }); + const breweryPost = await getBreweryPostByIdService({ breweryPostId: postId }); if (!breweryPost) { throw new ServerError('Brewery post not found', 404); } @@ -187,10 +187,10 @@ export const editBreweryPost = async ( ) => { const { body, - query: { id }, + query: { postId }, } = req; - await updateBreweryPostService({ breweryPostId: id, body }); + await updateBreweryPostService({ breweryPostId: postId, body }); res.status(200).json({ message: 'Brewery post updated successfully', @@ -203,8 +203,8 @@ export const deleteBreweryPost = async ( req: BreweryPostRequest, res: NextApiResponse, ) => { - const { id } = req.query; - const deleted = await deleteBreweryPostService({ breweryPostId: id }); + const { postId } = req.query; + const deleted = await deleteBreweryPostService({ breweryPostId: postId }); if (!deleted) { throw new ServerError('Brewery post not found', 404); diff --git a/src/controllers/posts/breweries/types/index.ts b/src/controllers/posts/breweries/types/index.ts index 85dd30a..2524b36 100644 --- a/src/controllers/posts/breweries/types/index.ts +++ b/src/controllers/posts/breweries/types/index.ts @@ -14,7 +14,7 @@ export interface CreateBreweryPostRequest extends UserExtendedNextApiRequest { } export interface BreweryPostRequest extends UserExtendedNextApiRequest { - query: { id: string }; + query: { postId: string }; } export interface EditBreweryPostRequest extends BreweryPostRequest { diff --git a/src/requests/posts/beer-post/deleteBeerPostRequest.ts b/src/requests/posts/beer-post/deleteBeerPostRequest.ts deleted file mode 100644 index ea3ee3f..0000000 --- a/src/requests/posts/beer-post/deleteBeerPostRequest.ts +++ /dev/null @@ -1,29 +0,0 @@ -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; - -/** - * Sends a DELETE request to the server to delete a beer post with the given ID. - * - * @param id The ID of the beer post to delete. - * @returns A Promise that resolves to the parsed API response. - * @throws An error if the response fails or the API response is invalid. - */ -const deleteBeerPostRequest = async (id: string) => { - const response = await fetch(`/api/beers/${id}`, { - method: 'DELETE', - }); - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('Could not successfully parse the response.'); - } - - return parsed; -}; - -export default deleteBeerPostRequest; diff --git a/src/requests/posts/beer-post/index.ts b/src/requests/posts/beer-post/index.ts new file mode 100644 index 0000000..921bc0b --- /dev/null +++ b/src/requests/posts/beer-post/index.ts @@ -0,0 +1,134 @@ +import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { + SendCreateBeerPostRequest, + SendDeleteBeerPostRequest, + SendEditBeerPostRequest, +} from './types'; + +/** + * Sends a POST request to create a new beer post. + * + * @example + * const beerPost = await sendCreateBeerPostRequest({ + * body: { + * abv: 5.5, + * description: 'A golden delight with a touch of citrus.', + * ibu: 30, + * name: 'Yerb Sunshine Ale', + * }, + * styleId: 'clqmteqxc000008jphoy31wqw', + * breweryId: 'clqmtexfb000108jp3nsg26c6', + * }); + * + * @param data - The data to send in the request. + * @param data.body - The body of the request. + * @param data.body.abv - The ABV of the beer. + * @param data.body.description - The description of the beer. + * @param data.body.ibu - The IBU of the beer. + * @param data.body.name - The name of the beer. + * @param data.styleId - The ID of the style of the beer. + * @param data.breweryId - The ID of the brewery of the beer. + * @returns The created beer post. + * @throws An error if the request fails or the response is invalid. + */ +export const sendCreateBeerPostRequest: SendCreateBeerPostRequest = async ({ + body: { abv, description, ibu, name }, + styleId, + breweryId, +}) => { + const response = await fetch('/api/beers/create', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ abv, description, ibu, name, styleId, breweryId }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Invalid API response'); + } + const { payload, success, message } = parsed.data; + if (!success) { + throw new Error(message); + } + const parsedPayload = BeerPostQueryResult.safeParse(payload); + if (!parsedPayload.success) { + throw new Error('Invalid API response payload'); + } + return parsedPayload.data; +}; + +/** + * Sends a DELETE request to delete a beer post. + * + * @example + * const response = await sendDeleteBeerPostRequest({ + * beerPostId: 'clqmtexfb000108jp3nsg26c6', + * }); + * + * @param args - The arguments to send in the request. + * @param args.beerPostId - The ID of the beer post to delete. + * @returns The response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendDeleteBeerPostRequest: SendDeleteBeerPostRequest = async ({ + beerPostId, +}) => { + const response = await fetch(`/api/beers/${beerPostId}`, { method: 'DELETE' }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Could not successfully parse the response.'); + } + return parsed.data; +}; + +/** + * Sends a PUT request to edit a beer post. + * + * @example + * const response = await sendEditBeerPostRequest({ + * beerPostId: 'clqmtexfb000108jp3nsg26c6', + * body: { + * abv: 5.5, + * description: 'A golden delight with a touch of citrus.', + * ibu: 30, + * name: 'Yerb Sunshine Ale', + * }, + * }); + * + * @param args - The arguments to send in the request. + * @param args.beerPostId - The ID of the beer post to edit. + * @param args.body - The body of the request. + * @param args.body.abv - The ABV of the beer. + * @param args.body.description - The description of the beer. + * @param args.body.ibu - The IBU of the beer. + * @param args.body.name - The name of the beer. + * @returns The response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendEditBeerPostRequest: SendEditBeerPostRequest = async ({ + beerPostId, + body: { abv, description, ibu, name }, +}) => { + const response = await fetch(`/api/beers/${beerPostId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ abv, description, ibu, name }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Invalid API response'); + } + return parsed.data; +}; diff --git a/src/requests/posts/beer-post/sendCreateBeerPostRequest.ts b/src/requests/posts/beer-post/sendCreateBeerPostRequest.ts deleted file mode 100644 index 7e36b1f..0000000 --- a/src/requests/posts/beer-post/sendCreateBeerPostRequest.ts +++ /dev/null @@ -1,67 +0,0 @@ -import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; -import CreateBeerPostValidationSchema from '@/services/posts/beer-post/schema/CreateBeerPostValidationSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -/** - * Sends a POST request to the server to create a new beer post. - * - * @param data Data containing the beer post information to be sent to the server. - * @param abv The alcohol by volume of the beer. - * @param breweryId The ID of the brewery that produces the beer. - * @param description The description of the beer. - * @param ibu The International Bitterness Units of the beer. - * @param name The name of the beer. - * @param styleId The ID of the beer style. - * @returns A Promise that resolves to the created beer post. - * @throws An error if the request fails, the API response is invalid, or the API response - * payload is invalid. - */ -const sendCreateBeerPostRequest = async ({ - abv, - breweryId, - description, - ibu, - name, - styleId, -}: z.infer) => { - const response = await fetch('/api/beers/create', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - abv, - breweryId, - description, - ibu, - name, - styleId, - }), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('Invalid API response'); - } - - const { payload, success, message } = parsed.data; - - if (!success) { - throw new Error(message); - } - - const parsedPayload = BeerPostQueryResult.safeParse(payload); - - if (!parsedPayload.success) { - throw new Error('Invalid API response payload'); - } - - return parsedPayload.data; -}; - -export default sendCreateBeerPostRequest; diff --git a/src/requests/posts/beer-post/sendEditBeerPostRequest.ts b/src/requests/posts/beer-post/sendEditBeerPostRequest.ts deleted file mode 100644 index de58f1d..0000000 --- a/src/requests/posts/beer-post/sendEditBeerPostRequest.ts +++ /dev/null @@ -1,42 +0,0 @@ -import EditBeerPostValidationSchema from '@/services/posts/beer-post/schema/EditBeerPostValidationSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -/** - * Sends a PUT request to the server to update a beer post. - * - * @param data Data containing the updated beer post information to be sent to the server. - * @param data.abv The updated ABV of the beer. - * @param data.description The updated description of the beer. - * @param data.ibu The updated IBU of the beer. - * @param data.id The ID of the beer post to be updated. - * @param data.name The updated name of the beer. - * @param data.styleId The updated style ID of the beer. - * @throws If the response status is not ok or the API response is not successful. - */ -const sendEditBeerPostRequest = async ({ - abv, - description, - ibu, - id, - name, -}: z.infer) => { - const response = await fetch(`/api/beers/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ abv, description, ibu, name, id }), - }); - - if (!response.ok) { - throw new Error(`${response.status}: ${response.statusText}`); - } - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error(parsed.error.message); - } -}; - -export default sendEditBeerPostRequest; diff --git a/src/requests/posts/beer-post/types/index.ts b/src/requests/posts/beer-post/types/index.ts new file mode 100644 index 0000000..0fc1d6b --- /dev/null +++ b/src/requests/posts/beer-post/types/index.ts @@ -0,0 +1,31 @@ +import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +type BeerPostQueryResultT = z.infer; +type APIResponse = z.infer; + +export type SendCreateBeerPostRequest = (data: { + body: { + abv: number; + description: string; + ibu: number; + name: string; + }; + styleId: string; + breweryId: string; +}) => Promise; + +export type SendDeleteBeerPostRequest = (args: { + beerPostId: string; +}) => Promise; + +export type SendEditBeerPostRequest = (args: { + beerPostId: string; + body: { + abv: number; + description: string; + ibu: number; + name: string; + }; +}) => Promise;