1- import React from 'react' ;
1+ import React , { useReducer } from 'react' ;
22import PropTypes from 'prop-types' ;
33import { useFormApi , FieldArray } from '@data-driven-forms/react-form-renderer' ;
44
@@ -8,6 +8,9 @@ import Typography from '@material-ui/core/Typography';
88import FormControl from '@material-ui/core/FormControl' ;
99import FormHelperText from '@material-ui/core/FormHelperText' ;
1010import { makeStyles } from '@material-ui/core/styles' ;
11+ import RedoIcon from '@material-ui/icons/Redo' ;
12+ import UndoIcon from '@material-ui/icons/Undo' ;
13+ import IconButton from '@material-ui/core/IconButton' ;
1114
1215import { useFieldApi } from '@data-driven-forms/react-form-renderer' ;
1316
@@ -77,6 +80,38 @@ const defaultButtonLabels = {
7780 remove : 'REMOVE'
7881} ;
7982
83+ const initialState = {
84+ index : 0 ,
85+ history : [ ]
86+ } ;
87+
88+ export const reducer = ( state , { type, action } ) => {
89+ switch ( type ) {
90+ case 'redo' :
91+ return {
92+ ...state ,
93+ index : state . index + 1
94+ } ;
95+ case 'action' :
96+ return {
97+ index : state . index + 1 ,
98+ history : [ ...state . history . slice ( 0 , state . index ) , action ]
99+ } ;
100+ case 'undo' :
101+ return {
102+ ...state ,
103+ index : state . index - 1
104+ } ;
105+ case 'resetHistory' :
106+ return {
107+ ...state ,
108+ history : state . history . slice ( 0 , state . index )
109+ } ;
110+ default :
111+ return state ;
112+ }
113+ } ;
114+
80115const DynamicArray = ( { ...props } ) => {
81116 const {
82117 arrayValidator,
@@ -93,6 +128,7 @@ const DynamicArray = ({ ...props }) => {
93128 buttonLabels,
94129 ...rest
95130 } = useFieldApi ( props ) ;
131+ const [ state , dispatch ] = useReducer ( reducer , initialState ) ;
96132
97133 const combinedButtonLabels = {
98134 ...defaultButtonLabels ,
@@ -108,51 +144,80 @@ const DynamicArray = ({ ...props }) => {
108144 < FormFieldGrid { ...FormFieldGridProps } className = { clsx ( classes . fieldArrayGroup , FormFieldGridProps . classname ) } >
109145 < FormControl component = "fieldset" error = { isError } { ...FormControlProps } className = { clsx ( classes . formControl , FormControlProps . className ) } >
110146 < FieldArray key = { rest . input . name } name = { rest . input . name } validate = { arrayValidator } >
111- { ( { fields : { map, value = [ ] , push, remove } } ) => (
112- < Grid container spacing = { 3 } >
113- { label && (
147+ { ( { fields : { map, value = [ ] , push, remove } } ) => {
148+ const pushWrapper = ( ) => {
149+ dispatch ( { type : 'resetHistory' } ) ;
150+ push ( defaultItem ) ;
151+ } ;
152+
153+ const removeWrapper = ( index ) => {
154+ dispatch ( { type : 'action' , action : { action : 'remove' , value : value [ index ] } } ) ;
155+ remove ( index ) ;
156+ } ;
157+
158+ const undo = ( ) => {
159+ push ( state . history [ state . index - 1 ] . value ) ;
160+
161+ dispatch ( { type : 'undo' } ) ;
162+ } ;
163+
164+ const redo = ( ) => {
165+ remove ( value . length - 1 ) ;
166+
167+ dispatch ( { type : 'redo' } ) ;
168+ } ;
169+
170+ return (
171+ < Grid container spacing = { 3 } >
114172 < Grid item xs = { 12 } className = { classes . header } >
115- < Typography variant = "h6" className = { classes . label } >
116- { label }
117- </ Typography >
118- < Button color = "primary" onClick = { ( ) => push ( defaultItem ) } disabled = { value . length >= maxItems } >
173+ { label && (
174+ < Typography variant = "h6" className = { classes . label } >
175+ { label }
176+ </ Typography >
177+ ) }
178+ < IconButton color = "primary" aria-label = "undo" component = "span" disabled = { state . index === 0 } onClick = { undo } >
179+ < UndoIcon />
180+ </ IconButton >
181+ < IconButton color = "primary" aria-label = "redo" component = "span" disabled = { state . index === state . history . length } onClick = { redo } >
182+ < RedoIcon />
183+ </ IconButton >
184+ < Button color = "primary" onClick = { pushWrapper } disabled = { value . length >= maxItems } >
119185 { combinedButtonLabels . add }
120186 </ Button >
121187 </ Grid >
122- ) }
123- { description && (
124- < Grid item xs = { 12 } >
125- < Typography variant = "subtitle1" > { description } </ Typography >
126- </ Grid >
127- ) }
128- { value . length <= 0 && (
188+ { description && (
189+ < Grid item xs = { 12 } >
190+ < Typography variant = "subtitle1" > { description } </ Typography >
191+ </ Grid >
192+ ) }
129193 < Grid item xs = { 12 } >
130- < Typography variant = "body1" gutterBottom className = { classes . centerText } >
131- { noItemsMessage }
132- </ Typography >
194+ { value . length <= 0 ? (
195+ < Typography variant = "body1" gutterBottom className = { classes . centerText } >
196+ { noItemsMessage }
197+ </ Typography >
198+ ) : (
199+ map ( ( name , index ) => (
200+ < ArrayItem
201+ key = { `${ name } -${ index } ` }
202+ fields = { formFields }
203+ name = { name }
204+ fieldIndex = { index }
205+ remove = { removeWrapper }
206+ length = { value . length }
207+ minItems = { minItems }
208+ removeLabel = { combinedButtonLabels . remove }
209+ />
210+ ) )
211+ ) }
133212 </ Grid >
134- ) }
135- < Grid item xs = { 12 } >
136- { map ( ( name , index ) => (
137- < ArrayItem
138- key = { `${ name } -${ index } ` }
139- fields = { formFields }
140- name = { name }
141- fieldIndex = { index }
142- remove = { remove }
143- length = { value . length }
144- minItems = { minItems }
145- removeLabel = { combinedButtonLabels . remove }
146- />
147- ) ) }
148213 { isError && (
149214 < Grid item xs = { 12 } >
150215 < FormHelperText > { error } </ FormHelperText >
151216 </ Grid >
152217 ) }
153218 </ Grid >
154- </ Grid >
155- ) }
219+ ) ;
220+ } }
156221 </ FieldArray >
157222 </ FormControl >
158223 </ FormFieldGrid >
0 commit comments