mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Update auth requests
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import validateEmailRequest from '@/requests/users/auth/validateEmailRequest';
|
||||
import validateUsernameRequest from '@/requests/users/profile/validateUsernameRequest';
|
||||
import { BaseCreateUserSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import { Switch } from '@headlessui/react';
|
||||
@@ -7,7 +6,7 @@ import { Dispatch, FC, useContext } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import UserContext from '@/contexts/UserContext';
|
||||
import sendEditUserRequest from '@/requests/users/auth/sendEditUserRequest';
|
||||
|
||||
import createErrorToast from '@/util/createErrorToast';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { AccountPageAction, AccountPageState } from '@/reducers/accountPageReducer';
|
||||
@@ -15,6 +14,7 @@ import FormError from '../ui/forms/FormError';
|
||||
import FormInfo from '../ui/forms/FormInfo';
|
||||
import FormLabel from '../ui/forms/FormLabel';
|
||||
import FormTextInput from '../ui/forms/FormTextInput';
|
||||
import { sendEditUserRequest, validateEmailRequest } from '@/requests/users/auth';
|
||||
|
||||
interface AccountInfoProps {
|
||||
pageState: AccountPageState;
|
||||
@@ -36,7 +36,7 @@ const AccountInfo: FC<AccountInfoProps> = ({ pageState, dispatch }) => {
|
||||
.refine(
|
||||
async (email) => {
|
||||
if (user!.email === email) return true;
|
||||
return validateEmailRequest(email);
|
||||
return validateEmailRequest({ email });
|
||||
},
|
||||
{ message: 'Email is already taken.' },
|
||||
),
|
||||
|
||||
@@ -4,10 +4,11 @@ import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { UpdatePasswordSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import sendUpdatePasswordRequest from '@/requests/users/auth/sendUpdatePasswordRequest';
|
||||
|
||||
import { AccountPageState, AccountPageAction } from '@/reducers/accountPageReducer';
|
||||
import toast from 'react-hot-toast';
|
||||
import createErrorToast from '@/util/createErrorToast';
|
||||
import { sendUpdatePasswordRequest } from '@/requests/users/auth';
|
||||
import FormError from '../ui/forms/FormError';
|
||||
import FormInfo from '../ui/forms/FormInfo';
|
||||
import FormLabel from '../ui/forms/FormLabel';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sendLoginUserRequest from '@/requests/users/auth/sendLoginUserRequest';
|
||||
import LoginValidationSchema from '@/services/users/auth/schema/LoginValidationSchema';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -15,6 +14,7 @@ import FormLabel from '../ui/forms/FormLabel';
|
||||
import FormSegment from '../ui/forms/FormSegment';
|
||||
import FormTextInput from '../ui/forms/FormTextInput';
|
||||
import Button from '../ui/forms/Button';
|
||||
import { sendLoginUserRequest } from '@/requests/users/auth';
|
||||
|
||||
type LoginT = z.infer<typeof LoginValidationSchema>;
|
||||
const LoginForm = () => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sendRegisterUserRequest from '@/requests/users/auth/sendRegisterUserRequest';
|
||||
import { CreateUserValidationSchemaWithUsernameAndEmailCheck } from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -9,6 +8,7 @@ import { z } from 'zod';
|
||||
|
||||
import createErrorToast from '@/util/createErrorToast';
|
||||
import toast from 'react-hot-toast';
|
||||
import { sendRegisterUserRequest } from '@/requests/users/auth';
|
||||
import Button from './ui/forms/Button';
|
||||
import FormError from './ui/forms/FormError';
|
||||
import FormInfo from './ui/forms/FormInfo';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import useFollowStatus from '@/hooks/data-fetching/user-follows/useFollowStatus';
|
||||
import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowedByUser';
|
||||
import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser';
|
||||
import sendUserFollowRequest from '@/requests/users/auth/sendUserFollowRequest';
|
||||
import { sendUserFollowRequest } from '@/requests/users/auth';
|
||||
|
||||
import GetUserSchema from '@/services/users/auth/schema/GetUserSchema';
|
||||
import { FC, useState } from 'react';
|
||||
import { FaUserCheck, FaUserPlus } from 'react-icons/fa';
|
||||
@@ -25,7 +26,7 @@ const UserFollowButton: FC<UserFollowButtonProps> = ({
|
||||
const onClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await sendUserFollowRequest(user.id);
|
||||
await sendUserFollowRequest({ userId: user.id });
|
||||
await Promise.all([
|
||||
mutateFollowStatus(),
|
||||
mutateFollowerCount(),
|
||||
|
||||
@@ -12,8 +12,9 @@ import { NextPage } from 'next';
|
||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useRouter } from 'next/router';
|
||||
import sendForgotPasswordRequest from '@/requests/users/auth/sendForgotPasswordRequest';
|
||||
|
||||
import { FaUserCircle } from 'react-icons/fa';
|
||||
import { sendForgotPasswordRequest } from '@/requests/users/auth';
|
||||
|
||||
interface ForgotPasswordPageProps {}
|
||||
|
||||
@@ -29,7 +30,7 @@ const ForgotPasswordPage: NextPage<ForgotPasswordPageProps> = () => {
|
||||
const onSubmit: SubmitHandler<{ email: string }> = async (data) => {
|
||||
try {
|
||||
const loadingToast = toast.loading('Sending reset link...');
|
||||
await sendForgotPasswordRequest(data.email);
|
||||
await sendForgotPasswordRequest({ email: data.email });
|
||||
reset();
|
||||
toast.dismiss(loadingToast);
|
||||
toast.success('Password reset link sent!');
|
||||
|
||||
169
src/requests/users/auth/index.ts
Normal file
169
src/requests/users/auth/index.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { BasicUserInfoSchema } from '@/config/auth/types';
|
||||
import GetUserSchema from '@/services/users/auth/schema/GetUserSchema';
|
||||
import type {
|
||||
SendEditUserRequest,
|
||||
SendForgotPasswordRequest,
|
||||
SendLoginUserRequest,
|
||||
SendRegisterUserRequest,
|
||||
SendUpdatePasswordRequest,
|
||||
SendUserFollowRequest,
|
||||
ValidateEmailRequest,
|
||||
} from './types';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const sendEditUserRequest: SendEditUserRequest = async ({ user, data }) => {
|
||||
const response = await fetch(`/api/users/${user!.id}`, {
|
||||
body: JSON.stringify(data),
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export const sendForgotPasswordRequest: SendForgotPasswordRequest = async ({ email }) => {
|
||||
const response = await fetch('/api/users/forgot-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Something went wrong and we couldn't send the reset link.");
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error(parsed.error.message);
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export const sendLoginUserRequest: SendLoginUserRequest = async ({
|
||||
username,
|
||||
password,
|
||||
}) => {
|
||||
const response = await fetch('/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password,
|
||||
}),
|
||||
});
|
||||
|
||||
const json: unknown = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed');
|
||||
}
|
||||
|
||||
if (!parsed.data.success) {
|
||||
throw new Error(parsed.data.message);
|
||||
}
|
||||
const parsedPayload = BasicUserInfoSchema.safeParse(parsed.data.payload);
|
||||
if (!parsedPayload.success) {
|
||||
throw new Error('API response payload validation failed');
|
||||
}
|
||||
|
||||
return parsedPayload.data;
|
||||
};
|
||||
|
||||
export const sendRegisterUserRequest: SendRegisterUserRequest = async (data) => {
|
||||
const response = await fetch('/api/users/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
if (!parsed.data.success) {
|
||||
throw new Error(parsed.data.message);
|
||||
}
|
||||
|
||||
const parsedPayload = GetUserSchema.safeParse(parsed.data.payload);
|
||||
|
||||
if (!parsedPayload.success) {
|
||||
throw new Error('API response payload validation failed.');
|
||||
}
|
||||
|
||||
return parsedPayload.data;
|
||||
};
|
||||
|
||||
export const sendUpdatePasswordRequest: SendUpdatePasswordRequest = async (data) => {
|
||||
const response = await fetch('/api/users/edit-password', {
|
||||
body: JSON.stringify(data),
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export const sendUserFollowRequest: SendUserFollowRequest = async ({ userId }) => {
|
||||
const response = await fetch(`/api/users/${userId}/follow-user`, { method: 'POST' });
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('Invalid API response.');
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export const validateEmailRequest: ValidateEmailRequest = async ({ email }) => {
|
||||
const response = await fetch(`/api/users/check-email?email=${email}`);
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parsedPayload = z
|
||||
.object({ emailIsTaken: z.boolean() })
|
||||
.safeParse(parsed.data.payload);
|
||||
|
||||
if (!parsedPayload.success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !parsedPayload.data.emailIsTaken;
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
import GetUserSchema from '@/services/users/auth/schema/GetUserSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface SendEditUserRequestArgs {
|
||||
user: z.infer<typeof GetUserSchema>;
|
||||
data: {
|
||||
username: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
};
|
||||
}
|
||||
|
||||
const sendEditUserRequest = async ({ user, data }: SendEditUserRequestArgs) => {
|
||||
const response = await fetch(`/api/users/${user!.id}`, {
|
||||
body: JSON.stringify(data),
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
return parsed;
|
||||
};
|
||||
|
||||
export default sendEditUserRequest;
|
||||
@@ -1,24 +0,0 @@
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
const sendForgotPasswordRequest = async (email: string) => {
|
||||
const response = await fetch('/api/users/forgot-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Something went wrong and we couldn't send the reset link.");
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error(parsed.error.message);
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export default sendForgotPasswordRequest;
|
||||
@@ -1,31 +0,0 @@
|
||||
import { BasicUserInfoSchema } from '@/config/auth/types';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
const sendLoginUserRequest = async (data: { username: string; password: string }) => {
|
||||
const response = await fetch('/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const json: unknown = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed');
|
||||
}
|
||||
|
||||
if (!parsed.data.success) {
|
||||
throw new Error(parsed.data.message);
|
||||
}
|
||||
const parsedPayload = BasicUserInfoSchema.safeParse(parsed.data.payload);
|
||||
if (!parsedPayload.success) {
|
||||
throw new Error('API response payload validation failed');
|
||||
}
|
||||
|
||||
return parsedPayload.data;
|
||||
};
|
||||
|
||||
export default sendLoginUserRequest;
|
||||
@@ -1,33 +0,0 @@
|
||||
import { CreateUserValidationSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import GetUserSchema from '@/services/users/auth/schema/GetUserSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
async function sendRegisterUserRequest(data: z.infer<typeof CreateUserValidationSchema>) {
|
||||
const response = await fetch('/api/users/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
if (!parsed.data.success) {
|
||||
throw new Error(parsed.data.message);
|
||||
}
|
||||
|
||||
const parsedPayload = GetUserSchema.safeParse(parsed.data.payload);
|
||||
|
||||
if (!parsedPayload.success) {
|
||||
throw new Error('API response payload validation failed.');
|
||||
}
|
||||
|
||||
return parsedPayload.data;
|
||||
}
|
||||
|
||||
export default sendRegisterUserRequest;
|
||||
@@ -1,26 +0,0 @@
|
||||
import { UpdatePasswordSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
const sendUpdatePasswordRequest = async (data: z.infer<typeof UpdatePasswordSchema>) => {
|
||||
const response = await fetch('/api/users/edit-password', {
|
||||
body: JSON.stringify(data),
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('API response validation failed.');
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
};
|
||||
|
||||
export default sendUpdatePasswordRequest;
|
||||
@@ -1,16 +0,0 @@
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
const sendUserFollowRequest = async (userId: string) => {
|
||||
const response = await fetch(`/api/users/${userId}/follow-user`, { method: 'POST' });
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new Error('Invalid API response.');
|
||||
}
|
||||
|
||||
return parsed;
|
||||
};
|
||||
|
||||
export default sendUserFollowRequest;
|
||||
41
src/requests/users/auth/types/index.ts
Normal file
41
src/requests/users/auth/types/index.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { BasicUserInfoSchema } from '@/config/auth/types';
|
||||
import {
|
||||
CreateUserValidationSchema,
|
||||
UpdatePasswordSchema,
|
||||
} from '@/services/users/auth/schema/CreateUserValidationSchemas';
|
||||
import GetUserSchema from '@/services/users/auth/schema/GetUserSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
export type SendEditUserRequest = (args: {
|
||||
user: z.infer<typeof GetUserSchema>;
|
||||
data: {
|
||||
username: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
};
|
||||
}) => Promise<z.infer<typeof APIResponseValidationSchema>>;
|
||||
|
||||
export type SendForgotPasswordRequest = (args: {
|
||||
email: string;
|
||||
}) => Promise<z.infer<typeof APIResponseValidationSchema>>;
|
||||
|
||||
export type SendLoginUserRequest = (args: {
|
||||
username: string;
|
||||
password: string;
|
||||
}) => Promise<z.infer<typeof BasicUserInfoSchema>>;
|
||||
|
||||
export type SendRegisterUserRequest = (
|
||||
args: z.infer<typeof CreateUserValidationSchema>,
|
||||
) => Promise<z.infer<typeof GetUserSchema>>;
|
||||
|
||||
export type SendUpdatePasswordRequest = (
|
||||
args: z.infer<typeof UpdatePasswordSchema>,
|
||||
) => Promise<z.infer<typeof APIResponseValidationSchema>>;
|
||||
|
||||
export type SendUserFollowRequest = (args: {
|
||||
userId: string;
|
||||
}) => Promise<z.infer<typeof APIResponseValidationSchema>>;
|
||||
|
||||
export type ValidateEmailRequest = (args: { email: string }) => Promise<boolean>;
|
||||
@@ -1,25 +0,0 @@
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
const validateEmailRequest = async (email: string) => {
|
||||
const response = await fetch(`/api/users/check-email?email=${email}`);
|
||||
const json = await response.json();
|
||||
|
||||
const parsed = APIResponseValidationSchema.safeParse(json);
|
||||
|
||||
if (!parsed.success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parsedPayload = z
|
||||
.object({ emailIsTaken: z.boolean() })
|
||||
.safeParse(parsed.data.payload);
|
||||
|
||||
if (!parsedPayload.success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !parsedPayload.data.emailIsTaken;
|
||||
};
|
||||
|
||||
export default validateEmailRequest;
|
||||
@@ -1,4 +1,4 @@
|
||||
import validateEmailRequest from '@/requests/users/auth/validateEmailRequest';
|
||||
import { validateEmailRequest } from '@/requests/users/auth';
|
||||
import validateUsernameRequest from '@/requests/users/profile/validateUsernameRequest';
|
||||
import sub from 'date-fns/sub';
|
||||
import { z } from 'zod';
|
||||
@@ -60,7 +60,7 @@ export const CreateUserValidationSchemaWithUsernameAndEmailCheck =
|
||||
email: z
|
||||
.string()
|
||||
.email({ message: 'Email must be a valid email address.' })
|
||||
.refine(async (email) => validateEmailRequest(email), {
|
||||
.refine(async (email) => validateEmailRequest({ email }), {
|
||||
message: 'Email is already taken.',
|
||||
}),
|
||||
username: z
|
||||
|
||||
Reference in New Issue
Block a user