Skip to content

Commit

Permalink
feat: zod를 이용한 유효성 검사를 추가합니다.
Browse files Browse the repository at this point in the history
  • Loading branch information
Zero-1016 committed May 23, 2024
1 parent d4cdc2e commit b444705
Show file tree
Hide file tree
Showing 19 changed files with 250 additions and 115 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@faker-js/faker": "^8.4.1",
"@hookform/resolvers": "^3.4.2",
"@lottiefiles/react-lottie-player": "^3.5.3",
"@mswjs/http-middleware": "^0.10.1",
"@mui/icons-material": "^5.15.15",
Expand All @@ -37,9 +38,11 @@
"next": "14.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.5",
"react-intersection-observer": "^9.10.0",
"react-youtube": "^10.1.0",
"sass": "^1.75.0"
"sass": "^1.75.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.1.4",
Expand Down
30 changes: 30 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/features/auth/hook/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { useSignInForm } from './use-sign-in-form'
export { useSignUpForm } from './use-sign-up-form'
30 changes: 30 additions & 0 deletions src/features/auth/hook/use-sign-in-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client'

import { zodResolver } from '@hookform/resolvers/zod'
import { SubmitHandler, useForm } from 'react-hook-form'
import { z } from 'zod'

import { signInFormSchema } from '@/features/auth/schema'

type SignInFormSchema = z.infer<typeof signInFormSchema>

export function useSignInForm() {
const onSubmit: SubmitHandler<SignInFormSchema> = data => {
console.info('로그인을 시도합니다', data)
}

const {
handleSubmit,
formState: { errors, isSubmitting },
register,
} = useForm<SignInFormSchema>({
resolver: zodResolver(signInFormSchema),
mode: 'onSubmit',
defaultValues: {
email: '',
password: '',
},
})

return { handleSubmit: handleSubmit(onSubmit), errors, register, isSubmitting }
}
31 changes: 31 additions & 0 deletions src/features/auth/hook/use-sign-up-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client'

import { zodResolver } from '@hookform/resolvers/zod'
import { SubmitHandler, useForm } from 'react-hook-form'
import { z } from 'zod'

import { signUpFormSchema } from '@/features/auth/schema'

type SignUpFormSchema = z.infer<typeof signUpFormSchema>

export function useSignUpForm() {
const onSubmit: SubmitHandler<SignUpFormSchema> = data => {
console.info('회원가입을 시도합니다.', data)
}

const {
handleSubmit,
formState: { errors },
register,
} = useForm<z.infer<typeof signUpFormSchema>>({
resolver: zodResolver(signUpFormSchema),
defaultValues: {
email: '',
password: '',
confirmPassword: '',
nickname: '',
},
})

return { handleSubmit: handleSubmit(onSubmit), errors, register }
}
2 changes: 2 additions & 0 deletions src/features/auth/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { signInFormSchema } from './sign-in-form-schema'
export { signUpFormSchema } from './sign-up-form-schema'
8 changes: 8 additions & 0 deletions src/features/auth/schema/sign-in-form-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from 'zod'

import { email, password } from './user-schema'

export const signInFormSchema = z.object({
email,
password,
})
15 changes: 15 additions & 0 deletions src/features/auth/schema/sign-up-form-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { z } from 'zod'

import { email, nickname, password } from './user-schema'

export const signUpFormSchema = z
.object({
nickname,
email,
password,
confirmPassword: password,
})
.refine(data => data.password === data.confirmPassword, {
message: '비밀번호가 일치하지 않습니다.',
path: ['confirmPassword'],
})
13 changes: 13 additions & 0 deletions src/features/auth/schema/user-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { z } from 'zod'

export const email = z.string().email({ message: '이메일 형식에 맞춰 작성해주세요' })

export const nickname = z
.string()
.min(2, { message: '최소 2글자 이상의 닉네임을 작성해주세요' })
.max(6, { message: '최소 6글자 미만의 닉네임을 작성해주세요' })

export const password = z
.string()
.min(6, { message: '최소 6글자 이상의 비밀번호를 작성해주세요' })
.max(20, { message: '최대 20글자 이하의 비밀번호를 작성해주세요' })
27 changes: 0 additions & 27 deletions src/features/auth/ui/ConfirmField.tsx

This file was deleted.

34 changes: 16 additions & 18 deletions src/features/auth/ui/SignInForm.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
'use client'

import { KeyRound, Mail } from 'lucide-react'
import { ChangeEventHandler, useState } from 'react'

import { TextFiled } from '@/shared/ui/TextFiled'
import { useSignInForm } from '@/features/auth/hook'
import { TextFiled } from '@/shared/ui'

import styles from './SignForm.module.scss'
import { SubmitButton } from './SubmitButton'

