summaryrefslogtreecommitdiff
path: root/lib/rfq-last/vendor-response/editor/quotation-items-table.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rfq-last/vendor-response/editor/quotation-items-table.tsx')
-rw-r--r--lib/rfq-last/vendor-response/editor/quotation-items-table.tsx174
1 files changed, 161 insertions, 13 deletions
diff --git a/lib/rfq-last/vendor-response/editor/quotation-items-table.tsx b/lib/rfq-last/vendor-response/editor/quotation-items-table.tsx
index 08928b4d..d98376c1 100644
--- a/lib/rfq-last/vendor-response/editor/quotation-items-table.tsx
+++ b/lib/rfq-last/vendor-response/editor/quotation-items-table.tsx
@@ -14,14 +14,26 @@ import { Label } from "@/components/ui/label"
import { CalendarIcon, Eye, Calculator, AlertCircle } from "lucide-react"
import { format } from "date-fns"
import { cn, formatCurrency } from "@/lib/utils"
-import { useState } from "react"
+import { useState, useEffect } from "react"
import {
Dialog,
DialogContent,
DialogDescription,
+ DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from "@/components/ui/alert-dialog"
interface QuotationItemsTableProps {
prItems: any[]
@@ -36,10 +48,30 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
const [selectedItem, setSelectedItem] = useState<any>(null)
const [showDetail, setShowDetail] = useState(false)
-
+ const [showBulkDateDialog, setShowBulkDateDialog] = useState(false)
+ const [bulkDeliveryDate, setBulkDeliveryDate] = useState<Date | undefined>(undefined)
+
const currency = watch("vendorCurrency") || "USD"
const quotationItems = watch("quotationItems")
+ // PR 아이템 정보를 quotationItems에 초기화
+ useEffect(() => {
+ if (prItems && prItems.length > 0) {
+ prItems.forEach((prItem, index) => {
+ // PR 아이템 정보를 quotationItem에 포함
+ setValue(`quotationItems.${index}.prNo`, prItem.prNo)
+ setValue(`quotationItems.${index}.materialCode`, prItem.materialCode)
+ setValue(`quotationItems.${index}.materialDescription`, prItem.materialDescription)
+ setValue(`quotationItems.${index}.quantity`, prItem.quantity)
+ setValue(`quotationItems.${index}.uom`, prItem.uom)
+ setValue(`quotationItems.${index}.rfqPrItemId`, prItem.id)
+
+ // currency는 vendorCurrency를 따름
+ setValue(`quotationItems.${index}.currency`, currency)
+ })
+ }
+ }, [prItems, setValue, currency])
+
// 단가 * 수량 계산
const calculateTotal = (index: number) => {
const item = quotationItems[index]
@@ -47,6 +79,13 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
if (item && prItem) {
const total = (item.unitPrice || 0) * (prItem.quantity || 0)
setValue(`quotationItems.${index}.totalPrice`, total)
+
+ // PR 아이템 정보도 함께 업데이트 (값이 변경되었을 수 있음)
+ setValue(`quotationItems.${index}.prNo`, prItem.prNo)
+ setValue(`quotationItems.${index}.materialCode`, prItem.materialCode)
+ setValue(`quotationItems.${index}.materialDescription`, prItem.materialDescription)
+ setValue(`quotationItems.${index}.quantity`, prItem.quantity)
+ setValue(`quotationItems.${index}.uom`, prItem.uom)
}
}
@@ -59,8 +98,27 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
const discountAmount = originalTotal * (item.discountRate / 100)
const finalTotal = originalTotal - discountAmount
setValue(`quotationItems.${index}.totalPrice`, finalTotal)
+ setValue(`quotationItems.${index}.discountAmount`, discountAmount)
+ }
+ }
+
+ // 일괄 납기일 적용
+ const applyBulkDeliveryDate = () => {
+ if (bulkDeliveryDate && fields.length > 0) {
+ fields.forEach((_, index) => {
+ setValue(`quotationItems.${index}.vendorDeliveryDate`, bulkDeliveryDate)
+ })
+ setShowBulkDateDialog(false)
+ setBulkDeliveryDate(undefined)
}
}
+
+ // 납기일 초기화
+ const clearAllDeliveryDates = () => {
+ fields.forEach((_, index) => {
+ setValue(`quotationItems.${index}.vendorDeliveryDate`, undefined)
+ })
+ }
const totalAmount = quotationItems?.reduce(
(sum: number, item: any) => sum + (item.totalPrice || 0), 0
@@ -118,7 +176,7 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
</Card>
{/* 제조사 정보 */}
- <Card>
+ {/* <Card>
<CardHeader className="pb-3">
<CardTitle className="text-base">제조사 정보</CardTitle>
</CardHeader>
@@ -150,7 +208,7 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
/>
</div>
</CardContent>
- </Card>
+ </Card> */}
{/* 기술 준수 및 대안 */}
<Card>
@@ -198,7 +256,7 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
</Card>
{/* 할인 정보 */}
- <Card>
+ {/* <Card>
<CardHeader className="pb-3">
<CardTitle className="text-base">할인 정보</CardTitle>
</CardHeader>
@@ -231,7 +289,7 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
</div>
</div>
</CardContent>
- </Card>
+ </Card> */}
{/* 비고 */}
<Card>
@@ -261,11 +319,32 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
각 PR 아이템에 대한 견적 단가와 정보를 입력하세요
</CardDescription>
</div>
- <div className="text-right">
- <p className="text-sm text-muted-foreground">총 견적금액</p>
- <p className="text-2xl font-bold text-primary">
- {formatCurrency(totalAmount, currency)}
- </p>
+ <div className="flex items-center gap-2">
+ <div className="flex gap-2">
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ onClick={() => setShowBulkDateDialog(true)}
+ >
+ <CalendarIcon className="h-4 w-4 mr-1" />
+ 전체 납기일 설정
+ </Button>
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ onClick={clearAllDeliveryDates}
+ >
+ 납기일 초기화
+ </Button>
+ </div>
+ <div className="text-right">
+ <p className="text-sm text-muted-foreground">총 견적금액</p>
+ <p className="text-2xl font-bold text-primary">
+ {formatCurrency(totalAmount, currency)}
+ </p>
+ </div>
</div>
</div>
</CardHeader>
@@ -329,10 +408,12 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
<div className="flex items-center gap-1">
<Input
type="number"
+ min="0"
step="0.01"
{...register(`quotationItems.${index}.unitPrice`, { valueAsNumber: true })}
onChange={(e) => {
- setValue(`quotationItems.${index}.unitPrice`, parseFloat(e.target.value))
+ const value = Math.max(0, parseFloat(e.target.value) || 0)
+ setValue(`quotationItems.${index}.unitPrice`, value)
calculateTotal(index)
}}
className="w-[120px]"
@@ -438,12 +519,79 @@ export default function QuotationItemsTable({ prItems }: QuotationItemsTableProp
{/* 상세 다이얼로그 */}
{selectedItem && (
- <ItemDetailDialog
+ <ItemDetailDialog
item={selectedItem.item}
prItem={selectedItem.prItem}
index={selectedItem.index}
/>
)}
+
+ {/* 일괄 납기일 설정 다이얼로그 */}
+ <Dialog open={showBulkDateDialog} onOpenChange={setShowBulkDateDialog}>
+ <DialogContent className="sm:max-w-md">
+ <DialogHeader>
+ <DialogTitle>전체 납기일 설정</DialogTitle>
+ <DialogDescription>
+ 모든 PR 아이템에 동일한 납기일을 적용합니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ <div className="space-y-4">
+ <div className="space-y-2">
+ <Label>납기일 선택</Label>
+ <Popover>
+ <PopoverTrigger asChild>
+ <Button
+ variant="outline"
+ className={cn(
+ "w-full justify-start text-left font-normal",
+ !bulkDeliveryDate && "text-muted-foreground"
+ )}
+ >
+ <CalendarIcon className="mr-2 h-4 w-4" />
+ {bulkDeliveryDate ? format(bulkDeliveryDate, "yyyy-MM-dd") : "날짜 선택"}
+ </Button>
+ </PopoverTrigger>
+ <PopoverContent className="w-auto p-0" align="start">
+ <Calendar
+ mode="single"
+ selected={bulkDeliveryDate}
+ onSelect={setBulkDeliveryDate}
+ initialFocus
+ />
+ </PopoverContent>
+ </Popover>
+ </div>
+
+ <div className="bg-muted/50 rounded-lg p-3">
+ <p className="text-sm text-muted-foreground">
+ 선택된 날짜가 <strong>{fields.length}개</strong>의 모든 PR 아이템에 적용됩니다.
+ 기존에 설정된 납기일은 모두 교체됩니다.
+ </p>
+ </div>
+ </div>
+
+ <DialogFooter>
+ <Button
+ type="button"
+ variant="outline"
+ onClick={() => {
+ setShowBulkDateDialog(false)
+ setBulkDeliveryDate(undefined)
+ }}
+ >
+ 취소
+ </Button>
+ <Button
+ type="button"
+ onClick={applyBulkDeliveryDate}
+ disabled={!bulkDeliveryDate}
+ >
+ 전체 적용
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
</Card>
)
} \ No newline at end of file