From 64f291255369ff9442775feb6d52537917f39557 Mon Sep 17 00:00:00 2001
From: Silke Bonnen <95029552+silkeholmebonnen@users.noreply.github.com>
Date: Tue, 4 Jun 2024 12:13:43 +0200
Subject: [PATCH] feat(web): add production source legends to data source
accordion for carbon and emission chart (#6728)
* add production source legends to data sources for carbon and emission chart
* add legends to bar-breakdown
* fix: assumes is not shown in data sources
* add power generation and emission factor to all charts
* remove data sources when graph is disabled
* fix source alignment
* hide when no sources
* fix: use not ! instead of == undefined | null
* fix: based on tonys comments
* fix: create hook useZoneDataSources
* renameing
* fix: remove productionSourceLegendList from breakdownChart when it is disabled
* remove padding and move files around
* fix: sort imports
---
web/src/features/charts/BreakdownChart.tsx | 73 +++++----
web/src/features/charts/CarbonChart.tsx | 24 ++-
web/src/features/charts/DataSources.tsx | 51 ++++++
web/src/features/charts/EmissionChart.tsx | 24 ++-
web/src/features/charts/NetExchangeChart.tsx | 2 +-
web/src/features/charts/PriceChart.tsx | 2 +-
.../ProductionSourceLegend.tsx | 0
.../ProductionSourceLegendList.tsx | 0
.../ProductionsSourceIcons.tsx | 0
.../{bar-breakdown => }/RoundedCard.tsx | 0
.../bar-breakdown/BarBreakdownChart.tsx | 125 +++++++--------
.../BarBreakdownEmissionsChart.tsx | 2 +-
.../BarElectricityBreakdownChart.tsx | 2 +-
.../charts/bar-breakdown/DataSources.tsx | 25 ---
.../features/charts/bar-breakdown/utils.ts | 57 -------
.../charts/hooks/useBreakdownChartData.ts | 24 +--
.../charts/hooks/useCarbonChartData.ts | 9 +-
.../charts/hooks/useEmissionChartData.ts | 9 +-
.../charts/hooks/useZoneDataSources.ts | 150 ++++++++++++++++++
.../tooltips/AreaGraphTooltipHeader.tsx | 2 +-
.../features/panels/zone/MethodologyCard.tsx | 2 +-
21 files changed, 366 insertions(+), 217 deletions(-)
create mode 100644 web/src/features/charts/DataSources.tsx
rename web/src/features/charts/{bar-breakdown => }/ProductionSourceLegend.tsx (100%)
rename web/src/features/charts/{bar-breakdown => }/ProductionSourceLegendList.tsx (100%)
rename web/src/features/charts/{bar-breakdown => }/ProductionsSourceIcons.tsx (100%)
rename web/src/features/charts/{bar-breakdown => }/RoundedCard.tsx (100%)
delete mode 100644 web/src/features/charts/bar-breakdown/DataSources.tsx
create mode 100644 web/src/features/charts/hooks/useZoneDataSources.ts
diff --git a/web/src/features/charts/BreakdownChart.tsx b/web/src/features/charts/BreakdownChart.tsx
index 1334110d22..558b98ad3c 100644
--- a/web/src/features/charts/BreakdownChart.tsx
+++ b/web/src/features/charts/BreakdownChart.tsx
@@ -2,6 +2,7 @@ import Accordion from 'components/Accordion';
import { max, sum } from 'd3-array';
import Divider from 'features/panels/zone/Divider';
import { CircleBoltIcon } from 'icons/circleBoltIcon';
+import { IndustryIcon } from 'icons/industryIcon';
import { WindTurbineIcon } from 'icons/windTurbineIcon';
import { useTranslation } from 'react-i18next';
import { ElectricityModeType } from 'types';
@@ -10,15 +11,16 @@ import { Mode, TimeAverages, TrackEvent } from 'utils/constants';
import { formatCo2 } from 'utils/formatting';
import { dataSourcesCollapsedBreakdown } from 'utils/state/atoms';
-import { DataSources } from './bar-breakdown/DataSources';
-import ProductionSourceLegendList from './bar-breakdown/ProductionSourceLegendList';
-import { RoundedCard } from './bar-breakdown/RoundedCard';
import { ChartTitle } from './ChartTitle';
+import { DataSources } from './DataSources';
import { DisabledMessage } from './DisabledMessage';
import AreaGraph from './elements/AreaGraph';
import { getBadgeText, getGenerationTypeKey, noop } from './graphUtils';
import useBreakdownChartData from './hooks/useBreakdownChartData';
+import useZoneDataSources from './hooks/useZoneDataSources';
import { NotEnoughDataMessage } from './NotEnoughDataMessage';
+import ProductionSourceLegendList from './ProductionSourceLegendList';
+import { RoundedCard } from './RoundedCard';
import BreakdownChartTooltip from './tooltips/BreakdownChartTooltip';
import { AreaGraphElement } from './types';
@@ -33,7 +35,12 @@ function BreakdownChart({
datetimes,
timeAverage,
}: BreakdownChartProps) {
- const { sources, data, mixMode } = useBreakdownChartData();
+ const { data, mixMode } = useBreakdownChartData();
+ const {
+ emissionFactorSources,
+ powerGenerationSources,
+ emissionFactorSourcesToProductionSources,
+ } = useZoneDataSources();
const { t } = useTranslation();
if (!data) {
@@ -101,29 +108,41 @@ function BreakdownChart({
dangerouslySetInnerHTML={{ __html: t('country-panel.exchangesAreMissing') }}
/>
)}
-
-
- {
- trackEvent(TrackEvent.DATA_SOURCES_CLICKED, {
- chart: displayByEmissions
- ? 'emission-origin-chart'
- : 'electricity-origin-chart',
- });
- }}
- title={t('data-sources.title')}
- className="text-md"
- isCollapsedAtom={dataSourcesCollapsedBreakdown}
- >
- }
- sources={sources}
- />
-
+ {!isBreakdownGraphOverlayEnabled && (
+ <>
+
+
+ {
+ trackEvent(TrackEvent.DATA_SOURCES_CLICKED, {
+ chart: displayByEmissions
+ ? 'emission-origin-chart'
+ : 'electricity-origin-chart',
+ });
+ }}
+ title={t('data-sources.title')}
+ className="text-md"
+ isCollapsedAtom={dataSourcesCollapsedBreakdown}
+ >
+ }
+ sources={powerGenerationSources}
+ />
+ }
+ sources={emissionFactorSources}
+ emissionFactorSourcesToProductionSources={
+ emissionFactorSourcesToProductionSources
+ }
+ />
+
+ >
+ )}
);
}
diff --git a/web/src/features/charts/CarbonChart.tsx b/web/src/features/charts/CarbonChart.tsx
index 526030b1be..0dcc533ed4 100644
--- a/web/src/features/charts/CarbonChart.tsx
+++ b/web/src/features/charts/CarbonChart.tsx
@@ -2,18 +2,20 @@ import Accordion from 'components/Accordion';
import Divider from 'features/panels/zone/Divider';
import { CloudArrowUpIcon } from 'icons/cloudArrowUpIcon';
import { IndustryIcon } from 'icons/industryIcon';
+import { WindTurbineIcon } from 'icons/windTurbineIcon';
import { useTranslation } from 'react-i18next';
import trackEvent from 'utils/analytics';
import { TimeAverages, TrackEvent } from 'utils/constants';
import { dataSourcesCollapsedEmission } from 'utils/state/atoms';
-import { DataSources } from './bar-breakdown/DataSources';
-import { RoundedCard } from './bar-breakdown/RoundedCard';
import { ChartTitle } from './ChartTitle';
+import { DataSources } from './DataSources';
import AreaGraph from './elements/AreaGraph';
import { getBadgeText, noop } from './graphUtils';
import { useCarbonChartData } from './hooks/useCarbonChartData';
+import useZoneDataSources from './hooks/useZoneDataSources';
import { NotEnoughDataMessage } from './NotEnoughDataMessage';
+import { RoundedCard } from './RoundedCard';
import CarbonChartTooltip from './tooltips/CarbonChartTooltip';
interface CarbonChartProps {
@@ -22,8 +24,12 @@ interface CarbonChartProps {
}
function CarbonChart({ datetimes, timeAverage }: CarbonChartProps) {
- const { data, emissionSourceToProductionSource, isLoading, isError } =
- useCarbonChartData();
+ const { data, isLoading, isError } = useCarbonChartData();
+ const {
+ emissionFactorSources,
+ powerGenerationSources,
+ emissionFactorSourcesToProductionSources,
+ } = useZoneDataSources();
const { t } = useTranslation();
if (isLoading || isError || !data) {
@@ -69,10 +75,18 @@ function CarbonChart({ datetimes, timeAverage }: CarbonChartProps) {
className="text-md"
isCollapsedAtom={dataSourcesCollapsedEmission}
>
+ }
+ sources={powerGenerationSources}
+ />
}
- sources={[...emissionSourceToProductionSource.keys()].sort()}
+ sources={emissionFactorSources}
+ emissionFactorSourcesToProductionSources={
+ emissionFactorSourcesToProductionSources
+ }
/>
diff --git a/web/src/features/charts/DataSources.tsx b/web/src/features/charts/DataSources.tsx
new file mode 100644
index 0000000000..60ef2c2654
--- /dev/null
+++ b/web/src/features/charts/DataSources.tsx
@@ -0,0 +1,51 @@
+import { ElectricityModeType } from 'types';
+
+import ProductionSourceLegend from './ProductionSourceLegend';
+
+export function DataSources({
+ title,
+ icon,
+ sources,
+ emissionFactorSourcesToProductionSources,
+}: {
+ title: string;
+ icon: React.ReactNode;
+ sources: string[];
+ emissionFactorSourcesToProductionSources?: { [key: string]: string[] };
+}) {
+ const showDataSources = Boolean(
+ (sources && sources?.length > 0) || emissionFactorSourcesToProductionSources
+ );
+ if (showDataSources == false) {
+ return null;
+ }
+
+ return (
+
+
+
+ {sources.sort().map((source, index) => (
+
+ {source}
+ {emissionFactorSourcesToProductionSources && (
+
+ {emissionFactorSourcesToProductionSources[source]?.map(
+ (productionSource, index) => (
+
+
+
+ )
+ )}
+
+ )}
+
+ ))}
+
+
+ );
+}
diff --git a/web/src/features/charts/EmissionChart.tsx b/web/src/features/charts/EmissionChart.tsx
index 4e5571b47f..eb6aa45a25 100644
--- a/web/src/features/charts/EmissionChart.tsx
+++ b/web/src/features/charts/EmissionChart.tsx
@@ -2,18 +2,20 @@ import Accordion from 'components/Accordion';
import Divider from 'features/panels/zone/Divider';
import { CloudArrowUpIcon } from 'icons/cloudArrowUpIcon';
import { IndustryIcon } from 'icons/industryIcon';
+import { WindTurbineIcon } from 'icons/windTurbineIcon';
import { useTranslation } from 'react-i18next';
import trackEvent from 'utils/analytics';
import { TimeAverages, TrackEvent } from 'utils/constants';
import { formatCo2 } from 'utils/formatting';
import { dataSourcesCollapsedEmission } from 'utils/state/atoms';
-import { DataSources } from './bar-breakdown/DataSources';
-import { RoundedCard } from './bar-breakdown/RoundedCard';
import { ChartTitle } from './ChartTitle';
+import { DataSources } from './DataSources';
import AreaGraph from './elements/AreaGraph';
import { getBadgeText, noop } from './graphUtils';
import { useEmissionChartData } from './hooks/useEmissionChartData';
+import useZoneDataSources from './hooks/useZoneDataSources';
+import { RoundedCard } from './RoundedCard';
import EmissionChartTooltip from './tooltips/EmissionChartTooltip';
interface EmissionChartProps {
@@ -22,8 +24,12 @@ interface EmissionChartProps {
}
function EmissionChart({ timeAverage, datetimes }: EmissionChartProps) {
- const { data, emissionSourceToProductionSource, isLoading, isError } =
- useEmissionChartData();
+ const { data, isLoading, isError } = useEmissionChartData();
+ const {
+ emissionFactorSources,
+ powerGenerationSources,
+ emissionFactorSourcesToProductionSources,
+ } = useZoneDataSources();
const { t } = useTranslation();
if (isLoading || isError || !data) {
return null;
@@ -67,10 +73,18 @@ function EmissionChart({ timeAverage, datetimes }: EmissionChartProps) {
className="text-md"
isCollapsedAtom={dataSourcesCollapsedEmission}
>
+ }
+ sources={powerGenerationSources}
+ />
}
- sources={[...emissionSourceToProductionSource.keys()].sort()}
+ sources={emissionFactorSources}
+ emissionFactorSourcesToProductionSources={
+ emissionFactorSourcesToProductionSources
+ }
/>
diff --git a/web/src/features/charts/NetExchangeChart.tsx b/web/src/features/charts/NetExchangeChart.tsx
index 67e72d2988..97e2d99d4c 100644
--- a/web/src/features/charts/NetExchangeChart.tsx
+++ b/web/src/features/charts/NetExchangeChart.tsx
@@ -4,11 +4,11 @@ import { TimeAverages } from 'utils/constants';
import { formatCo2 } from 'utils/formatting';
import { displayByEmissionsAtom, productionConsumptionAtom } from 'utils/state/atoms';
-import { RoundedCard } from './bar-breakdown/RoundedCard';
import { ChartTitle } from './ChartTitle';
import AreaGraph from './elements/AreaGraph';
import { noop } from './graphUtils';
import { useNetExchangeChartData } from './hooks/useNetExchangeChartData';
+import { RoundedCard } from './RoundedCard';
import NetExchangeChartTooltip from './tooltips/NetExchangeChartTooltip';
interface NetExchangeChartProps {
diff --git a/web/src/features/charts/PriceChart.tsx b/web/src/features/charts/PriceChart.tsx
index 93f3602489..802537b002 100644
--- a/web/src/features/charts/PriceChart.tsx
+++ b/web/src/features/charts/PriceChart.tsx
@@ -2,13 +2,13 @@ import { CoinsIcon } from 'icons/coinsIcon';
import { useTranslation } from 'react-i18next';
import { TimeAverages } from 'utils/constants';
-import { RoundedCard } from './bar-breakdown/RoundedCard';
import { ChartTitle } from './ChartTitle';
import { DisabledMessage } from './DisabledMessage';
import AreaGraph from './elements/AreaGraph';
import { noop } from './graphUtils';
import { usePriceChartData } from './hooks/usePriceChartData';
import { NotEnoughDataMessage } from './NotEnoughDataMessage';
+import { RoundedCard } from './RoundedCard';
import PriceChartTooltip from './tooltips/PriceChartTooltip';
interface PriceChartProps {
diff --git a/web/src/features/charts/bar-breakdown/ProductionSourceLegend.tsx b/web/src/features/charts/ProductionSourceLegend.tsx
similarity index 100%
rename from web/src/features/charts/bar-breakdown/ProductionSourceLegend.tsx
rename to web/src/features/charts/ProductionSourceLegend.tsx
diff --git a/web/src/features/charts/bar-breakdown/ProductionSourceLegendList.tsx b/web/src/features/charts/ProductionSourceLegendList.tsx
similarity index 100%
rename from web/src/features/charts/bar-breakdown/ProductionSourceLegendList.tsx
rename to web/src/features/charts/ProductionSourceLegendList.tsx
diff --git a/web/src/features/charts/bar-breakdown/ProductionsSourceIcons.tsx b/web/src/features/charts/ProductionsSourceIcons.tsx
similarity index 100%
rename from web/src/features/charts/bar-breakdown/ProductionsSourceIcons.tsx
rename to web/src/features/charts/ProductionsSourceIcons.tsx
diff --git a/web/src/features/charts/bar-breakdown/RoundedCard.tsx b/web/src/features/charts/RoundedCard.tsx
similarity index 100%
rename from web/src/features/charts/bar-breakdown/RoundedCard.tsx
rename to web/src/features/charts/RoundedCard.tsx
diff --git a/web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx b/web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx
index 7c04ab2e8b..0481900275 100644
--- a/web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx
+++ b/web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx
@@ -21,12 +21,13 @@ import {
} from 'utils/state/atoms';
import { useBreakpoint } from 'utils/styling';
+import { DataSources } from '../DataSources';
import { determineUnit } from '../graphUtils';
import useBarBreakdownChartData from '../hooks/useBarElectricityBreakdownChartData';
+import useZoneDataSources from '../hooks/useZoneDataSources';
import BreakdownChartTooltip from '../tooltips/BreakdownChartTooltip';
import BarBreakdownEmissionsChart from './BarBreakdownEmissionsChart';
import BarElectricityBreakdownChart from './BarElectricityBreakdownChart';
-import { DataSources } from './DataSources';
import BySource from './elements/BySource';
import EmptyBarBreakdownChart from './EmptyBarBreakdownChart';
import { useHeaderHeight } from './utils';
@@ -46,6 +47,14 @@ function BarBreakdownChart({
isLoading,
height,
} = useBarBreakdownChartData();
+
+ const {
+ capacitySources,
+ powerGenerationSources,
+ emissionFactorSources,
+ emissionFactorSourcesToProductionSources,
+ } = useZoneDataSources();
+
const [displayByEmissions] = useAtom(displayByEmissionsAtom);
const { ref, width: observerWidth = 0 } = useResizeObserver();
const { t } = useTranslation();
@@ -104,16 +113,17 @@ function BarBreakdownChart({
setTooltipData(null);
};
- const emissionData = [
- ...new Set(
- [
- ...Object.values(currentZoneDetail?.dischargeCo2IntensitySources || {}),
- ...Object.values(currentZoneDetail?.productionCo2IntensitySources || {}),
- ].flatMap((item) => item.split('; '))
- ),
- ]
- .filter((item) => !item.startsWith('assumes'))
- .sort();
+ const showPowerSources = Boolean(
+ powerGenerationSources && powerGenerationSources.length > 0
+ );
+ const showEmissionSources = Boolean(
+ emissionFactorSources && emissionFactorSources.length > 0
+ );
+ const showCapacitySources = Boolean(capacitySources && capacitySources.length > 0);
+
+ const showDataSourceAccordion = Boolean(
+ showCapacitySources || showPowerSources || showEmissionSources
+ );
return (
)}
-
-
-
{
- trackEvent(TrackEvent.DATA_SOURCES_CLICKED, { chart: 'bar-breakdown-chart' });
- }}
- title={t('data-sources.title')}
- className="text-md"
- isCollapsedAtom={dataSourcesCollapsedBarBreakdown}
- >
-
- {currentZoneDetail?.capacitySources && (
- }
- sources={[
- ...GetSourceArrayFromDictionary(currentZoneDetail?.capacitySources),
- ]}
- />
- )}
- {currentZoneDetail?.source && (
- }
- sources={currentZoneDetail?.source}
- />
- )}
- {emissionData && (
- }
- sources={emissionData}
- />
- )}
-
-
-
+ {showDataSourceAccordion && (
+ <>
+
+
+
{
+ trackEvent(TrackEvent.DATA_SOURCES_CLICKED, {
+ chart: 'bar-breakdown-chart',
+ });
+ }}
+ title={t('data-sources.title')}
+ className="text-md"
+ isCollapsedAtom={dataSourcesCollapsedBarBreakdown}
+ >
+
+ }
+ sources={capacitySources}
+ />
+ }
+ sources={powerGenerationSources}
+ />
+ }
+ sources={emissionFactorSources}
+ emissionFactorSourcesToProductionSources={
+ emissionFactorSourcesToProductionSources
+ }
+ />
+
+
+
{' '}
+ >
+ )}
);
}
export default BarBreakdownChart;
-
-function GetSourceArrayFromDictionary(sourceDict: {
- [key in ElectricityModeType]: string[] | null;
-}): Set {
- const sourcesWithoutDuplicates: Set = new Set();
- if (sourceDict == null) {
- return sourcesWithoutDuplicates;
- }
- for (const key of Object.keys(sourceDict)) {
- const capacitySource = sourceDict?.[key as ElectricityModeType];
- if (capacitySource != null) {
- for (const source of capacitySource) {
- sourcesWithoutDuplicates.add(source);
- }
- }
- }
- return sourcesWithoutDuplicates;
-}
diff --git a/web/src/features/charts/bar-breakdown/BarBreakdownEmissionsChart.tsx b/web/src/features/charts/bar-breakdown/BarBreakdownEmissionsChart.tsx
index 20aca982f7..ef4753e871 100644
--- a/web/src/features/charts/bar-breakdown/BarBreakdownEmissionsChart.tsx
+++ b/web/src/features/charts/bar-breakdown/BarBreakdownEmissionsChart.tsx
@@ -7,11 +7,11 @@ import { ElectricityModeType, ZoneDetail, ZoneKey } from 'types';
import { modeColor } from 'utils/constants';
import { formatCo2 } from 'utils/formatting';
+import ProductionSourceLegend from '../ProductionSourceLegend';
import { LABEL_MAX_WIDTH, PADDING_X } from './constants';
import Axis from './elements/Axis';
import HorizontalBar from './elements/HorizontalBar';
import Row from './elements/Row';
-import ProductionSourceLegend from './ProductionSourceLegend';
import { ExchangeDataType, getDataBlockPositions, ProductionDataType } from './utils';
interface BarBreakdownEmissionsChartProps {
diff --git a/web/src/features/charts/bar-breakdown/BarElectricityBreakdownChart.tsx b/web/src/features/charts/bar-breakdown/BarElectricityBreakdownChart.tsx
index fa64d01b49..fb08e9ae80 100644
--- a/web/src/features/charts/bar-breakdown/BarElectricityBreakdownChart.tsx
+++ b/web/src/features/charts/bar-breakdown/BarElectricityBreakdownChart.tsx
@@ -10,11 +10,11 @@ import { modeColor, TimeAverages } from 'utils/constants';
import { formatEnergy, formatPower } from 'utils/formatting';
import { timeAverageAtom } from 'utils/state/atoms';
+import ProductionSourceLegend from '../ProductionSourceLegend';
import { LABEL_MAX_WIDTH, PADDING_X } from './constants';
import Axis from './elements/Axis';
import HorizontalBar from './elements/HorizontalBar';
import Row from './elements/Row';
-import ProductionSourceLegend from './ProductionSourceLegend';
import {
ExchangeDataType,
getDataBlockPositions,
diff --git a/web/src/features/charts/bar-breakdown/DataSources.tsx b/web/src/features/charts/bar-breakdown/DataSources.tsx
deleted file mode 100644
index eadd135902..0000000000
--- a/web/src/features/charts/bar-breakdown/DataSources.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-export function DataSources({
- title,
- icon,
- sources,
-}: {
- title: string;
- icon: React.ReactNode;
- sources: string[];
-}) {
- return (
-
-
-
- {sources.map((source, index) => (
-
- {source}
-
- ))}
-
-
- );
-}
diff --git a/web/src/features/charts/bar-breakdown/utils.ts b/web/src/features/charts/bar-breakdown/utils.ts
index 9039143531..dc61a930de 100644
--- a/web/src/features/charts/bar-breakdown/utils.ts
+++ b/web/src/features/charts/bar-breakdown/utils.ts
@@ -208,60 +208,3 @@ export const useHeaderHeight = () => {
return headerHeight;
};
-
-export function getEmissionData(zoneData: ZoneDetails) {
- const sourceInfoToProductionSource = new Map();
-
- for (const state of Object.values(zoneData.zoneStates)) {
- updateMapWithSources(
- state.dischargeCo2IntensitySources,
- sourceInfoToProductionSource,
- true
- );
- updateMapWithSources(
- state.productionCo2IntensitySources,
- sourceInfoToProductionSource
- );
- }
-
- return sourceInfoToProductionSource;
-}
-
-function updateMapWithSources(
- sources: { [key: string]: string },
- sourceInfoToProductionSource: Map,
- storageType?: boolean
-) {
- for (const entry of Object.entries(sources)) {
- for (const sourceInfo of entry[1].split('; ')) {
- const productionSource = getProductionSourcesToAdd(
- entry,
- sourceInfoToProductionSource.get(sourceInfo),
- storageType
- );
- if (productionSource.length > 0) {
- sourceInfoToProductionSource.set(sourceInfo, productionSource);
- }
- }
- }
-}
-
-function getProductionSourcesToAdd(
- entry: [string, string],
- productionSourceArray: string[] | undefined,
- storageType?: boolean
-): string[] {
- const productionSource = storageType ? `${entry[0]} storage` : entry[0];
- const sourceInfo = entry[1];
-
- if (sourceInfo.startsWith('assumes')) {
- return [];
- }
- if (productionSourceArray === undefined) {
- return [productionSource];
- } else if (!productionSourceArray?.includes(productionSource)) {
- productionSourceArray?.push(productionSource);
- return productionSourceArray;
- }
- return [];
-}
diff --git a/web/src/features/charts/hooks/useBreakdownChartData.ts b/web/src/features/charts/hooks/useBreakdownChartData.ts
index afe2a6de0c..4cc240b8cb 100644
--- a/web/src/features/charts/hooks/useBreakdownChartData.ts
+++ b/web/src/features/charts/hooks/useBreakdownChartData.ts
@@ -9,7 +9,6 @@ import {
ElectricityStorageKeyType,
ElectricityStorageType,
ZoneDetail,
- ZoneDetails,
} from 'types';
import {
Mode,
@@ -130,23 +129,12 @@ export default function useBreakdownChartData() {
layerStroke: undefined,
};
- const sources = getSources(zoneData);
-
- return { sources, data: result, mixMode, isLoading, isError };
-}
-
-function getSources(zoneData: ZoneDetails) {
- const sourceSet = new Set();
-
- for (const state of Object.values(zoneData.zoneStates)) {
- const currentSources = state.source;
- for (const source of currentSources) {
- sourceSet.add(source);
- }
- }
-
- const sources = [...sourceSet];
- return sources;
+ return {
+ data: result,
+ mixMode,
+ isLoading,
+ isError,
+ };
}
function getStorageValue(
diff --git a/web/src/features/charts/hooks/useCarbonChartData.ts b/web/src/features/charts/hooks/useCarbonChartData.ts
index f7e1d45b0c..0f3efcaa46 100644
--- a/web/src/features/charts/hooks/useCarbonChartData.ts
+++ b/web/src/features/charts/hooks/useCarbonChartData.ts
@@ -4,7 +4,6 @@ import { useAtom } from 'jotai';
import { getCO2IntensityByMode } from 'utils/helpers';
import { productionConsumptionAtom } from 'utils/state/atoms';
-import { getEmissionData } from '../bar-breakdown/utils';
import { AreaGraphElement } from '../types';
export function useCarbonChartData() {
@@ -50,7 +49,9 @@ export function useCarbonChartData() {
layerFill,
};
- const emissionSourceToProductionSource = getEmissionData(data);
-
- return { data: result, emissionSourceToProductionSource, isLoading, isError };
+ return {
+ data: result,
+ isLoading,
+ isError,
+ };
}
diff --git a/web/src/features/charts/hooks/useEmissionChartData.ts b/web/src/features/charts/hooks/useEmissionChartData.ts
index 441ab3dd62..8ddc1a7c85 100644
--- a/web/src/features/charts/hooks/useEmissionChartData.ts
+++ b/web/src/features/charts/hooks/useEmissionChartData.ts
@@ -4,7 +4,6 @@ import { scaleLinear } from 'd3-scale';
import { useAtom } from 'jotai';
import { productionConsumptionAtom } from 'utils/state/atoms';
-import { getEmissionData } from '../bar-breakdown/utils';
import { getTotalEmissionsAvailable } from '../graphUtils';
import { AreaGraphElement } from '../types';
@@ -46,7 +45,9 @@ export function useEmissionChartData() {
layerStroke: undefined,
};
- const emissionSourceToProductionSource = getEmissionData(data);
-
- return { data: result, emissionSourceToProductionSource, isLoading, isError };
+ return {
+ data: result,
+ isLoading,
+ isError,
+ };
}
diff --git a/web/src/features/charts/hooks/useZoneDataSources.ts b/web/src/features/charts/hooks/useZoneDataSources.ts
new file mode 100644
index 0000000000..6659e30d0d
--- /dev/null
+++ b/web/src/features/charts/hooks/useZoneDataSources.ts
@@ -0,0 +1,150 @@
+import useGetZone from 'api/getZone';
+import { ElectricityModeType, ZoneDetails } from 'types';
+
+export default function useZoneDataSources() {
+ const { data: zoneData, isSuccess } = useGetZone();
+
+ if (!isSuccess) {
+ return {
+ capacitySources: [],
+ powerGenerationSources: [],
+ emissionFactorSources: [],
+ emissionFactorSourcesToProductionSources: {},
+ };
+ }
+
+ const capacitySources = getCapacitySources(zoneData);
+ const powerGenerationSources = getPowerGenerationSources(zoneData);
+ const emissionFactorSourcesToProductionSources =
+ getEmissionFactorSourcesToProductionSource(zoneData);
+ const emissionFactorSources = getEmissionFactorSource(zoneData);
+
+ return {
+ capacitySources,
+ powerGenerationSources,
+ emissionFactorSources,
+ emissionFactorSourcesToProductionSources,
+ };
+}
+
+function getCapacitySources(zoneData: ZoneDetails) {
+ const capacitySources: string[] = [];
+ for (const state of Object.values(zoneData.zoneStates)) {
+ const currentSources = extractUniqueSourcesFromDictionary(state.capacitySources);
+ for (const source of currentSources) {
+ if (!capacitySources.includes(source)) {
+ capacitySources.push(source);
+ }
+ }
+ }
+ return capacitySources;
+}
+
+function extractUniqueSourcesFromDictionary(
+ sourceDict:
+ | {
+ [key in ElectricityModeType]: string[] | null;
+ }
+ | undefined
+): Set {
+ const sourcesWithoutDuplicates: Set = new Set();
+ if (!sourceDict) {
+ return sourcesWithoutDuplicates;
+ }
+ for (const key of Object.keys(sourceDict)) {
+ const capacitySource = sourceDict?.[key as ElectricityModeType];
+ if (capacitySource != null) {
+ for (const source of capacitySource) {
+ sourcesWithoutDuplicates.add(source);
+ }
+ }
+ }
+ return sourcesWithoutDuplicates;
+}
+
+function getPowerGenerationSources(zoneData: ZoneDetails) {
+ const sourceSet = new Set();
+
+ for (const state of Object.values(zoneData.zoneStates)) {
+ const currentSources = state.source;
+ for (const source of currentSources) {
+ sourceSet.add(source);
+ }
+ }
+
+ const sources = [...sourceSet];
+ return sources;
+}
+
+function getEmissionFactorSource(zoneData: ZoneDetails) {
+ const emissionFactorSources = new Set();
+
+ const processSources = (sources: Record) => {
+ for (const source of Object.entries(sources)) {
+ for (const emissionFactorSource of source[1].split('; ')) {
+ if (!emissionFactorSource.startsWith('assumes')) {
+ emissionFactorSources.add(emissionFactorSource);
+ }
+ }
+ }
+ };
+
+ for (const state of Object.values(zoneData.zoneStates)) {
+ processSources(state.productionCo2IntensitySources);
+ processSources(state.dischargeCo2IntensitySources);
+ }
+
+ return [...emissionFactorSources];
+}
+
+function getEmissionFactorSourcesToProductionSource(zoneData: ZoneDetails) {
+ const emissionFactorsourceToProductionSource = {};
+
+ for (const state of Object.values(zoneData.zoneStates)) {
+ updateEmissionFactorSourcesWithProductionSources(
+ state.dischargeCo2IntensitySources,
+ emissionFactorsourceToProductionSource,
+ true
+ );
+ updateEmissionFactorSourcesWithProductionSources(
+ state.productionCo2IntensitySources,
+ emissionFactorsourceToProductionSource
+ );
+ }
+
+ return emissionFactorsourceToProductionSource;
+}
+
+function updateEmissionFactorSourcesWithProductionSources(
+ sources: { [key: string]: string },
+ emissionFactorsourceToProductionSource: { [key: string]: string[] },
+ storageType?: boolean
+) {
+ for (const entry of Object.entries(sources)) {
+ for (const emissionFactorSource of entry[1].split('; ')) {
+ const productionSources = getProductionSourcesToAdd(
+ storageType ? `${entry[0]} storage` : entry[0],
+ emissionFactorsourceToProductionSource[emissionFactorSource],
+ emissionFactorSource
+ );
+ if (productionSources.length > 0) {
+ emissionFactorsourceToProductionSource[emissionFactorSource] = productionSources;
+ }
+ }
+ }
+}
+
+function getProductionSourcesToAdd(
+ productionSource: string,
+ productionSourceArray: string[] | undefined,
+ emissionFactorSource: string
+): string[] {
+ if (emissionFactorSource.startsWith('assumes')) {
+ return [];
+ } else if (productionSourceArray == undefined) {
+ return [productionSource];
+ } else if (!productionSourceArray?.includes(productionSource)) {
+ productionSourceArray?.push(productionSource);
+ }
+ return productionSourceArray;
+}
diff --git a/web/src/features/charts/tooltips/AreaGraphTooltipHeader.tsx b/web/src/features/charts/tooltips/AreaGraphTooltipHeader.tsx
index e9e59eac37..86a8969252 100644
--- a/web/src/features/charts/tooltips/AreaGraphTooltipHeader.tsx
+++ b/web/src/features/charts/tooltips/AreaGraphTooltipHeader.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { TimeAverages } from 'utils/constants';
import { formatDate } from 'utils/formatting';
-import ProductionSourceIcon from '../bar-breakdown/ProductionsSourceIcons';
+import ProductionSourceIcon from '../ProductionsSourceIcons';
interface AreaGraphToolTipHeaderProps {
squareColor: string;
diff --git a/web/src/features/panels/zone/MethodologyCard.tsx b/web/src/features/panels/zone/MethodologyCard.tsx
index 723a25a712..c9a8a596ee 100644
--- a/web/src/features/panels/zone/MethodologyCard.tsx
+++ b/web/src/features/panels/zone/MethodologyCard.tsx
@@ -1,5 +1,5 @@
import Accordion from 'components/Accordion';
-import { RoundedCard } from 'features/charts/bar-breakdown/RoundedCard';
+import { RoundedCard } from 'features/charts/RoundedCard';
import { t } from 'i18next';
import { EmapsIcon } from 'icons/emapsIcon';
import trackEvent from 'utils/analytics';