fix(WEB): 오늘의 이슈 notification_type 기반 변환 로직 개선

transformers.ts:
- notification_type 영문 코드 기반 변환 (sales_order, bad_debt 등)
- NOTIFICATION_TYPE_TO_BADGE 매핑 테이블 추가
- validateNotificationType 함수로 타입 안전성 확보

types.ts:
- TodayIssueNotificationType 타입 추가
- TodayIssueListItem에 notificationType 필드 추가

TodayIssueSection:
- notificationType 기반 색상 매핑 적용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-28 15:48:17 +09:00
parent e5f0f5da61
commit eb3288dab7
5 changed files with 131 additions and 83 deletions

View File

@@ -34,6 +34,7 @@ import type {
TodayIssueItem,
TodayIssueListItem,
TodayIssueListBadgeType,
TodayIssueNotificationType,
CalendarScheduleItem,
CheckPoint,
CheckPointType,
@@ -602,49 +603,71 @@ export function transformStatusBoardResponse(api: StatusBoardApiResponse): Today
// 7. TodayIssue 변환
// ============================================
/** 유효한 뱃지 타입 목록 (API TodayIssue 모델과 동기화) */
const VALID_BADGE_TYPES: TodayIssueListBadgeType[] = [
'수주등록',
'추심이슈',
'안전재고',
'지출승인',
'세금신고',
'결재요청',
'신규업체',
'입금',
'출금',
'기타',
/** 유효한 notification_type 목록 (API TodayIssue 모델과 동기화) */
const VALID_NOTIFICATION_TYPES: TodayIssueNotificationType[] = [
'sales_order',
'bad_debt',
'safety_stock',
'expected_expense',
'vat_report',
'approval_request',
'new_vendor',
'deposit',
'withdrawal',
'other',
];
/** notification_type → 한글 badge 변환 매핑 */
const NOTIFICATION_TYPE_TO_BADGE: Record<TodayIssueNotificationType, TodayIssueListBadgeType> = {
sales_order: '수주 성공',
bad_debt: '추심 이슈',
safety_stock: '적정 재고',
expected_expense: '지출예상내역서',
vat_report: '세금 신고',
approval_request: '결재 요청',
new_vendor: '신규거래처',
deposit: '입금',
withdrawal: '출금',
other: '기타',
};
/**
* API 뱃지 문자열 → Frontend 뱃지 타입 변환
* 유효하지 않은 뱃지는 '기타'로 폴백
* API notification_type → Frontend notificationType 변환
* 유효하지 않은 타입은 'other'로 폴백
*/
function validateBadgeType(badge: string): TodayIssueListBadgeType {
if (VALID_BADGE_TYPES.includes(badge as TodayIssueListBadgeType)) {
return badge as TodayIssueListBadgeType;
function validateNotificationType(notificationType: string | null): TodayIssueNotificationType {
if (notificationType && VALID_NOTIFICATION_TYPES.includes(notificationType as TodayIssueNotificationType)) {
return notificationType as TodayIssueNotificationType;
}
return '기타';
return 'other';
}
/**
* TodayIssue API 응답 → Frontend 타입 변환
* 오늘의 이슈 리스트 데이터 변환
* notification_type 코드값 기반으로 색상 매핑 지원
*/
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: normalizePath(item.path, { addViewMode: true }),
})),
items: api.items.map((item) => {
const notificationType = validateNotificationType(item.notification_type);
// badge는 API 응답 그대로 사용하되, 없으면 notification_type에서 변환
const badge = item.badge || NOTIFICATION_TYPE_TO_BADGE[notificationType];
return {
id: item.id,
badge: badge as TodayIssueListBadgeType,
notificationType,
content: item.content,
time: item.time,
date: item.date,
needsApproval: item.needsApproval ?? false,
path: normalizePath(item.path, { addViewMode: true }),
};
}),
totalCount: api.total_count,
};
}

View File

@@ -173,10 +173,23 @@ export interface StatusBoardApiResponse {
// 7. TodayIssue (오늘의 이슈 리스트) API 응답 타입
// ============================================
/** 오늘의 이슈 notification_type 코드 (API 고정값) */
export type TodayIssueNotificationType =
| 'sales_order' // 수주등록
| 'bad_debt' // 추심이슈
| 'safety_stock' // 안전재고
| 'expected_expense' // 지출 승인대기
| 'vat_report' // 세금 신고
| 'approval_request' // 결재 요청
| 'new_vendor' // 신규거래처
| 'deposit' // 입금
| 'withdrawal'; // 출금
/** 오늘의 이슈 아이템 */
export interface TodayIssueItemApiResponse {
id: string; // 항목 고유 ID
badge: string; // 이슈 카테고리 뱃지
badge: string; // 이슈 카테고리 뱃지 (한글)
notification_type: TodayIssueNotificationType | null; // 이슈 타입 코드 (영문)
content: string; // 이슈 내용
time: string; // 상대 시간 (예: "10분 전")
date?: string; // 날짜 (ISO 형식)