refactor brewery post requests

This commit is contained in:
Aaron William Po
2024-02-16 01:56:44 -05:00
parent 7c4a4bde80
commit 9f1d09a61d
8 changed files with 577 additions and 150 deletions

View File

@@ -1,5 +1,5 @@
import sendUploadBreweryImagesRequest from '@/requests/images/brewery-image/sendUploadBreweryImageRequest';
import sendCreateBreweryPostRequest from '@/requests/posts/brewery-post/sendCreateBreweryPostRequest';
import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema';
import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema';
import createErrorToast from '@/util/createErrorToast';
@@ -27,6 +27,7 @@ import FormSegment from '../ui/forms/FormSegment';
import FormTextArea from '../ui/forms/FormTextArea';
import FormTextInput from '../ui/forms/FormTextInput';
import Button from '../ui/forms/Button';
import { sendCreateBreweryPostRequest } from '@/requests/posts/brewery-post';
const AddressAutofill = dynamic(
// @ts-expect-error
@@ -225,7 +226,7 @@ const CreateBreweryPostForm: FC<{
if (!(data.images instanceof FileList)) {
return;
}
const breweryPost = await sendCreateBreweryPostRequest(data);
const breweryPost = await sendCreateBreweryPostRequest({ body: data });
await sendUploadBreweryImagesRequest({ breweryPost, images: data.images });
await router.push(`/breweries/${breweryPost.id}`);
toast.remove(loadingToast);

View File

@@ -0,0 +1,106 @@
import EditBreweryPostValidationSchema from '@/services/posts/brewery-post/schema/EditBreweryPostValidationSchema';
import { zodResolver } from '@hookform/resolvers/zod';
import { useRouter } from 'next/router';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { FC, useState } from 'react';
import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult';
import {
sendDeleteBreweryPostRequest,
sendEditBreweryPostRequest,
} from '@/requests/posts/brewery-post';
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';
interface EditBreweryPostFormProps {
breweryPost: z.infer<typeof BreweryPostQueryResult>;
}
const EditBreweryPostForm: FC<EditBreweryPostFormProps> = ({ breweryPost }) => {
const router = useRouter();
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<z.infer<typeof EditBreweryPostValidationSchema>>({
resolver: zodResolver(EditBreweryPostValidationSchema),
defaultValues: {
name: breweryPost.name,
description: breweryPost.description,
id: breweryPost.id,
dateEstablished: breweryPost.dateEstablished,
},
});
const [isDeleting, setIsDeleting] = useState(false);
const onSubmit = async (data: z.infer<typeof EditBreweryPostValidationSchema>) => {
await sendEditBreweryPostRequest({ breweryPostId: breweryPost.id, body: data });
await router.push(`/breweries/${breweryPost.id}`);
};
const handleDelete = async () => {
setIsDeleting(true);
await sendDeleteBreweryPostRequest({ breweryPostId: breweryPost.id });
await router.push('/breweries');
};
return (
<form className="form-control space-y-4" onSubmit={handleSubmit(onSubmit)}>
<div className="w-full">
<FormInfo>
<FormLabel htmlFor="name">Name</FormLabel>
<FormError>{errors.name?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextInput
id="name"
type="text"
placeholder="Name"
formValidationSchema={register('name')}
error={!!errors.name}
disabled={isSubmitting || isDeleting}
/>
</FormSegment>
<FormInfo>
<FormLabel htmlFor="description">Description</FormLabel>
<FormError>{errors.description?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextArea
disabled={isSubmitting || isDeleting}
placeholder="Ratione cumque quas quia aut impedit ea culpa facere. Ut in sit et quas reiciendis itaque."
error={!!errors.description}
formValidationSchema={register('description')}
id="description"
rows={8}
/>
</FormSegment>
</div>
<div className="w-full space-y-3">
<button
disabled={isSubmitting || isDeleting}
className="btn btn-primary w-full"
type="submit"
>
{isSubmitting ? 'Saving...' : 'Save'}
</button>
<button
className="btn btn-primary w-full"
type="button"
disabled={isSubmitting || isDeleting}
onClick={handleDelete}
>
Delete Brewery
</button>
</div>
</form>
);
};
export default EditBreweryPostForm;

View File

@@ -1,20 +1,11 @@
import FormError from '@/components/ui/forms/FormError';
import FormInfo from '@/components/ui/forms/FormInfo';
import FormLabel from '@/components/ui/forms/FormLabel';
import EditBreweryPostForm from '@/components/EditBreweryPostForm';
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 { getBreweryPostByIdService } from '@/services/posts/brewery-post';
import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult';
import EditBreweryPostValidationSchema from '@/services/posts/brewery-post/schema/EditBreweryPostValidationSchema';
import withPageAuthRequired from '@/util/withPageAuthRequired';
import { zodResolver } from '@hookform/resolvers/zod';
import { NextPage } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { useForm } from 'react-hook-form';
import { BiBeer } from 'react-icons/bi';
import { z } from 'zod';
@@ -25,49 +16,6 @@ interface EditPageProps {
const EditBreweryPostPage: NextPage<EditPageProps> = ({ breweryPost }) => {
const pageTitle = `Edit \u201c${breweryPost.name}\u201d`;
const router = useRouter();
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<z.infer<typeof EditBreweryPostValidationSchema>>({
resolver: zodResolver(EditBreweryPostValidationSchema),
defaultValues: {
name: breweryPost.name,
description: breweryPost.description,
id: breweryPost.id,
dateEstablished: breweryPost.dateEstablished,
},
});
const onSubmit = async (data: z.infer<typeof EditBreweryPostValidationSchema>) => {
const response = await fetch(`/api/breweries/${breweryPost.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error('Something went wrong');
}
router.push(`/breweries/${breweryPost.id}`);
};
const handleDelete = async () => {
const response = await fetch(`/api/breweries/${breweryPost.id}`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error('Something went wrong');
}
router.push('/breweries');
};
return (
<>
<Head>
@@ -81,59 +29,7 @@ const EditBreweryPostPage: NextPage<EditPageProps> = ({ breweryPost }) => {
backLink={`/breweries/${breweryPost.id}`}
backLinkText={`Back to "${breweryPost.name}"`}
>
<>
<form className="form-control space-y-4" onSubmit={handleSubmit(onSubmit)}>
<div className="w-full">
<FormInfo>
<FormLabel htmlFor="name">Name</FormLabel>
<FormError>{errors.name?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextInput
id="name"
type="text"
placeholder="Name"
formValidationSchema={register('name')}
error={!!errors.name}
disabled={isSubmitting}
/>
</FormSegment>
<FormInfo>
<FormLabel htmlFor="description">Description</FormLabel>
<FormError>{errors.description?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextArea
disabled={isSubmitting}
placeholder="Ratione cumque quas quia aut impedit ea culpa facere. Ut in sit et quas reiciendis itaque."
error={!!errors.description}
formValidationSchema={register('description')}
id="description"
rows={8}
/>
</FormSegment>
</div>
<div className="w-full space-y-3">
<button
disabled={isSubmitting}
className="btn btn-primary w-full"
type="submit"
>
{isSubmitting ? 'Saving...' : 'Save'}
</button>
<button
className="btn btn-primary w-full"
type="button"
onClick={handleDelete}
>
Delete Brewery
</button>
</div>
</form>
</>
<EditBreweryPostForm breweryPost={breweryPost} />
</FormPageLayout>
</>
);

View File

@@ -0,0 +1,105 @@
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult';
import {
SendEditBreweryPostRequest,
SendDeleteBreweryPostRequest,
SendCreateBreweryPostRequest,
} from './types';
/**
* Sends an api request to edit a brewery post.
*
* @param args - The arguments for the request.
* @param args.body - The body of the request.
* @param args.body.name - The name of the brewery.
* @param args.body.description - The description of the brewery.
* @param args.body.dateEstablished - The date the brewery was established.
* @param args.breweryPostId - The id of the brewery post to edit.
*/
export const sendEditBreweryPostRequest: SendEditBreweryPostRequest = async ({
body,
breweryPostId,
}) => {
const response = await fetch(`/api/breweries/${breweryPostId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error('Something went wrong');
}
const json = await response.json();
const parsed = APIResponseValidationSchema.safeParse(json);
if (!parsed.success) {
throw new Error('Something went wrong');
}
return parsed.data;
};
/**
* Sends an api request to delete a brewery post.
*
* @param args - The arguments for the request.
* @param args.breweryPostId - The id of the brewery post to delete.
*/
export const sendDeleteBreweryPostRequest: SendDeleteBreweryPostRequest = async ({
breweryPostId,
}) => {
const response = await fetch(`/api/breweries/${breweryPostId}`, {
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(parsed.error.message);
}
return parsed.data;
};
/**
* Sends an api request to create a brewery post.
*
* @param args - The arguments for the request.
* @param args.body - The body of the request.
* @param args.body.name - The name of the brewery.
* @param args.body.description - The description of the brewery.
* @param args.body.dateEstablished - The date the brewery was established.
*/
export const sendCreateBreweryPostRequest: SendCreateBreweryPostRequest = async ({
body,
}) => {
const response = await fetch('/api/breweries/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
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;
};

View File

@@ -1,34 +0,0 @@
import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult';
import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { z } from 'zod';
const sendCreateBreweryPostRequest = async (
data: z.infer<typeof CreateBreweryPostSchema>,
) => {
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;

View File

@@ -0,0 +1,23 @@
import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult';
import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { z } from 'zod';
type APIResponse = z.infer<typeof APIResponseValidationSchema>;
export type SendDeleteBreweryPostRequest = (args: {
breweryPostId: string;
}) => Promise<APIResponse>;
export type SendEditBreweryPostRequest = (args: {
body: {
name: string;
description: string;
dateEstablished: Date;
};
breweryPostId: string;
}) => Promise<APIResponse>;
export type SendCreateBreweryPostRequest = (args: {
body: z.infer<typeof CreateBreweryPostSchema>;
}) => Promise<z.infer<typeof BreweryPostQueryResult>>;