Skip to content

Commit 658de2f

Browse files
committed
Use separate end-point for local units map
1 parent 47b1ae5 commit 658de2f

File tree

10 files changed

+200
-183
lines changed

10 files changed

+200
-183
lines changed

app/src/hooks/useFilterState.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ function useFilterState<FILTER extends object>(options: {
134134
[],
135135
);
136136

137+
const resetFilter = useCallback(
138+
() => {
139+
dispatch({ type: 'reset-filter' });
140+
},
141+
[],
142+
);
143+
137144
const setFilterField = useCallback(
138145
(...args: EntriesAsList<FILTER>) => {
139146
const [val, key] = args;
@@ -190,6 +197,8 @@ function useFilterState<FILTER extends object>(options: {
190197
setFilter,
191198
setFilterField,
192199

200+
resetFilter,
201+
193202
page: state.page,
194203
offset: pageSize * (debouncedState.page - 1),
195204
limit: pageSize,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"namespace": "nsLocalUnitsFilters",
3+
"strings": {
4+
"validated": "Validated",
5+
"notValidated": "Not Validated",
6+
"localUnitsFilterTypePlaceholder": "Type (All)",
7+
"localUnitsFilterTypeLabel": "Type",
8+
"localUnitsFilterClear": "Clear filters",
9+
"localUnitsFilterValidatedPlaceholder": "Validation (All)",
10+
"localUnitsFilterValidatedLabel": "Validation",
11+
"localUnitsFilterSearchLabel": "Search",
12+
"localUnitsFilterSearchPlaceholderLabel": "Search Local Units"
13+
}
14+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { useMemo } from 'react';
2+
import { SearchLineIcon } from '@ifrc-go/icons';
3+
import {
4+
Button,
5+
SelectInput,
6+
TextInput,
7+
} from '@ifrc-go/ui';
8+
import { useTranslation } from '@ifrc-go/ui/hooks';
9+
import {
10+
stringLabelSelector,
11+
stringNameSelector,
12+
} from '@ifrc-go/ui/utils';
13+
import { EntriesAsList } from '@togglecorp/toggle-form';
14+
15+
import { GoApiResponse } from '#utils/restRequest';
16+
17+
import {
18+
NOT_VALIDATED,
19+
VALIDATED,
20+
Validation,
21+
} from '../common';
22+
23+
import i18n from './i18n.json';
24+
import styles from './styles.module.css';
25+
26+
interface ValidationOption {
27+
key: Validation
28+
label: string;
29+
}
30+
31+
export interface FilterValue {
32+
search?: string | undefined;
33+
type?: number | undefined;
34+
isValidated?: Validation | undefined;
35+
}
36+
37+
type LocalUnitOptions = GoApiResponse<'/api/v2/local-units-options/'>;
38+
type LocalUnitType = LocalUnitOptions['type'][number];
39+
40+
function localUnitCodeSelector(localUnit: LocalUnitType) {
41+
return localUnit.code;
42+
}
43+
44+
function validationKeySelector(option: ValidationOption) {
45+
return option.key;
46+
}
47+
48+
interface Props {
49+
value: FilterValue;
50+
setFieldValue: (...entries: EntriesAsList<FilterValue>) => void;
51+
options: LocalUnitOptions | undefined;
52+
resetFilter: () => void;
53+
filtered: boolean;
54+
}
55+
56+
function Filters(props: Props) {
57+
const {
58+
value,
59+
setFieldValue: onChange,
60+
options,
61+
resetFilter,
62+
filtered,
63+
} = props;
64+
const strings = useTranslation(i18n);
65+
66+
const validationOptions = useMemo((): ValidationOption[] => ([
67+
{
68+
key: VALIDATED,
69+
label: strings.validated,
70+
},
71+
{
72+
key: NOT_VALIDATED,
73+
label: strings.notValidated,
74+
},
75+
]), [strings.validated, strings.notValidated]);
76+
77+
return (
78+
<>
79+
<SelectInput
80+
placeholder={strings.localUnitsFilterTypePlaceholder}
81+
label={strings.localUnitsFilterTypeLabel}
82+
name="type"
83+
value={value.type}
84+
onChange={onChange}
85+
keySelector={localUnitCodeSelector}
86+
labelSelector={stringNameSelector}
87+
options={options?.type}
88+
/>
89+
<SelectInput
90+
placeholder={strings.localUnitsFilterValidatedPlaceholder}
91+
label={strings.localUnitsFilterValidatedLabel}
92+
name="isValidated"
93+
value={value.isValidated}
94+
onChange={onChange}
95+
keySelector={validationKeySelector}
96+
labelSelector={stringLabelSelector}
97+
options={validationOptions}
98+
/>
99+
<TextInput
100+
name="search"
101+
label={strings.localUnitsFilterSearchLabel}
102+
placeholder={strings.localUnitsFilterSearchPlaceholderLabel}
103+
value={value.search}
104+
onChange={onChange}
105+
icons={<SearchLineIcon />}
106+
/>
107+
<div className={styles.actions}>
108+
<Button
109+
name={undefined}
110+
variant="secondary"
111+
onClick={resetFilter}
112+
disabled={!filtered}
113+
>
114+
{strings.localUnitsFilterClear}
115+
</Button>
116+
</div>
117+
</>
118+
);
119+
}
120+
121+
export default Filters;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.actions {
2+
display: flex;
3+
align-items: flex-end;
4+
}

app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsMap/styles.module.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
.local-units-map {
2-
display: flex;
3-
flex-direction: column;
4-
gap: var(--go-ui-spacing-md);
5-
62
.map-container-with-contact-details {
73
position: relative;
84

app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsTable/index.tsx

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import {
2-
useEffect,
3-
useMemo,
4-
} from 'react';
1+
import { useMemo } from 'react';
52
import { useOutletContext } from 'react-router-dom';
63
import {
74
Container,
@@ -28,29 +25,18 @@ import {
2825
} from '#utils/restRequest';
2926

3027
import { VALIDATED } from '../common';
28+
import Filters, { FilterValue } from '../Filters';
3129
import LocalUnitsTableActions, { type Props as LocalUnitsTableActionsProps } from './LocalUnitTableActions';
3230

3331
import i18n from './i18n.json';
3432
import styles from './styles.module.css';
3533

36-
const PAGE_SIZE = 15;
34+
const PAGE_SIZE = 12;
3735

3836
type LocalUnitsTableResponse = GoApiResponse<'/api/v2/local-units/'>;
3937
type LocalUnitsTableListItem = NonNullable<LocalUnitsTableResponse['results']>[number];
4038

41-
interface Props {
42-
filter: {
43-
type?: number;
44-
search?: string;
45-
isValidated?: string;
46-
}
47-
}
48-
49-
function LocalUnitsTable(props: Props) {
50-
const {
51-
filter: filterFromProps,
52-
} = props;
53-
39+
function LocalUnitsTable() {
5440
const strings = useTranslation(i18n);
5541
const { countryResponse } = useOutletContext<CountryOutletContext>();
5642

@@ -61,17 +47,17 @@ function LocalUnitsTable(props: Props) {
6147
setPage,
6248
filtered,
6349
filter,
64-
setFilter,
65-
} = useFilterState({
66-
filter: filterFromProps,
50+
setFilterField,
51+
rawFilter,
52+
resetFilter,
53+
} = useFilterState<FilterValue>({
54+
filter: {},
6755
pageSize: PAGE_SIZE,
6856
});
6957

70-
useEffect(() => {
71-
if (filterFromProps) {
72-
setFilter(filterFromProps);
73-
}
74-
}, [filterFromProps, setFilter]);
58+
const { response: localUnitsOptionsResponse } = useRequest({
59+
url: '/api/v2/local-units-options/',
60+
});
7561

7662
const {
7763
pending: localUnitsPending,
@@ -109,6 +95,7 @@ function LocalUnitsTable(props: Props) {
10995
'type',
11096
strings.localUnitsTableType,
11197
(item) => item.type_details.name,
98+
{ columnClassName: styles.type },
11299
),
113100
createStringColumn<LocalUnitsTableListItem, number>(
114101
'focal',
@@ -156,7 +143,7 @@ function LocalUnitsTable(props: Props) {
156143

157144
return (
158145
<Container
159-
footerContent={isDefined(localUnitsResponse)
146+
footerActions={isDefined(localUnitsResponse)
160147
&& isDefined(localUnitsResponse.count) && (
161148
<Pager
162149
activePage={page}
@@ -165,8 +152,17 @@ function LocalUnitsTable(props: Props) {
165152
onActivePageChange={setPage}
166153
/>
167154
)}
168-
footerClassName={styles.footerContent}
169155
contentViewType="vertical"
156+
withGridViewInFilter
157+
filters={(
158+
<Filters
159+
value={rawFilter}
160+
setFieldValue={setFilterField}
161+
options={localUnitsOptionsResponse}
162+
resetFilter={resetFilter}
163+
filtered={filtered}
164+
/>
165+
)}
170166
>
171167
<Table
172168
pending={localUnitsPending}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
.table {
22
display: flex;
3-
}
43

5-
.footer-content {
6-
align-self: end;
4+
.type {
5+
width: 8rem;
6+
min-width: 8rem;
7+
}
78
}

app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/i18n.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,8 @@
22
"namespace": "nationalSocietyLocalUnits",
33
"strings": {
44
"localUnitsMapTitle": "NS Local Units",
5-
"localUnitsFilterTypePlaceholder": "Type (All)",
6-
"localUnitsFilterTypeLabel": "Type",
7-
"localUnitsFilterValidatedPlaceholder": "Validation (All)",
8-
"localUnitsFilterValidatedLabel": "Validation",
9-
"validated": "Validated",
10-
"notValidated": "Not Validated",
11-
"localUnitsFilterSearchLabel": "Search",
12-
"localUnitsFilterSearchPlaceholderLabel": "Search Local Units",
135
"localUnitDetailAddressValue": "{address}, {city}, {country}",
146
"localUnitDetailType": "Type",
15-
"localUnitsFilterClear": "Clear Filters",
167
"localUnitsMapView": "Map view",
178
"localUnitsListView": "List view",
189
"editLocalUnitLink": "Add/Edit Local Units"

0 commit comments

Comments
 (0)