Did more work to beer post page, seed

Worked on comments and beer recs features. Fine tuning database seed amounts.
This commit is contained in:
Aaron William Po
2023-01-29 21:53:05 -05:00
parent fe277d5964
commit 0b96c8f1f5
38 changed files with 833 additions and 221 deletions

17
pages/404.tsx Normal file
View File

@@ -0,0 +1,17 @@
// create a 404 next js page using tailwind
import Layout from '@/components/ui/Layout';
import { NextPage } from 'next';
const NotFound: NextPage = () => {
return (
<Layout>
<div className="flex h-full flex-col items-center justify-center space-y-4">
<h1 className="text-7xl font-bold">Error: 404</h1>
<h2 className="text-xl font-bold">Page Not Found</h2>
</div>
</Layout>
);
};
export default NotFound;

View File

@@ -0,0 +1,74 @@
import DBClient from '@/prisma/DBClient';
import { NextApiHandler } from 'next';
import { z } from 'zod';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import ServerError from '@/config/util/ServerError';
import BeerCommentValidationSchema from '@/validation/CreateBeerCommentValidationSchema';
const handler: NextApiHandler<z.infer<typeof APIResponseValidationSchema>> = async (
req,
res,
) => {
try {
const { method } = req;
if (method !== 'POST') {
throw new ServerError('Method not allowed', 405);
}
const cleanedReqBody = BeerCommentValidationSchema.safeParse(req.body);
if (!cleanedReqBody.success) {
throw new ServerError('Invalid request body', 400);
}
const user = await DBClient.instance.user.findFirstOrThrow();
const { content, rating, beerPostId } = cleanedReqBody.data;
const newBeerComment = await DBClient.instance.beerComment.create({
data: {
content,
rating,
beerPost: { connect: { id: beerPostId } },
postedBy: { connect: { id: user.id } },
},
select: {
id: true,
content: true,
rating: true,
postedBy: {
select: {
id: true,
username: true,
},
},
createdAt: true,
},
});
res.status(201).json({
message: 'Beer comment created successfully',
statusCode: 201,
payload: newBeerComment.id,
success: true,
});
} catch (error) {
if (error instanceof ServerError) {
res.status(error.statusCode).json({
message: error.message,
statusCode: error.statusCode,
payload: null,
success: false,
});
} else {
res.status(500).json({
message: 'Internal server error',
statusCode: 500,
payload: null,
success: false,
});
}
}
};
export default handler;

View File

@@ -1,16 +1,10 @@
import BeerPostValidationSchema from '@/validation/BeerPostValidationSchema';
import BeerPostValidationSchema from '@/validation/CreateBeerPostValidationSchema';
import DBClient from '@/prisma/DBClient';
import { NextApiHandler } from 'next';
import { z } from 'zod';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
class ServerError extends Error {
constructor(message: string, public statusCode: number) {
super(message);
this.name = 'ServerError';
}
}
import ServerError from '@/config/util/ServerError';
const handler: NextApiHandler<z.infer<typeof APIResponseValidationSchema>> = async (
req,

View File

@@ -7,12 +7,37 @@ import Head from 'next/head';
import Image from 'next/image';
import BeerInfoHeader from '@/components/BeerById/BeerInfoHeader';
import CommentCard from '@/components/BeerById/CommentCard';
import { useState } from 'react';
import { BeerPost } from '@prisma/client';
import BeerCommentQueryResult from '@/services/BeerPost/types/BeerCommentQueryResult';
import BeerCommentForm from '../../components/BeerById/BeerCommentForm';
import BeerRecommendations from '../../components/BeerById/BeerRecommendations';
import getBeerRecommendations from '../../services/BeerPost/getBeerRecommendations';
import getAllBeerComments from '../../services/BeerPost/getAllBeerComments';
interface BeerPageProps {
beerPost: BeerPostQueryResult;
beerRecommendations: (BeerPost & {
brewery: {
id: string;
name: string;
};
beerImages: {
id: string;
alt: string;
url: string;
}[];
})[];
beerComments: BeerCommentQueryResult[];
}
const BeerByIdPage: NextPage<BeerPageProps> = ({ beerPost }) => {
const BeerByIdPage: NextPage<BeerPageProps> = ({
beerPost,
beerRecommendations,
beerComments,
}) => {
const [comments, setComments] = useState(beerComments);
return (
<Layout>
<Head>
@@ -24,6 +49,8 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({ beerPost }) => {
<Image
alt={beerPost.beerImages[0].alt}
src={beerPost.beerImages[0].url}
height={1080}
width={1920}
className="h-[42rem] w-full object-cover"
/>
)}
@@ -33,15 +60,19 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({ beerPost }) => {
<BeerInfoHeader beerPost={beerPost} />
<div className="mt-4 flex space-x-3">
<div className="w-[60%] space-y-3">
<div className="card h-[22rem] bg-base-300"></div>
<div className="card h-[44rem] overflow-y-auto bg-base-300">
{beerPost.beerComments.map((comment) => (
<div className="card h-96 bg-base-300">
<div className="card-body">
<BeerCommentForm beerPost={beerPost} setComments={setComments} />
</div>
</div>
<div className="card bg-base-300">
{comments.map((comment) => (
<CommentCard key={comment.id} comment={comment} />
))}
</div>
</div>
<div className="w-[40%]">
<div className="card h-full bg-base-300"></div>
<BeerRecommendations beerRecommendations={beerRecommendations} />
</div>
</div>
</div>
@@ -53,9 +84,22 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({ beerPost }) => {
export const getServerSideProps: GetServerSideProps<BeerPageProps> = async (context) => {
const beerPost = await getBeerPostById(context.params!.id! as string);
return !beerPost
? { notFound: true }
: { props: { beerPost: JSON.parse(JSON.stringify(beerPost)) } };
if (!beerPost) {
return { notFound: true };
}
const { type, brewery, id } = beerPost;
const beerComments = await getAllBeerComments({ id }, { pageSize: 3, pageNum: 1 });
const beerRecommendations = await getBeerRecommendations({ type, brewery });
const props = {
beerPost: JSON.parse(JSON.stringify(beerPost)),
beerRecommendations: JSON.parse(JSON.stringify(beerRecommendations)),
beerComments: JSON.parse(JSON.stringify(beerComments)),
};
return { props };
};
export default BeerByIdPage;

View File

@@ -21,13 +21,15 @@ const BeerPage: NextPage<BeerPageProps> = ({ initialBeerPosts, pageCount }) => {
return (
<Layout>
<div className="flex items-center justify-center bg-base-100">
<main className="mt-10 flex w-10/12 flex-col space-y-4">
<main className="my-10 flex w-10/12 flex-col space-y-4">
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
{initialBeerPosts.map((post) => {
return <BeerCard post={post} key={post.id} />;
})}
</div>
<Pagination pageNum={pageNum} pageCount={pageCount} />
<div className="flex justify-center">
<Pagination pageNum={pageNum} pageCount={pageCount} />
</div>
</main>
</div>
</Layout>

View File

@@ -1,7 +1,12 @@
import Layout from '@/components/ui/Layout';
import { NextPage } from 'next';
const Home: NextPage = () => {
return <h1 className="text-3xl font-bold underline">Hello world!</h1>;
return (
<Layout>
<div></div>
</Layout>
);
};
export default Home;