summaryrefslogtreecommitdiff
path: root/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/b-rfq/initial/initial-rfq-detail-columns.tsx')
-rw-r--r--lib/b-rfq/initial/initial-rfq-detail-columns.tsx358
1 files changed, 209 insertions, 149 deletions
diff --git a/lib/b-rfq/initial/initial-rfq-detail-columns.tsx b/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
index f7ac0960..02dfd765 100644
--- a/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
+++ b/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
@@ -3,8 +3,9 @@
import * as React from "react"
import { type ColumnDef } from "@tanstack/react-table"
+import { type Row } from "@tanstack/react-table"
import {
- Ellipsis, Building, Calendar, Eye,
+ Ellipsis, Building, Eye, Edit, Trash,
MessageSquare, Settings, CheckCircle2, XCircle
} from "lucide-react"
@@ -14,17 +15,27 @@ import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {
DropdownMenu, DropdownMenuContent, DropdownMenuItem,
- DropdownMenuSeparator, DropdownMenuTrigger
+ DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuShortcut
} from "@/components/ui/dropdown-menu"
import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
+import { InitialRfqDetailView } from "@/db/schema"
+
+
+// RowAction 타입 정의
+export interface DataTableRowAction<TData> {
+ row: Row<TData>
+ type: "update" | "delete"
+}
interface GetInitialRfqDetailColumnsProps {
onSelectDetail?: (detail: any) => void
+ setRowAction?: React.Dispatch<React.SetStateAction<DataTableRowAction<InitialRfqDetailView> | null>>
}
export function getInitialRfqDetailColumns({
- onSelectDetail
-}: GetInitialRfqDetailColumnsProps = {}): ColumnDef<any>[] {
+ onSelectDetail,
+ setRowAction
+}: GetInitialRfqDetailColumnsProps = {}): ColumnDef<InitialRfqDetailView>[] {
return [
/** ───────────── 체크박스 ───────────── */
@@ -56,53 +67,6 @@ export function getInitialRfqDetailColumns({
/** ───────────── RFQ 정보 ───────────── */
{
- accessorKey: "rfqCode",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="RFQ 코드" />
- ),
- cell: ({ row }) => (
- <Button
- variant="link"
- className="p-0 h-auto font-medium text-blue-600 hover:text-blue-800"
- onClick={() => onSelectDetail?.(row.original)}
- >
- {row.getValue("rfqCode") as string}
- </Button>
- ),
- size: 120,
- },
- {
- accessorKey: "rfqStatus",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="RFQ 상태" />
- ),
- cell: ({ row }) => {
- const status = row.getValue("rfqStatus") as string
- const getStatusColor = (status: string) => {
- switch (status) {
- case "DRAFT": return "secondary"
- case "Doc. Received": return "outline"
- case "PIC Assigned": return "default"
- case "Doc. Confirmed": return "default"
- case "Init. RFQ Sent": return "default"
- case "Init. RFQ Answered": return "success"
- case "TBE started": return "warning"
- case "TBE finished": return "warning"
- case "Final RFQ Sent": return "default"
- case "Quotation Received": return "success"
- case "Vendor Selected": return "success"
- default: return "secondary"
- }
- }
- return (
- <Badge variant={getStatusColor(status) as any}>
- {status}
- </Badge>
- )
- },
- size: 140
- },
- {
accessorKey: "initialRfqStatus",
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="초기 RFQ 상태" />
@@ -111,11 +75,10 @@ export function getInitialRfqDetailColumns({
const status = row.getValue("initialRfqStatus") as string
const getInitialStatusColor = (status: string) => {
switch (status) {
- case "PENDING": return "outline"
- case "SENT": return "default"
- case "RESPONDED": return "success"
- case "EXPIRED": return "destructive"
- case "CANCELLED": return "secondary"
+ case "DRAFT": return "outline"
+ case "Init. RFQ Sent": return "default"
+ case "Init. RFQ Answered": return "success"
+ case "S/L Decline": return "destructive"
default: return "secondary"
}
}
@@ -127,6 +90,30 @@ export function getInitialRfqDetailColumns({
},
size: 120
},
+ {
+ accessorKey: "rfqCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 코드" />
+ ),
+ cell: ({ row }) => (
+ <div className="text-sm">
+ {row.getValue("rfqCode") as string}
+ </div>
+ ),
+ size: 120,
+ },
+ {
+ accessorKey: "rfqRevision",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 리비전" />
+ ),
+ cell: ({ row }) => (
+ <div className="text-sm">
+ Rev. {row.getValue("rfqRevision") as number}
+ </div>
+ ),
+ size: 120,
+ },
/** ───────────── 벤더 정보 ───────────── */
{
@@ -137,7 +124,8 @@ export function getInitialRfqDetailColumns({
cell: ({ row }) => {
const vendorName = row.original.vendorName as string
const vendorCode = row.original.vendorCode as string
- const vendorCountry = row.original.vendorCountry as string
+ const vendorType = row.original.vendorCategory as string
+ const vendorCountry = row.original.vendorCountry === "KR" ? "D":"F"
const businessSize = row.original.vendorBusinessSize as string
return (
@@ -147,7 +135,7 @@ export function getInitialRfqDetailColumns({
<div className="font-medium">{vendorName}</div>
</div>
<div className="text-sm text-muted-foreground">
- {vendorCode} • {vendorCountry}
+ {vendorCode} • {vendorType} • {vendorCountry}
</div>
{businessSize && (
<Badge variant="outline" className="text-xs">
@@ -160,42 +148,67 @@ export function getInitialRfqDetailColumns({
size: 200,
},
- /** ───────────── 날짜 정보 ───────────── */
{
- accessorKey: "dueDate",
+ accessorKey: "cpRequestYn",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="마감일" />
+ <DataTableColumnHeaderSimple column={column} title="CP" />
),
cell: ({ row }) => {
- const dueDate = row.getValue("dueDate") as Date
- const isOverdue = dueDate && new Date(dueDate) < new Date()
-
- return dueDate ? (
- <div className={`flex items-center gap-2 ${isOverdue ? 'text-red-600' : ''}`}>
- <Calendar className="h-4 w-4" />
- <div>
- <div className="font-medium">{formatDate(dueDate)}</div>
- {isOverdue && (
- <div className="text-xs text-red-600">지연</div>
- )}
- </div>
- </div>
+ const cpRequest = row.getValue("cpRequestYn") as boolean
+ return cpRequest ? (
+ <Badge variant="outline" className="text-xs">
+ Yes
+ </Badge>
) : (
- <span className="text-muted-foreground">-</span>
+ <span className="text-muted-foreground text-xs">-</span>
)
},
- size: 120,
+ size: 60,
},
{
- accessorKey: "validDate",
+ accessorKey: "prjectGtcYn",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="유효일" />
+ <DataTableColumnHeaderSimple column={column} title="Project GTC" />
),
cell: ({ row }) => {
- const validDate = row.getValue("validDate") as Date
- return validDate ? (
+ const projectGtc = row.getValue("prjectGtcYn") as boolean
+ return projectGtc ? (
+ <Badge variant="outline" className="text-xs">
+ Yes
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground text-xs">-</span>
+ )
+ },
+ size: 100,
+ },
+ {
+ accessorKey: "gtcYn",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="GTC" />
+ ),
+ cell: ({ row }) => {
+ const gtc = row.getValue("gtcYn") as boolean
+ return gtc ? (
+ <Badge variant="outline" className="text-xs">
+ Yes
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground text-xs">-</span>
+ )
+ },
+ size: 60,
+ },
+ {
+ accessorKey: "gtcValidDate",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="GTC 유효일" />
+ ),
+ cell: ({ row }) => {
+ const gtcValidDate = row.getValue("gtcValidDate") as string
+ return gtcValidDate ? (
<div className="text-sm">
- {formatDate(validDate)}
+ {gtcValidDate}
</div>
) : (
<span className="text-muted-foreground">-</span>
@@ -204,7 +217,42 @@ export function getInitialRfqDetailColumns({
size: 100,
},
- /** ───────────── Incoterms ───────────── */
+ {
+ accessorKey: "classification",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="선급" />
+ ),
+ cell: ({ row }) => {
+ const classification = row.getValue("classification") as string
+ return classification ? (
+ <div className="text-sm font-medium max-w-[120px] truncate" title={classification}>
+ {classification}
+ </div>
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ )
+ },
+ size: 120,
+ },
+
+ {
+ accessorKey: "sparepart",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="Spare Part" />
+ ),
+ cell: ({ row }) => {
+ const sparepart = row.getValue("sparepart") as string
+ return sparepart ? (
+ <Badge variant="outline" className="text-xs">
+ {sparepart}
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ )
+ },
+ size: 100,
+ },
+
{
id: "incoterms",
header: ({ column }) => (
@@ -230,84 +278,71 @@ export function getInitialRfqDetailColumns({
size: 120,
},
- /** ───────────── 플래그 정보 ───────────── */
+ /** ───────────── 날짜 정보 ───────────── */
{
- id: "flags",
+ accessorKey: "validDate",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="플래그" />
+ <DataTableColumnHeaderSimple column={column} title="유효일" />
),
cell: ({ row }) => {
- const shortList = row.original.shortList as boolean
- const returnYn = row.original.returnYn as boolean
- const cpRequestYn = row.original.cpRequestYn as boolean
- const prjectGtcYn = row.original.prjectGtcYn as boolean
-
- return (
- <div className="flex flex-wrap gap-1">
- {shortList && (
- <Badge variant="secondary" className="text-xs">
- <CheckCircle2 className="h-3 w-3 mr-1" />
- Short List
- </Badge>
- )}
- {returnYn && (
- <Badge variant="outline" className="text-xs">
- Return
- </Badge>
- )}
- {cpRequestYn && (
- <Badge variant="outline" className="text-xs">
- CP Request
- </Badge>
- )}
- {prjectGtcYn && (
- <Badge variant="outline" className="text-xs">
- GTC
- </Badge>
- )}
+ const validDate = row.getValue("validDate") as Date
+ return validDate ? (
+ <div className="text-sm">
+ {formatDate(validDate)}
</div>
+ ) : (
+ <span className="text-muted-foreground">-</span>
)
},
- size: 150,
+ size: 100,
},
-
- /** ───────────── 분류 정보 ───────────── */
{
- id: "classification",
+ accessorKey: "dueDate",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="분류" />
+ <DataTableColumnHeaderSimple column={column} title="마감일" />
),
cell: ({ row }) => {
- const classification = row.original.classification as string
- const sparepart = row.original.sparepart as string
+ const dueDate = row.getValue("dueDate") as Date
+ const isOverdue = dueDate && new Date(dueDate) < new Date()
- return (
- <div className="space-y-1">
- {classification && (
- <div className="text-sm font-medium max-w-[120px] truncate" title={classification}>
- {classification}
- </div>
- )}
- {sparepart && (
- <Badge variant="outline" className="text-xs">
- {sparepart}
- </Badge>
+ return dueDate ? (
+ <div className={`${isOverdue ? 'text-red-600' : ''}`}>
+ <div className="font-medium">{formatDate(dueDate)}</div>
+ {isOverdue && (
+ <div className="text-xs text-red-600">지연</div>
)}
</div>
+ ) : (
+ <span className="text-muted-foreground">-</span>
)
},
size: 120,
},
-
- /** ───────────── 리비전 정보 ───────────── */
+ {
+ accessorKey: "returnYn",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 회신여부" />
+ ),
+ cell: ({ row }) => {
+ const returnFlag = row.getValue("returnYn") as boolean
+ return returnFlag ? (
+ <Badge variant="outline" className="text-xs">
+ Yes
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground text-xs">-</span>
+ )
+ },
+ size: 70,
+ },
{
accessorKey: "returnRevision",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="리비전" />
+ <DataTableColumnHeaderSimple column={column} title="회신 리비전" />
),
cell: ({ row }) => {
const revision = row.getValue("returnRevision") as number
- return revision ? (
+ return revision > 0 ? (
<Badge variant="outline">
Rev. {revision}
</Badge>
@@ -318,6 +353,25 @@ export function getInitialRfqDetailColumns({
size: 80,
},
+ {
+ accessorKey: "shortList",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="Short List" />
+ ),
+ cell: ({ row }) => {
+ const shortList = row.getValue("shortList") as boolean
+ return shortList ? (
+ <Badge variant="secondary" className="text-xs">
+ <CheckCircle2 className="h-3 w-3 mr-1" />
+ Yes
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground text-xs">-</span>
+ )
+ },
+ size: 90,
+ },
+
/** ───────────── 등록/수정 정보 ───────────── */
{
accessorKey: "createdAt",
@@ -333,7 +387,7 @@ export function getInitialRfqDetailColumns({
<div className="text-sm">{formatDate(created)}</div>
{updated && new Date(updated) > new Date(created) && (
<div className="text-xs text-blue-600">
- 수정: {formatDate(updated)}
+ 수정: {formatDate(updated, "KR")}
</div>
)}
</div>
@@ -346,7 +400,7 @@ export function getInitialRfqDetailColumns({
{
id: "actions",
enableHiding: false,
- cell: ({ row }) => {
+ cell: function Cell({ row }) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -359,23 +413,29 @@ export function getInitialRfqDetailColumns({
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
- <DropdownMenuItem onClick={() => onSelectDetail?.(row.original)}>
- <Eye className="mr-2 h-4 w-4" />
- 상세 보기
- </DropdownMenuItem>
<DropdownMenuItem>
<MessageSquare className="mr-2 h-4 w-4" />
벤더 응답 보기
</DropdownMenuItem>
<DropdownMenuSeparator />
- <DropdownMenuItem>
- <Settings className="mr-2 h-4 w-4" />
- 설정 수정
- </DropdownMenuItem>
- <DropdownMenuItem className="text-red-600">
- <XCircle className="mr-2 h-4 w-4" />
- 삭제
- </DropdownMenuItem>
+ {setRowAction && (
+ <>
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "update" })}
+ >
+ <Edit className="mr-2 h-4 w-4" />
+ 수정
+ </DropdownMenuItem>
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "delete" })}
+ >
+ <Trash className="mr-2 h-4 w-4" />
+ 삭제
+ <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
+ </DropdownMenuItem>
+ </>
+ )}
+
</DropdownMenuContent>
</DropdownMenu>
)