Skip to content

Commit 19c0951

Browse files
committed
refactor(features): add list filter
see #250
1 parent c6470db commit 19c0951

File tree

7 files changed

+299
-12
lines changed

7 files changed

+299
-12
lines changed

src/Events/EventFunctions/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,7 @@ class EventFunctionList extends Component {
390390
page={page}
391391
itemCount={total}
392392
loading={loading}
393-
// onFilter={this.handleListFilter}
394-
onNotify={this.openNotificationForm}
393+
// onFilter={this.handleListFiltersFormOpen}
395394
onShare={this.handleListShare}
396395
onRefresh={this.handleListRefresh}
397396
onPaginate={this.handleListPaginate}

src/GeographicalFeatures/AdministrativeAreas/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,7 @@ class AdministrativeAreaList extends Component {
373373
page={page}
374374
itemCount={total}
375375
loading={loading}
376-
// onFilter={this.handleListFilter}
377-
onNotify={this.openNotificationForm}
376+
// onFilter={this.handleListFiltersFormOpen}
378377
onShare={this.handleListShare}
379378
onRefresh={this.handleListRefresh}
380379
onPaginate={this.handleListPaginate}

src/GeographicalFeatures/AdministrativeLevels/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,7 @@ class AdministrativeLevelList extends Component {
369369
page={page}
370370
itemCount={total}
371371
loading={loading}
372-
// onFilter={this.handleListFilter}
373-
onNotify={this.openNotificationForm}
372+
// onFilter={this.handleListFiltersFormOpen}
374373
onShare={this.handleListShare}
375374
onRefresh={this.handleListRefresh}
376375
onPaginate={this.handleListPaginate}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Connect, reduxActions } from '@codetanzania/ewea-api-states';
4+
import { httpActions } from '@codetanzania/ewea-api-client';
5+
import { Button, Form } from 'antd';
6+
import get from 'lodash/get';
7+
import isFunction from 'lodash/isFunction';
8+
import SearchableSelectInput from '../../../components/SearchableSelectInput';
9+
10+
/* http actions */
11+
const { getAgencies, getFeatureTypes, getAdministrativeAreas } = httpActions;
12+
13+
/* state actions */
14+
const { clearFeatureFilters, filterFeatures } = reduxActions;
15+
16+
/* ui */
17+
const labelCol = {
18+
xs: { span: 24 },
19+
sm: { span: 24 },
20+
md: { span: 24 },
21+
lg: { span: 24 },
22+
xl: { span: 24 },
23+
xxl: { span: 24 },
24+
};
25+
const wrapperCol = {
26+
xs: { span: 24 },
27+
sm: { span: 24 },
28+
md: { span: 24 },
29+
lg: { span: 24 },
30+
xl: { span: 24 },
31+
xxl: { span: 24 },
32+
};
33+
34+
/**
35+
* @function
36+
* @name FeatureFiltersForm
37+
* @description Feature filters form
38+
* @param {object} props Filter props
39+
* @param {object} props.filter Filter object from the store
40+
* @param {object} props.cached Cached values for lazy loaded values
41+
* @param {Function} props.onCache Cache value callback
42+
* @param {Function} props.onClearCache Clear cached values callback
43+
* @param {Function} props.onCancel Close filter form callback
44+
* @returns {object} FeatureFiltersForm component
45+
* @author lally elias <lallyelias87@gmail.com>
46+
* @license MIT
47+
* @since 0.1.0
48+
* @version 0.1.0
49+
* @static
50+
* @public
51+
* @example
52+
*
53+
* <FeatureFiltersForm
54+
* filter={filter}
55+
* cached={cached}
56+
* onCache={this.handleOnCache}
57+
* onClearCache={this.handleOnClearCache}
58+
* onCancel={this.handleCloseFilterForm}
59+
* />
60+
*/
61+
const FeatureFiltersForm = ({
62+
filter,
63+
cached,
64+
onCache,
65+
onClearCache,
66+
onCancel,
67+
}) => {
68+
// form finish(submit) handler
69+
const onFinish = (values) => {
70+
// TODO: clear false values
71+
filterFeatures(values);
72+
onCancel();
73+
};
74+
75+
/**
76+
* @function
77+
* @name onClearFilters
78+
* @description On clear form filters callback
79+
*
80+
* @version 0.1.0
81+
* @since 0.1.0
82+
*/
83+
const onClearFilters = () => {
84+
clearFeatureFilters();
85+
if (isFunction(onClearCache)) {
86+
onClearCache();
87+
}
88+
onCancel();
89+
};
90+
91+
return (
92+
<Form
93+
onFinish={onFinish}
94+
labelCol={labelCol}
95+
wrapperCol={wrapperCol}
96+
autoComplete="off"
97+
initialValues={{
98+
...filter,
99+
}}
100+
>
101+
{/* start:feature type filter */}
102+
<Form.Item
103+
label="By Type"
104+
title="Critical infrastructure type e.g Hospital"
105+
name={['relations.type']}
106+
>
107+
<SearchableSelectInput
108+
onSearch={(optns = {}) => {
109+
return getFeatureTypes(optns);
110+
}}
111+
optionLabel={(type) => get(type, 'strings.name.en')}
112+
optionValue="_id"
113+
mode="multiple"
114+
onCache={(type) => onCache({ 'relations.type': type })}
115+
initialValue={get(cached, 'relations.type')}
116+
/>
117+
</Form.Item>
118+
{/* end:feature type filter */}
119+
120+
{/* start:feature area filter */}
121+
<Form.Item
122+
label="By Area"
123+
title="Critical infrastructure area e.g Dar es Salaam"
124+
name={['relations.area']}
125+
>
126+
<SearchableSelectInput
127+
onSearch={(optns = {}) => {
128+
return getAdministrativeAreas(optns);
129+
}}
130+
optionLabel={(area) => {
131+
return get(area, 'strings.name.en');
132+
}}
133+
optionValue="_id"
134+
mode="multiple"
135+
onCache={(area) => onCache({ 'relations.area': area })}
136+
initialValue={get(cached, 'relations.area', [])}
137+
/>
138+
</Form.Item>
139+
{/* end:feature area filter */}
140+
141+
{/* start:feature custodians filter */}
142+
<Form.Item
143+
label="By Custodian"
144+
title="Responsible Agencies e.g Police Force"
145+
name={['relations.custodians']}
146+
>
147+
<SearchableSelectInput
148+
onSearch={(optns = {}) => {
149+
return getAgencies(optns);
150+
}}
151+
optionLabel={(custodian) => get(custodian, 'name')}
152+
optionValue="_id"
153+
mode="multiple"
154+
onCache={(custodians) =>
155+
onCache({ 'relations.custodians': custodians })
156+
}
157+
initialValue={get(cached, 'relations.custodians', [])}
158+
/>
159+
</Form.Item>
160+
{/* end:feature custodians filter */}
161+
162+
{/* start:form actions */}
163+
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: 'right' }}>
164+
<Button onClick={onCancel}>Cancel</Button>
165+
<Button style={{ marginLeft: 8 }} onClick={onClearFilters}>
166+
Clear
167+
</Button>
168+
<Button style={{ marginLeft: 8 }} type="primary" htmlType="submit">
169+
Filter
170+
</Button>
171+
</Form.Item>
172+
{/* end:form actions */}
173+
</Form>
174+
);
175+
};
176+
177+
FeatureFiltersForm.propTypes = {
178+
filter: PropTypes.objectOf(
179+
PropTypes.shape({
180+
type: PropTypes.arrayOf(
181+
PropTypes.shape({
182+
_id: PropTypes.string,
183+
})
184+
),
185+
area: PropTypes.arrayOf(
186+
PropTypes.shape({
187+
_id: PropTypes.string,
188+
})
189+
),
190+
custodians: PropTypes.arrayOf(
191+
PropTypes.shape({
192+
_id: PropTypes.string,
193+
})
194+
),
195+
})
196+
),
197+
cached: PropTypes.shape({
198+
type: PropTypes.arrayOf(
199+
PropTypes.shape({
200+
_id: PropTypes.string,
201+
})
202+
),
203+
}),
204+
onCache: PropTypes.func.isRequired,
205+
onClearCache: PropTypes.func.isRequired,
206+
onCancel: PropTypes.func.isRequired,
207+
};
208+
209+
FeatureFiltersForm.defaultProps = {
210+
filter: null,
211+
cached: null,
212+
};
213+
214+
export default Connect(FeatureFiltersForm, {
215+
filter: 'dispatches.filter',
216+
});

