feat: Phase 2 프론트엔드 타입 및 API 연동
- API 타입 정의 추가 (LoanDashboard, TaxSimulation) - API 엔드포인트 함수 추가 (endpoints.ts) - 모달 데이터 훅 생성 (useCardManagementModals.ts) 관련: docs/plans/card-management-section-plan.md
This commit is contained in:
242
src/lib/api/dashboard/endpoints.ts
Normal file
242
src/lib/api/dashboard/endpoints.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
'use server';
|
||||
|
||||
/**
|
||||
* CEO Dashboard API 엔드포인트 함수
|
||||
*
|
||||
* 카드/가지급금 관리 섹션 (cm1-cm4) 데이터 조회
|
||||
*/
|
||||
|
||||
import { apiClient } from '../index';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
import type {
|
||||
ApiResponse,
|
||||
CardDashboardDetailApiResponse,
|
||||
LoanDashboardApiResponse,
|
||||
TaxSimulationApiResponse,
|
||||
} from './types';
|
||||
|
||||
// ============================================
|
||||
// 에러 핸들링 헬퍼
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 인증 에러인지 확인
|
||||
*/
|
||||
function isAuthenticationError(error: unknown): boolean {
|
||||
if (error && typeof error === 'object') {
|
||||
const err = error as { status?: number; code?: string; message?: string };
|
||||
if (err.status === 401) return true;
|
||||
if (err.code === 'AUTH_ERROR') return true;
|
||||
if (err.message?.includes('회원정보') || err.message?.includes('인증')) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 카드 거래 대시보드 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 카드 거래 대시보드 데이터 조회
|
||||
* GET /api/v1/card-transactions/dashboard
|
||||
*
|
||||
* @returns 카드 거래 요약, 월별 추이, 사용자별 분포, 거래 목록
|
||||
*/
|
||||
export async function fetchCardTransactionDashboard(): Promise<ApiResponse<CardDashboardDetailApiResponse>> {
|
||||
try {
|
||||
const response = await apiClient.get<ApiResponse<CardDashboardDetailApiResponse>>(
|
||||
'/card-transactions/dashboard'
|
||||
);
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Next.js redirect 에러는 전파
|
||||
if (isNextRedirectError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error('[Dashboard] fetchCardTransactionDashboard error:', error);
|
||||
|
||||
// 인증 에러인 경우
|
||||
if (isAuthenticationError(error)) {
|
||||
return {
|
||||
success: false,
|
||||
message: '인증이 만료되었습니다.',
|
||||
data: {
|
||||
summary: {
|
||||
current_month_total: 0,
|
||||
previous_month_total: 0,
|
||||
total_count: 0,
|
||||
current_month_count: 0,
|
||||
},
|
||||
monthly_trend: [],
|
||||
by_user: [],
|
||||
items: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 기타 에러
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'API 요청 실패',
|
||||
data: {
|
||||
summary: {
|
||||
current_month_total: 0,
|
||||
previous_month_total: 0,
|
||||
total_count: 0,
|
||||
current_month_count: 0,
|
||||
},
|
||||
monthly_trend: [],
|
||||
by_user: [],
|
||||
items: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 가지급금 대시보드 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 가지급금 대시보드 데이터 조회
|
||||
* GET /api/v1/loans/dashboard
|
||||
*
|
||||
* @returns 가지급금 요약, 월별 추이, 사용자별 분포, 거래 목록
|
||||
*/
|
||||
export async function fetchLoanDashboard(): Promise<ApiResponse<LoanDashboardApiResponse>> {
|
||||
try {
|
||||
const response = await apiClient.get<ApiResponse<LoanDashboardApiResponse>>(
|
||||
'/loans/dashboard'
|
||||
);
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Next.js redirect 에러는 전파
|
||||
if (isNextRedirectError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error('[Dashboard] fetchLoanDashboard error:', error);
|
||||
|
||||
// 인증 에러인 경우
|
||||
if (isAuthenticationError(error)) {
|
||||
return {
|
||||
success: false,
|
||||
message: '인증이 만료되었습니다.',
|
||||
data: {
|
||||
summary: {
|
||||
total_outstanding: 0,
|
||||
settled_amount: 0,
|
||||
recognized_interest: 0,
|
||||
pending_count: 0,
|
||||
},
|
||||
monthly_trend: [],
|
||||
user_distribution: [],
|
||||
items: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 기타 에러
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'API 요청 실패',
|
||||
data: {
|
||||
summary: {
|
||||
total_outstanding: 0,
|
||||
settled_amount: 0,
|
||||
recognized_interest: 0,
|
||||
pending_count: 0,
|
||||
},
|
||||
monthly_trend: [],
|
||||
user_distribution: [],
|
||||
items: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 세금 시뮬레이션 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 세금 시뮬레이션 데이터 조회
|
||||
* GET /api/v1/loans/tax-simulation?year={year}
|
||||
*
|
||||
* @param year - 시뮬레이션 연도 (기본값: 현재 연도)
|
||||
* @returns 가지급금 요약, 법인세 비교, 소득세 비교
|
||||
*/
|
||||
export async function fetchTaxSimulation(year?: number): Promise<ApiResponse<TaxSimulationApiResponse>> {
|
||||
try {
|
||||
const targetYear = year || new Date().getFullYear();
|
||||
const response = await apiClient.get<ApiResponse<TaxSimulationApiResponse>>(
|
||||
'/loans/tax-simulation',
|
||||
{ params: { year: String(targetYear) } }
|
||||
);
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Next.js redirect 에러는 전파
|
||||
if (isNextRedirectError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error('[Dashboard] fetchTaxSimulation error:', error);
|
||||
|
||||
const currentYear = year || new Date().getFullYear();
|
||||
|
||||
// 인증 에러인 경우
|
||||
if (isAuthenticationError(error)) {
|
||||
return {
|
||||
success: false,
|
||||
message: '인증이 만료되었습니다.',
|
||||
data: {
|
||||
year: currentYear,
|
||||
loan_summary: {
|
||||
total_outstanding: 0,
|
||||
recognized_interest: 0,
|
||||
interest_rate: 0.046,
|
||||
},
|
||||
corporate_tax: {
|
||||
without_loan: { taxable_income: 0, tax_amount: 0 },
|
||||
with_loan: { taxable_income: 0, tax_amount: 0 },
|
||||
difference: 0,
|
||||
rate_info: '법인세 19% 적용',
|
||||
},
|
||||
income_tax: {
|
||||
without_loan: { taxable_income: 0, tax_rate: '0%', tax_amount: 0 },
|
||||
with_loan: { taxable_income: 0, tax_rate: '35%', tax_amount: 0 },
|
||||
difference: 0,
|
||||
breakdown: { income_tax: 0, local_tax: 0, insurance: 0 },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 기타 에러
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'API 요청 실패',
|
||||
data: {
|
||||
year: currentYear,
|
||||
loan_summary: {
|
||||
total_outstanding: 0,
|
||||
recognized_interest: 0,
|
||||
interest_rate: 0.046,
|
||||
},
|
||||
corporate_tax: {
|
||||
without_loan: { taxable_income: 0, tax_amount: 0 },
|
||||
with_loan: { taxable_income: 0, tax_amount: 0 },
|
||||
difference: 0,
|
||||
rate_info: '법인세 19% 적용',
|
||||
},
|
||||
income_tax: {
|
||||
without_loan: { taxable_income: 0, tax_rate: '0%', tax_amount: 0 },
|
||||
with_loan: { taxable_income: 0, tax_rate: '35%', tax_amount: 0 },
|
||||
difference: 0,
|
||||
breakdown: { income_tax: 0, local_tax: 0, insurance: 0 },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user