From 76c5d3653f3d37ca16831681cbd640f71a7a1e4f Mon Sep 17 00:00:00 2001 From: Mingi Chu Date: Fri, 17 Oct 2025 22:19:53 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95=EC=A4=91.=201=EC=B0=A8=20?= =?UTF-8?q?=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jwt.md | 130 ++++++++++ src/mong/pages/StatisticsAnalysis.tsx | 111 +++++++-- src/mong/styles/statistics.css | 326 +++++++++++++++++++++++--- 3 files changed, 518 insertions(+), 49 deletions(-) create mode 100644 jwt.md diff --git a/jwt.md b/jwt.md new file mode 100644 index 0000000..6d22bc9 --- /dev/null +++ b/jwt.md @@ -0,0 +1,130 @@ +# JWT 인증 기능 구현 참고 가이드 + +## 📁 핵심 참고 파일들 + +### 1. Redux Store 구조 +**파일**: `src/mong/store/index.ts` +- Redux store 설정 +- RTK Query 또는 일반 Redux 설정 참고 +- 미들웨어 설정 방법 + +### 2. 인증 상태 관리 (Redux Slice) +**파일**: `src/mong/store/slices/authSlice.ts` +- **현재 상태**: localStorage 기반 인증 (JWT 미적용) +- **참고 포인트**: + - `createAsyncThunk`를 사용한 비동기 액션 패턴 + - `loginUser`, `registerUser` thunk 구조 + - Redux state 관리 방식 + - 에러 처리 및 로딩 상태 관리 +- **JWT 적용 시 수정 필요**: + - `accessToken`, `refreshToken` 상태 추가 + - API 호출을 axios로 변경 + - 토큰 자동 갱신 로직 추가 + +### 3. 타입 정의 +**파일**: `src/mong/types/redux.ts` +- **AuthState 인터페이스**: + ```typescript + export interface AuthState { + user: User | null; + isAuthenticated: boolean; + loading: boolean; + error: string | null; + // JWT 추가 필요: accessToken, refreshToken + } + ``` +- **참고 포인트**: 타입 안전성 확보 방법 + +**파일**: `src/mong/types/common.ts` +- **User 인터페이스**: 사용자 데이터 구조 +- **참고 포인트**: 공통 타입 정의 방식 + +### 4. API 클라이언트 설정 +**파일**: `src/mong/api/lib/axiosPublic.ts` +- **현재 상태**: 기본 axios 설정 +- **참고 포인트**: + - baseURL 설정 방법 + - 공개 API용 axios 인스턴스 생성 + +**파일**: `src/mong/api/lib/axiosAuth.ts` +- **현재 상태**: 인증된 API용 axios 설정 (미완성) +- **참고 포인트**: + - `authGet`, `authPost` 헬퍼 함수 + - 토큰 자동 첨부 방식 + - **JWT 적용 시 활용**: 인터셉터로 토큰 자동 관리 + +**파일**: `src/mong/api/features/auth/thunks.ts` +- **현재 상태**: 기본적인 로그인 thunk (미완성) +- **참고 포인트**: + - `createAsyncThunk` 사용법 + - API 호출 후 Redux 상태 업데이트 + +### 5. 커스텀 훅 +**파일**: `src/mong/store/hooks.ts` +- **useAuth 훅**: + - 현재 상태 관리 방법 + - 액션 디스패치 패턴 + - 메모이제이션을 통한 성능 최적화 +- **참고 포인트**: + - `useCallback`을 사용한 안전한 액션 디스패치 + - 타입 안전한 selector 사용법 + +### 6. 로컬 스토리지 관리 +**파일**: `src/mong/utils/storage.ts` +- **참고 포인트**: + - 타입 안전한 localStorage 관리 + - 에러 처리 포함한 storage 헬퍼 + - **JWT 적용 시**: 토큰 저장/관리 로직 추가 필요 + +## 🔧 JWT 구현 시 활용 방법 + +### 1. Axios 인터셉터 설정 +```typescript +// src/mong/api/lib/axiosAuth.ts 참고 +// 요청 인터셉터: 토큰 자동 첨부 +// 응답 인터셉터: 401 에러 시 토큰 갱신 +``` + +### 2. Redux 상태 확장 +```typescript +// src/mong/types/redux.ts의 AuthState 확장 +interface AuthState { + // 기존 필드들... + accessToken: string | null; + refreshToken: string | null; + isRefreshing: boolean; +} +``` + +### 3. 토큰 관리 유틸리티 +```typescript +// src/mong/utils/tokenManager.ts 생성 필요 +// - 토큰 저장/조회/삭제 +// - 토큰 만료 검증 +// - 자동 갱신 로직 +``` + +### 4. API 엔드포인트 매핑 +```typescript +// src/mong/api/features/auth/thunks.ts 확장 +// - loginThunk: /api/users/login +// - registerThunk: /api/users/sign-up +// - refreshTokenThunk: /api/token/reissue +// - logoutThunk: /api/users/log-out +``` + +## 📋 구현 순서 가이드 + +1. **토큰 관리 유틸리티 생성** (`src/mong/utils/tokenManager.ts`) +2. **Axios 인터셉터 설정** (`src/mong/api/lib/axiosAuth.ts` 수정) +3. **Redux 상태 확장** (`src/mong/types/redux.ts` 수정) +4. **Auth Slice 업데이트** (`src/mong/store/slices/authSlice.ts` 수정) +5. **API Thunk 구현** (`src/mong/api/features/auth/thunks.ts` 완성) +6. **컴포넌트에서 사용** (`src/mong/pages/Login.tsx` 등) + +## ⚠️ 주의사항 + +- 현재 프로젝트는 localStorage 기반 인증으로 구현되어 있음 +- JWT 적용 시 기존 localStorage 로직을 토큰 기반으로 변경 필요 +- `src/mong/api/lib/axiosAuth.ts`의 store import 경로 수정 필요 +- CORS 설정 확인 (백엔드: 5000, 프론트엔드: 5173) diff --git a/src/mong/pages/StatisticsAnalysis.tsx b/src/mong/pages/StatisticsAnalysis.tsx index 79ebbce..9bb9c5c 100644 --- a/src/mong/pages/StatisticsAnalysis.tsx +++ b/src/mong/pages/StatisticsAnalysis.tsx @@ -434,28 +434,107 @@ const StatisticsAnalysis: React.FC = () => { )} - {/* 목표 및 성취 - 데이터가 있을 때만 표시 */} + {/* AI 예측 및 목표 - 데이터가 있을 때만 표시 */} {sleepRecords.length > 0 && ( -
+
-

