2026-01-22 23:01:22 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Card Management Modals Hook
|
|
|
|
|
*
|
|
|
|
|
* CEO 대시보드 카드/가지급금 관리 섹션 (cm1-cm4) 모달 데이터 관리
|
|
|
|
|
*
|
|
|
|
|
* cm1: 카드 사용액 상세 → CardTransactionDashboard API
|
|
|
|
|
* cm2: 가지급금 상세 → LoanDashboard API
|
|
|
|
|
* cm3: 법인세 예상 가중 → TaxSimulation API (corporate_tax)
|
|
|
|
|
* cm4: 대표자 종합세 예상 가중 → TaxSimulation API (income_tax)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { useState, useCallback } from 'react';
|
|
|
|
|
import {
|
|
|
|
|
fetchCardTransactionDashboard,
|
|
|
|
|
fetchLoanDashboard,
|
|
|
|
|
fetchTaxSimulation,
|
|
|
|
|
} from '@/lib/api/dashboard/endpoints';
|
|
|
|
|
import type {
|
|
|
|
|
CardDashboardDetailApiResponse,
|
|
|
|
|
LoanDashboardApiResponse,
|
|
|
|
|
TaxSimulationApiResponse,
|
|
|
|
|
} from '@/lib/api/dashboard/types';
|
|
|
|
|
|
|
|
|
|
// ============================================
|
|
|
|
|
// 타입 정의
|
|
|
|
|
// ============================================
|
|
|
|
|
|
|
|
|
|
/** 카드 ID 타입 */
|
|
|
|
|
export type CardManagementCardId = 'cm1' | 'cm2' | 'cm3' | 'cm4';
|
|
|
|
|
|
2026-01-22 23:11:19 +09:00
|
|
|
/** 모달 데이터 반환 타입 */
|
|
|
|
|
export interface CardManagementModalData {
|
|
|
|
|
cm1Data?: CardDashboardDetailApiResponse | null;
|
|
|
|
|
cm2Data?: LoanDashboardApiResponse | null;
|
|
|
|
|
cm3Data?: TaxSimulationApiResponse | null;
|
|
|
|
|
cm4Data?: TaxSimulationApiResponse | null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-22 23:01:22 +09:00
|
|
|
/** Hook 반환 타입 */
|
|
|
|
|
export interface UseCardManagementModalsReturn {
|
|
|
|
|
/** cm1: 카드 사용액 상세 데이터 */
|
|
|
|
|
cm1Data: CardDashboardDetailApiResponse | null;
|
|
|
|
|
/** cm2: 가지급금 상세 데이터 */
|
|
|
|
|
cm2Data: LoanDashboardApiResponse | null;
|
|
|
|
|
/** cm3: 법인세 시뮬레이션 데이터 */
|
|
|
|
|
cm3Data: TaxSimulationApiResponse | null;
|
|
|
|
|
/** cm4: 소득세 시뮬레이션 데이터 (cm3와 동일 소스, 다른 표시) */
|
|
|
|
|
cm4Data: TaxSimulationApiResponse | null;
|
|
|
|
|
/** 로딩 상태 */
|
|
|
|
|
loading: boolean;
|
|
|
|
|
/** 에러 메시지 */
|
|
|
|
|
error: string | null;
|
2026-01-22 23:11:19 +09:00
|
|
|
/** 특정 카드의 모달 데이터 조회 - 데이터 직접 반환 */
|
|
|
|
|
fetchModalData: (cardId: CardManagementCardId) => Promise<CardManagementModalData>;
|
2026-01-22 23:01:22 +09:00
|
|
|
/** 모든 카드 데이터 조회 */
|
|
|
|
|
fetchAllData: () => Promise<void>;
|
|
|
|
|
/** 데이터 초기화 */
|
|
|
|
|
clearData: (cardId?: CardManagementCardId) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================
|
|
|
|
|
// Hook 구현
|
|
|
|
|
// ============================================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 카드/가지급금 관리 섹션 모달 데이터 관리 Hook
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* const { cm1Data, cm2Data, loading, fetchModalData } = useCardManagementModals();
|
|
|
|
|
*
|
|
|
|
|
* // 카드 클릭 시
|
|
|
|
|
* await fetchModalData('cm1');
|
|
|
|
|
*/
|
|
|
|
|
export function useCardManagementModals(): UseCardManagementModalsReturn {
|
|
|
|
|
// 각 카드별 데이터 상태
|
|
|
|
|
const [cm1Data, setCm1Data] = useState<CardDashboardDetailApiResponse | null>(null);
|
|
|
|
|
const [cm2Data, setCm2Data] = useState<LoanDashboardApiResponse | null>(null);
|
|
|
|
|
const [cm3Data, setCm3Data] = useState<TaxSimulationApiResponse | null>(null);
|
|
|
|
|
const [cm4Data, setCm4Data] = useState<TaxSimulationApiResponse | null>(null);
|
|
|
|
|
|
|
|
|
|
// 공통 상태
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* cm1: 카드 사용액 상세 데이터 조회
|
2026-01-22 23:11:19 +09:00
|
|
|
* @returns 조회된 데이터 (실패 시 null)
|
2026-01-22 23:01:22 +09:00
|
|
|
*/
|
2026-01-22 23:11:19 +09:00
|
|
|
const fetchCm1Data = useCallback(async (): Promise<CardDashboardDetailApiResponse | null> => {
|
2026-01-22 23:01:22 +09:00
|
|
|
try {
|
|
|
|
|
const response = await fetchCardTransactionDashboard();
|
2026-01-22 23:11:19 +09:00
|
|
|
if (response.success && response.data) {
|
2026-01-22 23:01:22 +09:00
|
|
|
setCm1Data(response.data);
|
2026-01-22 23:11:19 +09:00
|
|
|
return response.data;
|
2026-01-22 23:01:22 +09:00
|
|
|
} else {
|
|
|
|
|
throw new Error(response.message || '카드 거래 데이터 조회 실패');
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = err instanceof Error ? err.message : '카드 거래 데이터 조회 실패';
|
|
|
|
|
console.error('[useCardManagementModals] cm1 error:', err);
|
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* cm2: 가지급금 상세 데이터 조회
|
2026-01-22 23:11:19 +09:00
|
|
|
* @returns 조회된 데이터 (실패 시 null)
|
2026-01-22 23:01:22 +09:00
|
|
|
*/
|
2026-01-22 23:11:19 +09:00
|
|
|
const fetchCm2Data = useCallback(async (): Promise<LoanDashboardApiResponse | null> => {
|
2026-01-22 23:01:22 +09:00
|
|
|
try {
|
|
|
|
|
const response = await fetchLoanDashboard();
|
2026-01-22 23:11:19 +09:00
|
|
|
if (response.success && response.data) {
|
2026-01-22 23:01:22 +09:00
|
|
|
setCm2Data(response.data);
|
2026-01-22 23:11:19 +09:00
|
|
|
return response.data;
|
2026-01-22 23:01:22 +09:00
|
|
|
} else {
|
|
|
|
|
throw new Error(response.message || '가지급금 데이터 조회 실패');
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = err instanceof Error ? err.message : '가지급금 데이터 조회 실패';
|
|
|
|
|
console.error('[useCardManagementModals] cm2 error:', err);
|
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* cm3 & cm4: 세금 시뮬레이션 데이터 조회
|
|
|
|
|
* cm3은 법인세 (corporate_tax), cm4는 소득세 (income_tax) 사용
|
2026-01-22 23:11:19 +09:00
|
|
|
* @returns 조회된 데이터 (실패 시 null)
|
2026-01-22 23:01:22 +09:00
|
|
|
*/
|
2026-01-22 23:11:19 +09:00
|
|
|
const fetchTaxData = useCallback(async (): Promise<TaxSimulationApiResponse | null> => {
|
2026-01-22 23:01:22 +09:00
|
|
|
try {
|
|
|
|
|
const response = await fetchTaxSimulation();
|
2026-01-22 23:11:19 +09:00
|
|
|
if (response.success && response.data) {
|
2026-01-22 23:01:22 +09:00
|
|
|
// cm3, cm4 모두 같은 데이터 소스 사용 (표시만 다름)
|
|
|
|
|
setCm3Data(response.data);
|
|
|
|
|
setCm4Data(response.data);
|
2026-01-22 23:11:19 +09:00
|
|
|
return response.data;
|
2026-01-22 23:01:22 +09:00
|
|
|
} else {
|
|
|
|
|
throw new Error(response.message || '세금 시뮬레이션 데이터 조회 실패');
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = err instanceof Error ? err.message : '세금 시뮬레이션 데이터 조회 실패';
|
|
|
|
|
console.error('[useCardManagementModals] tax simulation error:', err);
|
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 특정 카드의 모달 데이터 조회
|
2026-01-22 23:11:19 +09:00
|
|
|
* @returns 조회된 모달 데이터 객체 (카드 ID에 해당하는 데이터만 포함)
|
2026-01-22 23:01:22 +09:00
|
|
|
*/
|
|
|
|
|
const fetchModalData = useCallback(
|
2026-01-22 23:11:19 +09:00
|
|
|
async (cardId: CardManagementCardId): Promise<CardManagementModalData> => {
|
2026-01-22 23:01:22 +09:00
|
|
|
setLoading(true);
|
|
|
|
|
setError(null);
|
|
|
|
|
|
2026-01-22 23:11:19 +09:00
|
|
|
const result: CardManagementModalData = {};
|
|
|
|
|
|
2026-01-22 23:01:22 +09:00
|
|
|
try {
|
|
|
|
|
switch (cardId) {
|
|
|
|
|
case 'cm1':
|
2026-01-22 23:11:19 +09:00
|
|
|
result.cm1Data = await fetchCm1Data();
|
2026-01-22 23:01:22 +09:00
|
|
|
break;
|
|
|
|
|
case 'cm2':
|
2026-01-22 23:11:19 +09:00
|
|
|
result.cm2Data = await fetchCm2Data();
|
2026-01-22 23:01:22 +09:00
|
|
|
break;
|
|
|
|
|
case 'cm3':
|
2026-01-22 23:11:19 +09:00
|
|
|
case 'cm4': {
|
2026-01-22 23:01:22 +09:00
|
|
|
// cm3, cm4는 같은 API 사용
|
2026-01-22 23:11:19 +09:00
|
|
|
const taxData = await fetchTaxData();
|
|
|
|
|
result.cm3Data = taxData;
|
|
|
|
|
result.cm4Data = taxData;
|
2026-01-22 23:01:22 +09:00
|
|
|
break;
|
2026-01-22 23:11:19 +09:00
|
|
|
}
|
2026-01-22 23:01:22 +09:00
|
|
|
default:
|
|
|
|
|
throw new Error(`알 수 없는 카드 ID: ${cardId}`);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = err instanceof Error ? err.message : '데이터 조회 실패';
|
|
|
|
|
setError(errorMessage);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
2026-01-22 23:11:19 +09:00
|
|
|
|
|
|
|
|
return result;
|
2026-01-22 23:01:22 +09:00
|
|
|
},
|
|
|
|
|
[fetchCm1Data, fetchCm2Data, fetchTaxData]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 모든 카드 데이터 조회 (초기 로드용)
|
|
|
|
|
*/
|
|
|
|
|
const fetchAllData = useCallback(async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
setError(null);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 병렬로 모든 데이터 조회
|
|
|
|
|
await Promise.all([fetchCm1Data(), fetchCm2Data(), fetchTaxData()]);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = err instanceof Error ? err.message : '데이터 조회 실패';
|
|
|
|
|
setError(errorMessage);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
}, [fetchCm1Data, fetchCm2Data, fetchTaxData]);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 데이터 초기화
|
|
|
|
|
*/
|
|
|
|
|
const clearData = useCallback((cardId?: CardManagementCardId) => {
|
|
|
|
|
if (!cardId) {
|
|
|
|
|
// 전체 초기화
|
|
|
|
|
setCm1Data(null);
|
|
|
|
|
setCm2Data(null);
|
|
|
|
|
setCm3Data(null);
|
|
|
|
|
setCm4Data(null);
|
|
|
|
|
setError(null);
|
|
|
|
|
} else {
|
|
|
|
|
// 특정 카드만 초기화
|
|
|
|
|
switch (cardId) {
|
|
|
|
|
case 'cm1':
|
|
|
|
|
setCm1Data(null);
|
|
|
|
|
break;
|
|
|
|
|
case 'cm2':
|
|
|
|
|
setCm2Data(null);
|
|
|
|
|
break;
|
|
|
|
|
case 'cm3':
|
|
|
|
|
setCm3Data(null);
|
|
|
|
|
break;
|
|
|
|
|
case 'cm4':
|
|
|
|
|
setCm4Data(null);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
cm1Data,
|
|
|
|
|
cm2Data,
|
|
|
|
|
cm3Data,
|
|
|
|
|
cm4Data,
|
|
|
|
|
loading,
|
|
|
|
|
error,
|
|
|
|
|
fetchModalData,
|
|
|
|
|
fetchAllData,
|
|
|
|
|
clearData,
|
|
|
|
|
};
|
|
|
|
|
}
|