feat: Phase 2 프론트엔드 타입 및 API 연동

- API 타입 정의 추가 (LoanDashboard, TaxSimulation)
- API 엔드포인트 함수 추가 (endpoints.ts)
- 모달 데이터 훅 생성 (useCardManagementModals.ts)

관련: docs/plans/card-management-section-plan.md
This commit is contained in:
2026-01-22 23:01:22 +09:00
parent f8d93e2851
commit fe845227df
4 changed files with 575 additions and 1 deletions

View 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 },
},
},
};
}
}

View File

@@ -3,4 +3,5 @@
*/
export * from './types';
export * from './transformers';
export * from './transformers';
export * from './endpoints';

View File

@@ -561,4 +561,106 @@ export interface ExpectedExpenseDashboardDetailApiResponse {
summary: ExpectedExpenseDashboardSummaryApiResponse;
items: ExpectedExpenseItemApiResponse[];
footer_summary: ExpectedExpenseFooterSummaryApiResponse;
}
// ============================================
// 17. Loan Dashboard Detail (가지급금 상세) API 응답 타입
// ============================================
/** 가지급금 대시보드 요약 */
export interface LoanDashboardSummaryApiResponse {
total_outstanding: number; // 미정산 잔액
settled_amount: number; // 정산 완료 금액
recognized_interest: number; // 인정이자
pending_count: number; // 미정산 건수
}
/** 가지급금 월별 추이 */
export interface LoanMonthlyTrendApiResponse {
month: string; // "2026-01"
label: string; // "1월"
amount: number; // 금액
}
/** 가지급금 사용자별 분포 */
export interface LoanUserDistributionApiResponse {
user_name: string; // 사용자명
total_outstanding: number; // 미정산 잔액
settled_amount: number; // 정산 완료
count: number; // 건수
color: string; // 차트 색상
}
/** 가지급금 거래 내역 */
export interface LoanItemApiResponse {
id: number;
user_name: string; // 사용자명
loan_date: string; // 가지급일
amount: number; // 금액
description: string; // 설명
status: string; // 상태 코드
status_label: string; // 상태 라벨
}
/** GET /api/v1/loans/dashboard 응답 */
export interface LoanDashboardApiResponse {
summary: LoanDashboardSummaryApiResponse;
monthly_trend: LoanMonthlyTrendApiResponse[];
user_distribution: LoanUserDistributionApiResponse[];
items: LoanItemApiResponse[];
}
// ============================================
// 18. Tax Simulation (세금 시뮬레이션) API 응답 타입
// ============================================
/** 세금 시뮬레이션 - 가지급금 요약 */
export interface TaxSimulationLoanSummaryApiResponse {
total_outstanding: number; // 가지급금 잔액
recognized_interest: number; // 인정이자
interest_rate: number; // 이자율 (4.6%)
}
/** 세금 계산 결과 - 기본 */
export interface TaxCalculationBaseApiResponse {
taxable_income: number; // 과세소득
tax_amount: number; // 세금액
}
/** 세금 계산 결과 - 소득세용 (세율 포함) */
export interface TaxCalculationWithRateApiResponse {
taxable_income: number; // 과세소득
tax_rate: string; // 세율 (예: "35%")
tax_amount: number; // 세금액
}
/** 법인세 비교 */
export interface CorporateTaxComparisonApiResponse {
without_loan: TaxCalculationBaseApiResponse; // 가지급금 없는 경우
with_loan: TaxCalculationBaseApiResponse; // 가지급금 있는 경우
difference: number; // 추가 법인세
rate_info: string; // "법인세 19% 적용"
}
/** 소득세 내역 */
export interface IncomeTaxBreakdownApiResponse {
income_tax: number; // 소득세 (35%)
local_tax: number; // 지방소득세 (소득세의 10%)
insurance: number; // 4대보험 추정 (9%)
}
/** 소득세 비교 */
export interface IncomeTaxComparisonApiResponse {
without_loan: TaxCalculationWithRateApiResponse; // 가지급금 없는 경우
with_loan: TaxCalculationWithRateApiResponse; // 가지급금 있는 경우
difference: number; // 추가 소득세
breakdown: IncomeTaxBreakdownApiResponse; // 세금 내역
}
/** GET /api/v1/loans/tax-simulation 응답 */
export interface TaxSimulationApiResponse {
year: number; // 시뮬레이션 연도
loan_summary: TaxSimulationLoanSummaryApiResponse; // 가지급금 요약
corporate_tax: CorporateTaxComparisonApiResponse; // 법인세 비교
income_tax: IncomeTaxComparisonApiResponse; // 소득세 비교
}