feat(WEB): Phase 2-3 V2 마이그레이션 완료 및 ServerErrorPage 적용

Phase 2 완료 (4개):
- 노무관리, 단가관리(건설), 입금, 출금

Phase 3 라우팅 구조 변경 완료 (22개):
- 거래처(영업), 팝업관리, 공정관리, 게시판관리, 대손추심, Q&A
- 현장관리, 실행내역, 견적관리, 견적(테스트)
- 입찰관리, 이슈관리, 현장설명회, 견적서(건설)
- 협력업체, 시공관리, 기성관리, 품목관리(건설)
- 회계 도메인: 거래처, 매출, 세금계산서, 매입

신규 컴포넌트:
- ErrorCard: 에러 페이지 UI 통일
- ServerErrorPage: V2 페이지 에러 처리 필수
- V2 Client 컴포넌트 및 Config 파일들

총 47개 상세 페이지 중 28개 완료, 19개 제외/불필요

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-19 17:31:28 +09:00
parent 1a6cde2d36
commit 1d7b028693
109 changed files with 6811 additions and 2562 deletions

View File

@@ -135,7 +135,7 @@ export function BadDebtDetail({ mode, recordId, initialData }: BadDebtDetailProp
}, [router]);
const handleEdit = useCallback(() => {
router.push(`/ko/accounting/bad-debt-collection/${recordId}/edit`);
router.push(`/ko/accounting/bad-debt-collection/${recordId}?mode=edit`);
}, [router, recordId]);
const handleCancel = useCallback(() => {

View File

@@ -0,0 +1,135 @@
'use client';
/**
* 대손추심 상세 클라이언트 컴포넌트 V2
*
* 라우팅 구조 변경: /[id], /[id]/edit, /new → /[id]?mode=view|edit, /new
* 기존 BadDebtDetail 컴포넌트 활용
*/
import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { BadDebtDetail } from './BadDebtDetail';
import { getBadDebtById } from './actions';
import type { BadDebtRecord } from './types';
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
import { ErrorCard } from '@/components/ui/error-card';
import { toast } from 'sonner';
type DetailMode = 'view' | 'edit' | 'new';
interface BadDebtDetailClientV2Props {
recordId?: string;
initialMode?: DetailMode;
}
const BASE_PATH = '/ko/accounting/bad-debt-collection';
export function BadDebtDetailClientV2({ recordId, initialMode }: BadDebtDetailClientV2Props) {
const router = useRouter();
const searchParams = useSearchParams();
// URL 쿼리에서 모드 결정
const modeFromQuery = searchParams.get('mode') as DetailMode | null;
const isNewMode = !recordId || recordId === 'new';
const [mode, setMode] = useState<DetailMode>(() => {
if (isNewMode) return 'new';
if (initialMode) return initialMode;
if (modeFromQuery === 'edit') return 'edit';
return 'view';
});
const [recordData, setRecordData] = useState<BadDebtRecord | null>(null);
const [isLoading, setIsLoading] = useState(!isNewMode);
const [error, setError] = useState<string | null>(null);
// 데이터 로드
useEffect(() => {
const loadData = async () => {
if (isNewMode) {
setIsLoading(false);
return;
}
setIsLoading(true);
setError(null);
try {
const result = await getBadDebtById(recordId!);
if (result) {
setRecordData(result);
} else {
setError('악성채권 정보를 찾을 수 없습니다.');
toast.error('악성채권을 불러오는데 실패했습니다.');
}
} catch (err) {
console.error('악성채권 조회 실패:', err);
setError('악성채권 정보를 불러오는 중 오류가 발생했습니다.');
toast.error('악성채권을 불러오는데 실패했습니다.');
} finally {
setIsLoading(false);
}
};
loadData();
}, [recordId, isNewMode]);
// URL 쿼리 변경 감지
useEffect(() => {
if (!isNewMode && modeFromQuery === 'edit') {
setMode('edit');
} else if (!isNewMode && !modeFromQuery) {
setMode('view');
}
}, [modeFromQuery, isNewMode]);
// 로딩 중
if (isLoading) {
return <ContentLoadingSpinner text="악성채권 정보를 불러오는 중..." />;
}
// 에러 발생 (view/edit 모드에서)
if (error && !isNewMode) {
return (
<ErrorCard
type="network"
title="악성채권 정보를 불러올 수 없습니다"
description={error}
tips={[
'해당 악성채권이 존재하는지 확인해주세요',
'인터넷 연결 상태를 확인해주세요',
'잠시 후 다시 시도해주세요',
]}
homeButtonLabel="목록으로 이동"
homeButtonHref={BASE_PATH}
/>
);
}
// 등록 모드
if (mode === 'new') {
return <BadDebtDetail mode="new" />;
}
// 수정 모드
if (mode === 'edit' && recordData) {
return <BadDebtDetail mode="edit" recordId={recordId} initialData={recordData} />;
}
// 상세 보기 모드
if (mode === 'view' && recordData) {
return <BadDebtDetail mode="view" recordId={recordId} initialData={recordData} />;
}
// 데이터 없음 (should not reach here)
return (
<ErrorCard
type="not-found"
title="악성채권을 찾을 수 없습니다"
description="요청하신 악성채권 정보가 존재하지 않습니다."
homeButtonLabel="목록으로 이동"
homeButtonHref={BASE_PATH}
/>
);
}

View File

@@ -1,5 +1,7 @@
'use client';
export { BadDebtDetailClientV2 } from './BadDebtDetailClientV2';
/**
* 악성채권 추심관리 - UniversalListPage 마이그레이션
*
@@ -103,7 +105,7 @@ export function BadDebtCollection({ initialData, initialSummary }: BadDebtCollec
const handleEdit = useCallback(
(item: BadDebtRecord) => {
router.push(`/ko/accounting/bad-debt-collection/${item.id}/edit`);
router.push(`/ko/accounting/bad-debt-collection/${item.id}?mode=edit`);
},
[router]
);