mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Update: beer post form now connected to a specific brewery.
This commit eliminates the brewery selector in the create beer post form, and reroutes the form page to /breweries/[id]/beers/create. This commit also introduces the use of turbopack for `next dev`.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev --turbo",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Link from 'next/link';
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { useInView } from 'react-intersection-observer';
|
import { useInView } from 'react-intersection-observer';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { FaPlus } from 'react-icons/fa';
|
||||||
import BeerRecommendationLoadingComponent from '../BeerById/BeerRecommendationLoadingComponent';
|
import BeerRecommendationLoadingComponent from '../BeerById/BeerRecommendationLoadingComponent';
|
||||||
|
|
||||||
interface BreweryCommentsSectionProps {
|
interface BreweryCommentsSectionProps {
|
||||||
@@ -31,7 +32,21 @@ const BreweryBeersSection: FC<BreweryCommentsSectionProps> = ({ breweryPost }) =
|
|||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<>
|
<>
|
||||||
<h3 className="text-2xl font-bold">Brews</h3>
|
<div className="my-2 flex flex-row items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-3xl font-bold">Brews</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Link
|
||||||
|
className={`btn-ghost btn-sm btn gap-2 rounded-2xl outline`}
|
||||||
|
href={`/breweries/${breweryPost.id}/beers/create`}
|
||||||
|
>
|
||||||
|
<FaPlus className="text-xl" />
|
||||||
|
Add Beer
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{!!beerPosts.length && (
|
{!!beerPosts.length && (
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{beerPosts.map((beerPost, index) => {
|
{beerPosts.map((beerPost, index) => {
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import useTimeDistance from '@/hooks/utilities/useTimeDistance';
|
|||||||
import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult';
|
import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { FC, useContext } from 'react';
|
import { FC, useContext } from 'react';
|
||||||
import { Link } from 'react-daisyui';
|
|
||||||
import { FaRegEdit } from 'react-icons/fa';
|
import { FaRegEdit } from 'react-icons/fa';
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import Link from 'next/link';
|
||||||
import BreweryPostLikeButton from '../BreweryIndex/BreweryPostLikeButton';
|
import BreweryPostLikeButton from '../BreweryIndex/BreweryPostLikeButton';
|
||||||
|
|
||||||
interface BreweryInfoHeaderProps {
|
interface BreweryInfoHeaderProps {
|
||||||
@@ -26,7 +28,8 @@ const BreweryInfoHeader: FC<BreweryInfoHeaderProps> = ({ breweryPost }) => {
|
|||||||
<article className="card flex flex-col justify-center bg-base-300">
|
<article className="card flex flex-col justify-center bg-base-300">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<header className="flex justify-between">
|
<header className="flex justify-between">
|
||||||
<div className="space-y-2">
|
<div className="w-full space-y-2">
|
||||||
|
<div className="flex w-full flex-row justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold lg:text-4xl">{breweryPost.name}</h1>
|
<h1 className="text-2xl font-bold lg:text-4xl">{breweryPost.name}</h1>
|
||||||
<h2 className="text-lg font-semibold lg:text-2xl">
|
<h2 className="text-lg font-semibold lg:text-2xl">
|
||||||
@@ -36,6 +39,8 @@ const BreweryInfoHeader: FC<BreweryInfoHeaderProps> = ({ breweryPost }) => {
|
|||||||
}`}
|
}`}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="italic">
|
<h3 className="italic">
|
||||||
{' posted by '}
|
{' posted by '}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import FormTextArea from './ui/forms/FormTextArea';
|
|||||||
import FormTextInput from './ui/forms/FormTextInput';
|
import FormTextInput from './ui/forms/FormTextInput';
|
||||||
|
|
||||||
interface BeerFormProps {
|
interface BeerFormProps {
|
||||||
breweries: z.infer<typeof BreweryPostQueryResult>[];
|
brewery: z.infer<typeof BreweryPostQueryResult>;
|
||||||
types: BeerType[];
|
types: BeerType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,13 +29,14 @@ const CreateBeerPostWithImagesValidationSchema = CreateBeerPostValidationSchema.
|
|||||||
);
|
);
|
||||||
|
|
||||||
const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
||||||
breweries = [],
|
|
||||||
types = [],
|
types = [],
|
||||||
|
brewery,
|
||||||
}) => {
|
}) => {
|
||||||
const { register, handleSubmit, formState } = useForm<
|
const { register, handleSubmit, formState } = useForm<
|
||||||
z.infer<typeof CreateBeerPostWithImagesValidationSchema>
|
z.infer<typeof CreateBeerPostWithImagesValidationSchema>
|
||||||
>({
|
>({
|
||||||
resolver: zodResolver(CreateBeerPostWithImagesValidationSchema),
|
resolver: zodResolver(CreateBeerPostWithImagesValidationSchema),
|
||||||
|
defaultValues: { breweryId: brewery.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { errors, isSubmitting } = formState;
|
const { errors, isSubmitting } = formState;
|
||||||
@@ -48,23 +49,9 @@ const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { breweryId, typeId, name, abv, ibu, description } = data;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await sendCreateBeerPostRequest({
|
const response = await sendCreateBeerPostRequest(data);
|
||||||
breweryId,
|
await sendUploadBeerImagesRequest({ beerPost: response, images: data.images });
|
||||||
typeId,
|
|
||||||
name,
|
|
||||||
abv,
|
|
||||||
ibu,
|
|
||||||
description,
|
|
||||||
});
|
|
||||||
|
|
||||||
await sendUploadBeerImagesRequest({
|
|
||||||
beerPost: response,
|
|
||||||
images: data.images,
|
|
||||||
});
|
|
||||||
|
|
||||||
router.push(`/beers/${response.id}`);
|
router.push(`/beers/${response.id}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof Error)) {
|
if (!(e instanceof Error)) {
|
||||||
@@ -93,28 +80,6 @@ const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
|||||||
/>
|
/>
|
||||||
</FormSegment>
|
</FormSegment>
|
||||||
|
|
||||||
<div className="flex flex-wrap">
|
|
||||||
<div className="mb-2 w-full md:mb-0 md:w-1/2 md:pr-3">
|
|
||||||
<FormInfo>
|
|
||||||
<FormLabel htmlFor="breweryId">Brewery</FormLabel>
|
|
||||||
<FormError>{errors.breweryId?.message}</FormError>
|
|
||||||
</FormInfo>
|
|
||||||
<FormSegment>
|
|
||||||
<FormSelect
|
|
||||||
disabled={isSubmitting}
|
|
||||||
formRegister={register('breweryId')}
|
|
||||||
error={!!errors.breweryId}
|
|
||||||
id="breweryId"
|
|
||||||
options={breweries.map((brewery) => ({
|
|
||||||
value: brewery.id,
|
|
||||||
text: brewery.name,
|
|
||||||
}))}
|
|
||||||
placeholder="Brewery"
|
|
||||||
message="Pick a brewery"
|
|
||||||
/>
|
|
||||||
</FormSegment>
|
|
||||||
</div>
|
|
||||||
<div className="mb-2 w-full md:mb-0 md:w-1/2 md:pl-3">
|
|
||||||
<FormInfo>
|
<FormInfo>
|
||||||
<FormLabel htmlFor="typeId">Type</FormLabel>
|
<FormLabel htmlFor="typeId">Type</FormLabel>
|
||||||
<FormError>{errors.typeId?.message}</FormError>
|
<FormError>{errors.typeId?.message}</FormError>
|
||||||
@@ -133,8 +98,6 @@ const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
|||||||
message="Pick a beer type"
|
message="Pick a beer type"
|
||||||
/>
|
/>
|
||||||
</FormSegment>
|
</FormSegment>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-wrap md:mb-3">
|
<div className="flex flex-wrap md:mb-3">
|
||||||
<div className="mb-2 w-full md:mb-0 md:w-1/2 md:pr-3">
|
<div className="mb-2 w-full md:mb-0 md:w-1/2 md:pr-3">
|
||||||
@@ -192,6 +155,7 @@ const CreateBeerPostForm: FunctionComponent<BeerFormProps> = ({
|
|||||||
{...register('images')}
|
{...register('images')}
|
||||||
multiple
|
multiple
|
||||||
className="file-input-bordered file-input w-full"
|
className="file-input-bordered file-input w-full"
|
||||||
|
disabled={isSubmitting}
|
||||||
/>
|
/>
|
||||||
</FormSegment>
|
</FormSegment>
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ const useNavbar = () => {
|
|||||||
|
|
||||||
/** These pages are accessible to both authenticated and unauthenticated users. */
|
/** These pages are accessible to both authenticated and unauthenticated users. */
|
||||||
const otherPages: readonly Page[] = [
|
const otherPages: readonly Page[] = [
|
||||||
{ slug: '/beers', name: 'Beers' },
|
|
||||||
{ slug: '/breweries', name: 'Breweries' },
|
{ slug: '/breweries', name: 'Breweries' },
|
||||||
|
{ slug: '/beers', name: 'Beers' },
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -47,16 +47,6 @@ const BeerPage: NextPage = () => {
|
|||||||
<h1 className="text-4xl font-bold lg:text-6xl">The Biergarten App</h1>
|
<h1 className="text-4xl font-bold lg:text-6xl">The Biergarten App</h1>
|
||||||
<h2 className="text-2xl font-bold lg:text-4xl">Beers</h2>
|
<h2 className="text-2xl font-bold lg:text-4xl">Beers</h2>
|
||||||
</div>
|
</div>
|
||||||
{!!user && (
|
|
||||||
<div
|
|
||||||
className="tooltip tooltip-left h-full"
|
|
||||||
data-tip="Create a new beer post"
|
|
||||||
>
|
|
||||||
<Link href="/beers/create" className="btn-ghost btn-sm btn">
|
|
||||||
<FaPlus />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</header>
|
</header>
|
||||||
<div className="grid gap-6 xl:grid-cols-2">
|
<div className="grid gap-6 xl:grid-cols-2">
|
||||||
{!!beerPosts.length && !isLoading && (
|
{!!beerPosts.length && !isLoading && (
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ import FormPageLayout from '@/components/ui/forms/FormPageLayout';
|
|||||||
|
|
||||||
import withPageAuthRequired from '@/util/withPageAuthRequired';
|
import withPageAuthRequired from '@/util/withPageAuthRequired';
|
||||||
import DBClient from '@/prisma/DBClient';
|
import DBClient from '@/prisma/DBClient';
|
||||||
import getAllBreweryPosts from '@/services/BreweryPost/getAllBreweryPosts';
|
|
||||||
import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult';
|
import BreweryPostQueryResult from '@/services/BreweryPost/types/BreweryPostQueryResult';
|
||||||
import { BeerType } from '@prisma/client';
|
import { BeerType } from '@prisma/client';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import { BiBeer } from 'react-icons/bi';
|
import { BiBeer } from 'react-icons/bi';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import getBreweryPostById from '@/services/BreweryPost/getBreweryPostById';
|
||||||
|
|
||||||
interface CreateBeerPageProps {
|
interface CreateBeerPageProps {
|
||||||
breweries: z.infer<typeof BreweryPostQueryResult>[];
|
brewery: z.infer<typeof BreweryPostQueryResult>;
|
||||||
types: BeerType[];
|
types: BeerType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateBeerPost: NextPage<CreateBeerPageProps> = ({ breweries, types }) => {
|
const CreateBeerPost: NextPage<CreateBeerPageProps> = ({ brewery, types }) => {
|
||||||
return (
|
return (
|
||||||
<FormPageLayout
|
<FormPageLayout
|
||||||
headingText="Create a new beer"
|
headingText="Create a new beer"
|
||||||
@@ -23,21 +23,26 @@ const CreateBeerPost: NextPage<CreateBeerPageProps> = ({ breweries, types }) =>
|
|||||||
backLink="/beers"
|
backLink="/beers"
|
||||||
backLinkText="Back to beers"
|
backLinkText="Back to beers"
|
||||||
>
|
>
|
||||||
<CreateBeerPostForm breweries={breweries} types={types} />
|
<CreateBeerPostForm brewery={brewery} types={types} />
|
||||||
</FormPageLayout>
|
</FormPageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getServerSideProps = withPageAuthRequired<CreateBeerPageProps>(async () => {
|
export const getServerSideProps = withPageAuthRequired<CreateBeerPageProps>(
|
||||||
const breweryPosts = await getAllBreweryPosts();
|
async (context) => {
|
||||||
|
const id = context.params?.id as string;
|
||||||
|
|
||||||
|
const breweryPost = await getBreweryPostById(id);
|
||||||
|
|
||||||
const beerTypes = await DBClient.instance.beerType.findMany();
|
const beerTypes = await DBClient.instance.beerType.findMany();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
breweries: JSON.parse(JSON.stringify(breweryPosts)),
|
brewery: JSON.parse(JSON.stringify(breweryPost)),
|
||||||
types: JSON.parse(JSON.stringify(beerTypes)),
|
types: JSON.parse(JSON.stringify(beerTypes)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export default CreateBeerPost;
|
export default CreateBeerPost;
|
||||||
Reference in New Issue
Block a user