diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-12 11:36:25 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-12 11:36:25 +0000 |
| commit | a6b9cdaf9ea5ed548292632f821e36453f377a83 (patch) | |
| tree | 1c07b92b4173bfe3a12eedba7188fba8dc6f94cb /lib/procurement-rfqs/table/rfq-table-column.tsx | |
| parent | df91418cd28e98ce05845e476e51aa810202bf33 (diff) | |
(대표님) procurement-rfq 작업업
Diffstat (limited to 'lib/procurement-rfqs/table/rfq-table-column.tsx')
| -rw-r--r-- | lib/procurement-rfqs/table/rfq-table-column.tsx | 373 |
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 |
