chore(WEB): actions.ts 에러 핸들링 및 CEO 대시보드 개선

- 전체 모듈 actions.ts redirect 에러 핸들링 추가
- CEODashboard DetailModal 추가
- MonthlyExpenseSection 개선
- fetch-wrapper redirect 에러 처리
- redirect-error 유틸 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2026-01-08 18:41:15 +09:00
parent 9885085259
commit 0d539628f3
61 changed files with 1226 additions and 359 deletions

View File

@@ -11,7 +11,7 @@
'use server';
import { isRedirectError } from 'next/dist/client/components/redirect';
import { isNextRedirectError } from '@/lib/utils/redirect-error';
import { cookies } from 'next/headers';
import { serverFetch } from '@/lib/api/fetch-wrapper';
import type {
@@ -185,7 +185,7 @@ export async function uploadFiles(files: File[]): Promise<{
return { success: true, data: uploadedFiles };
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] uploadFiles error:', error);
return { success: false, error: '파일 업로드 중 오류가 발생했습니다.' };
}
@@ -237,7 +237,7 @@ export async function getExpenseEstimateItems(yearMonth?: string): Promise<{
finalDifference: result.data.final_difference,
};
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] getExpenseEstimateItems error:', error);
return null;
}
@@ -278,7 +278,7 @@ export async function getEmployees(search?: string): Promise<ApprovalPerson[]> {
return result.data.data.map(transformEmployee);
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] getEmployees error:', error);
return [];
}
@@ -359,7 +359,7 @@ export async function createApproval(formData: DocumentFormData): Promise<{
},
};
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] createApproval error:', error);
return {
success: false,
@@ -402,7 +402,7 @@ export async function submitApproval(id: number): Promise<{
return { success: true };
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] submitApproval error:', error);
return {
success: false,
@@ -440,7 +440,7 @@ export async function createAndSubmitApproval(formData: DocumentFormData): Promi
data: createResult.data,
};
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] createAndSubmitApproval error:', error);
return {
success: false,
@@ -488,7 +488,7 @@ export async function getApprovalById(id: number): Promise<{
return { success: true, data: formDataResult };
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] getApprovalById error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
@@ -567,7 +567,7 @@ export async function updateApproval(id: number, formData: DocumentFormData): Pr
},
};
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] updateApproval error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
@@ -602,7 +602,7 @@ export async function updateAndSubmitApproval(id: number, formData: DocumentForm
data: updateResult.data,
};
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] updateAndSubmitApproval error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
@@ -641,7 +641,7 @@ export async function deleteApproval(id: number): Promise<{
return { success: true };
} catch (error) {
if (isRedirectError(error)) throw error;
if (isNextRedirectError(error)) throw error;
console.error('[DocumentCreateActions] deleteApproval error:', error);
return {
success: false,