Skip to content

Commit

Permalink
Add learning by sector and regions bar chart
Browse files Browse the repository at this point in the history
  • Loading branch information
roshni73 committed Dec 11, 2024
1 parent cbe00a9 commit a9f5ebb
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 2 deletions.
5 changes: 4 additions & 1 deletion app/src/views/OperationalLearning/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
152 changes: 151 additions & 1 deletion app/src/views/OperationalLearning/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from 'react';
import { InfoIcon } from '@ifrc-go/icons';
import {
BarChart,
Button,
Chip,
Container,
Expand All @@ -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,
Expand Down Expand Up @@ -98,6 +102,88 @@ const disasterTypeKeySelector = (type: DisasterType) => type.id;
const disasterTypeLabelSelector = (type: DisasterType) => type.name ?? '?';

/** @knipignore */

const responseData = {
operations_included: 9,
learning_extracts: 6,
sectors_covered: 6,
sources_used: 8,
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);
Expand Down Expand Up @@ -281,7 +367,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 (
<Page
className={styles.operationalLearning}
Expand Down Expand Up @@ -444,6 +545,55 @@ export function Component() {
</>
)}
/>
<div className={styles.learningOverview}>
<Container
heading="Map"
/>
<div className={styles.charts}>
<Container
heading={strings.learningBySector}
className={styles.learningChart}
withHeaderBorder
withInternalPadding
>
<BarChart
data={mockSectorData}
keySelector={keySelector}
valueSelector={valueSelector}
labelSelector={labelSelector}
/>
</Container>
<Container
heading={strings.learningByRegions}
className={styles.learningChart}
withHeaderBorder
withInternalPadding
>
<BarChart
data={mockRegionData}
keySelector={keySelector}
valueSelector={valueSelector}
labelSelector={labelSelector}
/>
</Container>
<Container
heading={strings.sourceOvertime}
className={styles.learningChart}
withHeaderBorder
withInternalPadding
>
<TimeSeriesChart
className={styles.timeSeriesChart}
timePoints={dateList}
dataKeys={timeSeriesDataKeys.map((key) => key.date)}
dateSelector={dateSelector}
valueSelector={timeSeriesValueSelector}
classNameSelector={timeseriesChartClassNameSelector}
xAxisFormatter={xAxisFormatter}
/>
</Container>
</div>
</div>
{showKeyInsights && (
<KeyInsights
opsLearningSummaryResponse={opsLearningSummaryResponse}
Expand Down
29 changes: 29 additions & 0 deletions app/src/views/OperationalLearning/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,34 @@
display: inline;
}
}
.learning-overview{
display: flex;
flex-direction: row;
justify-content: space-between;
.charts {
display: grid;
grid-gap: var(--go-ui-spacing-md);
grid-template-columns: repeat(auto-fit, minmax(25rem, 1fr));
@media screen and (max-width: 30rem) {
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.learning-chart{
border-radius: var(--go-ui-border-radius-lg);
box-shadow: var(--go-ui-box-shadow-md);

.time-series-chart {
width: 100%;
height: 10rem;

.source-chart {
color: var(--go-ui-color-primary-red);
stroke: var(--go-ui-color-primary-red);
stroke-width: var(1pt);
fill: none;
}
}
}
}
}
}

0 comments on commit a9f5ebb

Please sign in to comment.