Files
sam-react-prod/src/components/quotes/QuoteFooterBar.tsx
권혁성 a486977b80 feat(WEB): 발주처 검색 모달 추가 및 견적 할인 기능 개선
- SupplierSearchModal: 매입 가능 거래처 검색 모달 신규 생성
- QuoteRegistrationV2: 할인율/할인금액을 formData로 통합하여 저장/로드 연동
- QuoteFooterBar: view 모드에서 할인 버튼 비활성화
- types.ts: discountRate/discountAmount 필드 추가, 할인 반영 총액 계산 수정
- quote-management page: 저장 실패 시 에러 메시지 정확히 표시하도록 throw 방식 변경
2026-01-30 11:23:35 +09:00

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>
);
}