export function SignInForm() {
const [id, setId] = useState(() => '')
const [pw, setPw] = useState(() => '')
const { handleSubmit, register, errors, isSubmitting } = useSignInForm()

const onIdChange: ChangeEventHandler<HTMLInputElement> = e => {
setId(e.target.value)
}

const onPasswordChange: ChangeEventHandler<HTMLInputElement> = e => {
setPw(e.target.value)
}
return (
<form className={styles.form}>
<TextFiled name={'email'} placeholder="Email" value={id} onChange={onIdChange} icon={<Mail color="#475069" />} />
<form onSubmit={handleSubmit} className={styles.form}>
<TextFiled
type="email"
placeholder="Email"
error={errors['email']}
icon={<Mail color="#475069" />}
{...register('email')}
/>
<TextFiled
name={'pw'}
placeholder="password"
value={pw}
onChange={onPasswordChange}
type="password"
placeholder="Password"
{...register('password')}
error={errors['password']}
icon={<KeyRound color="#475069" />}
/>
<SubmitButton>Login</SubmitButton>
<SubmitButton disabled={isSubmitting}>Login</SubmitButton>
</form>
)
}
63 changes: 16 additions & 47 deletions src/features/auth/ui/SignUpForm.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,16 @@
'use client'

import { KeyRound, KeySquare, Mail, UserRound } from 'lucide-react'
import { ChangeEventHandler, useState } from 'react'
import { useState } from 'react'

import { TextFiled } from '@/shared/ui/TextFiled'
import { useSignUpForm } from '@/features/auth/hook'
import { ConfirmField, TextFiled } from '@/shared/ui'

import { ConfirmField } from './ConfirmField'
import styles from './SignForm.module.scss'
import { SubmitButton } from './SubmitButton'

export function SignUpForm() {
const [nickname, setNickname] = useState(() => '')
const [email, setEmail] = useState(() => '')
const [pw, setPw] = useState(() => '')
const [confirmPw, setConfirmPw] = useState(() => '')
const [checked, setChecked] = useState([false, false])

const onNicknameChange: ChangeEventHandler<HTMLInputElement> = e => {
nickNameReset()
setNickname(e.target.value)
}

const onEmailChange: ChangeEventHandler<HTMLInputElement> = e => {
emailReset()
setEmail(e.target.value)
}

const onPasswordChange: ChangeEventHandler<HTMLInputElement> = e => {
setPw(e.target.value)
}

const onConfirmPasswordChange: ChangeEventHandler<HTMLInputElement> = e => {
setConfirmPw(e.target.value)
}

const nickNameChecked = (newState: boolean) => {
setChecked(prevState => [newState, prevState[1]])
}
Expand All @@ -50,48 +27,40 @@ export function SignUpForm() {
emailChecked(true)
}

const nickNameReset = () => {
nickNameChecked(false)
}
const { handleSubmit, register, errors } = useSignUpForm()

const emailReset = () => {
emailChecked(false)
}
return (
<form className={styles.form}>
<form className={styles.form} onSubmit={handleSubmit}>
<ConfirmField
disabled={checked[0]}
value={nickname}
onChange={onNicknameChange}
name="name"
btnDisabled={checked[0]}
error={errors['nickname']}
placeholder="NickName"
confirmAPIFn={nickNameApiFn}
icon={<UserRound color="#475069" />}
{...register('nickname')}
/>
<ConfirmField
disabled={checked[1]}
value={email}
onChange={onEmailChange}
name="email"
btnDisabled={checked[1]}
type="email"
error={errors['email']}
placeholder="Email"
confirmAPIFn={emailApiFn}
icon={<Mail color="#475069" />}
{...register('email')}
/>
<TextFiled
name="password"
error={errors['password']}
type="password"
placeholder="Password"
value={pw}
onChange={onPasswordChange}
icon={<KeyRound color="#475069" />}
{...register('password')}
/>
<TextFiled
name="passwordConfirm"
error={errors['confirmPassword']}
type="password"
placeholder="PasswordConfirm"
value={confirmPw}
onChange={onConfirmPasswordChange}
icon={<KeySquare color="#475069" />}
{...register('confirmPassword')}
/>
<SubmitButton disabled={!!checked.filter(value => !value).length}>Sign Up</SubmitButton>
</form>
Expand Down
1 change: 1 addition & 0 deletions src/features/search/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { searchKeywordSchema } from './search-keyword-schema'
3 changes: 3 additions & 0 deletions src/features/search/schema/search-keyword-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { z } from 'zod'

export const searchKeywordSchema = z.string().min(2, '검색의 최소 길이 (2글자)를 넘지 않습니다.')
Loading

0 comments on commit b444705

Please sign in to comment.