summaryrefslogtreecommitdiff
path: root/lib/tbe-last/vendor/vendor-pr-items-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tbe-last/vendor/vendor-pr-items-dialog.tsx')
-rw-r--r--lib/tbe-last/vendor/vendor-pr-items-dialog.tsx253
1 files changed, 253 insertions, 0 deletions
diff --git a/lib/tbe-last/vendor/vendor-pr-items-dialog.tsx b/lib/tbe-last/vendor/vendor-pr-items-dialog.tsx
new file mode 100644
index 00000000..e4b03e6d
--- /dev/null
+++ b/lib/tbe-last/vendor/vendor-pr-items-dialog.tsx
@@ -0,0 +1,253 @@
+// lib/vendor-rfq-response/vendor-tbe-table/vendor-pr-items-dialog.tsx
+
+"use client"
+
+import * as React from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogDescription
+} from "@/components/ui/dialog"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { formatDate } from "@/lib/utils"
+import { Download, Package, AlertCircle } from "lucide-react"
+import { toast } from "sonner"
+import { exportDataToExcel } from "@/lib/export-to-excel"
+import { getVendorPrItems } from "../vendor-tbe-service"
+
+interface VendorPrItemsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ rfqId: number | null
+}
+
+interface PrItem {
+ id: number
+ prNo: string
+ prItem: string
+ materialCode: string
+ materialDescription: string
+ size?: string
+ quantity: number
+ uom: string
+ deliveryDate?: string
+ majorYn: boolean
+ specifications?: string
+ remarks?: string
+}
+
+export function VendorPrItemsDialog({
+ open,
+ onOpenChange,
+ rfqId
+}: VendorPrItemsDialogProps) {
+
+ const [prItems, setPrItems] = React.useState<PrItem[]>([])
+ const [isLoading, setIsLoading] = React.useState(false)
+
+ // Load PR items when dialog opens
+ React.useEffect(() => {
+ if (open && rfqId) {
+ loadPrItems()
+ }
+ }, [open, rfqId])
+
+ const loadPrItems = async () => {
+ if (!rfqId) return
+
+ setIsLoading(true)
+ try {
+ const data = await getVendorPrItems(rfqId)
+
+ setPrItems(data)
+
+ } catch (error) {
+ console.error("Failed to load PR items:", error)
+ toast.error("Error loading PR items")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ // Export to Excel
+ const handleExport = async () => {
+ if (prItems.length === 0) {
+ toast.error("No items to export")
+ return
+ }
+
+ try {
+ // Prepare data for export
+ const exportData = prItems.map(item => ({
+ "PR No": item.prNo || "-",
+ "PR Item": item.prItem || "-",
+ "Material Code": item.materialCode || "-",
+ "Description": item.materialDescription || "-",
+ "Size": item.size || "-",
+ "Quantity": item.quantity,
+ "Unit": item.uom || "-",
+ "Delivery Date": item.deliveryDate ? formatDate(item.deliveryDate, "KR") : "-",
+ "Major Item": item.majorYn ? "Yes" : "No",
+ "Specifications": item.specifications || "-",
+ "Remarks": item.remarks || "-"
+ }))
+
+ // Export using new utility
+ await exportDataToExcel(exportData, {
+ filename: `pr-items-${rfqId}`,
+ sheetName: "PR Items",
+ autoFilter: true,
+ freezeHeader: true
+ })
+
+ toast.success("Excel file exported successfully")
+ } catch (error) {
+ console.error("Export error:", error)
+ toast.error("Failed to export Excel file")
+ }
+ }
+
+ // Statistics
+ const statistics = React.useMemo(() => {
+ const totalItems = prItems.length
+ const majorItems = prItems.filter(item => item.majorYn).length
+ const minorItems = totalItems - majorItems
+
+ return { totalItems, majorItems, minorItems }
+ }, [prItems])
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-6xl max-h-[80vh]">
+ <DialogHeader>
+ <div className="flex items-center justify-between">
+ <div>
+ <DialogTitle>Purchase Request Items</DialogTitle>
+ <DialogDescription>
+ RFQ에 포함된 구매 요청 아이템 목록
+ </DialogDescription>
+ </div>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleExport}
+ disabled={prItems.length === 0}
+ >
+ <Download className="h-4 w-4 mr-2" />
+ Export
+ </Button>
+ </div>
+ </DialogHeader>
+
+ {/* Statistics */}
+ <div className="flex items-center gap-4 py-2">
+ <Badge variant="outline" className="flex items-center gap-1">
+ <Package className="h-3 w-3" />
+ Total: {statistics.totalItems}
+ </Badge>
+ <Badge variant="default" className="flex items-center gap-1">
+ <AlertCircle className="h-3 w-3" />
+ Major: {statistics.majorItems}
+ </Badge>
+ <Badge variant="secondary">
+ Minor: {statistics.minorItems}
+ </Badge>
+ </div>
+
+ {/* PR Items Table */}
+ {isLoading ? (
+ <div className="p-8 text-center">Loading PR items...</div>
+ ) : prItems.length === 0 ? (
+ <div className="p-8 text-center text-muted-foreground">
+ No PR items available
+ </div>
+ ) : (
+ <ScrollArea className="h-[400px]">
+ <Table>
+ <TableHeader>
+ <TableRow>
+ <TableHead className="w-[100px]">PR No</TableHead>
+ <TableHead className="w-[80px]">Item</TableHead>
+ <TableHead className="w-[120px]">Material Code</TableHead>
+ <TableHead>Description</TableHead>
+ <TableHead className="w-[80px]">Size</TableHead>
+ <TableHead className="w-[80px] text-right">Qty</TableHead>
+ <TableHead className="w-[60px]">Unit</TableHead>
+ <TableHead className="w-[100px]">Delivery</TableHead>
+ <TableHead className="w-[80px] text-center">Major</TableHead>
+ </TableRow>
+ </TableHeader>
+ <TableBody>
+ {prItems.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell className="font-medium">{item.prNo || "-"}</TableCell>
+ <TableCell>{item.prItem || "-"}</TableCell>
+ <TableCell>
+ <span className="font-mono text-xs">{item.materialCode || "-"}</span>
+ </TableCell>
+ <TableCell>
+ <div>
+ <p className="text-sm">{item.materialDescription || "-"}</p>
+ {item.remarks && (
+ <p className="text-xs text-muted-foreground mt-1">
+ {item.remarks}
+ </p>
+ )}
+ </div>
+ </TableCell>
+ <TableCell>{item.size || "-"}</TableCell>
+ <TableCell className="text-right font-medium">
+ {item.quantity.toLocaleString()}
+ </TableCell>
+ <TableCell>{item.uom || "-"}</TableCell>
+ <TableCell>
+ {item.deliveryDate ? (
+ <span className="text-sm">
+ {formatDate(item.deliveryDate, "KR")}
+ </span>
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ )}
+ </TableCell>
+ <TableCell className="text-center">
+ {item.majorYn ? (
+ <Badge variant="default" className="text-xs">
+ Major
+ </Badge>
+ ) : (
+ <Badge variant="outline" className="text-xs">
+ Minor
+ </Badge>
+ )}
+ </TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </ScrollArea>
+ )}
+
+ {/* Footer Note */}
+ <div className="mt-4 p-3 bg-muted/50 rounded-lg">
+ <p className="text-xs text-muted-foreground">
+ <strong>Note:</strong> Major items은 기술 평가의 주요 대상이며,
+ 모든 기술 요구사항을 충족해야 합니다.
+ 각 아이템의 세부 사양은 RFQ 문서를 참조해주세요.
+ </p>
+ </div>
+ </DialogContent>
+ </Dialog>
+ )
+} \ No newline at end of file