added vehicles and vehicles extra, dynamic tables for entities, dynamic dropdowns with overlay for selecting and manage data
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useReportData } from './DataContext';
|
||||
import './ConfigPanel.css';
|
||||
|
||||
function ConfigPanel({ apiEndpoint, onApiEndpointChange, isOpen, onClose }) {
|
||||
const { reportData, isLoading, error, fetchData, setData, clearData } = useReportData();
|
||||
const [localEndpoint, setLocalEndpoint] = useState(apiEndpoint || '');
|
||||
const [manualDataInput, setManualDataInput] = useState('');
|
||||
const [showManualInput, setShowManualInput] = useState(false);
|
||||
|
||||
const handleFetch = async () => {
|
||||
if (localEndpoint.trim()) {
|
||||
onApiEndpointChange(localEndpoint);
|
||||
await fetchData(localEndpoint);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSetManualData = () => {
|
||||
const trimmedInput = manualDataInput.trim();
|
||||
|
||||
if (!trimmedInput) {
|
||||
alert('Please enter some JSON data first');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(trimmedInput);
|
||||
setData(data);
|
||||
setShowManualInput(false);
|
||||
setManualDataInput('');
|
||||
} catch (err) {
|
||||
alert('Invalid JSON: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
clearData();
|
||||
setLocalEndpoint('');
|
||||
onApiEndpointChange('');
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="config-panel-overlay" onClick={onClose}>
|
||||
<div className="config-panel" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="config-panel-header">
|
||||
<h2>Report Configuration</h2>
|
||||
<button className="close-button" onClick={onClose}>×</button>
|
||||
</div>
|
||||
|
||||
<div className="config-panel-content">
|
||||
{/* API Endpoint Section */}
|
||||
<div className="config-section">
|
||||
<h3>API Endpoint</h3>
|
||||
<div className="input-group">
|
||||
<input
|
||||
type="text"
|
||||
className="config-input"
|
||||
placeholder="http://localhost:8000/api/report-data"
|
||||
value={localEndpoint}
|
||||
onChange={(e) => setLocalEndpoint(e.target.value)}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<button
|
||||
className="config-button primary"
|
||||
onClick={handleFetch}
|
||||
disabled={isLoading || !localEndpoint.trim()}
|
||||
>
|
||||
{isLoading ? 'Fetching...' : 'Fetch Data'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="config-error">
|
||||
<strong>Error:</strong> {error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Manual Data Input Section */}
|
||||
<div className="config-section">
|
||||
<button
|
||||
className="config-button"
|
||||
onClick={() => {
|
||||
if (!showManualInput && !manualDataInput) {
|
||||
// Pre-fill with example data when opening for the first time
|
||||
setManualDataInput(JSON.stringify({
|
||||
"reportTitle": "Weight Measurements Report",
|
||||
"reportDate": "2026-01-26",
|
||||
"owner": {
|
||||
"name": "John Doe",
|
||||
"contact": {
|
||||
"phone": "555-1234",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
},
|
||||
"vessel": {
|
||||
"id": "ABC123",
|
||||
"type": "Truck",
|
||||
"capacity": 5000
|
||||
},
|
||||
"measurements": [
|
||||
{
|
||||
"id": 1,
|
||||
"weight": 1500,
|
||||
"timestamp": "2026-01-26T08:00:00",
|
||||
"operator": "Alice",
|
||||
"items": [
|
||||
{ "name": "Box A", "quantity": 10, "unitWeight": 50 },
|
||||
{ "name": "Box B", "quantity": 20, "unitWeight": 25 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"weight": 1650,
|
||||
"timestamp": "2026-01-26T09:30:00",
|
||||
"operator": "Bob",
|
||||
"items": [
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Pallet D", "quantity": 15, "unitWeight": 30 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"weight": 1820,
|
||||
"timestamp": "2026-01-26T11:15:00",
|
||||
"operator": "Charlie",
|
||||
"items": [
|
||||
{ "name": "Container E", "quantity": 8, "unitWeight": 75 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"weight": 41820,
|
||||
"timestamp": "2026-01-26T11:15:00",
|
||||
"operator": "4Charlie",
|
||||
"items": [
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Crate C", "quantity": 5, "unitWeight": 100 },
|
||||
{ "name": "Container E", "quantity": 8, "unitWeight": 75 }
|
||||
]
|
||||
}
|
||||
|
||||
],
|
||||
"summary": {
|
||||
"totalMeasurements": 3,
|
||||
"averageWeight": 1656.67,
|
||||
"maxWeight": 1820,
|
||||
"minWeight": 1500
|
||||
}
|
||||
}, null, 2));
|
||||
}
|
||||
setShowManualInput(!showManualInput);
|
||||
}}
|
||||
>
|
||||
{showManualInput ? 'Hide' : 'Enter'} Manual Data (JSON)
|
||||
</button>
|
||||
|
||||
{showManualInput && (
|
||||
<div className="manual-input-section">
|
||||
<textarea
|
||||
className="manual-data-input"
|
||||
placeholder='{"owner": {"name": "John Doe"}, "vessel": {"id": "ABC123"}}'
|
||||
value={manualDataInput}
|
||||
onChange={(e) => setManualDataInput(e.target.value)}
|
||||
rows={8}
|
||||
/>
|
||||
<button
|
||||
className="config-button primary"
|
||||
onClick={handleSetManualData}
|
||||
>
|
||||
Set Data
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Data Preview Section */}
|
||||
{reportData && (
|
||||
<div className="config-section">
|
||||
<div className="section-header">
|
||||
<h3>Current Data</h3>
|
||||
<button className="config-button small" onClick={handleClear}>
|
||||
Clear Data
|
||||
</button>
|
||||
</div>
|
||||
<div className="data-preview">
|
||||
<pre>{JSON.stringify(reportData, null, 2)}</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!reportData && !isLoading && !error && (
|
||||
<div className="config-info">
|
||||
No data loaded. Enter an API endpoint to fetch data, or use manual input.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConfigPanel;
|
||||
Reference in New Issue
Block a user