수면 목표 및 성취

-

{analysisType === 'weekly' ? '이번 주' : '이번 달'} 목표 달성률

+
+
+ + + + + +
+

AI 예측 및 목표

+
+

현재 패턴을 기반으로 한 AI 분석 결과, 아래 개선사항을 실천하시면 4-6주 내에 수면 점수를 85점에서 90점으로 향상 시킬 수 있을 것으로 예측됩니다.

-
- {currentData.goals.map((goal, index) => ( -
-
- {goal.name} - {goal.progress}% 달성 +
+
+
+
+
92
+
89
+
86
+
83
+
80
-
-
+
+
+ + {/* 격자 시스템: Y축 5개 라벨 (92, 89, 86, 83, 80) = 5개 수평선 */} + {/* 격자 시스템: X축 6개 라벨 (1주전, 현재, 1주후, 2주후, 3주후, 4주후) = 6개 수직선 */} + + {/* Y축 수평 격자선 - 5개 (Y축 라벨 개수만큼) */} + + + + + + + {/* X축 수직 격자선 - 6개 (1주 전이 Y축에 완전히 붙어있음) */} + + + + + + + + {/* 데이터 라인 및 포인트 */} + {/* Y축 좌표 계산: (92-value) * 200 / (92-80) = (92-value) * 16.67 */} + {/* 점수 80 = y:200, 점수 83 = y:150, 점수 86 = y:100, 점수 89 = y:50, 점수 92 = y:0 */} + + {/* 과거 데이터 (실제 성과) - 1주 전: 83점, 현재: 85점 */} + + + {/* 미래 예측 (AI 예측) - 1주후: 87점, 2주후: 89점, 3주후: 91점, 4주후: 92점 */} + + + {/* 데이터 포인트 */} + {/* 1주 전 (83점) - Y축에 완전히 붙어있음 */} + + {/* 현재 (85점) */} + + {/* 1주 후 (87점 예측) */} + + {/* 2주 후 (89점 예측) */} + + {/* 3주 후 (91점 예측) */} + + {/* 4주 후 (92점 예측) */} + + + {/* '현재' 텍스트 레이블 - 그래프와 겹치지 않도록 위치 조정 */} + 현재 + +
+
+
1주 전
+
현재
+
1주 후
+
2주 후
+
3주 후
+
4주 후
+
- ))} +
)} diff --git a/src/mong/styles/statistics.css b/src/mong/styles/statistics.css index 48a4a20..c7eaa91 100644 --- a/src/mong/styles/statistics.css +++ b/src/mong/styles/statistics.css @@ -56,28 +56,58 @@ /* Cards */ .summary-card, .patterns-card, -.analysis-card, -.goals-card { +.analysis-card { background: #1a1a1a; border: 1px solid #2a2a2a; border-radius: 14px; padding: 24px; } +.header-content { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 4px; + justify-content: flex-start; + width: 100%; +} + +.header-icon { + display: flex; + align-items: center; + justify-content: center; + color: #a1a1aa; +} + +.header-icon svg { + width: 16px; + height: 16px; +} + +.card-header { + display: flex; + flex-direction: column; + align-items: flex-start; + text-align: left; + margin-bottom: 16px; +} + .card-header h4 { font-size: 18px; font-weight: 600; color: #ffffff; margin: 0 0 4px 0; - display: flex; - align-items: center; - gap: 8px; + text-align: left; + width: 100%; } .card-header p { font-size: 14px; color: #a1a1aa; margin: 0; + text-align: left; + width: 100%; + line-height: 1.4; } @@ -194,57 +224,203 @@ } -/* Goals List */ -.goals-list { - margin-top: 24px; +/* AI Prediction Card - 피그마 디자인 정확 구현 */ +.ai-prediction-card { + background: #1a1a1a; + border: 1px solid #2a2a2a; + border-radius: 14px; + padding: 24px; + width: 100%; + max-width: 754px; + height: 404px; + position: relative; + box-sizing: border-box; + display: flex; + flex-direction: column; + overflow: hidden; } -.goal-item { - margin-bottom: 16px; +.prediction-chart-container { + margin-top: 20px; + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + overflow: hidden; +} + +.prediction-chart { + background: #0f0f0f; + border-radius: 8px; + padding: 16px; + position: relative; + flex: 1; + box-sizing: border-box; + display: flex; + flex-direction: column; + overflow: hidden; + min-height: 0; } -.goal-header { + +.chart-content { display: flex; + flex: 1; + position: relative; + min-height: 0; + overflow: hidden; +} + +.chart-y-axis { + display: flex; + flex-direction: column; justify-content: space-between; + width: 16px; + padding: 0; + flex-shrink: 0; + align-self: stretch; + position: relative; +} + +.y-label { + font-size: 7px; + color: #a1a1aa; + text-align: right; + line-height: 1; + height: 0; + display: flex; align-items: center; - margin-bottom: 8px; + justify-content: flex-end; + margin: 0; + flex: 1; + position: relative; } -.goal-name { - font-size: 14px; - font-weight: 500; - color: #ffffff; +/* Y축 라벨을 격자선과 정확히 정렬 - 격자선 중앙에 위치 */ +.y-label:nth-child(1) { /* 92점 - y=0 격자선 */ + transform: translateY(0px); } -.goal-progress { - font-size: 14px; - color: #a1a1aa; +.y-label:nth-child(2) { /* 89점 - y=50 격자선 */ + transform: translateY(0px); } -.goal-bar { - width: 100%; - height: 8px; - background: #2a2a2a; - border-radius: 4px; +.y-label:nth-child(3) { /* 86점 - y=100 격자선 */ + transform: translateY(0px); +} + +.y-label:nth-child(4) { /* 83점 - y=150 격자선 */ + transform: translateY(0px); +} + +.y-label:nth-child(5) { /* 80점 - y=200 격자선 */ + transform: translateY(0px); +} + +.chart-area { + flex: 1; + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + min-height: 0; overflow: hidden; } -.goal-fill { +.chart-grid { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: grid; + grid-template-columns: repeat(6, 1fr); + grid-template-rows: repeat(5, 1fr); + z-index: 1; +} + +.grid-line.horizontal { + grid-column: 1 / -1; + height: 1px; + background: transparent; + border-top: 1px dashed #3a3a3a; + opacity: 0.6; + align-self: center; +} + +.grid-line.vertical { + grid-row: 1 / -1; + width: 1px; + background: transparent; + border-left: 1px dashed #3a3a3a; + opacity: 0.6; + justify-self: center; +} + +.grid-line.vertical.current { + opacity: 0.8; + border-left: 1px dashed #a1a1aa; +} + +.chart-lines { + flex: 1; + position: relative; + z-index: 2; + overflow: visible; + width: 100%; + min-height: 0; + max-height: 100%; +} + +.prediction-svg { + width: 100%; height: 100%; - border-radius: 4px; - transition: width 0.3s ease; + max-width: 100%; + max-height: 100%; + display: block; } -.goal-fill.primary { - background: #00d4aa; +.current-label { + font-size: 11px; + fill: #ffffff; + font-weight: 500; + text-anchor: middle; + dominant-baseline: hanging; + paint-order: stroke fill; + stroke: #1a1a1a; + stroke-width: 3px; + stroke-linejoin: round; } -.goal-fill.blue { - background: #3b82f6; +.chart-x-axis { + display: flex; + justify-content: space-between; + height: 18px; + align-items: center; + position: relative; + flex-shrink: 0; + overflow: hidden; } -.goal-fill.green { - background: #22c55e; +.x-label { + font-size: 11px; + color: #a1a1aa; + text-align: center; + flex: 1; + margin: 0; + line-height: 1; + position: relative; + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.x-label.current { + color: #ffffff; + font-weight: 500; } @@ -911,6 +1087,90 @@ .recommendation-badges { align-self: flex-start; } + + .card-header { + align-items: flex-start; + text-align: left; + } + + .card-header h4 { + text-align: left; + font-size: 16px; + } + + .card-header p { + text-align: left; + font-size: 13px; + } + + .header-content { + justify-content: flex-start; + } + + .ai-prediction-card { + padding: 16px; + height: auto; + min-height: 300px; + overflow: hidden; + } + + .prediction-chart { + padding: 12px; + min-height: 0; + overflow: hidden; + } + + .prediction-chart-container { + margin-top: 16px; + overflow: hidden; + } + + .chart-content { + min-height: 0; + overflow: hidden; + } + + .chart-lines { + overflow: visible; + width: 100%; + min-height: 0; + max-height: 100%; + } + + .prediction-svg { + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; + } + + .chart-x-axis { + height: 16px; + flex-shrink: 0; + overflow: hidden; + } + + .x-label { + font-size: 9px; + } + + .y-label { + font-size: 9px; + height: 0; + } + + .chart-y-axis { + width: 14px; + } + + .y-label { + font-size: 6px; + } + + .current-label { + font-size: 9px; + stroke-width: 2px; + } } /* Brainwave Chart Styles */ From ac04384c141eac0b0a5f37394ee59fb264e4a199 Mon Sep 17 00:00:00 2001 From: Mingi Chu Date: Fri, 17 Oct 2025 22:30:05 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EC=88=98=EC=A0=95=202?= =?UTF-8?q?=EC=B0=A8=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mong/pages/StatisticsAnalysis.tsx | 2 +- src/mong/styles/statistics.css | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mong/pages/StatisticsAnalysis.tsx b/src/mong/pages/StatisticsAnalysis.tsx index 9bb9c5c..fe66493 100644 --- a/src/mong/pages/StatisticsAnalysis.tsx +++ b/src/mong/pages/StatisticsAnalysis.tsx @@ -462,7 +462,7 @@ const StatisticsAnalysis: React.FC = () => {
- + {/* 격자 시스템: Y축 5개 라벨 (92, 89, 86, 83, 80) = 5개 수평선 */} {/* 격자 시스템: X축 6개 라벨 (1주전, 현재, 1주후, 2주후, 3주후, 4주후) = 6개 수직선 */} diff --git a/src/mong/styles/statistics.css b/src/mong/styles/statistics.css index c7eaa91..3b2f6a6 100644 --- a/src/mong/styles/statistics.css +++ b/src/mong/styles/statistics.css @@ -1137,12 +1137,13 @@ max-height: 100%; } - .prediction-svg { - width: 100%; - height: 100%; - max-width: 100%; - max-height: 100%; - } +.prediction-svg { + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; + display: block; +} .chart-x-axis { height: 16px; From 9d72c39655c5eb82c9ec0c943ba6644c7772033e Mon Sep 17 00:00:00 2001 From: Mingi Chu Date: Sat, 18 Oct 2025 09:37:23 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95=203=EC=B0=A8=20=EC=BB=A4?= =?UTF-8?q?=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mong/pages/StatisticsAnalysis.tsx | 21 ++++++++++++++++++++- src/mong/styles/statistics.css | 26 +++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/mong/pages/StatisticsAnalysis.tsx b/src/mong/pages/StatisticsAnalysis.tsx index fe66493..3c37da2 100644 --- a/src/mong/pages/StatisticsAnalysis.tsx +++ b/src/mong/pages/StatisticsAnalysis.tsx @@ -462,10 +462,19 @@ const StatisticsAnalysis: React.FC = () => {
- + {/* 격자 시스템: Y축 5개 라벨 (92, 89, 86, 83, 80) = 5개 수평선 */} {/* 격자 시스템: X축 6개 라벨 (1주전, 현재, 1주후, 2주후, 3주후, 4주후) = 6개 수직선 */} + {/* 좌표축 - X축과 Y축 화살표 실선 */} + {/* Y축 (세로축) - 아래에서 위로 화살표 */} + + + + {/* X축 (가로축) - 왼쪽에서 오른쪽으로 화살표 */} + + + {/* Y축 수평 격자선 - 5개 (Y축 라벨 개수만큼) */} @@ -522,6 +531,16 @@ const StatisticsAnalysis: React.FC = () => { {/* '현재' 텍스트 레이블 - 그래프와 겹치지 않도록 위치 조정 */} 현재 + + {/* 축 라벨 */} + {/* Y축 라벨 (수면 점수) - 한 글자씩 세로로 배치, X축과 동일한 간격 */} + + + + + + {/* X축 라벨 (시간) */} + 시간
diff --git a/src/mong/styles/statistics.css b/src/mong/styles/statistics.css index 3b2f6a6..31d6d0d 100644 --- a/src/mong/styles/statistics.css +++ b/src/mong/styles/statistics.css @@ -275,7 +275,7 @@ display: flex; flex-direction: column; justify-content: space-between; - width: 16px; + width: 40px; padding: 0; flex-shrink: 0; align-self: stretch; @@ -285,7 +285,7 @@ .y-label { font-size: 7px; color: #a1a1aa; - text-align: right; + text-align: center; line-height: 1; height: 0; display: flex; @@ -392,6 +392,26 @@ stroke-linejoin: round; } +.axis-label { + font-size: 12px; + font-weight: 600; + fill: #ffffff; + paint-order: stroke fill; + stroke: #1a1a1a; + stroke-width: 2px; + stroke-linejoin: round; +} + +.axis-label-vertical { + font-size: 12px; + font-weight: 600; + fill: #ffffff; + paint-order: stroke fill; + stroke: #1a1a1a; + stroke-width: 2px; + stroke-linejoin: round; +} + .chart-x-axis { display: flex; justify-content: space-between; @@ -1161,7 +1181,7 @@ } .chart-y-axis { - width: 14px; + width: 36px; } .y-label { From 80d03ffee9d9914223193812ca4a43d3b85dcfb7 Mon Sep 17 00:00:00 2001 From: Mingi Chu Date: Sat, 18 Oct 2025 09:56:51 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=ED=99=88=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mong/assets/heartIcon.svg | 3 +++ src/mong/assets/statisticsIcon.svg | 6 ++++++ src/mong/pages/Home.tsx | 10 ++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/mong/assets/heartIcon.svg create mode 100644 src/mong/assets/statisticsIcon.svg diff --git a/src/mong/assets/heartIcon.svg b/src/mong/assets/heartIcon.svg new file mode 100644 index 0000000..c105d31 --- /dev/null +++ b/src/mong/assets/heartIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/mong/assets/statisticsIcon.svg b/src/mong/assets/statisticsIcon.svg new file mode 100644 index 0000000..ba3926c --- /dev/null +++ b/src/mong/assets/statisticsIcon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/mong/pages/Home.tsx b/src/mong/pages/Home.tsx index baa7051..605ac56 100644 --- a/src/mong/pages/Home.tsx +++ b/src/mong/pages/Home.tsx @@ -1,6 +1,9 @@ import React from 'react' import { useNavigate } from 'react-router-dom'; import Container from '../components/Container' +import moonIcon from '../assets/moonIcon.svg' +import heartIcon from '../assets/heartIcon.svg' +import statisticsIcon from '../assets/statisticsIcon.svg' export default function Home() { const navigate = useNavigate(); @@ -9,7 +12,7 @@ export default function Home() {
-
+ moon

mong

@@ -22,16 +25,19 @@ export default function Home() { {[{ title: '스마트 수면 측정', desc: '정확한 수면 단계 분석으로 수면의 질을 측\n정합니다', + icon: moonIcon }, { title: '상세한 통계', desc: '개인 맞춤 수면 패턴 분석과 개선 제안을 제\n공합니다', + icon: statisticsIcon }, { title: '건강 관리', desc: '수면을 통한 전체적인 건강 상태 모니터링', + icon: heartIcon }].map((card, idx) => (

-
+ icon
{card.title}
{card.desc}
From 8177f65f68b23d45c05951b0687bd99f95304fec Mon Sep 17 00:00:00 2001 From: Mingi Chu Date: Sat, 18 Oct 2025 10:06:55 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=EB=B0=94=20UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mong/components/NavBar.tsx | 62 +++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/mong/components/NavBar.tsx b/src/mong/components/NavBar.tsx index dab1a70..7d4eb37 100644 --- a/src/mong/components/NavBar.tsx +++ b/src/mong/components/NavBar.tsx @@ -1,5 +1,5 @@ import React, { useState, useRef, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import moonIcon from '../assets/moonIcon.svg'; import '../styles/header.css'; @@ -20,6 +20,7 @@ const NavBar: React.FC = ({ userProfile, onLogout, onStartSleepReco const [isDropdownOpen, setIsDropdownOpen] = useState(false); const dropdownRef = useRef(null); const navigate = useNavigate(); + const location = useLocation(); // 드롭다운 외부 클릭 시 닫기 useEffect(() => { @@ -62,6 +63,15 @@ const NavBar: React.FC = ({ userProfile, onLogout, onStartSleepReco navigate(`/daily-report/${today}`); }; + const handleBackClick = () => { + navigate('/dashboard'); + }; + + // 현재 경로가 통계 또는 일별보고서 페이지인지 확인 + const isStatisticsPage = location.pathname === '/statistics'; + const isDailyReportPage = location.pathname.startsWith('/daily-report/'); + const showBackButton = isStatisticsPage || isDailyReportPage; + return (
@@ -73,36 +83,48 @@ const NavBar: React.FC = ({ userProfile, onLogout, onStartSleepReco
moon icon
- mong + mong
- {/* 중앙 메뉴 버튼들 - 가운데 고정 */} -
- - -
+ {/* 중앙 메뉴 버튼들 - 가운데 고정 (통계/일별보고서 페이지에서는 숨김) */} + {!showBackButton && ( +
+ + +
+ )} - {/* 수면 기록 시작 버튼 - 프로필 바로 왼쪽 */} + {/* 수면 기록 시작 버튼 또는 뒤로가기 버튼 - 프로필 바로 왼쪽 */}
- {showStartButton && ( + {showBackButton ? ( + + ) : showStartButton ? ( - )} + ) : null} {/* 사용자 드롭다운 */}