Skip to content

Commit

Permalink
Fix contingency CustomAgGridTable types
Browse files Browse the repository at this point in the history
  • Loading branch information
Tristan-WorkGH committed Sep 18, 2024
1 parent 615af38 commit 77a6a80
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import IconButton from '@mui/material/IconButton';
import { ArrowCircleDown, ArrowCircleUp, Upload } from '@mui/icons-material';
import AddIcon from '@mui/icons-material/ControlPoint';
import DeleteIcon from '@mui/icons-material/Delete';
import { useState } from 'react';
import { useCallback, useState } from 'react';
import { useIntl } from 'react-intl';
import { styled } from '@mui/material/styles';
import { FieldValues, UseFieldArrayReturn } from 'react-hook-form';
import ErrorInput from '../errorManagement/ErrorInput';
import FieldErrorAlert from '../errorManagement/FieldErrorAlert';
import CsvUploader from './csvUploader/CsvUploader';
import CsvUploader, { CsvUploaderProps } from './csvUploader/CsvUploader';

const InnerColoredButton = styled(IconButton)(({ theme }) => {
return {
Expand All @@ -33,7 +33,7 @@ export interface BottomRightButtonsProps {
handleMoveRowUp: () => void;
handleMoveRowDown: () => void;
useFieldArrayOutput: UseFieldArrayReturn<FieldValues, string, 'id'>;
csvProps: any;
csvProps: Omit<CsvUploaderProps, 'open' | 'onClose' | 'name' | 'useFieldArrayOutput'>;
}

function BottomRightButtons({
Expand All @@ -47,7 +47,7 @@ function BottomRightButtons({
handleMoveRowDown,
useFieldArrayOutput,
csvProps,
}: BottomRightButtonsProps) {
}: Readonly<BottomRightButtonsProps>) {
const [uploaderOpen, setUploaderOpen] = useState(false);
const intl = useIntl();

Expand Down Expand Up @@ -88,7 +88,7 @@ function BottomRightButtons({
</Grid>
<CsvUploader
open={uploaderOpen}
onClose={() => setUploaderOpen(false)}
onClose={useCallback(() => setUploaderOpen(false), [])}
name={name}
useFieldArrayOutput={useFieldArrayOutput}
{...csvProps}
Expand Down
153 changes: 84 additions & 69 deletions src/components/inputs/reactHookForm/agGridTable/CustomAgGridTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import { Grid, useTheme } from '@mui/material';
import { useIntl } from 'react-intl';
import { CellEditingStoppedEvent, ColumnState, SortChangedEvent } from 'ag-grid-community';
import BottomRightButtons from './BottomRightButtons';
import { ColDef, GridApi, GridOptions } from 'ag-grid-community';
import BottomRightButtons, { BottomRightButtonsProps } from './BottomRightButtons';
import FieldConstants from '../../../../utils/constants/fieldConstants';

type AgGridFn<TFn extends keyof GridOptions, TData> = NonNullable<GridOptions<TData>[TFn]>;

export const ROW_DRAGGING_SELECTION_COLUMN_DEF = [
{
rowDrag: true,
headerCheckboxSelection: true,
checkboxSelection: true,
maxWidth: 50,
},
];
] as const satisfies Readonly<ColDef[]>;

const style = (customProps: any) => ({
const style = (customProps: object = {}) => ({
grid: (theme: any) => ({
width: 'auto',
height: '100%',
Expand Down Expand Up @@ -83,21 +85,23 @@ const style = (customProps: any) => ({
}),
});

export interface CustomAgGridTableProps {
export interface CustomAgGridTableProps<TData, TValue> {
name: string;
columnDefs: any;
makeDefaultRowData: any;
csvProps: unknown;
cssProps: unknown;
defaultColDef: unknown;
columnDefs: ColDef<TData, TValue>[];
makeDefaultRowData: () => unknown;
csvProps: BottomRightButtonsProps['csvProps'];
cssProps?: object;
defaultColDef: GridOptions<TData>['defaultColDef'];
pagination: boolean;
paginationPageSize: number;
suppressRowClickSelection: boolean;
alwaysShowVerticalScroll: boolean;
stopEditingWhenCellsLoseFocus: boolean;
}

function CustomAgGridTable({
// TODO: rename ContingencyAgGridTable
// TODO: used only once in gridexplore, move to gridexplore?
function CustomAgGridTable<TData = unknown, TValue = unknown>({
name,
columnDefs,
makeDefaultRowData,
Expand All @@ -109,11 +113,10 @@ function CustomAgGridTable({
suppressRowClickSelection,
alwaysShowVerticalScroll,
stopEditingWhenCellsLoseFocus,
...props
}: CustomAgGridTableProps) {
}: Readonly<CustomAgGridTableProps<TData, TValue>>) {
const theme: any = useTheme();
const [gridApi, setGridApi] = useState<any>(null);
const [selectedRows, setSelectedRows] = useState([]);
const [gridApi, setGridApi] = useState<GridApi<TData>>();
const [selectedRows, setSelectedRows] = useState<TData[]>([]);
const [newRowAdded, setNewRowAdded] = useState(false);
const [isSortApplied, setIsSortApplied] = useState(false);

Expand All @@ -124,15 +127,15 @@ function CustomAgGridTable({
});
const { append, remove, update, swap, move } = useFieldArrayOutput;

const rowData = watch(name);
const rowData = watch(name); // TODO: use correct types for useFormContext<...>()

const isFirstSelected = Boolean(
rowData?.length && gridApi?.api.getRowNode(rowData[0][FieldConstants.AG_GRID_ROW_UUID])?.isSelected()
rowData?.length && gridApi?.getRowNode(rowData[0][FieldConstants.AG_GRID_ROW_UUID])?.isSelected()
);

const isLastSelected = Boolean(
rowData?.length &&
gridApi?.api.getRowNode(rowData[rowData.length - 1][FieldConstants.AG_GRID_ROW_UUID])?.isSelected()
gridApi?.getRowNode(rowData[rowData.length - 1][FieldConstants.AG_GRID_ROW_UUID])?.isSelected()
);

const noRowSelected = selectedRows.length === 0;
Expand All @@ -146,26 +149,26 @@ function CustomAgGridTable({
[getValues, name]
);

const handleMoveRowUp = () => {
const handleMoveRowUp = useCallback(() => {
selectedRows
.map((row) => getIndex(row))
.map(getIndex)
.sort()
.forEach((idx) => {
swap(idx, idx - 1);
});
};
}, [getIndex, selectedRows, swap]);

const handleMoveRowDown = () => {
const handleMoveRowDown = useCallback(() => {
selectedRows
.map((row) => getIndex(row))
.map(getIndex)
.sort()
.reverse()
.forEach((idx) => {
swap(idx, idx + 1);
});
};
}, [getIndex, selectedRows, swap]);

const handleDeleteRows = () => {
const handleDeleteRows = useCallback(() => {
if (selectedRows.length === rowData.length) {
remove();
} else {
Expand All @@ -174,52 +177,59 @@ function CustomAgGridTable({
remove(idx);
});
}
};

useEffect(() => {
if (gridApi) {
gridApi.api.refreshCells({
force: true,
});
}
}, [gridApi, rowData]);
}, [getIndex, remove, rowData.length, selectedRows]);

const handleAddRow = () => {
const handleAddRow = useCallback(() => {
append(makeDefaultRowData());
setNewRowAdded(true);
};
}, [append, makeDefaultRowData]);

useEffect(() => {
if (gridApi) {
gridApi.api.sizeColumnsToFit();
}
gridApi?.refreshCells({
force: true,
});
}, [gridApi, rowData]);

useEffect(() => {
gridApi?.sizeColumnsToFit();
}, [columnDefs, gridApi]);

const intl = useIntl();
const getLocaleText = useCallback(
(params: any) => {
const key = `agGrid.${params.key}`;
return intl.messages[key] || params.defaultValue;
},
const getLocaleText = useCallback<AgGridFn<'getLocaleText', TData>>(
(params) => intl.formatMessage({ id: `agGrid.${params.key}`, defaultMessage: params.defaultValue }),
[intl]
);

const onGridReady = (params: any) => {
setGridApi(params);
};
const onGridReady = useCallback<AgGridFn<'onGridReady', TData>>((event) => {
setGridApi(event.api);
}, []);

const onRowDragEnd = useCallback<AgGridFn<'onRowDragEnd', TData>>(
(e) => move(getIndex(e.node.data), e.overIndex),
[getIndex, move]
);

const onSelectionChanged = useCallback<AgGridFn<'onSelectionChanged', TData>>(
// @ts-expect-error TODO manage null api case (not possible at runtime?)
() => setSelectedRows(gridApi.getSelectedRows()),
[gridApi]
);

const onRowDataUpdated = () => {
setNewRowAdded(false);
if (gridApi?.api) {
// update due to new appended row, let's scroll
const lastIndex = rowData.length - 1;
gridApi.api.paginationGoToLastPage();
gridApi.api.ensureIndexVisible(lastIndex, 'bottom');
}
};
const onRowDataUpdated = useCallback<AgGridFn<'onRowDataUpdated', TData>>(
(/* event */) => {
setNewRowAdded(false);
if (gridApi) {
// update due to new appended row, let's scroll
const lastIndex = rowData.length - 1;
gridApi.paginationGoToLastPage();
gridApi.ensureIndexVisible(lastIndex, 'bottom');
}
},
[gridApi, rowData.length]
);

const onCellEditingStopped = useCallback(
(event: CellEditingStoppedEvent) => {
const onCellEditingStopped = useCallback<AgGridFn<'onCellEditingStopped', TData>>(
(event) => {
const rowIndex = getIndex(event.data);
if (rowIndex === -1) {
return;
Expand All @@ -229,15 +239,22 @@ function CustomAgGridTable({
[getIndex, update]
);

const onSortChanged = useCallback((event: SortChangedEvent) => {
const isAnycolumnhasSort = event.api.getColumnState().some((col: ColumnState) => col.sort);
setIsSortApplied(isAnycolumnhasSort);
}, []);
const onSortChanged = useCallback<AgGridFn<'onSortChanged', TData>>(
(event) => setIsSortApplied(event.api.getColumnState().some((col) => col.sort)),
[]
);

const getRowId = useCallback<AgGridFn<'getRowId', TData>>(
// @ts-expect-error: we don't know at compile time if TData has a "FieldConstants.AG_GRID_ROW_UUID" field
// TODO maybe force TData type to have this field?
(row) => row.data[FieldConstants.AG_GRID_ROW_UUID],
[]
);

return (
<Grid container spacing={2}>
<Grid item xs={12} className={theme.aggrid.theme} sx={style(cssProps).grid}>
<AgGridReact
<AgGridReact<TData>
rowData={rowData}
onGridReady={onGridReady}
getLocaleText={getLocaleText}
Expand All @@ -246,23 +263,21 @@ function CustomAgGridTable({
domLayout="autoHeight"
rowDragEntireRow
rowDragManaged
onRowDragEnd={(e) => move(getIndex(e.node.data), e.overIndex)}
onRowDragEnd={onRowDragEnd}
suppressBrowserResizeObserver
defaultColDef={defaultColDef}
columnDefs={columnDefs}
detailRowAutoHeight
onSelectionChanged={() => {
setSelectedRows(gridApi.api.getSelectedRows());
}}
onSelectionChanged={onSelectionChanged}
onRowDataUpdated={newRowAdded ? onRowDataUpdated : undefined}
onCellEditingStopped={onCellEditingStopped}
onSortChanged={onSortChanged}
getRowId={(row) => row.data[FieldConstants.AG_GRID_ROW_UUID]}
getRowId={getRowId}
pagination={pagination}
paginationPageSize={paginationPageSize}
suppressRowClickSelection={suppressRowClickSelection}
alwaysShowVerticalScroll={alwaysShowVerticalScroll}
stopEditingWhenCellsLoseFocus={stopEditingWhenCellsLoseFocus}
{...props}
/>
</Grid>
<BottomRightButtons
Expand Down
Loading

0 comments on commit 77a6a80

Please sign in to comment.