|
| 1 | +import React, {createContext, useCallback, useContext, useState} from 'react'; |
| 2 | + |
| 3 | +interface DatasetRow { |
| 4 | + id: string | number; |
| 5 | + [key: string]: any; |
| 6 | +} |
| 7 | + |
| 8 | +interface EditedCell { |
| 9 | + [fieldName: string]: unknown; |
| 10 | +} |
| 11 | + |
| 12 | +interface DatasetEditContextType { |
| 13 | + /** Map of edited cells, keyed by row absolute index */ |
| 14 | + editedCellsMap: Map<number, EditedCell>; |
| 15 | + setEditedCellsMap: React.Dispatch< |
| 16 | + React.SetStateAction<Map<number, EditedCell>> |
| 17 | + >; |
| 18 | + /** Map of complete edited rows, keyed by row absolute index */ |
| 19 | + editedRows: Map<number, DatasetRow>; |
| 20 | + setEditedRows: React.Dispatch<React.SetStateAction<Map<number, DatasetRow>>>; |
| 21 | + /** Callback to process row updates from the data grid */ |
| 22 | + processRowUpdate: (newRow: DatasetRow, oldRow: DatasetRow) => DatasetRow; |
| 23 | + /** Array of row indices that have been marked for deletion */ |
| 24 | + deletedRows: number[]; |
| 25 | + setDeletedRows: React.Dispatch<React.SetStateAction<number[]>>; |
| 26 | + /** Map of newly added rows, keyed by temporary row ID */ |
| 27 | + addedRows: Map<string, DatasetRow>; |
| 28 | + setAddedRows: React.Dispatch<React.SetStateAction<Map<string, DatasetRow>>>; |
| 29 | + /** Reset the context to its initial state */ |
| 30 | + reset: () => void; |
| 31 | +} |
| 32 | + |
| 33 | +export const DatasetEditContext = createContext< |
| 34 | + DatasetEditContextType | undefined |
| 35 | +>(undefined); |
| 36 | + |
| 37 | +export const useDatasetEditContext = () => { |
| 38 | + const context = useContext(DatasetEditContext); |
| 39 | + if (!context) { |
| 40 | + throw new Error( |
| 41 | + 'useDatasetEditContext must be used within a DatasetEditProvider' |
| 42 | + ); |
| 43 | + } |
| 44 | + return context; |
| 45 | +}; |
| 46 | + |
| 47 | +interface DatasetEditProviderProps { |
| 48 | + children: React.ReactNode; |
| 49 | +} |
| 50 | + |
| 51 | +export const DatasetEditProvider: React.FC<DatasetEditProviderProps> = ({ |
| 52 | + children, |
| 53 | +}) => { |
| 54 | + const [editedCellsMap, setEditedCellsMap] = useState<Map<number, EditedCell>>( |
| 55 | + new Map() |
| 56 | + ); |
| 57 | + const [editedRows, setEditedRows] = useState<Map<number, DatasetRow>>( |
| 58 | + new Map() |
| 59 | + ); |
| 60 | + const [deletedRows, setDeletedRows] = useState<number[]>([]); |
| 61 | + const [addedRows, setAddedRows] = useState<Map<string, DatasetRow>>( |
| 62 | + new Map() |
| 63 | + ); |
| 64 | + |
| 65 | + const processRowUpdate = useCallback( |
| 66 | + (newRow: DatasetRow, oldRow: DatasetRow): DatasetRow => { |
| 67 | + const changedField = Object.keys(newRow).find( |
| 68 | + key => newRow[key] !== oldRow[key] && key !== 'id' |
| 69 | + ); |
| 70 | + |
| 71 | + if (changedField) { |
| 72 | + const rowKey = String(newRow.id); |
| 73 | + const rowIndex = newRow._index; |
| 74 | + if (rowKey.startsWith('new-')) { |
| 75 | + setAddedRows(prev => { |
| 76 | + const updatedMap = new Map(prev); |
| 77 | + updatedMap.set(rowKey, newRow); |
| 78 | + return updatedMap; |
| 79 | + }); |
| 80 | + } else { |
| 81 | + setEditedCellsMap(prev => { |
| 82 | + const existingEdits = prev.get(rowIndex) || {}; |
| 83 | + const updatedMap = new Map(prev); |
| 84 | + updatedMap.set(rowIndex, { |
| 85 | + ...existingEdits, |
| 86 | + [changedField]: newRow[changedField], |
| 87 | + }); |
| 88 | + return updatedMap; |
| 89 | + }); |
| 90 | + setEditedRows(prev => { |
| 91 | + const updatedMap = new Map(prev); |
| 92 | + updatedMap.set(rowIndex, newRow); |
| 93 | + return updatedMap; |
| 94 | + }); |
| 95 | + } |
| 96 | + } |
| 97 | + return newRow; |
| 98 | + }, |
| 99 | + [] |
| 100 | + ); |
| 101 | + |
| 102 | + const reset = useCallback(() => { |
| 103 | + setEditedCellsMap(new Map()); |
| 104 | + setEditedRows(new Map()); |
| 105 | + setDeletedRows([]); |
| 106 | + setAddedRows(new Map()); |
| 107 | + }, []); |
| 108 | + |
| 109 | + return ( |
| 110 | + <DatasetEditContext.Provider |
| 111 | + value={{ |
| 112 | + editedCellsMap, |
| 113 | + setEditedCellsMap, |
| 114 | + editedRows, |
| 115 | + setEditedRows, |
| 116 | + processRowUpdate, |
| 117 | + deletedRows, |
| 118 | + setDeletedRows, |
| 119 | + addedRows, |
| 120 | + setAddedRows, |
| 121 | + reset, |
| 122 | + }}> |
| 123 | + {children} |
| 124 | + </DatasetEditContext.Provider> |
| 125 | + ); |
| 126 | +}; |
0 commit comments