Files
sam-react-prod/src/components/quotes/QuoteFooterBar.tsx
권혁성 05fd5b32f2 feat: 견적 V2 품목 검색 API 연동 및 수동 품목 관리 개선
- ItemSearchModal: API 프록시 라우트 연동, 검색 유효성 검사 (영문/한글 1자 이상)
- items.ts: HttpOnly 쿠키 인증을 위한 프록시 라우트 사용
- LocationDetailPanel: 수동 품목 추가 시 subtotals/grouped_items 동시 업데이트
- QuoteRegistrationV2: 견적 산출 시 수동 추가 품목(is_manual) 보존
- 상세별 합계에서 수동 추가 품목이 카테고리별로 표시되도록 개선
2026-01-27 14:28:17 +09:00

172 lines
5.1 KiB
TypeScript

/**
* 견적 푸터 바
*
* - 예상 전체 견적금액 표시
* - 버튼: 견적서 산출, 임시저장, 최종저장
* - 뒤로가기 버튼
*/
"use client";
import { Download, Save, Check, ArrowLeft, Loader2, Calculator, Eye, Pencil, ClipboardList } from "lucide-react";
import { Button } from "../ui/button";
// =============================================================================
// Props
// =============================================================================
interface QuoteFooterBarProps {
totalLocations: number;
totalAmount: number;
status: "draft" | "temporary" | "final";
onCalculate: () => void;
onPreview: () => void;
onSaveTemporary: () => void;
onSaveFinal: () => void;
onBack: () => void;
onEdit?: () => void;
onOrderRegister?: () => void;
isCalculating?: boolean;
isSaving?: boolean;
disabled?: boolean;
/** view 모드 여부 (view: 수정+최종저장, edit: 임시저장+최종저장) */
isViewMode?: boolean;
}
// =============================================================================
// 컴포넌트
// =============================================================================
export function QuoteFooterBar({
totalLocations,
totalAmount,
status,
onCalculate,
onPreview,
onSaveTemporary,
onSaveFinal,
onBack,
onEdit,
onOrderRegister,
isCalculating = 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">
{/* 견적서 산출 - edit 모드에서만 활성화 */}
{!isViewMode && (
<Button
onClick={onCalculate}
disabled={isCalculating || totalLocations === 0}
className="bg-indigo-600 hover:bg-indigo-700 text-white gap-2 px-6"
>
{isCalculating ? (
<>
<Loader2 className="h-4 w-4 animate-spin" />
...
</>
) : (
<>
<Calculator className="h-4 w-4" />
</>
)}
</Button>
)}
{/* 미리보기 */}
<Button
onClick={onPreview}
disabled={totalLocations === 0}
variant="outline"
className="gap-2 px-6"
>
<Eye 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>
)}
{/* 임시저장 - edit 모드에서만 표시 */}
{!isViewMode && (
<Button
onClick={onSaveTemporary}
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={onSaveFinal}
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>
);
}