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: Auth Page 기능 구현 및 My Page 기능 로직 구현 #25 #26

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
103 changes: 94 additions & 9 deletions src/modal/FindPw.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,60 @@
import { useState, useEffect } from 'react';

const FindPw = () => {
const [email, setEmail] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [touched, setTouched] = useState({
email: false,
verificationCode: false,
password: false,
confirmPassword: false,
});
const [errors, setErrors] = useState({
email: '',
verificationCode: '',
password: '',
confirmPassword: '',
});
const [isFormValid, setIsFormValid] = useState(false);

const validateEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};

const validatePassword = (password: string) => {
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+=\-{};:'",.<>/?\\|[\]~`]).{8,16}$/;
return passwordRegex.test(password);
};

useEffect(() => {
const newErrors = { email: '', verificationCode: '', password: '', confirmPassword: '' };

if (touched.email && !validateEmail(email)) {
newErrors.email = '유효한 이메일을 입력하세요.';
}
if (touched.verificationCode && verificationCode.length === 0) {
newErrors.verificationCode = '인증 코드를 입력하세요.';
}
if (touched.password && !validatePassword(password)) {
newErrors.password = '비밀번호는 8자 이상 16자 이하이며, 숫자, 영문, 특수문자를 포함해야 합니다.';
}
if (touched.confirmPassword && password !== confirmPassword) {
newErrors.confirmPassword = '비밀번호가 일치하지 않습니다.';
}
setErrors(newErrors);
const isValid = !Object.values(newErrors).some((error) => error !== '');
setIsFormValid(isValid);
}, [email, verificationCode, password, confirmPassword, touched]);

const handleChangePassword = () => {
if (isFormValid) {
-console.log('비밀번호 찾기 성공');
}
};

return (
<div className="flex items-center justify-center w-screen h-screen bg-Dark_Layout-100 bg-opacity-60">
<div className="relative flex flex-col items-center w-[20.875rem] h-[40.4375rem] bg-Light_Layout-400 border-none rounded-lg rounded-15">
Expand All @@ -12,46 +68,75 @@ const FindPw = () => {
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="가입한 이메일"
value={email}
onChange={(e) => setEmail(e.target.value)}
onFocus={() => setTouched({ ...touched, email: true })}
/>
<button className="w-[4.4375rem] h-[1.1875rem] text-Light_Text_AboutMe font-pre border border-1 border-Light_Text_AboutMe rounded-lg rounded-20 text-[8px]">
<button className="flex items-center justify-center w-[4.4375rem] h-[1.1875rem] text-Light_Text_AboutMe font-pre border border-1 border-Light_Text_AboutMe rounded-lg rounded-20 text-[8px]">
인증번호 발송
</button>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="w-[16.625rem] flex justify-between mt-[0.75rem] ">
<div className="h-[0.875rem]">
<div className="w-[16.625rem] font-pre text-[7px] text-error">{touched.email && errors.email}</div>
</div>
<div className="w-[16.625rem] flex justify-between mt-[0.75rem]">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="인증 번호"
value={verificationCode}
onChange={(e) => setVerificationCode(e.target.value)}
onFocus={() => setTouched({ ...touched, verificationCode: true })}
/>
<div className="w-[3.625rem] h-[1.625rem] flex items-center justify-between">
<span className=" font-pre text-[7px] text-Dark_Text_AboutMe">02:47</span>
<button className="w-[2rem] h-[1rem] text-Button font-pre border border-1 border-Button rounded-lg rounded-20 text-[7px]">
<span className="font-pre text-[7px] text-Dark_Text_AboutMe">02:47</span>
<button className="flex items-center justify-center w-[2rem] h-[1rem] text-Button font-pre border border-1 border-Button rounded-lg rounded-20 text-[7px]">
인증
</button>
</div>
</div>
<div className="w-[16.625rem] h-[0rem] border border-1 border-Dark_Text_Contents"></div>
<div className="h-[0.875rem]">
<div className="w-[16.625rem] font-pre text-[7px] text-error">
{touched.verificationCode && errors.verificationCode}
</div>
</div>

<div className="w-[16.625rem] mt-[2.375rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="비밀번호"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onFocus={() => setTouched({ ...touched, password: true })}
/>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="w-[16.625rem] font-pre text-[7px] text-error">
8자 이상 16자 이하로 사용 가능하며 숫자, 영문, 특수문자를 포함해야 합니다.
<div className="h-[0.875rem]">
<div className="w-[16.625rem] font-pre text-[7px] text-error">{touched.password && errors.password}</div>
</div>

<div className="w-[16.625rem] mt-[2.375rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="비밀번호 확인"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
onFocus={() => setTouched({ ...touched, confirmPassword: true })}
/>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="w-[16.625rem] font-pre text-[7px] text-error">비밀번호가 일치하지 않습니다.</div>
<button className="mt-[2.5rem] w-[17.625rem] h-[2.3125rem] bg-Button font-pre font-bold text-Light_Layout-100 text-[15px] border rounded-lg rounded-10">
<div className="h-[0.875rem]">
<div className="w-[16.625rem] font-pre text-[7px] text-error">
{touched.confirmPassword && errors.confirmPassword}
</div>
</div>
<button
className={`mt-[2.5rem] w-[17.625rem] h-[2.3125rem] bg-Button font-pre font-bold text-Light_Layout-100 text-[15px] border rounded-lg rounded-10 ${!isFormValid && 'opacity-50 cursor-not-allowed}'}`}
onClick={handleChangePassword}
disabled={!isFormValid}
>
비밀번호 변경
</button>
</div>
Expand Down
104 changes: 94 additions & 10 deletions src/modal/SignUp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,65 @@
import { useState, useEffect } from 'react';

const SignUp = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [nickname, setNickname] = useState('');
const [touched, setTouched] = useState({
email: false,
password: false,
confirmPassword: false,
nickname: false,
});
const [errors, setErrors] = useState({
email: '',
password: '',
confirmPassword: '',
nickname: '',
});
const [isFormValid, setIsFormValid] = useState(false);

const validateEmail = (email: string) => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email);
};

