feat(WEB): CEO 대시보드 Phase 2 API 연동 완료

- StatusBoard(현황판) API Hook 및 타입 추가
- TodayIssue(오늘의 이슈) API Hook 및 타입 추가
- Calendar(캘린더) API Hook 및 타입 추가
- Vat(부가세) API Hook 및 타입 추가
- Entertainment(접대비) API Hook 및 타입 추가
- Welfare(복리후생비) API Hook 및 타입 추가
- CEODashboard.tsx에 모든 Phase 2 Hook 통합
- API 응답 → Frontend 타입 변환 transformer 추가
- WelfareCalculationType 'percentage' → 'ratio' 타입 일치 수정
This commit is contained in:
2026-01-21 10:38:09 +09:00
parent e6ef80f17f
commit fb1d7bf241
5 changed files with 774 additions and 9 deletions

View File

@@ -10,6 +10,12 @@ import type {
BadDebtApiResponse,
ExpectedExpenseApiResponse,
CardTransactionApiResponse,
StatusBoardApiResponse,
TodayIssueApiResponse,
CalendarApiResponse,
VatApiResponse,
EntertainmentApiResponse,
WelfareApiResponse,
} from './types';
import type {
@@ -18,8 +24,16 @@ import type {
DebtCollectionData,
MonthlyExpenseData,
CardManagementData,
TodayIssueItem,
TodayIssueListItem,
TodayIssueListBadgeType,
CalendarScheduleItem,
CheckPoint,
CheckPointType,
VatData,
EntertainmentData,
WelfareData,
HighlightColor,
} from '@/components/business/CEODashboard/types';
// ============================================
@@ -428,4 +442,201 @@ export function transformCardManagementResponse(
],
checkPoints: generateCardManagementCheckPoints(api),
};
}
// ============================================
// 6. StatusBoard 변환
// ============================================
/**
* StatusBoard API 응답 → Frontend 타입 변환
* API 응답 형식이 TodayIssueItem과 거의 동일하므로 단순 매핑
*/
export function transformStatusBoardResponse(api: StatusBoardApiResponse): TodayIssueItem[] {
return api.items.map((item) => ({
id: item.id,
label: item.label,
count: item.count,
path: item.path,
isHighlighted: item.isHighlighted,
}));
}
// ============================================
// 7. TodayIssue 변환
// ============================================
/** 유효한 뱃지 타입 목록 */
const VALID_BADGE_TYPES: TodayIssueListBadgeType[] = [
'수주 성공',
'주식 이슈',
'직정 제고',
'지출예상내역서',
'세금 신고',
'결재 요청',
'기타',
];
/**
* API 뱃지 문자열 → Frontend 뱃지 타입 변환
* 유효하지 않은 뱃지는 '기타'로 폴백
*/
function validateBadgeType(badge: string): TodayIssueListBadgeType {
if (VALID_BADGE_TYPES.includes(badge as TodayIssueListBadgeType)) {
return badge as TodayIssueListBadgeType;
}
return '기타';
}
/**
* TodayIssue API 응답 → Frontend 타입 변환
* 오늘의 이슈 리스트 데이터 변환
*/
export function transformTodayIssueResponse(api: TodayIssueApiResponse): {
items: TodayIssueListItem[];
totalCount: number;
} {
return {
items: api.items.map((item) => ({
id: item.id,
badge: validateBadgeType(item.badge),
content: item.content,
time: item.time,
date: item.date,
needsApproval: item.needsApproval ?? false,
path: item.path,
})),
totalCount: api.total_count,
};
}
// ============================================
// 8. Calendar 변환
// ============================================
/**
* Calendar API 응답 → Frontend 타입 변환
* API 응답 형식이 CalendarScheduleItem과 동일하므로 단순 매핑
*/
export function transformCalendarResponse(api: CalendarApiResponse): {
items: CalendarScheduleItem[];
totalCount: number;
} {
return {
items: api.items.map((item) => ({
id: item.id,
title: item.title,
startDate: item.startDate,
endDate: item.endDate,
startTime: item.startTime,
endTime: item.endTime,
isAllDay: item.isAllDay,
type: item.type,
department: item.department,
personName: item.personName,
color: item.color,
})),
totalCount: api.total_count,
};
}
// ============================================
// 9. Vat 변환
// ============================================
/** 유효한 하이라이트 색상 목록 */
const VALID_HIGHLIGHT_COLORS: HighlightColor[] = ['red', 'green', 'blue'];
/**
* API 색상 문자열 → Frontend 하이라이트 색상 변환
* 유효하지 않은 색상은 'blue'로 폴백
*/
function validateHighlightColor(color: string): HighlightColor {
if (VALID_HIGHLIGHT_COLORS.includes(color as HighlightColor)) {
return color as HighlightColor;
}
return 'blue';
}
/**
* Vat API 응답 → Frontend 타입 변환
* 부가세 현황 데이터 변환
*/
export function transformVatResponse(api: VatApiResponse): VatData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}
// ============================================
// 10. Entertainment 변환
// ============================================
/**
* Entertainment API 응답 → Frontend 타입 변환
* 접대비 현황 데이터 변환
*/
export function transformEntertainmentResponse(api: EntertainmentApiResponse): EntertainmentData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}
// ============================================
// 11. Welfare 변환
// ============================================
/**
* Welfare API 응답 → Frontend 타입 변환
* 복리후생비 현황 데이터 변환
*/
export function transformWelfareResponse(api: WelfareApiResponse): WelfareData {
return {
cards: api.cards.map((card) => ({
id: card.id,
label: card.label,
amount: card.amount,
subLabel: card.subLabel,
unit: card.unit,
})),
checkPoints: api.check_points.map((cp) => ({
id: cp.id,
type: cp.type as CheckPointType,
message: cp.message,
highlights: cp.highlights?.map((h) => ({
text: h.text,
color: validateHighlightColor(h.color),
})),
})),
};
}