Skip to content

Commit 5516eb2

Browse files
committed
feat: 마이페이지 구현 및 로그인,로그아웃 기능 추가
1 parent 6461f5e commit 5516eb2

11 files changed

Lines changed: 1260 additions & 50 deletions

File tree

package-lock.json

Lines changed: 276 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
"@testing-library/react": "^16.3.0",
1010
"@testing-library/user-event": "^13.5.0",
1111
"@types/jest": "^27.5.2",
12+
"@types/js-cookie": "^3.0.6",
1213
"@types/react": "^19.1.8",
1314
"@types/react-dom": "^19.1.6",
15+
"axios": "^1.10.0",
16+
"js-cookie": "^3.0.5",
1417
"react": "^19.1.0",
1518
"react-dom": "^19.1.0",
1619
"react-router-dom": "^7.6.2",

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SubscriptionModal from './components/common/SubscriptionModal';
1313
import { ModalProvider } from './contexts/ModalContext';
1414
import ModalManager from './components/common/ModalManager';
1515
import './App.css';
16+
import ProfileSection from './components/sections/ProfileSection';
1617

1718
// React Query client 생성
1819
const queryClient = new QueryClient({
@@ -40,6 +41,7 @@ function App() {
4041
<Route path="/mailform" element={<TodayEmailFormSection />} />
4142
<Route path="/verification-email" element={<VerificationEmailPage />} />
4243
<Route path="/subscriptions/:subscriptionId" element={<SubscriptionEditSection />} />
44+
<Route path="/profile" element={<ProfileSection />} />
4345
</Routes>
4446
<Footer />
4547
<SubscriptionModal

src/components/common/Header.tsx

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
import React, { useState, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import { useLoginModal } from '../../hooks/useModal';
4+
import { useAuth, useLogout } from '../../hooks/useAuth';
45

56
const Header: React.FC = () => {
67
const { openLoginModal } = useLoginModal();
78
const [isScrolled, setIsScrolled] = useState(false);
89
const navigate = useNavigate();
10+
11+
// 인증 상태와 로그아웃 기능 가져오기
12+
const { isAuthenticated, isLoading } = useAuth();
13+
const logoutMutation = useLogout();
14+
15+
// 디버깅용 로그
16+
React.useEffect(() => {
17+
console.log('🎯 Header auth state:', { isAuthenticated, isLoading });
18+
}, [isAuthenticated, isLoading]);
19+
20+
// 로그아웃 핸들러
21+
const handleLogout = async () => {
22+
try {
23+
console.log('🚪 User clicked logout button');
24+
await logoutMutation.mutateAsync();
25+
console.log('✅ Logout completed successfully');
26+
navigate('/'); // 로그아웃 후 홈으로 이동
27+
} catch (error) {
28+
console.error('❌ 로그아웃 실패:', error);
29+
// 에러가 발생해도 홈으로 이동 (사용자 경험 개선)
30+
navigate('/');
31+
}
32+
};
933

1034
useEffect(() => {
1135
const handleScroll = () => {
@@ -28,7 +52,7 @@ const Header: React.FC = () => {
2852
borderBottom: isScrolled ? '1px solid rgba(229, 231, 235, 0.8)' : '1px solid transparent'
2953
}}
3054
>
31-
<div className="max-w-6xl mx-auto px-5 py-4 flex items-center justify-between">
55+
<div className="max-w-6xl mx-auto px-3 sm:px-5 py-3 sm:py-4 flex items-center justify-between">
3256
<div className="flex items-center space-x-3">
3357
<div
3458
className="flex items-center cursor-pointer"
@@ -37,17 +61,43 @@ const Header: React.FC = () => {
3761
<img
3862
src="/cs25.png"
3963
alt="CS25"
40-
className="h-8 w-auto"
64+
className="h-6 sm:h-8 w-auto"
4165
/>
4266
</div>
4367
</div>
4468

45-
<button
46-
onClick={openLoginModal}
47-
className="px-6 py-2 rounded-lg font-medium transition-all duration-300 bg-gradient-to-r from-brand-500 to-brand-600 text-white hover:from-brand-600 hover:to-brand-700 shadow-sm"
48-
>
49-
로그인
50-
</button>
69+
<div className="flex items-center space-x-2 sm:space-x-4">
70+
{isAuthenticated ? (
71+
// 로그인된 상태
72+
<div className="flex items-center space-x-2 sm:space-x-3">
73+
<button
74+
onClick={() => navigate('/profile')}
75+
className="px-2 sm:px-4 py-1.5 sm:py-2 rounded-lg font-medium transition-all duration-300 text-gray-700 hover:text-brand-600 hover:bg-brand-50 text-sm sm:text-base"
76+
>
77+
<span className="sm:inline">마이페이지</span>
78+
</button>
79+
<button
80+
onClick={handleLogout}
81+
disabled={logoutMutation.isPending}
82+
className={`px-3 sm:px-6 py-1.5 sm:py-2 rounded-lg font-medium transition-all duration-300 text-sm sm:text-base ${
83+
logoutMutation.isPending
84+
? 'bg-gray-400 text-white cursor-not-allowed'
85+
: 'bg-gradient-to-r from-brand-500 to-brand-600 text-white hover:from-brand-600 hover:to-brand-700 shadow-sm'
86+
}`}
87+
>
88+
로그아웃
89+
</button>
90+
</div>
91+
) : (
92+
// 로그인되지 않은 상태
93+
<button
94+
onClick={openLoginModal}
95+
className="px-4 sm:px-6 py-1.5 sm:py-2 rounded-lg font-medium transition-all duration-300 bg-gradient-to-r from-brand-500 to-brand-600 text-white hover:from-brand-600 hover:to-brand-700 shadow-sm text-sm sm:text-base"
96+
>
97+
로그인
98+
</button>
99+
)}
100+
</div>
51101
</div>
52102
</header>
53103
);

0 commit comments

Comments
 (0)