refactor(WEB): 전체 actions.ts에 공통 API 유틸 적용
- buildApiUrl / executePaginatedAction 패턴으로 전환 (40+ actions 파일) - 직접 URLSearchParams 조립 → buildApiUrl 유틸 사용 - 수동 페이지네이션 메타 변환 → executePaginatedAction 자동 처리 - HandoverReportDocumentModal, OrderDocumentModal 개선 - 급여관리 SalaryManagement 코드 개선 - CLAUDE.md Server Action 공통 유틸 규칙 정리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,12 +2,11 @@
|
||||
|
||||
|
||||
import { executeServerAction, type ActionResult } from '@/lib/api/execute-server-action';
|
||||
import type { PaginatedApiResponse } from '@/lib/api/types';
|
||||
import { executePaginatedAction } from '@/lib/api/execute-paginated-action';
|
||||
import { buildApiUrl } from '@/lib/api/query-params';
|
||||
import { fetchVendorOptions, fetchBankAccountOptions } from '@/lib/api/shared-lookups';
|
||||
import type { WithdrawalRecord, WithdrawalType } from './types';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
// ===== API 응답 타입 =====
|
||||
interface WithdrawalApiData {
|
||||
id: number;
|
||||
@@ -32,11 +31,6 @@ interface WithdrawalApiData {
|
||||
card?: { id: number; card_name: string } | null;
|
||||
}
|
||||
|
||||
type WithdrawalPaginatedResponse = PaginatedApiResponse<WithdrawalApiData>;
|
||||
|
||||
interface FrontendPagination { currentPage: number; lastPage: number; perPage: number; total: number }
|
||||
const DEFAULT_PAGINATION: FrontendPagination = { currentPage: 1, lastPage: 1, perPage: 20, total: 0 };
|
||||
|
||||
// ===== API → Frontend 변환 =====
|
||||
function transformApiToFrontend(apiData: WithdrawalApiData): WithdrawalRecord {
|
||||
return {
|
||||
@@ -77,40 +71,26 @@ function transformFrontendToApi(data: Partial<WithdrawalRecord>): Record<string,
|
||||
export async function getWithdrawals(params?: {
|
||||
page?: number; perPage?: number; startDate?: string; endDate?: string;
|
||||
withdrawalType?: string; vendor?: string; search?: string;
|
||||
}): Promise<{ success: boolean; data: WithdrawalRecord[]; pagination: FrontendPagination; error?: string }> {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (params?.page) searchParams.set('page', String(params.page));
|
||||
if (params?.perPage) searchParams.set('per_page', String(params.perPage));
|
||||
if (params?.startDate) searchParams.set('start_date', params.startDate);
|
||||
if (params?.endDate) searchParams.set('end_date', params.endDate);
|
||||
if (params?.withdrawalType && params.withdrawalType !== 'all') searchParams.set('withdrawal_type', params.withdrawalType);
|
||||
if (params?.vendor && params.vendor !== 'all') searchParams.set('vendor', params.vendor);
|
||||
if (params?.search) searchParams.set('search', params.search);
|
||||
const queryString = searchParams.toString();
|
||||
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals${queryString ? `?${queryString}` : ''}`,
|
||||
transform: (data: WithdrawalPaginatedResponse | WithdrawalApiData[]) => {
|
||||
const isPaginated = !Array.isArray(data) && data && 'data' in data;
|
||||
const rawData = isPaginated ? (data as WithdrawalPaginatedResponse).data : (Array.isArray(data) ? data : []);
|
||||
const items = rawData.map(transformApiToFrontend);
|
||||
const meta = isPaginated
|
||||
? (data as WithdrawalPaginatedResponse)
|
||||
: { current_page: 1, last_page: 1, per_page: 20, total: items.length };
|
||||
return {
|
||||
items,
|
||||
pagination: { currentPage: meta.current_page || 1, lastPage: meta.last_page || 1, perPage: meta.per_page || 20, total: meta.total || items.length },
|
||||
};
|
||||
},
|
||||
}) {
|
||||
return executePaginatedAction<WithdrawalApiData, WithdrawalRecord>({
|
||||
url: buildApiUrl('/api/v1/withdrawals', {
|
||||
page: params?.page,
|
||||
per_page: params?.perPage,
|
||||
start_date: params?.startDate,
|
||||
end_date: params?.endDate,
|
||||
withdrawal_type: params?.withdrawalType !== 'all' ? params?.withdrawalType : undefined,
|
||||
vendor: params?.vendor !== 'all' ? params?.vendor : undefined,
|
||||
search: params?.search,
|
||||
}),
|
||||
transform: transformApiToFrontend,
|
||||
errorMessage: '출금 내역 조회에 실패했습니다.',
|
||||
});
|
||||
return { success: result.success, data: result.data?.items || [], pagination: result.data?.pagination || DEFAULT_PAGINATION, error: result.error };
|
||||
}
|
||||
|
||||
// ===== 출금 내역 삭제 =====
|
||||
export async function deleteWithdrawal(id: string): Promise<ActionResult> {
|
||||
return executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals/${id}`,
|
||||
url: buildApiUrl(`/api/v1/withdrawals/${id}`),
|
||||
method: 'DELETE',
|
||||
errorMessage: '출금 내역 삭제에 실패했습니다.',
|
||||
});
|
||||
@@ -119,7 +99,7 @@ export async function deleteWithdrawal(id: string): Promise<ActionResult> {
|
||||
// ===== 계정과목명 일괄 저장 =====
|
||||
export async function updateWithdrawalTypes(ids: string[], withdrawalType: string): Promise<ActionResult> {
|
||||
return executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals/bulk-update-type`,
|
||||
url: buildApiUrl('/api/v1/withdrawals/bulk-update-type'),
|
||||
method: 'PUT',
|
||||
body: { ids: ids.map(id => parseInt(id, 10)), withdrawal_type: withdrawalType },
|
||||
errorMessage: '계정과목명 저장에 실패했습니다.',
|
||||
@@ -129,7 +109,7 @@ export async function updateWithdrawalTypes(ids: string[], withdrawalType: strin
|
||||
// ===== 출금 상세 조회 =====
|
||||
export async function getWithdrawalById(id: string): Promise<ActionResult<WithdrawalRecord>> {
|
||||
return executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals/${id}`,
|
||||
url: buildApiUrl(`/api/v1/withdrawals/${id}`),
|
||||
transform: (data: WithdrawalApiData) => transformApiToFrontend(data),
|
||||
errorMessage: '출금 내역 조회에 실패했습니다.',
|
||||
});
|
||||
@@ -138,7 +118,7 @@ export async function getWithdrawalById(id: string): Promise<ActionResult<Withdr
|
||||
// ===== 출금 등록 =====
|
||||
export async function createWithdrawal(data: Partial<WithdrawalRecord>): Promise<ActionResult<WithdrawalRecord>> {
|
||||
return executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals`,
|
||||
url: buildApiUrl('/api/v1/withdrawals'),
|
||||
method: 'POST',
|
||||
body: transformFrontendToApi(data),
|
||||
transform: (data: WithdrawalApiData) => transformApiToFrontend(data),
|
||||
@@ -149,7 +129,7 @@ export async function createWithdrawal(data: Partial<WithdrawalRecord>): Promise
|
||||
// ===== 출금 수정 =====
|
||||
export async function updateWithdrawal(id: string, data: Partial<WithdrawalRecord>): Promise<ActionResult<WithdrawalRecord>> {
|
||||
return executeServerAction({
|
||||
url: `${API_URL}/api/v1/withdrawals/${id}`,
|
||||
url: buildApiUrl(`/api/v1/withdrawals/${id}`),
|
||||
method: 'PUT',
|
||||
body: transformFrontendToApi(data),
|
||||
transform: (data: WithdrawalApiData) => transformApiToFrontend(data),
|
||||
|
||||
Reference in New Issue
Block a user