diff --git a/src/app/logs/page.tsx b/src/app/logs/page.tsx index d6941e6..4466ea8 100644 --- a/src/app/logs/page.tsx +++ b/src/app/logs/page.tsx @@ -94,8 +94,8 @@ export default function LogsPage() { // carLogs를 VehicleLog 형식으로 변환해서 전달 const mappedLogs = carLogs.map(log => { // API 응답의 driveType을 변환 - let driveType: DriveType = 'UNREGISTERED'; - if (log.driveType === 'COMMUTE' || log.driveType === 'WORK') { + let driveType: DriveType = 'UNCLASSIFIED'; + if (log.driveType === 'COMMUTE' || log.driveType === 'BUSINESS' || log.driveType === 'PERSONAL') { driveType = log.driveType as DriveType; } diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx index 9b02a3c..172347b 100644 --- a/src/app/profile/page.tsx +++ b/src/app/profile/page.tsx @@ -183,7 +183,7 @@ export default function ProfilePage() { setIsLoading(true); setApiError(null); - await fetchApi('/api/users/password', undefined, { + await fetchApi<{data: any, message: string, statusCode: number}>('/api/users/password', undefined, { method: 'PUT', headers: { 'Content-Type': 'application/json', @@ -234,7 +234,10 @@ export default function ProfilePage() { setLoadingPermissions(true); try { - const response = await fetchApi<{ permissionTypes: string[] }>('/api/users/permissions/my'); + const apiResponse = await fetchApi<{data: { permissionTypes: string[] }, message: string, statusCode: number}>('/api/users/permissions/my'); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const response = apiResponse.data || apiResponse; if (response && response.permissionTypes) { // 권한 ID 배열을 Permission 객체로 변환 diff --git a/src/components/logs/VehicleLogDetailSlidePanel.tsx b/src/components/logs/VehicleLogDetailSlidePanel.tsx index a18fbe7..2c894a4 100644 --- a/src/components/logs/VehicleLogDetailSlidePanel.tsx +++ b/src/components/logs/VehicleLogDetailSlidePanel.tsx @@ -108,7 +108,7 @@ export default function VehicleLogDetailSlidePanel({ isOpen, onClose, log, onDel if (editedLog) { try { const updateData = { - driveType: editedLog.driveType === 'UNREGISTERED' ? null : editedLog.driveType, + driveType: editedLog.driveType, driver: editedLog.driver?.name || '', description: editedLog.note || '' }; @@ -206,20 +206,22 @@ export default function VehicleLogDetailSlidePanel({ isOpen, onClose, log, onDel switch (type) { case 'COMMUTE': return 'bg-blue-50 text-blue-700 dark:bg-blue-50 dark:text-blue-700'; - case 'WORK': + case 'BUSINESS': return 'bg-teal-50 text-teal-700 dark:bg-teal-50 dark:text-teal-700'; - case 'UNREGISTERED': - return 'bg-slate-50 text-slate-700 dark:bg-slate-50 dark:text-slate-700'; + case 'PERSONAL': + return 'bg-purple-50 text-purple-700 dark:bg-purple-50 dark:text-purple-700'; + case 'UNCLASSIFIED': default: - return ''; + return 'bg-slate-50 text-slate-700 dark:bg-slate-50 dark:text-slate-700'; } }; const getDriveTypeLabel = (type: DriveType) => { const types = { COMMUTE: '출퇴근', - WORK: '업무', - UNREGISTERED: '미등록', + BUSINESS: '업무', + PERSONAL: '개인', + UNCLASSIFIED: '미분류', } as const; return types[type]; }; @@ -355,8 +357,9 @@ export default function VehicleLogDetailSlidePanel({ isOpen, onClose, log, onDel className={`ml-2 rounded-md border ${currentTheme.border} ${currentTheme.inputBg} ${currentTheme.text} px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500`} > - - + + + )} diff --git a/src/components/logs/VehicleLogFilter.tsx b/src/components/logs/VehicleLogFilter.tsx index 00e9fb8..f9fafca 100644 --- a/src/components/logs/VehicleLogFilter.tsx +++ b/src/components/logs/VehicleLogFilter.tsx @@ -156,7 +156,7 @@ export function VehicleLogFilter({ onChange, onApplyFilter, initialFilter }: Veh -
+
@@ -197,6 +197,33 @@ export function VehicleLogFilter({ onChange, onApplyFilter, initialFilter }: Veh )}
+
+ +
+ + {localFilter.driveType && ( +
+ +
+ )} +
+
diff --git a/src/components/logs/VehicleLogList.tsx b/src/components/logs/VehicleLogList.tsx index 2b46c54..8a4441e 100644 --- a/src/components/logs/VehicleLogList.tsx +++ b/src/components/logs/VehicleLogList.tsx @@ -47,8 +47,8 @@ export function VehicleLogList({ const mappedLogs = useMemo(() => { return carLogs.map(log => { // API 응답의 driveType을 변환 - let driveType: DriveType = 'UNREGISTERED'; - if (log.driveType === 'COMMUTE' || log.driveType === 'WORK') { + let driveType: DriveType = 'UNCLASSIFIED'; + if (log.driveType === 'COMMUTE' || log.driveType === 'BUSINESS' || log.driveType === 'PERSONAL') { driveType = log.driveType as DriveType; } @@ -108,20 +108,22 @@ export function VehicleLogList({ switch (type) { case 'COMMUTE': return 'bg-blue-50 text-blue-700 dark:bg-blue-50 dark:text-blue-700'; - case 'WORK': + case 'BUSINESS': return 'bg-teal-50 text-teal-700 dark:bg-teal-50 dark:text-teal-700'; - case 'UNREGISTERED': - return 'bg-slate-50 text-slate-700 dark:bg-slate-50 dark:text-slate-700'; + case 'PERSONAL': + return 'bg-purple-50 text-purple-700 dark:bg-purple-50 dark:text-purple-700'; + case 'UNCLASSIFIED': default: - return ''; + return 'bg-slate-50 text-slate-700 dark:bg-slate-50 dark:text-slate-700'; } }; const getDriveTypeLabel = (type: DriveType) => { const types = { COMMUTE: '출퇴근', - WORK: '업무', - UNREGISTERED: '미등록', + BUSINESS: '업무', + PERSONAL: '개인', + UNCLASSIFIED: '미분류', } as const; return types[type]; }; diff --git a/src/lib/announcementStore.ts b/src/lib/announcementStore.ts index e620a1b..f288d39 100644 --- a/src/lib/announcementStore.ts +++ b/src/lib/announcementStore.ts @@ -29,12 +29,15 @@ export const useAnnouncementStore = create((set) => ({ fetchAnnouncements: async (page = 0, size = 10) => { set({ isLoading: true, error: null }); try { - const response = await fetchApi('/api/announcement', { + const apiResponse = await fetchApi<{data: AnnouncementsResponse, message: string, statusCode: number}>('/api/announcements', { page, size }); - console.log('API 원본 응답:', response); + console.log('API 원본 응답:', apiResponse); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const response = apiResponse.data || apiResponse; // announcementId를 id로 매핑하여 처리 const processedAnnouncements = response.content.map((item, index) => { @@ -73,9 +76,12 @@ export const useAnnouncementStore = create((set) => ({ fetchAnnouncementDetail: async (id: number) => { set({ isLoading: true, error: null }); try { - const response = await fetchApi(`/api/announcement/${id}`); + const apiResponse = await fetchApi<{data: AnnouncementApiResponse, message: string, statusCode: number}>(`/api/announcements/${id}`); + + console.log('상세 API 원본 응답:', apiResponse); - console.log('상세 API 원본 응답:', response); + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const response = apiResponse.data || apiResponse; // announcementId를 id로 매핑하여 처리 const processedDetail = { diff --git a/src/lib/authStore.ts b/src/lib/authStore.ts index d2d4fc4..28a79ab 100644 --- a/src/lib/authStore.ts +++ b/src/lib/authStore.ts @@ -147,7 +147,10 @@ export const useAuthStore = create((set, get) => ({ set({ profileLoading: true, profileError: null }); // 백엔드 API 호출 - const response = await fetchApi('/api/users/my'); + const apiResponse = await fetchApi<{data: UserResponse, message: string, statusCode: number}>('/api/users/my'); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const response = apiResponse.data || apiResponse; // API 응답을 UserInfo 형태로 변환 const userInfo: UserInfo = { @@ -322,7 +325,7 @@ export const useAuthStore = create((set, get) => ({ // 사용자 정보 업데이트 updateUserProfile: async (userRequest: UserRequest) => { try { - await fetchApi('/api/users/my', undefined, { + await fetchApi<{data: any, message: string, statusCode: number}>('/api/users/my', undefined, { method: 'PUT', body: JSON.stringify(userRequest) }); diff --git a/src/lib/carLogsStore.ts b/src/lib/carLogsStore.ts index 31bfb2f..2a81260 100644 --- a/src/lib/carLogsStore.ts +++ b/src/lib/carLogsStore.ts @@ -125,14 +125,17 @@ export const useCarLogsStore = create((set, get) => ({ requestBody.driveType = driveType; } - const data = await fetchApi(`/api/carLogs?page=${page}&size=${size}`, undefined, { + const data = await fetchApi<{data: any, message: string, statusCode: number}>(`/api/carLogs?page=${page}&size=${size}`, undefined, { method: 'POST', body: JSON.stringify(requestBody) }); - const content = Array.isArray(data.content) ? data.content : (Array.isArray(data) ? data : []); - const totalPages = data.totalPages || 1; - const totalElements = data.totalElements || content.length; + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const responseData = data.data || data; + + const content = Array.isArray(responseData.content) ? responseData.content : (Array.isArray(responseData) ? responseData : []); + const totalPages = responseData.totalPages || 1; + const totalElements = responseData.totalElements || content.length; if (params) { const newFilter = { ...currentFilter }; @@ -158,7 +161,7 @@ export const useCarLogsStore = create((set, get) => ({ }); } - return data; + return responseData; } catch (error) { console.error('운행일지 데이터 가져오기 실패:', error); set({ @@ -173,10 +176,13 @@ export const useCarLogsStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const data = await fetchApi('/api/carLogs/statics', undefined, { + const response = await fetchApi<{data: any, message: string, statusCode: number}>('/api/carLogs/statics', undefined, { method: 'GET' }); + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const data = response.data || response; + set({ stats: { totalMileage: data.totalMileage || 0, @@ -198,7 +204,7 @@ export const useCarLogsStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const responseText = await fetchApi(`/api/carLogs/${logId}`, undefined, { + const response = await fetchApi<{data: string, message: string, statusCode: number}>(`/api/carLogs/${logId}`, undefined, { method: 'PUT', body: JSON.stringify(data) }); @@ -207,7 +213,7 @@ export const useCarLogsStore = create((set, get) => ({ return { success: true, - message: responseText || '운행일지가 성공적으로 수정되었습니다.' + message: response.message || response.data || '운행일지가 성공적으로 수정되었습니다.' }; } catch (error) { console.error('운행일지 수정 실패:', error); @@ -227,7 +233,7 @@ export const useCarLogsStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const responseText = await fetchApi(`/api/carLogs/${logId}`, undefined, { + const response = await fetchApi<{data: string, message: string, statusCode: number}>(`/api/carLogs/${logId}`, undefined, { method: 'DELETE' }); @@ -235,7 +241,7 @@ export const useCarLogsStore = create((set, get) => ({ return { success: true, - message: responseText || '운행일지가 성공적으로 삭제되었습니다.' + message: response.message || response.data || '운행일지가 성공적으로 삭제되었습니다.' }; } catch (error) { console.error('운행일지 삭제 실패:', error); diff --git a/src/lib/carOverviewStore.ts b/src/lib/carOverviewStore.ts index 710058d..bae2817 100644 --- a/src/lib/carOverviewStore.ts +++ b/src/lib/carOverviewStore.ts @@ -26,7 +26,10 @@ export const useCarOverviewStore = create((set) => ({ try { set({ isLoading: true, error: null }); - const data = await fetchApi('/api/cars/overview'); + const response = await fetchApi<{data: CarOverviewData, message: string, statusCode: number}>('/api/cars/overview'); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const data = response.data || response; set({ data: data, diff --git a/src/lib/companyStore.ts b/src/lib/companyStore.ts index c9a9720..e086484 100644 --- a/src/lib/companyStore.ts +++ b/src/lib/companyStore.ts @@ -45,7 +45,10 @@ export const useCompanyStore = create((set) => ({ try { set({ isLoading: true, error: null }); - const data = await fetchApi('/api/companies/my'); + const response = await fetchApi<{data: CompanyResponse, message: string, statusCode: number}>('/api/companies/my'); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const data = response.data || response; set({ company: data, @@ -66,13 +69,14 @@ export const useCompanyStore = create((set) => ({ try { set({ updating: true, updateError: null, updateSuccess: false }); - await fetchApi('/api/companies/my', undefined, { + const updateResponse = await fetchApi<{data: any, message: string, statusCode: number}>('/api/companies/my', undefined, { method: 'PUT', body: JSON.stringify(companyRequest) }); // 업데이트가 성공하면 회사 정보를 다시 가져옴 - const updatedCompany = await fetchApi('/api/companies/my'); + const response = await fetchApi<{data: CompanyResponse, message: string, statusCode: number}>('/api/companies/my'); + const updatedCompany = response.data || response; set({ company: updatedCompany, diff --git a/src/lib/userStore.ts b/src/lib/userStore.ts index c8fdfd0..ee74395 100644 --- a/src/lib/userStore.ts +++ b/src/lib/userStore.ts @@ -52,7 +52,10 @@ export const useUserStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const data = await fetchApi('/api/users/companies/my'); + const response = await fetchApi<{data: UserResponse[], message: string, statusCode: number}>('/api/users/companies/my'); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const data = response.data || response; set({ users: data, @@ -74,26 +77,29 @@ export const useUserStore = create((set, get) => ({ set({ loadingPermissions: true, permissionsError: null }); // API에서 권한 정보 가져오기 - const response = await fetchApi(`/api/users/permissions/${userId}`); + const response = await fetchApi<{data: any, message: string, statusCode: number}>(`/api/users/permissions/${userId}`); + + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const permissionData = response.data || response; // 응답에서 권한 타입 배열 추출 (다양한 응답 형식 처리) let permissionIds: string[] = []; // 응답이 배열인 경우 (API가 권한 ID 목록을 직접 반환) - if (Array.isArray(response)) { - permissionIds = response; + if (Array.isArray(permissionData)) { + permissionIds = permissionData; } // 응답이 객체이고 permissionTypes 속성이 있는 경우 - else if (response && response.permissionTypes) { - permissionIds = Array.isArray(response.permissionTypes) - ? response.permissionTypes + else if (permissionData && permissionData.permissionTypes) { + permissionIds = Array.isArray(permissionData.permissionTypes) + ? permissionData.permissionTypes : []; } // 응답이 객체이고 권한 관련 다른 형식인 경우 - else if (response && typeof response === 'object') { + else if (permissionData && typeof permissionData === 'object') { // 객체의 모든 키를 검사하여 권한 ID 같은 형식(PERM_ 접두사)을 찾음 - Object.keys(response).forEach(key => { - if (typeof response[key] === 'boolean' && response[key] === true && key.startsWith('PERM_')) { + Object.keys(permissionData).forEach(key => { + if (typeof permissionData[key] === 'boolean' && permissionData[key] === true && key.startsWith('PERM_')) { permissionIds.push(key); } }); @@ -178,14 +184,15 @@ export const useUserStore = create((set, get) => ({ delete requestData.password; } - await fetchApi(`/api/users/${userId}`, undefined, { + const updateResponse = await fetchApi<{data: any, message: string, statusCode: number}>(`/api/users/${userId}`, undefined, { method: 'PUT', body: JSON.stringify(requestData) }); // API에서 업데이트된 사용자 정보 다시 조회 try { - const updatedUser = await fetchApi(`/api/users/${userId}`); + const response = await fetchApi<{data: UserResponse, message: string, statusCode: number}>(`/api/users/${userId}`); + const updatedUser = response.data || response; console.log(`업데이트된 사용자 정보 조회 (ID: ${userId}):`, updatedUser); // 스토어의 사용자 데이터 업데이트 (API에서 받은 최신 정보 사용) @@ -218,21 +225,24 @@ export const useUserStore = create((set, get) => ({ fetchUser: async (userId: string) => { try { - const response = await fetchApi(`/api/users/${userId}`); + const response = await fetchApi<{data: UserResponse, message: string, statusCode: number}>(`/api/users/${userId}`); console.log(`API에서 사용자 정보 가져옴 (ID: ${userId}):`, response); + // 새로운 API 응답 형식 처리 (data 필드에 실제 데이터가 있음) + const userData = response.data || response; + // 캐시된 사용자 목록에 없는 경우 추가 set((state) => { const exists = state.users.some(u => u.userId.toString() === userId); if (!exists) { return { - users: [...state.users, response] + users: [...state.users, userData] }; } return state; }); - return response; + return userData; } catch (error) { console.error(`사용자 정보 가져오기 실패 (ID: ${userId}):`, error); return undefined; @@ -241,7 +251,7 @@ export const useUserStore = create((set, get) => ({ deleteUser: async (userId: string) => { try { - const response = await fetchApi(`/api/users/${userId}`, undefined, { + const response = await fetchApi<{data: any, message: string, statusCode: number}>(`/api/users/${userId}`, undefined, { method: 'DELETE' }); diff --git a/src/lib/vehicleStore.ts b/src/lib/vehicleStore.ts index c00a956..3a98286 100644 --- a/src/lib/vehicleStore.ts +++ b/src/lib/vehicleStore.ts @@ -39,16 +39,18 @@ export const useVehicleStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const overviewData = await fetchApi<{totalCars: number}>('/api/cars/overview'); + const overviewResponse = await fetchApi<{data: {totalCars: number}, message: string, statusCode: number}>('/api/cars/overview'); + const overviewData = overviewResponse.data || overviewResponse; const totalCars = overviewData.totalCars || 100; - const response = await fetchApi(`/api/cars?page=0&size=${totalCars}`); + const response = await fetchApi<{data: Vehicle[] | {content: Vehicle[], totalElements: number}, message: string, statusCode: number}>(`/api/cars?page=0&size=${totalCars}`); + const responseData = response.data || response; let vehicles: Vehicle[]; - if (Array.isArray(response)) { - vehicles = response; - } else if (response && typeof response === 'object' && 'content' in response) { - vehicles = response.content; + if (Array.isArray(responseData)) { + vehicles = responseData; + } else if (responseData && typeof responseData === 'object' && 'content' in responseData) { + vehicles = responseData.content; } else { vehicles = []; } @@ -68,7 +70,7 @@ export const useVehicleStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const response = await fetchApi('/api/cars', undefined, { + const response = await fetchApi<{data: string, message: string, statusCode: number}>('/api/cars', undefined, { method: 'POST', body: JSON.stringify(vehicle), }); @@ -78,8 +80,12 @@ export const useVehicleStore = create((set, get) => ({ set({ isLoading: false }); - if (typeof response === 'string') { - return response; + const responseData = response.data || response; + + if (typeof responseData === 'string') { + return responseData; + } else if (response.message) { + return response.message; } else { return '차량이 성공적으로 등록되었습니다.'; } @@ -98,7 +104,7 @@ export const useVehicleStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - const response = await fetchApi(`/api/cars/${vehicle.id}`, undefined, { + const response = await fetchApi<{data: string, message: string, statusCode: number}>(`/api/cars/${vehicle.id}`, undefined, { method: 'PUT', body: JSON.stringify(vehicle), }); @@ -109,9 +115,13 @@ export const useVehicleStore = create((set, get) => ({ set({ isLoading: false }); + const responseData = response.data || response; + // 응답이 문자열이라면 그대로 반환, 아니라면 기본 성공 메시지 반환 - if (typeof response === 'string') { - return response; + if (typeof responseData === 'string') { + return responseData; + } else if (response.message) { + return response.message; } else { return '차량 정보가 성공적으로 수정되었습니다.'; } @@ -129,7 +139,7 @@ export const useVehicleStore = create((set, get) => ({ try { set({ isLoading: true, error: null }); - await fetchApi(`/api/cars/${id}`, undefined, { + await fetchApi<{data: any, message: string, statusCode: number}>(`/api/cars/${id}`, undefined, { method: 'DELETE', }); diff --git a/src/types/logs.ts b/src/types/logs.ts index 3d5d6a4..972fb8e 100644 --- a/src/types/logs.ts +++ b/src/types/logs.ts @@ -1,4 +1,4 @@ -export type DriveType = 'COMMUTE' | 'WORK' | 'UNREGISTERED'; +export type DriveType = 'UNCLASSIFIED' | 'COMMUTE' | 'BUSINESS' | 'PERSONAL'; export interface Driver { id: string;