- SupplierSearchModal: 매입 가능 거래처 검색 모달 신규 생성 - QuoteRegistrationV2: 할인율/할인금액을 formData로 통합하여 저장/로드 연동 - QuoteFooterBar: view 모드에서 할인 버튼 비활성화 - types.ts: discountRate/discountAmount 필드 추가, 할인 반영 총액 계산 수정 - quote-management page: 저장 실패 시 에러 메시지 정확히 표시하도록 throw 방식 변경
202 lines
6.0 KiB
TypeScript
202 lines
6.0 KiB
TypeScript
/**
|
|
* 견적 푸터 바
|
|
*
|
|
* - 예상 전체 견적금액 표시
|
|
* - 버튼: 견적서 보기, 거래명세서 보기, 할인하기, 최종확정
|
|
* - 뒤로가기 버튼
|
|
*/
|
|
|
|
"use client";
|
|
|
|
import { Save, Check, ArrowLeft, Loader2, FileText, Pencil, ClipboardList, Percent, Calculator } from "lucide-react";
|
|
|
|
import { Button } from "../ui/button";
|
|
|
|
// =============================================================================
|
|
// Props
|
|
// =============================================================================
|
|
|
|
interface QuoteFooterBarProps {
|
|
totalLocations: number;
|
|
totalAmount: number;
|
|
status: "draft" | "temporary" | "final";
|
|
/** 견적서 보기 */
|
|
onQuoteView: () => void;
|
|
/** 거래명세서 보기 */
|
|
onTransactionView: () => void;
|
|
/** 저장 (임시저장) */
|
|
onSave: () => void;
|
|
/** 최종확정 */
|
|
onFinalize: () => void;
|
|
/** 뒤로가기 */
|
|
onBack: () => void;
|
|
/** 수정 */
|
|
onEdit?: () => void;
|
|
/** 수주등록 */
|
|
onOrderRegister?: () => void;
|
|
/** 할인하기 */
|
|
onDiscount?: () => void;
|
|
/** 수식보기 */
|
|
onFormulaView?: () => void;
|
|
/** BOM 결과 유무 */
|
|
hasBomResult?: boolean;
|
|
isSaving?: boolean;
|
|
disabled?: boolean;
|
|
/** view 모드 여부 (view: 수정+최종확정, edit: 저장+최종확정) */
|
|
isViewMode?: boolean;
|
|
}
|
|
|
|
// =============================================================================
|
|
// 컴포넌트
|
|
// =============================================================================
|
|
|
|
export function QuoteFooterBar({
|
|
totalLocations,
|
|
totalAmount,
|
|
status,
|
|
onQuoteView,
|
|
onTransactionView,
|
|
onSave,
|
|
onFinalize,
|
|
onBack,
|
|
onEdit,
|
|
onOrderRegister,
|
|
onDiscount,
|
|
onFormulaView,
|
|
hasBomResult = false,
|
|
isSaving = false,
|
|
disabled = false,
|
|
isViewMode = false,
|
|
}: QuoteFooterBarProps) {
|
|
return (
|
|
<div className="sticky bottom-0 bg-gradient-to-r from-blue-50 to-indigo-50 border-t border-blue-200 shadow-lg">
|
|
<div className="px-6 py-4 flex items-center justify-between">
|
|
{/* 왼쪽: 뒤로가기 + 금액 표시 */}
|
|
<div className="flex items-center gap-6">
|
|
<Button
|
|
variant="outline"
|
|
onClick={onBack}
|
|
className="gap-2"
|
|
>
|
|
<ArrowLeft className="h-4 w-4" />
|
|
목록으로
|
|
</Button>
|
|
|
|
<div>
|
|
<p className="text-sm text-gray-600">예상 전체 견적금액</p>
|
|
<p className="text-3xl font-bold text-blue-600">
|
|
{totalAmount.toLocaleString()}
|
|
<span className="text-lg font-normal text-gray-500 ml-1">원</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 오른쪽: 버튼들 */}
|
|
<div className="flex items-center gap-3">
|
|
{/* 견적서 보기 */}
|
|
<Button
|
|
onClick={onQuoteView}
|
|
disabled={totalLocations === 0}
|
|
variant="outline"
|
|
className="gap-2 px-6"
|
|
>
|
|
<FileText className="h-4 w-4" />
|
|
견적서 보기
|
|
</Button>
|
|
|
|
{/* 거래명세서 보기 */}
|
|
<Button
|
|
onClick={onTransactionView}
|
|
disabled={totalLocations === 0}
|
|
variant="outline"
|
|
className="gap-2 px-6"
|
|
>
|
|
<ClipboardList className="h-4 w-4" />
|
|
거래명세서 보기
|
|
</Button>
|
|
|
|
{/* 수식보기 - 개발환경(local/development)에서만 표시 */}
|
|
{onFormulaView && ['local', 'development'].includes(process.env.NEXT_PUBLIC_APP_ENV || '') && (
|
|
<Button
|
|
onClick={onFormulaView}
|
|
disabled={!hasBomResult}
|
|
variant="outline"
|
|
className="gap-2 px-6 border-purple-300 text-purple-600 hover:bg-purple-50"
|
|
>
|
|
<Calculator className="h-4 w-4" />
|
|
수식보기
|
|
</Button>
|
|
)}
|
|
|
|
{/* 수정 - view 모드에서만 표시 */}
|
|
{isViewMode && onEdit && (
|
|
<Button
|
|
onClick={onEdit}
|
|
variant="outline"
|
|
className="gap-2 px-6"
|
|
>
|
|
<Pencil className="h-4 w-4" />
|
|
수정
|
|
</Button>
|
|
)}
|
|
|
|
{/* 할인하기 - view 모드에서는 비활성 */}
|
|
{onDiscount && (
|
|
<Button
|
|
onClick={onDiscount}
|
|
disabled={isViewMode}
|
|
variant="outline"
|
|
className="gap-2 px-6 border-orange-300 text-orange-600 hover:bg-orange-50"
|
|
>
|
|
<Percent className="h-4 w-4" />
|
|
할인하기
|
|
</Button>
|
|
)}
|
|
|
|
{/* 저장 - edit 모드에서만 표시 */}
|
|
{!isViewMode && (
|
|
<Button
|
|
onClick={onSave}
|
|
disabled={isSaving}
|
|
className="bg-slate-500 hover:bg-slate-600 text-white gap-2 px-6"
|
|
>
|
|
{isSaving ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<Save className="h-4 w-4" />
|
|
)}
|
|
저장
|
|
</Button>
|
|
)}
|
|
|
|
{/* 최종확정 - 양쪽 모드에서 표시 (final 상태가 아닐 때만) */}
|
|
{status !== "final" && (
|
|
<Button
|
|
onClick={onFinalize}
|
|
disabled={isSaving || totalAmount === 0}
|
|
className="bg-blue-600 hover:bg-blue-700 text-white gap-2 px-6"
|
|
>
|
|
{isSaving ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<Check className="h-4 w-4" />
|
|
)}
|
|
최종확정
|
|
</Button>
|
|
)}
|
|
|
|
{/* 수주등록 - final 상태일 때 표시 */}
|
|
{status === "final" && onOrderRegister && (
|
|
<Button
|
|
onClick={onOrderRegister}
|
|
className="bg-green-600 hover:bg-green-700 text-white gap-2 px-6"
|
|
>
|
|
<ClipboardList className="h-4 w-4" />
|
|
수주등록
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |