diff --git a/public/assets/google_icon.png b/public/assets/google_icon.png new file mode 100644 index 000000000..9a8f6902d Binary files /dev/null and b/public/assets/google_icon.png differ diff --git a/public/assets/naver_icon.png b/public/assets/naver_icon.png new file mode 100644 index 000000000..8a3a31f44 Binary files /dev/null and b/public/assets/naver_icon.png differ diff --git a/src/constants/message-constants.ts b/src/constants/message-constants.ts index 0bdb800bb..5d38e2598 100644 --- a/src/constants/message-constants.ts +++ b/src/constants/message-constants.ts @@ -5,11 +5,15 @@ export const AUTH_MESSAGE = { EMAIL_INVALID: '올바른 이메일 형식이어야 합니다.', PASSWORD_LENGTH: '비밀번호는 6자 이상이어야 합니다.', PASSWORD_SPECIAL_CHAR: '비밀번호는 최소 하나의 특수 문자를 포함해야 합니다.', + EMAIL_EMPTY_FIELD: '이메일을 입력해주세요.', + PASSWORD_EMPTY_FIELD: '비밀번호를 입력해주세요.' }, RESULT: { SIGN_UP_SUCCESS: '회원 가입에 성공했습니다.', SIGN_UP_FAILED: '회원 가입에 실패했습니다.', SIGN_UP_EXIST_ERROR: '이미 존재하는 이메일입니다.', SIGN_UP_EMPTY_FIELD: '모든 값을 입력해주세요.', + SIGN_IN_SUCCESS: '로그인에 성공했습니다.', + SIGN_IN_FAILED: '이메일 혹은 비밀번호를 확인해주세요.' }, }; diff --git a/src/features/auth/auth-input.tsx b/src/features/auth/auth-input.tsx index e017ebc3a..42e865296 100644 --- a/src/features/auth/auth-input.tsx +++ b/src/features/auth/auth-input.tsx @@ -1,18 +1,17 @@ -import { UseFormRegister } from 'react-hook-form'; -import { FormData } from './sign-up/data/schema'; +import { Path, UseFormRegister } from 'react-hook-form'; -type Props = { +type Props = { label: string; - id: keyof FormData; - register: UseFormRegister; + id: Path; + register: UseFormRegister; error?: { message?: string }; type: string; }; -const AuthInput = ({ label, id, register, error, type }: Props) => ( +const AuthInput = ({ label, id, register, error, type }: Props) => (
- +
{error &&

{error.message}

}
); diff --git a/src/features/auth/sign-up/api/client-services.ts b/src/features/auth/sign-up/api/client-services.ts index 09d3380aa..83363ac6e 100644 --- a/src/features/auth/sign-up/api/client-services.ts +++ b/src/features/auth/sign-up/api/client-services.ts @@ -1,17 +1,20 @@ import { ROUTE_HANDLER_PATH } from '@/constants/path-constant'; -type SignUpProps = { +type Props = { name: string; email: string; password: string; }; -export const postSignUp = async (sign_up_data: SignUpProps) => { +const { AUTH } = ROUTE_HANDLER_PATH; +const { SIGN_UP } = AUTH; + +export const postSignUp = async (signUpData: Props) => { try { - const res = await fetch(ROUTE_HANDLER_PATH.AUTH.SIGN_UP, { + const res = await fetch(SIGN_UP, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(sign_up_data), + body: JSON.stringify(signUpData), }); const data = await res.json(); diff --git a/src/features/auth/sign-up/data/schema.ts b/src/features/auth/sign-up/data/schema.ts index 69400e321..b6e3f6d8f 100644 --- a/src/features/auth/sign-up/data/schema.ts +++ b/src/features/auth/sign-up/data/schema.ts @@ -6,19 +6,22 @@ const NAME_VALIDATION_MAX = 8; const NAME_VALIDATION_REGEX = /^[a-zA-Z0-9가-힣]+$/; const PASSWORD_VALIDATION_MIN = 6; +const { VALIDATION } = AUTH_MESSAGE; +const { NAME_LENGTH, NAME_SPECIAL_CHAR, EMAIL_INVALID, PASSWORD_LENGTH, PASSWORD_SPECIAL_CHAR } = VALIDATION; + export const schema = z.object({ name: z .string() .trim() - .min(NAME_VALIDATION_MIN, AUTH_MESSAGE.VALIDATION.NAME_LENGTH) - .max(NAME_VALIDATION_MAX, AUTH_MESSAGE.VALIDATION.NAME_LENGTH) - .regex(NAME_VALIDATION_REGEX, AUTH_MESSAGE.VALIDATION.NAME_SPECIAL_CHAR), - email: z.string().trim().email(AUTH_MESSAGE.VALIDATION.EMAIL_INVALID), + .min(NAME_VALIDATION_MIN, NAME_LENGTH) + .max(NAME_VALIDATION_MAX, NAME_LENGTH) + .regex(NAME_VALIDATION_REGEX, NAME_SPECIAL_CHAR), + email: z.string().trim().email(EMAIL_INVALID), password: z .string() .trim() - .min(PASSWORD_VALIDATION_MIN, AUTH_MESSAGE.VALIDATION.PASSWORD_LENGTH) - .regex(/[^a-zA-Z0-9]/, AUTH_MESSAGE.VALIDATION.PASSWORD_SPECIAL_CHAR), + .min(PASSWORD_VALIDATION_MIN, PASSWORD_LENGTH) + .regex(/[^a-zA-Z0-9]/, PASSWORD_SPECIAL_CHAR), }); -export type FormData = z.infer; \ No newline at end of file +export type SignUpFormData = z.infer; diff --git a/src/features/auth/sign-up/sign-up-auth-form.tsx b/src/features/auth/sign-up/sign-up-auth-form.tsx index 335ca5a8f..6f3138e83 100644 --- a/src/features/auth/sign-up/sign-up-auth-form.tsx +++ b/src/features/auth/sign-up/sign-up-auth-form.tsx @@ -2,28 +2,28 @@ import { PATH } from '@/constants/path-constant'; import { useRouter } from 'next/navigation'; -import { postSignUp } from './api/client-services'; +import { postSignUp } from '@/features/auth/sign-up/api/client-services'; import { AUTH_MESSAGE } from '@/constants/message-constants'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import AuthInput from '@/features/auth/auth-input'; -import { FormData, schema } from './data/schema'; +import { SignUpFormData, schema } from '@/features/auth/sign-up/data/schema'; const SignUpAuthForm = () => { const { register, handleSubmit, formState: { errors }, - } = useForm({ + } = useForm({ resolver: zodResolver(schema), mode: 'onBlur', - defaultValues: { name: '', email: '', password: '' } as FormData, + defaultValues: { name: '', email: '', password: '' } as SignUpFormData, }); const router = useRouter(); - const onSubmit = async (data: FormData) => { + const onSubmit = async (data: SignUpFormData) => { try { - await postSignUp(data as Required); + await postSignUp(data as Required); router.push(PATH.AUTH.SIGN_IN); alert(AUTH_MESSAGE.RESULT.SIGN_UP_SUCCESS); } catch (error) { @@ -38,7 +38,7 @@ const SignUpAuthForm = () => {

우리 같이 취업을 향한 여정을 떠나볼까요?

원할한 서비스 이용을 위해 회원가입 해주세요.

-
+ diff --git a/src/features/auth/sing-in/data/schema.ts b/src/features/auth/sing-in/data/schema.ts new file mode 100644 index 000000000..5b596304d --- /dev/null +++ b/src/features/auth/sing-in/data/schema.ts @@ -0,0 +1,14 @@ +import { AUTH_MESSAGE } from '@/constants/message-constants'; +import { z } from 'zod'; + +const PASSWORD_VALIDATION_MIN = 1; + +const { VALIDATION } = AUTH_MESSAGE; +const { EMAIL_EMPTY_FIELD, PASSWORD_EMPTY_FIELD } = VALIDATION; + +export const schema = z.object({ + email: z.string().trim().email(EMAIL_EMPTY_FIELD), + password: z.string().trim().min(PASSWORD_VALIDATION_MIN, PASSWORD_EMPTY_FIELD), +}); + +export type SignInFormData = z.infer; diff --git a/src/features/auth/sing-in/sign-in-auth-form.tsx b/src/features/auth/sing-in/sign-in-auth-form.tsx index 27b5194b2..9d1d5282b 100644 --- a/src/features/auth/sing-in/sign-in-auth-form.tsx +++ b/src/features/auth/sing-in/sign-in-auth-form.tsx @@ -4,30 +4,40 @@ import { PATH } from '@/constants/path-constant'; import { signIn } from 'next-auth/react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; +import AuthInput from '@/features/auth/auth-input'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { schema, SignInFormData } from '@/features/auth/sing-in/data/schema'; +import Image from 'next/image'; +import { AUTH_MESSAGE } from '@/constants/message-constants'; const callback_url = `${process.env.NEXT_PUBLIC_BASE_URL}/${PATH.ON_BOARDING}`; +const { RESULT } = AUTH_MESSAGE; +const { SIGN_IN_SUCCESS, SIGN_IN_FAILED } = RESULT; + const SignInAuthForm = () => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + mode: 'onBlur', + defaultValues: { email: '', password: '' } as SignInFormData, + }); const router = useRouter(); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - const formData = new FormData(e.target as HTMLFormElement); - - const sign_in_data = { - email: String(formData.get('email')), - password: String(formData.get('password')), - }; + const onSubmit = async (data: SignInFormData) => { try { const res = await signIn('credentials', { - ...sign_in_data, + ...data, redirect: false, }); if (!res.ok) { - throw new Error('로그인에 실패했습니다.'); + throw new Error(SIGN_IN_FAILED); } else { - alert('로그인에 성공했습니다.'); + alert(SIGN_IN_SUCCESS); router.replace(PATH.ON_BOARDING); } } catch (error) { @@ -37,55 +47,46 @@ const SignInAuthForm = () => { return (
-

로그인

- -
- - -
-
- - -
+

+ 만나서 반가워요.병아리씨! +

+

우리 같이 취업을 향한 여정을 떠나볼까요?

+

원할한 서비스 이용을 위해 로그인 해주세요.

+ + + -
- 계정이 없으신가요? +
<> +
+
+ OR +
+
+ + 30초만에 회원가입하기 +
);