Skip to content

Commit c59fca4

Browse files
rework notifications
1 parent 754d33d commit c59fca4

File tree

8 files changed

+82
-77
lines changed

8 files changed

+82
-77
lines changed
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import React from 'react';
2+
import { connect } from 'react-redux';
23
import { Alert } from 'react-bootstrap';
3-
import { useNotificationsSystem } from '../contexts/NotificationsContext';
4+
import { NotificationsSystemActions } from '../store/slices/Notifications';
45

5-
function NotificationsArea() {
6-
const NotificationsSystem = useNotificationsSystem();
7-
const { currentNotifications } = NotificationsSystem;
8-
if(!currentNotifications) return null;
9-
10-
const hideNotifications = () => { NotificationsSystem.clear(); };
6+
function NotificationsArea({ hasNotifications, message, clearNotifications }) {
7+
if(!hasNotifications) return null;
118

129
return (
13-
<Alert variant="info" onClose={hideNotifications} dismissible>
14-
{currentNotifications.message}
10+
<Alert variant="info" onClose={clearNotifications} dismissible>
11+
{message}
1512
</Alert>
1613
);
1714
}
1815

19-
export default NotificationsArea;
16+
export default connect(
17+
(state) => ({
18+
hasNotifications: state.notifications.currentNotifications != null,
19+
message: state.notifications.currentNotifications?.message
20+
}), {
21+
clearNotifications: NotificationsSystemActions.clear
22+
}
23+
)(NotificationsArea);

ui/src/components/SystemControls.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,18 @@ import { connect } from 'react-redux';
33
import { Button } from 'react-bootstrap';
44

55
import { useWaterPumpAPI } from '../contexts/WaterPumpAPIContext';
6-
import { useNotificationsSystem } from '../contexts/NotificationsContext.js';
76
import { startPump, stopPump } from '../store/slices/SystemStatus.js';
87

98
export function SystemControlsComponent({
109
pouringTime, systemStatus, startPump, stopPump
1110
}) {
1211
const api = useWaterPumpAPI().API;
13-
const NotificationsSystem = useNotificationsSystem();
14-
1512
const handleStart = async () => {
16-
try {
17-
await startPump({ api , pouringTime });
18-
} catch (error) {
19-
NotificationsSystem.alert('Error starting water pump: ' + error.message);
20-
}
13+
await startPump({ api , pouringTime });
2114
};
2215

2316
const handleStop = async () => {
24-
try {
25-
await stopPump({ api });
26-
} catch (error) {
27-
NotificationsSystem.alert('Error stopping water pump: ' + error.message);
28-
}
17+
await stopPump({ api });
2918
};
3019

3120
const isRunning = systemStatus.pump.running;

ui/src/components/WaterPumpStatusProvider.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ import React from 'react';
22
import { connect } from 'react-redux';
33
import { updateSystemStatus } from '../store/slices/SystemStatus';
44
import { useWaterPumpAPI } from '../contexts/WaterPumpAPIContext';
5-
import { useNotificationsSystem } from '../contexts/NotificationsContext';
65

76
const FETCH_INTERVAL = 5000;
87
const CHECK_INTERVAL = Math.round(FETCH_INTERVAL / 10);
98

109
function WaterPumpStatusProviderComoponent({ children, updateStatus, systemStatus }) {
1110
const { API } = useWaterPumpAPI();
12-
const NotificationsSystem = useNotificationsSystem();
1311
const nextFetchTime = React.useRef(0);
1412

1513
// Function to fetch water pump status
@@ -19,16 +17,10 @@ function WaterPumpStatusProviderComoponent({ children, updateStatus, systemStatu
1917
if(null == API) return;
2018

2119
nextFetchTime.current = Number.MAX_SAFE_INTEGER; // prevent concurrent fetches
22-
try {
23-
const status = await API.status();
24-
updateStatus(status);
25-
} catch (error) {
26-
NotificationsSystem.alert('Error fetching system status: ' + error.message);
27-
updateStatus(null);
28-
}
20+
await updateStatus(API);
2921
nextFetchTime.current = Date.now() + FETCH_INTERVAL;
3022
},
31-
[API, NotificationsSystem, updateStatus, nextFetchTime]
23+
[API, updateStatus, nextFetchTime]
3224
);
3325

3426
// Effect to start fetching periodically and when API changes
@@ -58,6 +50,5 @@ export default connect(
5850
systemStatus: state.systemStatus
5951
}), {
6052
updateStatus: updateSystemStatus
61-
6253
}
6354
)(WaterPumpStatusProviderComoponent);

ui/src/contexts/NotificationsContext.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

ui/src/index.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22
import App from './App.js';
33
import 'bootstrap/dist/css/bootstrap.min.css'; // Importing Bootstrap CSS
44

5-
import { NotificationsProvider } from './contexts/NotificationsContext.js';
65
import { WaterPumpAPIProvider } from './contexts/WaterPumpAPIContext.js';
76
// Redux store
87
import { AppStore } from './store';
@@ -12,11 +11,9 @@ const root = createRoot(document.getElementById('root'));
1211
root.render(
1312
<React.StrictMode>
1413
<AppStore>
15-
<NotificationsProvider>
16-
<WaterPumpAPIProvider>
17-
<App />
18-
</WaterPumpAPIProvider>
19-
</NotificationsProvider>
14+
<WaterPumpAPIProvider>
15+
<App />
16+
</WaterPumpAPIProvider>
2017
</AppStore>
2118
</React.StrictMode>
2219
);

ui/src/store/slices/Notifications.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { createSlice } from '@reduxjs/toolkit';
2+
3+
export const NotificationsSlice = createSlice({
4+
name: 'notifications',
5+
initialState: {
6+
currentNotifications: null
7+
},
8+
reducers: {
9+
alert: (state, action) => {
10+
state.currentNotifications = action.payload;
11+
},
12+
clear: state => {
13+
state.currentNotifications = null;
14+
}
15+
}
16+
});
17+
18+
export const NotificationsSystemActions = NotificationsSlice.actions;

ui/src/store/slices/SystemStatus.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,49 @@
11
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
2+
import { NotificationsSystemActions } from './Notifications';
3+
4+
function withNotification(action, message) {
5+
return async (params, { dispatch }) => {
6+
try {
7+
return await action(params);
8+
} catch(error) {
9+
dispatch(NotificationsSystemActions.alert({
10+
type: 'error',
11+
message: `${message} (${error.message})`
12+
}));
13+
throw error;
14+
}
15+
};
16+
}
217

318
// Async thunks
419
export const startPump = createAsyncThunk(
520
'systemStatus/startPump',
6-
async ({ api, pouringTime }, { dispatch }) => {
7-
const response = await api.start(pouringTime);
8-
return response;
9-
}
21+
withNotification(
22+
async ({ api, pouringTime }) => {
23+
return await api.start(pouringTime);
24+
},
25+
'Failed to start pump'
26+
)
1027
);
1128

1229
export const stopPump = createAsyncThunk(
1330
'systemStatus/stopPump',
14-
async ({ api }, { dispatch }) => {
15-
const response = await api.stop();
16-
return response;
17-
}
31+
withNotification(
32+
async ({ api }) => {
33+
return await api.stop();
34+
},
35+
'Failed to stop pump'
36+
)
37+
);
38+
39+
export const updateSystemStatus = createAsyncThunk(
40+
'systemStatus/update',
41+
withNotification(
42+
async ( api ) => {
43+
return await api.status();
44+
},
45+
'Failed to update system status'
46+
)
1847
);
1948

2049
// slice for system status
@@ -25,18 +54,17 @@ const bindStatus = (state, action) => {
2554
export const SystemStatusSlice = createSlice({
2655
name: 'systemStatus',
2756
initialState: null,
28-
reducers: {
29-
updateSystemStatus: bindStatus,
30-
},
57+
reducers: {},
3158
extraReducers: (builder) => {
3259
// update system status on start/stop pump
3360
builder.addCase(startPump.fulfilled, bindStatus);
3461
builder.addCase(stopPump.fulfilled, bindStatus);
62+
builder.addCase(updateSystemStatus.fulfilled, bindStatus);
3563
// on error, do not update system status
3664
builder.addCase(startPump.rejected, (state, action) => state);
3765
builder.addCase(stopPump.rejected, (state, action) => state);
66+
builder.addCase(updateSystemStatus.rejected, (state, action) => state);
3867
}
3968
});
4069

41-
export const actions = SystemStatusSlice.actions;
42-
export const { updateSystemStatus } = actions;
70+
export const actions = SystemStatusSlice.actions;

ui/src/store/slices/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { SystemStatusSlice } from "./SystemStatus";
22
import { UISlice } from "./UI";
3+
import { NotificationsSlice } from "./Notifications";
34

4-
const slices = [ SystemStatusSlice, UISlice ];
5+
const slices = [ SystemStatusSlice, UISlice, NotificationsSlice ];
56
// export all slices as an object { [sliceName]: slice }
67
export const ALL_APP_SLICES = slices.reduce((acc, slice) => {
78
acc[slice.name] = slice;

0 commit comments

Comments
 (0)