feat(CEODashboard): Phase 4 - 카드/가지급금 관리 섹션 카드 API 연동

카드/가지급금 관리 섹션의 4개 카드(cm1~cm4)를 실제 API 데이터로 연동:

- cm1: 카드 사용액 - CardTransaction API (기존)
- cm2: 가지급금 - LoanDashboard API (신규 연동)
- cm3: 법인세 예상 가중 - TaxSimulation API (신규 연동)
- cm4: 대표자 종합세 예상 가중 - TaxSimulation API (신규 연동)

변경 사항:
- transformCardManagementResponse: LoanDashboard, TaxSimulation 파라미터 추가
- useCEODashboard: 3개 API 병렬 호출 (Promise.all)
- useCardManagement: 동일하게 다중 API 호출 적용
- 각 API 실패 시 fallback 데이터 사용 (graceful degradation)
This commit is contained in:
2026-01-23 09:04:56 +09:00
parent 1a0b1c4c48
commit 9cfd10a265
2 changed files with 67 additions and 18 deletions

View File

@@ -23,8 +23,15 @@ import type {
WelfareApiResponse,
WelfareDetailApiResponse,
ExpectedExpenseDashboardDetailApiResponse,
LoanDashboardApiResponse,
TaxSimulationApiResponse,
} from '@/lib/api/dashboard/types';
import {
fetchLoanDashboard,
fetchTaxSimulation,
} from '@/lib/api/dashboard/endpoints';
import {
transformDailyReportResponse,
transformReceivableResponse,
@@ -226,8 +233,18 @@ export function useCardManagement(fallbackData?: CardManagementData) {
setLoading(true);
setError(null);
const apiData = await fetchApi<CardTransactionApiResponse>('card-transactions/summary');
const transformed = transformCardManagementResponse(apiData, fallbackData);
// 3개 API 병렬 호출: 카드거래, 가지급금, 세금 시뮬레이션
const [cardApiData, loanResponse, taxResponse] = await Promise.all([
fetchApi<CardTransactionApiResponse>('card-transactions/summary'),
fetchLoanDashboard(),
fetchTaxSimulation(),
]);
// LoanDashboard와 TaxSimulation은 ApiResponse wrapper가 있으므로 data 추출
const loanData = loanResponse.success ? loanResponse.data : null;
const taxData = taxResponse.success ? taxResponse.data : null;
const transformed = transformCardManagementResponse(cardApiData, loanData, taxData, fallbackData);
setData(transformed);
} catch (err) {
@@ -1028,8 +1045,21 @@ export function useCEODashboard(options: UseCEODashboardOptions = {}): CEODashbo
try {
setCardManagementLoading(true);
setCardManagementError(null);
const apiData = await fetchApi<CardTransactionApiResponse>('card-transactions/summary');
setCardManagementData(transformCardManagementResponse(apiData, cardManagementFallback));
// 3개 API 병렬 호출: 카드거래, 가지급금, 세금 시뮬레이션
const [cardApiData, loanResponse, taxResponse] = await Promise.all([
fetchApi<CardTransactionApiResponse>('card-transactions/summary'),
fetchLoanDashboard(),
fetchTaxSimulation(),
]);
// LoanDashboard와 TaxSimulation은 ApiResponse wrapper가 있으므로 data 추출
const loanData = loanResponse.success ? loanResponse.data : null;
const taxData = taxResponse.success ? taxResponse.data : null;
setCardManagementData(
transformCardManagementResponse(cardApiData, loanData, taxData, cardManagementFallback)
);
} catch (err) {
setCardManagementError(err instanceof Error ? err.message : '데이터 로딩 실패');
} finally {

View File

@@ -21,6 +21,8 @@ import type {
CardDashboardDetailApiResponse,
BillDashboardDetailApiResponse,
ExpectedExpenseDashboardDetailApiResponse,
LoanDashboardApiResponse,
TaxSimulationApiResponse,
} from './types';
import type {
@@ -485,43 +487,60 @@ function generateCardManagementCheckPoints(api: CardTransactionApiResponse): Che
/**
* CardTransaction API 응답 → Frontend 타입 변환
* 4개 카드 구조 유지: 카드, 가지급금, 법인세 예상 가중, 대표자 종합세 예상 가중
* 주의: 가지급금, 법인세, 종합세 관련 데이터는 별도 API 필요 (현재 목업 유지)
* 4개 카드 구조:
* - cm1: 카드 사용액 (CardTransaction API)
* - cm2: 가지급금 (LoanDashboard API)
* - cm3: 법인세 예상 가중 (TaxSimulation API - corporate_tax.difference)
* - cm4: 대표자 종합세 예상 가중 (TaxSimulation API - income_tax.difference)
*/
export function transformCardManagementResponse(
summaryApi: CardTransactionApiResponse,
loanApi?: LoanDashboardApiResponse | null,
taxApi?: TaxSimulationApiResponse | null,
fallbackData?: CardManagementData
): CardManagementData {
const changeRate = calculateChangeRate(summaryApi.current_month_total, summaryApi.previous_month_total);
// cm2: 가지급금 금액 (LoanDashboard API 또는 fallback)
const loanAmount = loanApi?.summary?.total_outstanding ?? fallbackData?.cards[1]?.amount ?? 0;
// cm3: 법인세 예상 가중 (TaxSimulation API 또는 fallback)
const corporateTaxDifference = taxApi?.corporate_tax?.difference ?? fallbackData?.cards[2]?.amount ?? 0;
// cm4: 대표자 종합세 예상 가중 (TaxSimulation API 또는 fallback)
const incomeTaxDifference = taxApi?.income_tax?.difference ?? fallbackData?.cards[3]?.amount ?? 0;
// 가지급금 경고 배너 표시 여부 결정 (가지급금 잔액 > 0이면 표시)
const hasLoanWarning = loanAmount > 0;
return {
// 가지급금 관련 경고 배너 (별도 API 필요)
warningBanner: fallbackData?.warningBanner,
// 가지급금 관련 경고 배너 (가지급금 있을 때만 표시)
warningBanner: hasLoanWarning ? fallbackData?.warningBanner : undefined,
cards: [
// cm1: 카드 사용액 (API 데이터)
// cm1: 카드 사용액 (CardTransaction API)
{
id: 'cm1',
label: '카드',
amount: summaryApi.current_month_total,
previousLabel: `전월 대비 ${changeRate > 0 ? '+' : ''}${changeRate.toFixed(1)}%`,
},
// cm2: 가지급금 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[1] ?? {
// cm2: 가지급금 (LoanDashboard API)
{
id: 'cm2',
label: '가지급금',
amount: 0,
amount: loanAmount,
},
// cm3: 법인세 예상 가중 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[2] ?? {
// cm3: 법인세 예상 가중 (TaxSimulation API)
{
id: 'cm3',
label: '법인세 예상 가중',
amount: 0,
amount: corporateTaxDifference,
},
// cm4: 대표자 종합세 예상 가중 (별도 API 필요 - 현재 fallback)
fallbackData?.cards[3] ?? {
// cm4: 대표자 종합세 예상 가중 (TaxSimulation API)
{
id: 'cm4',
label: '대표자 종합세 예상 가중',
amount: 0,
amount: incomeTaxDifference,
},
],
checkPoints: generateCardManagementCheckPoints(summaryApi),