mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Refactor
Extract upload middleware to separate file and implement edit profile functionality.
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
import useTimeDistance from '@/hooks/utilities/useTimeDistance';
|
import useTimeDistance from '@/hooks/utilities/useTimeDistance';
|
||||||
|
|
||||||
import { FC } from 'react';
|
import { FC, useContext } from 'react';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import GetUserSchema from '@/services/User/schema/GetUserSchema';
|
import GetUserSchema from '@/services/User/schema/GetUserSchema';
|
||||||
import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowedByUser';
|
import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowedByUser';
|
||||||
import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser';
|
import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser';
|
||||||
|
import UserContext from '@/contexts/UserContext';
|
||||||
|
import Link from 'next/link';
|
||||||
import UserAvatar from '../Account/UserAvatar';
|
import UserAvatar from '../Account/UserAvatar';
|
||||||
import UserFollowButton from './UserFollowButton';
|
import UserFollowButton from './UserFollowButton';
|
||||||
|
|
||||||
@@ -25,6 +27,8 @@ const UserHeader: FC<UserHeaderProps> = ({ user }) => {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { user: currentUser } = useContext(UserContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="card text-center items-center">
|
<header className="card text-center items-center">
|
||||||
<div className="card-body items-center w-full">
|
<div className="card-body items-center w-full">
|
||||||
@@ -55,13 +59,22 @@ const UserHeader: FC<UserHeaderProps> = ({ user }) => {
|
|||||||
<div className="w-6/12">
|
<div className="w-6/12">
|
||||||
<p className="text-sm">{user.bio}</p>
|
<p className="text-sm">{user.bio}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-20 flex items-center justify-center">
|
|
||||||
|
{currentUser?.id !== user.id ? (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
<UserFollowButton
|
<UserFollowButton
|
||||||
mutateFollowerCount={mutateFollowerCount}
|
mutateFollowerCount={mutateFollowerCount}
|
||||||
user={user}
|
user={user}
|
||||||
mutateFollowingCount={mutateFollowingCount}
|
mutateFollowingCount={mutateFollowingCount}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<Link href={`/account/profile`} className="btn btn-primary">
|
||||||
|
Edit Profile
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
30
src/config/multer/uploadMiddleware.ts
Normal file
30
src/config/multer/uploadMiddleware.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import multer from 'multer';
|
||||||
|
import { expressWrapper } from 'next-connect';
|
||||||
|
import cloudinaryConfig from '../cloudinary';
|
||||||
|
|
||||||
|
const { storage } = cloudinaryConfig;
|
||||||
|
|
||||||
|
const fileFilter: multer.Options['fileFilter'] = (req, file, callback) => {
|
||||||
|
const { mimetype } = file;
|
||||||
|
|
||||||
|
const isImage = mimetype.startsWith('image/');
|
||||||
|
|
||||||
|
if (!isImage) {
|
||||||
|
callback(null, false);
|
||||||
|
}
|
||||||
|
callback(null, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uploadMiddlewareMultiple = expressWrapper(
|
||||||
|
multer({ storage, fileFilter, limits: { files: 5, fileSize: 15 * 1024 * 1024 } }).array(
|
||||||
|
'images',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const singleUploadMiddleware = expressWrapper(
|
||||||
|
multer({
|
||||||
|
storage,
|
||||||
|
fileFilter,
|
||||||
|
limits: { files: 1, fileSize: 15 * 1024 * 1024 },
|
||||||
|
}).single('image'),
|
||||||
|
);
|
||||||
@@ -33,6 +33,7 @@ const UseBeerPostsByBrewery = ({ pageSize, breweryId }: UseBeerPostsByBreweryPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
||||||
const count = response.headers.get('X-Total-Count');
|
const count = response.headers.get('X-Total-Count');
|
||||||
|
|
||||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||||
|
|||||||
157
src/pages/account/profile.tsx
Normal file
157
src/pages/account/profile.tsx
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import FormError from '@/components/ui/forms/FormError';
|
||||||
|
import FormInfo from '@/components/ui/forms/FormInfo';
|
||||||
|
import FormLabel from '@/components/ui/forms/FormLabel';
|
||||||
|
import FormSegment from '@/components/ui/forms/FormSegment';
|
||||||
|
import FormTextInput from '@/components/ui/forms/FormTextInput';
|
||||||
|
import findUserById from '@/services/User/findUserById';
|
||||||
|
import GetUserSchema from '@/services/User/schema/GetUserSchema';
|
||||||
|
import withPageAuthRequired from '@/util/withPageAuthRequired';
|
||||||
|
import { GetServerSideProps, NextPage } from 'next';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import createErrorToast from '@/util/createErrorToast';
|
||||||
|
import Button from '@/components/ui/forms/Button';
|
||||||
|
|
||||||
|
interface ProfilePageProps {
|
||||||
|
user: z.infer<typeof GetUserSchema>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateProfileSchema = z.object({
|
||||||
|
bio: z.string().min(1, 'Bio cannot be empty'),
|
||||||
|
userAvatar: z
|
||||||
|
.instanceof(typeof FileList !== 'undefined' ? FileList : Object)
|
||||||
|
.refine((fileList) => fileList instanceof FileList, {
|
||||||
|
message: 'You must submit this form in a web browser.',
|
||||||
|
})
|
||||||
|
.refine((fileList) => (fileList as FileList).length === 1, {
|
||||||
|
message: 'You must upload exactly one file.',
|
||||||
|
})
|
||||||
|
.refine(
|
||||||
|
(fileList) =>
|
||||||
|
[...(fileList as FileList)]
|
||||||
|
.map((file) => file.type)
|
||||||
|
.every((fileType) => fileType.startsWith('image/')),
|
||||||
|
{ message: 'You must upload only images.' },
|
||||||
|
)
|
||||||
|
.refine(
|
||||||
|
(fileList) =>
|
||||||
|
[...(fileList as FileList)]
|
||||||
|
.map((file) => file.size)
|
||||||
|
.every((fileSize) => fileSize < 15 * 1024 * 1024),
|
||||||
|
{ message: 'You must upload images smaller than 15MB.' },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendUpdateProfileRequest = async (data: z.infer<typeof UpdateProfileSchema>) => {
|
||||||
|
if (!(data.userAvatar instanceof FileList)) {
|
||||||
|
throw new Error('You must submit this form in a web browser.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { bio, userAvatar } = data;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('image', userAvatar[0]);
|
||||||
|
formData.append('bio', bio);
|
||||||
|
|
||||||
|
const response = await fetch(`/api/users/profile`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Something went wrong.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedUser = await response.json();
|
||||||
|
|
||||||
|
return updatedUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProfilePage: NextPage<ProfilePageProps> = ({ user }) => {
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors, isSubmitting },
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
reset,
|
||||||
|
} = useForm<z.infer<typeof UpdateProfileSchema>>({
|
||||||
|
resolver: zodResolver(UpdateProfileSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<z.infer<typeof UpdateProfileSchema>> = async (data) => {
|
||||||
|
try {
|
||||||
|
await sendUpdateProfileRequest(data);
|
||||||
|
const loadingToast = toast.loading('Updating profile...');
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 1000);
|
||||||
|
});
|
||||||
|
toast.remove(loadingToast);
|
||||||
|
// reset();
|
||||||
|
toast.success('Profile updated!');
|
||||||
|
} catch (error) {
|
||||||
|
createErrorToast(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<div className="w-9/12">
|
||||||
|
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||||
|
<form className="form-control" noValidate onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<FormInfo>
|
||||||
|
<FormLabel htmlFor="bio">Bio</FormLabel>
|
||||||
|
<FormError>{errors.bio?.message}</FormError>
|
||||||
|
</FormInfo>
|
||||||
|
|
||||||
|
<FormSegment>
|
||||||
|
<FormTextInput
|
||||||
|
disabled={isSubmitting}
|
||||||
|
id="bio"
|
||||||
|
type="text"
|
||||||
|
formValidationSchema={register('bio')}
|
||||||
|
error={!!errors.bio}
|
||||||
|
placeholder="Bio"
|
||||||
|
/>
|
||||||
|
</FormSegment>
|
||||||
|
|
||||||
|
<FormInfo>
|
||||||
|
<FormLabel htmlFor="userAvatar">Avatar</FormLabel>
|
||||||
|
<FormError>{errors.userAvatar?.message}</FormError>
|
||||||
|
</FormInfo>
|
||||||
|
<FormSegment>
|
||||||
|
<input
|
||||||
|
disabled={isSubmitting}
|
||||||
|
type="file"
|
||||||
|
id="userAvatar"
|
||||||
|
className="file-input-bordered file-input w-full"
|
||||||
|
{...register('userAvatar')}
|
||||||
|
/>
|
||||||
|
</FormSegment>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<Button type="submit" isSubmitting={isSubmitting}>
|
||||||
|
Update Profile
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProfilePage;
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps =
|
||||||
|
withPageAuthRequired<ProfilePageProps>(async (context, session) => {
|
||||||
|
const { id } = session;
|
||||||
|
|
||||||
|
const user = await findUserById(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return { notFound: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { props: { user: JSON.parse(JSON.stringify(user)) } };
|
||||||
|
});
|
||||||
@@ -1,38 +1,17 @@
|
|||||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||||
import { createRouter, expressWrapper } from 'next-connect';
|
import { createRouter } from 'next-connect';
|
||||||
|
|
||||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||||
|
|
||||||
import multer from 'multer';
|
|
||||||
|
|
||||||
import cloudinaryConfig from '@/config/cloudinary';
|
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||||
import addBeerImageToDB from '@/services/BeerImage/addBeerImageToDB';
|
import addBeerImageToDB from '@/services/BeerImage/addBeerImageToDB';
|
||||||
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
||||||
|
import { uploadMiddlewareMultiple } from '@/config/multer/uploadMiddleware';
|
||||||
const { storage } = cloudinaryConfig;
|
|
||||||
|
|
||||||
const fileFilter: multer.Options['fileFilter'] = (req, file, cb) => {
|
|
||||||
const { mimetype } = file;
|
|
||||||
|
|
||||||
const isImage = mimetype.startsWith('image/');
|
|
||||||
|
|
||||||
if (!isImage) {
|
|
||||||
cb(null, false);
|
|
||||||
}
|
|
||||||
cb(null, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const uploadMiddleware = expressWrapper(
|
|
||||||
multer({ storage, fileFilter, limits: { files: 5, fileSize: 15 * 1024 * 1024 } }).array(
|
|
||||||
'images',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
interface UploadBeerPostImagesRequest extends UserExtendedNextApiRequest {
|
interface UploadBeerPostImagesRequest extends UserExtendedNextApiRequest {
|
||||||
files?: Express.Multer.File[];
|
files?: Express.Multer.File[];
|
||||||
@@ -75,7 +54,7 @@ const router = createRouter<
|
|||||||
router.post(
|
router.post(
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
uploadMiddleware,
|
uploadMiddlewareMultiple,
|
||||||
validateRequest({ bodySchema: ImageMetadataValidationSchema }),
|
validateRequest({ bodySchema: ImageMetadataValidationSchema }),
|
||||||
processImageData,
|
processImageData,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,11 +18,14 @@ const getAllBeersByBrewery = async (
|
|||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
const { page_size, page_num, id } = req.query;
|
const { page_size, page_num, id } = req.query;
|
||||||
|
|
||||||
|
const pageNum = parseInt(page_num, 10);
|
||||||
|
const pageSize = parseInt(page_size, 10);
|
||||||
|
|
||||||
const beers: z.infer<typeof BeerPostQueryResult>[] =
|
const beers: z.infer<typeof BeerPostQueryResult>[] =
|
||||||
await DBClient.instance.beerPost.findMany({
|
await DBClient.instance.beerPost.findMany({
|
||||||
where: { breweryId: id },
|
where: { breweryId: id },
|
||||||
take: parseInt(page_size, 10),
|
skip: (pageNum - 1) * pageSize,
|
||||||
skip: parseInt(page_num, 10) * parseInt(page_size, 10),
|
take: pageSize,
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
|||||||
@@ -1,38 +1,17 @@
|
|||||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||||
import { createRouter, expressWrapper } from 'next-connect';
|
import { createRouter } from 'next-connect';
|
||||||
|
|
||||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||||
|
|
||||||
import multer from 'multer';
|
|
||||||
|
|
||||||
import cloudinaryConfig from '@/config/cloudinary';
|
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||||
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
||||||
import addBreweryImageToDB from '@/services/BreweryImage/addBreweryImageToDB';
|
import addBreweryImageToDB from '@/services/BreweryImage/addBreweryImageToDB';
|
||||||
|
import { uploadMiddlewareMultiple } from '@/config/multer/uploadMiddleware';
|
||||||
const { storage } = cloudinaryConfig;
|
|
||||||
|
|
||||||
const fileFilter: multer.Options['fileFilter'] = (req, file, cb) => {
|
|
||||||
const { mimetype } = file;
|
|
||||||
|
|
||||||
const isImage = mimetype.startsWith('image/');
|
|
||||||
|
|
||||||
if (!isImage) {
|
|
||||||
cb(null, false);
|
|
||||||
}
|
|
||||||
cb(null, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const uploadMiddleware = expressWrapper(
|
|
||||||
multer({ storage, fileFilter, limits: { files: 5, fileSize: 15 * 1024 * 1024 } }).array(
|
|
||||||
'images',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
interface UploadBreweryPostImagesRequest extends UserExtendedNextApiRequest {
|
interface UploadBreweryPostImagesRequest extends UserExtendedNextApiRequest {
|
||||||
files?: Express.Multer.File[];
|
files?: Express.Multer.File[];
|
||||||
@@ -75,7 +54,7 @@ const router = createRouter<
|
|||||||
router.post(
|
router.post(
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
uploadMiddleware,
|
uploadMiddlewareMultiple,
|
||||||
validateRequest({ bodySchema: ImageMetadataValidationSchema }),
|
validateRequest({ bodySchema: ImageMetadataValidationSchema }),
|
||||||
processImageData,
|
processImageData,
|
||||||
);
|
);
|
||||||
|
|||||||
99
src/pages/api/users/profile.ts
Normal file
99
src/pages/api/users/profile.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||||
|
import { singleUploadMiddleware } from '@/config/multer/uploadMiddleware';
|
||||||
|
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||||
|
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
import GetUserSchema from '@/services/User/schema/GetUserSchema';
|
||||||
|
|
||||||
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
|
import { NextApiResponse } from 'next';
|
||||||
|
import { createRouter } from 'next-connect';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
interface UpdateProfileRequest extends UserExtendedNextApiRequest {
|
||||||
|
file?: Express.Multer.File;
|
||||||
|
body: {
|
||||||
|
bio: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateUserProfileByIdParams {
|
||||||
|
id: string;
|
||||||
|
data: {
|
||||||
|
bio: string;
|
||||||
|
avatar: {
|
||||||
|
alt: string;
|
||||||
|
path: string;
|
||||||
|
caption: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateUserProfileById = async ({ id, data }: UpdateUserProfileByIdParams) => {
|
||||||
|
const { alt, path, caption } = data.avatar;
|
||||||
|
const user: z.infer<typeof GetUserSchema> = await DBClient.instance.user.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
bio: data.bio,
|
||||||
|
userAvatar: {
|
||||||
|
upsert: { create: { alt, path, caption }, update: { alt, path, caption } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
username: true,
|
||||||
|
email: true,
|
||||||
|
bio: true,
|
||||||
|
userAvatar: true,
|
||||||
|
accountIsVerified: true,
|
||||||
|
createdAt: true,
|
||||||
|
firstName: true,
|
||||||
|
lastName: true,
|
||||||
|
updatedAt: true,
|
||||||
|
dateOfBirth: true,
|
||||||
|
role: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateProfile = async (req: UpdateProfileRequest, res: NextApiResponse) => {
|
||||||
|
const { file, body, user } = req;
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
throw new Error('No file uploaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateUserProfileById({
|
||||||
|
id: user!.id,
|
||||||
|
data: {
|
||||||
|
bio: body.bio,
|
||||||
|
avatar: { alt: file.originalname, path: file.path, caption: '' },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
res.status(200).json({
|
||||||
|
message: 'User confirmed successfully.',
|
||||||
|
statusCode: 200,
|
||||||
|
success: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = createRouter<
|
||||||
|
UpdateProfileRequest,
|
||||||
|
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||||
|
>();
|
||||||
|
|
||||||
|
router.put(
|
||||||
|
getCurrentUser,
|
||||||
|
// @ts-expect-error
|
||||||
|
singleUploadMiddleware,
|
||||||
|
|
||||||
|
validateRequest({ bodySchema: z.object({ bio: z.string().max(1000) }) }),
|
||||||
|
updateProfile,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handler = router.handler();
|
||||||
|
|
||||||
|
export default handler;
|
||||||
|
export const config = { api: { bodyParser: false } };
|
||||||
Reference in New Issue
Block a user