summaryrefslogtreecommitdiff
path: root/lib/procurement-rfqs/table/rfq-table-column.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/procurement-rfqs/table/rfq-table-column.tsx')
-rw-r--r--lib/procurement-rfqs/table/rfq-table-column.tsx373
1 files changed, 373 insertions, 0 deletions
diff --git a/lib/procurement-rfqs/table/rfq-table-column.tsx b/lib/procurement-rfqs/table/rfq-table-column.tsx
new file mode 100644
index 00000000..3cf06315
--- /dev/null
+++ b/lib/procurement-rfqs/table/rfq-table-column.tsx
@@ -0,0 +1,373 @@
+"use client"
+
+import * as React from "react"
+import { ColumnDef } from "@tanstack/react-table"
+import { formatDate, formatDateTime } from "@/lib/utils"
+import { Checkbox } from "@/components/ui/checkbox"
+import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
+import { DataTableRowAction } from "@/types/table"
+import { ProcurementRfqsView } from "@/db/schema"
+import { Check, Pencil, X } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import { toast } from "sonner"
+import { Input } from "@/components/ui/input"
+import { updateRfqRemark } from "../services"
+
+interface GetColumnsProps {
+ setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<ProcurementRfqsView> | null>>;
+ // 상태와 상태 설정 함수를 props로 받음
+ editingCell: EditingCellState | null;
+ setEditingCell: (state: EditingCellState | null) => void;
+ updateRemark: (rfqId: number, remark: string) => Promise<void>;
+}
+
+export interface EditingCellState {
+ rowId: string | number;
+ value: string;
+}
+
+
+export function getColumns({
+ setRowAction,
+ editingCell,
+ setEditingCell,
+ updateRemark,
+}: GetColumnsProps): ColumnDef<ProcurementRfqsView>[] {
+
+
+
+ return [
+ {
+ id: "select",
+ // Remove the "Select all" checkbox in header since we're doing single-select
+ header: () => <span className="sr-only">Select</span>,
+ cell: ({ row, table }) => (
+ <Checkbox
+ checked={row.getIsSelected()}
+ onCheckedChange={(value) => {
+ // If selecting this row
+ if (value) {
+ // First deselect all rows (to ensure single selection)
+ table.toggleAllRowsSelected(false)
+ // Then select just this row
+ row.toggleSelected(true)
+ // Trigger the same action that was in the "Select" button
+ setRowAction({ row, type: "select" })
+ } else {
+ // Just deselect this row
+ row.toggleSelected(false)
+ }
+ }}
+ aria-label="Select row"
+ className="translate-y-0.5"
+ />
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ enableResizing: false,
+ size: 40,
+ minSize: 40,
+ maxSize: 40,
+ },
+
+ {
+ accessorKey: "status",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="status" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("status")}</div>,
+ meta: {
+ excelHeader: "status"
+ },
+ enableResizing: true,
+ minSize: 80,
+ size: 100,
+ },
+ {
+ accessorKey: "projectCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="프로젝트" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("projectCode")}</div>,
+ meta: {
+ excelHeader: "프로젝트"
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "series",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="시리즈" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("series")}</div>,
+ meta: {
+ excelHeader: "시리즈"
+ },
+ enableResizing: true,
+ minSize: 80,
+ size: 100,
+ },
+ {
+ accessorKey: "rfqSealedYn",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 밀봉" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("rfqSealedYn") ? "Y":"N"}</div>,
+ meta: {
+ excelHeader: "RFQ 밀봉"
+ },
+ enableResizing: true,
+ minSize: 80,
+ size: 100,
+ },
+ {
+ accessorKey: "rfqCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ NO." />
+ ),
+ cell: ({ row }) => <div>{row.getValue("rfqCode")}</div>,
+ meta: {
+ excelHeader: "RFQ NO."
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "po_no",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="대표 PR NO." />
+ ),
+ cell: ({ row }) => <div>{row.getValue("po_no")}</div>,
+ meta: {
+ excelHeader: "대표 PR NO."
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "itemCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="자재그룹" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("itemCode")}</div>,
+ meta: {
+ excelHeader: "자재그룹"
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "majorItemMaterialCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="자재코드" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("majorItemMaterialCode")}</div>,
+ meta: {
+ excelHeader: "자재코드"
+ },
+ enableResizing: true,
+ minSize: 80,
+ size: 120,
+ },
+ {
+ accessorKey: "itemName",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="자재명" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("itemName")}</div>,
+ meta: {
+ excelHeader: "자재명"
+ },
+ enableResizing: true,
+ size: 140,
+ },
+ {
+ accessorKey: "prItemsCount",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="PR 건수" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("prItemsCount")}</div>,
+ meta: {
+ excelHeader: "PR 건수"
+ },
+ enableResizing: true,
+ // size: 80,
+ },
+ {
+ accessorKey: "rfqSendDate",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 전송일" />
+ ),
+ cell: ({ cell }) => {
+ const value = cell.getValue();
+ return value ? formatDate(value as Date, "KR") : "";
+ },
+ meta: {
+ excelHeader: "RFQ 전송일"
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "earliestQuotationSubmittedAt",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="첫회신 접수일" />
+ ),
+ cell: ({ cell }) => {
+ const value = cell.getValue();
+ return value ? formatDate(value as Date, "KR") : "";
+ },
+ meta: {
+ excelHeader: "첫회신 접수일"
+ },
+ enableResizing: true,
+ // size: 140,
+ },
+ {
+ accessorKey: "dueDate",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 마감일" />
+ ),
+ cell: ({ cell }) => {
+ const value = cell.getValue();
+ return value ? formatDate(value as Date, "KR") : "";
+ },
+ meta: {
+ excelHeader: "RFQ 마감일"
+ },
+ enableResizing: true,
+ minSize: 80,
+ size: 120,
+ },
+ {
+ accessorKey: "sentByUserName",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 요청자" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("sentByUserName")}</div>,
+ meta: {
+ excelHeader: "RFQ 요청자"
+ },
+ enableResizing: true,
+ size: 120,
+ },
+ {
+ accessorKey: "updatedAt",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="Updated At" />
+ ),
+ cell: ({ cell }) => formatDateTime(cell.getValue() as Date, "KR"),
+ meta: {
+ excelHeader: "updated At"
+ },
+ enableResizing: true,
+ size: 140,
+ },
+
+ {
+ accessorKey: "remark",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="비고" />
+ ),
+ cell: ({ row }) => {
+ const rowId = row.id
+ const value = row.getValue("remark") as string
+ const isEditing = editingCell && editingCell.rowId === rowId
+
+ const startEditing = () => {
+ setEditingCell({
+ rowId,
+ value: value || ""
+ })
+ }
+
+ const cancelEditing = () => {
+ setEditingCell(null)
+ }
+
+ const saveChanges = async () => {
+ if (!editingCell) return
+
+ try {
+
+ // 컴포넌트에서 전달받은 업데이트 함수 사용
+ await updateRemark(row.original.id, editingCell.value)
+ row.original.remark = editingCell.value;
+
+ // 편집 모드 종료
+ setEditingCell(null)
+ } catch (error) {
+ console.error("비고 업데이트 오류:", error)
+ }
+ }
+
+ // 키보드 이벤트 처리
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter") {
+ saveChanges()
+ } else if (e.key === "Escape") {
+ cancelEditing()
+ }
+ }
+
+ if (isEditing) {
+ return (
+ <div className="flex items-center space-x-1">
+ <Input
+ value={editingCell.value}
+ onChange={(e) => setEditingCell({
+ ...editingCell,
+ value: e.target.value
+ })}
+ onKeyDown={handleKeyDown}
+ autoFocus
+ className="h-8 w-full"
+ />
+ <div className="flex items-center">
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={saveChanges}
+ className="h-7 w-7"
+ >
+ <Check className="h-4 w-4 text-green-500" />
+ </Button>
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={cancelEditing}
+ className="h-7 w-7"
+ >
+ <X className="h-4 w-4 text-red-500" />
+ </Button>
+ </div>
+ </div>
+ )
+ }
+
+ return (
+ <div
+ className="flex items-center justify-between group"
+ onDoubleClick={startEditing} // 더블클릭 이벤트 추가
+ >
+ <div className="truncate">{value || "-"}</div>
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={startEditing}
+ className="h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity"
+ >
+ <Pencil className="h-3.5 w-3.5 text-muted-foreground" />
+ </Button>
+ </div>
+ )
+ },
+ meta: {
+ excelHeader: "비고"
+ },
+ enableResizing: true,
+ size: 200,
+ }
+ ]
+} \ No newline at end of file