Files
scalesApp/frontend/src/components/ReportEditor/ConfigPanel.jsx
T

187 lines
6.7 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { useReportData } from './DataContext';
import { useNomenclatureData } from '../../contexts/NomenclatureDataContext';
import './ConfigPanel.css';
function ConfigPanel({ apiEndpoint, onApiEndpointChange, isOpen, onClose }) {
const { reportData, isLoading, error, fetchData, setData, clearData } = useReportData();
const { definitions, entries } = useNomenclatureData();
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) {
// Build extra sample from actual nomenclature definitions
// Lookup fields become nested objects with all their sub-fields
const extra = {};
for (const def of Object.values(definitions)) {
if (def.kind === 'lookup') {
const activeEntries = (entries[def.code] || []).filter(e => e.is_active);
const firstEntry = activeEntries[0];
if (firstEntry?.data && Object.keys(firstEntry.data).length > 0) {
// Use actual field values from the first active entry
extra[def.name] = { ...firstEntry.data };
} else if (def.fields?.length > 0) {
// No entries yet — build placeholders from field definitions
const sample = {};
for (const field of def.fields) {
if (field.field_type === 'number') sample[field.key] = 0;
else if (field.field_type === 'bool') sample[field.key] = false;
else sample[field.key] = 'Sample';
}
extra[def.name] = sample;
} else {
extra[def.name] = {};
}
} else {
extra[def.name] = 'Sample Text';
}
}
setManualDataInput(JSON.stringify({
vehicle: {
vehicle_number: 'АА1234ВВ',
trailer1_number: 'ПВ5678ВВ',
trailer2_number: null,
driver_pid: '123456789',
tare: 8500,
tare_date: '2026-02-22T08:00:00Z',
tare_user_name: 'operator',
gross: 28500,
gross_date: '2026-02-22T10:30:00Z',
gross_user_name: 'operator',
net: 20000,
net_date: '2026-02-22T10:30:00Z',
net_user_name: 'operator',
doc_number: '2026-001',
extra,
}
}, 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;