227 lines
6.4 KiB
JavaScript
227 lines
6.4 KiB
JavaScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { loadConfig } from '../utils';
|
|
import { useAlert } from '../context/AlertProvider';
|
|
import { alertTypes } from '../assets/data/types';
|
|
import * as APIConfigs from '../assets/data/apis'
|
|
import { callAPI } from '../utils/apiService';
|
|
|
|
export const useCommonSearch = (configPath) => {
|
|
const [config, setConfig] = useState(null);
|
|
const [searchParams, setSearchParams] = useState({});
|
|
const [loading, setLoading] = useState(false);
|
|
const [data, setData] = useState(null);
|
|
const [configLoaded, setConfigLoaded] = useState(false);
|
|
const { showToast } = useAlert();
|
|
const [apiEndpoint, setApiEndpoint] = useState(null);
|
|
const [apiConfig, setApiConfig] = useState(null);
|
|
|
|
// 설정 파일 로드
|
|
useEffect(() => {
|
|
const fetchConfig = async () => {
|
|
try {
|
|
const configData = await loadConfig(configPath);
|
|
setConfig(configData);
|
|
|
|
// 초기 검색 파라미터 설정
|
|
if (configData.initialSearchParams) {
|
|
setSearchParams(configData.initialSearchParams);
|
|
}
|
|
|
|
// API 엔드포인트 설정 가져오기
|
|
if (configData.apiInfo && configData.apiInfo.endpointName) {
|
|
const endpointName = configData.apiInfo.endpointName;
|
|
// API 설정 파일에서 엔드포인트 정보 찾기
|
|
for (const configKey in APIConfigs) {
|
|
const apiConfigData = APIConfigs[configKey];
|
|
if (apiConfigData.endpoints && apiConfigData.endpoints[endpointName]) {
|
|
setApiEndpoint(apiConfigData.endpoints[endpointName]);
|
|
setApiConfig(apiConfigData);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setConfigLoaded(true);
|
|
} catch (error) {
|
|
console.error('Error loading search configuration:', error);
|
|
}
|
|
};
|
|
|
|
fetchConfig();
|
|
}, [configPath]);
|
|
|
|
// 파라미터 값 변환 (날짜 등)
|
|
const transformParams = useCallback((params) => {
|
|
if (!config || !config.apiInfo || !config.apiInfo.paramTransforms) {
|
|
return params;
|
|
}
|
|
|
|
const transformedParams = { ...params };
|
|
|
|
// 파라미터 변환 적용
|
|
config.apiInfo.paramTransforms.forEach(paramConfig => {
|
|
if (paramConfig.param && paramConfig.transform) {
|
|
const value = params[paramConfig.param];
|
|
|
|
if (value) {
|
|
if (paramConfig.transform === 'toISOString') {
|
|
transformedParams[paramConfig.param] = new Date(value).toISOString();
|
|
}
|
|
// 필요시 다른 변환 로직 추가
|
|
}
|
|
}
|
|
});
|
|
|
|
return transformedParams;
|
|
}, [config]);
|
|
|
|
// 데이터 가져오기
|
|
const fetchData = useCallback(async (params) => {
|
|
if (!apiEndpoint || !apiConfig) return;
|
|
|
|
try {
|
|
setLoading(true);
|
|
const transformedParams = transformParams(params);
|
|
|
|
// 페이지네이션 필드 옵션
|
|
const paginationOptions = {
|
|
paginationType: config.paginationType
|
|
};
|
|
if (config.apiInfo?.pageField) {
|
|
paginationOptions.pageField = config.apiInfo.pageField;
|
|
}
|
|
if (config.apiInfo?.pageSizeField) {
|
|
paginationOptions.pageSizeField = config.apiInfo.pageSizeField;
|
|
}
|
|
if (config.apiInfo?.orderField) {
|
|
paginationOptions.orderField = config.apiInfo.orderField;
|
|
}
|
|
if (config.paginationType === 'dynamodb' && config.apiInfo?.lastPageKeyField) {
|
|
paginationOptions.lastPageKeyField = config.apiInfo.lastPageKeyField;
|
|
}
|
|
|
|
// API 호출
|
|
const result = await callAPI(
|
|
apiConfig,
|
|
apiEndpoint,
|
|
transformedParams,
|
|
paginationOptions
|
|
);
|
|
|
|
// 에러 처리
|
|
if (result.result && result.result.startsWith('ERROR')) {
|
|
showToast(result.data.message, { type: alertTypes.error });
|
|
}
|
|
// console.log(result.data);
|
|
setData(result.data || result);
|
|
return result.data || result;
|
|
} catch (error) {
|
|
console.error(`Error fetching data:`, error);
|
|
throw error;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [apiEndpoint, apiConfig, config, transformParams, showToast]);
|
|
|
|
const initialLoad = useCallback((config) => {
|
|
// loadOnMount가 undefined 또는 true인 경우 true 반환
|
|
return config?.apiInfo?.loadOnMount === undefined ||
|
|
config?.apiInfo?.loadOnMount === true;
|
|
}, []);
|
|
|
|
// 초기 데이터 로드
|
|
useEffect(() => {
|
|
if (configLoaded && config && searchParams && apiEndpoint && config.apiInfo?.loadOnMount && initialLoad(config)) {
|
|
fetchData(searchParams);
|
|
}
|
|
}, [configLoaded, config, searchParams, apiEndpoint, fetchData]);
|
|
|
|
// 검색 파라미터 업데이트
|
|
const updateSearchParams = useCallback((newParams) => {
|
|
setSearchParams(prev => ({
|
|
...prev,
|
|
...newParams
|
|
}));
|
|
}, []);
|
|
|
|
// 검색 처리
|
|
const handleSearch = useCallback(async (newParams = {}, executeSearch = true) => {
|
|
if (!config) return null;
|
|
|
|
const pageField = 'currentPage'; // 항상 내부적으로는 currentPage 사용
|
|
|
|
const updatedParams = {
|
|
...searchParams,
|
|
...newParams,
|
|
[pageField]: newParams[pageField] || 1 // 새 검색 시 첫 페이지로 리셋
|
|
};
|
|
|
|
if (executeSearch && config.searchFields) {
|
|
const requiredFields = config.searchFields.filter(field => field.required);
|
|
|
|
for (const field of requiredFields) {
|
|
if (!updatedParams[field.id] || updatedParams[field.id].trim() === '') {
|
|
// 필수 필드가 비어있는 경우
|
|
showToast('SEARCH_REQUIRED_WARNING', { type: alertTypes.warning });
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
updateSearchParams(updatedParams);
|
|
|
|
if (executeSearch) {
|
|
return await fetchData(updatedParams);
|
|
}
|
|
return null;
|
|
}, [searchParams, fetchData, config, updateSearchParams]);
|
|
|
|
// 검색 초기화
|
|
const handleReset = useCallback(async () => {
|
|
if (!config || !config.initialSearchParams) return null;
|
|
|
|
setSearchParams(config.initialSearchParams);
|
|
setData(null);
|
|
// return await fetchData(config.initialSearchParams);
|
|
}, [config, fetchData]);
|
|
|
|
// 페이지 변경
|
|
const handlePageChange = useCallback(async (newPage) => {
|
|
if (!config) return null;
|
|
|
|
return await handleSearch({ currentPage: newPage }, true);
|
|
}, [handleSearch, config]);
|
|
|
|
// 페이지 크기 변경
|
|
const handlePageSizeChange = useCallback(async (newSize) => {
|
|
if (!config) return null;
|
|
|
|
return await handleSearch({
|
|
pageSize: newSize,
|
|
currentPage: 1
|
|
}, true);
|
|
}, [handleSearch, config]);
|
|
|
|
// 정렬 방식 변경
|
|
const handleOrderByChange = useCallback(async (newOrder) => {
|
|
if (!config) return null;
|
|
|
|
return await handleSearch({ orderBy: newOrder }, true);
|
|
}, [handleSearch, config]);
|
|
|
|
return {
|
|
config,
|
|
searchParams,
|
|
loading,
|
|
data,
|
|
handleSearch,
|
|
handleReset,
|
|
handlePageChange,
|
|
handlePageSizeChange,
|
|
handleOrderByChange,
|
|
updateSearchParams,
|
|
configLoaded
|
|
};
|
|
};
|
|
|
|
export default useCommonSearch; |