added vehicles and vehicles extra, dynamic tables for entities, dynamic dropdowns with overlay for selecting and manage data

This commit is contained in:
2026-02-10 17:32:33 +02:00
parent ed35a90cc0
commit 6a42099169
60 changed files with 4845 additions and 81 deletions
@@ -0,0 +1,158 @@
import { useState, useMemo } from 'react';
import { useNomenclatureData } from '../../contexts/NomenclatureDataContext';
import NomenclatureManagementOverlay from './NomenclatureManagementOverlay';
import './NomenclatureDropdown.css';
export default function NomenclatureDropdown({
nomenclatureCode,
value,
onChange,
label,
disabled = false,
}) {
const { definitions, getActiveEntries, isLoading } = useNomenclatureData();
const [showOverlay, setShowOverlay] = useState(false);
const nomenclature = definitions[nomenclatureCode];
const activeEntries = useMemo(
() => getActiveEntries(nomenclatureCode),
[getActiveEntries, nomenclatureCode]
);
if (!nomenclature) {
if (isLoading) {
return (
<div className="nui-dropdown">
{label && <label className="nui-dropdown-label">{label}</label>}
<select disabled className="nui-dropdown-select">
<option>Loading...</option>
</select>
</div>
);
}
return null;
}
const displayLabel = label || nomenclature.name;
// LOOKUP type: select dropdown + manage button
if (nomenclature.kind === 'lookup') {
const handleSelectChange = (e) => {
const val = e.target.value;
onChange(val ? parseInt(val, 10) : undefined);
};
const handleOverlaySelect = (entryId) => {
onChange(entryId);
setShowOverlay(false);
};
return (
<div className="nui-dropdown">
<label className="nui-dropdown-label">{displayLabel}</label>
<div className="nui-dropdown-row">
<select
className="nui-dropdown-select"
value={value || ''}
onChange={handleSelectChange}
disabled={disabled}
>
<option value="">-- Select --</option>
{activeEntries.map(entry => (
<option key={entry.id} value={entry.id}>
{entry.display_value}
</option>
))}
</select>
<button
className="nui-dropdown-manage-btn"
onClick={() => setShowOverlay(true)}
disabled={disabled}
type="button"
title={`Manage ${displayLabel}`}
>
&#8230;
</button>
</div>
<NomenclatureManagementOverlay
nomenclatureCode={nomenclatureCode}
isOpen={showOverlay}
onClose={() => setShowOverlay(false)}
mode="select"
initialSelection={value || null}
onSelect={handleOverlaySelect}
/>
</div>
);
}
// FIELD type: render appropriate input
const fieldDef = nomenclature.fields?.[0];
if (!fieldDef) return null;
if (fieldDef.field_type === 'bool') {
return (
<div className="nui-dropdown">
<label className="nui-dropdown-label nui-dropdown-label--checkbox">
<input
type="checkbox"
checked={value || false}
onChange={(e) => onChange(e.target.checked)}
disabled={disabled}
className="nui-dropdown-checkbox"
/>
{displayLabel}
</label>
</div>
);
}
if (fieldDef.field_type === 'number') {
return (
<div className="nui-dropdown">
<label className="nui-dropdown-label">{displayLabel}</label>
<input
type="number"
className="nui-dropdown-input"
value={value ?? ''}
onChange={(e) => onChange(e.target.value === '' ? undefined : Number(e.target.value))}
disabled={disabled}
/>
</div>
);
}
if (fieldDef.field_type === 'choice' && fieldDef.choices) {
return (
<div className="nui-dropdown">
<label className="nui-dropdown-label">{displayLabel}</label>
<select
className="nui-dropdown-select"
value={value || ''}
onChange={(e) => onChange(e.target.value || undefined)}
disabled={disabled}
>
<option value="">-- Select --</option>
{fieldDef.choices.map(c => (
<option key={c} value={c}>{c}</option>
))}
</select>
</div>
);
}
// Default: text input
return (
<div className="nui-dropdown">
<label className="nui-dropdown-label">{displayLabel}</label>
<input
type="text"
className="nui-dropdown-input"
value={value || ''}
onChange={(e) => onChange(e.target.value || undefined)}
disabled={disabled}
/>
</div>
);
}