Skip to content

Commit 13e6a53

Browse files
samsharafrozenhelium
authored andcommitted
feat: implement functionality to validate local units
1 parent 0dffd52 commit 13e6a53

File tree

8 files changed

+182
-24
lines changed

8 files changed

+182
-24
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import { type GoApiResponse } from '#utils/restRequest';
4646
import i18n from './i18n.json';
4747
import styles from './styles.module.css';
4848

49-
type GetLocalUnitResponseType = GoApiResponse<'/api/v2/local-units/'>;
49+
type GetLocalUnitResponseType = GoApiResponse<'/api/v2/public-local-units/'>;
5050
const basePointPaint: CirclePaint = {
5151
'circle-radius': 5,
5252
'circle-color': COLOR_RED,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"namespace": "localUnitsTableActions",
3+
"strings": {
4+
"localUnitsEdit": "Edit",
5+
"localUnitsView": "View",
6+
"localUnitsDelete": "Delete",
7+
"localUnitsValidate": "Validate",
8+
"deleteLocalUnitHeading": "Delete Local Unit Confirmation",
9+
"deleteLocalUnitMessage": "Are you sure you want to delete \"{localUnitName}\"?",
10+
"validationMessage": "{localUnitName} was validated.",
11+
"validateLocalUnitHeading": "Validate Local Unit Confirmation",
12+
"validateLocalUnitMessage": "Are you sure you want to validate \"{localUnitName}\"?"
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { useCallback } from 'react';
2+
import { TableActions } from '@ifrc-go/ui';
3+
import { useTranslation } from '@ifrc-go/ui/hooks';
4+
import { resolveToString } from '@ifrc-go/ui/utils';
5+
6+
import DropdownMenuItem from '#components/DropdownMenuItem';
7+
import useAlert from '#hooks/useAlert';
8+
import {
9+
type GoApiResponse,
10+
useLazyRequest,
11+
} from '#utils/restRequest';
12+
13+
import i18n from './i18n.json';
14+
import styles from './styles.module.css';
15+
16+
export interface Props {
17+
localUnitName: string | null | undefined;
18+
localUnitId: number;
19+
isValidated: boolean;
20+
onActionSuccess: () => void;
21+
}
22+
23+
export type LocalUnitValidateResponsePostBody = GoApiResponse<'/api/v2/local-units/{id}/'>;
24+
25+
function LocalUnitsTableActions(props: Props) {
26+
const {
27+
localUnitName,
28+
localUnitId,
29+
isValidated,
30+
onActionSuccess,
31+
} = props;
32+
33+
const strings = useTranslation(i18n);
34+
const alert = useAlert();
35+
36+
const {
37+
pending: validateLocalUnitPending,
38+
trigger: validateLocalUnit,
39+
} = useLazyRequest({
40+
method: 'POST',
41+
url: '/api/v2/local-units/{id}/validate/',
42+
pathVariables: { id: localUnitId },
43+
// FIXME: typings should be fixed in the server
44+
body: () => ({} as never),
45+
onSuccess: (response) => {
46+
const validationMessage = resolveToString(
47+
strings.validationMessage,
48+
{ localUnitName: response.local_branch_name ?? response.english_branch_name },
49+
);
50+
alert.show(
51+
validationMessage,
52+
{ variant: 'success' },
53+
);
54+
onActionSuccess();
55+
},
56+
});
57+
58+
const handleLocalUnitValidate = useCallback(() => {
59+
// NOTE sending an empty post request to validate the local unit
60+
validateLocalUnit(null);
61+
}, [validateLocalUnit]);
62+
63+
return (
64+
<TableActions
65+
persistent
66+
extraActions={(
67+
<>
68+
<DropdownMenuItem
69+
type="link"
70+
to={undefined}
71+
>
72+
{strings.localUnitsEdit}
73+
</DropdownMenuItem>
74+
<DropdownMenuItem
75+
type="link"
76+
to={undefined}
77+
>
78+
{strings.localUnitsView}
79+
</DropdownMenuItem>
80+
{!(isValidated) && (
81+
<DropdownMenuItem
82+
persist
83+
name={undefined}
84+
type="confirm-button"
85+
variant="tertiary"
86+
className={styles.button}
87+
confirmHeading={strings.validateLocalUnitHeading}
88+
confirmMessage={resolveToString(
89+
strings.validateLocalUnitMessage,
90+
{ localUnitName },
91+
)}
92+
onConfirm={handleLocalUnitValidate}
93+
disabled={validateLocalUnitPending}
94+
>
95+
{strings.localUnitsValidate}
96+
</DropdownMenuItem>
97+
)}
98+
</>
99+
)}
100+
/>
101+
);
102+
}
103+
104+
export default LocalUnitsTableActions;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.button {
2+
padding: var(--go-ui-spacing-sm) var(--go-ui-spacing-lg);
3+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"localUnitsTableName": "Name",
66
"localUnitsTableAddress": "Address",
77
"localUnitsTableType": "Type",
8-
"localUnitsTableFocal": "Focal person",
8+
"localUnitsTableFocal": "Focal Person",
99
"localUnitsTablePhoneNumber": "Phone Number",
1010
"localUnitsTableEmail": "Email",
11-
"localUnitsTableValidate": "Validate"
11+
"localUnitsTableValidated": "Validated"
1212
}
1313
}

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

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { useMemo } from 'react';
1+
import {
2+
useEffect,
3+
useMemo,
4+
} from 'react';
5+
import { useOutletContext } from 'react-router-dom';
26
import {
37
Container,
48
Pager,
@@ -7,28 +11,32 @@ import {
711
import { useTranslation } from '@ifrc-go/ui/hooks';
812
import {
913
createBooleanColumn,
14+
createElementColumn,
1015
createStringColumn,
16+
numericIdSelector,
1117
} from '@ifrc-go/ui/utils';
1218
import { isDefined } from '@togglecorp/fujs';
1319

1420
import useFilterState from '#hooks/useFilterState';
21+
import { type CountryOutletContext } from '#utils/outletContext';
1522
import {
1623
type GoApiResponse,
1724
useRequest,
1825
} from '#utils/restRequest';
1926

2027
import { VALIDATED } from '../common';
28+
import LocalUnitsTableActions, { type Props as LocalUnitsTableActionsProps } from './LocalUnitTableActions';
2129

2230
import i18n from './i18n.json';
2331
import styles from './styles.module.css';
2432

33+
const PAGE_SIZE = 15;
34+
2535
type LocalUnitsTableResponse = GoApiResponse<'/api/v2/local-units/'>;
2636
type LocalUnitsTableListItem = NonNullable<LocalUnitsTableResponse['results']>[number];
2737

28-
const localUnitsKeySelector = (option: LocalUnitsTableListItem) => option.id;
29-
3038
interface Props {
31-
filter : {
39+
filter: {
3240
type?: number;
3341
search?: string;
3442
isValidated?: string;
@@ -37,23 +45,38 @@ interface Props {
3745

3846
function LocalUnitsTable(props: Props) {
3947
const {
40-
filter,
48+
filter: filterFromProps,
4149
} = props;
50+
4251
const strings = useTranslation(i18n);
52+
const { countryResponse } = useOutletContext<CountryOutletContext>();
4353

4454
const {
4555
limit,
4656
offset,
4757
page,
4858
setPage,
59+
filtered,
60+
filter,
61+
setFilter,
4962
} = useFilterState({
50-
filter: {},
51-
pageSize: 5,
63+
filter: {
64+
...filterFromProps,
65+
},
66+
pageSize: PAGE_SIZE,
5267
});
5368

69+
useEffect(() => {
70+
if (filterFromProps) {
71+
setFilter(filterFromProps);
72+
}
73+
}, [filterFromProps, setFilter]);
74+
5475
const {
5576
pending: localUnitsTablePending,
77+
error: localUnitsTableError,
5678
response: localUnitsTableResponse,
79+
retrigger: refetchLocalUnits,
5780
} = useRequest({
5881
url: '/api/v2/local-units/',
5982
preserveResponse: true,
@@ -64,20 +87,21 @@ function LocalUnitsTable(props: Props) {
6487
validated: isDefined(filter?.isValidated)
6588
? filter.isValidated === VALIDATED : undefined,
6689
search: filter?.search,
90+
country__iso3: isDefined(countryResponse?.iso3) ? countryResponse?.iso3 : undefined,
6791
},
6892
});
6993

7094
const columns = useMemo(
7195
() => ([
7296
createStringColumn<LocalUnitsTableListItem, number>(
73-
'english_branch_name',
97+
'branch_name',
7498
strings.localUnitsTableName,
75-
(item) => item.english_branch_name,
99+
(item) => item.local_branch_name ?? item.english_branch_name,
76100
),
77101
createStringColumn<LocalUnitsTableListItem, number>(
78-
'address_en',
102+
'address',
79103
strings.localUnitsTableAddress,
80-
(item) => item.address_en,
104+
(item) => item.address_loc ?? item.address_en,
81105
),
82106
createStringColumn<LocalUnitsTableListItem, number>(
83107
'type',
@@ -100,24 +124,34 @@ function LocalUnitsTable(props: Props) {
100124
(item) => item.email,
101125
),
102126
createBooleanColumn<LocalUnitsTableListItem, number>(
103-
'validate',
104-
strings.localUnitsTableValidate,
127+
'validated',
128+
strings.localUnitsTableValidated,
105129
(item) => item.validated,
106130
),
107-
].filter(isDefined)),
131+
createElementColumn<LocalUnitsTableListItem, number, LocalUnitsTableActionsProps>(
132+
'actions',
133+
'',
134+
LocalUnitsTableActions,
135+
(_, item) => ({
136+
localUnitId: item.id,
137+
isValidated: item.validated,
138+
localUnitName: item.local_branch_name ?? item.english_branch_name,
139+
onActionSuccess: refetchLocalUnits,
140+
}),
141+
),
142+
]),
108143
[
109144
strings.localUnitsTableAddress,
110145
strings.localUnitsTableName,
111146
strings.localUnitsTableType,
112147
strings.localUnitsTableFocal,
113148
strings.localUnitsTablePhoneNumber,
114149
strings.localUnitsTableEmail,
115-
strings.localUnitsTableValidate,
150+
strings.localUnitsTableValidated,
151+
refetchLocalUnits,
116152
],
117153
);
118154

119-
const isFilterApplied = isDefined(filter);
120-
121155
return (
122156
<Container
123157
footerContent={(
@@ -133,10 +167,11 @@ function LocalUnitsTable(props: Props) {
133167
>
134168
<Table
135169
pending={localUnitsTablePending}
136-
filtered={isFilterApplied}
170+
filtered={filtered}
171+
errored={isDefined(localUnitsTableError)}
137172
className={styles.table}
138173
columns={columns}
139-
keySelector={localUnitsKeySelector}
174+
keySelector={numericIdSelector}
140175
data={localUnitsTableResponse?.results?.filter(isDefined)}
141176
/>
142177
</Container>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ function NationalSocietyLocalUnits(props: Props) {
9191
response: localUnitListResponse,
9292
} = useRequest({
9393
skip: isNotDefined(countryResponse?.iso3),
94-
url: '/api/v2/local-units/',
94+
url: '/api/v2/public-local-units/',
9595
query: {
9696
limit,
9797
type__code: filter.type,
@@ -106,7 +106,7 @@ function NationalSocietyLocalUnits(props: Props) {
106106
response: localUnitsOptionsResponse,
107107
pending: localUnitsOptionsResponsePending,
108108
} = useRequest({
109-
url: '/api/v2/local-units/options/',
109+
url: '/api/v2/local-units-options/',
110110
});
111111

112112
const validationOptions = useMemo((): ValidationOptions[] => ([

packages/ui/src/utils/selectors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
export function booleanValueSelector(option: { value: boolean }) {
22
return option.value;
33
}
4+
45
export function numericValueSelector(option: { value: number }) {
56
return option.value;
67
}
8+
79
export function stringValueSelector(option: { value: string }) {
810
return option.value;
911
}

0 commit comments

Comments
 (0)