diff --git a/src/views/CountryOngoingActivities/index.tsx b/src/views/CountryOngoingActivities/index.tsx index 58391ff96d..6888aaf752 100644 --- a/src/views/CountryOngoingActivities/index.tsx +++ b/src/views/CountryOngoingActivities/index.tsx @@ -30,6 +30,7 @@ export function Component() { countryResponsePending, ], ); + return (
diff --git a/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/i18n.json b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/i18n.json new file mode 100644 index 0000000000..d357be7ffd --- /dev/null +++ b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/i18n.json @@ -0,0 +1,10 @@ +{ + "namespace": "emergencyActivities", + "strings": { + "severityLow": "Less than 2", + "severityMedium": "2 to 4", + "severityHigh": "5 to 9", + "severitySevere": "10 or more", + "numberOfProjects": "Number of Projects" + } +} diff --git a/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/index.tsx b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/index.tsx new file mode 100644 index 0000000000..06b66b5bcb --- /dev/null +++ b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/index.tsx @@ -0,0 +1,195 @@ +import { useMemo } from 'react'; +import { + _cs, + isDefined, + isNotDefined, + mapToList, +} from '@togglecorp/fujs'; +import { + useOutletContext, +} from 'react-router-dom'; +import type { FillLayer } from 'mapbox-gl'; +import { + MapLayer, + MapBounds, +} from '@togglecorp/re-map'; +import getBbox from '@turf/bbox'; + +import LegendItem from '#components/LegendItem'; +import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer'; +import useTranslation from '#hooks/useTranslation'; +import type { CountryOutletContext } from '#utils/outletContext'; +import { + DURATION_MAP_ZOOM, + DEFAULT_MAP_PADDING, + COLOR_LIGHT_GREY, +} from '#utils/constants'; +import BaseMap from '#components/domain/BaseMap'; + +import i18n from './i18n.json'; +import styles from './styles.module.css'; + +const COLOR_SEVERITY_LOW = '#ccd2d9'; +const COLOR_SEVERITY_MEDIUM = '#99a5b4'; +const COLOR_SEVERITY_HIGH = '#67788d'; +const COLOR_SEVERITY_SEVERE = '#344b67'; + +const SEVERITY_LOW = 2; +const SEVERITY_MEDIUM = 5; +const SEVERITY_HIGH = 10; + +interface Props { + className?: string; + sidebarContent?: React.ReactNode; + emergencyProjectCountByDistrict: Record; +} + +function ResponseActivitiesMap(props: Props) { + const { + className, + sidebarContent, + emergencyProjectCountByDistrict, + } = props; + + const strings = useTranslation(i18n); + const { + // countryId, + countryResponse, + } = useOutletContext(); + + const bounds = useMemo( + () => (countryResponse ? getBbox(countryResponse?.bbox) : undefined), + [countryResponse], + ); + + const emergencyProjectCountByDistrictList = mapToList( + emergencyProjectCountByDistrict, + (value, key) => ({ district: key, count: value }), + ); + + const districtIdList = useMemo( + () => emergencyProjectCountByDistrictList.map( + (list) => Number(list.district), + ), + [emergencyProjectCountByDistrictList], + ); + + const adminOneLabelSelectedLayerOptions = useMemo>( + () => ({ + type: 'fill', + layout: { visibility: 'visible' }, + filter: [ + 'in', + 'district_id', + ...districtIdList, + ], + }), + [districtIdList], + ); + + const adminOneHighlightLayerOptions = useMemo>( + () => { + if (isNotDefined((emergencyProjectCountByDistrictList)) + || emergencyProjectCountByDistrictList.length < 1) { + return { + type: 'fill', + layout: { visibility: 'visible' }, + paint: { + 'fill-color': COLOR_LIGHT_GREY, + }, + }; + } + + return { + type: 'fill', + layout: { visibility: 'visible' }, + paint: { + 'fill-color': [ + 'match', + ['get', 'district_id'], + ...(emergencyProjectCountByDistrictList).flatMap(({ district, count }) => [ + Number(district), + [ + 'interpolate', + ['exponential', 1], + ['number', count], + 0, + COLOR_SEVERITY_LOW, + SEVERITY_LOW, + COLOR_SEVERITY_MEDIUM, + SEVERITY_MEDIUM, + COLOR_SEVERITY_HIGH, + SEVERITY_HIGH, + COLOR_SEVERITY_SEVERE, + ], + ]), + COLOR_LIGHT_GREY, + ], + }, + }; + }, + [emergencyProjectCountByDistrictList], + ); + + return ( +
+
+ + + + + )} + > + +
+ {strings.numberOfProjects} +
+ + + + +
+ )} + /> + {isDefined(bounds) && ( + + )} + +
+ {sidebarContent && ( +
+ {sidebarContent} +
+ )} +
+ ); +} + +export default ResponseActivitiesMap; diff --git a/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/styles.module.css b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/styles.module.css new file mode 100644 index 0000000000..7168c3fa49 --- /dev/null +++ b/src/views/CountryOngoingActivitiesThreeWActivities/ResponseActivitiesMap/styles.module.css @@ -0,0 +1,53 @@ +.map { + display: flex; + gap: var(--go-ui-spacing-md); + height: 40rem; + overflow: auto; + + .map-with-legend { + display: flex; + flex-direction: column; + flex-grow: 1; + + .map-container { + flex-grow: 1; + } + + .legend { + display: flex; + flex-wrap: wrap; + background-color: var(--go-ui-color-background); + gap: var(--go-ui-spacing-sm) var(--go-ui-spacing-md); + padding: var(--go-ui-spacing-md); + + .label { + font-weight: var(--go-ui-font-weight-medium); + } + } + } + + .sidebar { + flex-basis: calc(14vw + 12rem); + background-color: var(--go-ui-color-background); + overflow: auto; + } + + @media screen and (max-width: 50rem) { + flex-direction: column; + height: initial; + + .sidebar { + flex-basis: unset; + } + + .map-with-legend { + height: min(40rem, 60vh); + } + } +} + +.map-popup-content { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-md); +} diff --git a/src/views/CountryOngoingActivitiesThreeWActivities/i18n.json b/src/views/CountryOngoingActivitiesThreeWActivities/i18n.json index 6938c6316e..de69740195 100644 --- a/src/views/CountryOngoingActivitiesThreeWActivities/i18n.json +++ b/src/views/CountryOngoingActivitiesThreeWActivities/i18n.json @@ -2,10 +2,26 @@ "namespace": "countryOngoingActivitiesThreeWActivities", "strings": { "pageTitle": "Country Ongoing 3W Activities", + + "addThreeWActivity": "Add 3W Activity", + "chartDescription": "The data represents the added projects and may not reflect all of the ongoing projects.", "uniqueEruAndNationalSocietyCount": "Active National Societies / ERUs", + "failedToCreateExport": "Failed to generate export.", "peopleInNeedReached": "Services Provided to People in Need", "peopleReachedTooltip": "The figure displayed here is a sum of all individual services or interventions delivered as part of this emergency operation to people in need. Some people may have received more than one service or intervention.", + "activitySectors": "Activity Sectors", "uniqueSectorCount": "Sectors", - "totalActivities": "Total Activities" + "totalActivities": "Total Activities", + "activityStatus": "Activity Status", + "emergencyProjectNationalSociety": "National Society / ERU", + "emergencyProjectTitle": "Title", + "emergencyProjectStartDate": "Start Date", + "emergencyProjectCountry": "Country", + "emergencyProjectDistrict": "Province / Region", + "emergencyProjectStatus": "Status", + "emergencyProjectPeopleReached": "Services Provided to People in Need", + "responseActivities": "Response Activities", + "activitiesBySector": "Activities by Sector", + "dataNotAvailable": "No Activities" } } diff --git a/src/views/CountryOngoingActivitiesThreeWActivities/index.tsx b/src/views/CountryOngoingActivitiesThreeWActivities/index.tsx index 9cfb4ed9fb..21d70b2edb 100644 --- a/src/views/CountryOngoingActivitiesThreeWActivities/index.tsx +++ b/src/views/CountryOngoingActivitiesThreeWActivities/index.tsx @@ -1,12 +1,19 @@ import { useMemo } from 'react'; import { useOutletContext } from 'react-router-dom'; -import { compareNumber, isDefined, isNotDefined } from '@togglecorp/fujs'; +import { + compareNumber, + isDefined, + isNotDefined, + mapToList, +} from '@togglecorp/fujs'; import PieChart from '#components/PieChart'; import BlockLoading from '#components/BlockLoading'; import Container from '#components/Container'; import KeyFigure from '#components/KeyFigure'; import InfoPopup from '#components/InfoPopup'; +import Pager from '#components/Pager'; +import Message from '#components/Message'; import useTranslation from '#hooks/useTranslation'; import useFilterState from '#hooks/useFilterState'; @@ -19,9 +26,11 @@ import { stringTitleSelector, } from '#utils/selectors'; -import { type FilterValue } from '#views/EmergencyActivities/Filters'; +import Filters, { type FilterValue } from '#views/EmergencyActivities/Filters'; import useEmergencyProjectStats from '#views/EmergencyActivities/useEmergencyProjectStats'; +import ActivityDetail from '#views/EmergencyActivities/ActivityDetail'; +import ResponseActivitiesMap from './ResponseActivitiesMap'; import i18n from './i18n.json'; import styles from './styles.module.css'; @@ -98,7 +107,14 @@ export function Component() { const strings = useTranslation(i18n); const { + rawFilter, filter: filters, + setFilter: setFilters, + page: activePage, + setPage: setActivePage, + filtered: isFiltered, + limit, + offset, } = useFilterState({ filter: { reporting_ns: [], @@ -130,8 +146,10 @@ export function Component() { ); const { + emergencyProjectCountByDistrict, emergencyProjectCountListBySector, emergencyProjectCountListByStatus, + sectorGroupedEmergencyProjects, peopleReached, uniqueEruCount, uniqueNsCount, @@ -149,6 +167,25 @@ export function Component() { getAggregatedValues(emergencyProjectCountListByStatus) ), [emergencyProjectCountListByStatus]); + const paginatedEmergencyProjectList = useMemo(() => ( + filteredProjectList.slice(offset, offset + limit) + ), [filteredProjectList, offset, limit]); + + const sectorGroupedEmergencyProjectList = useMemo(() => ( + mapToList( + sectorGroupedEmergencyProjects, + (value, key) => ({ + sector: key, + projects: value.projects, + sectorDetails: value.sectorDetails, + }), + ) + ), [sectorGroupedEmergencyProjects]); + + const noActivitiesBySector = (isNotDefined(sectorGroupedEmergencyProjectList) + || (isDefined(sectorGroupedEmergencyProjectList) + && (sectorGroupedEmergencyProjectList.length < 1))); + return (
@@ -210,6 +247,53 @@ export function Component() {
)} + + )} + footerActions={( + + )} + > + + {noActivitiesBySector && ( + + )} + {/* FIXME: use List, add pending, filtered state */} + {sectorGroupedEmergencyProjectList.map((sectorGroupedProject) => ( + + ))} + + )} + /> + ); }