src/GeographicalFeatures/CriticalFacilities/Form/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ const FeatureForm = ({ feature, isEditForm, posting, onCancel }) => {
118118
<Col span={11}>
119119
<Form.Item
120120
label="Type"
121-
title="Administrative type e.g Hospital"
121+
title="Critical infrastructure type e.g Hospital"
122122
name={['relations', 'type', '_id']}
123123
rules={[
124124
{
125125
required: true,
126-
message: 'Administrative type is required',
126+
message: 'Critical infrastructure type is required',
127127
},
128128
]}
129129
>

src/GeographicalFeatures/CriticalFacilities/index.js

+77-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import get from 'lodash/get';
99
import map from 'lodash/map';
1010
import Topbar from '../../components/Topbar';
1111
import FeatureForm from './Form';
12+
import FeatureFiltersForm from './Filters';
1213
import NotificationForm from '../../components/NotificationForm';
1314
import { notifyError, notifySuccess, truncateString } from '../../util';
1415
import ItemList from '../../components/List';
@@ -120,10 +121,12 @@ class FeatureList extends Component {
120121
constructor(props) {
121122
super(props);
122123
this.state = {
124+
showFilters: false,
123125
isEditForm: false,
124126
showNotificationForm: false,
125127
notificationSubject: undefined,
126128
notificationBody: undefined,
129+
cached: null,
127130
};
128131
}
129132

@@ -139,6 +142,34 @@ class FeatureList extends Component {
139142
getFeatures();
140143
}
141144

145+
/**
146+
* @function handleOnCache
147+
* @name handleOnCache
148+
* @description Handle updating cache
149+
* @param {object} cached values cached
150+
*
151+
* @version 0.1.0
152+
* @since 0.1.0
153+
*/
154+
handleOnCache = (cached) => {
155+
const { cached: previousCached } = this.state;
156+
const values = { ...previousCached, ...cached };
157+
this.setState({ cached: values });
158+
};
159+
160+
/**
161+
* @function handleOnClearCache
162+
* @name handleOnClearCache
163+
* @description Handle clearing cache
164+
*
165+
* @version 0.1.0
166+
* @since 0.1.0
167+
*/
168+
handleOnClearCache = () => {
169+
// TODO: support keys to clear specific cached value
170+
this.setState({ cached: null });
171+
};
172+
142173
/**
143174
* @function handleListSearch
144175
* @name handleListSearch
@@ -329,6 +360,30 @@ class FeatureList extends Component {
329360
this.setState({ showNotificationForm: false });
330361
};
331362

363+
/**
364+
* @function handleNotificationFormClose
365+
* @name handleNotificationFormClose
366+
* @description Handle filters form opening
367+
*
368+
* @version 0.1.0
369+
* @since 0.1.0
370+
*/
371+
handleListFiltersFormOpen = () => {
372+
this.setState({ showFilters: true });
373+
};
374+
375+
/**
376+
* @function handleNotificationFormClose
377+
* @name handleNotificationFormClose
378+
* @description Handle filters form closing
379+
*
380+
* @version 0.1.0
381+
* @since 0.1.0
382+
*/
383+
handleListFiltersFormClose = () => {
384+
this.setState({ showFilters: false });
385+
};
386+
332387
/**
333388
* @function render
334389
* @name render
@@ -353,6 +408,8 @@ class FeatureList extends Component {
353408

354409
// states
355410
const {
411+
showFilters,
412+
cached,
356413
isEditForm,
357414
showNotificationForm,
358415
notificationSubject,
@@ -389,8 +446,7 @@ class FeatureList extends Component {
389446
page={page}
390447
itemCount={total}
391448
loading={loading}
392-
// onFilter={this.handleListFilter}
393-
onNotify={this.openNotificationForm}
449+
onFilter={this.handleListFiltersFormOpen}
394450
onShare={this.handleListShare}
395451
onRefresh={this.handleListRefresh}
396452
onPaginate={this.handleListPaginate}
@@ -488,6 +544,25 @@ class FeatureList extends Component {
488544
</Modal>
489545
{/* end: notification modal */}
490546

547+
{/* start: filter modal */}
548+
<Modal
549+
title="Filter Critical Infrastructures"
550+
visible={showFilters}
551+
className="FormModal"
552+
footer={null}
553+
onCancel={this.handleListFiltersFormClose}
554+
destroyOnClose
555+
maskClosable={false}
556+
>
557+
<FeatureFiltersForm
558+
cached={cached}
559+
onCache={this.handleOnCache}
560+
onCancel={this.handleListFiltersFormClose}
561+
onClearCache={this.handleOnClearCache}
562+
/>
563+
</Modal>
564+
{/* end: filter modal */}
565+
491566
{/* start: form modal */}
492567
<Modal
493568
title={

0 commit comments

Comments
 (0)