diff options
author | eug-vs <eug-vs@keemail.me> | 2021-04-17 16:42:30 +0300 |
---|---|---|
committer | eug-vs <eug-vs@keemail.me> | 2021-04-17 16:42:30 +0300 |
commit | f3d3471e697d6ebede4fa584c8671fb686028381 (patch) | |
tree | 3df451176c8c9be81c6fe812d2a0a6be4aa918b0 | |
parent | 944996544868f403dbe807f4b8183ee482d31811 (diff) | |
download | commercel-ui-f3d3471e697d6ebede4fa584c8671fb686028381.tar.gz |
refactor: move move filters to ServiceFilters
-rw-r--r-- | src/containers/Page.tsx | 62 | ||||
-rw-r--r-- | src/lib/ServiceFilters.tsx | 74 | ||||
-rw-r--r-- | src/lib/ServiceList.tsx | 44 |
3 files changed, 92 insertions, 88 deletions
diff --git a/src/containers/Page.tsx b/src/containers/Page.tsx index 69f3513..887e839 100644 --- a/src/containers/Page.tsx +++ b/src/containers/Page.tsx @@ -1,62 +1,30 @@ import React from 'react'; -import { useLocation } from 'react-router-dom'; import Paper from '../components/Paper'; import Button from '../components/Button'; -import { Action, Filter } from '../lib/ServiceContext'; -import { SelectBase } from '../components/Select'; +import { Action } from '../lib/ServiceContext'; interface Props { title?: string; actions?: Action[]; - filters?: Filter[]; - applyFilter?: (key: string, value: string) => void; - resetFilters?: () => void; + filters?: JSX.Element; className?: string; } const style = 'mb-2 flex justify-between md:flex-row md:items-center'; -const Page: React.FC<Props> = ({ title, actions, filters, applyFilter, resetFilters, className, children }) => { - const location = useLocation(); - - const handleFilterChange = (key: string) => (event: React.ChangeEvent<HTMLSelectElement>) => { - if (applyFilter) applyFilter(key, event.target.value); - }; - - return ( - <Paper className="xl:m-5"> - <div className={`${style} ${(actions?.length || 0) > 1 ? 'flex-col items-start' : 'flex-row items-center'}`}> - <span className="text-2xl font-bold">{title}</span> - <div className="flex"> - <div className="mr-6 flex items-center"> - {filters && location.search && ( - <span - onClick={resetFilters} - role="presentation" - className="underline mr-2 cursor-pointer" - > - Сбросить фильтры - </span> - )} - {filters?.map(filter => ( - <SelectBase - key={filter.key} - options={filter.options || []} - value={filter.value} - onChange={handleFilterChange(filter.key)} - /> - ))} - </div> - <div> - {actions?.map(action => (<Button {...action} key={action.name} size="sm">{action.name}</Button>))} - </div> - </div> - </div> - <div className={className}> - {children} +const Page: React.FC<Props> = ({ title, actions, filters, className, children }) => ( + <Paper className="xl:m-5"> + <div className={`${style} ${(actions?.length || 0) > 1 ? 'flex-col items-start' : 'flex-row items-center'}`}> + <span className="text-2xl font-bold">{title}</span> + <div className="flex"> + {filters} + {actions?.map(action => (<Button {...action} key={action.name} size="sm">{action.name}</Button>))} </div> - </Paper> - ); -}; + </div> + <div className={className}> + {children} + </div> + </Paper> +); export default Page; diff --git a/src/lib/ServiceFilters.tsx b/src/lib/ServiceFilters.tsx new file mode 100644 index 0000000..4a7f166 --- /dev/null +++ b/src/lib/ServiceFilters.tsx @@ -0,0 +1,74 @@ +import React, { useContext } from 'react'; +import { useHistory } from 'react-router-dom'; +import _ from 'lodash'; +import hooks from '../hooks/useAPIClient'; +import useQuery from '../hooks/useQuery'; +import ServiceContext, { Filter } from './ServiceContext'; +import { SelectBase } from '../components/Select'; + +const getOptionLabel = (item: any, filter: Filter) => { + const value = _.get(item, filter.as || filter.key); + return filter.transform ? filter.transform(value) : value; +}; + + +const ServiceFilters: React.FC = () => { + const service = useContext(ServiceContext); + const query = useQuery(); + const history = useHistory(); + const { data } = hooks[service.route].useList('', { revalidateOnMount: !_.isEmpty(query) }); + + const filters = service.filters?.map(filter => { + const options = _ + .uniqBy(data, filter.key) + .map((item: any) => ({ + key: _.get(item, filter.key), + label: getOptionLabel(item, filter), + })); + + // Add default option + options?.unshift({ + key: '-', + label: filter.label, + }); + + const value = _.get(query, filter.key) || '-'; + + return { ...filter, options, value }; + }); + + const handleFilterChange = (key: string) => (event: React.ChangeEvent<HTMLSelectElement>) => { + const { value } = event.target; + const updatedQuery = { ...query, [key]: value }; + if (value === '-') delete updatedQuery[key]; + + const queryString = new URLSearchParams(updatedQuery); + history.push(`${service.route}?${queryString}`); + }; + + const resetFilters = () => history.push(service.route); + + return ( + <div className="mr-6 flex items-center"> + {filters && !_.isEmpty(query) && ( + <span + onClick={resetFilters} + role="presentation" + className="underline mr-2 cursor-pointer" + > + Сбросить фильтры + </span> + )} + {filters?.map(filter => ( + <SelectBase + key={filter.key} + options={filter.options || []} + value={filter.value} + onChange={handleFilterChange(filter.key)} + /> + ))} + </div> + ); +}; + +export default ServiceFilters; diff --git a/src/lib/ServiceList.tsx b/src/lib/ServiceList.tsx index 9f6835a..ae17a9c 100644 --- a/src/lib/ServiceList.tsx +++ b/src/lib/ServiceList.tsx @@ -4,46 +4,20 @@ import _ from 'lodash'; import Page from '../containers/Page'; import ListTable from '../components/ListTable'; import hooks from '../hooks/useAPIClient'; -import ServiceContext, { Filter } from './ServiceContext'; -import useQuery from '../hooks/useQuery'; - -const getOptionLabel = (item: any, filter: Filter) => { - const value = _.get(item, filter.as || filter.key); - return filter.transform ? filter.transform(value) : value; -}; +import ServiceContext from './ServiceContext'; +import ServiceFilters from './ServiceFilters'; const ServiceList: React.FC = () => { const service = useContext(ServiceContext); const history = useHistory(); const location = useLocation(); - const query = useQuery(); const { data } = hooks[service.route].useList(location.search); - const { data: unfilteredData } = hooks[service.route].useList('', { revalidateOnMount: !!location.search }); const actions = service.actions || [{ name: 'Добавить', route: `/${service.route}/add${location.search}`, }]; - const filters = service.filters?.map(filter => { - const options = _ - .uniqBy(unfilteredData, filter.key) - .map((item: any) => ({ - key: _.get(item, filter.key), - label: getOptionLabel(item, filter), - })); - - // Add default option - options?.unshift({ - key: '-', - label: filter.label, - }); - - const value = _.get(query, filter.key); - - return { ...filter, options, value }; - }); - const handleRowClick = (item: any) => { const route = service.rowLink ? service.rowLink(item) @@ -52,23 +26,11 @@ const ServiceList: React.FC = () => { history.push(route); }; - const applyFilter = (key: string, value: string) => { - const updatedQuery = { ...query, [key]: value }; - if (value === '-') delete updatedQuery[key]; - - const queryString = new URLSearchParams(updatedQuery); - history.push(`${service.route}?${queryString}`); - }; - - const resetFilters = () => history.push(service.route); - return ( <Page title={service.name} actions={actions} - filters={filters} - applyFilter={applyFilter} - resetFilters={resetFilters} + filters={<ServiceFilters />} > <ListTable items={data} fields={service.tableFields} handleRowClick={handleRowClick} /> </Page> |