diff options
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/App.css | 9 | ||||
| -rw-r--r-- | frontend/src/App.js | 8 | ||||
| -rw-r--r-- | frontend/src/Info.js | 5 | ||||
| -rw-r--r-- | frontend/src/InfoDisplay.js | 2 | ||||
| -rw-r--r-- | frontend/src/Options.js | 170 | ||||
| -rw-r--r-- | frontend/src/Path.js | 5 |
6 files changed, 166 insertions, 33 deletions
diff --git a/frontend/src/App.css b/frontend/src/App.css index cc8ccba..19cf08b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -3,15 +3,6 @@ background: url(topo.svg), #111; } - -.App-logo { - height: 40vmin; - max-height: 256px; - pointer-events: none; - - mix-blend-mode: lighten; -} - .App-header { background-color: #282c34; min-height: 100vh; diff --git a/frontend/src/App.js b/frontend/src/App.js index 463566a..569ff74 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,3 @@ -import logo from './logo.png'; import './App.css'; import Path from './Path'; @@ -13,7 +12,7 @@ function App() { <div className="w-2/3 h-full overflow-auto hide-scrollbar"> <Path /> </div> - {/* Sidebar for Options, LogComponent, and Logo */} + {/* Sidebar for route info, controls, and log output */} <div className="w-1/3 h-full flex flex-col"> <div className="h-1/4 overflow-auto"> <Info /> @@ -21,12 +20,9 @@ function App() { <div className="h-1/4 overflow-auto"> <Options /> </div> - <div className="h-1/4 overflow-auto"> + <div className="flex-1 overflow-auto"> <Log/> </div> - <div className="h-1/4 flex items-center justify-center overflow-auto"> - <img src={logo} className="App-logo" alt="logo" /> - </div> </div> </div> ); diff --git a/frontend/src/Info.js b/frontend/src/Info.js index 3fcfa3e..d46d914 100644 --- a/frontend/src/Info.js +++ b/frontend/src/Info.js @@ -1,9 +1,10 @@ import React from 'react'; -import usePolling from './usePolling'; +import useSSE from './useSSE'; import InfoDisplay from './InfoDisplay'; // Import the DataDisplay component const Info = () => { - const { data, error } = usePolling('http://localhost:8000/route_info', 1000); + const { data: sseData, error } = useSSE('http://localhost:8000/data_stream'); + const data = sseData ? sseData.route_info : null; return ( <div className="text-white"> diff --git a/frontend/src/InfoDisplay.js b/frontend/src/InfoDisplay.js index 2253802..c8a77c1 100644 --- a/frontend/src/InfoDisplay.js +++ b/frontend/src/InfoDisplay.js @@ -36,7 +36,7 @@ const InfoDisplay = ({ data }) => { <td>{riskPercent} ({riskCost} isk)</td> </tr> <tr> - <td style={{ textAlign: 'left' }}>Capital:</td> + <td style={{ textAlign: 'left' }}>Peak Capital:</td> <td>{capitalFormatted} isk</td> </tr> <tr> diff --git a/frontend/src/Options.js b/frontend/src/Options.js index 4c8a7e9..b490f67 100644 --- a/frontend/src/Options.js +++ b/frontend/src/Options.js @@ -1,29 +1,173 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import './Options.css'; +import useSSE from './useSSE'; const Options = () => { const [message, setMessage] = useState(''); + const [messageType, setMessageType] = useState('info'); + const [isSettingWaypoints, setIsSettingWaypoints] = useState(false); + const [settings, setSettings] = useState({ + cargo: '', + max_warp_speed: '', + max_subwarp_speed: '', + risk_cost: '', + ship_cost: '', + tax_rate: '', + profit_threshold: '', + max_capital: '', + snipe_profit_threshold: '' + }); + const { data: sseData } = useSSE('http://localhost:8000/data_stream'); + const route = Array.isArray(sseData?.route) ? sseData.route : []; + const hasRouteWaypoints = route.length > 1; - const handleClick = async () => { - setMessage('Sending request...'); + useEffect(() => { + fetch('http://localhost:8000/settings') + .then(res => res.json()) + .then(data => { + setSettings({ + cargo: data.cargo, + max_warp_speed: data.max_warp_speed, + max_subwarp_speed: data.max_subwarp_speed, + risk_cost: data.risk_cost, + ship_cost: data.ship_cost, + tax_rate: data.tax_rate, + profit_threshold: data.profit_threshold, + max_capital: data.max_capital, + snipe_profit_threshold: data.snipe_profit_threshold + }); + }) + .catch(err => console.error("Error fetching settings", err)); + }, []); + + const handleSettingsChange = (e) => { + const { name, value } = e.target; + setSettings(prev => ({ ...prev, [name]: value })); + }; + + const handleSaveSettings = async () => { try { - const response = await fetch('http://localhost:8000/create_route', { method: 'POST' }); - const data = await response.json(); - setMessage(`Response received: ${JSON.stringify(data)}`); + const response = await fetch('http://localhost:8000/settings', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + cargo: Number(settings.cargo), + max_warp_speed: Number(settings.max_warp_speed), + max_subwarp_speed: Number(settings.max_subwarp_speed), + risk_cost: Number(settings.risk_cost), + ship_cost: Number(settings.ship_cost), + tax_rate: Number(settings.tax_rate), + profit_threshold: Number(settings.profit_threshold), + max_capital: Number(settings.max_capital), + snipe_profit_threshold: Number(settings.snipe_profit_threshold) + }) + }); + if (response.ok) { + setMessageType('success'); + setMessage('Settings saved'); + setTimeout(() => setMessage(''), 3000); + } + } catch (error) { + setMessageType('error'); + setMessage(`Error: ${error.message}`); + } + }; + + const handleCreateRoute = async () => { + try { + await fetch('http://localhost:8000/create_route', { method: 'POST' }); } catch (error) { setMessage(`Error: ${error}`); } }; + const handleSetWaypoints = async () => { + if (!hasRouteWaypoints) { + setMessageType('error'); + setMessage('No route exists'); + return; + } + + setIsSettingWaypoints(true); + setMessageType('info'); + setMessage('Sending to EVE...'); + try { + const response = await fetch('http://localhost:8000/set_waypoints', { method: 'POST' }); + const resData = await response.json(); + const nextMessage = resData.message || resData.status || 'Waypoint request completed'; + const nextType = resData.success ? 'success' : resData.status === 'partial' ? 'warning' : 'error'; + setMessageType(nextType); + setMessage(nextMessage); + if (resData.success) { + setTimeout(() => setMessage(''), 4000); + } + } catch (error) { + setMessageType('error'); + setMessage(`Error: ${error}`); + } finally { + setIsSettingWaypoints(false); + } + }; + + const messageClassName = messageType === 'error' + ? 'mb-1 text-red-400' + : messageType === 'warning' + ? 'mb-1 text-yellow-300' + : 'mb-1 text-green-400'; + + const waypointButtonClassName = hasRouteWaypoints && !isSettingWaypoints + ? 'options-button flex-1 px-2 py-1 text-sm bg-green-700 hover:bg-green-600 text-white rounded' + : 'options-button flex-1 px-2 py-1 text-sm bg-green-900 text-white rounded opacity-50 cursor-not-allowed'; + return ( - <div className="p-8"> - <button - className="options-button" - onClick={handleClick} - > - Create Route + <div className="p-2 options-container flex flex-col content-start h-full text-white text-xs"> + <div className="flex gap-2 mb-2"> + <button className="options-button flex-1 px-2 py-1 text-sm bg-blue-600 hover:bg-blue-500 text-white rounded" onClick={handleCreateRoute}> + Create Route + </button> + <button + className={waypointButtonClassName} + onClick={handleSetWaypoints} + disabled={!hasRouteWaypoints || isSettingWaypoints} + > + Set in Game + </button> + </div> + + {message && <p className={messageClassName}>{message}</p>} + + <div className="settings-form grid grid-cols-4 gap-x-2 gap-y-1 items-center"> + <label>Cargo (m³)</label> + <input name="cargo" type="number" value={settings.cargo} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Risk (ISK)</label> + <input name="risk_cost" type="number" value={settings.risk_cost} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Warp (AU/s)</label> + <input name="max_warp_speed" type="number" step="0.1" value={settings.max_warp_speed} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Ship (ISK)</label> + <input name="ship_cost" type="number" value={settings.ship_cost} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Sub (m/s)</label> + <input name="max_subwarp_speed" type="number" step="0.1" value={settings.max_subwarp_speed} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Tax (%)</label> + <input name="tax_rate" type="number" step="0.1" value={settings.tax_rate} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Prof. Thr.</label> + <input name="profit_threshold" type="number" value={settings.profit_threshold} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Max Cap.</label> + <input name="max_capital" type="number" value={settings.max_capital} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + + <label>Snipe Thr.</label> + <input name="snipe_profit_threshold" type="number" value={settings.snipe_profit_threshold} onChange={handleSettingsChange} className="text-black p-1 w-full" /> + </div> + + <button className="mt-2 bg-blue-600 hover:bg-blue-500 py-1 px-2 text-white font-bold rounded" onClick={handleSaveSettings}> + Save </button> - <p className='text-white pt-2'>{message}</p> </div> ); } diff --git a/frontend/src/Path.js b/frontend/src/Path.js index f375743..3fd50ea 100644 --- a/frontend/src/Path.js +++ b/frontend/src/Path.js @@ -1,9 +1,10 @@ import React from 'react'; -import usePolling from './usePolling'; +import useSSE from './useSSE'; import DataDisplay from './DataDisplay'; // Import the DataDisplay component const Path = () => { - const { data, error } = usePolling('http://localhost:8000/route', 1000); + const { data: sseData, error } = useSSE('http://localhost:8000/data_stream'); + const data = sseData ? sseData.route : null; return ( <div className="text-white"> |
