Update page auth HOF type definitions

Added vercel config, update packages
This commit is contained in:
Aaron William Po
2023-02-25 19:17:49 -05:00
parent 6f604b9768
commit 11b3304c54
12 changed files with 841 additions and 3429 deletions

View File

@@ -5,6 +5,7 @@ import { FC, useContext, useEffect, useState } from 'react';
import { BeerPostQueryResult } from '@/services/BeerPost/schema/BeerPostQueryResult';
import UserContext from '@/contexts/userContext';
import { FaRegEdit } from 'react-icons/fa';
import BeerPostLikeButton from './BeerPostLikeButton';
const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: number }> = ({
@@ -16,6 +17,18 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
const { user } = useContext(UserContext);
const [likeCount, setLikeCount] = useState(initialLikeCount);
const [isPostOwner, setIsPostOwner] = useState(false);
useEffect(() => {
const idMatches = user && beerPost.postedBy.id === user.id;
if (!(user && idMatches)) {
setIsPostOwner(false);
return;
}
setIsPostOwner(true);
}, [user, beerPost]);
useEffect(() => {
setLikeCount(initialLikeCount);
@@ -28,6 +41,8 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
return (
<div className="card flex flex-col justify-center bg-base-300">
<div className="card-body">
<div className="flex justify-between">
<div>
<h1 className="text-4xl font-bold">{beerPost.name}</h1>
<h2 className="text-2xl font-semibold">
by{' '}
@@ -38,6 +53,19 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
{beerPost.brewery.name}
</Link>
</h2>
</div>
<div>
{isPostOwner && (
<Link
className="btn-outline btn-sm btn gap-2 rounded-2xl"
href={`/beers/${beerPost.id}/edit`}
>
<FaRegEdit className="text-xl" />
Edit
</Link>
)}
</div>
</div>
<h3 className="italic">
posted by{' '}
@@ -53,7 +81,7 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
</h3>
<p>{beerPost.description}</p>
<div className="mt-5 flex justify-between">
<div className="flex justify-between">
<div className="space-y-1">
<div>
<Link

View File

@@ -161,6 +161,8 @@ const BeerForm: FunctionComponent<BeerFormProps> = ({
/>
</FormSegment>
{formType === 'create' && types.length && (
<>
<FormInfo>
<FormLabel htmlFor="typeId">Type</FormLabel>
<FormError>{errors.typeId?.message}</FormError>
@@ -179,6 +181,8 @@ const BeerForm: FunctionComponent<BeerFormProps> = ({
message="Pick a beer type"
/>
</FormSegment>
</>
)}
{!isSubmitting && (
<Button type="submit" isSubmitting={isSubmitting}>{`${

View File

@@ -1,24 +1,32 @@
import { GetServerSideProps, GetServerSidePropsContext } from 'next';
import { GetServerSidePropsContext, GetServerSidePropsResult, PreviewData } from 'next';
import { ParsedUrlQuery } from 'querystring';
import { getLoginSession } from './session';
export type ExtendedGetServerSideProps<
P extends { [key: string]: any } = { [key: string]: any },
Q extends ParsedUrlQuery = ParsedUrlQuery,
D extends PreviewData = PreviewData,
> = (
context: GetServerSidePropsContext<Q, D>,
session: Awaited<ReturnType<typeof getLoginSession>>,
) => Promise<GetServerSidePropsResult<P>>;
const withPageAuthRequired =
(fn?: GetServerSideProps) => async (context: GetServerSidePropsContext) => {
<P extends { [key: string]: any } = { [key: string]: any }>(
fn?: ExtendedGetServerSideProps<P>,
) =>
async (context: GetServerSidePropsContext) => {
try {
const { req } = context;
await getLoginSession(req);
const session = await getLoginSession(req);
if (!fn) {
return { props: {} };
}
return await fn(context);
return await fn(context, session);
} catch (error) {
console.log(error);
return {
redirect: {
destination: '/login',
permanent: false,
},
};
return { redirect: { destination: '/login', permanent: false } };
}
};

View File

@@ -12,7 +12,6 @@ const useUser = () => {
const response = await fetch(url);
if (!response.ok) {
document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
throw new Error(response.statusText);
}

4040
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,59 +10,55 @@
"format": "npx prettier . --write",
"prestart": "npm run build",
"prismaDev": "dotenv -e .env.local prisma migrate dev",
"vercel-build": "DISABLE_ERD=true npx prisma generate && npx prisma migrate deploy && next build",
"seed": "npx ts-node ./prisma/seed/index.ts"
},
"dependencies": {
"@hapi/iron": "7.0.0",
"@hapi/iron": "^7.0.1",
"@hookform/resolvers": "^2.9.10",
"@next/font": "13.1.6",
"@prisma/client": "^4.9.0",
"@prisma/client": "^4.10.1",
"argon2": "^0.30.3",
"cloudinary": "^1.33.0",
"cloudinary": "^1.34.0",
"cookie": "0.5.0",
"date-fns": "^2.29.3",
"multer": "^1.4.5-lts.1",
"multer": "^2.0.0-rc.4",
"multer-storage-cloudinary": "^4.0.0",
"next": "13.1.6",
"next": "^13.2.1",
"next-connect": "^1.0.0-next.3",
"passport": "^0.6.0",
"passport-local": "^1.0.0",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"pino": "^8.11.0",
"pino-pretty": "^9.3.0",
"react": "18.2.0",
"react-daisyui": "^3.0.2",
"react-daisyui": "^3.0.3",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.0",
"react-hook-form": "^7.43.2",
"react-icons": "^4.7.1",
"swr": "^2.0.3",
"zod": "^3.20.2"
"zod": "^3.20.6"
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"@mermaid-js/mermaid-cli": "^9.3.0",
"@types/cookie": "^0.5.1",
"@types/multer": "^1.4.7",
"@types/node": "^18.13.0",
"@types/node": "^18.14.1",
"@types/passport-local": "^1.0.35",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"autoprefixer": "^10.4.13",
"daisyui": "^2.50.0",
"daisyui": "^2.51.0",
"dotenv-cli": "^7.0.0",
"eslint": "8.33.0",
"eslint": "^8.34.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "17.0.0",
"eslint-config-next": "^13.1.6",
"eslint-config-next": "^13.2.1",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-react": "^7.32.2",
"postcss": "^8.4.21",
"prettier": "^2.8.3",
"prettier-plugin-jsdoc": "^0.4.2",
"prettier-plugin-tailwindcss": "^0.2.2",
"prisma": "^4.9.0",
"prisma-erd-generator": "^1.2.5",
"tailwindcss": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.2.3",
"prisma": "^4.10.1",
"tailwindcss": "^3.2.7",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
}

51
pages/beers/[id]/edit.tsx Normal file
View File

@@ -0,0 +1,51 @@
import Head from 'next/head';
import React from 'react';
import Layout from '@/components/ui/Layout';
import { NextPage } from 'next';
import withPageAuthRequired from '@/config/auth/withPageAuthRequired';
import getBeerPostById from '@/services/BeerPost/getBeerPostById';
import { BeerPostQueryResult } from '@/services/BeerPost/schema/BeerPostQueryResult';
interface EditPageProps {
beerPost: BeerPostQueryResult;
}
const EditPage: NextPage<EditPageProps> = ({ beerPost }) => {
return (
<Layout>
<Head>
<title>Edit {beerPost.name}</title>
<meta name="description" content={`Edit ${beerPost.name}`} />
</Head>
</Layout>
);
};
export default EditPage;
export const getServerSideProps = withPageAuthRequired<EditPageProps>(
async (context, session) => {
const beerPostId = context.params?.id as string;
const beerPost = await getBeerPostById(beerPostId);
const { id: userId } = session;
if (!beerPost) {
return { notFound: true };
}
const isBeerPostOwner = beerPost.postedBy.id === userId;
if (!isBeerPostOwner) {
return {
redirect: { destination: `/beers/${beerPostId}`, permanent: false },
};
}
return {
props: {
beerPost: JSON.parse(JSON.stringify(beerPost)),
},
};
},
);

View File

@@ -106,7 +106,7 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({
Next Comments
</Link>
<Link
className={`btn btn-outline ${
className={`btn-outline btn ${
commentsPageNum === commentsPageCount
? 'btn-disabled pointer-events-none'
: 'pointer-events-auto'

View File

@@ -31,7 +31,7 @@ const Create: NextPage<CreateBeerPageProps> = ({ breweries, types }) => {
);
};
export const getServerSideProps = withPageAuthRequired(async () => {
export const getServerSideProps = withPageAuthRequired<CreateBeerPageProps>(async () => {
const breweryPosts = await getAllBreweryPosts();
const beerTypes = await DBClient.instance.beerType.findMany();

View File

@@ -5,13 +5,6 @@ generator client {
provider = "prisma-client-js"
}
generator erdSVG {
provider = "prisma-erd-generator"
output = "./ERD.svg"
includeRelationFromFields = true
theme = "neutral"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")

View File

@@ -32,7 +32,7 @@ const createNewBeerPosts = async ({
abv: Math.floor(Math.random() * (12 - 4) + 4),
ibu: Math.floor(Math.random() * (60 - 10) + 10),
name: faker.commerce.productName(),
description: faker.lorem.lines(24),
description: faker.lorem.lines(42).replace(/(\r\n|\n|\r)/gm, ' '),
brewery: { connect: { id: breweryPost.id } },
postedBy: { connect: { id: user.id } },
type: { connect: { id: beerType.id } },

3
vercel.json Normal file
View File

@@ -0,0 +1,3 @@
{
"buildCommand": "npx prisma generate && npx prisma migrate deploy && next build"
}