onsitesurvey/src/hooks/useInquiry.ts
keyy1315 f693062d96 feat: 내가 작성한 매물/문의 경로 별 적용 구현
- 메인 화면에서 진입 시 내가 작성한 매물/문의 해제
- 사이드바에서 진입 시 내가 작성환 매물/문의 체크
2025-07-02 10:31:13 +09:00

248 lines
7.9 KiB
TypeScript

import { InquiryList, Inquiry, InquirySaveResponse, CommonCode } from '@/types/Inquiry'
import { useAxios } from '@/hooks/useAxios'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
import { useMemo } from 'react'
import { useRouter } from 'next/navigation'
import { useAlertMsg } from '@/hooks/useAlertMsg'
/**
* @description 문의사항 관련 기능을 제공하는 커스텀 훅
*
* @param {number} [qnoNo] 문의사항 번호
* @param {string} [compCd] 회사 코드
* @returns {Object} 문의사항 관련 기능과 데이터
* @returns {InquiryList[]} inquiryList - 문의사항 목록
* @returns {boolean} isLoadingInquiryList - 문의사항 목록 로딩 상태
* @returns {Inquiry|null} inquiryDetail - 문의사항 상세 정보
* @returns {boolean} isLoadingInquiryDetail - 문의사항 상세 정보 로딩 상태
* @returns {boolean} isSavingInquiry - 문의사항 저장 중 상태
* @returns {Function} saveInquiry - 문의사항 저장 함수
* @returns {Function} downloadFile - 파일 다운로드 함수
* @returns {CommonCode[]} commonCodeList - 공통 코드 목록
*/
export function useInquiry(
qnoNo?: number,
isList?: boolean,
): {
inquiryList: InquiryList[]
isLoadingInquiryList: boolean
inquiryDetail: Inquiry | null
isLoadingInquiryDetail: boolean
isSavingInquiry: boolean
saveInquiry: (formData: FormData) => Promise<InquirySaveResponse>
downloadFile: (encodeFileNo: number, srcFileNm: string) => Promise<Blob | null>
commonCodeList: CommonCode[]
} {
const queryClient = useQueryClient()
const { inquiryListRequest, offset, isMyInquiry } = useInquiryFilterStore()
const { axiosInstance } = useAxios()
const router = useRouter()
const { showErrorAlert } = useAlertMsg()
/**
* @description API 에러 처리 및 라우팅
*
* @param {any} error 에러 객체
* @returns {void} 라우팅 처리
*/
const handleError = (error: any, isThrow?: boolean) => {
const status = error.response?.status
const errorMsg = error.response?.data.error
console.error('❌ AXIOS INSTANCE ERROR : ', error)
if (errorMsg) {
showErrorAlert(errorMsg)
}
if (isThrow) {
throw new Error(error)
}
switch (status) {
// session 없는 경우
case 401:
router.replace('/login')
break
// 조회 권한 없는 경우
case 403:
router.replace('/inquiry/list')
break
// 데이터 DB상 존재하지 않는 경우
case 404:
router.replace('/inquiry/list')
break
// 서버 오류
case 500:
router.back()
break
default:
break
}
}
/**
* @description 비동기 함수 try-catch 처리 함수
* @param {() => Promise<any>} func 비동기 함수
* @param {boolean} isList 목록 조회 여부
* @param {boolean} isThrow 에러 던지기 여부
* @returns {Promise<any>} 함수 결과 또는 빈 데이터
*/
const tryFunction = async (func: () => Promise<any>, isList?: boolean, isThrow?: boolean): Promise<any> => {
try {
return await func()
} catch (error) {
handleError(error, isThrow)
if (isList) {
return { data: [], count: 0 }
}
return null
}
}
/**
* @description 문의사항 목록 조회
*
* @returns {Object} 문의사항 목록 데이터
* @returns {InquiryList[]} data - 문의사항 목록
* @returns {boolean} isLoading - 문의사항 목록 로딩 상태
*/
const { data: inquiryList, isLoading: isLoadingInquiryList } = useQuery({
queryKey: ['inquiryList', inquiryListRequest.loginId, inquiryListRequest.schTitle, inquiryListRequest.schAnswerYn, offset, isMyInquiry],
queryFn: async () => {
const isListQuery = true
const shouldThrowError = false
const resp = await tryFunction(
() =>
axiosInstance(null).get<{ data: InquiryList[] }>(`/api/qna/list`, {
params: { inquiryListRequest, startRow: offset, endRow: offset + 9, schRegId: isMyInquiry },
}),
isListQuery,
shouldThrowError,
)
return resp.data
},
enabled: isList,
})
/**
* @description 문의사항 목록 데이터 메모이제이션
*
* @returns {Object} 메모이제이션된 문의사항 목록 데이터
* @returns {InquiryList[]} inquiryList - 문의사항 목록
*/
const inquriyListData = useMemo(() => {
if (isLoadingInquiryList) {
return { inquiryList: [] }
}
return {
inquiryList: inquiryList ?? [],
}
}, [inquiryList, isLoadingInquiryList])
/**
* @description 문의사항 상세 정보 조회
*
* @returns {Object} 문의사항 상세 정보 데이터
* @returns {Inquiry|null} data - 문의사항 상세 정보
* @returns {boolean} isLoading - 문의사항 상세 정보 로딩 상태
*/
const { data: inquiryDetail, isLoading: isLoadingInquiryDetail } = useQuery({
queryKey: ['inquiryDetail', qnoNo],
queryFn: async () => {
const isListQuery = false
const shouldThrowError = false
const resp = await tryFunction(
() =>
axiosInstance(null).get<{ data: Inquiry }>(`/api/qna/detail`, {
params: { qnoNo, compCd: '5200', langCd: 'JA' },
}),
isListQuery,
shouldThrowError,
)
return resp?.data ?? null
},
enabled: qnoNo !== undefined,
})
/**
* @description 문의사항 저장
*
* @param {FormData} formData 저장할 문의사항 데이터
* @returns {Promise<InquirySaveResponse>} 저장된 문의사항 응답 데이터
*/
const { mutateAsync: saveInquiry, isPending: isSavingInquiry } = useMutation({
mutationFn: async (formData: FormData) => {
const isListQuery = false
const shouldThrowError = true
const resp = await tryFunction(
() => axiosInstance(null).post<{ data: InquirySaveResponse }>('/api/qna/save', formData),
isListQuery,
shouldThrowError,
)
return resp?.data ?? null
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['inquiryList'] })
},
onError: (error: any) => {
handleError(error, true)
},
})
/**
* @description 파일 다운로드
*
* @param {number} encodeFileNo 인코딩된 파일 번호
* @param {string} srcFileNm 원본 파일명
* @returns {Promise<Blob|null>} 다운로드된 파일 데이터 또는 null
*/
const downloadFile = async (encodeFileNo: number, srcFileNm: string) => {
const isListQuery = false
const shouldThrowError = true
const resp = await tryFunction(() => fetch(`/api/qna/file?encodeFileNo=${encodeFileNo}&srcFileNm=${srcFileNm}`), isListQuery, shouldThrowError)
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = srcFileNm
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
return blob
}
/**
* @description 공통 코드 목록 조회
*
* @returns {Object} 공통 코드 목록 데이터
* @returns {CommonCode[]} data - 공통 코드 목록
* @returns {boolean} isLoading - 공통 코드 목록 로딩 상태
*/
const { data: commonCodeList, isLoading: isLoadingCommonCodeList } = useQuery({
queryKey: ['commonCodeList'],
queryFn: async () => {
const isListQuery = false
const shouldThrowError = false
const resp = await tryFunction(() => axiosInstance(null).get<{ data: CommonCode[] }>(`/api/qna`), isListQuery, shouldThrowError)
return resp.data
},
staleTime: Infinity,
gcTime: Infinity,
})
return {
inquiryList: inquriyListData.inquiryList,
inquiryDetail: inquiryDetail ?? null,
isLoadingInquiryList,
isLoadingInquiryDetail,
isSavingInquiry,
saveInquiry,
downloadFile,
commonCodeList: commonCodeList?.data ?? [],
}
}