Skip to content

Commit 9b63c84

Browse files
authored
Merge pull request #149 from GDGoCINHA/Fix/render
Fix/render
2 parents 01f3bd6 + 27bc7f7 commit 9b63c84

27 files changed

Lines changed: 538 additions & 104 deletions

File tree

next.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const nextConfig: NextConfig = {
55
unoptimized: true,
66
},
77
trailingSlash: true,
8+
output: 'export',
89
};
910

1011
export default nextConfig;
File renamed without changes.

src/app/_auth/signin/layout.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//import { Suspense } from "react";
2+
import Header2 from '@/components/ui/common/Header2';
3+
4+
export const metadata = {
5+
title: "SignIn",
6+
description: "SignIn to your account",
7+
};
8+
9+
export default function SignInLayout({ children }) {
10+
return (
11+
<div className='min-h-screen flex flex-col overflow-hidden relative'>
12+
<Header2 />
13+
{children}
14+
</div>
15+
);
16+
}

src/app/_auth/signin/page.jsx

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { useRouter } from 'next/navigation';
5+
import Image from 'next/image';
6+
7+
import Header2 from '@/components/ui/common/Header2';
8+
import Loader from '@/components/ui/common/Loader';
9+
10+
import AuthLogin from '@/components/auth/screen/AuthLogin';
11+
import AuthFindId from '@/components/auth/screen/AuthFindId';
12+
import AuthResetPassword from '@/components/auth/screen/AuthResetPassword';
13+
import AuthResetRequest from '@/components/auth/screen/AuthResetRequest';
14+
15+
import { GoogleLogin } from '@/services/auth/signin/google/GoogleLogin';
16+
import { login } from '@/services/auth/signin/custom/CustomAuthApi';
17+
18+
import { useAuth } from '@/hooks/useAuth';
19+
20+
import loginBg from '@public/images/bgimg.png';
21+
22+
export default function Page() {
23+
const router = useRouter();
24+
const { setAccessToken } = useAuth();
25+
const { handleGoogleLogin } = GoogleLogin();
26+
27+
const [password, setPassword] = useState('');
28+
const [errors, setErrors] = useState([]);
29+
const [isRendering, setIsRendering] = useState(0);
30+
const [loading, setLoading] = useState(false);
31+
32+
const handleBackToLogin = () => setIsRendering(0);
33+
const handleFindIdClick = () => setIsRendering(1);
34+
const handleResetPasswordClick = () => setIsRendering(2);
35+
const handleBackToResetRequest = () => setIsRendering(2);
36+
const handleResetPasswordNext = () => setIsRendering(3);
37+
38+
const validatePassword = (password) => {
39+
const newErrors = [];
40+
if (password.length <= 0) {
41+
newErrors.push('비밀번호를 입력해주세요.');
42+
}
43+
return newErrors;
44+
};
45+
46+
const onSubmit = async (e) => {
47+
e.preventDefault();
48+
49+
const formData = Object.fromEntries(new FormData(e.currentTarget));
50+
const passwordErrors = validatePassword(password);
51+
52+
if (passwordErrors.length > 0) {
53+
setErrors(passwordErrors);
54+
} else {
55+
setErrors([]);
56+
57+
try {
58+
const { email, password } = formData;
59+
setLoading(true);
60+
const res = await login(email, password);
61+
const { exists, access_token } = res.data.data;
62+
63+
if (!exists) {
64+
alert('아이디 혹은 비밀번호가 올바르지 않습니다.');
65+
setLoading(false);
66+
return;
67+
}
68+
69+
setAccessToken(access_token);
70+
router.push('/main');
71+
} catch (error) {
72+
console.error('로그인 실패:', error);
73+
alert('로그인 중 오류가 발생했습니다.');
74+
setLoading(false);
75+
}
76+
}
77+
};
78+
79+
return (
80+
<>
81+
<Loader isLoading={loading} />
82+
<Image src={loginBg} alt='loginBg' fill className='absolute top-0 left-0 -z-10 object-cover opacity-70 blur-sm' />
83+
<div className='flex justify-center items-center flex-1 relative'>
84+
{/* 로그인 화면 */}
85+
<div
86+
key='screen1'
87+
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
88+
isRendering === 0 ? 'translate-x-0 opacity-100' : '-translate-x-full opacity-0'
89+
} flex justify-center items-center`}
90+
>
91+
<AuthLogin
92+
router={router}
93+
onSubmit={onSubmit}
94+
errors={errors}
95+
password={password}
96+
setPassword={setPassword}
97+
setErrors={setErrors}
98+
handleGoogleLogin={handleGoogleLogin}
99+
handleFindIdClick={handleFindIdClick}
100+
handleResetPasswordClick={handleResetPasswordClick}
101+
/>
102+
</div>
103+
104+
{/* 아이디 찾기 화면 */}
105+
<div
106+
key='screen2'
107+
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
108+
isRendering === 1 ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
109+
} flex justify-center items-center mt-[-30px]`}
110+
>
111+
<AuthFindId handleBackToLogin={handleBackToLogin} />
112+
</div>
113+
114+
{/* 비밀번호 재설정 화면 1 */}
115+
<div
116+
key='screen3'
117+
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
118+
isRendering === 2
119+
? 'translate-x-0 opacity-100'
120+
: `${isRendering === 3 ? '-translate-x-full' : 'translate-x-full'} opacity-0`
121+
} flex justify-center items-center`}
122+
>
123+
<AuthResetRequest
124+
handleNextStep={handleResetPasswordNext}
125+
handleBackToLogin={handleBackToLogin}
126+
setLoading={setLoading}
127+
/>
128+
</div>
129+
130+
{/* 비밀번호 재설정 화면 2 */}
131+
<div
132+
key='screen4'
133+
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
134+
isRendering === 3 ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
135+
} flex justify-center items-center`}
136+
>
137+
<AuthResetPassword
138+
handleBackToLogin={handleBackToLogin}
139+
handleBackToResetRequest={handleBackToResetRequest}
140+
setLoading={setLoading}
141+
/>
142+
</div>
143+
</div>
144+
</>
145+
);
146+
}

