From 3071d1b7e803e369bfc3f0df88ef7b63e01d7a7d Mon Sep 17 00:00:00 2001 From: roshni73 Date: Thu, 5 Dec 2024 16:33:17 +0545 Subject: [PATCH] Add learning by sector and regions bar chart --- app/src/views/OperationalLearning/i18n.json | 5 +- app/src/views/OperationalLearning/index.tsx | 148 +++++++++++++++++- .../OperationalLearning/styles.module.css | 29 ++++ 3 files changed, 180 insertions(+), 2 deletions(-) diff --git a/app/src/views/OperationalLearning/i18n.json b/app/src/views/OperationalLearning/i18n.json index 89de54521..202513e19 100644 --- a/app/src/views/OperationalLearning/i18n.json +++ b/app/src/views/OperationalLearning/i18n.json @@ -20,6 +20,9 @@ "failedToCreateExport": "Failed to generate export.", "disclaimerMessage": "This is an updated implementation of the Operational Learning project started by the DREF and PER teams at IFRC. The previous dashboard can be found {link}.", "here": "here", - "beta": "beta" + "beta": "beta", + "learningBySector": "learnings by sectors", + "learningByRegions": "learnings by regions", + "sourceOvertime": "Sources Overtime" } } diff --git a/app/src/views/OperationalLearning/index.tsx b/app/src/views/OperationalLearning/index.tsx index e60659bc0..06d615d45 100644 --- a/app/src/views/OperationalLearning/index.tsx +++ b/app/src/views/OperationalLearning/index.tsx @@ -5,6 +5,7 @@ import { } from 'react'; import { InfoIcon } from '@ifrc-go/icons'; import { + BarChart, Button, Chip, Container, @@ -18,9 +19,12 @@ import { TabPanel, Tabs, TextOutput, + TimeSeriesChart, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { + getDatesSeparatedByMonths, + getFormattedDateKey, hasSomeDefinedValue, numericIdSelector, resolveToComponent, @@ -98,6 +102,84 @@ const disasterTypeKeySelector = (type: DisasterType) => type.id; const disasterTypeLabelSelector = (type: DisasterType) => type.name ?? '?'; /** @knipignore */ + +const responseData = { + learning_by_region: [ + { region_name: 'Americas', region_id: 1, count: 2 }, + { region_name: 'Asia Pacific', region_id: 2, count: 5 }, + { region_name: 'Europe', region_id: 3, count: 2 }, + ], + 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 }, + ], + learning_by_sector: [ + { id: 17, count: 1, title: 'health' }, + { id: 18, count: 1, title: 'education' }, + { id: 19, count: 3, title: 'Livelihoods and basic needs' }, + { id: 20, count: 4, title: 'Migration' }, + { id: 21, count: 1, title: 'WASH' }, + { id: 22, count: 1, title: 'Shelter' }, + ], + sources_overtime: { + DREF: [ + { year: 2023, count: 1 }, + { year: 2024, count: 3 }, + ], + 'Emergency Appeal': [ + { year: 2023, count: 1 }, + { year: 2024, count: 1 }, + ], + 'International Appeal': [ + { year: 2023, count: 1 }, + { year: 2024, count: 1 }, + ], + 'Forecast Based Action': [ + { year: 2022, count: 1 }, + ], + }, +}; + +const mockSectorData = responseData.learning_by_sector.map((sector) => ({ + key: sector.id, + value: sector.count, + label: sector.title, +})); + +const mockRegionData = responseData.learning_by_region.map((region) => ({ + key: region.region_id, + value: region.count, + label: region.region_name, +})); + +const timeSeriesDataKeys = Object.entries( + responseData.sources_overtime, +).flatMap(([source, entries]) => entries.map((entry) => ({ + date: `${entry.year}-01-01`, + value: entry.count, + source, +}))); + +const oneYearAgo = new Date(); +oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); +oneYearAgo.setDate(1); +oneYearAgo.setMonth(oneYearAgo.getMonth() + 1); +oneYearAgo.setHours(0, 0, 0, 0); +const timeseriesChartClassNameSelector = () => styles.sourceChart; +const xAxisFormatter = (date: Date) => date.toLocaleString( + navigator.language, + { month: 'short' }, +); +const keySelector = (datum: { key: number; value: number; label: string }) => datum.key; + +const valueSelector = (d: { value: number }) => d.value; +const labelSelector = (d: { label: string }) => d.label; +const dateSelector = (d: { date: string }) => d.date; + // eslint-disable-next-line import/prefer-default-export export function Component() { const strings = useTranslation(i18n); @@ -281,7 +363,22 @@ export function Component() { setFilterPristine(true); setQuery(undefined); }, [resetFilter]); - + const dateList = useMemo( + () => { + const startDate = oneYearAgo; + const endDate = new Date(); + return getDatesSeparatedByMonths(startDate, endDate); + }, + [], + ); + const timeSeriesValueSelector = useCallback( + (_: string, date: Date) => timeSeriesDataKeys?.find( + (source) => ( + getFormattedDateKey(source.date) === getFormattedDateKey(date) + ), + ) ?? null, + [], + ); return ( )} /> +
+ +
+ + + + + + + + + +
+
{showKeyInsights && (