fix(WEB): 토큰 만료 시 무한 로딩 대신 로그인 리다이렉트 처리

- 52개 이상의 컴포넌트에 isNextRedirectError 처리 추가
- Server Action의 redirect() 에러가 catch 블록에서 삼켜지는 문제 해결
- access_token + refresh_token 모두 만료 시 정상적으로 로그인 페이지로 리다이렉트

수정된 영역:
- accounting: 10개 컴포넌트
- production: 12개 컴포넌트
- hr: 5개 컴포넌트
- settings: 8개 컴포넌트
- approval: 5개 컴포넌트
- items: 20개+ 컴포넌트
- board: 5개 컴포넌트
- quality: 4개 컴포넌트
- material, outbound, quotes 등 기타 컴포넌트

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2026-01-11 17:19:11 +09:00
parent 8bc4b90fe9
commit e56b7d53a4
131 changed files with 3320 additions and 1979 deletions

View File

@@ -23,24 +23,27 @@ interface MasterFieldDialogProps {
setNewMasterFieldName: (name: string) => void;
newMasterFieldKey: string;
setNewMasterFieldKey: (key: string) => void;
newMasterFieldInputType: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
setNewMasterFieldInputType: (type: any) => void;
// string 타입으로 유연하게 처리
newMasterFieldInputType: string;
setNewMasterFieldInputType: (type: string) => void;
newMasterFieldRequired: boolean;
setNewMasterFieldRequired: (required: boolean) => void;
newMasterFieldCategory: string;
setNewMasterFieldCategory: (category: string) => void;
newMasterFieldDescription: string;
setNewMasterFieldDescription: (description: string) => void;
newMasterFieldOptions: string;
setNewMasterFieldOptions: (options: string) => void;
newMasterFieldAttributeType: 'custom' | 'unit' | 'material' | 'surface';
setNewMasterFieldAttributeType: (type: 'custom' | 'unit' | 'material' | 'surface') => void;
// string 또는 string[] 모두 지원
newMasterFieldOptions: string | string[];
setNewMasterFieldOptions: ((options: string) => void) | React.Dispatch<React.SetStateAction<string[]>>;
// string 타입으로 유연하게 처리
newMasterFieldAttributeType: string;
setNewMasterFieldAttributeType: (type: string) => void;
newMasterFieldMultiColumn: boolean;
setNewMasterFieldMultiColumn: (multi: boolean) => void;
newMasterFieldColumnCount: number;
setNewMasterFieldColumnCount: (count: number) => void;
newMasterFieldColumnNames: string[];
setNewMasterFieldColumnNames: (names: string[]) => void;
setNewMasterFieldColumnNames: ((names: string[]) => void) | React.Dispatch<React.SetStateAction<string[]>>;
handleUpdateMasterField: () => void;
handleAddMasterField: () => void;
}
@@ -77,6 +80,13 @@ export function MasterFieldDialog({
}: MasterFieldDialogProps) {
const [isSubmitted, setIsSubmitted] = useState(false);
// 옵션을 문자열로 변환하여 처리
const optionsString = Array.isArray(newMasterFieldOptions) ? newMasterFieldOptions.join(', ') : newMasterFieldOptions;
// setNewMasterFieldOptions 래퍼 - union type 호환성 해결
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleSetNewMasterFieldOptions = (options: string) => (setNewMasterFieldOptions as any)(options);
// 2025-12-01: masterFieldService 사용으로 유효성 검사 중앙화
const nameValidation = masterFieldService.validateFieldName(newMasterFieldName);
const keyValidation = masterFieldService.validateFieldKey(newMasterFieldKey);
@@ -93,7 +103,7 @@ export function MasterFieldDialog({
setNewMasterFieldRequired(false);
setNewMasterFieldCategory('공통');
setNewMasterFieldDescription('');
setNewMasterFieldOptions('');
handleSetNewMasterFieldOptions('');
setNewMasterFieldAttributeType('custom');
setNewMasterFieldMultiColumn(false);
setNewMasterFieldColumnCount(2);
@@ -267,8 +277,8 @@ export function MasterFieldDialog({
)}
</div>
<Textarea
value={newMasterFieldOptions}
onChange={(e) => setNewMasterFieldOptions(e.target.value)}
value={optionsString}
onChange={(e) => handleSetNewMasterFieldOptions(e.target.value)}
placeholder="제품,부품,원자재 (쉼표로 구분)"
disabled={newMasterFieldAttributeType !== 'custom'}
className="min-h-[80px]"