add user context and likes

This commit is contained in:
Aaron William Po
2023-02-08 07:43:59 -05:00
parent 20000cc4af
commit f6880deeb6
12 changed files with 300 additions and 47 deletions

View File

@@ -1,6 +1,14 @@
import useUser from '@/hooks/useUser';
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import UserContext from './contexts/userContext';
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
const { user, isLoading, error } = useUser();
return (
<UserContext.Provider value={{ user, isLoading, error }}>
<Component {...pageProps} />
</UserContext.Provider>
);
}

View File

@@ -0,0 +1,72 @@
import DBClient from '@/prisma/DBClient';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import getBeerPostById from '@/services/BeerPost/getBeerPostById';
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import validateRequest from '@/config/zod/middleware/validateRequest';
import getCurrentUser from '@/config/auth/middleware/getCurrentUser';
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import nextConnect from 'next-connect';
import { z } from 'zod';
import { NextApiResponse } from 'next';
import ServerError from '@/config/util/ServerError';
const likeBeerPost = async (
req: UserExtendedNextApiRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const user = req.user!;
const id = req.query.id as string;
const beer = await getBeerPostById(id);
if (!beer) {
throw new ServerError('Could not find a beer post with that id', 404);
}
const alreadyLiked = await DBClient.instance.beerPostLikes.findFirst({
where: {
beerPostId: id,
userId: user.id,
},
});
if (alreadyLiked) {
await DBClient.instance.beerPostLikes.delete({
where: {
id: alreadyLiked.id,
},
});
res.status(200).json({
success: true,
message: 'Successfully unliked beer post',
statusCode: 200,
});
return;
}
await DBClient.instance.beerPostLikes.create({
data: {
beerPost: { connect: { id } },
user: { connect: { id: user.id } },
},
});
res.status(200).json({
success: true,
message: 'Successfully liked beer post',
statusCode: 200,
});
};
const handler = nextConnect(NextConnectConfig).post(
getCurrentUser,
validateRequest({
querySchema: z.object({
id: z.string().uuid(),
}),
}),
likeBeerPost,
);
export default handler;

View File

@@ -0,0 +1,45 @@
import getCurrentUser from '@/config/auth/middleware/getCurrentUser';
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import validateRequest from '@/config/zod/middleware/validateRequest';
import DBClient from '@/prisma/DBClient';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import nextConnect from 'next-connect';
import { z } from 'zod';
const checkIfLiked = async (
req: UserExtendedNextApiRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const user = req.user!;
const id = req.query.id as string;
const alreadyLiked = await DBClient.instance.beerPostLikes.findFirst({
where: {
beerPostId: id,
userId: user.id,
},
});
res.status(200).json({
success: true,
message: 'Successfully checked if beer post is liked by the current user',
statusCode: 200,
payload: {
isLiked: !!alreadyLiked,
},
});
};
const handler = nextConnect(NextConnectConfig).get(
getCurrentUser,
validateRequest({
querySchema: z.object({
id: z.string().uuid(),
}),
}),
checkIfLiked,
);
export default handler;

View File

@@ -12,8 +12,8 @@ import { BeerPost } from '@prisma/client';
import { NextPage, GetServerSideProps } from 'next';
import Head from 'next/head';
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { useState, useEffect, useContext } from 'react';
import UserContext from '../contexts/userContext';
interface BeerPageProps {
beerPost: BeerPostQueryResult;
@@ -36,10 +36,13 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({
beerRecommendations,
beerComments,
}) => {
const { user } = useContext(UserContext);
const [comments, setComments] = useState(beerComments);
useEffect(() => {
setComments(beerComments);
}, [beerComments]);
return (
<Layout>
<Head>
@@ -63,8 +66,16 @@ const BeerByIdPage: NextPage<BeerPageProps> = ({
<div className="mt-4 flex space-x-3">
<div className="w-[60%] space-y-3">
<div className="card h-96 bg-base-300">
<div className="card-body">
<BeerCommentForm beerPost={beerPost} setComments={setComments} />
<div className="card-body h-full">
{user ? (
<BeerCommentForm beerPost={beerPost} setComments={setComments} />
) : (
<div className="flex h-full flex-col items-center justify-center">
<span className="text-lg font-bold">
Log in to leave a comment.
</span>
</div>
)}
</div>
</div>
<div className="card h-[135rem] bg-base-300">

View File

@@ -0,0 +1,11 @@
import GetUserSchema from '@/services/user/schema/GetUserSchema';
import { createContext } from 'react';
import { z } from 'zod';
const UserContext = createContext<{
user?: z.infer<typeof GetUserSchema>;
error?: unknown;
isLoading: boolean;
}>({ isLoading: true });
export default UserContext;

View File

@@ -1,11 +1,13 @@
import Layout from '@/components/ui/Layout';
import Spinner from '@/components/ui/Spinner';
import withPageAuthRequired from '@/config/auth/withPageAuthRequired';
import useUser from '@/hooks/useUser';
import { GetServerSideProps, NextPage } from 'next';
import { useContext } from 'react';
import UserContext from '../contexts/userContext';
const ProtectedPage: NextPage = () => {
const { user, isLoading, error } = useUser();
const { user, error, isLoading } = useContext(UserContext);
return (
<Layout>