api 공통 모듈생성
search, api 공통 모듈 생성 공통모듈 화면 별 반영
This commit is contained in:
227
src/hooks/useCommonSearch.js
Normal file
227
src/hooks/useCommonSearch.js
Normal file
@@ -0,0 +1,227 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user