st: feat: 신규 버튼 컴포넌트 추가, 50:50 비율 그리드 추가 작업중

This commit is contained in:
2026-01-12 15:26:33 +09:00
parent 57151eae76
commit 2eddbacc7f
4 changed files with 224 additions and 0 deletions
@@ -0,0 +1,23 @@
import { Checkbox } from "@common/components";
import type React from "react";
interface NotApplicableCheckButtonProp {
isCheck: boolean;
setIsCheck: React.Dispatch<React.SetStateAction<boolean>>;
}
const NotApplicableCheckButton = ({ isCheck, setIsCheck }: NotApplicableCheckButtonProp) => {
const handleCheckChange = (value: boolean) => {
setIsCheck(value);
};
return (
<div className="flex items-center space-x-2">
<label htmlFor="notApplicable">해당사항 없음</label>
<Checkbox id="notApplicable" checked={isCheck} onCheckedChange={handleCheckChange} />
</div>
);
};
export default NotApplicableCheckButton;
@@ -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<RealGridReact>(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<string, string>();
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 (
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem] w-1/2">
<div className="h-[65vh]">
<RealGridReact
ref={gridRef}
autoGenerateField={true}
layout={columnLayout}
rows={rowData}
>
{columns.map((column) => (
<RGDataColumn
key={column.name}
name={column.name}
fieldName={column.fieldName}
valueType={column.valueType ? column.valueType : ValueType.TEXT}
{...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.000' })}
header={column.header}
editable={column.editable}
footer={column.footer ? {
text: column.footer.text,
expression: column.footer.expression,
numberFormat: column.footer.numberFormat,
} : undefined}
mergeRule={column.mergeCells ? { criteria: 'value' } : undefined}
sortable={!column.sortdisable}
/>
))}
</RealGridReact>
</div>
</div>
);
};
export default CompactDataGrid;
@@ -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 (
<div className="flex gap-[0.6rem] mx-[0.6rem]">
<CompactDataGrid
columnInfo={leftColumnInfo}
fixedColumns={leftFixedColumns}
showHeaderCheckbox={showHeaderCheckbox}
rowData={leftRowData}
setRowData={setLeftRowData}
/>
<CompactDataGrid
columnInfo={rightColumnInfo}
fixedColumns={rightFixedColumns}
showHeaderCheckbox={showHeaderCheckbox}
rowData={rightRowData}
setRowData={setRightRowData}
/>
</div>
);
};
export default SplitDataGrid;
@@ -84,4 +84,16 @@ export type TabDataGridProps = {
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
rowDataMap: Map<string, Record<string, string | number>[]>;
setRowDataMap: React.Dispatch<React.SetStateAction<Map<string, Record<string, string | number>[]>>>;
};
export type SplitDataGridProps = {
leftColumnInfo: ColumnInfo;
rightColumnInfo: ColumnInfo;
leftFixedColumns?: number;
rightFixedColumns?: number;
showHeaderCheckbox?: boolean;
leftRowData: Record<string, string | number>[];
rightRowData: Record<string, string | number>[];
setLeftRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
setRightRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
};