summaryrefslogtreecommitdiff
path: root/components/form-data/form-data-table copy.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/form-data/form-data-table copy.tsx')
-rw-r--r--components/form-data/form-data-table copy.tsx539
1 files changed, 539 insertions, 0 deletions
diff --git a/components/form-data/form-data-table copy.tsx b/components/form-data/form-data-table copy.tsx
new file mode 100644
index 00000000..aa16513a
--- /dev/null
+++ b/components/form-data/form-data-table copy.tsx
@@ -0,0 +1,539 @@
+"use client";
+
+import * as React from "react";
+import { useParams, useRouter } from "next/navigation";
+import { useTranslation } from "@/i18n/client";
+
+import { ClientDataTable } from "../client-data-table/data-table";
+import {
+ getColumns,
+ DataTableRowAction,
+ DataTableColumnJSON,
+ ColumnType,
+} from "./form-data-table-columns";
+import type { DataTableAdvancedFilterField } from "@/types/table";
+import { Button } from "../ui/button";
+import {
+ Download,
+ Loader,
+ Save,
+ Upload,
+ Plus,
+ Tag,
+ TagsIcon,
+ FileText,
+ FileSpreadsheet,
+ FileOutput,
+ Clipboard,
+ Send
+} from "lucide-react";
+import { toast } from "sonner";
+import {
+ getReportTempList,
+ sendFormDataToSEDP,
+ syncMissingTags,
+ updateFormDataInDB,
+} from "@/lib/forms/services";
+import { UpdateTagSheet } from "./update-form-sheet";
+import { FormDataReportTempUploadDialog } from "./form-data-report-temp-upload-dialog";
+import { FormDataReportDialog } from "./form-data-report-dialog";
+import { FormDataReportBatchDialog } from "./form-data-report-batch-dialog";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+ DropdownMenuSeparator,
+} from "@/components/ui/dropdown-menu";
+import { AddFormTagDialog } from "./add-formTag-dialog";
+import { importExcelData } from "./import-excel-form";
+import { exportExcelData } from "./export-excel-form";
+import { SEDPConfirmationDialog, SEDPStatusDialog } from "./sedp-components";
+
+interface GenericData {
+ [key: string]: any;
+}
+
+export interface DynamicTableProps {
+ dataJSON: GenericData[];
+ columnsJSON: DataTableColumnJSON[];
+ contractItemId: number;
+ formCode: string;
+ formId: number;
+ projectId: number;
+ formName?: string;
+ objectCode?: string;
+}
+
+export default function DynamicTable({
+ dataJSON,
+ columnsJSON,
+ contractItemId,
+ formCode,
+ formId,
+ projectId,
+ formName = `VD)${formCode}`, // Default form name based on formCode
+ objectCode = "LO_PT_CLAS", // Default object code
+}: DynamicTableProps) {
+ const params = useParams();
+ const router = useRouter();
+ const lng = (params?.lng as string) || "ko";
+ const { t } = useTranslation(lng, "translation");
+
+ const [rowAction, setRowAction] =
+ React.useState<DataTableRowAction<GenericData> | null>(null);
+ const [tableData, setTableData] = React.useState<GenericData[]>(dataJSON);
+
+
+ console.log(tableData)
+ console.log(columnsJSON)
+
+ // Update tableData when dataJSON changes
+ React.useEffect(() => {
+ setTableData(dataJSON);
+ }, [dataJSON]);
+
+ // Separate loading states for different operations
+ const [isSyncingTags, setIsSyncingTags] = React.useState(false);
+ const [isImporting, setIsImporting] = React.useState(false);
+ const [isExporting, setIsExporting] = React.useState(false);
+ const [isSaving, setIsSaving] = React.useState(false);
+ const [isSendingSEDP, setIsSendingSEDP] = React.useState(false);
+
+ // Any operation in progress
+ const isAnyOperationPending = isSyncingTags || isImporting || isExporting || isSaving || isSendingSEDP;
+
+ // SEDP dialogs state
+ const [sedpConfirmOpen, setSedpConfirmOpen] = React.useState(false);
+ const [sedpStatusOpen, setSedpStatusOpen] = React.useState(false);
+ const [sedpStatusData, setSedpStatusData] = React.useState({
+ status: 'success' as 'success' | 'error' | 'partial',
+ message: '',
+ successCount: 0,
+ errorCount: 0,
+ totalCount: 0
+ });
+
+ const [tempUpDialog, setTempUpDialog] = React.useState(false);
+ const [reportData, setReportData] = React.useState<GenericData[]>([]);
+ const [batchDownDialog, setBatchDownDialog] = React.useState(false);
+ const [tempCount, setTempCount] = React.useState(0);
+ const [addTagDialogOpen, setAddTagDialogOpen] = React.useState(false);
+
+ React.useEffect(() => {
+ const getTempCount = async () => {
+ const tempList = await getReportTempList(contractItemId, formId);
+ setTempCount(tempList.length);
+ };
+
+ getTempCount();
+ }, [contractItemId, formId, tempUpDialog]);
+
+ const columns = React.useMemo(
+ () => getColumns<GenericData>({ columnsJSON, setRowAction, setReportData, tempCount }),
+ [columnsJSON, setRowAction, setReportData, tempCount]
+ );
+
+ function mapColumnTypeToAdvancedFilterType(
+ columnType: ColumnType
+ ): DataTableAdvancedFilterField<GenericData>["type"] {
+ switch (columnType) {
+ case "STRING":
+ return "text";
+ case "NUMBER":
+ return "number";
+ case "LIST":
+ return "select";
+ default:
+ return "text";
+ }
+ }
+
+ const advancedFilterFields = React.useMemo<
+ DataTableAdvancedFilterField<GenericData>[]
+ >(() => {
+ return columnsJSON.map((col) => ({
+ id: col.key,
+ label: col.label,
+ type: mapColumnTypeToAdvancedFilterType(col.type),
+ options:
+ col.type === "LIST"
+ ? col.options?.map((v) => ({ label: v, value: v }))
+ : undefined,
+ }));
+ }, [columnsJSON]);
+
+ // 태그 불러오기
+ async function handleSyncTags() {
+ try {
+ setIsSyncingTags(true);
+ const result = await syncMissingTags(contractItemId, formCode);
+
+ // Prepare the toast messages based on what changed
+ const changes = [];
+ if (result.createdCount > 0)
+ changes.push(`${result.createdCount}건 태그 생성`);
+ if (result.updatedCount > 0)
+ changes.push(`${result.updatedCount}건 태그 업데이트`);
+ if (result.deletedCount > 0)
+ changes.push(`${result.deletedCount}건 태그 삭제`);
+
+ if (changes.length > 0) {
+ // If any changes were made, show success message and reload
+ toast.success(`동기화 완료: ${changes.join(", ")}`);
+ router.refresh(); // Use router.refresh instead of location.reload
+ } else {
+ // If no changes were made, show an info message
+ toast.info("변경사항이 없습니다. 모든 태그가 최신 상태입니다.");
+ }
+ } catch (err) {
+ console.error(err);
+ toast.error("태그 동기화 중 에러가 발생했습니다.");
+ } finally {
+ setIsSyncingTags(false);
+ }
+ }
+
+ // Excel Import - Modified to directly save to DB
+ async function handleImportExcel(e: React.ChangeEvent<HTMLInputElement>) {
+ const file = e.target.files?.[0];
+ if (!file) return;
+
+ try {
+ setIsImporting(true);
+
+ // Call the updated importExcelData function with direct save capability
+ const result = await importExcelData({
+ file,
+ tableData,
+ columnsJSON,
+ formCode, // Pass formCode for direct save
+ contractItemId, // Pass contractItemId for direct save
+ onPendingChange: setIsImporting,
+ onDataUpdate: (newData) => {
+ // This is called only after successful DB save
+ setTableData(Array.isArray(newData) ? newData : newData(tableData));
+ }
+ });
+
+ // If import and save was successful, refresh the page
+ if (result.success) {
+ router.refresh();
+ }
+ } catch (error) {
+ console.error("Import failed:", error);
+ toast.error("Failed to import Excel data");
+ } finally {
+ // Always clear the file input value
+ e.target.value = "";
+ setIsImporting(false);
+ }
+ }
+
+ // SEDP Send handler (with confirmation)
+ function handleSEDPSendClick() {
+ if (tableData.length === 0) {
+ toast.error("No data to send to SEDP");
+ return;
+ }
+
+ // Open confirmation dialog
+ setSedpConfirmOpen(true);
+ }
+
+ // Actual SEDP send after confirmation
+// In your DynamicTable component, update the handler for SEDP sending
+
+async function handleSEDPSendConfirmed() {
+ try {
+ setIsSendingSEDP(true);
+
+ // Validate data
+ const invalidData = tableData.filter((item) => !item.TAG_NO?.trim());
+ if (invalidData.length > 0) {
+ toast.error(`태그 번호가 없는 항목이 ${invalidData.length}개 있습니다.`);
+ setSedpConfirmOpen(false);
+ return;
+ }
+
+ // Then send to SEDP - pass formCode instead of formName
+ const sedpResult = await sendFormDataToSEDP(
+ formCode, // Send formCode instead of formName
+ projectId, // Project ID
+ tableData, // Table data
+ columnsJSON // Column definitions
+ );
+
+ // Close confirmation dialog
+ setSedpConfirmOpen(false);
+
+ // Set status data based on result
+ if (sedpResult.success) {
+ setSedpStatusData({
+ status: 'success',
+ message: "Data successfully sent to SEDP",
+ successCount: tableData.length,
+ errorCount: 0,
+ totalCount: tableData.length
+ });
+ } else {
+ setSedpStatusData({
+ status: 'error',
+ message: sedpResult.message || "Failed to send data to SEDP",
+ successCount: 0,
+ errorCount: tableData.length,
+ totalCount: tableData.length
+ });
+ }
+
+ // Open status dialog to show result
+ setSedpStatusOpen(true);
+
+ // Refresh the route to get fresh data
+ router.refresh();
+
+ } catch (err: any) {
+ console.error("SEDP error:", err);
+
+ // Set error status
+ setSedpStatusData({
+ status: 'error',
+ message: err.message || "An unexpected error occurred",
+ successCount: 0,
+ errorCount: tableData.length,
+ totalCount: tableData.length
+ });
+
+ // Close confirmation and open status
+ setSedpConfirmOpen(false);
+ setSedpStatusOpen(true);
+
+ } finally {
+ setIsSendingSEDP(false);
+ }
+}
+ // Template Export
+ async function handleExportExcel() {
+ try {
+ setIsExporting(true);
+ await exportExcelData({
+ tableData,
+ columnsJSON,
+ formCode,
+ onPendingChange: setIsExporting
+ });
+ } finally {
+ setIsExporting(false);
+ }
+ }
+
+ // Handle batch document check
+ const handleBatchDocument = () => {
+ if (tempCount > 0) {
+ setBatchDownDialog(true);
+ } else {
+ toast.error("업로드된 Template File이 없습니다.");
+ }
+ };
+
+ return (
+ <>
+ <ClientDataTable
+ data={tableData}
+ columns={columns}
+ advancedFilterFields={advancedFilterFields}
+ >
+ {/* 버튼 그룹 */}
+ <div className="flex items-center gap-2">
+ {/* 태그 관리 드롭다운 */}
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button variant="outline" size="sm" disabled={isAnyOperationPending}>
+ {isSyncingTags && (
+ <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" />
+ )}
+ <TagsIcon className="size-4" />
+ Tag Operations
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end">
+ <DropdownMenuItem onClick={handleSyncTags} disabled={isAnyOperationPending}>
+ <Tag className="mr-2 h-4 w-4" />
+ Sync Tags
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => setAddTagDialogOpen(true)} disabled={isAnyOperationPending}>
+ <Plus className="mr-2 h-4 w-4" />
+ Add Tags
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+
+ {/* 리포트 관리 드롭다운 */}
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button variant="outline" size="sm" disabled={isAnyOperationPending}>
+ <Clipboard className="size-4" />
+ Report Operations
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end">
+ <DropdownMenuItem onClick={() => setTempUpDialog(true)} disabled={isAnyOperationPending}>
+ <Upload className="mr-2 h-4 w-4" />
+ Upload Template
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={handleBatchDocument} disabled={isAnyOperationPending}>
+ <FileOutput className="mr-2 h-4 w-4" />
+ Batch Document
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+
+ {/* IMPORT 버튼 (파일 선택) */}
+ <Button asChild variant="outline" size="sm" disabled={isAnyOperationPending}>
+ <label>
+ {isImporting ? (
+ <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" />
+ ) : (
+ <Upload className="size-4" />
+ )}
+ Import
+ <input
+ type="file"
+ accept=".xlsx,.xls"
+ onChange={handleImportExcel}
+ style={{ display: "none" }}
+ disabled={isAnyOperationPending}
+ />
+ </label>
+ </Button>
+
+ {/* EXPORT 버튼 */}
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleExportExcel}
+ disabled={isAnyOperationPending}
+ >
+ {isExporting ? (
+ <Loader className="mr-2 size-4 animate-spin" />
+ ) : (
+ <Download className="mr-2 size-4" />
+ )}
+ Export
+ </Button>
+
+
+ {/* SEDP 전송 버튼 */}
+ <Button
+ variant="samsung"
+ size="sm"
+ onClick={handleSEDPSendClick}
+ disabled={isAnyOperationPending}
+ >
+ {isSendingSEDP ? (
+ <>
+ <Loader className="mr-2 size-4 animate-spin" />
+ SEDP 전송 중...
+ </>
+ ) : (
+ <>
+ <Send className="size-4" />
+ Send to SHI
+ </>
+ )}
+ </Button>
+ </div>
+ </ClientDataTable>
+
+ {/* Modal dialog for tag update */}
+ <UpdateTagSheet
+ open={rowAction?.type === "update"}
+ onOpenChange={(open) => {
+ if (!open) setRowAction(null);
+ }}
+ columns={columnsJSON}
+ rowData={rowAction?.row.original ?? null}
+ formCode={formCode}
+ contractItemId={contractItemId}
+ onUpdateSuccess={(updatedValues) => {
+ // Update the specific row in tableData when a single row is updated
+ if (rowAction?.row.original?.TAG_NO) {
+ const tagNo = rowAction.row.original.TAG_NO;
+ setTableData(prev =>
+ prev.map(item =>
+ item.TAG_NO === tagNo ? updatedValues : item
+ )
+ );
+ }
+ }}
+ />
+
+ {/* Dialog for adding tags */}
+ <AddFormTagDialog
+ projectId={projectId}
+ formCode={formCode}
+ formName={`Form ${formCode}`}
+ contractItemId={contractItemId}
+ open={addTagDialogOpen}
+ onOpenChange={setAddTagDialogOpen}
+ />
+
+ {/* SEDP Confirmation Dialog */}
+ <SEDPConfirmationDialog
+ isOpen={sedpConfirmOpen}
+ onClose={() => setSedpConfirmOpen(false)}
+ onConfirm={handleSEDPSendConfirmed}
+ formName={formName}
+ tagCount={tableData.length}
+ isLoading={isSendingSEDP}
+ />
+
+ {/* SEDP Status Dialog */}
+ <SEDPStatusDialog
+ isOpen={sedpStatusOpen}
+ onClose={() => setSedpStatusOpen(false)}
+ status={sedpStatusData.status}
+ message={sedpStatusData.message}
+ successCount={sedpStatusData.successCount}
+ errorCount={sedpStatusData.errorCount}
+ totalCount={sedpStatusData.totalCount}
+ />
+
+ {/* Other dialogs */}
+ {tempUpDialog && (
+ <FormDataReportTempUploadDialog
+ columnsJSON={columnsJSON}
+ open={tempUpDialog}
+ setOpen={setTempUpDialog}
+ packageId={contractItemId}
+ formCode={formCode}
+ formId={formId}
+ uploaderType="vendor"
+ />
+ )}
+
+ {reportData.length > 0 && (
+ <FormDataReportDialog
+ columnsJSON={columnsJSON}
+ reportData={reportData}
+ setReportData={setReportData}
+ packageId={contractItemId}
+ formCode={formCode}
+ formId={formId}
+ />
+ )}
+
+ {batchDownDialog && (
+ <FormDataReportBatchDialog
+ open={batchDownDialog}
+ setOpen={setBatchDownDialog}
+ columnsJSON={columnsJSON}
+ reportData={tableData}
+ packageId={contractItemId}
+ formCode={formCode}
+ formId={formId}
+ />
+ )}
+ </>
+ );
+} \ No newline at end of file