Skip to content

Commit 18a3c06

Browse files
authored
Merge pull request #203 from prgrms-aibe-devcourse/feat/expense-LLM
refactor: 로그인 인증 실패 로직 변경
2 parents 97558b6 + 9a7e8d3 commit 18a3c06

5 files changed

Lines changed: 86 additions & 24 deletions

File tree

src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import { useAppStore } from "./store/appStore.ts";
3434
import YouthPolicyList from "./components/youthpolicy/YouthPolicyList";
3535
import YouthPolicyDetailPage from "./components/youthpolicy/YouthPolicyDetailPage";
3636

37+
import AuthNavigator from "./utils/AuthNavigator"; // 추가
38+
3739
function App() {
3840
const { isAuthenticated, user } = useAuthStore();
3941
const { getCurrentUser } = useAuth();
@@ -123,6 +125,7 @@ function App() {
123125
v7_relativeSplatPath: true,
124126
}}
125127
>
128+
<AuthNavigator /> {/* 추가 */}
126129
<ScrollToTop />
127130
{/* Version indicator for debugging */}
128131
<div

src/api/calendar.ts

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class CalendarApi {
6767
const hours = date.getHours().toString().padStart(2, '0');
6868
const minutes = date.getMinutes().toString().padStart(2, '0');
6969
const seconds = date.getSeconds().toString().padStart(2, '0');
70-
70+
7171
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
7272
}
7373

