Added SignalR for real-time progress updates during weather data fetch. Refactored WeatherPage to use a new reusable WeatherGrid component and SignalRHelper. Improved loading UI with a radial progress indicator.
76 lines
3.4 KiB
TypeScript
76 lines
3.4 KiB
TypeScript
import with_main_layout from "../../layouts/with_main_layout.ts.tsx";
|
|
import useLocalStorageState from 'use-local-storage-state'; // install via npm
|
|
import {Client, WeatherForecast} from "../../ApiCient.ts";
|
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|
import {faDownload, faTrash} from "@fortawesome/free-solid-svg-icons";
|
|
import {useState} from "react";
|
|
import WeatherGrid from "./WeatherGrid.tsx";
|
|
import {useSignalR} from "../../signalr/SignalRHelper.ts";
|
|
|
|
function WeatherPage() {
|
|
// Use the hook to persist your weather data. It will default to null.
|
|
const [weatherData, setWeatherData] = useLocalStorageState<WeatherForecast[] | null>('WeatherPage-Forecast', {defaultValue: [],});
|
|
const [loading, setLoading] = useState(false);
|
|
const [currentState, setCurrentState] = useState<string | null>(null);
|
|
const {subscribe} = useSignalR('http://localhost:5175', 'WeatherUpdateHub');
|
|
|
|
|
|
const fetchWeatherData = async () => {
|
|
const apiClient = new Client();
|
|
try {
|
|
const progressCleanup = subscribe<string>('ProgressUpdate', (_, message) => {
|
|
setCurrentState(message);
|
|
});
|
|
setLoading(true);
|
|
const data = await apiClient.getWeatherForecast();
|
|
setWeatherData(data);
|
|
setLoading(false);
|
|
progressCleanup();
|
|
setCurrentState(null);
|
|
} catch (error) {
|
|
console.error("Error fetching weather data:", error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="card shadow-md card-sm w-full bg-auto-50">
|
|
<div className="card-header text-2xl ml-5 mt-1">Weather Data</div>
|
|
<div className="card-body">
|
|
<div className="row-auto flex gap-x-2 ">
|
|
<button className="btn w-48" onClick={fetchWeatherData}>
|
|
<FontAwesomeIcon className="mr-1" icon={faDownload}/>
|
|
Fetch Weather Data
|
|
</button>
|
|
<button className="btn w-48" onClick={() => setWeatherData(null)}>
|
|
<FontAwesomeIcon className="mr-1" icon={faTrash}/>
|
|
Clear Weather
|
|
</button>
|
|
</div>
|
|
<div className="mt-5">
|
|
{loading ?
|
|
<div>
|
|
{/*<p className="m-5">Progress: {currentState ? JSON.parse(currentState).percentage : 0}% - {currentState ? JSON.parse(currentState).message : ''}</p>*/}
|
|
{(() => {
|
|
const percentage = currentState ? JSON.parse(currentState).percentage : 0;
|
|
return (
|
|
<div className="radial-progress" style={{['--value' as unknown as string]: percentage}} aria-valuenow={percentage} role="progressbar">
|
|
{percentage}%
|
|
</div>
|
|
);
|
|
})()}
|
|
</div>
|
|
:
|
|
!weatherData || weatherData.length === 0 ? (
|
|
<p>No weather data, please request it!</p>
|
|
) : (
|
|
<WeatherGrid data={weatherData}/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export const PageWithLayout = with_main_layout(WeatherPage);
|
|
export default PageWithLayout;
|