refactor(WEB): claudedocs 재정리 및 AuthContext/Zustand/유틸 코드 개선

- claudedocs 폴더 구조 재정리: archive/sessions, guides/migration·mobile·universal-list, refactoring 분류
- 오래된 세션 컨텍스트/체크리스트 문서 정리 (아카이브 이동 또는 삭제)
- AuthContext → authStore(Zustand) 전환 시작, RootProvider 간소화
- GenericCRUDDialog 공통 다이얼로그 컴포넌트 추가
- PermissionDialog 삭제 → GenericCRUDDialog로 대체
- RankDialog/TitleDialog GenericCRUDDialog 기반으로 리팩토링
- toast-utils.ts 삭제 (미사용)
- fileDownload.ts 개선, excel-download.ts 정리
- menuStore/themeStore Zustand 셀렉터 최적화
- useColumnSettings/useTableColumnStore 기능 보강
- 세금계산서/견적/작업자화면/결재 등 소규모 개선

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-02-23 17:17:13 +09:00
parent 6c3572e568
commit 07374c826c
75 changed files with 1704 additions and 1376 deletions

View File

@@ -1,116 +0,0 @@
/**
* API 에러 토스트 유틸리티
* - 개발 중 디버깅을 위해 에러 코드와 메시지를 함께 표시
* - 나중에 프로덕션에서 코드 숨기려면 이 파일만 수정하면 됨
*/
import { toast } from 'sonner';
import { ApiError, DuplicateCodeError, getErrorMessage } from './error-handler';
/**
* 디버그 모드 설정
* - true: 에러 코드 표시 (개발/테스트)
* - false: 메시지만 표시 (프로덕션)
*
* TODO: 프로덕션 배포 시 false로 변경하거나 환경변수 사용
*/
const SHOW_ERROR_CODE = true;
/**
* API 에러를 토스트로 표시
* - ApiError: [상태코드] 메시지 형식
* - DuplicateCodeError: 중복 코드 정보 포함
* - 일반 Error: 메시지만 표시
*
* @param error - 발생한 에러 객체
* @param fallbackMessage - 에러 메시지가 없을 때 표시할 기본 메시지
*/
export function toastApiError(
error: unknown,
fallbackMessage = '오류가 발생했습니다.'
): void {
// DuplicateCodeError - 중복 코드 에러 (별도 처리 필요할 수 있음)
if (error instanceof DuplicateCodeError) {
const message = SHOW_ERROR_CODE
? `[${error.status}] ${error.message} (코드: ${error.duplicateCode})`
: error.message;
toast.error(message);
return;
}
// ApiError - HTTP 에러
if (error instanceof ApiError) {
const message = SHOW_ERROR_CODE
? `[${error.status}] ${error.message}`
: error.message;
// Validation 에러가 있으면 첫 번째 에러도 표시
if (error.errors && SHOW_ERROR_CODE) {
const firstErrorField = Object.keys(error.errors)[0];
if (firstErrorField) {
const firstError = error.errors[firstErrorField][0];
toast.error(`${message}\n${firstErrorField}: ${firstError}`);
return;
}
}
toast.error(message);
return;
}
// 일반 Error
if (error instanceof Error) {
toast.error(error.message || fallbackMessage);
return;
}
// unknown 타입
toast.error(fallbackMessage);
}
/**
* API 성공 토스트
* - 일관된 성공 메시지 표시
*
* @param message - 성공 메시지
*/
export function toastSuccess(message: string): void {
toast.success(message);
}
/**
* API 경고 토스트
*
* @param message - 경고 메시지
*/
export function toastWarning(message: string): void {
toast.warning(message);
}
/**
* API 정보 토스트
*
* @param message - 정보 메시지
*/
export function toastInfo(message: string): void {
toast.info(message);
}
/**
* 에러 메시지 포맷팅 (토스트 외 용도)
* - 에러 코드 포함 여부는 SHOW_ERROR_CODE 설정 따름
*
* @param error - 발생한 에러 객체
* @param fallbackMessage - 기본 메시지
* @returns 포맷팅된 에러 메시지
*/
export function formatApiError(
error: unknown,
fallbackMessage = '오류가 발생했습니다.'
): string {
if (error instanceof ApiError) {
return SHOW_ERROR_CODE
? `[${error.status}] ${error.message}`
: error.message;
}
return getErrorMessage(error) || fallbackMessage;
}