summaryrefslogtreecommitdiff
path: root/lib/tech-vendor-rfq-response/vendor-rfq-table/rfqs-table.tsx
diff options
context:
space:
mode:
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.tsx280
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