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

Feat: #35 ID/PW 찾기 페이지 UI 작성 및 Validation 체크 #58

Merged
merged 11 commits into from
Aug 5, 2024
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9,007 changes: 9,007 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/components/common/ValidationInput.tsx
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ export default function ValidationInput({
{isButtonInput && (
<button
type="button"
className="flex h-20 w-75 items-center justify-center rounded bg-sub px-8 font-bold shadow-md"
className="flex h-20 w-75 items-center justify-center rounded bg-sub px-8 font-bold"
onClick={onButtonClick}
>
{buttonLabel}
18 changes: 18 additions & 0 deletions src/components/user/authForm/AuthForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { FormEvent, ReactNode } from 'react';

type AuthFormProps = {
children: ReactNode;
onSubmit: (e: FormEvent<HTMLFormElement>) => void;
};

export default function AuthForm({ children, onSubmit }: AuthFormProps) {
return (
<form onSubmit={onSubmit} className="flex h-screen w-300 flex-col py-30">
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
<section className="h-1/6 text-large text-main">
Welcome to our site!
<br /> Grow Up your Life with us.
</section>
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
<section className="auth-form-section">{children}</section>
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
</form>
);
}
65 changes: 65 additions & 0 deletions src/components/user/authForm/FooterLinks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useNavigate } from 'react-router-dom';

type FooterLinksProps = {
type: 'signIn' | 'searchId' | 'searchPassword';
};

export default function FooterLinks({ type }: FooterLinksProps) {
const nav = useNavigate();

const renderLinks = () => {
switch (type) {
case 'signIn':
return (
<>
<button type="button" className="inherit-btn" onClick={() => nav('/search/id')}>
아이디 찾기
</button>
<p>|</p>
<button type="button" className="inherit-btn" onClick={() => nav('/search/password')}>
비밀번호 찾기
</button>
</>
);
case 'searchId':
return (
<>
<button type="button" className="inherit-btn" onClick={() => nav('/signin')}>
로그인
</button>
<p>|</p>
<button type="button" className="inherit-btn" onClick={() => nav('/search/password')}>
비밀번호 찾기
</button>
</>
);
case 'searchPassword':
return (
<>
<button type="button" className="inherit-btn" onClick={() => nav('/signin')}>
로그인
</button>
<p>|</p>
<button type="button" className="inherit-btn" onClick={() => nav('/search/id')}>
아이디 찾기
</button>
</>
);
default:
return null;
}
};
Seok93 marked this conversation as resolved.
Show resolved Hide resolved

return (
<>
<div className="flex flex-row justify-center gap-8">{renderLinks()}</div>

<div className="mb-35 mt-15 flex flex-row items-center justify-center gap-8">
<p className="items-center font-bold">회원이 아니신가요?</p>
<button type="button" className="auth-btn" onClick={() => nav('/signup')}>
회원가입
</button>
</div>
</>
);
}
3 changes: 3 additions & 0 deletions src/constants/formValidationRules.ts
Original file line number Diff line number Diff line change
@@ -64,4 +64,7 @@ export const STATUS_VALIDATION_RULES = deepFreeze({
PASSWORD_CONFIRM: () => ({
required: '비밀번호를 한 번 더 입력해 주세요.',
}),
ID: () => ({
required: '아이디를 입력해 주세요.',
}),
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
});
15 changes: 12 additions & 3 deletions src/globals.css
Original file line number Diff line number Diff line change
@@ -87,11 +87,20 @@
@apply absolute left-0 top-0 block h-30 w-3 bg-main content-[''];
}

/* Auth Styles */
.auth-form-section {
@apply flex flex-grow flex-col justify-center gap-8;
}

Seok93 marked this conversation as resolved.
Show resolved Hide resolved
.auth-btn {
@apply flex h-30 items-center justify-center rounded-lg bg-sub px-8 font-bold;
@apply flex h-30 cursor-pointer items-center justify-center rounded-lg bg-sub px-8 font-bold;
}

.inherit-btn {
@apply cursor-pointer bg-inherit font-bold;
}

.auth-input {
@apply h-30 flex-grow rounded-lg border border-input px-8 text-sm outline-none placeholder:text-emphasis;
.centered-flex-col {
@apply flex flex-col text-center;
}
}
53 changes: 52 additions & 1 deletion src/pages/user/SearchIdPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
import { useForm } from 'react-hook-form';
import ValidationInput from '@/components/common/ValidationInput';
import { STATUS_VALIDATION_RULES } from '@/constants/formValidationRules';
import { SearchIDForm } from '@/types/UserType';
import AuthForm from '@/components/user/authForm/AuthForm';
import FooterLinks from '@/components/user/authForm/FooterLinks';

export default function SearchIdPage() {
return <div>SearchIdPage</div>;
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<SearchIDForm>({
mode: 'onChange',
defaultValues: {
email: '',
code: '',
},
});

const onSubmit = (data: SearchIDForm) => {
console.log(data);
};

return (
<AuthForm onSubmit={handleSubmit(onSubmit)}>
<section className="auth-form-section">
{/* 이메일 */}
<ValidationInput
isButtonInput
buttonLabel="인증번호 발송"
placeholder="이메일"
errors={errors.email?.message}
register={register('email', STATUS_VALIDATION_RULES.EMAIL())}
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
/>

{/* 이메일 인증 */}
<ValidationInput
placeholder="인증번호"
errors={errors.code?.message}
register={register('code', STATUS_VALIDATION_RULES.CERTIFICATION())}
/>

<div className="centered-flex-col">
<button type="submit" className="auth-btn" disabled={isSubmitting}>
아이디 찾기
</button>
</div>

<FooterLinks type="searchId" />
</section>
</AuthForm>
);
}
61 changes: 60 additions & 1 deletion src/pages/user/SearchPasswordPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
import { useForm } from 'react-hook-form';
import ValidationInput from '@/components/common/ValidationInput';
import { STATUS_VALIDATION_RULES } from '@/constants/formValidationRules';
import AuthForm from '@/components/user/authForm/AuthForm';
import FooterLinks from '@/components/user/authForm/FooterLinks';
import { SearchPasswordForm } from '@/types/UserType';

export default function SearchPasswordPage() {
return <div>SearchPasswordPage</div>;
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<SearchPasswordForm>({
mode: 'onChange',
defaultValues: {
id: '',
email: '',
code: '',
},
});

const onSubmit = (data: SearchPasswordForm) => {
console.log(data);
};

return (
<AuthForm onSubmit={handleSubmit(onSubmit)}>
<section className="auth-form-section">
{/* 아이디 */}
<ValidationInput
placeholder="아이디"
errors={errors.id?.message}
register={register('id', STATUS_VALIDATION_RULES.ID())}
/>

{/* 이메일 */}
<ValidationInput
isButtonInput
buttonLabel="인증번호 발송"
placeholder="이메일"
errors={errors.email?.message}
register={register('email', STATUS_VALIDATION_RULES.EMAIL())}
/>

{/* 이메일 인증 */}
<ValidationInput
placeholder="인증번호"
errors={errors.code?.message}
register={register('code', STATUS_VALIDATION_RULES.CERTIFICATION())}
/>

<div className="centered-flex-col">
<button type="submit" className="auth-btn" disabled={isSubmitting}>
비밀번호 찾기
</button>
</div>

<FooterLinks type="searchPassword" />
</section>
</AuthForm>
Seok93 marked this conversation as resolved.
Show resolved Hide resolved
);
}
54 changes: 17 additions & 37 deletions src/pages/user/SignInPage.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,37 @@
import { useNavigate } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import Kakao from '@assets/social_kakao_icon.svg';
import Google from '@assets/social_google_icon.svg';
import { UserSignIn } from '@/types/UserType';
import { UserSignInForm } from '@/types/UserType';
import ValidationInput from '@/components/common/ValidationInput';
import { STATUS_VALIDATION_RULES } from '@/constants/formValidationRules';
import AuthForm from '@/components/user/authForm/AuthForm';
import FooterLinks from '@/components/user/authForm/FooterLinks';

export default function SignInPage() {
const nav = useNavigate();
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm({
mode: 'onChange',
defaultValues: {
email: '',
id: '',
password: '',
},
});

const onSubmit = (data: UserSignIn) => {
const onSubmit = (data: UserSignInForm) => {
console.log(data);
};

return (
<form onSubmit={handleSubmit(onSubmit)} noValidate className="flex h-screen w-300 flex-col py-30">
<section className="h-1/6 text-large text-main">
Welcome to our site!
<br /> Grow Up your Life with us.
</section>

<section className="flex flex-grow flex-col justify-center gap-8">
{/* 이메일(아이디) */}
<AuthForm onSubmit={handleSubmit(onSubmit)}>
<section className="auth-form-section">
{/* 아이디 */}
<ValidationInput
placeholder="이메일"
errors={errors.email?.message}
register={register('email', STATUS_VALIDATION_RULES.EMAIL())}
placeholder="아이디"
errors={errors.id?.message}
register={register('id', STATUS_VALIDATION_RULES.ID())}
/>

{/* 비밀번호 */}
@@ -47,44 +42,29 @@ export default function SignInPage() {
register={register('password', STATUS_VALIDATION_RULES.PASSWORD())}
/>

<div className="flex flex-col gap-4 text-center">
<div className="centered-flex-col">
<button type="submit" className="auth-btn" disabled={isSubmitting}>
로그인
</button>
</div>

<div className="flex flex-row justify-center gap-8">
<button type="button" className="cursor-pointer bg-inherit font-bold" onClick={() => nav('/search/id')}>
아이디 찾기
</button>
<p>|</p>
<button type="button" className="cursor-pointer bg-inherit font-bold" onClick={() => nav('/search/password')}>
비밀번호 찾기
</button>
</div>

<div className="mb-35 mt-15 flex flex-row items-center justify-center gap-8">
<p className="items-center font-bold">회원이 아니신가요?</p>
<button type="button" className="auth-btn" onClick={() => nav('/signup')}>
회원가입
</button>
</div>
<FooterLinks type="signIn" />
</section>

<section className="flex h-1/6 flex-col gap-4 text-center">
<section className="flex h-1/6 flex-col gap-8 text-center">
<button type="button" className="auth-btn bg-kakao" disabled={isSubmitting}>
<div className="flex w-81 items-center justify-between">
<div className="flex h-30 w-81 items-center justify-between">
<img src={Kakao} alt="Kakao" className="size-15" />
카카오 로그인
</div>
</button>
<button type="button" className="auth-btn bg-button" disabled={isSubmitting}>
<div className="flex w-81 items-center justify-between">
<div className="flex h-30 w-81 items-center justify-between">
<img src={Google} alt="Google" className="size-42" />
로그인
</div>
</button>
</section>
</form>
</AuthForm>
);
}
3 changes: 2 additions & 1 deletion src/pages/user/SignUpPage.tsx
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ export default function SignUpPage() {
} = useForm<UserSignUp>({
mode: 'onChange',
defaultValues: {
id: '',
image: [], // 추후 이미지 전송 폼 분리 예정
email: '',
emailVerificationCode: '',
@@ -242,7 +243,7 @@ export default function SignUpPage() {
</div>

{/* 회원가입 버튼 */}
<div className="flex flex-col gap-4 text-center">
<div className="centered-flex-col gap-8">
<button
type="submit"
className="flex h-30 items-center justify-center rounded-lg bg-sub px-8 font-bold"
18 changes: 13 additions & 5 deletions src/types/UserType.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// 회원가입, 로그인 시 필요한 유저 타입 정의
export type UserSignIn = {
email: string;
export type UserSignInForm = {
id: string;
password: string;
};

export type UserSignUpForm = UserSignIn & {
export type UserSignUpForm = UserSignInForm & {
email: string;
image: File[];
password: string;
nickname: string;
@@ -19,6 +20,13 @@ export type UserSignUp = UserSignUpForm & {
checkPassword: string;
};

export type UserSearchIdForm = {
phone: string;
export type SearchIDForm = {
email: string;
code: string;
};

export type SearchPasswordForm = {
id: string;
email: string;
code: string;
};
Loading