const validatePassword = (password: string) => {
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+=\-{};:'",.<>/?\\|[\]~`]).{8,16}$/;
return passwordRegex.test(password);
};

const validateNickname = (nickname: string) => {
const nicknameRegex = /^.{2,20}$/;
return nicknameRegex.test(nickname);
};

useEffect(() => {
const newErrors = { email: '', password: '', confirmPassword: '', nickname: '' };
if (touched.email && !validateEmail(email)) {
newErrors.email = '유효한 이메일을 입력해주세요.';
}
if (touched.password && !validatePassword(password)) {
newErrors.password = '비밀번호는 8자 이상 16자 이하이며, 숫자, 영문, 특수문자를 포함해야 합니다.';
}
if (touched.confirmPassword && password !== confirmPassword) {
newErrors.confirmPassword = '비밀번호가 일치하지 않습니다.';
}
if (touched.nickname && !validateNickname(nickname)) {
newErrors.nickname = '닉네임은 2자 이상 20자 이하로 입력해주세요.';
}
setErrors(newErrors);

const isValid = !Object.values(newErrors).some((error) => error !== '');
setIsFormValid(isValid);
}, [email, password, confirmPassword, nickname, touched]);

const handleSignUp = () => {
if (isFormValid) {
console.log('회원가입 성공');
}
};

