Skip to content

Instantly share code, notes, and snippets.

@aderbas
Last active July 29, 2020 18:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aderbas/45803580f171b4bc49dba337398e7594 to your computer and use it in GitHub Desktop.
Save aderbas/45803580f171b4bc49dba337398e7594 to your computer and use it in GitHub Desktop.
Checklist selector with Material-UI
/**
* Checklist selector with Material-UI
* @author: Aderbal Nunes <aderbalnunes@gmail.com>
* @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