Files
sam-react-prod/src/lib/api/transformers.ts

421 lines
12 KiB
TypeScript
Raw Normal View History

// API 응답 데이터 변환 헬퍼
// API 응답 (snake_case + 특정 값) ↔ Frontend State (snake_case + 변환된 값)
import type {
ItemPageResponse,
ItemSectionResponse,
ItemFieldResponse,
BomItemResponse,
SectionTemplateResponse,
MasterFieldResponse,
UnitOptionResponse,
CustomTabResponse,
} from '@/types/item-master-api';
import type {
ItemPage,
ItemSection,
ItemField,
BOMItem,
SectionTemplate,
ItemMasterField,
} from '@/contexts/ItemMasterContext';
// ============================================
// 타입 값 변환 매핑
// ============================================
/**
* API section type Frontend section_type
* API: 'fields' | 'bom'
* Frontend: 'BASIC' | 'BOM' | 'CUSTOM'
*/
const SECTION_TYPE_MAP: Record<string, 'BASIC' | 'BOM' | 'CUSTOM'> = {
fields: 'BASIC',
bom: 'BOM',
};
/**
* Frontend section_type API section type
*/
const SECTION_TYPE_REVERSE_MAP: Record<string, 'fields' | 'bom'> = {
BASIC: 'fields',
BOM: 'bom',
CUSTOM: 'fields', // CUSTOM은 fields로 매핑
};
/**
* API field_type Frontend field_type
* API: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea'
* Frontend: 'TEXT' | 'NUMBER' | 'DATE' | 'SELECT' | 'TEXTAREA' | 'CHECKBOX'
*/
const FIELD_TYPE_MAP: Record<
string,
'TEXT' | 'NUMBER' | 'DATE' | 'SELECT' | 'TEXTAREA' | 'CHECKBOX'
> = {
textbox: 'TEXT',
number: 'NUMBER',
dropdown: 'SELECT',
checkbox: 'CHECKBOX',
date: 'DATE',
textarea: 'TEXTAREA',
};
/**
* Frontend field_type API field_type
*/
const FIELD_TYPE_REVERSE_MAP: Record<
string,
'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea'
> = {
TEXT: 'textbox',
NUMBER: 'number',
SELECT: 'dropdown',
CHECKBOX: 'checkbox',
DATE: 'date',
TEXTAREA: 'textarea',
};
// ============================================
// API Response → Frontend State 변환
// ============================================
/**
* ItemPageResponse ItemPage
*/
export const transformPageResponse = (
response: ItemPageResponse
): ItemPage => {
return {
id: response.id,
tenant_id: response.tenant_id,
page_name: response.page_name,
item_type: response.item_type as 'FG' | 'PT' | 'SM' | 'RM' | 'CS',
absolute_path: response.absolute_path,
is_active: response.is_active,
sections: response.sections?.map(transformSectionResponse) || [],
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
/**
* ItemSectionResponse ItemSection
* 변환: type section_type, (fields BASIC, bom BOM)
*/
export const transformSectionResponse = (
response: ItemSectionResponse
): ItemSection => {
return {
id: response.id,
tenant_id: response.tenant_id,
page_id: response.page_id,
title: response.title,
section_type: SECTION_TYPE_MAP[response.type] || 'BASIC', // 타입 값 변환
order_no: response.order_no,
fields: response.fields?.map(transformFieldResponse) || [],
bom_items: response.bomItems?.map(transformBomItemResponse) || [],
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
/**
* ItemFieldResponse ItemField
* 변환: field_type (textbox TEXT, dropdown SELECT )
*/
export const transformFieldResponse = (
response: ItemFieldResponse
): ItemField => {
return {
id: response.id,
tenant_id: response.tenant_id,
section_id: response.section_id,
field_name: response.field_name,
field_type: FIELD_TYPE_MAP[response.field_type] || 'TEXT', // 타입 값 변환
order_no: response.order_no,
is_required: response.is_required,
placeholder: response.placeholder,
default_value: response.default_value,
display_condition: response.display_condition,
validation_rules: response.validation_rules,
options: response.options,
properties: response.properties,
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
/**
* BomItemResponse BOMItem
*/
export const transformBomItemResponse = (
response: BomItemResponse
): BOMItem => {
return {
id: response.id,
tenant_id: response.tenant_id,
section_id: response.section_id,
item_code: response.item_code,
item_name: response.item_name,
quantity: response.quantity,
unit: response.unit,
unit_price: response.unit_price,
total_price: response.total_price,
spec: response.spec,
note: response.note,
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
/**
* SectionTemplateResponse SectionTemplate
* 변환: title template_name, type section_type,
*/
export const transformSectionTemplateResponse = (
response: SectionTemplateResponse
): SectionTemplate => {
return {
id: response.id,
tenant_id: response.tenant_id,
template_name: response.title, // 필드명 변환
section_type: SECTION_TYPE_MAP[response.type] || 'BASIC', // 타입 값 변환
description: response.description,
default_fields: null, // API 응답에 없으므로 null
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
/**
* MasterFieldResponse ItemMasterField
* 변환: field_type (textbox TEXT, dropdown SELECT )
*/
export const transformMasterFieldResponse = (
response: MasterFieldResponse
): ItemMasterField => {
return {
id: response.id,
tenant_id: response.tenant_id,
field_name: response.field_name,
field_type: FIELD_TYPE_MAP[response.field_type] || 'TEXT', // 타입 값 변환
category: response.category,
description: response.description,
default_validation: response.validation_rules, // 필드명 매핑
default_properties: response.properties, // 필드명 매핑
created_by: response.created_by,
updated_by: response.updated_by,
created_at: response.created_at,
updated_at: response.updated_at,
};
};
// ============================================
// Frontend State → API Request 변환
// ============================================
/**
* ItemSection ItemSectionRequest
* 변환: section_type type, (BASIC fields, BOM bom)
*/
export const transformSectionToRequest = (
section: Partial<ItemSection>
): { title: string; type: 'fields' | 'bom' } => {
return {
title: section.title || '',
type: section.section_type
? SECTION_TYPE_REVERSE_MAP[section.section_type] || 'fields'
: 'fields',
};
};
/**
* ItemField ItemFieldRequest
* 변환: field_type (TEXT textbox, SELECT dropdown )
*/
export const transformFieldToRequest = (field: Partial<ItemField>) => {
return {
field_name: field.field_name || '',
field_type: field.field_type
? FIELD_TYPE_REVERSE_MAP[field.field_type] || 'textbox'
: 'textbox',
is_required: field.is_required ?? false,
placeholder: field.placeholder || null,
default_value: field.default_value || null,
display_condition: field.display_condition || null,
validation_rules: field.validation_rules || null,
options: field.options || null,
properties: field.properties || null,
};
};
/**
* BOMItem BomItemRequest
*/
export const transformBomItemToRequest = (bomItem: Partial<BOMItem>) => {
return {
item_code: bomItem.item_code || undefined,
item_name: bomItem.item_name || '',
quantity: bomItem.quantity || 0,
unit: bomItem.unit || undefined,
unit_price: bomItem.unit_price || undefined,
total_price: bomItem.total_price || undefined,
spec: bomItem.spec || undefined,
note: bomItem.note || undefined,
};
};
/**
* SectionTemplate SectionTemplateRequest
* 변환: template_name title, section_type type,
*/
export const transformSectionTemplateToRequest = (
template: Partial<SectionTemplate>
) => {
return {
title: template.template_name || '', // 필드명 역변환
type: template.section_type
? SECTION_TYPE_REVERSE_MAP[template.section_type] || 'fields'
: 'fields',
description: template.description || undefined,
is_default: false, // 기본값
};
};
/**
* ItemMasterField MasterFieldRequest
* 변환: field_type , default_validation/properties
*/
export const transformMasterFieldToRequest = (
field: Partial<ItemMasterField>
) => {
return {
field_name: field.field_name || '',
field_type: field.field_type
? FIELD_TYPE_REVERSE_MAP[field.field_type] || 'textbox'
: 'textbox',
category: field.category || undefined,
description: field.description || undefined,
is_common: false, // 기본값
default_value: undefined,
options: undefined,
validation_rules: field.default_validation || undefined, // 필드명 역변환
properties: field.default_properties || undefined, // 필드명 역변환
};
};
// ============================================
// 배치 변환 헬퍼
// ============================================
/**
*
*/
export const transformPagesResponse = (
responses: ItemPageResponse[]
): ItemPage[] => {
return responses.map(transformPageResponse);
};
/**
*
*/
export const transformSectionsResponse = (
responses: ItemSectionResponse[]
): ItemSection[] => {
return responses.map(transformSectionResponse);
};
/**
*
*/
export const transformFieldsResponse = (
responses: ItemFieldResponse[]
): ItemField[] => {
return responses.map(transformFieldResponse);
};
/**
* BOM
*/
export const transformBomItemsResponse = (
responses: BomItemResponse[]
): BOMItem[] => {
return responses.map(transformBomItemResponse);
};
/**
* 릿
*/
export const transformSectionTemplatesResponse = (
responses: SectionTemplateResponse[]
): SectionTemplate[] => {
return responses.map(transformSectionTemplateResponse);
};
/**
*
*/
export const transformMasterFieldsResponse = (
responses: MasterFieldResponse[]
): ItemMasterField[] => {
return responses.map(transformMasterFieldResponse);
};
/**
* UnitOptionResponse MasterOption (Frontend의 MasterOption )
*/
export const transformUnitOptionResponse = (
response: UnitOptionResponse
): { id: string; value: string; label: string; isActive: boolean } => {
return {
id: response.id.toString(), // number → string 변환
value: response.value,
label: response.label,
isActive: true, // API에 없으므로 기본값
};
};
/**
* CustomTabResponse Frontend customTabs
*/
export const transformCustomTabResponse = (
response: CustomTabResponse
): { id: string; label: string; icon: string; isDefault: boolean; order: number } => {
return {
id: response.id.toString(), // number → string 변환
label: response.label,
icon: response.icon || 'FileText', // null이면 기본 아이콘
isDefault: response.is_default,
order: response.order_no,
};
};
/**
*
*/
export const transformUnitOptionsResponse = (
responses: UnitOptionResponse[]
) => {
return responses.map(transformUnitOptionResponse);
};
/**
*
*/
export const transformCustomTabsResponse = (
responses: CustomTabResponse[]
) => {
return responses.map(transformCustomTabResponse);
};