Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 로그인/회원가입 폼에 react-hook-form 적용 #223

Merged
merged 10 commits into from
Jun 23, 2024
2 changes: 1 addition & 1 deletion src/home/components/SignupContents/SignupContents.style.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components';

export const StyledSignupContentContainer = styled.div`
export const StyledSignupContentContainer = styled.form`
width: 100%;
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ export interface SignupFormProps {
onConfirm: () => void;
email: string;
}

export interface SignupFormStates {
nickname: string;
password: string;
}
56 changes: 33 additions & 23 deletions src/home/components/SignupContents/SignupForm/SignupForm.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,71 @@
import { BoxButton, PasswordTextField, SimpleTextField } from '@yourssu/design-system-react';
import { useForm } from 'react-hook-form';

import { SignupFormProps } from '@/home/components/SignupContents/SignupForm/SignUpForm.type.ts';
import { useSignUpForm } from '@/home/components/SignupContents/SignupForm/useSignUpForm.ts';
import { usePreventDuplicateClick } from '@/hooks/usePreventDuplicateClick.ts';
import { useSignupFormValidation } from '@/hooks/useSignupFormValidator.ts';
import {
SignupFormProps,
SignupFormStates,
} from '@/home/components/SignupContents/SignupForm/SignUpForm.type.ts';

import {
StyledSignupButtonText,
StyledSignupContentContainer,
StyledSignupContentTitle,
} from '../SignupContents.style';

import { useSignupFormConfirm } from './useSignupFormConfirm';
import { useSignupFormValidation } from './useSignupFormValidation';

export const SignupForm = ({ email, onConfirm }: SignupFormProps) => {
const { nickname, password, onFormConfirm, setNickname, setPassword } = useSignUpForm({
email,
onConfirm,
const { register, handleSubmit, setValue, watch, formState } = useForm<SignupFormStates>({
defaultValues: {
nickname: '',
password: '',
},
});

const { nicknameValidOnce, passwordValidOnce, isFormValid, isNicknameValid, isPasswordValid } =
useSignupFormValidation(nickname, password);
const onFormConfirm = useSignupFormConfirm({ email, onConfirm });

const { disabled, handleClick } = usePreventDuplicateClick();
const { nicknameValidOnce, passwordValidOnce, isFormValid, isNicknameValid, isPasswordValid } =
useSignupFormValidation({
nickname: watch('nickname'),
password: watch('password'),
});
Comment on lines -15 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/react-hook-form/resolvers RHF에 resolver를 사용할 수도 있습니다 ㅎㅎ


return (
<StyledSignupContentContainer>
<StyledSignupContentContainer onSubmit={handleSubmit(onFormConfirm)}>
<StyledSignupContentTitle>회원가입</StyledSignupContentTitle>
<SimpleTextField
value={nickname}
{...register('nickname', {
onChange: () => {
if (isNicknameValid) nicknameValidOnce.current = true;
},
})}
fieldLabel="사용할 닉네임을 입력해주세요."
helperLabel="한글, 영어, 숫자를 사용해 2~12자로 입력해주세요"
placeholder="ppushoong"
isNegative={!isNicknameValid && nicknameValidOnce.current}
onChange={(e) => {
if (isNicknameValid) nicknameValidOnce.current = true;
setNickname(e.target.value);
}}
onClickClearButton={() => {
nicknameValidOnce.current = false;
setNickname('');
setValue('nickname', '');
}}
/>
<PasswordTextField
{...register('password', {
onChange: () => {
if (isPasswordValid) passwordValidOnce.current = true;
},
})}
fieldLabel="사용할 비밀번호를 입력해주세요."
helperLabel="숫자, 영문자, 특수문자 조합으로 8자 이상 입력해주세요"
placeholder="비밀번호"
isNegative={!isPasswordValid && passwordValidOnce.current}
onChange={(e) => {
if (isPasswordValid) passwordValidOnce.current = true;
setPassword(e.target.value);
}}
/>
<BoxButton
type="submit"
rounding={8}
size="large"
variant="filled"
onClick={() => handleClick(onFormConfirm)}
disabled={!isFormValid || disabled}
disabled={!isFormValid || formState.isSubmitting}
>
<StyledSignupButtonText>회원가입</StyledSignupButtonText>
</BoxButton>
Expand Down
43 changes: 0 additions & 43 deletions src/home/components/SignupContents/SignupForm/useSignUpForm.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { AxiosError } from 'axios';
import { SubmitHandler } from 'react-hook-form';

import { STORAGE_KEYS } from '@/constants/storage.constant';
import { postAuthSignUp } from '@/home/apis/postAuthSignUp';
import { AuthErrorData } from '@/home/types/Auth.type';

import { SignupFormProps, SignupFormStates } from './SignUpForm.type';

export const useSignupFormConfirm = ({ email, onConfirm }: SignupFormProps) => {
const onSignupError = (error: AxiosError) => {
alert(
(error as AxiosError<AuthErrorData>).response?.data.message || '회원가입에 실패했습니다.'
);
};

const onSignupSuccess = () => {
sessionStorage.removeItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN);
sessionStorage.removeItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN_EXPIRED_IN);
onConfirm();
};

const onFormConfirm: SubmitHandler<SignupFormStates> = async ({ nickname, password }) => {
const sessionToken = sessionStorage.getItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN);

if (!sessionToken) {
alert('세션 토큰이 없습니다.');
return;
}

const signUpParams = {
nickName: nickname,
password: password,
sessionToken: sessionToken,
email: email,
};

const { data, error } = await postAuthSignUp(signUpParams);

if (data) onSignupSuccess();
else if (error) onSignupError(error);
};

return onFormConfirm;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { useMemo, useRef } from 'react';

import { hasNumberAndEnglishWithSymbols, hasNumberOrEnglishOrHangulOrSpace } from '@yourssu/utils';

export const useSignupFormValidation = (nickname: string, password: string) => {
import { SignupFormStates } from './SignUpForm.type';

export const useSignupFormValidation = ({ nickname, password }: SignupFormStates) => {
const nicknameValidOnce = useRef(false);
const passwordValidOnce = useRef(false);

Expand Down