Skip to content

Commit 453a397

Browse files
committed
Improve styling of local unit form
1 parent fdc58a3 commit 453a397

File tree

20 files changed

+1034
-754
lines changed

20 files changed

+1034
-754
lines changed

.changeset/breezy-peaches-talk.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@ifrc-go/ui": patch
3+
---
4+
5+
- Add and export Legend component
6+
- Add FilterBar component
7+
- Update RawList to extend Key prop from react
8+
- Add a pageWidth option for Modal size
9+
- Update Container to use FilterBar
10+
- Remove withGridViewInFiterProp from Container, make it the default behavior
11+
- Add filterActions props in Container

.changeset/polite-houses-suffer.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"go-web-app": patch
3+
---
4+
5+
- Update Local Unit map, table and form to match the updated design
6+
- Add delete button in Local units table and form
7+
- Use filter prop in container and remove manual stylings
8+
- Update size of WikiLink to match height of other action items
9+
- Add error boundary to BaseMap component

app/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
"papaparse": "^5.4.1",
5454
"react": "^18.2.0",
5555
"react-dom": "^18.2.0",
56-
"react-error-boundary": "^4.0.13",
5756
"react-router-dom": "^6.18.0",
5857
"sanitize-html": "^2.10.0"
5958
},

app/src/components/domain/BaseMapPointInput/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ function BaseMapPointInput<NAME extends string>(props: Props<NAME>) {
103103
type: 'Point',
104104
coordinates: [value.lng, value.lat],
105105
},
106-
properties: {},
106+
properties: {
107+
radius: 10,
108+
},
107109
};
108110
},
109111
[value],
@@ -150,7 +152,7 @@ function BaseMapPointInput<NAME extends string>(props: Props<NAME>) {
150152
visibility: 'visible',
151153
},
152154
paint: {
153-
'circle-radius': 10,
155+
'circle-radius': ['get', 'radius'],
154156
'circle-color': COLOR_PRIMARY_RED,
155157
},
156158
}),
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"namespace": "localUnitDeleteButton",
3+
"strings": {
4+
"localUnitsDelete": "Delete",
5+
"deleteSuccessMessage": "{localUnitName} was deleted.",
6+
"deleteFailureMessage": "Failed to validate {localUnitName}",
7+
"deleteLocalUnitHeading": "Delete Local Unit Confirmation",
8+
"deleteLocalUnitMessage": "Are you sure you want to delete \"{localUnitName}\"?"
9+
}
10+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import {
2+
ButtonVariant,
3+
ConfirmButton,
4+
} from '@ifrc-go/ui';
5+
import { useTranslation } from '@ifrc-go/ui/hooks';
6+
import { resolveToString } from '@ifrc-go/ui/utils';
7+
8+
import usePermissions from '#hooks/domain/usePermissions';
9+
import useAlert from '#hooks/useAlert';
10+
import { useLazyRequest } from '#utils/restRequest';
11+
12+
import i18n from './i18n.json';
13+
14+
interface Props {
15+
countryId: number;
16+
localUnitId: number;
17+
onActionSuccess: () => void;
18+
localUnitName: string | null | undefined;
19+
disabled?: boolean;
20+
variant?: ButtonVariant;
21+
}
22+
23+
function LocalUnitDeleteButton(props: Props) {
24+
const strings = useTranslation(i18n);
25+
const {
26+
countryId,
27+
localUnitId,
28+
localUnitName,
29+
onActionSuccess,
30+
disabled,
31+
variant = 'secondary',
32+
} = props;
33+
34+
const { isCountryAdmin, isSuperUser } = usePermissions();
35+
const alert = useAlert();
36+
37+
const hasDeletePermission = isSuperUser || isCountryAdmin(countryId);
38+
39+
const {
40+
pending: validateLocalUnitPending,
41+
trigger: validateLocalUnit,
42+
} = useLazyRequest({
43+
method: 'DELETE',
44+
url: '/api/v2/local-units/{id}/',
45+
pathVariables: { id: localUnitId },
46+
onSuccess: () => {
47+
const validationMessage = resolveToString(
48+
strings.deleteSuccessMessage,
49+
{ localUnitName },
50+
);
51+
alert.show(
52+
validationMessage,
53+
{ variant: 'success' },
54+
);
55+
onActionSuccess();
56+
},
57+
onFailure: (response) => {
58+
const {
59+
value: { messageForNotification },
60+
debugMessage,
61+
} = response;
62+
63+
alert.show(
64+
resolveToString(
65+
strings.deleteFailureMessage,
66+
{ localUnitName },
67+
),
68+
{
69+
variant: 'danger',
70+
description: messageForNotification,
71+
debugMessage,
72+
},
73+
);
74+
},
75+
});
76+
77+
return (
78+
<ConfirmButton
79+
variant={variant}
80+
// NOTE sending an empty post request to validate the local unit
81+
name={null}
82+
spacing="compact"
83+
confirmHeading={strings.deleteLocalUnitHeading}
84+
confirmMessage={resolveToString(
85+
strings.deleteLocalUnitMessage,
86+
{ localUnitName: localUnitName ?? '' },
87+
)}
88+
onConfirm={validateLocalUnit}
89+
disabled={disabled
90+
|| validateLocalUnitPending
91+
|| !hasDeletePermission}
92+
>
93+
{strings.localUnitsDelete}
94+
</ConfirmButton>
95+
);
96+
}
97+
98+
export default LocalUnitDeleteButton;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"namespace": "localUnitValidateButton",
3+
"strings": {
4+
"localUnitsValidate": "Validate",
5+
"localUnitsValidated": "Validated",
6+
"localUnitsNotValidated": "Not validated",
7+
"validationSuccessMessage": "{localUnitName} was validated.",
8+
"validationFailureMessage": "Failed to validate {localUnitName}",
9+
"validateLocalUnitHeading": "Validate Local Unit Confirmation",
10+
"validateLocalUnitMessage": "Are you sure you want to validate \"{localUnitName}\"?"
11+
}
12+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { useMemo } from 'react';
2+
import { CheckboxCircleLineIcon } from '@ifrc-go/icons';
3+
import { ConfirmButton } from '@ifrc-go/ui';
4+
import { useTranslation } from '@ifrc-go/ui/hooks';
5+
import { resolveToString } from '@ifrc-go/ui/utils';
6+
7+
import usePermissions from '#hooks/domain/usePermissions';
8+
import useAlert from '#hooks/useAlert';
9+
import { useLazyRequest } from '#utils/restRequest';
10+
11+
import i18n from './i18n.json';
12+
import styles from './styles.module.css';
13+
14+
interface Props {
15+
countryId: number;
16+
localUnitId: number;
17+
isValidated: boolean;
18+
onActionSuccess: () => void;
19+
localUnitName: string | null | undefined;
20+
disabled?: boolean;
21+
readOnly?: boolean;
22+
}
23+
24+
function LocalUnitValidateButton(props: Props) {
25+
const strings = useTranslation(i18n);
26+
const {
27+
countryId,
28+
localUnitId,
29+
localUnitName,
30+
isValidated,
31+
onActionSuccess,
32+
disabled,
33+
readOnly,
34+
} = props;
35+
36+
const { isCountryAdmin, isSuperUser } = usePermissions();
37+
const alert = useAlert();
38+
39+
const hasValidatePermission = isSuperUser || isCountryAdmin(countryId);
40+
41+
const {
42+
pending: validateLocalUnitPending,
43+
trigger: validateLocalUnit,
44+
} = useLazyRequest({
45+
method: 'POST',
46+
url: '/api/v2/local-units/{id}/validate/',
47+
pathVariables: { id: localUnitId },
48+
// FIXME: typings should be fixed in the server
49+
body: () => ({} as never),
50+
onSuccess: (response) => {
51+
const validationMessage = resolveToString(
52+
strings.validationSuccessMessage,
53+
{ localUnitName: response.local_branch_name ?? response.english_branch_name },
54+
);
55+
alert.show(
56+
validationMessage,
57+
{ variant: 'success' },
58+
);
59+
onActionSuccess();
60+
},
61+
onFailure: (response) => {
62+
const {
63+
value: { messageForNotification },
64+
debugMessage,
65+
} = response;
66+
67+
alert.show(
68+
resolveToString(
69+
strings.validationFailureMessage,
70+
{ localUnitName },
71+
),
72+
{
73+
variant: 'danger',
74+
description: messageForNotification,
75+
debugMessage,
76+
},
77+
);
78+
},
79+
});
80+
81+
const label = useMemo(
82+
() => {
83+
if (isValidated) {
84+
return strings.localUnitsValidated;
85+
}
86+
87+
if (readOnly) {
88+
return strings.localUnitsNotValidated;
89+
}
90+
91+
return strings.localUnitsValidate;
92+
},
93+
[isValidated, readOnly, strings],
94+
);
95+
96+
return (
97+
<ConfirmButton
98+
className={styles.localUnitValidateButton}
99+
// NOTE sending an empty post request to validate the local unit
100+
name={null}
101+
spacing="compact"
102+
confirmHeading={strings.validateLocalUnitHeading}
103+
confirmMessage={resolveToString(
104+
strings.validateLocalUnitMessage,
105+
{ localUnitName: localUnitName ?? '' },
106+
)}
107+
onConfirm={validateLocalUnit}
108+
disabled={disabled
109+
|| validateLocalUnitPending
110+
|| !hasValidatePermission
111+
|| isValidated}
112+
icons={isValidated && <CheckboxCircleLineIcon className={styles.icon} />}
113+
>
114+
{label}
115+
</ConfirmButton>
116+
);
117+
}
118+
119+
export default LocalUnitValidateButton;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.local-unit-table-actions {
1+
.local-unit-validate-button {
22
.icon {
33
font-size: var(--go-ui-height-icon-multiplier);
44
}

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,26 @@
55
"failedMessage": "Failed to add local unit",
66
"updateMessage": "Local unit updated successfully!",
77
"updateFailedMessage": "Failed to update local unit",
8-
"healthCareDetails": "Health care details",
8+
"specialitiesAndCapacityTitle": "Specialities & Capacity",
99
"subtype": "Sub-type",
1010
"subtypeDescription": "(e.g. hospital)",
1111
"englishLabel": "English",
1212
"localLabel": "Local",
13-
"localUnitName": "Local unit name",
13+
"localUnitNameEn": "Local unit name (En)",
14+
"localUnitNameLocal": "Local unit name (Local)",
1415
"coverage": "Coverage",
15-
"focalPerson": "Focal person name",
16+
"focalPersonEn": "Focal person (En)",
17+
"focalPersonLocal": "Focal person (Local)",
1618
"country": "Country",
17-
"focalPointLabel": "Focal point",
18-
"source": "Source",
19+
"sourceEn": "Source (En)",
20+
"sourceLocal": "Source (Local)",
1921
"addressAndContactTitle": "Address and Contact",
20-
"facilityCategoryTitle": "Facility Category",
21-
"facilityCapacityTitle": "Facility Capacity",
2222
"humanResourcesTitle": "Human Resources",
2323
"servicesTitle": "Services",
24-
"address": "Address",
25-
"locality": "Locality",
24+
"addressEn": "Address (En)",
25+
"addressLocal": "Address (Local)",
26+
"localityEn": "Locality (En)",
27+
"localityLocal": "Locality (Local)",
2628
"postCode": "Local unit post code",
2729
"localUnitDetail": "Local Unit detail",
2830
"phone": "Local unit phone number",
@@ -40,10 +42,10 @@
4042
"teachingHospital": "Teaching Hospital",
4143
"inPatientCapacity": "In-patient capacity",
4244
"isolationRoomsWards": "Isolation rooms wards",
43-
"focalPointName": "Name",
44-
"focalPointPosition": "Position",
45-
"focalPointEmail": "Email",
46-
"focalPointPhoneNumber": "Phone number",
45+
"focalPointName": "Focal person name",
46+
"focalPointPosition": "Focal person position",
47+
"focalPointEmail": "Focal person email",
48+
"focalPointPhoneNumber": "Focal person phone number",
4749
"specialties": "Specialties",
4850
"otherServices": "Other Services",
4951
"bloodServices": "Blood Services",

0 commit comments

Comments
 (0)