333 lines
12 KiB
TypeScript
333 lines
12 KiB
TypeScript
import { useInfiniteQuery } from '@tanstack/react-query'
|
||
import { transformObjectKeys } from '@/libs/axios'
|
||
import { useSuitableStore } from '@/store/useSuitableStore'
|
||
import { useAxios } from './useAxios'
|
||
import { useCommCode } from './useCommCode'
|
||
import { SUITABLE_HEAD_CODE, type Suitable, type SuitableDetail, type SuitableIds } from '@/types/Suitable'
|
||
|
||
export function useSuitable() {
|
||
const { axiosInstance } = useAxios()
|
||
const { getCommCode } = useCommCode()
|
||
const {
|
||
itemPerPage,
|
||
suitableCommCode,
|
||
setSuitableCommCode,
|
||
searchCategory,
|
||
clearSearchCategory,
|
||
searchKeyword,
|
||
clearSearchKeyword,
|
||
selectedItems,
|
||
clearSelectedItems,
|
||
} = useSuitableStore()
|
||
|
||
/**
|
||
* @description 지붕재 적합성 데이터 조회. API를 호출하여 검색 조건에 맞는 지붕재 적합성 데이터를 페이지 단위로 조회
|
||
*
|
||
* @param {Object} param
|
||
* @param {number} [param.pageNumber] 페이지 번호 (기본값: 1)
|
||
* @param {string} [param.category] 지붕재그룹코드
|
||
* @param {string} [param.keyword] 검색키워드
|
||
*
|
||
* @returns {Promise<Suitable[]>} 지붕재 적합성 데이터
|
||
*/
|
||
const getSuitables = async ({
|
||
pageNumber,
|
||
category,
|
||
keyword,
|
||
}: {
|
||
pageNumber?: number
|
||
category?: string
|
||
keyword?: string
|
||
}): Promise<Suitable[]> => {
|
||
try {
|
||
const params: Record<string, string | number> = {
|
||
pageNumber: pageNumber || 1,
|
||
itemPerPage: itemPerPage,
|
||
}
|
||
if (category) params.category = category
|
||
if (keyword) params.keyword = keyword
|
||
|
||
const response = await axiosInstance(null).get<Suitable[]>('/api/suitable/list', { params })
|
||
return response.data
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 데이터 조회 실패: ${error}`)
|
||
return []
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 데이터 아이디 조회. API를 호출하여 검색 조건에 맞는 지붕재 적합성 데이터의 main_id, detail_id를 조회
|
||
*
|
||
* @returns {Promise<SuitableIds[]>} 지붕재 적합성 데이터 아이디 목록
|
||
*/
|
||
const getSuitableIds = async (): Promise<SuitableIds[]> => {
|
||
try {
|
||
const params: Record<string, string> = {}
|
||
if (searchCategory) params.category = searchCategory
|
||
if (searchKeyword) params.keyword = searchKeyword
|
||
const response = await axiosInstance(null).get<SuitableIds[]>('/api/suitable/pick', { params })
|
||
return response.data
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 데이터 아이디 조회 실패: ${error}`)
|
||
return []
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 데이터 조회. API를 호출하여 지붕재 적합성 데이터의 모든 컬럼을 조회
|
||
*
|
||
* @param {string} ids 지붕재 적합성 데이터의 main_id (쉼표로 구분된 문자열)
|
||
* @param {string} [detailIds] 지붕재 적합성 데이터의 detail_id (쉼표로 구분된 문자열)
|
||
*
|
||
* @returns {Promise<Suitable[]>} 지붕재 적합성 데이터
|
||
*/
|
||
const getSuitableDetails = async (ids: string, detailIds?: string): Promise<Suitable[]> => {
|
||
try {
|
||
const params: Record<string, string> = { ids: ids }
|
||
if (detailIds?.trim()) params.detailIds = detailIds
|
||
const response = await axiosInstance(null).post<Suitable[]>('/api/suitable', params)
|
||
return response.data
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 상세 데이터 조회 실패: ${error}`)
|
||
return []
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 공통 코드 조회. API를 호출하여 지붕재 적합성 데이터에서 사용하는 공통 코드 조회 후 스토어에 맵핑하여 저장
|
||
*
|
||
* @returns {void}
|
||
*/
|
||
const getSuitableCommCode = (): void => {
|
||
const headCodes = Object.values(SUITABLE_HEAD_CODE) as SUITABLE_HEAD_CODE[]
|
||
for (const code of headCodes) {
|
||
getCommCode(code).then((res) => {
|
||
setSuitableCommCode(code, res)
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 공통 코드의 JP 코드명 조회
|
||
*
|
||
* @param {string} headCode 공통 코드의 head_code
|
||
* @param {string} code 공통 코드의 code
|
||
*
|
||
* @returns {string} 공통 코드의 JP 코드명
|
||
*/
|
||
const toCodeName = (headCode: string, code: string): string => {
|
||
const commCode = suitableCommCode.get(headCode)
|
||
return commCode?.find((item) => item.code === code)?.codeJp || ''
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 detail 데이터를 string 형태로 받아 파싱하여 반환
|
||
*
|
||
* @param {string} suitableDetailString 지붕재 적합성 detail string
|
||
*
|
||
* @returns {SuitableDetail[]} 파싱된 지붕재 적합성 detail 데이터
|
||
*/
|
||
const toSuitableDetail = (suitableDetailString: string): SuitableDetail[] => {
|
||
if (!suitableDetailString) return []
|
||
try {
|
||
const suitableDetailArray = transformObjectKeys(JSON.parse(suitableDetailString)) as SuitableDetail[]
|
||
if (!Array.isArray(suitableDetailArray)) {
|
||
throw new Error('suitableDetailArray is not an array')
|
||
}
|
||
return suitableDetailArray
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 detail 데이터 파싱 실패: ${error}`)
|
||
return []
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 상위 데이터 클릭 시 호출되는 함수. 지붕재 적합성 detail 데이터에서 id 목록을 추출하여 Set 형태로 반환
|
||
*
|
||
* @param {string} suitableDetailString 지붕재 적합성 detail 데이터
|
||
*
|
||
* @returns {Set<number>} 지붕재 적합성 detail 데이터의 id 목록
|
||
*/
|
||
const toSuitableDetailIds = (suitableDetailString: string): Set<number> => {
|
||
try {
|
||
if (!suitableDetailString) return new Set()
|
||
return new Set<number>(JSON.parse(suitableDetailString).map(({ id }: { id: number }) => id))
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 detail 데이터 파싱 실패: ${error}`)
|
||
return new Set()
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 조회 페이지에서 보여지는 지붕재 적합성 데이터 조회
|
||
*
|
||
* @returns {Object} 지붕재 적합성 데이터 조회 결과
|
||
*/
|
||
const {
|
||
data: suitables,
|
||
fetchNextPage,
|
||
hasNextPage,
|
||
isFetchingNextPage,
|
||
isLoading,
|
||
// isError,
|
||
// error,
|
||
} = useInfiniteQuery<Suitable[]>({
|
||
queryKey: ['suitables', 'list', searchCategory, searchKeyword],
|
||
queryFn: async (context) => {
|
||
const pageParam = context.pageParam as number
|
||
if (pageParam === 1) clearSuitableStore({ items: true })
|
||
return await getSuitables({
|
||
pageNumber: pageParam,
|
||
...(searchCategory && { category: searchCategory }),
|
||
...(searchKeyword && { keyword: searchKeyword }),
|
||
})
|
||
},
|
||
getNextPageParam: (lastPage: Suitable[], allPages: Suitable[][]) => {
|
||
return lastPage.length === itemPerPage ? allPages.length + 1 : undefined
|
||
},
|
||
initialPageParam: 1,
|
||
staleTime: 1000 * 60 * 10,
|
||
gcTime: 1000 * 60 * 10,
|
||
enabled: searchCategory !== '' || searchKeyword !== '',
|
||
})
|
||
|
||
/**
|
||
* @description 지붕재 적합성 스토어 초기화. 선택된 지붕재 적합성 데이터, 검색 카테고리, 검색 키워드 초기화
|
||
*
|
||
* @param {Object} param
|
||
* @param {boolean} [param.items] 선택된 지붕재 적합성 데이터 초기화 여부
|
||
* @param {boolean} [param.category] 검색 카테고리 초기화 여부
|
||
* @param {boolean} [param.keyword] 검색 키워드 초기화 여부
|
||
*
|
||
* @returns {void}
|
||
*/
|
||
const clearSuitableStore = ({ items = false, category = false, keyword = false }: { items?: boolean; category?: boolean; keyword?: boolean }) => {
|
||
if (items) clearSelectedItems()
|
||
if (category) clearSearchCategory()
|
||
if (keyword) clearSearchKeyword()
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 비고에 따른 아이콘 반환
|
||
*
|
||
* @param {string} value 지붕재 적합성 비고
|
||
*
|
||
* @returns {string} 지붕재 적합성 비고에 따른 아이콘
|
||
*/
|
||
// TODO: 추후 지붕재 적합성 데이터 CUD 구현 시 ×, -, ー 데이터 관리 필요
|
||
const suitableCheckIcon = (value: string): string => {
|
||
const iconMap: Record<string, string> = {
|
||
'×': '/assets/images/sub/compliance_x_icon.svg',
|
||
'-': '/assets/images/sub/compliance_quest_icon.svg',
|
||
'ー': '/assets/images/sub/compliance_quest_icon.svg',
|
||
default: '/assets/images/sub/compliance_check_icon.svg',
|
||
}
|
||
return iconMap[value] || iconMap.default
|
||
}
|
||
|
||
/**
|
||
* @description 지붕재 적합성 비고에 따른 적합 결과 반환
|
||
*
|
||
* @param {string} value 지붕재 적합성 비고
|
||
*
|
||
* @returns {string} 지붕재 적합성 비고에 따른 적합 결과
|
||
*/
|
||
// TODO: 추후 지붕재 적합성 데이터 CUD 구현 시 ○, ×, -, ー 데이터 관리 필요
|
||
const suitableCheckMemo = (value: string): string => {
|
||
if (value === '○') return '設置可'
|
||
if (value === '×') return '設置不可'
|
||
if (value === '-' || value === 'ー') return 'お問い合わせください'
|
||
return `${value}で設置可`
|
||
}
|
||
|
||
/**
|
||
* @description 선택된 지붕재 적합성 데이터의 main_id, detail_id를 쉼표로 구분하여 반환. 선택된 지붕재 적합성 데이터가 없으면 빈 문자열 반환
|
||
*
|
||
* @returns {Object} 선택된 지붕재 적합성 데이터의 main_id, detail_id
|
||
* @returns {string} 선택된 지붕재 적합성 데이터의 main_id (쉼표로 구분된 문자열)
|
||
* @returns {string} 선택된 지붕재 적합성 데이터의 detail_id (쉼표로 구분된 문자열)
|
||
*/
|
||
const serializeSelectedItems = (): { ids: string; detailIds: string } => {
|
||
const ids: string[] = []
|
||
const detailIds: string[] = []
|
||
for (const [key, value] of selectedItems) {
|
||
ids.push(String(key))
|
||
for (const id of value) detailIds.push(String(id))
|
||
}
|
||
return { ids: ids.join(','), detailIds: detailIds.length > 0 ? detailIds.join(',') : '' }
|
||
}
|
||
|
||
/**
|
||
* @description 선택된 지붕재 적합성 데이터 조회. API를 호출하여 선택된 지붕재 적합성 데이터의 모든 컬럼을 조회
|
||
*
|
||
* @returns {Promise<Suitable[]>} 선택된 지붕재 적합성 데이터
|
||
*/
|
||
const getSelectedSuitables = async (): Promise<Suitable[]> => {
|
||
const { ids, detailIds } = serializeSelectedItems()
|
||
return await getSuitableDetails(ids, detailIds)
|
||
}
|
||
|
||
/**
|
||
* @description 선택된 지붕재 적합성 데이터 pdf 다운로드. form 태그를 생성하여 직접 API를 호출하여 pdf 다운로드
|
||
*
|
||
* @returns {Promise<void>} 선택된 지붕재 적합성 데이터 pdf 다운로드
|
||
*/
|
||
const downloadSuitablePdf = async (): Promise<void> => {
|
||
try {
|
||
const { ids, detailIds } = serializeSelectedItems()
|
||
const fileTitle = `(${
|
||
suitableCommCode.get(SUITABLE_HEAD_CODE.ROOF_MATL_GRP_CD)?.find((category) => category.code === searchCategory)?.codeJp
|
||
}) 屋根材適合表`
|
||
|
||
const form = document.createElement('form')
|
||
form.method = 'POST'
|
||
form.action = '/api/suitable/pdf'
|
||
form.target = '_blank'
|
||
|
||
const inputIds = document.createElement('input')
|
||
inputIds.type = 'hidden'
|
||
inputIds.name = 'ids'
|
||
inputIds.value = ids
|
||
|
||
const inputDetailIds = document.createElement('input')
|
||
inputDetailIds.type = 'hidden'
|
||
inputDetailIds.name = 'detailIds'
|
||
inputDetailIds.value = detailIds
|
||
|
||
const inputFileTitle = document.createElement('input')
|
||
inputFileTitle.type = 'hidden'
|
||
inputFileTitle.name = 'fileTitle'
|
||
inputFileTitle.value = fileTitle
|
||
|
||
form.appendChild(inputIds)
|
||
form.appendChild(inputDetailIds)
|
||
form.appendChild(inputFileTitle)
|
||
document.body.appendChild(form)
|
||
|
||
form.submit()
|
||
document.body.removeChild(form)
|
||
} catch (error) {
|
||
console.error(`지붕재 적합성 상세 데이터 pdf 다운로드 실패: ${error}`)
|
||
}
|
||
}
|
||
|
||
return {
|
||
getSuitables,
|
||
getSuitableIds,
|
||
getSuitableCommCode,
|
||
toCodeName,
|
||
toSuitableDetail,
|
||
toSuitableDetailIds,
|
||
suitables,
|
||
fetchNextPage,
|
||
hasNextPage,
|
||
isFetchingNextPage,
|
||
isLoading,
|
||
getSelectedSuitables,
|
||
clearSuitableStore,
|
||
suitableCheckIcon,
|
||
suitableCheckMemo,
|
||
downloadSuitablePdf,
|
||
}
|
||
}
|