- executePaginatedAction, buildApiUrl 유틸 모듈 분리 - QuoteCalculationReport, demoStore, export.ts 불필요 코드 삭제 - CLAUDE.md에 Zod 스키마 검증 및 Server Action 공통 유틸 규칙 추가 - package.json 의존성 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
/**
|
|
* 페이지네이션 조회 전용 Server Action 래퍼
|
|
*
|
|
* executeServerAction + toPaginationMeta 조합을 통합하여
|
|
* 50+ 파일에서 반복되는 15~25줄 패턴을 5~8줄로 줄입니다.
|
|
*
|
|
* 적용 범위: 신규 코드만 (기존 코드 마이그레이션 없음)
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // Before: ~20줄
|
|
* const result = await executeServerAction({
|
|
* url: `${API_URL}/api/v1/bills?${queryString}`,
|
|
* transform: (data: BillPaginatedResponse) => ({
|
|
* items: (data?.data || []).map(transformApiToFrontend),
|
|
* pagination: { currentPage: data?.current_page || 1, ... },
|
|
* }),
|
|
* errorMessage: '어음 목록 조회에 실패했습니다.',
|
|
* });
|
|
* return { success: result.success, data: result.data?.items || [], ... };
|
|
*
|
|
* // After: ~5줄
|
|
* return executePaginatedAction({
|
|
* url: buildApiUrl('/api/v1/bills', params),
|
|
* transform: transformApiToFrontend,
|
|
* errorMessage: '어음 목록 조회에 실패했습니다.',
|
|
* });
|
|
* ```
|
|
*/
|
|
|
|
import { executeServerAction } from './execute-server-action';
|
|
import { toPaginationMeta, type PaginatedApiResponse, type PaginationMeta } from './types';
|
|
|
|
// ===== 반환 타입 =====
|
|
export interface PaginatedActionResult<T> {
|
|
success: boolean;
|
|
data: T[];
|
|
pagination: PaginationMeta;
|
|
error?: string;
|
|
__authError?: boolean;
|
|
}
|
|
|
|
// ===== 옵션 타입 =====
|
|
interface PaginatedActionOptions<TApi, TResult> {
|
|
/** API URL (전체 경로) */
|
|
url: string;
|
|
/** 개별 아이템 변환 함수 (API 응답 아이템 → 프론트엔드 타입) */
|
|
transform: (item: TApi) => TResult;
|
|
/** 실패 시 기본 에러 메시지 */
|
|
errorMessage: string;
|
|
}
|
|
|
|
const DEFAULT_PAGINATION: PaginationMeta = {
|
|
currentPage: 1,
|
|
lastPage: 1,
|
|
perPage: 20,
|
|
total: 0,
|
|
};
|
|
|
|
/**
|
|
* 페이지네이션 조회 Server Action 실행
|
|
*
|
|
* executeServerAction으로 API 호출 → data 배열에 transform 적용 → toPaginationMeta 변환
|
|
*/
|
|
export async function executePaginatedAction<TApi, TResult>(
|
|
options: PaginatedActionOptions<TApi, TResult>
|
|
): Promise<PaginatedActionResult<TResult>> {
|
|
const { url, transform, errorMessage } = options;
|
|
|
|
const result = await executeServerAction<PaginatedApiResponse<TApi>>({
|
|
url,
|
|
errorMessage,
|
|
});
|
|
|
|
if (!result.success || !result.data) {
|
|
return {
|
|
success: result.success,
|
|
data: [],
|
|
pagination: DEFAULT_PAGINATION,
|
|
error: result.error,
|
|
__authError: result.__authError,
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: (result.data.data || []).map(transform),
|
|
pagination: toPaginationMeta(result.data),
|
|
};
|
|
}
|