return (
<div className="flex items-center justify-center w-screen h-screen bg-Dark_Layout-100 bg-opacity-60">
<div className="relative flex flex-col items-center w-[20.875rem] h-[40.4375rem] bg-Light_Layout-400 border-none rounded-lg rounded-15">
Expand All @@ -8,58 +69,81 @@ const SignUp = () => {
<h1 className="mt-[3.5rem] text-center font-pre font-bold text-Light_Text_Name text-[15px] w-[20.875rem] h-[2.125rem]">
가입하기
</h1>
<div className="mt-[4rem] w-[16.625rem] flex justify-between">
<div className="mt-[3rem] w-[16.625rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="이메일"
value={email}
onChange={(e) => setEmail(e.target.value)}
onFocus={() => setTouched({ ...touched, email: true })}
/>
<button className="w-[4.4375rem] h-[1.1875rem] text-Light_Text_AboutMe font-pre border border-1 border-Light_Text_AboutMe rounded-lg rounded-20 text-[8px]">
<button className="flex items-center justify-center w-[4.4375rem] h-[1.1875rem] text-Light_Text_AboutMe font-pre border border-1 border-Light_Text_AboutMe rounded-lg rounded-20 text-[8px]">
인증번호 발송
</button>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="h-[0.875rem]">
<div className="w-[16.625rem] text-error text-[7px]">{touched.email && errors.email}</div>
</div>
<div className="w-[16.625rem] flex justify-between mt-[0.75rem] ">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="인증 번호"
/>
<div className="w-[3.625rem] h-[1.625rem] flex items-center justify-between">
<span className=" font-pre text-[7px] text-Dark_Text_AboutMe">02:47</span>
<button className="w-[2rem] h-[1rem] text-Button font-pre border border-1 border-Button rounded-lg rounded-20 text-[7px]">
<button className="flex items-center justify-center w-[2rem] h-[1rem] text-Button font-pre border border-1 border-Button rounded-lg rounded-20 text-[7px]">
인증
</button>
</div>
</div>
<div className="w-[16.625rem] h-[0rem] border border-1 border-Dark_Text_Contents"></div>

<div className="w-[16.625rem] mt-[2rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="닉네임"
value={nickname}
onChange={(e) => setNickname(e.target.value)}
onFocus={() => setTouched({ ...touched, nickname: true })}
/>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />

<div className="h-[0.875rem]">
<div className="w-[16.625rem] text-error text-[7px]">{touched.nickname && errors.nickname}</div>
</div>
<div className="w-[16.625rem] mt-[2.375rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="비밀번호"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onFocus={() => setTouched({ ...touched, password: true })}
/>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="w-[16.625rem] font-pre text-[7px] text-error">
8자 이상 16자 이하로 사용 가능하며 숫자, 영문, 특수문자를 포함해야 합니다.
<div className="h-[0.875rem]">
<div className="w-[16.625rem] text-error text-[7px]">{touched.password && errors.password}</div>
</div>

<div className="w-[16.625rem] mt-[2.375rem] flex justify-between">
<input
className="font-bold font-pre text-Light_Text_Name placeholder-Dark_Text_Contents text-[12px]"
placeholder="비밀번호 확인"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
onFocus={() => setTouched({ ...touched, confirmPassword: true })}
/>
</div>
<div className="w-[16.625rem] h-[0rem] mt-[0.375rem] border border-1 border-Dark_Text_Contents" />
<div className="w-[16.625rem] font-pre text-[7px] text-error">비밀번호가 일치하지 않습니다.</div>
<button className="mt-[2.5rem] w-[17.625rem] h-[2.3125rem] bg-Button font-pre font-bold text-Light_Layout-100 text-[15px] border rounded-lg rounded-10">
<div className="h-[0.875rem]">
<div className="w-[16.625rem] text-error text-[7px]">{touched.confirmPassword && errors.confirmPassword}</div>
</div>
<button
className={`mt-[2.5rem] w-[17.625rem] h-[2.3125rem] bg-Button font-pre font-bold text-Light_Layout-100 text-[15px] border rounded-lg rounded-10 ${!isFormValid && 'opacity-50 cursor-not-allowed'}`}
onClick={handleSignUp}
disabled={!isFormValid}
>
회원가입
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/mypage/BlockAccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const BlockAccountPage = () => {
닉네임 뭐하지
</div>
<button className="w-[5.75rem] h-[1.5625rem] bg-Light_Layout-100 font-pre text-Light_Text_AboutMe text-[0.8rem] rounded-[1.5625rem]">
변경
해제
</button>
</div>
</div>
Expand Down
Loading