refactor: IntegratedDetailTemplate 마이그레이션 (수주/견적)

- order-management-sales/[id]/page.tsx: PageLayout → IntegratedDetailTemplate (view)
- order-management-sales/[id]/edit/page.tsx: PageLayout → IntegratedDetailTemplate (edit)
- EstimateDetailForm.tsx: PageLayout → IntegratedDetailTemplate (view/edit)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-20 16:47:33 +09:00
parent 29c257c9f8
commit 09b2c256fb
3 changed files with 205 additions and 198 deletions

View File

@@ -2,7 +2,7 @@
import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { FileText, Loader2, List } from 'lucide-react';
import { Loader2 } from 'lucide-react';
import { getExpenseItemOptions, updateEstimate, type ExpenseItemOption } from './actions';
import { createBiddingFromEstimate } from '../bidding/actions';
import { useAuth } from '@/contexts/AuthContext';
@@ -17,8 +17,8 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { PageLayout } from '@/components/organisms/PageLayout';
import { PageHeader } from '@/components/organisms/PageHeader';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
import { estimateConfig } from './estimateConfig';
import { toast } from 'sonner';
import type {
EstimateDetail,
@@ -106,9 +106,6 @@ export default function EstimateDetailForm({
controller: number;
} | null>(null);
// 조정단가 적용 여부 (전체 적용 버튼 클릭 시에만 true)
const useAdjustedPrice = appliedPrices !== null;
// ===== 네비게이션 핸들러 =====
const handleBack = useCallback(() => {
router.push('/ko/construction/project/bidding/estimates');
@@ -118,10 +115,6 @@ export default function EstimateDetailForm({
router.push(`/ko/construction/project/bidding/estimates/${estimateId}/edit`);
}, [router, estimateId]);
const handleCancel = useCallback(() => {
router.push(`/ko/construction/project/bidding/estimates/${estimateId}`);
}, [router, estimateId]);
// ===== 저장/삭제 핸들러 =====
const handleSave = useCallback(() => {
setShowSaveDialog(true);
@@ -622,17 +615,8 @@ export default function EstimateDetailForm({
[isViewMode]
);
// ===== 타이틀 및 설명 =====
const pageTitle = useMemo(() => {
return isEditMode ? '견적 수정' : '견적 상세';
}, [isEditMode]);
const pageDescription = useMemo(() => {
return isEditMode ? '견적 정보를 수정합니다' : '견적 정보를 등록하고 관리합니다';
}, [isEditMode]);
// ===== 헤더 버튼 =====
const headerActions = useMemo(() => {
const renderHeaderActions = useCallback(() => {
if (isViewMode) {
return (
<div className="flex gap-2">
@@ -645,18 +629,11 @@ export default function EstimateDetailForm({
<Button variant="outline" onClick={handleRegisterBidding} className="text-green-600 border-green-200 hover:bg-green-50">
</Button>
<Button onClick={handleEdit} className="bg-blue-500 hover:bg-blue-600">
</Button>
</div>
);
}
return (
<div className="flex gap-2">
<Button variant="outline" onClick={handleBack}>
<List className="h-4 w-4 mr-2" />
</Button>
<Button
variant="outline"
className="text-red-500 border-red-200 hover:bg-red-50"
@@ -670,18 +647,11 @@ export default function EstimateDetailForm({
</Button>
</div>
);
}, [isViewMode, isLoading, handleBack, handleEdit, handleDelete, handleSave, handleRegisterBidding]);
return (
<PageLayout>
<PageHeader
title={pageTitle}
description={pageDescription}
icon={FileText}
actions={headerActions}
onBack={handleBack}
/>
}, [isViewMode, isLoading, handleDelete, handleSave, handleRegisterBidding]);
// ===== 컨텐츠 렌더링 =====
const renderContent = useCallback(() => {
return (
<div className="space-y-8">
{/* 견적 정보 + 현장설명회 + 입찰 정보 */}
<EstimateInfoSection
@@ -746,6 +716,69 @@ export default function EstimateDetailForm({
onReset={handleDetailReset}
/>
</div>
);
}, [
formData,
isViewMode,
isDragging,
documentInputRef,
expenseOptions,
appliedPrices,
handleBidInfoChange,
handleDocumentUpload,
handleDocumentRemove,
handleDragOver,
handleDragLeave,
handleDrop,
handleAddSummaryItem,
handleRemoveSummaryItem,
handleSummaryItemChange,
handleSummaryMemoChange,
handleAddExpenseItems,
handleRemoveSelectedExpenseItems,
handleExpenseItemChange,
handleExpenseSelectItem,
handleExpenseSelectAll,
handlePriceAdjustmentChange,
handlePriceAdjustmentSave,
handlePriceAdjustmentApplyAll,
handlePriceAdjustmentReset,
handleAddDetailItems,
handleRemoveDetailItem,
handleRemoveSelectedDetailItems,
handleDetailItemChange,
handleDetailSelectItem,
handleDetailSelectAll,
handleApplyAdjustedPriceToSelected,
handleDetailReset,
]);
// Edit 모드용 config (타이틀 변경)
const currentConfig = useMemo(() => {
if (isEditMode) {
return {
...estimateConfig,
title: '견적 수정',
description: '견적 정보를 수정합니다',
};
}
return estimateConfig;
}, [isEditMode]);
return (
<>
<IntegratedDetailTemplate
config={currentConfig}
mode={mode}
initialData={formData}
itemId={estimateId}
isLoading={false}
onBack={handleBack}
onEdit={handleEdit}
renderView={renderContent}
renderForm={renderContent}
headerActions={renderHeaderActions()}
/>
{/* 전자결재 모달 */}
<ElectronicApprovalModal
@@ -839,6 +872,6 @@ export default function EstimateDetailForm({
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</PageLayout>
</>
);
}