- eslint.config.mjs 규칙 강화 및 정리 - 전역 unused import/변수 제거 (312개 파일) - next.config.ts, middleware, proxy route 개선 - CopyableCell molecule 추가 - 회계/결재/HR/생산/건설/품질/영업 등 전 도메인 lint 정리 - IntegratedListTemplateV2, DataTable, MobileCard 등 공통 컴포넌트 개선 - execute-server-action 에러 핸들링 보강
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useRef } from 'react';
|
|
import { useSearchParams } from 'next/navigation';
|
|
|
|
// ===== 공통 페이지네이션 기본값 =====
|
|
export const DEFAULT_PAGINATION = {
|
|
currentPage: 1,
|
|
lastPage: 1,
|
|
perPage: 100,
|
|
total: 0,
|
|
};
|
|
|
|
export type PaginationMeta = {
|
|
currentPage: number;
|
|
lastPage: number;
|
|
perPage: number;
|
|
total: number;
|
|
};
|
|
|
|
// ===== 반환 타입 =====
|
|
export interface UseAccountingListPageReturn<TData> {
|
|
data: TData[];
|
|
pagination: PaginationMeta;
|
|
isLoading: boolean;
|
|
mode: string | null;
|
|
}
|
|
|
|
/**
|
|
* 회계 목록 페이지 공통 훅
|
|
*
|
|
* searchParams의 mode를 읽어서 skipModes가 아닌 경우 fetchFn을 호출합니다.
|
|
* data, pagination, isLoading, mode를 반환합니다.
|
|
*
|
|
* @param fetchFn - 데이터를 가져오는 함수 (클로저로 params 전달)
|
|
* @param options.skipModes - 데이터 로드를 건너뛸 mode 값 (기본: ['new'])
|
|
*
|
|
* @example
|
|
* const { data, pagination, isLoading, mode } = useAccountingListPage(
|
|
* () => getSales({ perPage: 100 })
|
|
* );
|
|
*/
|
|
export function useAccountingListPage<TData>(
|
|
fetchFn: () => Promise<{ success?: boolean; data: TData[]; pagination?: PaginationMeta }>,
|
|
options?: { skipModes?: string[] }
|
|
): UseAccountingListPageReturn<TData> {
|
|
const searchParams = useSearchParams();
|
|
const mode = searchParams.get('mode');
|
|
const skipModes = options?.skipModes ?? ['new'];
|
|
|
|
const [data, setData] = useState<TData[]>([]);
|
|
const [pagination, setPagination] = useState<PaginationMeta>(DEFAULT_PAGINATION);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
// fetchFn을 ref로 보관하여 stale closure 방지
|
|
const fetchFnRef = useRef(fetchFn);
|
|
fetchFnRef.current = fetchFn;
|
|
|
|
useEffect(() => {
|
|
if (mode && skipModes.includes(mode)) {
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
fetchFnRef.current()
|
|
.then(result => {
|
|
setData(result.data ?? []);
|
|
if (result.pagination) {
|
|
setPagination(result.pagination);
|
|
}
|
|
})
|
|
.finally(() => setIsLoading(false));
|
|
// mode 변경 시에만 재실행
|
|
|
|
}, [mode]);
|
|
|
|
return { data, pagination, isLoading, mode };
|
|
}
|