From 81200c9c4a3a031f729b56d45217654927d91f81 Mon Sep 17 00:00:00 2001 From: thehighestprimenumber Date: Thu, 20 Feb 2025 16:49:41 -0300 Subject: [PATCH 1/3] bug: [ON-3326] fix tooltip out of bounds --- .../EmissionsForecastChart.tsx | 121 ++----------- .../EmissionsForecast/TooltipCard.tsx | 159 ++++++++++++++++++ 2 files changed, 174 insertions(+), 106 deletions(-) create mode 100644 app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx diff --git a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/EmissionsForecastChart.tsx b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/EmissionsForecastChart.tsx index 71b59a85f..c5e6f7b18 100644 --- a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/EmissionsForecastChart.tsx +++ b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/EmissionsForecastChart.tsx @@ -1,20 +1,16 @@ import { EmissionsForecastData } from "@/util/types"; import type { TFunction } from "i18next"; import { - getReferenceNumberByName, getSectorByName, getSectorByReferenceNumber, getSubSectorByName, getSubSectorByReferenceNumber, - ISector, } from "@/util/constants"; -import { Box, Card, Heading, HStack, Table, Text } from "@chakra-ui/react"; -import { convertKgToTonnes, toKebabCase } from "@/util/helpers"; +import { Box } from "@chakra-ui/react"; +import { convertKgToTonnes } from "@/util/helpers"; import { ResponsiveLine } from "@nivo/line"; import CustomLegend from "@/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/CustomLegend"; -import { ColoredCircle } from "@/components/ColoredCircle"; -import { ButtonSmall } from "@/components/Texts/Button"; -import { TitleMedium } from "@/components/Texts/Title"; +import TooltipCard from "./TooltipCard"; interface LineChartData { id: string; @@ -93,105 +89,18 @@ export const EmissionsForecastChart = ({ format: (value: number) => convertKgToTonnes(value), }} colors={colors} - tooltip={({ point }) => { - const year = point.data.x; - const sumOfYs = data.reduce((sum, series) => { - const yearData = series.data.find(({ x }) => x === year); - return sum + parseInt((yearData?.y as unknown as string) || "0"); - }, 0); - - return ( - - - {t("year")} - - {year as unknown as string} - - - - - - - - {t("sector").toUpperCase()} - - - {t("rate").toUpperCase()} - - - % - - - - {t("total-emissions").toUpperCase()} - - - - - - {data.map(({ data, id }) => { - const yearData = data.find( - ({ x }) => x === point.data.x, - ); - const percentage = yearData - ? ((yearData.y / sumOfYs) * 100).toFixed(2) - : 0; - const sectorRefNo = - getReferenceNumberByName( - toKebabCase(id as string) as keyof ISector, - ) || getSubSectorByName(id)?.referenceNumber; - - const yearGrowthRates = - yearData && - forecast.growthRates[yearData.x as string]; - const growthRate = - yearGrowthRates?.[sectorRefNo!] || - yearGrowthRates?.[point.serieId as string]; - - return ( - - - - - {t(id)} - - - {growthRate} - {percentage}% - - {convertKgToTonnes( - parseInt(yearData?.y as unknown as string), - )} - - - ); - })} - - - {t("total").toUpperCase()} - - - - - {convertKgToTonnes(sumOfYs)} - - - - - - - - ); - }} + tooltip={({ point }) => ( + + )} + enableSlices="x" + sliceTooltip={({ slice }) => ( + + )} enableGridX={false} enableGridY={false} enablePoints={false} diff --git a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx new file mode 100644 index 000000000..296324c3c --- /dev/null +++ b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx @@ -0,0 +1,159 @@ +import React from "react"; +import { Box, Card, Heading, HStack, Table, Text } from "@chakra-ui/react"; +import { convertKgToTonnes, toKebabCase } from "@/util/helpers"; +import { + getReferenceNumberByName, + getSubSectorByName, + ISector, +} from "@/util/constants"; +import { ColoredCircle } from "@/components/ColoredCircle"; +import { ButtonSmall } from "@/components/Texts/Button"; +import { TitleMedium } from "@/components/Texts/Title"; +import { getColorForSeries } from "./EmissionsForecastChart"; +import type { TFunction } from "i18next"; + +interface PointData { + x: string; + y: number; + yStacked: number; + xFormatted: string; + yFormatted: string; +} + +interface Point { + id: string; + index: number; + serieId: string; + serieColor: string; + x: number; + y: number; + color: string; + borderColor: string; + data: PointData; +} + +interface TooltipCardProps { + point: Point; + data: { id: string; color: string; data: { x: string; y: string }[] }[]; + forecast: any; + t: TFunction; +} + +const TooltipCard = ({ point, data, forecast, t }: TooltipCardProps) => { + console.log("point", JSON.stringify(point, null, 2)); // TODO NINA + console.log("data", JSON.stringify(data, null, 2)); // TODO NINA + console.log("forecast", JSON.stringify(forecast, null, 2)); // TODO NINA + const year = point.data.x; + const sumOfYs = data.reduce((sum, series) => { + const yearData = series.data.find(({ x }) => x === year); + return sum + parseInt((yearData?.y as unknown as string) || "0"); + }, 0); + + // Get the container width + const containerWidth = typeof window !== "undefined" ? window.innerWidth : 0; + // Get the x position from the point + const xPosition = point.x; + const GRAPH_RATIO = 0.68; // the ratio of the graph to the container + // Determine if we're in the left or right half of the screen + const isLeftHalf = xPosition < (containerWidth * GRAPH_RATIO) / 2; + return ( +
+ + + {t("year")} + + {year as unknown as string} + + + + + + + + {t("sector").toUpperCase()} + + + {t("rate").toUpperCase()} + + + % + + + + {t("total-emissions").toUpperCase()} + + + + + + {data.map(({ data, id }) => { + const yearData = data.find(({ x }) => x === point.data.x); + const percentage = yearData + ? ((parseInt(yearData.y) / sumOfYs) * 100).toFixed(2) + : 0; + const sectorRefNo = + getReferenceNumberByName( + toKebabCase(id as string) as keyof ISector, + ) || getSubSectorByName(id)?.referenceNumber; + + const yearGrowthRates = + yearData && forecast.growthRates[yearData.x as string]; + const growthRate = + yearGrowthRates?.[sectorRefNo!] || + yearGrowthRates?.[point.serieId as string]; + + return ( + + + + + {t(id)} + + + {growthRate} + {percentage}% + + {convertKgToTonnes( + parseInt(yearData?.y as unknown as string), + )} + + + ); + })} + + + {t("total").toUpperCase()} + + + + + {convertKgToTonnes(sumOfYs)} + + + + + + +
+ ); +}; + +export default TooltipCard; From 4abdaa3659ada9c9ac37da30245628690ba0b197 Mon Sep 17 00:00:00 2001 From: thehighestprimenumber Date: Fri, 21 Feb 2025 09:45:52 -0300 Subject: [PATCH 2/3] bug: [ON-3326] korbit review --- .../EmissionsForecast/TooltipCard.tsx | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx index 296324c3c..16c69cd08 100644 --- a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx +++ b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { Box, Card, Heading, HStack, Table, Text } from "@chakra-ui/react"; import { convertKgToTonnes, toKebabCase } from "@/util/helpers"; import { @@ -11,6 +11,7 @@ import { ButtonSmall } from "@/components/Texts/Button"; import { TitleMedium } from "@/components/Texts/Title"; import { getColorForSeries } from "./EmissionsForecastChart"; import type { TFunction } from "i18next"; +import { EmissionsForecastData } from "@/util/types"; interface PointData { x: string; @@ -35,26 +36,43 @@ interface Point { interface TooltipCardProps { point: Point; data: { id: string; color: string; data: { x: string; y: string }[] }[]; - forecast: any; + forecast: EmissionsForecastData; t: TFunction; } +function debounce(func: Function, wait: number) { + let timeout: NodeJS.Timeout; + return function (this: void, ...args: any[]) { + clearTimeout(timeout); + timeout = setTimeout(() => func.apply(this, args), wait); + }; +} + const TooltipCard = ({ point, data, forecast, t }: TooltipCardProps) => { - console.log("point", JSON.stringify(point, null, 2)); // TODO NINA - console.log("data", JSON.stringify(data, null, 2)); // TODO NINA - console.log("forecast", JSON.stringify(forecast, null, 2)); // TODO NINA + const [containerWidth, setContainerWidth] = useState( + typeof window !== "undefined" ? window.innerWidth : 0, + ); + + const handleResize = useCallback(() => { + setContainerWidth(window.innerWidth); + }, []); + + useEffect(() => { + const debouncedResize = debounce(handleResize, 100); + window.addEventListener("resize", debouncedResize); + return () => { + window.removeEventListener("resize", debouncedResize); + }; + }, [handleResize]); + const year = point.data.x; const sumOfYs = data.reduce((sum, series) => { const yearData = series.data.find(({ x }) => x === year); return sum + parseInt((yearData?.y as unknown as string) || "0"); }, 0); - // Get the container width - const containerWidth = typeof window !== "undefined" ? window.innerWidth : 0; - // Get the x position from the point const xPosition = point.x; - const GRAPH_RATIO = 0.68; // the ratio of the graph to the container - // Determine if we're in the left or right half of the screen + const GRAPH_RATIO = 0.68; const isLeftHalf = xPosition < (containerWidth * GRAPH_RATIO) / 2; return (
Date: Mon, 24 Feb 2025 10:19:55 -0300 Subject: [PATCH 3/3] bug: [ON-3326] fix build --- .../EmissionsForecast/TooltipCard.tsx | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx index 16c69cd08..4c2ebb5e6 100644 --- a/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx +++ b/app/src/app/[lng]/[inventory]/InventoryResultTab/EmissionsForecast/TooltipCard.tsx @@ -12,30 +12,17 @@ import { TitleMedium } from "@/components/Texts/Title"; import { getColorForSeries } from "./EmissionsForecastChart"; import type { TFunction } from "i18next"; import { EmissionsForecastData } from "@/util/types"; +import type { Point } from "@nivo/line"; -interface PointData { - x: string; - y: number; - yStacked: number; - xFormatted: string; - yFormatted: string; -} - -interface Point { +interface LineChartData { id: string; - index: number; - serieId: string; - serieColor: string; - x: number; - y: number; color: string; - borderColor: string; - data: PointData; + data: { x: string; y: number }[]; } interface TooltipCardProps { point: Point; - data: { id: string; color: string; data: { x: string; y: string }[] }[]; + data: LineChartData[]; forecast: EmissionsForecastData; t: TFunction; } @@ -122,7 +109,7 @@ const TooltipCard = ({ point, data, forecast, t }: TooltipCardProps) => { {data.map(({ data, id }) => { const yearData = data.find(({ x }) => x === point.data.x); const percentage = yearData - ? ((parseInt(yearData.y) / sumOfYs) * 100).toFixed(2) + ? ((yearData.y / sumOfYs) * 100).toFixed(2) : 0; const sectorRefNo = getReferenceNumberByName(