@@ -77,13 +77,13 @@ export class CalendarApi {
7777
private extractTimeFromDate(date: Date | string): string {
7878
// 백엔드에서 LocalDateTime으로 오는 데이터를 로컬 시간으로 처리
7979
// 예: "2025-06-23T09:00:00" → "09:00"
80-
80+
8181
if (date instanceof Date) {
8282
const hours = date.getHours();
8383
const minutes = date.getMinutes();
8484
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
8585
}
86-
86+
8787
// Date가 아닌 경우 (문자열 등) ISO 문자열에서 추출
8888
const dateStr = String(date);
8989
const timeMatch = dateStr.match(/T(\d{2}:\d{2})/);
@@ -148,9 +148,9 @@ export class CalendarApi {
148148
// startDate에서 시간 추출 (시간대 보정)
149149
const startTime = calendar?.isAllDay ? '' : this.extractTimeFromDate(safeStartDate);
150150
const endTime = calendar?.isAllDay ? '' : (
151-
calendar?.endDate
152-
? this.extractTimeFromDate(new Date(calendar.endDate))
153-
: this.extractTimeFromDate(new Date(safeStartDate.getTime() + 60 * 60 * 1000))
151+
calendar?.endDate
152+
? this.extractTimeFromDate(new Date(calendar.endDate))
153+
: this.extractTimeFromDate(new Date(safeStartDate.getTime() + 60 * 60 * 1000))
154154
);
155155

156156
// exceptionDates 처리
@@ -242,7 +242,7 @@ export class CalendarApi {
242242
*/
243243
private mapRepeatTypeFromBackend(repeatType?: string): 'none' | 'daily' | 'weekly' | 'monthly' | 'yearly' {
244244
if (!repeatType) return 'none';
245-
245+
246246
switch (repeatType.toUpperCase()) {
247247
case 'DAILY': return 'daily';
248248
case 'WEEKLY': return 'weekly';
@@ -304,13 +304,13 @@ export class CalendarApi {
304304
Object.entries(query).forEach(([key, value]) => {
305305
if (value !== undefined) {
306306
let stringValue = String(value);
307-
307+
308308
// dateTime 파라미터의 경우 LocalDateTime 호환 형식으로 변환
309309
if (key === 'dateTime' && typeof value === 'string') {
310310
// ISO 문자열에서 Z 제거하고 밀리초 제거
311311
stringValue = value.replace('Z', '').split('.')[0];
312312
}
313-
313+
314314
searchParams.append(key, stringValue);
315315
}
316316
});
@@ -357,10 +357,10 @@ export class CalendarApi {
357357
if (response.data) {
358358
const responseData = response.data.data || response.data;
359359
const event = this.calendarToEvent(responseData);
360-
return {
361-
success: true,
362-
data: event,
363-
message: response.data.message
360+
return {
361+
success: true,
362+
data: event,
363+
message: response.data.message
364364
};
365365
}
366366

@@ -383,11 +383,17 @@ export class CalendarApi {
383383
try {
384384
const requestData = this.eventToCalendarRequest(eventData);
385385

386-
const response = await apiClient.post('/api/v1/calendars', requestData);
386+
// groupId가 있으면 URL 파라미터로 추가
387+
let endpoint = '/api/v1/calendars';
388+
if (eventData.groupId) {
389+
endpoint += `?groupId=${eventData.groupId}`;
390+
}
391+
392+
const response = await apiClient.post(endpoint, requestData);
387393

388394
if (response.data) {
389395
const responseData = response.data.data || response.data;
390-
396+
391397
// 응답 데이터 유효성 검사
392398
if (!responseData.calendarId) {
393399
// 임시 ID 할당
@@ -428,10 +434,10 @@ export class CalendarApi {
428434
if (response.data) {
429435
const responseData = response.data.data || response.data;
430436
const event = this.calendarToEvent(responseData);
431-
return {
432-
success: true,
433-
data: event,
434-
message: response.data.message
437+
return {
438+
success: true,
439+
data: event,
440+
message: response.data.message
435441
};
436442
}
437443

@@ -457,7 +463,7 @@ export class CalendarApi {
457463
console.log('[CalendarApi] Deleting calendar:', endpoint);
458464

459465
const response = await apiClient.delete(endpoint);
460-
466+
461467
return {
462468
success: true,
463469
message: response.data?.message || 'Calendar deleted successfully'
@@ -480,13 +486,13 @@ export class CalendarApi {
480486
Object.entries(query).forEach(([key, value]) => {
481487
if (value !== undefined) {
482488
let stringValue = String(value);
483-
489+
484490
// dateTime 파라미터의 경우 LocalDateTime 호환 형식으로 변환
485491
if (key === 'dateTime' && typeof value === 'string') {
486492
// ISO 문자열에서 Z 제거하고 밀리초 제거
487493
stringValue = value.replace('Z', '').split('.')[0];
488494
}
489-
495+
490496
searchParams.append(key, stringValue);
491497
}
492498
});

src/utils/AuthNavigator.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useEffect } from 'react';
2+
import { useNavigate } from 'react-router-dom';
3+
import { eventEmitter } from './eventEmitter';
4+
5+
const AuthNavigator = () => {
6+
const navigate = useNavigate();
7+
8+
useEffect(() => {
9+
const handleUnauthorized = () => {
10+
navigate('/login');
11+
};
12+
13+
const unsubscribe = eventEmitter.on('unauthorized', handleUnauthorized);
14+
15+
return () => {
16+
unsubscribe();
17+
};
18+
}, [navigate]);
19+
20+
return null;
21+
};
22+
23+
export default AuthNavigator;

src/utils/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import axios from "axios";
22
import { useAuthStore } from "../store/authStore";
33
import toast from "react-hot-toast";
4+
import { eventEmitter } from "./eventEmitter"; // 추가
45

56
const getApiBaseUrl = () => {
67
const envUrl = import.meta.env.VITE_API_BASE_URL;
@@ -50,10 +51,10 @@ const handleUnauthorized = () => {
5051
}
5152
});
5253

53-
// 3초 후 로그인 페이지로 이동
54+
// 1초 후 로그인 페이지로 이동 (이벤트 발생)
5455
setTimeout(() => {
5556
authErrorShown = false;
56-
window.location.href = "/login";
57+
eventEmitter.emit('unauthorized'); // 변경
5758
}, 1000);
5859
}
5960
};

src/utils/eventEmitter.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
type EventListener = (...args: any[]) => void;
2+
3+
class EventEmitter {
4+
private events: { [key: string]: EventListener[] } = {};
5+
6+
on(event: string, listener: EventListener): () => void {
7+
if (!this.events[event]) {
8+
this.events[event] = [];
9+
}
10+
this.events[event].push(listener);
11+
return () => this.off(event, listener);
12+
}
13+
14+
off(event: string, listener: EventListener): void {
15+
if (!this.events[event]) {
16+
return;
17+
}
18+
this.events[event] = this.events[event].filter(l => l !== listener);
19+
}
20+
21+
emit(event: string, ...args: any[]): void {
22+
if (!this.events[event]) {
23+
return;
24+
}
25+
this.events[event].forEach(listener => listener(...args));
26+
}
27+
}
28+
29+
export const eventEmitter = new EventEmitter();

0 commit comments

Comments
 (0)