diff --git a/apps/st/src/components/button/NotApplicableCheckButton.tsx b/apps/st/src/components/button/NotApplicableCheckButton.tsx new file mode 100644 index 000000000..6e9a8c899 --- /dev/null +++ b/apps/st/src/components/button/NotApplicableCheckButton.tsx @@ -0,0 +1,23 @@ +import { Checkbox } from "@common/components"; +import type React from "react"; + +interface NotApplicableCheckButtonProp { + isCheck: boolean; + setIsCheck: React.Dispatch>; +} + +const NotApplicableCheckButton = ({ isCheck, setIsCheck }: NotApplicableCheckButtonProp) => { + + const handleCheckChange = (value: boolean) => { + setIsCheck(value); + }; + + return ( +
+ + +
+ ); +}; + +export default NotApplicableCheckButton; \ No newline at end of file diff --git a/apps/st/src/components/module/CompactDataGrid.tsx b/apps/st/src/components/module/CompactDataGrid.tsx new file mode 100644 index 000000000..1312230a9 --- /dev/null +++ b/apps/st/src/components/module/CompactDataGrid.tsx @@ -0,0 +1,154 @@ +import { useRef, useEffect } from "react" +import { ValueType } from "realgrid" + +import RealGrid, { GridFitStyle } from "realgrid" +import { RealGridReact, RGDataColumn } from "realgrid-react" +import type { DataGridProps } from "../type/DataGrid.type" + +// RealGrid 타입 확장 +declare module "realgrid" { + interface GridView { + setOptions(options: { + footer?: { visible?: boolean }; + summaryMode?: 'aggregate' | 'statistical' | 'none'; + checkBar?: { visible?: boolean }; + }): void; + } +} + +RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || ''); + +const CompactDataGrid = ({ columnInfo, fixedColumns, showHeaderCheckbox = false, rowData, setRowData }: DataGridProps) => { + const { columns, columnLayout } = columnInfo; + const gridRef = useRef(null); + + useEffect(() => { + if (!gridRef.current?.gridView || !gridRef.current?.dataProvider) return; + + const gridView = gridRef.current.gridView; + const dataProvider = gridRef.current.dataProvider; + + const fieldsToSet: Array<{ fieldName: string; dataType: string }> = []; + const fieldMap = new Map(); + + columns.forEach(col => { + if (col.valueType && col.fieldName && !fieldMap.has(col.fieldName)) { + fieldMap.set(col.fieldName, col.valueType); + fieldsToSet.push({ + fieldName: col.fieldName, + dataType: col.valueType + }); + } + }); + + // 필드가 이미 존재하는지 확인하고, valueType이 설정된 필드만 업데이트 + if (fieldsToSet.length > 0) { + try { + // 기존 필드 정보 가져오기 + const existingFields = (dataProvider as { getFields?: () => Array<{ fieldName: string; dataType?: string }> }).getFields?.() || []; + const existingFieldMap = new Map(existingFields.map(f => [f.fieldName, f.dataType || 'text'])); + + // valueType이 설정된 필드 중 dataType이 다른 필드만 업데이트 + const fieldsToUpdate = fieldsToSet.filter(field => { + const existingDataType = existingFieldMap.get(field.fieldName); + return existingDataType !== field.dataType; + }); + + if (fieldsToUpdate.length > 0) { + // 기존 필드 정보를 유지하면서 dataType만 업데이트 + // 컬럼 정의에 valueType이 있으면 그것을 우선 사용, 없으면 기존 필드의 dataType 사용 + const allFields = existingFields.map(f => ({ + fieldName: f.fieldName, + dataType: fieldMap.get(f.fieldName) || f.dataType || 'text' + })); + + // 새로 추가할 필드가 있으면 추가 + fieldsToSet.forEach(field => { + if (!existingFieldMap.has(field.fieldName)) { + allFields.push({ fieldName: field.fieldName, dataType: field.dataType }); + } + }); + + // setFields를 호출하여 필드의 dataType 업데이트 + (dataProvider as { setFields: (fields: Array<{ fieldName: string; dataType: string }>) => void }) + .setFields(allFields); + } + } catch (error) { + console.warn('Failed to set field dataType:', error); + } + } + + gridView.setDisplayOptions({ + fitStyle: GridFitStyle.EVEN + }); + + gridView.header.height = 60; + + // 헤더 체크박스 표시 여부 설정 + gridView.setOptions({ + checkBar: { visible: showHeaderCheckbox }, + }); + + // footer가 있는 컬럼이 있으면 footer 높이 설정 + const hasFooter = columns.some(col => col.footer); + if (hasFooter) { + gridView.footer.height = 40; + } + + // 고정 컬럼 설정 + if (fixedColumns !== undefined && fixedColumns > 0) { + gridView.setFixedOptions({ + colCount: fixedColumns, + }); + } + + gridView.setOptions({ + summaryMode: "aggregate" + }); + + // footer의 valueCallback 설정 + columns.forEach(col => { + if (col.footer && col.footer.valueCallback) { + const column = gridView.columnByName(col.name); + if (column && column.footer) { + (column.footer as { valueCallback?: typeof col.footer.valueCallback }).valueCallback = col.footer.valueCallback; + } + } + }); + + }, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox]); + + return ( +
+
+ + {columns.map((column) => ( + + ))} + +
+
+ ); +}; + +export default CompactDataGrid; \ No newline at end of file diff --git a/apps/st/src/components/module/SplitDataGrid.tsx b/apps/st/src/components/module/SplitDataGrid.tsx new file mode 100644 index 000000000..7d24c96c0 --- /dev/null +++ b/apps/st/src/components/module/SplitDataGrid.tsx @@ -0,0 +1,35 @@ +import CompactDataGrid from "./CompactDataGrid"; +import type { SplitDataGridProps } from "../type/DataGrid.type"; + +const SplitDataGrid = ({ + leftColumnInfo, + rightColumnInfo, + leftFixedColumns, + rightFixedColumns, + showHeaderCheckbox = false, + leftRowData, + rightRowData, + setLeftRowData, + setRightRowData, +}: SplitDataGridProps) => { + return ( +
+ + +
+ ); +}; + +export default SplitDataGrid; diff --git a/apps/st/src/components/type/DataGrid.type.ts b/apps/st/src/components/type/DataGrid.type.ts index 3c405546f..d89159ff3 100644 --- a/apps/st/src/components/type/DataGrid.type.ts +++ b/apps/st/src/components/type/DataGrid.type.ts @@ -84,4 +84,16 @@ export type TabDataGridProps = { showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true) rowDataMap: Map[]>; setRowDataMap: React.Dispatch[]>>>; +}; + +export type SplitDataGridProps = { + leftColumnInfo: ColumnInfo; + rightColumnInfo: ColumnInfo; + leftFixedColumns?: number; + rightFixedColumns?: number; + showHeaderCheckbox?: boolean; + leftRowData: Record[]; + rightRowData: Record[]; + setLeftRowData: React.Dispatch[]>>; + setRightRowData: React.Dispatch[]>>; }; \ No newline at end of file