Refactor multiple choice field widget

This commit is contained in:
dominik-zeglen 2020-01-16 14:44:16 +01:00
parent 15470221c2
commit 0a58c3a5e1
4 changed files with 200 additions and 46 deletions

View file

@ -0,0 +1,145 @@
import React from "react";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import TextField from "@material-ui/core/TextField";
import makeStyles from "@material-ui/core/styles/makeStyles";
import { FormattedMessage } from "react-intl";
import { toggle } from "@saleor/utils/lists";
import { MultiAutocompleteChoiceType } from "../MultiAutocompleteSelectField";
import Link from "../Link";
import Checkbox from "../Checkbox";
import Hr from "../Hr";
import { IFilterElement } from "./types";
import { FilterReducerAction } from "./reducer";
interface FilterAutocompleteFieldProps {
displayValues: Record<string, MultiAutocompleteChoiceType[]>;
filterField: IFilterElement<string>;
setDisplayValues: (
values: Record<string, MultiAutocompleteChoiceType[]>
) => void;
onFilterPropertyChange: React.Dispatch<FilterReducerAction<string>>;
}
const useStyles = makeStyles(
theme => ({
hr: {
backgroundColor: theme.palette.primary.light,
margin: theme.spacing(1, 0)
},
input: {
padding: "12px 0 9px 12px"
},
inputContainer: {
marginBottom: theme.spacing(1)
},
option: {
left: -theme.spacing(0.5),
position: "relative"
},
showMore: {
display: "inline-block",
marginTop: theme.spacing(1)
}
}),
{ name: "FilterAutocompleteField" }
);
const FilterAutocompleteField: React.FC<FilterAutocompleteFieldProps> = ({
displayValues,
filterField,
setDisplayValues,
onFilterPropertyChange
}) => {
const classes = useStyles({});
const fieldDisplayValues = displayValues[filterField.name];
const availableOptions = filterField.options.filter(option =>
fieldDisplayValues.every(
displayValue => displayValue.value !== option.value
)
);
const displayHr = !(
(fieldDisplayValues.length === 0 && availableOptions.length > 0) ||
(availableOptions.length === 0 && fieldDisplayValues.length > 0)
);
const handleChange = (option: MultiAutocompleteChoiceType) => {
onFilterPropertyChange({
payload: {
name: filterField.name,
update: {
value: toggle(option.value, filterField.value, (a, b) => a === b)
}
},
type: "set-property"
});
setDisplayValues({
...displayValues,
[filterField.name]: toggle(
option,
fieldDisplayValues,
(a, b) => a.value === b.value
)
});
};
return (
<div>
<TextField
className={classes.inputContainer}
fullWidth
name={filterField.name + "_autocomplete"}
InputProps={{
classes: {
input: classes.input
}
}}
onChange={event => filterField.onSearchChange(event.target.value)}
/>
{fieldDisplayValues.map(displayValue => (
<div className={classes.option} key={displayValue.value}>
<FormControlLabel
control={
<Checkbox
checked={filterField.value.includes(displayValue.value)}
/>
}
label={displayValue.label}
name={filterField.name}
onChange={() => handleChange(displayValue)}
/>
</div>
))}
{displayHr && <Hr className={classes.hr} />}
{availableOptions.map(option => (
<div className={classes.option} key={option.value}>
<FormControlLabel
control={
<Checkbox checked={filterField.value.includes(option.value)} />
}
label={option.label}
name={filterField.name}
onChange={() => handleChange(option)}
/>
</div>
))}
{filterField.hasMore && (
<Link
className={classes.showMore}
underline
onClick={filterField.onFetchMore}
>
<FormattedMessage
defaultMessage="Show more"
description="search results"
/>
</Link>
)}
</div>
);
};
FilterAutocompleteField.displayName = "FilterAutocompleteField";
export default FilterAutocompleteField;

View file

@ -22,9 +22,11 @@ import FormSpacer from "../FormSpacer";
import MultiAutocompleteSelectField, {
MultiAutocompleteChoiceType
} from "../MultiAutocompleteSelectField";
import Link from "../Link";
import { IFilter, FieldType, FilterType } from "./types";
import Arrow from "./Arrow";
import { FilterReducerAction } from "./reducer";
import FilterAutocompleteField from "./FilterAutocompleteField";
export interface FilterContentProps<T extends string = string> {
currencySymbol: string;
@ -428,51 +430,57 @@ const FilterContent: React.FC<FilterContentProps> = ({
))}
{filterField.type === FieldType.autocomplete &&
filterField.multiple && (
<MultiAutocompleteSelectField
displayValues={
autocompleteDisplayValues[filterField.name]
}
label={filterField.label}
choices={filterField.options}
name={filterField.name}
value={filterField.value}
// helperText={intl.formatMessage({
// defaultMessage:
// "*Optional. Adding product to collection helps users find it.",
// description: "field is optional"
// })}
onChange={createMultiAutocompleteSelectHandler(
event =>
onFilterPropertyChange({
payload: {
name: filterField.name,
update: {
value: toggle(
event.target.value,
filterField.value,
(a, b) => a === b
)
}
},
type: "set-property"
}),
value =>
setAutocompleteDisplayValues({
...autocompleteDisplayValues,
[filterField.name]: toggle(
value[0],
autocompleteDisplayValues[filterField.name],
(a, b) => a.value === b.value
)
}),
[],
filterField.options
)}
fetchChoices={filterField.onSearchChange}
loading={filterField.loading}
data-tc={filterField.name}
key={filterField.name}
<FilterAutocompleteField
displayValues={autocompleteDisplayValues}
filterField={filterField}
setDisplayValues={setAutocompleteDisplayValues}
onFilterPropertyChange={onFilterPropertyChange}
/>
// <MultiAutocompleteSelectField
// displayValues={
// autocompleteDisplayValues[filterField.name]
// }
// label={filterField.label}
// choices={filterField.options}
// name={filterField.name}
// value={filterField.value}
// // helperText={intl.formatMessage({
// // defaultMessage:
// // "*Optional. Adding product to collection helps users find it.",
// // description: "field is optional"
// // })}
// onChange={createMultiAutocompleteSelectHandler(
// event =>
// onFilterPropertyChange({
// payload: {
// name: filterField.name,
// update: {
// value: toggle(
// event.target.value,
// filterField.value,
// (a, b) => a === b
// )
// }
// },
// type: "set-property"
// }),
// value =>
// setAutocompleteDisplayValues({
// ...autocompleteDisplayValues,
// [filterField.name]: toggle(
// value[0],
// autocompleteDisplayValues[filterField.name],
// (a, b) => a.value === b.value
// )
// }),
// [],
// filterField.options
// )}
// fetchChoices={filterField.onSearchChange}
// loading={filterField.loading}
// data-tc={filterField.name}
// key={filterField.name}
// />
)}
</div>
)}

View file

@ -26,7 +26,8 @@ function merge<T extends string>(
if (!!prevFilter) {
return {
...newFilter,
active: prevFilter.active
active: prevFilter.active,
value: prevFilter.value
};
}

View file

@ -44,7 +44,7 @@ const Link: React.FC<LinkProps> = props => {
return (
<Typography
component="a"
className={classNames({
className={classNames(className, {
[classes.root]: true,
[classes[color]]: true,
[classes.underline]: underline