ERP-node/frontend/hooks/useAutoFill.ts

200 lines
5.4 KiB
TypeScript

/**
* 자동 입력 (Auto-Fill) 커스텀 훅
* 마스터 선택 시 여러 필드를 자동으로 입력하는 기능
*/
import { useState, useCallback, useEffect } from "react";
import {
cascadingAutoFillApi,
AutoFillGroup,
AutoFillOption,
} from "@/lib/api/cascadingAutoFill";
interface AutoFillMapping {
targetField: string;
targetLabel: string;
value: any;
isEditable: boolean;
isRequired: boolean;
}
interface UseAutoFillProps {
/** 자동 입력 그룹 코드 */
groupCode: string;
/** 자동 입력 데이터가 로드되었을 때 호출되는 콜백 */
onAutoFill?: (data: Record<string, any>, mappings: AutoFillMapping[]) => void;
}
interface UseAutoFillResult {
/** 마스터 옵션 목록 */
masterOptions: AutoFillOption[];
/** 현재 선택된 마스터 값 */
selectedMasterValue: string | null;
/** 자동 입력된 데이터 */
autoFilledData: Record<string, any>;
/** 매핑 정보 */
mappings: AutoFillMapping[];
/** 그룹 정보 */
groupInfo: AutoFillGroup | null;
/** 로딩 상태 */
isLoading: boolean;
/** 에러 메시지 */
error: string | null;
/** 마스터 값 선택 핸들러 */
selectMasterValue: (value: string) => Promise<void>;
/** 마스터 옵션 새로고침 */
refreshOptions: () => Promise<void>;
/** 자동 입력 데이터 초기화 */
clearAutoFill: () => void;
}
export function useAutoFill({
groupCode,
onAutoFill,
}: UseAutoFillProps): UseAutoFillResult {
// 상태
const [masterOptions, setMasterOptions] = useState<AutoFillOption[]>([]);
const [selectedMasterValue, setSelectedMasterValue] = useState<string | null>(null);
const [autoFilledData, setAutoFilledData] = useState<Record<string, any>>({});
const [mappings, setMappings] = useState<AutoFillMapping[]>([]);
const [groupInfo, setGroupInfo] = useState<AutoFillGroup | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// 마스터 옵션 로드
const loadMasterOptions = useCallback(async () => {
if (!groupCode) return;
setIsLoading(true);
setError(null);
try {
// 그룹 정보 로드
const groupResponse = await cascadingAutoFillApi.getGroupDetail(groupCode);
if (groupResponse.success && groupResponse.data) {
setGroupInfo(groupResponse.data);
}
// 마스터 옵션 로드
const optionsResponse = await cascadingAutoFillApi.getMasterOptions(groupCode);
if (optionsResponse.success && optionsResponse.data) {
setMasterOptions(optionsResponse.data);
} else {
setError(optionsResponse.error || "옵션 로드 실패");
}
} catch (err: any) {
setError(err.message || "옵션 로드 중 오류 발생");
} finally {
setIsLoading(false);
}
}, [groupCode]);
// 마스터 값 선택 시 자동 입력 데이터 로드
const selectMasterValue = useCallback(
async (value: string) => {
if (!groupCode || !value) {
setSelectedMasterValue(null);
setAutoFilledData({});
setMappings([]);
return;
}
setIsLoading(true);
setError(null);
setSelectedMasterValue(value);
try {
const response = await cascadingAutoFillApi.getData(groupCode, value);
if (response.success) {
const data = response.data || {};
const mappingInfo = response.mappings || [];
setAutoFilledData(data);
setMappings(mappingInfo);
// 콜백 호출
if (onAutoFill) {
onAutoFill(data, mappingInfo);
}
} else {
setError(response.error || "데이터 로드 실패");
}
} catch (err: any) {
setError(err.message || "데이터 로드 중 오류 발생");
} finally {
setIsLoading(false);
}
},
[groupCode, onAutoFill]
);
// 자동 입력 데이터 초기화
const clearAutoFill = useCallback(() => {
setSelectedMasterValue(null);
setAutoFilledData({});
setMappings([]);
}, []);
// 초기 로드
useEffect(() => {
if (groupCode) {
loadMasterOptions();
}
}, [groupCode, loadMasterOptions]);
return {
masterOptions,
selectedMasterValue,
autoFilledData,
mappings,
groupInfo,
isLoading,
error,
selectMasterValue,
refreshOptions: loadMasterOptions,
clearAutoFill,
};
}
// =====================================================
// 화면관리 시스템용 자동 입력 컴포넌트 설정 타입
// =====================================================
export interface AutoFillConfig {
/** 자동 입력 활성화 여부 */
enabled: boolean;
/** 자동 입력 그룹 코드 */
groupCode: string;
/** 마스터 필드명 (이 필드 선택 시 자동 입력 트리거) */
masterField: string;
/** 자동 입력 후 수정 가능 여부 (전체 설정) */
allowEdit?: boolean;
}
/**
* 폼 데이터에 자동 입력 적용
*/
export function applyAutoFillToFormData(
formData: Record<string, any>,
autoFilledData: Record<string, any>,
mappings: AutoFillMapping[]
): Record<string, any> {
const result = { ...formData };
for (const mapping of mappings) {
// 수정 불가능한 필드이거나 기존 값이 없는 경우에만 자동 입력
if (!mapping.isEditable || !result[mapping.targetField]) {
result[mapping.targetField] = autoFilledData[mapping.targetField];
}
}
return result;
}