Feat: implement client side functionality for user follow feature

This commit is contained in:
Aaron William Po
2023-11-27 22:04:55 -05:00
parent e0e22ba7af
commit 7c87be09cf
11 changed files with 300 additions and 25 deletions

View File

@@ -35,7 +35,7 @@ const AccountPage: NextPage = () => {
<div className="flex flex-col items-center">
<div className="m-12 flex w-11/12 flex-col items-center justify-center space-y-3 lg:w-8/12">
<div className="flex flex-col items-center space-y-3">
<div className="h-20 mb-10 w-20">
<div className="h-28 mb-1 w-28">
<UserAvatar user={user} />
</div>

View File

@@ -0,0 +1,81 @@
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
import ServerError from '@/config/util/ServerError';
import DBClient from '@/prisma/DBClient';
import findUserById from '@/services/User/findUserById';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import { createRouter } from 'next-connect';
import { z } from 'zod';
interface GetUserFollowInfoRequest extends UserExtendedNextApiRequest {
query: { id: string };
}
const router = createRouter<
GetUserFollowInfoRequest,
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
>();
const followUser = async (
req: GetUserFollowInfoRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { id } = req.query;
const user = await findUserById(id);
if (!user) {
throw new ServerError('User not found', 404);
}
const currentUser = req.user!;
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
where: {
followerId: currentUser.id,
followingId: id,
},
});
if (!userIsFollowedBySessionUser) {
await DBClient.instance.userFollow.create({
data: { followerId: currentUser.id, followingId: id },
});
res.status(200).json({
message: 'Now following user.',
success: true,
statusCode: 200,
});
return;
}
await DBClient.instance.userFollow.delete({
where: {
followerId_followingId: {
followerId: currentUser.id,
followingId: id,
},
},
});
res.status(200).json({
message: 'No longer following user.',
success: true,
statusCode: 200,
});
};
router.post(
validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }),
getCurrentUser,
followUser,
);
const handler = router.handler(NextConnectOptions);
export default handler;

View File

@@ -0,0 +1,71 @@
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
import ServerError from '@/config/util/ServerError';
import DBClient from '@/prisma/DBClient';
import findUserById from '@/services/User/findUserById';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import { createRouter } from 'next-connect';
import { z } from 'zod';
interface GetUserFollowInfoRequest extends UserExtendedNextApiRequest {
query: { id: string };
}
const router = createRouter<
GetUserFollowInfoRequest,
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
>();
const checkIfUserIsFollowedBySessionUser = async (
req: GetUserFollowInfoRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { id } = req.query;
const user = await findUserById(id);
if (!user) {
throw new ServerError('User not found', 404);
}
const currentUser = req.user!;
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
where: {
followerId: currentUser.id,
followingId: id,
},
});
if (!userIsFollowedBySessionUser) {
res.status(200).json({
message: 'User is not followed by the current user.',
success: true,
statusCode: 200,
payload: { isFollowed: false },
});
return;
}
res.status(200).json({
message: 'User is followed by the current user.',
success: true,
statusCode: 200,
payload: { isFollowed: true },
});
};
router.get(
validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }),
getCurrentUser,
checkIfUserIsFollowedBySessionUser,
);
const handler = router.handler(NextConnectOptions);
export default handler;

View File

@@ -7,8 +7,6 @@ import { FC } from 'react';
import { z } from 'zod';
import withPageAuthRequired from '@/util/withPageAuthRequired';
import UserHeader from '@/components/UserPage/UserHeader';
import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowedByUser';
import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser';
interface UserInfoPageProps {
user: z.infer<typeof GetUserSchema>;
@@ -19,16 +17,6 @@ const UserInfoPage: FC<UserInfoPageProps> = ({ user }) => {
const isDesktop = useMediaQuery('(min-width: 1024px)');
const title = `${user.username} | The Biergarten App`;
const { followingCount } = useGetUsersFollowedByUser({
userId: user.id,
pageSize: 10,
});
const { followerCount } = useGetUsersFollowingUser({
userId: user.id,
pageSize: 10,
});
return (
<>
<Head>
@@ -38,11 +26,7 @@ const UserInfoPage: FC<UserInfoPageProps> = ({ user }) => {
<>
<main className="mb-12 mt-10 flex w-full items-center justify-center">
<div className="h-full w-11/12 space-y-3 xl:w-9/12 2xl:w-8/12">
<UserHeader
user={user}
followerCount={followerCount}
followingCount={followingCount}
/>
<UserHeader user={user} />
{isDesktop ? (
<div className="h-64 flex space-x-3">