Files
payload/src/admin/components/elements/WhereBuilder/index.tsx
Jessica Boezwinkle d2571fa798 elements to TS
2020-11-23 17:44:57 -05:00

161 lines
4.2 KiB
TypeScript

import React, { useState, useReducer } from 'react';
import { Props } from './types';
import useThrottledEffect from '../../../hooks/useThrottledEffect';
import Button from '../Button';
import reducer from './reducer';
import Condition from './Condition';
import fieldTypes from './field-types';
import flattenTopLevelFields from '../../../../utilities/flattenTopLevelFields';
import './index.scss';
const baseClass = 'where-builder';
const validateWhereQuery = (query) => {
if (query.or.length > 0 && query.or[0].and && query.or[0].and.length > 0) {
return query;
}
return null;
};
const reduceFields = (fields) => flattenTopLevelFields(fields).reduce((reduced, field) => {
if (typeof fieldTypes[field.type] === 'object') {
const formattedField = {
label: field.label,
value: field.name,
...fieldTypes[field.type],
props: {
...field,
},
};
return [
...reduced,
formattedField,
];
}
return reduced;
}, []);
const WhereBuilder: React.FC<Props> = (props) => {
const {
collection,
collection: {
labels: {
plural,
} = {},
} = {},
handleChange,
} = props;
const [where, dispatchWhere] = useReducer(reducer, []);
const [reducedFields] = useState(() => reduceFields(collection.fields));
useThrottledEffect(() => {
let whereQuery = {
or: [],
};
if (where) {
whereQuery.or = where.map((or) => or.reduce((conditions, condition) => {
const { field, operator, value } = condition;
if (field && operator && value) {
return {
and: [
...conditions.and,
{
[field]: {
[operator]: value,
},
},
],
};
}
return conditions;
}, {
and: [],
}));
}
whereQuery = validateWhereQuery(whereQuery);
if (typeof handleChange === 'function') handleChange(whereQuery);
}, 500, [where, handleChange]);
return (
<div className={baseClass}>
{where.length > 0 && (
<React.Fragment>
<div className={`${baseClass}__label`}>
Filter
{' '}
{plural}
{' '}
where
</div>
<ul className={`${baseClass}__or-filters`}>
{where.map((or, orIndex) => (
<li key={orIndex}>
{orIndex !== 0 && (
<div className={`${baseClass}__label`}>
Or
</div>
)}
<ul className={`${baseClass}__and-filters`}>
{or && or.map((_, andIndex) => (
<li key={andIndex}>
{andIndex !== 0 && (
<div className={`${baseClass}__label`}>
And
</div>
)}
<Condition
value={where[orIndex][andIndex]}
orIndex={orIndex}
andIndex={andIndex}
key={andIndex}
fields={reducedFields}
dispatch={dispatchWhere}
/>
</li>
))}
</ul>
</li>
))}
</ul>
<Button
className={`${baseClass}__add-or`}
icon="plus"
buttonStyle="icon-label"
iconPosition="left"
iconStyle="with-border"
onClick={() => dispatchWhere({ type: 'add' })}
>
Or
</Button>
</React.Fragment>
)}
{where.length === 0 && (
<div className={`${baseClass}__no-filters`}>
<div className={`${baseClass}__label`}>No filters set</div>
<Button
className={`${baseClass}__add-first-filter`}
icon="plus"
buttonStyle="icon-label"
iconPosition="left"
iconStyle="with-border"
onClick={() => dispatchWhere({ type: 'add' })}
>
Add filter
</Button>
</div>
)}
</div>
);
};
export default WhereBuilder;