feat: #1001 - builds a way to allow list view to search multiple fields
* make textfields searchable * shorten namings in placeholder function * chore: finishes listSearchableFields Co-authored-by: Christian Reichart <christian.reichart@camperboys.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import AnimateHeight from 'react-animate-height';
|
||||
import { fieldAffectsData } from '../../../../fields/config/types';
|
||||
import { FieldAffectingData, fieldAffectsData } from '../../../../fields/config/types';
|
||||
import SearchFilter from '../SearchFilter';
|
||||
import ColumnSelector from '../ColumnSelector';
|
||||
import WhereBuilder from '../WhereBuilder';
|
||||
@@ -29,6 +29,7 @@ const ListControls: React.FC<Props> = (props) => {
|
||||
fields,
|
||||
admin: {
|
||||
useAsTitle,
|
||||
listSearchableFields,
|
||||
},
|
||||
},
|
||||
} = props;
|
||||
@@ -37,6 +38,7 @@ const ListControls: React.FC<Props> = (props) => {
|
||||
const shouldInitializeWhereOpened = validateWhereQuery(params?.where);
|
||||
|
||||
const [titleField] = useState(() => fields.find((field) => fieldAffectsData(field) && field.name === useAsTitle));
|
||||
const [textFieldsToBeSearched] = useState(listSearchableFields ? () => fields.filter((field) => fieldAffectsData(field) && listSearchableFields.includes(field.name)) as FieldAffectingData[] : null);
|
||||
const [visibleDrawer, setVisibleDrawer] = useState<'where' | 'sort' | 'columns'>(shouldInitializeWhereOpened ? 'where' : undefined);
|
||||
|
||||
return (
|
||||
@@ -47,6 +49,7 @@ const ListControls: React.FC<Props> = (props) => {
|
||||
handleChange={handleWhereChange}
|
||||
modifySearchQuery={modifySearchQuery}
|
||||
fieldLabel={titleField && titleField.label ? titleField.label : undefined}
|
||||
listSearchableFields={textFieldsToBeSearched}
|
||||
/>
|
||||
<div className={`${baseClass}__buttons`}>
|
||||
<div className={`${baseClass}__buttons-wrap`}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import queryString from 'qs';
|
||||
import { Props } from './types';
|
||||
@@ -16,6 +16,7 @@ const SearchFilter: React.FC<Props> = (props) => {
|
||||
fieldName = 'id',
|
||||
fieldLabel = 'ID',
|
||||
modifySearchQuery = true,
|
||||
listSearchableFields,
|
||||
handleChange,
|
||||
} = props;
|
||||
|
||||
@@ -24,11 +25,32 @@ const SearchFilter: React.FC<Props> = (props) => {
|
||||
|
||||
const [search, setSearch] = useState(() => params?.where?.[fieldName]?.like || '');
|
||||
|
||||
const placeholder = useRef(`Search by ${fieldLabel}`);
|
||||
|
||||
const debouncedSearch = useDebounce(search, 300);
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedSearch !== params?.where?.[fieldName]?.like) {
|
||||
const newWhere = {
|
||||
if (debouncedSearch || params?.where) {
|
||||
let newWhere = listSearchableFields?.length > 0 ? {
|
||||
...(typeof params?.where === 'object' ? params.where : {}),
|
||||
or: [
|
||||
{
|
||||
[fieldName]: {
|
||||
like: debouncedSearch,
|
||||
},
|
||||
},
|
||||
...listSearchableFields.reduce<Record<string, unknown>[]>((prev, curr) => {
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
[curr.name]: {
|
||||
like: debouncedSearch,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, []),
|
||||
],
|
||||
} : {
|
||||
...(typeof params?.where === 'object' ? params.where : {}),
|
||||
[fieldName]: {
|
||||
like: debouncedSearch,
|
||||
@@ -36,12 +58,12 @@ const SearchFilter: React.FC<Props> = (props) => {
|
||||
};
|
||||
|
||||
if (!debouncedSearch) {
|
||||
delete newWhere[fieldName];
|
||||
newWhere = undefined;
|
||||
}
|
||||
|
||||
if (handleChange) handleChange(newWhere as Where);
|
||||
|
||||
if (modifySearchQuery && params?.where?.[fieldName]?.like !== newWhere?.[fieldName]?.like) {
|
||||
if (modifySearchQuery && queryString.stringify(params?.where) !== queryString.stringify(newWhere)) {
|
||||
history.replace({
|
||||
search: queryString.stringify({
|
||||
...params,
|
||||
@@ -51,13 +73,24 @@ const SearchFilter: React.FC<Props> = (props) => {
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [debouncedSearch, history, fieldName, params, handleChange, modifySearchQuery]);
|
||||
}, [debouncedSearch, history, fieldName, params, handleChange, modifySearchQuery, listSearchableFields]);
|
||||
|
||||
useEffect(() => {
|
||||
if (listSearchableFields?.length > 0) {
|
||||
placeholder.current = listSearchableFields.reduce<string>((prev, curr, i) => {
|
||||
if (i === listSearchableFields.length - 1) {
|
||||
return `${prev} or ${curr.label || curr.name}`;
|
||||
}
|
||||
return `${prev}, ${curr.label || curr.name}`;
|
||||
}, placeholder.current);
|
||||
}
|
||||
}, [listSearchableFields]);
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<input
|
||||
className={`${baseClass}__input`}
|
||||
placeholder={`Search by ${fieldLabel}`}
|
||||
placeholder={placeholder.current}
|
||||
type="text"
|
||||
value={search || ''}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { FieldAffectingData } from '../../../../fields/config/types';
|
||||
import { Where } from '../../../../types';
|
||||
|
||||
export type Props = {
|
||||
fieldName?: string,
|
||||
fieldLabel?: string,
|
||||
modifySearchQuery?: boolean
|
||||
listSearchableFields?: FieldAffectingData[]
|
||||
handleChange?: (where: Where) => void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user