diff --git a/ui/src/App.js b/ui/src/App.js index d88e43a..854ceae 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -1,22 +1,20 @@ import React, { useState, useEffect } from 'react'; +import './App.css'; import { Container, Row, Col, Form, Button } from 'react-bootstrap'; -import { CWaterPumpAPI } from './api/CWaterPumpAPI.js'; + +import { useWaterPumpAPI } from './contexts/WaterPumpAPIContext'; import { useNotificationsSystem } from './contexts/NotificationsContext.js'; -import './App.css'; import NotificationsArea from './components/NotificationsArea.js'; +import APIAddressField from './components/APIAddressField'; -const STORE_API = 'apiAddress'; const STORE_RUNTIME = 'runTime'; function App() { - const [apiAddress, setApiAddress] = useState(''); + const waterPumpCtx = useWaterPumpAPI(); const [runTime, setRunTime] = useState(1000); const NotificationsSystem = useNotificationsSystem(); useEffect(() => { - const storedApiAddress = localStorage.getItem(STORE_API); - if (storedApiAddress) setApiAddress(storedApiAddress); - let storedRunTime = localStorage.getItem(STORE_RUNTIME); if (storedRunTime) { if (typeof storedRunTime === 'string') { @@ -25,18 +23,16 @@ function App() { setRunTime(storedRunTime); } }, []); - - const waterPumpAPI = React.useMemo(() => { - let url = apiAddress; - if (!url.startsWith('http://') && !url.startsWith('https://')) { - url = 'http://' + url; - } - return new CWaterPumpAPI({ URL: url }); - }, [apiAddress]); + + const handleRunTimeChange = (event) => { + const runTime = parseInt(event.target.value, 10); + setRunTime(runTime); + localStorage.setItem(STORE_RUNTIME, runTime); + }; const handleStart = async () => { try { - await waterPumpAPI.start(runTime); + await waterPumpCtx.API.start(runTime); NotificationsSystem.alert('Water pump started successfully!'); } catch (error) { NotificationsSystem.alert('Error starting water pump: ' + error.message); @@ -45,38 +41,19 @@ function App() { const handleStop = async () => { try { - await waterPumpAPI.stop(); + await waterPumpCtx.API.stop(); NotificationsSystem.alert('Water pump stopped successfully!'); } catch (error) { NotificationsSystem.alert('Error stopping water pump: ' + error.message); } }; - const handleRunTimeChange = (event) => { - const runTime = parseInt(event.target.value, 10); - setRunTime(runTime); - localStorage.setItem(STORE_RUNTIME, runTime); - }; - - const handleApiAddressChange = (event) => { - const apiAddress = event.target.value; - setApiAddress(apiAddress); - localStorage.setItem(STORE_API, apiAddress); - }; - return (

Tea System UI

- - - API Address: - - - - - + Run Time (ms): diff --git a/ui/src/components/APIAddressField.js b/ui/src/components/APIAddressField.js new file mode 100644 index 0000000..de85e67 --- /dev/null +++ b/ui/src/components/APIAddressField.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { Row, Col, Form } from 'react-bootstrap'; +import { useWaterPumpAPI } from '../contexts/WaterPumpAPIContext'; + +function APIAddressField() { + const waterPumpCtx = useWaterPumpAPI(); + + const handleApiAddressChange = (event) => { + const apiAddress = event.target.value; + waterPumpCtx.bindApiHost(apiAddress); + }; + + return ( + + + API Address: + + + + + + ); +} + +export default APIAddressField; \ No newline at end of file diff --git a/ui/src/contexts/WaterPumpAPIContext.js b/ui/src/contexts/WaterPumpAPIContext.js new file mode 100644 index 0000000..a97e3d8 --- /dev/null +++ b/ui/src/contexts/WaterPumpAPIContext.js @@ -0,0 +1,47 @@ +import React from 'react'; +import { CWaterPumpAPI } from '../api/CWaterPumpAPI.js'; + +const STORE_API = 'apiAddress'; +const WaterPumpAPIContext = React.createContext(); + +export function useWaterPumpAPI() { + return React.useContext(WaterPumpAPIContext); +} + +function preprocessApiHost(apiHost) { + let url = apiHost; + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = 'http://' + url; + } + if (!url.endsWith('/')) url += '/'; + return url; +} + +export function WaterPumpAPIProvider({ children }) { + const [apiHost, setApiHost] = React.useState(''); + React.useEffect(() => { + const storedApiHost = localStorage.getItem(STORE_API); + if (storedApiHost) setApiHost(storedApiHost); + }, []); // on mount only + + const apiObject = React.useMemo(() => { + if (!apiHost) return null; // not ready yet + + const url = preprocessApiHost(apiHost); + localStorage.setItem(STORE_API, url); + return new CWaterPumpAPI({ URL: url }); + }, [apiHost] + ); + + const value = { + API: apiObject, + apiHost: apiHost, + bindApiHost: setApiHost, + }; + + return ( + + {children} + + ); +} diff --git a/ui/src/index.js b/ui/src/index.js index 9ea6ccb..175c001 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -4,11 +4,14 @@ import App from './App.js'; import 'bootstrap/dist/css/bootstrap.min.css'; // Importing Bootstrap CSS import { NotificationsProvider } from './contexts/NotificationsContext.js'; +import { WaterPumpAPIProvider } from './contexts/WaterPumpAPIContext.js'; ReactDOM.render( - + + + , document.getElementById('root')