Skip to content

Commit ff6af46

Browse files
committed
Fix selected UPS card not updating in real-time
- Implemented reducer pattern in Dashboard component for better state management - Added forceUpdate counter to trigger re-renders when UPS data changes - Ensured both small UPS cards and detailed UPS view stay in sync - Used key prop with dynamic values to force component re-rendering - Improved data synchronization between UPS list and detailed view
1 parent 512a360 commit ff6af46

File tree

2 files changed

+66
-18
lines changed

2 files changed

+66
-18
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to the PowerPulse project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.9.1] - 2025-03-01
8+
## [1.9.1] - 2025-03-02
99

1010
### Added
1111
- Documented previously undocumented API endpoints:
@@ -21,6 +21,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2121
- Added data sampling for multi-day views to get a more representative sample across the full time range
2222
- Increased record limit for multi-day views to provide better data coverage
2323
- Enhanced logging for better troubleshooting of time filter issues
24+
- Fixed selected UPS card not updating in real-time:
25+
- Implemented reducer pattern in Dashboard component for better state management
26+
- Added forceUpdate counter to trigger re-renders when UPS data changes
27+
- Ensured both small UPS cards and detailed UPS view stay in sync
28+
- Used key prop with dynamic values to force component re-rendering
29+
- Improved data synchronization between UPS list and detailed view
2430

2531
### Improved
2632
- Simplified battery history implementation:

client/src/pages/Dashboard.jsx

+59-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useReducer } from 'react';
22
import axios from 'axios';
33
import { FiBattery, FiAlertCircle, FiClock, FiThermometer, FiPercent, FiZap, FiActivity, FiRefreshCw, FiCalendar, FiFilter } from 'react-icons/fi';
44
import { useSettings } from '../context/SettingsContext';
@@ -30,11 +30,45 @@ ChartJS.register(
3030

3131
const Dashboard = () => {
3232
const { getPollIntervalMs, settings } = useSettings();
33-
const [upsSystems, setUpsSystems] = useState([]);
34-
const [loading, setLoading] = useState(true);
35-
const [error, setError] = useState(null);
36-
const [selectedUps, setSelectedUps] = useState(null);
33+
// Define reducer for dashboard state
34+
const initialState = {
35+
upsSystems: [],
36+
loading: true,
37+
error: null,
38+
selectedUpsId: null,
39+
lastUpdated: new Date(),
40+
forceUpdate: 0 // Used to force re-renders
41+
};
42+
43+
const dashboardReducer = (state, action) => {
44+
switch (action.type) {
45+
case 'SET_UPS_SYSTEMS':
46+
return {
47+
...state,
48+
upsSystems: action.payload,
49+
lastUpdated: new Date(),
50+
forceUpdate: state.forceUpdate + 1 // Increment to force re-render
51+
};
52+
case 'SET_LOADING':
53+
return { ...state, loading: action.payload };
54+
case 'SET_ERROR':
55+
return { ...state, error: action.payload };
56+
case 'SET_SELECTED_UPS_ID':
57+
return { ...state, selectedUpsId: action.payload };
58+
default:
59+
return state;
60+
}
61+
};
62+
63+
// Use reducer instead of multiple useState calls
64+
const [state, dispatch] = useReducer(dashboardReducer, initialState);
65+
const { upsSystems, loading, error, selectedUpsId, lastUpdated, forceUpdate } = state;
66+
67+
// Get the selected UPS from the current state
68+
const selectedUps = upsSystems.find(ups => ups.id === selectedUpsId) || null;
69+
3770
const [timeFilter, setTimeFilter] = useState(3); // Default to 3 days
71+
3872
const {
3973
batteryHistory,
4074
loading: historyLoading,
@@ -43,37 +77,45 @@ const Dashboard = () => {
4377
refreshData: refreshBatteryHistory,
4478
currentTimeFilter
4579
} = useBatteryHistory(selectedUps?.id, timeFilter);
46-
const [lastUpdated, setLastUpdated] = useState(new Date());
4780

81+
// Effect for fetching UPS systems data
4882
useEffect(() => {
4983
const fetchUpsSystems = async () => {
5084
try {
51-
setLoading(true);
85+
dispatch({ type: 'SET_LOADING', payload: true });
5286
const response = await axios.get('/api/ups/systems');
53-
setUpsSystems(response.data);
54-
setLastUpdated(new Date());
87+
const data = response.data;
5588

56-
if (response.data.length > 0 && !selectedUps) {
57-
setSelectedUps(response.data[0]);
89+
// Set initial selection if needed
90+
if (data.length > 0 && !selectedUpsId) {
91+
dispatch({ type: 'SET_SELECTED_UPS_ID', payload: data[0].id });
5892
}
93+
94+
dispatch({ type: 'SET_UPS_SYSTEMS', payload: data });
95+
96+
// Log for debugging
97+
console.log('UPS systems data fetched:', data);
5998
} catch (err) {
60-
setError('Failed to fetch UPS systems. Please check your connection to the NUT server.');
99+
dispatch({
100+
type: 'SET_ERROR',
101+
payload: 'Failed to fetch UPS systems. Please check your connection to the NUT server.'
102+
});
61103
console.error('Error fetching UPS systems:', err);
62104
} finally {
63-
setLoading(false);
105+
dispatch({ type: 'SET_LOADING', payload: false });
64106
}
65107
};
66108

67109
fetchUpsSystems();
68110

69-
// Set up polling for real-time updates using the configured poll interval
111+
// Set up polling for real-time updates
70112
const interval = setInterval(fetchUpsSystems, getPollIntervalMs());
71113

72114
return () => clearInterval(interval);
73-
}, [getPollIntervalMs, selectedUps]);
115+
}, [getPollIntervalMs, selectedUpsId]); // Added selectedUpsId back to ensure proper initial selection
74116

75117
const handleUpsSelect = (ups) => {
76-
setSelectedUps(ups);
118+
dispatch({ type: 'SET_SELECTED_UPS_ID', payload: ups.id });
77119
};
78120

79121
const getStatusColor = (status) => {
@@ -226,7 +268,7 @@ const Dashboard = () => {
226268
{/* Selected UPS Details */}
227269
<div className="md:col-span-2">
228270
{selectedUps && (
229-
<div className="space-y-6">
271+
<div className="space-y-6" key={`${selectedUps.id}-${selectedUps.batteryCharge}-${forceUpdate}`}>
230272
<div className="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
231273
<div className="px-4 py-5 sm:px-6 border-b dark:border-gray-700 flex justify-between items-center">
232274
<div>

0 commit comments

Comments
 (0)