Last active
July 29, 2020 18:26
-
-
Save aderbas/45803580f171b4bc49dba337398e7594 to your computer and use it in GitHub Desktop.
Checklist selector with Material-UI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checklist selector with Material-UI | |
* @author: Aderbal Nunes <[email protected]> | |
* @since: 02/11/2019 | |
* | |
* usage: | |
* <MyChecklist | |
* list={[ | |
* {label: 'Foo', isChecked: false, id: 23}, | |
* {label: 'Bar', isChecked: false, id: 44}, | |
* ]} | |
* /> | |
* | |
* https://jsfiddle.net/aderbas/xeynLazj/ | |
*/ | |
import React, { PureComponent } from 'react'; | |
import PropTypes from 'prop-types'; | |
import {FormControlLabel,Box,Switch,Divider} from '@material-ui/core'; | |
const ChooserDispatch = React.createContext(null); | |
function reducer(state, action){ | |
switch(action.type){ | |
case 'togglesingle': | |
state.list = state.list.map(l => l.id === action.id?({...l, isChecked: !l.isChecked}):l); | |
// changes to parent | |
if(action.ch && typeof action.ch === 'function'){ | |
action.ch(state.list); | |
} | |
return { | |
...state, | |
checked: state.list.every(l => l.isChecked), | |
}; | |
case 'toggleall': | |
state.checked = !state.checked; | |
state.list = state.list.map(l => ({...l, isChecked: state.checked})); | |
// changes to parent | |
if(action.ch && typeof action.ch === 'function'){ | |
action.ch(state.list); | |
} | |
return { | |
...state | |
}; | |
case 'update': | |
return { | |
...state, | |
list: action.list | |
}; | |
default: | |
throw new Error(); | |
} | |
} | |
/** | |
* Confirm all | |
*/ | |
const ConfirmAll = ({...props}) => { | |
const dispatch = React.useContext(ChooserDispatch); | |
const {state,onChange} = props; | |
const checkAll = () => { | |
dispatch({type: 'toggleall', ch: onChange}); | |
}; | |
return ( | |
<React.Fragment> | |
<FormControlLabel | |
label="Check all" | |
control={ | |
<Switch | |
checked={state.checked} | |
onChange={checkAll} | |
/> | |
} | |
/> | |
<Divider /> | |
</React.Fragment> | |
) | |
}; | |
/** | |
* Render switch component | |
*/ | |
const SingleSwitch = ({...props}) => { | |
const dispatch = React.useContext(ChooserDispatch); | |
const {item,onChange} = props; | |
const onCheck = () => { | |
dispatch({type: 'togglesingle', id: item.id, ch: onChange}); | |
}; | |
return ( | |
<Switch | |
checked={item.isChecked} | |
onChange={onCheck} | |
/> | |
) | |
}; | |
/** | |
* Render component | |
*/ | |
const Render = ({...props}) => { | |
const [state, dispatch] = React.useReducer(reducer, { | |
checked: false, | |
list: props.list | |
}); | |
const {onChange,list} = props; | |
React.useEffect(() => { | |
dispatch({type: 'update', list: list}); | |
}, [list]); | |
if(!state.list || state.list.length <= 0){ | |
return null | |
} | |
return ( | |
<ChooserDispatch.Provider value={dispatch}> | |
<ConfirmAll state={state} /> | |
{state.list.map((current,k) => { | |
return ( | |
<div key={k}> | |
<FormControlLabel | |
onClick={() => onChange(current)} | |
control={ | |
<SingleSwitch | |
item={current} | |
/> | |
} | |
label={current.label} | |
/> | |
</div> | |
); | |
})} | |
</ChooserDispatch.Provider> | |
); | |
} | |
/** | |
* Main class | |
*/ | |
class MyChecklist extends PureComponent{ | |
render(){ | |
const {list, ...others} = this.props; | |
if(list.length <= 0) return null; | |
return ( | |
<Render | |
list={list} | |
{...others} | |
/> | |
); | |
}; | |
} | |
MyChecklist.propTypes = { | |
list: PropTypes.array.isRequired, | |
}; | |
export default MyChecklist; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment