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(login): 로그인 퍼널 구현 #42

Merged
merged 26 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
4,147 changes: 2,047 additions & 2,100 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"lowlight": "^3.1.0",
"lucide-react": "^0.411.0",
"next": "14.2.4",
"next-auth": "beta",
"react": "^18",
"react-colorful": "^5.6.1",
"react-day-picker": "8.10.1",
Expand Down
2 changes: 1 addition & 1 deletion src/apis/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ axiosInstance.interceptors.request.use(async (requestConfig: InternalAxiosReques
if (typeof window === 'undefined') {
return requestConfig;
}

const token = getCookie('accessToken');
const config = { ...requestConfig };

Expand All @@ -49,6 +48,7 @@ axiosInstance.interceptors.response.use(
if (axios.isAxiosError(error)) {
const status = error.response?.status;
const refreshToken = getCookie('refreshToken');

if (status === 401) {
if (refreshToken) {
deleteCookie('accessToken');
Expand Down
31 changes: 0 additions & 31 deletions src/apis/login.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/app/(sidebar)/(my-info)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Dropdown, Icon } from '@/system/components';
import { InfoCardList } from './components/InfoCardList';
import { Suspense, useEffect, useRef, useState } from 'react';
import { useRef, useState } from 'react';
import { AddInfoCardDialog } from './components/AddInfoCardDialog';
import { TouchButton } from '@/components/TouchButton';
import { INFO_TYPES, InfoType } from '@/types';
Expand Down
80 changes: 0 additions & 80 deletions src/app/(sidebar)/login/page.tsx

This file was deleted.

13 changes: 13 additions & 0 deletions src/app/AuthRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { auth } from '@/auth';
import { Redirect } from '@/components/Redirect';
import { StrictPropsWithChildren } from '@/types';

export default async function AuthRedirect({ children }: StrictPropsWithChildren) {
const session = await auth();

return (
<Redirect condition={session?.accessToken != null} to="/login">
{children}
</Redirect>
);
}
Copy link
Member Author

Choose a reason for hiding this comment

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

로그인 여부를 확인해, 리다이렉트를 설정하는 선언형 컴포넌트입니다.

3 changes: 3 additions & 0 deletions src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { handlers } from '@/auth';

export const { GET, POST } = handlers;
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import '@/styles/globals.css';
import '@/styles/memo.css';
import { Inter } from 'next/font/google';
import { cn } from '@/utils';
import { SessionProvider } from 'next-auth/react';

const inter = Inter({ subsets: ['latin'] });

Expand All @@ -23,7 +24,9 @@ export default function RootLayout({
return (
<html lang="en">
<body className={cn(inter.className, 'bg-neutral-1')}>
<QueryProvider>{children}</QueryProvider>
<QueryProvider>
<SessionProvider>{children}</SessionProvider>
</QueryProvider>
</body>
</html>
);
Expand Down
5 changes: 5 additions & 0 deletions src/app/login/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use server';

import { signIn } from '@/auth';

export const googleLogin = () => signIn('google', { redirectTo: '/login?auth=select' });
Copy link
Member Author

Choose a reason for hiding this comment

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

auth.js가 next/header를 사용하고 있어, action으로 export하여 별도로 사용합니다.

client에서 server action을 사용하게 하는 nextJs에서 권장 방법입니다.

12 changes: 12 additions & 0 deletions src/app/login/api/postLogin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { http } from '@/apis/http';

export const postLogin = (provider: 'GOOGLE' | 'KAKAO', token: string) =>
http.post<{ accessToken: string; refreshToken: string }>({
url: '/users/social-login',
params: {
provider,
},
headers: {
'SOCIAL-AUTH-TOKEN': token,
},
});
46 changes: 46 additions & 0 deletions src/app/login/components/Login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';

import { motion } from 'framer-motion';
import { TouchButton } from '@/components/TouchButton';
import { Icon } from '@/system/components';
import { googleLogin } from '../actions';

export function Login() {
return (
<motion.form
initial={{
opacity: 0,
y: 150,
}}
animate={{
opacity: 1,
y: 0,
}}
exit={{
opacity: 0,
x: 120,
}}
transition={{ duration: 1 }}
action={googleLogin}
className="w-552 h-604 p-68 pt-116 flex flex-col justify-between rounded-30 bg-[white]">
<div className="flex flex-col items-center gap-16">
<Icon name="cloverLogo" size={74} />

<h1 className="text-28 font-bold tracking-[-0.972px]">뽀각 시작하기</h1>
<p className="text-center text-neutral-70 trackiing-[0.091px]">
취업 준비 과정에서의 정보를 쉽게 <br />
정리하고 탐색해보세요
</p>
</div>

<div className="flex flex-col gap-12">
<TouchButton type="submit" className="relative h-62 rounded-54 bg-[#F2F2F2]">
<div className="absolute top-6 left-6">
<Icon name="google" size={50} />
</div>
<p className="font-semibold tracking-[-0.091px]">구글로 시작하기</p>
</TouchButton>
</div>
</motion.form>
);
}
74 changes: 74 additions & 0 deletions src/app/login/components/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { easeIn, motion } from 'framer-motion';
import { TouchButton } from '@/components/TouchButton';
import { Icon } from '@/system/components';
import { cn } from '@/utils';
import { useState } from 'react';
import { useFunnelContext } from '@/system/components/Funnel/useFunnel';

export default function Select() {
const [position, setPosition] = useState<'designer' | 'developer' | ''>('');
const { setStep } = useFunnelContext();

return (
<motion.section
initial={{
opacity: 0,
x: 150,
}}
animate={{
opacity: 1,
x: 0,
}}
exit={{
opacity: 0,
x: -150,
}}
transition={{ duration: 0.6, ease: 'easeOut' }}
className="w-552 h-604 p-68 pt-116 flex flex-col justify-center gap-56 rounded-30 bg-[white]">
<div className="flex flex-col items-center gap-16">
<h1 className="text-36 font-bold">환영해요 조혜원님!</h1>
Copy link
Collaborator

Choose a reason for hiding this comment

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

유저 정보 가져오는게 가능하면 이 부분 유저 이름으로 바꿔야될 것 같아요~

Copy link
Member Author

Choose a reason for hiding this comment

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

좋아요 !


<p className="text-center text-neutral-70 trackiing-[0.091px]">
취업 준비 중인 직군을 선택해주시면 <br />
직군에 맞는 키워드 태그를 제공해드려요
</p>
</div>

<div>
<div className="flex gap-28">
<TouchButton
onClick={() => setPosition('developer')}
className={cn(
'relative flex flex-col justify-center items-center gap-16 w-190 h-212 hover:bg-neutral-1 transition-all rounded-18 border-1 border-transparent',
position === 'developer' && 'bg-[#EEF9F5] border-[#2DC98E] hover:bg-bg-[#EEF9F5]',
)}>
<Icon name="codingSignUp" size={120} />
<p className="font-bold text-20 tracking-[-0.24px]">개발자</p>
</TouchButton>

<TouchButton
onClick={() => setPosition('designer')}
className={cn(
'relative flex flex-col justify-center items-center gap-16 w-190 h-212 hover:bg-neutral-1 transition-all rounded-18 border-1 border-transparent',
position === 'designer' && 'bg-[#EEF9F5] border-[#2DC98E] hover:bg-bg-[#EEF9F5]',
)}>
<Icon name="designSignUp" size={120} />
<p className="font-bold text-20 tracking-[-0.24px]">디자이너</p>
</TouchButton>
</div>
</div>

<TouchButton
disabled={position === ''}
className={cn(
'bg-neutral-5 rounded-6 py-13 h-48 px-20 w-full text-15 font-semibold text-neutral-30 transition-all',
position !== '' && 'text-white bg-[black]',
)}
onClick={() => {
setStep('aaa');
}}>
선택 완료
</TouchButton>
</motion.section>
);
}
13 changes: 13 additions & 0 deletions src/app/login/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { auth } from '@/auth';
import { Redirect } from '@/components/Redirect';
import { StrictPropsWithChildren } from '@/types';

export default async function Layout({ children }: StrictPropsWithChildren) {
const session = await auth();

return (
<Redirect condition={!!session?.accessToken}>
<main className="h-screen flex justify-center items-center bg-neutral-95">{children}</main>;
</Redirect>
);
}
27 changes: 27 additions & 0 deletions src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import { useSession } from 'next-auth/react';
import { useFunnel } from '@/system/components/Funnel/useFunnel';
import { Login } from './components/Login';
import { Redirect } from '@/components/Redirect';
import Select from './components/Select';

export default function Page() {
const session = useSession();
const Funnel = useFunnel(['login', 'select'] as const, { initialStep: 'login', stepQueryKey: 'auth' });

return (
<Funnel mode="wait">
<Funnel.Step name="login">
<Login />
</Funnel.Step>

<Funnel.Step name="select">
{/* TODO: initial 로그인 여부 확인 */}
<Redirect condition={!session.data?.accessToken}>
<Select />
</Redirect>
</Funnel.Step>
</Funnel>
);
}
Loading
Loading