Skip to content

Commit

Permalink
Add map for learning
Browse files Browse the repository at this point in the history
  • Loading branch information
roshni73 committed Dec 13, 2024
1 parent 6a70d50 commit b3c6ee6
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"namespace": "OperationalLearningMap",
"strings": {
"downloadMapTitle": "Operational learning map"
}
}
201 changes: 201 additions & 0 deletions app/src/views/OperationalLearning/OperationalLearningMap/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
useCallback,
useMemo,
useState,
} from 'react';
import {
Container,
TextOutput,
} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
import {
_cs,
isDefined,
isNotDefined,
} from '@togglecorp/fujs';
import {
MapLayer,
MapSource,
} from '@togglecorp/re-map';

import BaseMap from '#components/domain/BaseMap';
import Link from '#components/Link';
import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer';
import MapPopup from '#components/MapPopup';
import useCountryRaw from '#hooks/domain/useCountryRaw';
import { adminFillLayerOptions } from '#utils/map';

import i18n from './i18n.json';
import styles from './styles.module.css';

const sourceOptions: mapboxgl.GeoJSONSourceRaw = {
type: 'geojson',
};

interface CountryProperties {
country_id: number;
name: string;
operation_count: number;
}

interface ClickedPoint {
feature: GeoJSON.Feature<GeoJSON.Point, CountryProperties>;
lngLat: mapboxgl.LngLatLike;
}

interface Props {
className?: string;
}

function OperationalLearningMap(props: Props) {
const strings = useTranslation(i18n);
const {
className,
} = props;

const [
clickedPointProperties,
setClickedPointProperties,
] = useState<ClickedPoint | undefined>();

const countryResponse = useCountryRaw();

const countryCentroidGeoJson = useMemo(
(): GeoJSON.FeatureCollection<GeoJSON.Geometry> => {
const learning_by_country = [
{
country_name: 'Afghanistan',
country_id: 14,
operation_count: 4,
},
{
country_name: 'Albania',
country_id: 15,
operation_count: 1,
},
{
country_name: 'Argentina',
country_id: 20,
operation_count: 1,
},
{
country_name: 'Australia',
country_id: 22,
operation_count: 1,
},
{
country_name: 'Belgium',
country_id: 30,
operation_count: 1,
},
{
country_name: 'Canada',
country_id: 42,
operation_count: 1,
},
];

const features = countryResponse
?.map((country) => {
const learningList = learning_by_country.find(
(item) => item.country_id === country.id,
);
if (isNotDefined(learningList)) {
return undefined;
}

const units = learningList.operation_count ?? 0;

return {
type: 'Feature' as const,
geometry: country.centroid as {
type: 'Point',
coordinates: [number, number],
},
properties: {
country_id: country.id,
name: country.name,
operation_count: units,
},
};
})
.filter(isDefined) ?? [];

return {
type: 'FeatureCollection',
features,
};
},
[countryResponse],
);

const handleCountryClick = useCallback(
(feature: mapboxgl.MapboxGeoJSONFeature, lngLat: mapboxgl.LngLatLike) => {
setClickedPointProperties({
feature: feature as unknown as ClickedPoint['feature'],
lngLat,
});
return false;
},
[],
);

const handlePointClose = useCallback(() => {
setClickedPointProperties(undefined);
}, []);

return (
<Container className={_cs(styles.learningMap, className)}>
<BaseMap
baseLayers={(
<MapLayer
layerKey="admin-0"
hoverable
layerOptions={adminFillLayerOptions}
onClick={handleCountryClick}
/>
)}
>
<MapContainerWithDisclaimer
className={styles.mapContainer}
title={strings.downloadMapTitle}
/>
<MapSource
sourceKey="points"
sourceOptions={sourceOptions}
geoJson={countryCentroidGeoJson}
/>
{clickedPointProperties?.lngLat && (
<MapPopup
onCloseButtonClick={handlePointClose}
coordinates={clickedPointProperties.lngLat}
heading={(
<Link
to="countriesLayout"
urlParams={{
countryId: clickedPointProperties.feature.properties.country_id,
}}
>
{clickedPointProperties.feature.properties.name}
</Link>
)}
childrenContainerClassName={styles.popupContent}
>
<Container
className={styles.popupEvent}
childrenContainerClassName={styles.popupEventDetail}
headingLevel={5}
>
<TextOutput
value={clickedPointProperties.feature.properties.operation_count}
valueType="number"
/>
</Container>
</MapPopup>
)}
</BaseMap>
</Container>
);
}

export default OperationalLearningMap;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.learning-map {

.map-container {
height: 40rem;
}
}

.popup-content {
display: flex;
flex-direction: column;
gap: var(--go-ui-spacing-md);

.popup-appeal {
gap: var(--go-ui-spacing-xs);

.popup-appeal-detail {
display: flex;
flex-direction: column;
font-size: var(--go-ui-font-size-sm);
}
}
}
50 changes: 50 additions & 0 deletions app/src/views/OperationalLearning/OperationalLearningMap/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// import type {
// CircleLayer,
// CirclePaint,
// FillLayer,
// } from 'mapbox-gl';

// import {
// COLOR_BLACK,
// COLOR_BLUE,
// COLOR_DARK_GREY,
// COLOR_LIGHT_GREY,
// COLOR_RED,
// COLOR_YELLOW,
// } from '#utils/constants';

// const COLOR_LEARNING_AND_PERSONNEL = COLOR_BLUE;
// const COLOR_LEARNING_ONLY = COLOR_RED;
// const COLOR_PERSONNEL_ONLY = COLOR_YELLOW;
// const COLOR_DEFAULT = COLOR_BLACK;

// export const adminFillLayerOptions: Omit<FillLayer, 'id'> = {
// type: 'fill',
// paint: {
// 'fill-color': [
// 'case',
// ['boolean', ['feature-state', 'hovered'], false],
// COLOR_DARK_GREY,
// COLOR_LIGHT_GREY,
// ],
// },
// };

// const circleColor: CirclePaint['circle-color'] = [
// 'case',
// COLOR_LEARNING_AND_PERSONNEL,
// COLOR_LEARNING_ONLY,
// COLOR_PERSONNEL_ONLY,
// COLOR_DEFAULT,
// ];

// const basePointPaint: CirclePaint = {
// 'circle-radius': 5,
// 'circle-color': circleColor,
// 'circle-opacity': 0.8,
// };

// export const basePointLayerOptions: Omit<CircleLayer, 'id'> = {
// type: 'circle',
// paint: basePointPaint,
// };
Loading

0 comments on commit b3c6ee6

Please sign in to comment.