mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Refactor BeerPostHeader, refactor login and register
- Updated BeerPostHeader in /id page to use semantic HTML tags - Removed the getServerSidesProps fn in /login and /register. Moved the redirect logic over to the client, will redirect on the client side. - Added delete BeerPost option on the edit page.
This commit is contained in:
@@ -39,10 +39,10 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
|
|||||||
}, [beerPost.createdAt]);
|
}, [beerPost.createdAt]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card flex flex-col justify-center bg-base-300">
|
<main className="card flex flex-col justify-center bg-base-300">
|
||||||
<div className="card-body">
|
<article className="card-body">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div>
|
<header>
|
||||||
<h1 className="text-4xl font-bold">{beerPost.name}</h1>
|
<h1 className="text-4xl font-bold">{beerPost.name}</h1>
|
||||||
<h2 className="text-2xl font-semibold">
|
<h2 className="text-2xl font-semibold">
|
||||||
by{' '}
|
by{' '}
|
||||||
@@ -53,8 +53,7 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
|
|||||||
{beerPost.brewery.name}
|
{beerPost.brewery.name}
|
||||||
</Link>
|
</Link>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</header>
|
||||||
<div>
|
|
||||||
{isPostOwner && (
|
{isPostOwner && (
|
||||||
<div className="tooltip tooltip-left" data-tip={`Edit '${beerPost.name}'`}>
|
<div className="tooltip tooltip-left" data-tip={`Edit '${beerPost.name}'`}>
|
||||||
<Link
|
<Link
|
||||||
@@ -66,18 +65,17 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 className="italic">
|
<h3 className="italic">
|
||||||
posted by{' '}
|
posted by{' '}
|
||||||
<Link href={`/users/${beerPost.postedBy.id}`} className="link-hover link">
|
<Link href={`/users/${beerPost.postedBy.id}`} className="link-hover link">
|
||||||
{beerPost.postedBy.username}{' '}
|
{beerPost.postedBy.username}
|
||||||
</Link>
|
</Link>
|
||||||
<span
|
<span
|
||||||
className="tooltip tooltip-bottom"
|
className="tooltip tooltip-bottom"
|
||||||
data-tip={format(createdAtDate, 'MM/dd/yyyy')}
|
data-tip={format(createdAtDate, 'MM/dd/yyyy')}
|
||||||
>
|
>
|
||||||
{timeDistance} ago
|
{` ${timeDistance}`} ago
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
@@ -108,8 +106,8 @@ const BeerInfoHeader: FC<{ beerPost: BeerPostQueryResult; initialLikeCount: numb
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,18 @@ const EditBeerPostForm: FC<EditBeerPostFormProps> = ({ previousValues }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDelete = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/beers/${previousValues.id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
if (response.status === 200) {
|
||||||
|
router.push('/beers');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<form className="form-control" onSubmit={handleSubmit(onSubmit)}>
|
<form className="form-control" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
@@ -116,10 +128,17 @@ const EditBeerPostForm: FC<EditBeerPostFormProps> = ({ previousValues }) => {
|
|||||||
/>
|
/>
|
||||||
</FormSegment>
|
</FormSegment>
|
||||||
|
|
||||||
<div className="mt-2">
|
<div className="mt-2 space-y-4">
|
||||||
<Button type="submit" isSubmitting={isSubmitting}>
|
<Button type="submit" isSubmitting={isSubmitting}>
|
||||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||||
</Button>
|
</Button>
|
||||||
|
<button
|
||||||
|
className={`btn-primary btn w-full rounded-xl ${isSubmitting ? 'loading' : ''}`}
|
||||||
|
type="button"
|
||||||
|
onClick={onDelete}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { GetServerSideProps, GetServerSidePropsContext, Redirect } from 'next';
|
|
||||||
import { getLoginSession } from '@/config/auth/session';
|
|
||||||
import findUserById from '@/services/User/findUserById';
|
|
||||||
|
|
||||||
const redirectIfLoggedIn = (redirect: Redirect) => {
|
|
||||||
const fn: GetServerSideProps = async (context: GetServerSidePropsContext) => {
|
|
||||||
try {
|
|
||||||
const { req } = context;
|
|
||||||
const session = await getLoginSession(req);
|
|
||||||
|
|
||||||
const { id } = session;
|
|
||||||
|
|
||||||
const user = await findUserById(id);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new Error('Could not get user.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return { redirect };
|
|
||||||
} catch {
|
|
||||||
return { props: {} };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default redirectIfLoggedIn;
|
|
||||||
17
hooks/useRedirectIfLoggedIn.ts
Normal file
17
hooks/useRedirectIfLoggedIn.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import UserContext from '@/contexts/userContext';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
|
||||||
|
const useRedirectWhenLoggedIn = () => {
|
||||||
|
const { user } = useContext(UserContext);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
router.push('/');
|
||||||
|
}, [user, router]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useRedirectWhenLoggedIn;
|
||||||
@@ -6,20 +6,25 @@ import editBeerPostById from '@/services/BeerPost/editBeerPostById';
|
|||||||
import EditBeerPostValidationSchema from '@/services/BeerPost/schema/EditBeerPostValidationSchema';
|
import EditBeerPostValidationSchema from '@/services/BeerPost/schema/EditBeerPostValidationSchema';
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { createRouter } from 'next-connect';
|
import { createRouter, NextHandler } from 'next-connect';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
|
||||||
interface EditBeerPostRequest extends UserExtendedNextApiRequest {
|
interface BeerPostRequest extends UserExtendedNextApiRequest {
|
||||||
query: { id: string };
|
query: { id: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EditBeerPostRequest extends BeerPostRequest {
|
||||||
body: z.infer<typeof EditBeerPostValidationSchema>;
|
body: z.infer<typeof EditBeerPostValidationSchema>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const editBeerPost = async (
|
const checkIfBeerPostOwner = async (
|
||||||
req: EditBeerPostRequest,
|
req: BeerPostRequest,
|
||||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
res: NextApiResponse,
|
||||||
|
next: NextHandler,
|
||||||
) => {
|
) => {
|
||||||
const { body, user, query } = req;
|
const { user, query } = req;
|
||||||
const { id } = query;
|
const { id } = query;
|
||||||
|
|
||||||
const beerPost = await getBeerPostById(id);
|
const beerPost = await getBeerPostById(id);
|
||||||
@@ -32,6 +37,18 @@ const editBeerPost = async (
|
|||||||
throw new ServerError('You cannot edit that beer post.', 403);
|
throw new ServerError('You cannot edit that beer post.', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
const editBeerPost = async (
|
||||||
|
req: EditBeerPostRequest,
|
||||||
|
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
body,
|
||||||
|
query: { id },
|
||||||
|
} = req;
|
||||||
|
|
||||||
await editBeerPostById(id, body);
|
await editBeerPostById(id, body);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
@@ -41,12 +58,32 @@ const editBeerPost = async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteBeerPost = async (req: BeerPostRequest, res: NextApiResponse) => {
|
||||||
|
const {
|
||||||
|
query: { id },
|
||||||
|
} = req;
|
||||||
|
|
||||||
|
const deleted = await DBClient.instance.beerPost.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!deleted) {
|
||||||
|
throw new ServerError('Beer post not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
message: 'Beer post deleted successfully',
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
});
|
||||||
|
};
|
||||||
const router = createRouter<
|
const router = createRouter<
|
||||||
EditBeerPostRequest,
|
EditBeerPostRequest,
|
||||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||||
>();
|
>();
|
||||||
|
|
||||||
router.put(getCurrentUser, editBeerPost);
|
router.put(getCurrentUser, checkIfBeerPostOwner, editBeerPost);
|
||||||
|
router.delete(getCurrentUser, checkIfBeerPostOwner, deleteBeerPost);
|
||||||
|
|
||||||
const handler = router.handler(NextConnectOptions);
|
const handler = router.handler(NextConnectOptions);
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import Image from 'next/image';
|
|||||||
import { FaUserCircle } from 'react-icons/fa';
|
import { FaUserCircle } from 'react-icons/fa';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import redirectIfLoggedIn from '@/getServerSideProps/redirectIfLoggedIn';
|
|
||||||
|
import useRedirectWhenLoggedIn from '@/hooks/useRedirectIfLoggedIn';
|
||||||
|
|
||||||
const LoginPage: NextPage = () => {
|
const LoginPage: NextPage = () => {
|
||||||
|
useRedirectWhenLoggedIn();
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
@@ -52,8 +54,3 @@ const LoginPage: NextPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default LoginPage;
|
export default LoginPage;
|
||||||
|
|
||||||
export const getServerSideProps = redirectIfLoggedIn({
|
|
||||||
destination: '/',
|
|
||||||
permanent: false,
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import RegisterUserForm from '@/components/RegisterUserForm';
|
import RegisterUserForm from '@/components/RegisterUserForm';
|
||||||
import FormPageLayout from '@/components/ui/forms/FormPageLayout';
|
import FormPageLayout from '@/components/ui/forms/FormPageLayout';
|
||||||
import Layout from '@/components/ui/Layout';
|
import Layout from '@/components/ui/Layout';
|
||||||
import redirectIfLoggedIn from '@/getServerSideProps/redirectIfLoggedIn';
|
|
||||||
|
import useRedirectWhenLoggedIn from '@/hooks/useRedirectIfLoggedIn';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import { BiUser } from 'react-icons/bi';
|
import { BiUser } from 'react-icons/bi';
|
||||||
|
|
||||||
const RegisterUserPage: NextPage = () => {
|
const RegisterUserPage: NextPage = () => {
|
||||||
|
useRedirectWhenLoggedIn();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Head>
|
<Head>
|
||||||
@@ -26,8 +29,3 @@ const RegisterUserPage: NextPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default RegisterUserPage;
|
export default RegisterUserPage;
|
||||||
|
|
||||||
export const getServerSideProps = redirectIfLoggedIn({
|
|
||||||
destination: '/',
|
|
||||||
permanent: false,
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ const sendCreateBeerCommentRequest = async ({
|
|||||||
throw new Error('Invalid API response');
|
throw new Error('Invalid API response');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(parsedResponse);
|
|
||||||
const parsedPayload = BeerCommentQueryResult.safeParse(parsedResponse.data.payload);
|
const parsedPayload = BeerCommentQueryResult.safeParse(parsedResponse.data.payload);
|
||||||
|
|
||||||
if (!parsedPayload.success) {
|
if (!parsedPayload.success) {
|
||||||
|
|||||||
Reference in New Issue
Block a user