Compare commits
No commits in common. "c92c1c247007d67162510e9b95c174ad54d92403" and "54cd61c8b2919aea67654dbf45660ee977deee92" have entirely different histories.
c92c1c2470
...
54cd61c8b2
@ -9,7 +9,7 @@ import { SUITABLE_HEAD_CODE, type Suitable, type SuitableDetail } from '@/types/
|
|||||||
|
|
||||||
export default function SuitableDetailPopup() {
|
export default function SuitableDetailPopup() {
|
||||||
const popupController = usePopupController()
|
const popupController = usePopupController()
|
||||||
const { toCodeName, toSuitableDetail, suitableCheckIcon, suitableCheckMemo, getSelectedSuitables, suitableErrorAlert } = useSuitable()
|
const { toCodeName, toSuitableDetail, suitableCheckIcon, suitableCheckMemo, getSelectedSuitables } = useSuitable()
|
||||||
|
|
||||||
const [openItems, setOpenItems] = useState<Set<number>>(new Set())
|
const [openItems, setOpenItems] = useState<Set<number>>(new Set())
|
||||||
const [selectedSuitables, setSelectedSuitables] = useState<Suitable[]>([])
|
const [selectedSuitables, setSelectedSuitables] = useState<Suitable[]>([])
|
||||||
@ -24,13 +24,9 @@ export default function SuitableDetailPopup() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getSelectedSuitables()
|
getSelectedSuitables().then((res) => {
|
||||||
.then((res) => {
|
setSelectedSuitables(res)
|
||||||
setSelectedSuitables(res)
|
})
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
suitableErrorAlert()
|
|
||||||
})
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -6,16 +6,12 @@ import { useSuitableStore } from '@/store/useSuitableStore'
|
|||||||
|
|
||||||
export default function SuitableButton() {
|
export default function SuitableButton() {
|
||||||
const popupController = usePopupController()
|
const popupController = usePopupController()
|
||||||
const { getSuitableIds, clearSuitableStore, downloadSuitablePdf, suitableErrorAlert } = useSuitable()
|
const { getSuitableIds, clearSuitableStore, downloadSuitablePdf } = useSuitable()
|
||||||
const { selectedItems, addAllSelectedItem } = useSuitableStore()
|
const { selectedItems, addAllSelectedItem } = useSuitableStore()
|
||||||
|
|
||||||
/* 데이터 전체 선택 */
|
/* 데이터 전체 선택 */
|
||||||
const handleSelectAll = async () => {
|
const handleSelectAll = async () => {
|
||||||
try {
|
addAllSelectedItem(await getSuitableIds())
|
||||||
addAllSelectedItem(await getSuitableIds())
|
|
||||||
} catch (error) {
|
|
||||||
suitableErrorAlert()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 상세 팝업 열기 */
|
/* 상세 팝업 열기 */
|
||||||
|
|||||||
@ -19,9 +19,7 @@ export default function SuitableList() {
|
|||||||
hasNextPage,
|
hasNextPage,
|
||||||
isFetchingNextPage,
|
isFetchingNextPage,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
|
||||||
suitableCheckIcon,
|
suitableCheckIcon,
|
||||||
suitableErrorAlert,
|
|
||||||
} = useSuitable()
|
} = useSuitable()
|
||||||
const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore()
|
const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore()
|
||||||
const [openItems, setOpenItems] = useState<Set<number>>(new Set())
|
const [openItems, setOpenItems] = useState<Set<number>>(new Set())
|
||||||
@ -146,11 +144,6 @@ export default function SuitableList() {
|
|||||||
useSpinnerStore.getState().setIsShow(isLoading || isFetchingNextPage)
|
useSpinnerStore.getState().setIsShow(isLoading || isFetchingNextPage)
|
||||||
}, [isLoading, isFetchingNextPage])
|
}, [isLoading, isFetchingNextPage])
|
||||||
|
|
||||||
/* 조회 데이터 오류 처리 */
|
|
||||||
useEffect(() => {
|
|
||||||
if (isError) suitableErrorAlert()
|
|
||||||
}, [isError])
|
|
||||||
|
|
||||||
/* 조회 데이터 없는 경우 */
|
/* 조회 데이터 없는 경우 */
|
||||||
if (!suitableList.length) return <SuitableNoData />
|
if (!suitableList.length) return <SuitableNoData />
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export function useCommCode() {
|
|||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`common code (${headCode}) load failed:`, error)
|
console.error(`common code (${headCode}) load failed:`, error)
|
||||||
throw error
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export function useSuitable() {
|
|||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`지붕재 적합성 데이터 조회 실패: ${error}`)
|
console.error(`지붕재 적합성 데이터 조회 실패: ${error}`)
|
||||||
throw error
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ export function useSuitable() {
|
|||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`지붕재 적합성 데이터 아이디 조회 실패: ${error}`)
|
console.error(`지붕재 적합성 데이터 아이디 조회 실패: ${error}`)
|
||||||
throw error
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ export function useSuitable() {
|
|||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`지붕재 적합성 상세 데이터 조회 실패: ${error}`)
|
console.error(`지붕재 적합성 상세 데이터 조회 실패: ${error}`)
|
||||||
throw error
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,13 +101,9 @@ export function useSuitable() {
|
|||||||
const getSuitableCommCode = (): void => {
|
const getSuitableCommCode = (): void => {
|
||||||
const headCodes = Object.values(SUITABLE_HEAD_CODE) as SUITABLE_HEAD_CODE[]
|
const headCodes = Object.values(SUITABLE_HEAD_CODE) as SUITABLE_HEAD_CODE[]
|
||||||
for (const code of headCodes) {
|
for (const code of headCodes) {
|
||||||
getCommCode(code)
|
getCommCode(code).then((res) => {
|
||||||
.then((res) => {
|
setSuitableCommCode(code, res)
|
||||||
setSuitableCommCode(code, res)
|
})
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
suitableErrorAlert()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,8 +169,8 @@ export function useSuitable() {
|
|||||||
hasNextPage,
|
hasNextPage,
|
||||||
isFetchingNextPage,
|
isFetchingNextPage,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
// isError,
|
||||||
error,
|
// error,
|
||||||
} = useInfiniteQuery<Suitable[]>({
|
} = useInfiniteQuery<Suitable[]>({
|
||||||
queryKey: ['suitables', 'list', searchCategory, searchKeyword],
|
queryKey: ['suitables', 'list', searchCategory, searchKeyword],
|
||||||
queryFn: async (context) => {
|
queryFn: async (context) => {
|
||||||
@ -193,8 +189,6 @@ export function useSuitable() {
|
|||||||
staleTime: 1000 * 60 * 10,
|
staleTime: 1000 * 60 * 10,
|
||||||
gcTime: 1000 * 60 * 10,
|
gcTime: 1000 * 60 * 10,
|
||||||
enabled: searchCategory !== '' || searchKeyword !== '',
|
enabled: searchCategory !== '' || searchKeyword !== '',
|
||||||
retry: 1,
|
|
||||||
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -269,12 +263,8 @@ export function useSuitable() {
|
|||||||
* @returns {Promise<Suitable[]>} 선택된 지붕재 적합성 데이터
|
* @returns {Promise<Suitable[]>} 선택된 지붕재 적합성 데이터
|
||||||
*/
|
*/
|
||||||
const getSelectedSuitables = async (): Promise<Suitable[]> => {
|
const getSelectedSuitables = async (): Promise<Suitable[]> => {
|
||||||
try {
|
const { ids, detailIds } = serializeSelectedItems()
|
||||||
const { ids, detailIds } = serializeSelectedItems()
|
return await getSuitableDetails(ids, detailIds)
|
||||||
return await getSuitableDetails(ids, detailIds)
|
|
||||||
} catch (error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,20 +308,11 @@ export function useSuitable() {
|
|||||||
document.body.removeChild(form)
|
document.body.removeChild(form)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`지붕재 적합성 상세 데이터 pdf 다운로드 실패: ${error}`)
|
console.error(`지붕재 적합성 상세 데이터 pdf 다운로드 실패: ${error}`)
|
||||||
suitableErrorAlert()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 지붕재 적합성 오류 알림 표시
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
const suitableErrorAlert = (): void => {
|
|
||||||
alert('一時的なエラーが発生しました。 継続的な場合は、管理者に連絡してください。')
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
getSuitables,
|
||||||
getSuitableIds,
|
getSuitableIds,
|
||||||
getSuitableCommCode,
|
getSuitableCommCode,
|
||||||
toCodeName,
|
toCodeName,
|
||||||
@ -342,13 +323,10 @@ export function useSuitable() {
|
|||||||
hasNextPage,
|
hasNextPage,
|
||||||
isFetchingNextPage,
|
isFetchingNextPage,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
|
||||||
error,
|
|
||||||
getSelectedSuitables,
|
getSelectedSuitables,
|
||||||
clearSuitableStore,
|
clearSuitableStore,
|
||||||
suitableCheckIcon,
|
suitableCheckIcon,
|
||||||
suitableCheckMemo,
|
suitableCheckMemo,
|
||||||
downloadSuitablePdf,
|
downloadSuitablePdf,
|
||||||
suitableErrorAlert,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,14 +15,9 @@ interface ApiLogData {
|
|||||||
body: string | undefined
|
body: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 현재 날짜 반환 함수 (YYYY-MM-DD 형식) */
|
|
||||||
const getCurrentDate = (): string => {
|
|
||||||
return new Date().toISOString().split('T')[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 날짜별 로그 파일 경로 생성 함수 */
|
/* 날짜별 로그 파일 경로 생성 함수 */
|
||||||
const getLogFilePath = (): string => {
|
const getLogFilePath = (): string => {
|
||||||
const today: string = getCurrentDate()
|
const today = new Date().toISOString().split('T')[0] // YYYY-MM-DD 형식
|
||||||
return join(process.cwd(), 'logs', `onsite-survey-${today}.log`)
|
return join(process.cwd(), 'logs', `onsite-survey-${today}.log`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +25,15 @@ const getLogFilePath = (): string => {
|
|||||||
class DailyLogger {
|
class DailyLogger {
|
||||||
private currentDate: string
|
private currentDate: string
|
||||||
private logger: pino.Logger
|
private logger: pino.Logger
|
||||||
private destination?: ReturnType<typeof pino.destination>
|
private destination: ReturnType<typeof pino.destination>
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.currentDate = getCurrentDate()
|
this.currentDate = new Date().toISOString().split('T')[0]
|
||||||
|
this.destination = pino.destination({
|
||||||
|
dest: getLogFilePath(),
|
||||||
|
mkdir: true,
|
||||||
|
sync: false,
|
||||||
|
})
|
||||||
this.logger = this.createLogger()
|
this.logger = this.createLogger()
|
||||||
|
|
||||||
/* kill signal 핸들러 등록 */
|
/* kill signal 핸들러 등록 */
|
||||||
@ -42,31 +42,14 @@ class DailyLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async handleShutdown(): Promise<void> {
|
private async handleShutdown(): Promise<void> {
|
||||||
if (isProduction && this.destination) {
|
this.destination.flushSync()
|
||||||
this.destination.flushSync()
|
this.destination.end()
|
||||||
this.destination.end()
|
|
||||||
}
|
|
||||||
this.logger.flush()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createLogger(): pino.Logger {
|
private createLogger(): pino.Logger {
|
||||||
if (!isProduction) return pino({ level: 'silent' })
|
|
||||||
|
|
||||||
/* 기존 destination 종료 */
|
|
||||||
if (this.destination) {
|
|
||||||
this.destination.flushSync()
|
|
||||||
this.destination.end()
|
|
||||||
}
|
|
||||||
/* 새로운 destination 생성 */
|
|
||||||
this.destination = pino.destination({
|
|
||||||
dest: getLogFilePath(),
|
|
||||||
mkdir: true,
|
|
||||||
sync: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
return pino(
|
return pino(
|
||||||
{
|
{
|
||||||
level: 'info',
|
level: isProduction ? 'info' : 'silent',
|
||||||
timestamp: pino.stdTimeFunctions.isoTime,
|
timestamp: pino.stdTimeFunctions.isoTime,
|
||||||
},
|
},
|
||||||
this.destination,
|
this.destination,
|
||||||
@ -74,16 +57,24 @@ class DailyLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public info(obj: any, msg?: string): void {
|
public info(obj: any, msg?: string): void {
|
||||||
try {
|
const today = new Date().toISOString().split('T')[0]
|
||||||
const today: string = getCurrentDate()
|
|
||||||
if (today !== this.currentDate) {
|
if (today !== this.currentDate) {
|
||||||
this.currentDate = today
|
/* 기존 destination 종료 */
|
||||||
this.logger = this.createLogger()
|
this.destination.flushSync()
|
||||||
}
|
this.destination.end()
|
||||||
this.logger.info(obj, msg)
|
|
||||||
} catch (error) {
|
/* 새로운 destination 생성 */
|
||||||
console.error(`[DailyLogger] Failed to write log: ${error}`)
|
this.destination = pino.destination({
|
||||||
|
dest: getLogFilePath(),
|
||||||
|
mkdir: true,
|
||||||
|
sync: false,
|
||||||
|
})
|
||||||
|
this.currentDate = today
|
||||||
|
this.logger = this.createLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.info(obj, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,8 +83,6 @@ const dailyLogger = new DailyLogger()
|
|||||||
|
|
||||||
/* API 로그 기록 함수 */
|
/* API 로그 기록 함수 */
|
||||||
export const writeApiLog = async (request: NextRequest, responseStatus: number): Promise<void> => {
|
export const writeApiLog = async (request: NextRequest, responseStatus: number): Promise<void> => {
|
||||||
if (!isProduction) return
|
|
||||||
|
|
||||||
const logData: ApiLogData = {
|
const logData: ApiLogData = {
|
||||||
responseStatus: responseStatus,
|
responseStatus: responseStatus,
|
||||||
method: request.method,
|
method: request.method,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user