src/app/_auth/signup/layout.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//import { Suspense } from "react";
2+
import Header from "@/components/ui/common/Header";
3+
4+
export const metadata = {
5+
title: "SignUp",
6+
description: "SignUp to your account",
7+
};
8+
9+
export default function SignUpLayout({ children }) {
10+
return (
11+
<>
12+
<Header />
13+
{children}
14+
</>
15+
);
16+
}

src/app/_auth/signup/page.jsx

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
"use client"
2+
3+
import { useState, useEffect } from "react";
4+
import { useRouter } from "next/navigation";
5+
import { Button } from "@nextui-org/react";
6+
7+
import ProfileInfoForm from "@/components/auth/signup/ProfileInfoForm";
8+
import AdditionalInfoForm from "@/components/auth/signup/AdditionalInfoForm";
9+
10+
import { useAuthenticatedApi } from '@/hooks/useAuthenticatedApi.js';
11+
import usePasswordValidation from "@/hooks/usePasswordValidation";
12+
13+
export default function Signup() {
14+
const router = useRouter();
15+
const { apiClient, handLeLogout }= useAuthenticatedApi();
16+
17+
const [isLoading, setIsLoading] = useState(true);
18+
19+
// 사용자 정보 상태
20+
const [name, setName] = useState("");
21+
const [email, setEmail] = useState("");
22+
const [password, setPassword] = useState("");
23+
const [confirmPassword, setConfirmPassword] = useState("");
24+
const [isEmailValid, setIsEmailValid] = useState(false);
25+
const [major, setMajor] = useState("");
26+
const [studentId, setStudentId] = useState("");
27+
const [phoneNumber, setPhoneNumber] = useState("");
28+
29+
// 애니메이션 상태
30+
const [isAnimating, setIsAnimating] = useState(false);
31+
const [isRendering, setIsRendering] = useState(false);
32+
33+
// 필드 비활성화 상태
34+
const [isNameDisabled, setIsNameDisabled] = useState(false);
35+
const [isEmailDisabled, setIsEmailDisabled] = useState(false);
36+
37+
// 비밀번호 유효성 검사 훅 사용
38+
const { errors } = usePasswordValidation(password);
39+
40+
useEffect(() => {
41+
// localStorage에서 signup_email과 signup_name 값을 확인
42+
if (typeof window !== 'undefined') {
43+
const storedEmail = localStorage.getItem('signup_email');
44+
const storedName = localStorage.getItem('signup_name');
45+
46+
if (storedEmail) {
47+
setEmail(storedEmail);
48+
setIsEmailDisabled(true);
49+
}
50+
51+
if (storedName) {
52+
setName(storedName);
53+
setIsNameDisabled(true);
54+
}
55+
}
56+
57+
setIsLoading(false);
58+
}, []);
59+
60+
// 첫 번째 화면에서 다음 버튼 클릭 시 처리
61+
const handleNext = () => {
62+
if (!name || !email || !password || !confirmPassword) {
63+
alert("모든 칸을 채워주세요.");
64+
return;
65+
}
66+
if (password !== confirmPassword) {
67+
alert("비밀번호가 일치하지 않습니다.");
68+
return;
69+
}
70+
if(email === "pwc2002"){
71+
setIsEmailValid(true);
72+
alert("이미 가입된 이메일입니다.");
73+
return;
74+
}
75+
if(errors.length > 0){
76+
alert("비밀번호 조건을 만족해주세요.");
77+
return;
78+
}
79+
80+
// 화면 전환 애니메이션
81+
setIsRendering(true);
82+
setTimeout(() => {
83+
setIsAnimating(true);
84+
}, 100);
85+
};
86+
87+
const setMajorInfo = (value) => {
88+
setMajor(value);
89+
};
90+
91+
// 가입하기 버튼 클릭 시 처리
92+
const handleSignup = async () => {
93+
if (!major || !studentId || !phoneNumber) {
94+
alert("모든 칸을 채워주세요.");
95+
console.log(name,email,password,major,studentId,phoneNumber);
96+
return;
97+
}
98+
99+
// 회원가입 정보 객체 생성
100+
const userinfo = {
101+
name: name,
102+
email: email,
103+
password: password,
104+
major: major,
105+
studentId: studentId,
106+
phoneNumber: phoneNumber
107+
}
108+
109+
try {
110+
const res = await apiClient.post('/auth/signup', userinfo);
111+
console.log(res);
112+
} catch (error) {
113+
console.log(error);
114+
}
115+
116+
// 홈으로 리디렉션
117+
router.push("/");
118+
};
119+
120+
// 로딩 상태 처리
121+
if (isLoading) {
122+
return (
123+
<div className="flex flex-col w-full items-center justify-center h-screen bg-black">
124+
<div className="text-white text-2xl">로딩 중...</div>
125+
</div>
126+
);
127+
}
128+
129+
return (
130+
<div className="flex flex-col w-full items-center justify-start h-screen bg-black">
131+
<div className="flex flex-col max-w-[414px] w-full h-full pt-[30px] px-5">
132+
<p className="text-white text-xl font-bold mb-2">회원가입하기</p>
133+
134+
<div className="relative w-full h-full overflow-y-scroll">
135+
<div key="screen1" className={`absolute w-full transition-all duration-500 ease-in-out transform ${isAnimating ? "-translate-x-full opacity-0" : "translate-x-0 opacity-100"}`}>
136+
<ProfileInfoForm
137+
name={name}
138+
setName={setName}
139+
email={email}
140+
setEmail={setEmail}
141+
password={password}
142+
setPassword={setPassword}
143+
confirmPassword={confirmPassword}
144+
setConfirmPassword={setConfirmPassword}
145+
errors={errors}
146+
isEmailValid={isEmailValid}
147+
isNameDisabled={isNameDisabled}
148+
isEmailDisabled={isEmailDisabled}
149+
/>
150+
</div>
151+
152+
<div key="screen2" className={`${isRendering ? "" : "hidden"} absolute w-full transition-all duration-500 ease-in-out transform ${isAnimating ? "translate-x-0 opacity-100" : "translate-x-full opacity-0"}`}>
153+
<AdditionalInfoForm
154+
major={major}
155+
setMajor={setMajorInfo}
156+
studentId={studentId}
157+
setStudentId={setStudentId}
158+
phoneNumber={phoneNumber}
159+
setPhoneNumber={setPhoneNumber}
160+
/>
161+
</div>
162+
</div>
163+
164+
{/* 하단 버튼 영역 */}
165+
<div className="flex flex-col w-full pb-4 mt-auto">
166+
<Button
167+
className="text-white bg-[#EA4336] w-full h-[48px] rounded-full"
168+
style={{boxShadow: "black 0px -10px 20px 10px"}}
169+
onPress={isAnimating ? handleSignup : handleNext}
170+
isDisabled={!isAnimating && (!name || !email || !password || !confirmPassword || errors.length > 0 || password !== confirmPassword)}
171+
>
172+
{isAnimating ? "가입하기" : "다음"}
173+
</Button>
174+
</div>
175+
</div>
176+
</div>
177+
);
178+
}
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)