96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import axios from 'axios';
|
|
|
|
interface JobFormProps {
|
|
onJobSubmitted: (jobId: string) => void;
|
|
selectedLat?: string;
|
|
selectedLon?: string;
|
|
}
|
|
|
|
const API_ENDPOINT = 'https://api.portfolio.techarvest.co.zw';
|
|
|
|
const JobForm: React.FC<JobFormProps> = ({ onJobSubmitted, selectedLat, selectedLon }) => {
|
|
const [lat, setLat] = useState<string>('-17.8');
|
|
const [lon, setLon] = useState<string>('31.0');
|
|
const [radius, setRadius] = useState<number>(2000);
|
|
const [year, setYear] = useState<string>('2022');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (selectedLat) setLat(selectedLat);
|
|
if (selectedLon) setLon(selectedLon);
|
|
}, [selectedLat, selectedLon]);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const token = localStorage.getItem('token');
|
|
if (!token) {
|
|
alert('Authentication required.');
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
try {
|
|
const response = await axios.post(`${API_ENDPOINT}/jobs`, {
|
|
lat: parseFloat(lat),
|
|
lon: parseFloat(lon),
|
|
radius_km: radius / 1000,
|
|
year: year,
|
|
model_name: 'Ensemble'
|
|
}, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
onJobSubmitted(response.data.job_id);
|
|
} catch (err) {
|
|
console.error('Failed to submit job:', err);
|
|
alert('Failed to submit job. Check console.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '10px', marginTop: '15px', borderTop: '1px solid #eee', paddingTop: '15px' }}>
|
|
<h2 style={{ fontSize: '16px', margin: 0, fontWeight: 'bold' }}>Submit New Job</h2>
|
|
|
|
<div style={{ display: 'flex', gap: '10px' }}>
|
|
<div style={{ flex: 1 }}>
|
|
<label style={{ fontSize: '11px', color: '#666' }}>Lat</label>
|
|
<input type="text" placeholder="Lat" value={lat} onChange={(e) => setLat(e.target.value)} style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', boxSizing: 'border-box' }} />
|
|
</div>
|
|
<div style={{ flex: 1 }}>
|
|
<label style={{ fontSize: '11px', color: '#666' }}>Lon</label>
|
|
<input type="text" placeholder="Lon" value={lon} onChange={(e) => setLon(e.target.value)} style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', boxSizing: 'border-box' }} />
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label style={{ fontSize: '11px', color: '#666' }}>Radius (meters)</label>
|
|
<input type="number" placeholder="Radius (m)" value={radius} onChange={(e) => setRadius(parseInt(e.target.value))} style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', boxSizing: 'border-box' }} />
|
|
</div>
|
|
<div>
|
|
<label style={{ fontSize: '11px', color: '#666' }}>Season Year</label>
|
|
<select value={year} onChange={(e) => setYear(e.target.value)} style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', boxSizing: 'border-box' }}>
|
|
{[2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025].map(y => (
|
|
<option key={y} value={y.toString()}>{y}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<button type="submit" disabled={loading} style={{
|
|
background: '#28a745',
|
|
color: 'white',
|
|
border: 'none',
|
|
padding: '12px',
|
|
borderRadius: '4px',
|
|
cursor: loading ? 'not-allowed' : 'pointer',
|
|
fontWeight: 'bold',
|
|
marginTop: '5px'
|
|
}}>
|
|
{loading ? 'Submitting...' : 'Run Classification'}
|
|
</button>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default JobForm;
|