Skip to content

Commit e776bae

Browse files
authored
Merge pull request #520 from openclimatefix/issue/519-india-X-forecast
Issue/519 india x forecast
2 parents 932e2e7 + 8c979ec commit e776bae

File tree

11 files changed

+362
-61
lines changed

11 files changed

+362
-61
lines changed

apps/quartz-app/app/globals.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,17 @@ body {
2525
text-wrap: balance;
2626
}
2727
}
28+
29+
.fade-out {
30+
opacity: 1;
31+
animation: fade-out 2s ease-in-out forwards;
32+
}
33+
34+
@keyframes fade-out {
35+
from {
36+
opacity: 1;
37+
}
38+
to {
39+
opacity: 0;
40+
}
41+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
type TooltipProps = {
2+
children: React.ReactNode;
3+
tip: string | React.ReactNode;
4+
position?: "left" | "right" | "middle" | "top";
5+
className?: string;
6+
fullWidth?: boolean;
7+
};
8+
9+
const Tooltip: React.FC<TooltipProps> = ({
10+
children,
11+
tip,
12+
position,
13+
className,
14+
fullWidth = false,
15+
}) => {
16+
let containerPositionClass = "";
17+
let tipPositionClass = "";
18+
switch (position) {
19+
case "left":
20+
containerPositionClass = "right-1";
21+
tipPositionClass = "-right-1 top-2";
22+
break;
23+
case "right":
24+
containerPositionClass = "left-1";
25+
tipPositionClass = "-left-1 top-2";
26+
break;
27+
// case "middle":
28+
// containerPositionClass = "right-5";
29+
// // containerPositionClass = "left-1/2 transform -translate-x-1/2";
30+
// tipPositionClass = "-right-1 top-0";
31+
// break;
32+
// case "top":
33+
// containerPositionClass = "bottom-5 right-2";
34+
// tipPositionClass = "-right-2 bottom-0";
35+
}
36+
return (
37+
<div
38+
className={`relative flex flex-col group z-20 ${
39+
fullWidth ? "w-full" : "w-max items-center"
40+
}
41+
${className || ""}`}
42+
>
43+
{position !== "top" && children}
44+
<div
45+
className={`absolute flex-col items-center hidden mt-6 group-hover:flex w-fit ${containerPositionClass}`}
46+
>
47+
<span
48+
className={`absolute ${tipPositionClass} mb-1 z-30 p-2 text-xs leading-none text-white whitespace-no-wrap bg-ocf-black shadow-lg rounded-md`}
49+
>
50+
{tip}
51+
</span>
52+
{/*<div className="w-3 h-5 -mt-[6px] rotate-45 bg-ocf-black "></div>*/}
53+
</div>
54+
{position === "top" && children}
55+
</div>
56+
);
57+
};
58+
59+
export default Tooltip;

apps/quartz-app/src/components/Main.tsx

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,63 @@ import { useEffect, useMemo } from "react";
1313

1414
export const Main = () => {
1515
const [combinedData, setCombinedData] = useGlobalState("combinedData");
16+
const [forecastHorizon] = useGlobalState("forecastHorizon");
17+
const [forecastHorizonMinutes] = useGlobalState("forecastHorizonMinutes");
1618

17-
const { data: solarRegionsData, error: solarRegionsError } =
18-
useGetRegionsQuery("solar");
19+
const {
20+
data: solarRegionsData,
21+
isLoading: solarRegionsLoading,
22+
error: solarRegionsError,
23+
} = useGetRegionsQuery("solar");
1924

20-
const { data: windRegionsData, error: windRegionsError } =
21-
useGetRegionsQuery("wind");
25+
const {
26+
data: windRegionsData,
27+
isLoading: windRegionsLoading,
28+
error: windRegionsError,
29+
} = useGetRegionsQuery("wind");
2230

23-
const { data: solarGenerationData, error: solarGenerationError } =
24-
useGetGenerationForRegionQuery(
25-
"solar",
26-
solarRegionsData?.regions[0] || "",
27-
!!solarRegionsData?.regions[0]
28-
);
29-
const { data: windGenerationData, error: windGenerationError } =
30-
useGetGenerationForRegionQuery(
31-
"wind",
32-
windRegionsData?.regions[0] || "",
33-
!!windRegionsData?.regions[0]
34-
);
31+
const {
32+
data: solarGenerationData,
33+
isLoading: solarGenerationLoading,
34+
error: solarGenerationError,
35+
} = useGetGenerationForRegionQuery(
36+
"solar",
37+
solarRegionsData?.regions[0] || "",
38+
!!solarRegionsData?.regions[0]
39+
);
40+
const {
41+
data: windGenerationData,
42+
isLoading: windGenerationLoading,
43+
error: windGenerationError,
44+
} = useGetGenerationForRegionQuery(
45+
"wind",
46+
windRegionsData?.regions[0] || "",
47+
!!windRegionsData?.regions[0]
48+
);
3549

3650
// Get forecast data
37-
const { data: solarForecastData, error: solarForecastError } =
38-
useGetForecastedGenerationForRegionQuery(
39-
"solar",
40-
solarRegionsData?.regions[0] || "",
41-
!!solarRegionsData?.regions[0]
42-
);
43-
const { data: windForecastData, error: windForecastError } =
44-
useGetForecastedGenerationForRegionQuery(
45-
"wind",
46-
windRegionsData?.regions[0] || "",
47-
!!windRegionsData?.regions[0]
48-
);
51+
const {
52+
data: solarForecastData,
53+
isLoading: solarForecastLoading,
54+
error: solarForecastError,
55+
} = useGetForecastedGenerationForRegionQuery(
56+
"solar",
57+
solarRegionsData?.regions[0] || "",
58+
!!solarRegionsData?.regions[0],
59+
forecastHorizon,
60+
forecastHorizonMinutes
61+
);
62+
const {
63+
data: windForecastData,
64+
isLoading: windForecastLoading,
65+
error: windForecastError,
66+
} = useGetForecastedGenerationForRegionQuery(
67+
"wind",
68+
windRegionsData?.regions[0] || "",
69+
!!windRegionsData?.regions[0],
70+
forecastHorizon,
71+
forecastHorizonMinutes
72+
);
4973

5074
const latestCombinedData: CombinedData = useMemo(() => {
5175
return {
@@ -66,6 +90,24 @@ export const Main = () => {
6690
setCombinedData(latestCombinedData);
6791
}, [latestCombinedData]);
6892

93+
const isLoading = useMemo(() => {
94+
return (
95+
solarForecastLoading ||
96+
windForecastLoading ||
97+
solarGenerationLoading ||
98+
windGenerationLoading ||
99+
solarRegionsLoading ||
100+
windRegionsLoading
101+
);
102+
}, [
103+
solarForecastLoading,
104+
windForecastLoading,
105+
solarGenerationLoading,
106+
windGenerationLoading,
107+
solarRegionsLoading,
108+
windRegionsLoading,
109+
]);
110+
69111
if (
70112
solarRegionsError ||
71113
windRegionsError ||
@@ -83,7 +125,11 @@ export const Main = () => {
83125
solarForecastError,
84126
windForecastError
85127
);
86-
return <div>Error</div>;
128+
return (
129+
<div className="text-white flex items-center justify-center absolute inset-0">
130+
An error has occurred. Please refresh, or try again shortly.
131+
</div>
132+
);
87133
}
88134

89135
return (
@@ -95,7 +141,7 @@ export const Main = () => {
95141
solarGenerationData={solarGenerationData}
96142
windGenerationData={windGenerationData}
97143
/>
98-
<Charts combinedData={combinedData} />
144+
<Charts combinedData={combinedData} isLoading={isLoading} />
99145
</>
100146
);
101147
};

apps/quartz-app/src/components/charts/Charts.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ import {
1212
} from "recharts";
1313
// @ts-ignore
1414
import { theme } from "@/tailwind.config";
15-
import { FC, ReactNode } from "react";
15+
import { ChangeEvent, FC, useEffect } from "react";
1616
import {
1717
ACTUAL_SOLAR_COLOR,
1818
ACTUAL_WIND_COLOR,
1919
SOLAR_COLOR,
2020
WIND_COLOR,
2121
} from "@/src/constants";
22-
import { LegendContainer } from "@/src/components/charts/legend/LegendContainer";
2322
import {
2423
formatEpochToHumanDayName,
2524
formatEpochToPrettyTime,
@@ -32,12 +31,15 @@ import { useChartData } from "@/src/hooks/useChartData";
3231
import { CustomLabel } from "@/src/components/charts/labels/CustomLabel";
3332
import { useGlobalState } from "../helpers/globalState";
3433
import { DateTime } from "luxon";
34+
import { Spinner, SpinnerTextInline } from "@/src/components/icons/icons";
35+
import HorizonSelect from "@/src/components/charts/HorizonSelect";
3536

3637
type ChartsProps = {
3738
combinedData: CombinedData;
39+
isLoading: boolean;
3840
};
3941

40-
const Charts: FC<ChartsProps> = ({ combinedData }) => {
42+
const Charts: FC<ChartsProps> = ({ combinedData, isLoading }) => {
4143
const { data, error } = useGetRegionsQuery("solar");
4244
console.log("Charts data test", data);
4345
const formattedChartData = useChartData(combinedData);
@@ -70,6 +72,22 @@ const Charts: FC<ChartsProps> = ({ combinedData }) => {
7072

7173
return (
7274
<div className="flex-1 flex flex-col justify-center items-center bg-ocf-grey-800">
75+
<div className="flex flex-1 w-full items-center justify-between -mb-6 py-3 px-4">
76+
<div className="flex">
77+
{isLoading ? (
78+
<div className="pointer-events-none text-white px-2.5 py-0.5 rounded-md bg-ocf-black flex items-center gap-2">
79+
Loading data <SpinnerTextInline />
80+
</div>
81+
) : (
82+
<div className="fade-out pointer-events-none text-white px-2.5 py-0.5 rounded-md bg-ocf-black flex items-center">
83+
Data loaded
84+
</div>
85+
)}
86+
</div>
87+
<div className="flex gap-5">
88+
<HorizonSelect />
89+
</div>
90+
</div>
7391
<div style={{ position: "relative", width: "100%", height: "100%" }}>
7492
{/* Helps with the resizing of the chart in both axes */}
7593
<div
@@ -81,6 +99,13 @@ const Charts: FC<ChartsProps> = ({ combinedData }) => {
8199
top: 0,
82100
}}
83101
>
102+
{isLoading && (
103+
<div
104+
className={`absolute flex pb-7 items-center justify-center inset-0 z-30`}
105+
>
106+
<Spinner className="w-10 h-10 fill-ocf-yellow text-ocf-grey-700" />
107+
</div>
108+
)}
84109
<ResponsiveContainer>
85110
<ComposedChart
86111
data={formattedChartData}

0 commit comments

Comments
 (0)