@muvehealth/fixins
Version:
Component library for Muvehealth
183 lines (171 loc) • 5.12 kB
Flow
// @flow
import React, { PureComponent } from 'react'
import any from 'ramda/src/any'
import append from 'ramda/src/append'
import equals from 'ramda/src/equals'
import map from 'ramda/src/map'
import pathOr from 'ramda/src/pathOr'
import prop from 'ramda/src/prop'
import propOr from 'ramda/src/propOr'
import reject from 'ramda/src/reject'
import uniq from 'ramda/src/uniq'
import Box from '../../elements/Box'
import Checkbox from '../../elements/Checkbox'
import ErrorMessage from '../../elements/ErrorMessage'
import Grid from '../../elements/Grid'
import Label from '../../elements/Label'
import { isNotEmptyOrNotNil } from '../../utils'
import { type EventType, type InputType, type MetaType } from '../../types'
const checkboxGridModifierProps = (modifier, columns) => {
switch (modifier) {
case 'vertical':
return null
default:
return {
gridTemplateColumns: [
'1fr',
`repeat(${columns != null ? columns : 4}, 1fr)`,
`repeat(${columns != null ? columns : 4}, 1fr)`,
],
gridTemplateRows: [
`repeat(${columns != null ? columns : 4}, 1fr)`,
'1fr',
'1fr',
],
}
}
}
type Props = {
change?: (string | () => string, Array<string> | () => Array<string>) => void,
columns?: number,
input?: InputType,
gridStyles?: {},
label: string,
labelColor?: ?string,
labelModifier?: ?string,
labelTextStyle?: string,
meta?: MetaType,
modifier?: string,
noLabel?: boolean,
onChange?: ?(boolean, Array<string>) => void,
onChangeDouble?: ?(boolean, Array<string>) => void,
readOnly?: boolean,
values: Array<{
label: string,
value: string,
id?: ?string,
}>,
}
type State = {
values: Array<string>,
}
class CheckboxGroup extends PureComponent<Props, State> {
static defaultProps = {
change: undefined,
columns: 4,
gridStyles: undefined,
input: undefined,
labelColor: undefined,
labelModifier: undefined,
labelTextStyle: '',
meta: undefined,
modifier: 'horizontal',
noLabel: false,
onChange: undefined,
onChangeDouble: undefined,
readOnly: false,
}
// eslint-disable-next-line react/no-unused-state
state = { values: [] }
componentWillMount() {
this.setState((state, props) => {
const { change, input } = props
const inputVals = pathOr([], ['input', 'value'], props)
const uniqVals = uniq(inputVals)
if (input && change && uniqVals !== inputVals) {
change(input.name, uniqVals)
}
return {
values: uniqVals,
}
})
}
handleOnChange = (e: EventType) => {
const { target } = e
this.setState((state, props) => {
let newValues = state.values
const { change, input, onChange, onChangeDouble } = props
if (target && target.checked && any(equals(target.value), newValues)) {
newValues = state.values
} else if (target && target.checked) {
newValues = append(target.value, newValues)
} else if (target && !target.checked) {
newValues = reject(equals(target.value), newValues)
}
if (change && input) {
change(input.name, newValues)
}
if (onChangeDouble != null) {
onChangeDouble(target.checked, newValues)
} else if (onChange) {
onChange(target.checked, newValues)
}
return {
values: uniq(newValues),
}
})
}
render() {
const { columns, input, label, labelColor, labelModifier, labelTextStyle,
meta, modifier, noLabel, onChange, onChangeDouble,
readOnly, values, gridStyles, ...styles
} = this.props
return (
<Box {...styles}>
<Label
color={labelColor}
fontSize={2}
hidden={noLabel}
htmlFor={prop('name', input)}
mb={4}
textStyle={labelModifier === 'decal' ? 'uppercase' : labelTextStyle}
modifier={labelModifier}
>
{label}
</Label>
<Grid
gridColumnGap={3}
gridRowGap={4}
{...checkboxGridModifierProps(modifier, columns)}
// $FlowFixMe: Dont want to limit styled-system props
{...gridStyles}
>
{ map(({ label: optionLabel, value: optionValue }) => (
<Checkbox
defaultChecked={any(equals(optionValue), propOr([], 'value', input))}
id={`${prop('name', input)}-${optionLabel}`}
key={optionLabel}
label={optionLabel}
name={prop('name', input)}
onFocus={prop('onFocus', input)}
onChange={this.handleOnChange}
onBlur={this.handleOnChange}
readOnly={readOnly === true}
value={optionValue}
/>
), values)
}
</Grid>
{ prop('touched', meta) === true && isNotEmptyOrNotNil(prop('error', meta))
&& (
<ErrorMessage
message={prop('error', meta)}
maxWidth={116}
/>
)
}
</Box>
)
}
}
export default CheckboxGroup