diff options
Diffstat (limited to 'lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx')
| -rw-r--r-- | lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx b/lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx new file mode 100644 index 00000000..2e5ae5dc --- /dev/null +++ b/lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx @@ -0,0 +1,280 @@ +"use client" + +import * as React from "react" +import type { + DataTableAdvancedFilterField, + DataTableFilterField, + DataTableRowAction, +} from "@/types/table" +import { useRouter } from "next/navigation" + +import { useDataTable } from "@/hooks/use-data-table" +import { DataTable } from "@/components/data-table/data-table" +import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar" + +import { useFeatureFlags } from "./feature-flags-provider" +import { getColumns } from "./rfqs-table-columns" +import { RfqWithAll } from "../types" + +import { + fetchRfqAttachments, + fetchRfqAttachmentsbyCommentId, +} from "../../rfqs-tech/service" + +import { RfqsVendorTableToolbarActions } from "./rfqs-table-toolbar-actions" +import { RfqsItemsDialog } from "./ItemsDialog" +import { RfqAttachmentsSheet } from "./attachment-rfq-sheet" +import { CommentSheet } from "./comments-sheet" +import { getRfqResponsesForVendor } from "../service" +import { useSession } from "next-auth/react" // Next-auth session hook 추가 + +interface RfqsTableProps { + promises: Promise<[Awaited<ReturnType<typeof getRfqResponsesForVendor>>]> +} + +// 코멘트+첨부파일 구조 예시 +export interface RfqCommentWithAttachments { + id: number + commentText: string + commentedBy?: number + commentedByEmail?: string + createdAt?: Date + attachments?: { + id: number + fileName: string + filePath: string + }[] +} + +export interface ExistingAttachment { + id: number + fileName: string + filePath: string + createdAt?: Date + vendorId?: number | null + size?: number +} + +export interface ExistingItem { + id?: number + itemCode: string + description: string | null + quantity: number | null + uom: string | null +} + +export function RfqsVendorTable({ promises }: RfqsTableProps) { + const { featureFlags } = useFeatureFlags() + const { data: session } = useSession() // 세션 정보 가져오기 + + // 1) 테이블 데이터( RFQs ) + const [{ data: responseData, pageCount }] = React.use(promises) + + // 데이터를 RfqWithAll 타입으로 변환 (id 필드 추가) + const data: RfqWithAll[] = React.useMemo(() => { + return responseData.map(item => ({ + ...item, + id: item.rfqId, // id 필드를 rfqId와 동일하게 설정 + })); + }, [responseData]); + + const router = useRouter() + + // 2) 첨부파일 시트 + 관련 상태 + const [attachmentsOpen, setAttachmentsOpen] = React.useState(false) + const [selectedRfqIdForAttachments, setSelectedRfqIdForAttachments] = React.useState<number | null>(null) + const [attachDefault, setAttachDefault] = React.useState<ExistingAttachment[]>([]) + + // 3) 코멘트 시트 + 관련 상태 + const [initialComments, setInitialComments] = React.useState<RfqCommentWithAttachments[]>([]) + const [commentSheetOpen, setCommentSheetOpen] = React.useState(false) + const [selectedRfqIdForComments, setSelectedRfqIdForComments] = React.useState<number | null>(null) + + // 4) rowAction으로 다양한 모달/시트 열기 + const [rowAction, setRowAction] = React.useState<DataTableRowAction<RfqWithAll> | null>(null) + + // 열리고 닫힐 때마다, rowAction 등을 확인해서 시트 열기/닫기 처리 + React.useEffect(() => { + if (rowAction?.type === "comments" && rowAction?.row.original) { + openCommentSheet(rowAction.row.original.id) + } + }, [rowAction]) + + /** + * (A) 코멘트 시트를 열기 전에, + * DB에서 (rfqId에 해당하는) 코멘트들 + 각 코멘트별 첨부파일을 조회. + */ + const openCommentSheet = React.useCallback(async (rfqId: number) => { + setInitialComments([]) + + // 여기서 rowAction을 직접 참조하지 않고, 필요한 데이터만 파라미터로 받기 + const comments = data.find(rfq => rfq.rfqId === rfqId)?.comments || [] + + if (comments && comments.length > 0) { + const commentWithAttachments = await Promise.all( + comments.map(async (c) => { + const attachments = await fetchRfqAttachmentsbyCommentId(c.id) + return { + ...c, + commentedBy: c.commentedBy || 1, + attachments, + } + }) + ) + + setInitialComments(commentWithAttachments) + } + + setSelectedRfqIdForComments(rfqId) + setCommentSheetOpen(true) + }, [data]) // data만 의존성으로 추가 + + /** + * (B) 첨부파일 시트 열기 + */ + const openAttachmentsSheet = React.useCallback(async (rfqId: number) => { + const list = await fetchRfqAttachments(rfqId) + setAttachDefault(list) + setSelectedRfqIdForAttachments(rfqId) + setAttachmentsOpen(true) + }, []) + + // 5) DataTable 컬럼 세팅 + const columns = React.useMemo( + () => + getColumns({ + setRowAction, + router, + openAttachmentsSheet, + openCommentSheet + }), + [setRowAction, router, openAttachmentsSheet, openCommentSheet] + ) + + /** + * 간단한 filterFields 예시 + */ + const filterFields: DataTableFilterField<RfqWithAll>[] = [ + { + id: "rfqCode", + label: "RFQ Code", + placeholder: "Filter RFQ Code...", + }, + { + id: "projectName", + label: "Project", + placeholder: "Filter Project...", + }, + { + id: "rfqDescription", + label: "Description", + placeholder: "Filter Description...", + }, + ] + + /** + * Advanced filter fields 예시 + */ + const advancedFilterFields: DataTableAdvancedFilterField<RfqWithAll>[] = [ + { + id: "rfqCode", + label: "RFQ Code", + type: "text", + }, + { + id: "rfqDescription", + label: "Description", + type: "text", + }, + { + id: "projectCode", + label: "Project Code", + type: "text", + }, + { + id: "projectName", + label: "Project Name", + type: "text", + }, + { + id: "rfqDueDate", + label: "Due Date", + type: "date", + }, + { + id: "responseStatus", + label: "Response Status", + type: "select", + options: [ + { label: "Reviewing", value: "REVIEWING" }, + { label: "Accepted", value: "ACCEPTED" }, + { label: "Declined", value: "DECLINED" }, + ], + } + ] + + // useDataTable() 훅 -> pagination, sorting 등 관리 + const { table } = useDataTable({ + data, + columns, + pageCount, + filterFields, + enablePinning: true, + enableAdvancedFilter: true, + initialState: { + sorting: [{ id: "respondedAt", desc: true }], + columnPinning: { right: ["actions"] }, + }, + getRowId: (originalRow) => String(originalRow.id), + shallow: false, + clearOnDefault: true, + }) + + const currentUserId = session?.user?.id ? parseInt(session.user.id, 10) : 0 + const currentVendorId = session?.user?.id ? session.user.companyId : 0 + + + + return ( + <> + <DataTable table={table}> + <DataTableAdvancedToolbar + table={table} + filterFields={advancedFilterFields} + shallow={false} + > + <RfqsVendorTableToolbarActions table={table} /> + </DataTableAdvancedToolbar> + </DataTable> + + {/* 1) 아이템 목록 Dialog */} + {rowAction?.type === "items" && rowAction?.row.original && ( + <RfqsItemsDialog + open={true} + onOpenChange={() => setRowAction(null)} + rfq={rowAction.row.original} + /> + )} + + {/* 2) 코멘트 시트 */} + {selectedRfqIdForComments && ( + <CommentSheet + open={commentSheetOpen} + onOpenChange={setCommentSheetOpen} + initialComments={initialComments} + rfqId={selectedRfqIdForComments} + vendorId={currentVendorId??0} + currentUserId={currentUserId} + /> + )} + + {/* 3) 첨부파일 시트 */} + <RfqAttachmentsSheet + open={attachmentsOpen} + onOpenChange={setAttachmentsOpen} + rfqId={selectedRfqIdForAttachments ?? 0} + attachments={attachDefault} + /> + </> + ) +}
\ No newline at end of file |
