From 1bf04ff9cc92f5b9b37b1cd9bed2b9ef362f2336 Mon Sep 17 00:00:00 2001 From: cesarLima1 <105736261+cesarLima1@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:13:18 -0400 Subject: [PATCH] [TM-1466] add donut chart for eco region monitored data (#736) --- .../MonitoredTab/components/DataCard.tsx | 9 +- .../components/EcoRegionDoughnutChart.tsx | 128 ++++++++++++++++++ src/constants/dashboardConsts.ts | 5 + src/utils/dashboardUtils.ts | 30 ++++ 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/admin/components/ResourceTabs/MonitoredTab/components/EcoRegionDoughnutChart.tsx diff --git a/src/admin/components/ResourceTabs/MonitoredTab/components/DataCard.tsx b/src/admin/components/ResourceTabs/MonitoredTab/components/DataCard.tsx index 0767c613f..094718899 100644 --- a/src/admin/components/ResourceTabs/MonitoredTab/components/DataCard.tsx +++ b/src/admin/components/ResourceTabs/MonitoredTab/components/DataCard.tsx @@ -26,6 +26,7 @@ import Icon, { IconNames } from "@/components/extensive/Icon/Icon"; import { CHART_TYPES, DEFAULT_POLYGONS_DATA, + DEFAULT_POLYGONS_DATA_ECOREGIONS, DEFAULT_POLYGONS_DATA_STRATEGIES, DUMMY_DATA_FOR_CHART_SIMPLE_BAR_CHART } from "@/constants/dashboardConsts"; @@ -39,12 +40,14 @@ import { TOTAL_HECTARES_UNDER_RESTORATION_TOOLTIP } from "@/pages/dashboard/cons import { EntityName, OptionValue } from "@/types/common"; import { isEmptyChartData, + parsePolygonsIndicatorDataForEcoRegion, parsePolygonsIndicatorDataForLandUse, parsePolygonsIndicatorDataForStrategies } from "@/utils/dashboardUtils"; import { downloadFileBlob } from "@/utils/network"; import { useMonitoredData } from "../hooks/useMonitoredData"; +import EcoRegionDoughnutChart from "./EcoRegionDoughnutChart"; interface TableData { polygonName: string; @@ -413,6 +416,10 @@ const DataCard = ({ ? parsePolygonsIndicatorDataForStrategies(polygonsIndicator) : DEFAULT_POLYGONS_DATA_STRATEGIES; + const ecoRegionData: any = polygonsIndicator + ? parsePolygonsIndicatorDataForEcoRegion(polygonsIndicator) + : DEFAULT_POLYGONS_DATA_ECOREGIONS; + const [topHeaderFirstTable, setTopHeaderFirstTable] = useState("102px"); const [topHeaderSecondTable, setTopHeaderSecondTable] = useState("70px"); @@ -675,7 +682,7 @@ const DataCard = ({ - +
diff --git a/src/admin/components/ResourceTabs/MonitoredTab/components/EcoRegionDoughnutChart.tsx b/src/admin/components/ResourceTabs/MonitoredTab/components/EcoRegionDoughnutChart.tsx new file mode 100644 index 000000000..c0a4efc4f --- /dev/null +++ b/src/admin/components/ResourceTabs/MonitoredTab/components/EcoRegionDoughnutChart.tsx @@ -0,0 +1,128 @@ +import React, { useState } from "react"; +import { Cell, Label, Legend, Pie, PieChart, ResponsiveContainer, Sector, Tooltip } from "recharts"; + +interface ChartDataItem { + name: string; + value: number; +} + +export interface EcoRegionData { + chartData: ChartDataItem[]; + total: number; +} + +interface EcoRegionDoughnutChartProps { + data: EcoRegionData; +} + +type LegendPayload = { + value: string; + id?: string; + type?: string; + color?: string; +}; + +interface CustomLegendProps { + payload?: LegendPayload[]; +} + +const COLORS = ["#FFD699", "#90EE90", "#2F4F4F", "#BDB76B", "#98FB98"]; + +const CustomLegend = ({ payload }: CustomLegendProps) => { + if (!payload) return null; + return ( + + ); +}; + +const CustomTooltip = ({ active, payload }: any) => { + if (active && payload && payload.length) { + return ( +
+

{payload[0].name}

+

{`Value: ${payload[0].value}`}

+
+ ); + } + return null; +}; + +const renderActiveShape = (props: any) => { + const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill } = props; + return ( + + + + ); +}; + +const EcoRegionDoughnutChart: React.FC = ({ data }) => { + const { chartData } = data; + const [activeIndex, setActiveIndex] = useState(undefined); + + const onPieEnter = (_: any, index: number) => { + setActiveIndex(index); + }; + + const onPieLeave = () => { + setActiveIndex(undefined); + }; + + return ( +
+ + + } /> + + + {chartData.map((entry, index) => ( + + ))} + + } + layout="vertical" + align="right" + verticalAlign="middle" + wrapperStyle={{ + right: 0, + left: 400, + paddingLeft: 0 + }} + /> + + +
+ ); +}; + +export default EcoRegionDoughnutChart; diff --git a/src/constants/dashboardConsts.ts b/src/constants/dashboardConsts.ts index b64565569..71f1f109e 100644 --- a/src/constants/dashboardConsts.ts +++ b/src/constants/dashboardConsts.ts @@ -58,6 +58,11 @@ export const DEFAULT_POLYGONS_DATA_STRATEGIES = [ { label: "Multiple Strategies", value: 0 } ]; +export const DEFAULT_POLYGONS_DATA_ECOREGIONS = { + chartData: [], + total: 0 +}; + export const DUMMY_DATA_FOR_CHART_MULTI_LINE_CHART = [ { name: "Total", diff --git a/src/utils/dashboardUtils.ts b/src/utils/dashboardUtils.ts index 8137e4ab2..b2dd8436b 100644 --- a/src/utils/dashboardUtils.ts +++ b/src/utils/dashboardUtils.ts @@ -139,6 +139,11 @@ export interface ParsedPolygonsData { }; } +interface ParsedResult { + chartData: ChartDataItem[]; + total: number; +} + export const formatNumberUS = (value: number) => value ? (value >= 1000000 ? `${(value / 1000000).toFixed(2)}M` : value.toLocaleString("en-US")) : ""; @@ -519,3 +524,28 @@ export const parsePolygonsIndicatorDataForStrategies = (polygonsIndicator: Polyg value: Number(value.toFixed(2)) })); }; + +export const parsePolygonsIndicatorDataForEcoRegion = (polygons: PolygonIndicator[]): ParsedResult => { + const result: ParsedResult = { + chartData: [], + total: 0 + }; + + const ecoRegionMap = new Map(); + + polygons.forEach(polygon => { + polygon.data && + Object.entries(polygon.data).forEach(([name, value]) => { + ecoRegionMap.set(name, (ecoRegionMap.get(name) || 0) + value); + }); + }); + + result.chartData = Array.from(ecoRegionMap, ([name, value]) => ({ + name: formatLabel(name), + value: Number(value.toFixed(3)) + })); + + result.total = Number(result.chartData.reduce((sum, item) => sum + Number(item.value), 0).toFixed(3)); + + return result; +};