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/social login #41

Merged
merged 9 commits into from
Oct 5, 2024
Merged
9 changes: 9 additions & 0 deletions public/images/sign/google-login.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/images/sign/kakao-login.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/images/sign/naver-login.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,12 @@
justify-content: space-between;
}
}


.line-clamp-3 {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2; /* 3-line limit */
white-space: normal;
}
86 changes: 50 additions & 36 deletions src/app/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
'use client';

import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, Suspense } from 'react';
import Step1 from '@/components/signup/Step1';
import Step2 from '@/components/signup/Step2';
import Step3 from '@/components/signup/Step3';
import Step4 from '@/components/signup/Step4';
import { finalSignup } from '@/service/auth';
import { useRouter } from 'next/navigation';

const SignupPage: React.FC = () => {
const [currentStep, setCurrentStep] = useState(1);
const [isSocialLogin, setIsSocialLogin] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const [formData, setFormData] = useState<{
email?: string;
name?: string;
Expand All @@ -18,28 +20,34 @@ const SignupPage: React.FC = () => {
birthDate?: string;
investmentExperience?: string;
marketingConsent?: boolean;
loginType: 'local';
loginType: 'local' | 'social';
}>({
loginType: 'local'
loginType: 'local',
});

const [maxHeightClass, setmaxHeightClass] = useState('max-h-screen');

const router = useRouter();

// URL에서 verify 토큰과 email을 추출하고 처리하는 로직
useEffect(() => {
const handleResize = () => {
if (window.innerWidth < 640) {
setmaxHeightClass('max-h-[calc(100vh-75.5px)]');
} else {
setmaxHeightClass('max-h-screen');
}
};
handleResize();
window.addEventListener('resize', handleResize);
const searchParams = new URLSearchParams(window.location.search);
const verifyToken = searchParams.get('verify');
const email = searchParams.get('email');

if (verifyToken && email && !isSocialLogin) {
// 소셜 로그인 사용자일 때만 상태를 업데이트
setIsSocialLogin(true);
setFormData((prev) => ({
...prev,
email,
loginType: 'social',
}));

// verifyToken을 로컬 스토리지에 저장 (토큰 저장)
localStorage.setItem('access_token', verifyToken);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
setCurrentStep(4); // 소셜 로그인인 경우 Step4로 이동
}
}, [isSocialLogin]);

const handleNext = () => {
setCurrentStep((prev) => prev + 1);
Expand All @@ -49,14 +57,15 @@ const SignupPage: React.FC = () => {
setFormData((prev) => {
const updatedFormData = { ...prev, ...data };

// 상태가 이전과 같다면 업데이트하지 않음
if (JSON.stringify(prev) === JSON.stringify(updatedFormData)) {
return prev;
}

return updatedFormData;
});
};

const handleSubmit = async () => {
try {
console.log('최종 제출 데이터:', formData);
Expand All @@ -68,32 +77,37 @@ const SignupPage: React.FC = () => {

const authHeaders = {
cookie: '',
authorization: `Bearer ${accessToken}`
Verify: accessToken, // Verify 헤더에 JWT 토큰을 포함
};

const response = await finalSignup(formData, authHeaders);
console.log('서버 응답 데이터:', response);

// 회원가입 완료 후 페이지 이동
router.push('/dashboard'); // 완료 후 다른 페이지로 이동
} catch (error) {
console.error('서버 요청 오류:', error);
}
};

return (
<div className='flex flex-col items-center justify-center'>
{currentStep === 1 && (
<Step1 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 2 && (
<Step2 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 3 && (
<Step3 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 4 && (
<Step4 onNext={handleSubmit} onUpdate={(data) => handleUpdate(data)} />
)}
</div>
<Suspense fallback={<div></div>}>
<div className={`flex flex-col items-center justify-center max-h-screen`}>
{currentStep === 1 && (
<Step1 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 2 && (
<Step2 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 3 && (
<Step3 onNext={handleNext} onUpdate={(data) => handleUpdate(data)} />
)}
{currentStep === 4 && (
<Step4 onNext={handleSubmit} onUpdate={(data) => handleUpdate(data)} />
)}
</div>
</Suspense>
);
};

export default SignupPage;
export default SignupPage;
6 changes: 5 additions & 1 deletion src/components/common/Container.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { ReactNode } from 'react';

const Container = ({ children }: { children: ReactNode }) => {
return <div className=" w-full mx-auto desk:max-w-[1000px] ">{children}</div>;
return (
<div className="max-w-[360px] mx-auto desk:max-w-[1000px] w-[90%] lg:w-[100%]">
{children}
</div>
);
};

export default Container;
2 changes: 1 addition & 1 deletion src/components/common/Gnb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const Gnb = () => {
? 'shadow-custom-light border-b border-gray100'
: ''
}>
<div className="px-5 py-[16px] max-w-[1000px] mx-auto flex items-center justify-between sm:px-0 sm:py-3 ">
<div className="py-[16px] max-w-[1000px] mx-auto flex items-center justify-between sm:px-0 sm:py-3 w-[90%] lg:w-[100%]">
<Link href={'/'} className="cursor-pointer">
<img src="/images/logo.svg" alt="logo" className="w-[144px] h-5" />
</Link>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Navbar = () => {
const pathname = usePathname();

return (
<div className="hidden shadow-custom-light border-b border-gray100 sm:block">
<div className="hidden shadow-custom-light border-b border-gray100 sm:block w-[90%] lg:w-[100%] mx-auto">
<div className="max-w-[1000px] mx-auto flex items-center">
<div
onClick={() => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/home/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import MoblieRank from './MoblieRank';
const HomeIndex = () => {
return (
<div className="overflow-x-hidden">
<section className="max-w-[1000px] mx-auto flex items-center desk:min-w-[390px] gap-[28px] sm:mt-[29px]">
<section className="max-w-[1000px] mx-auto flex items-center desk:min-w-[390px] gap-[28px] sm:mt-[29px] w-[90%] lg:w-[100%]">
<Guide />
<RealtimeRank />
</section>
Expand Down
2 changes: 1 addition & 1 deletion src/components/practice/CategoryPractice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const CategoryPractice = () => {
const secondItem = allPosts[index * 2 + 1];

return (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 w-full">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-0 sm:gap-8 w-full">
{firstItem && (
<CategorySubloadmapBottomArticle
key={firstItem.id}
Expand Down
15 changes: 12 additions & 3 deletions src/components/practice/CategorySubloadmapBottomArticle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const CategorySubloadmapBottomArticle: React.FC<InvestmentGuideProps> = ({ id, t
window.open(link, '_blank');
};

const formattedDate = date.split('T')[0];

return (
<div className='w-full pt-5' onClick={handleClick}>
<div className="flex gap-5 items-center cursor-pointer">
Expand All @@ -17,11 +19,18 @@ const CategorySubloadmapBottomArticle: React.FC<InvestmentGuideProps> = ({ id, t
alt={title}
width={70}
height={70}
className="w-[70px] h-[70px] rounded-lg"
className="w-[70px] h-[70px] rounded-lg mb-auto"
/>
<div className="flex-1 flex flex-col gap-3">
<div className="flex-1 flex flex-col gap-3 h-full">
<div className="text-gray600 text-body5 sm:text-title1">{title}</div>
<div className="text-gray300 text-caption3 sm:text-body7">{description}ㆍ{date}</div>

{/* Description with 3-line limit */}
<div className="text-gray300 text-caption3 sm:text-body7 line-clamp-3 flex-grow">
{description}
</div>

{/* Date with margin-top auto to push it to the bottom */}
<div className="text-gray300 text-caption3 sm:text-body7 ml-auto mt-auto">{formattedDate}</div>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/practice/PracticeIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const PracticeIndex = () => {
<section className="hidden sm:flex justify-center mt-6 pb-[29px]">
<img src="/images/report/report_main.svg" alt="" />
</section>
<section className="px-5 sm:px-0">
<section className="">
<CategoryPractice />
</section>
<div className="h-[100px] sm:h-12" />
Expand Down
24 changes: 24 additions & 0 deletions src/components/sign/GoogleLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Image from 'next/image';
import React from 'react';
import GoogleLoginButton from '../../../public/images/sign/google-login.svg';

const GoogleLogin = ({ setLoginType }: { setLoginType: (type: 'google') => void }) => {
const handleGoogleLogin = () => {
// loginType을 google로 설정
setLoginType('google');
// 구글 로그인 페이지로 리다이렉트
window.location.href = 'https://accounts.google.com/o/oauth2/auth';
};

return (
<Image
onClick={handleGoogleLogin}
src={GoogleLoginButton}
alt="구글 로그인"
width={320}
height={52}
/>
);
};

export default GoogleLogin;
24 changes: 24 additions & 0 deletions src/components/sign/KakaoLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Image from 'next/image';
import React from 'react';
import KakaoLoginButton from '../../../public/images/sign/kakao-login.svg';

const KakaoLogin = ({ setLoginType }: { setLoginType: (type: 'kakao') => void }) => {
const handleKakaoLogin = () => {
// loginType을 kakao로 설정
setLoginType('kakao');
// 카카오 로그인 페이지로 리다이렉트
window.location.href = 'https://kauth.kakao.com/oauth/authorize';
};

return (
<Image
onClick={handleKakaoLogin}
src={KakaoLoginButton}
alt="카카오 로그인"
width={320}
height={52}
/>
);
};

export default KakaoLogin;
24 changes: 24 additions & 0 deletions src/components/sign/NaverLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import Image from 'next/image';
import NaverLoginButton from '../../../public/images/sign/naver-login.svg';

const NaverLogin = ({ setLoginType }: { setLoginType: (type: 'naver') => void }) => {
const handleNaverLogin = () => {
// loginType을 naver로 설정
setLoginType('naver');
// 네이버 로그인 페이지로 리다이렉트
window.location.href = 'https://api.moaguide.com/oauth2/authorization/naver';
};

return (
<Image
onClick={handleNaverLogin}
src={NaverLoginButton}
alt="네이버 로그인"
width={320}
height={52}
/>
);
};

export default NaverLogin;
Loading
Loading