Skip to content

Commit 38cde08

Browse files
authored
[feat] 로그인 기능 구현 (#63) - 로그아웃 이슈는 추후 논의 필요
* [refactor] modal store 삭제 * [feat] 쿠키 저장 구현중... * [feat] 로그인 쿠키저장하여 이전페이지 이동 완료 * [docs] 의미없는 폴더 삭제
1 parent 8b81b23 commit 38cde08

File tree

10 files changed

+86
-61
lines changed

10 files changed

+86
-61
lines changed

src/api/index.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
3+
export async function POST(req: NextRequest) {
4+
const { path } = await req.json(); // 클라이언트가 보내는 페이지 경로
5+
const res = NextResponse.json({ ok: true });
6+
7+
res.cookies.set({
8+
name: 'preLoginPath',
9+
value: path,
10+
path: '/',
11+
maxAge: 60 * 30, // 30분
12+
httpOnly: false, // JS에서 읽을 수 있게
13+
secure: process.env.NODE_ENV === 'production',
14+
sameSite: 'lax',
15+
});
16+
17+
return res;
18+
}

src/shared/@store/modal.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/shared/components/auth/LoginRedirectHandler.tsx

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
import { useEffect, useState } from 'react';
44
import { usePathname, useRouter } from 'next/navigation';
55
import { useAuthStore } from '@/shared/@store/auth';
6-
import { useModalStore } from '@/shared/@store/modal';
76
import { customToast } from '@/shared/components/toast/CustomToastUtils';
87
import Spinner from '../spinner/Spinner';
8+
import WelcomeModal from './WelcomeModal';
9+
import { getCookie, removeCookie } from './utils/cookie';
910

1011
function LoginRedirectHandler() {
1112
const pathname = usePathname();
1213
const router = useRouter();
1314
const { user, updateUser } = useAuthStore();
14-
const { openWelcomeModal } = useModalStore();
1515
const [loading, setLoading] = useState(true);
16+
const [welcomeModalOpen, setWelcomeModalOpen] = useState(false);
1617

1718
useEffect(() => {
1819
if (!user && loading) {
@@ -32,15 +33,28 @@ function LoginRedirectHandler() {
3233
useEffect(() => {
3334
if (!user || loading) return;
3435

35-
const preLoginPath = sessionStorage.getItem('preLoginPath') || '/';
36+
const preLoginPath = getCookie('preLoginPath') || '/';
37+
console.log(preLoginPath);
3638

39+
// 첫 유저일 경우 모달 오픈
3740
if (pathname.startsWith('/login/first-user')) {
38-
openWelcomeModal(user.nickname);
39-
} else if (pathname.startsWith('/login/success')) {
41+
setWelcomeModalOpen(true);
42+
}
43+
// 기존 유저일 경우
44+
else if (pathname.startsWith('/login/success')) {
4045
customToast.success(`${user.nickname}님 \n 로그인 성공 🎉`);
4146
router.replace(preLoginPath);
47+
removeCookie('preLoginPath');
4248
}
43-
}, [pathname, user, router, openWelcomeModal, loading]);
49+
}, [pathname, user, loading, router]);
50+
51+
// 환영 모달 닫힐 때 이동
52+
const handleCloseWelcomeModal = () => {
53+
setWelcomeModalOpen(false);
54+
const preLoginPath = getCookie('preLoginPath') || '/';
55+
removeCookie('preLoginPath');
56+
router.replace(preLoginPath);
57+
};
4458

4559
if (loading) {
4660
return (
@@ -50,6 +64,17 @@ function LoginRedirectHandler() {
5064
);
5165
}
5266

53-
return null;
67+
return (
68+
<>
69+
{/* 첫 유저 모달 */}
70+
{user && (
71+
<WelcomeModal
72+
userNickname={user.nickname}
73+
open={welcomeModalOpen}
74+
onClose={handleCloseWelcomeModal}
75+
/>
76+
)}
77+
</>
78+
);
5479
}
5580
export default LoginRedirectHandler;

src/shared/components/auth/Welcome.tsx renamed to src/shared/components/auth/WelcomeModal.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,29 @@ import Button from '@/shared/components/button/Button';
66
import ModalLayout from '@/shared/components/modalPop/ModalLayout';
77
import Ssury from '@/shared/assets/ssury/ssury_jump.webp';
88
import { useRouter } from 'next/navigation';
9-
import { useModalStore } from '@/shared/@store/modal';
10-
import { useAuthStore } from '@/shared/@store/auth';
119

12-
function Welcome() {
13-
const router = useRouter();
14-
const { user } = useAuthStore();
15-
const { welcomeModal, closeWelcomeModal } = useModalStore();
10+
interface Props {
11+
userNickname: string;
12+
open: boolean;
13+
onClose: () => void;
14+
}
1615

17-
if (!welcomeModal.open || !user) return null;
16+
function Welcome({ userNickname, open, onClose }: Props) {
17+
const router = useRouter();
1818

1919
return (
2020
<ModalLayout
21-
open={welcomeModal.open}
22-
onClose={closeWelcomeModal}
23-
title={`환영합니다, ${user.nickname}님!`}
21+
open={open}
22+
onClose={onClose}
23+
title={`환영합니다, ${userNickname}님!`}
2424
description="바텐더 쑤리가 안내해드릴게요"
2525
buttons={
2626
<>
2727
<Button
2828
type="button"
2929
color="purple"
3030
onClick={() => {
31-
closeWelcomeModal();
31+
onClose();
3232
router.push('/recipe');
3333
}}
3434
>
@@ -37,7 +37,7 @@ function Welcome() {
3737
<Button
3838
type="button"
3939
onClick={() => {
40-
closeWelcomeModal();
40+
onClose();
4141
router.push('/recommend');
4242
}}
4343
>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function getCookie(name: string) {
2+
if (typeof document === 'undefined') return null;
3+
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
4+
return match ? decodeURIComponent(match[2]) : null;
5+
}
6+
7+
export function removeCookie(name: string) {
8+
if (typeof document === 'undefined') return;
9+
document.cookie = `${name}=; path=/; max-age=0`;
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export async function setPreLoginPath(path: string) {
2+
await fetch('/api/login/set-pre-login-path', {
3+
method: 'POST',
4+
headers: { 'Content-Type': 'application/json' },
5+
body: JSON.stringify({ path }), // 인자로 받은 path 사용
6+
credentials: 'include',
7+
});
8+
}

src/shared/components/header/DropdownMenu.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { usePathname } from 'next/navigation';
77
import { useEffect, useRef } from 'react';
88
import gsap from 'gsap';
99
import { useAuthStore } from '@/shared/@store/auth';
10+
import { setPreLoginPath } from '../auth/utils/setPreLoginPath';
1011

1112
interface Props {
1213
isClicked: boolean;
@@ -116,9 +117,9 @@ function DropdownMenu({ isClicked, setIsClicked }: Props) {
116117
) : (
117118
<Link
118119
href="/login"
119-
onNavigate={() => {
120+
onNavigate={async () => {
120121
setIsClicked(false);
121-
sessionStorage.setItem('preLoginPath', window.location.pathname);
122+
await setPreLoginPath(window.location.pathname);
122123
}}
123124
className="flex items-center gap-2 text-black font-light text-xl hover:text-black/70"
124125
>

src/shared/components/header/HeaderBtn.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import SignIn from '@/shared/assets/icons/sign_in_24.svg';
55
import { useRouter } from 'next/navigation';
66
import tw from '@/shared/utills/tw';
77
import { useAuthStore } from '@/shared/@store/auth';
8+
import { setPreLoginPath } from '../auth/utils/setPreLoginPath';
89

910
type RouterType = ReturnType<typeof useRouter>;
1011

@@ -39,8 +40,8 @@ function HeaderBtn({ pathname }: { pathname: string }) {
3940
icon: SignIn,
4041
label: '로그인',
4142
className: `${pathname === '/login' ? 'text-tertiary' : ''}`,
42-
onClick: () => {
43-
sessionStorage.setItem('preLoginPath', window.location.pathname);
43+
onClick: async () => {
44+
await setPreLoginPath(window.location.pathname);
4445
router.push('/login');
4546
},
4647
},

src/shared/lib/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)