Updates to database and API for dropdowns.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { apiClient } from '../../../core/api/client';
|
||||
import { Vehicle, CreateVehicleRequest, UpdateVehicleRequest, DropdownOption, VINDecodeResponse } from '../types/vehicles.types';
|
||||
import { Vehicle, CreateVehicleRequest, UpdateVehicleRequest, VINDecodeResponse } from '../types/vehicles.types';
|
||||
|
||||
// All requests (including dropdowns) use authenticated apiClient
|
||||
|
||||
@@ -38,28 +38,28 @@ export const vehiclesApi = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getMakes: async (year: number): Promise<DropdownOption[]> => {
|
||||
getMakes: async (year: number): Promise<string[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/makes?year=${year}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getModels: async (year: number, makeId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/models?year=${year}&make_id=${makeId}`);
|
||||
getModels: async (year: number, make: string): Promise<string[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/models?year=${year}&make=${encodeURIComponent(make)}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTransmissions: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/transmissions?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
getTransmissions: async (year: number, make: string, model: string): Promise<string[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/transmissions?year=${year}&make=${encodeURIComponent(make)}&model=${encodeURIComponent(model)}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getEngines: async (year: number, makeId: number, modelId: number, trimId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/engines?year=${year}&make_id=${makeId}&model_id=${modelId}&trim_id=${trimId}`);
|
||||
getEngines: async (year: number, make: string, model: string, trim: string): Promise<string[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/engines?year=${year}&make=${encodeURIComponent(make)}&model=${encodeURIComponent(model)}&trim=${encodeURIComponent(trim)}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTrims: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/trims?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
getTrims: async (year: number, make: string, model: string): Promise<string[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/trims?year=${year}&make=${encodeURIComponent(make)}&model=${encodeURIComponent(model)}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { Button } from '../../../shared-minimal/components/Button';
|
||||
import { CreateVehicleRequest, DropdownOption } from '../types/vehicles.types';
|
||||
import { CreateVehicleRequest } from '../types/vehicles.types';
|
||||
import { vehiclesApi } from '../api/vehicles.api';
|
||||
|
||||
const vehicleSchema = z
|
||||
@@ -68,21 +68,20 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
loading,
|
||||
}) => {
|
||||
const [years, setYears] = useState<number[]>([]);
|
||||
const [makes, setMakes] = useState<DropdownOption[]>([]);
|
||||
const [models, setModels] = useState<DropdownOption[]>([]);
|
||||
const [engines, setEngines] = useState<DropdownOption[]>([]);
|
||||
const [trims, setTrims] = useState<DropdownOption[]>([]);
|
||||
const [transmissions, setTransmissions] = useState<DropdownOption[]>([]);
|
||||
const [makes, setMakes] = useState<string[]>([]);
|
||||
const [models, setModels] = useState<string[]>([]);
|
||||
const [engines, setEngines] = useState<string[]>([]);
|
||||
const [trims, setTrims] = useState<string[]>([]);
|
||||
const [transmissions, setTransmissions] = useState<string[]>([]);
|
||||
const [selectedYear, setSelectedYear] = useState<number | undefined>();
|
||||
const [selectedMake, setSelectedMake] = useState<DropdownOption | undefined>();
|
||||
const [selectedModel, setSelectedModel] = useState<DropdownOption | undefined>();
|
||||
const [selectedMake, setSelectedMake] = useState<string>('');
|
||||
const [selectedModel, setSelectedModel] = useState<string>('');
|
||||
const [selectedTrim, setSelectedTrim] = useState<string>('');
|
||||
const [loadingDropdowns, setLoadingDropdowns] = useState(false);
|
||||
const [selectedTrim, setSelectedTrim] = useState<DropdownOption | undefined>();
|
||||
const [decodingVIN, setDecodingVIN] = useState(false);
|
||||
const [decodeSuccess, setDecodeSuccess] = useState(false);
|
||||
const hasInitialized = useRef(false);
|
||||
const isInitializing = useRef(false);
|
||||
const [dropdownsReady, setDropdownsReady] = useState(false);
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -157,57 +156,51 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
try {
|
||||
setLoadingDropdowns(true);
|
||||
|
||||
// Set year and load makes
|
||||
// Step 1: Set year and load makes
|
||||
setSelectedYear(initialData.year);
|
||||
const makesData = await vehiclesApi.getMakes(initialData.year);
|
||||
setMakes(makesData);
|
||||
|
||||
if (initialData.make) {
|
||||
const makeOption = makesData.find(m => m.name === initialData.make);
|
||||
if (makeOption) {
|
||||
setSelectedMake(makeOption);
|
||||
|
||||
// Load models
|
||||
const modelsData = await vehiclesApi.getModels(initialData.year, makeOption.id);
|
||||
setModels(modelsData);
|
||||
|
||||
if (initialData.model) {
|
||||
const modelOption = modelsData.find(m => m.name === initialData.model);
|
||||
if (modelOption) {
|
||||
setSelectedModel(modelOption);
|
||||
|
||||
// Load trims and transmissions in parallel
|
||||
const [trimsData, transmissionsData] = await Promise.all([
|
||||
vehiclesApi.getTrims(initialData.year, makeOption.id, modelOption.id),
|
||||
vehiclesApi.getTransmissions(initialData.year, makeOption.id, modelOption.id)
|
||||
]);
|
||||
setTrims(trimsData);
|
||||
setTransmissions(transmissionsData);
|
||||
|
||||
if (initialData.trimLevel) {
|
||||
const trimOption = trimsData.find(t => t.name === initialData.trimLevel);
|
||||
if (trimOption) {
|
||||
setSelectedTrim(trimOption);
|
||||
|
||||
// Load engines
|
||||
const enginesData = await vehiclesApi.getEngines(
|
||||
initialData.year,
|
||||
makeOption.id,
|
||||
modelOption.id,
|
||||
trimOption.id
|
||||
);
|
||||
setEngines(enginesData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!initialData.make) {
|
||||
isInitializing.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal that dropdowns are ready
|
||||
setDropdownsReady(true);
|
||||
// Step 2: Set make and load models
|
||||
setSelectedMake(initialData.make);
|
||||
const modelsData = await vehiclesApi.getModels(initialData.year, initialData.make);
|
||||
setModels(modelsData);
|
||||
|
||||
if (!initialData.model) {
|
||||
isInitializing.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: Set model and load trims + transmissions
|
||||
setSelectedModel(initialData.model);
|
||||
const [trimsData, transmissionsData] = await Promise.all([
|
||||
vehiclesApi.getTrims(initialData.year, initialData.make, initialData.model),
|
||||
vehiclesApi.getTransmissions(initialData.year, initialData.make, initialData.model)
|
||||
]);
|
||||
setTrims(trimsData);
|
||||
setTransmissions(transmissionsData);
|
||||
|
||||
if (initialData.trimLevel) {
|
||||
// Step 4: Set trim and load engines
|
||||
setSelectedTrim(initialData.trimLevel);
|
||||
const enginesData = await vehiclesApi.getEngines(
|
||||
initialData.year,
|
||||
initialData.make,
|
||||
initialData.model,
|
||||
initialData.trimLevel
|
||||
);
|
||||
setEngines(enginesData);
|
||||
}
|
||||
|
||||
isInitializing.current = false;
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize edit mode:', error);
|
||||
isInitializing.current = false;
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
@@ -216,37 +209,12 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
initializeEditMode();
|
||||
}, [initialData]); // Run when initialData is available
|
||||
|
||||
// Reset form values after dropdowns are loaded and rendered
|
||||
// Reset form values after initialization
|
||||
useEffect(() => {
|
||||
if (!dropdownsReady || !initialData) return;
|
||||
|
||||
let timer2: NodeJS.Timeout;
|
||||
|
||||
// Use setTimeout to ensure React has rendered the dropdown options
|
||||
const timer1 = setTimeout(() => {
|
||||
// Normalize the data to match dropdown option values (lowercase)
|
||||
const normalizedData = {
|
||||
...initialData,
|
||||
make: initialData.make?.toLowerCase(),
|
||||
model: initialData.model?.toLowerCase(),
|
||||
trimLevel: initialData.trimLevel,
|
||||
transmission: initialData.transmission,
|
||||
engine: initialData.engine
|
||||
};
|
||||
|
||||
reset(normalizedData);
|
||||
|
||||
// Mark initialization complete after a delay to allow effects to process
|
||||
timer2 = setTimeout(() => {
|
||||
isInitializing.current = false;
|
||||
}, 100);
|
||||
}, 50);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer1);
|
||||
if (timer2) clearTimeout(timer2);
|
||||
};
|
||||
}, [dropdownsReady, initialData, reset]);
|
||||
if (!isInitializing.current && initialData) {
|
||||
reset(initialData);
|
||||
}
|
||||
}, [initialData, reset]);
|
||||
|
||||
// Load makes when year changes
|
||||
useEffect(() => {
|
||||
@@ -262,17 +230,18 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
setSelectedYear(watchedYear);
|
||||
|
||||
// Clear dependent selections
|
||||
setSelectedMake('');
|
||||
setSelectedModel('');
|
||||
setSelectedTrim('');
|
||||
setModels([]);
|
||||
setEngines([]);
|
||||
setTrims([]);
|
||||
setEngines([]);
|
||||
setTransmissions([]);
|
||||
setSelectedMake(undefined);
|
||||
setSelectedModel(undefined);
|
||||
setValue('make', '');
|
||||
setValue('model', '');
|
||||
setValue('trimLevel', '');
|
||||
setValue('transmission', '');
|
||||
setValue('engine', '');
|
||||
setValue('trimLevel', '');
|
||||
} catch (error) {
|
||||
console.error('Failed to load makes:', error);
|
||||
setMakes([]);
|
||||
@@ -290,76 +259,70 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
// Skip during initialization
|
||||
if (isInitializing.current) return;
|
||||
|
||||
if (watchedMake && watchedYear && watchedMake !== selectedMake?.name) {
|
||||
const makeOption = makes.find(make => make.name === watchedMake);
|
||||
if (makeOption) {
|
||||
const loadModels = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const modelsData = await vehiclesApi.getModels(watchedYear, makeOption.id);
|
||||
setModels(modelsData);
|
||||
setSelectedMake(makeOption);
|
||||
if (watchedMake && watchedYear && watchedMake !== selectedMake) {
|
||||
const loadModels = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const modelsData = await vehiclesApi.getModels(watchedYear, watchedMake);
|
||||
setModels(modelsData);
|
||||
setSelectedMake(watchedMake);
|
||||
|
||||
// Clear dependent selections
|
||||
setEngines([]);
|
||||
setTrims([]);
|
||||
setTransmissions([]);
|
||||
setSelectedModel(undefined);
|
||||
setValue('model', '');
|
||||
setValue('transmission', '');
|
||||
setValue('engine', '');
|
||||
setValue('trimLevel', '');
|
||||
} catch (error) {
|
||||
console.error('Failed to load models:', error);
|
||||
setModels([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
// Clear dependent selections
|
||||
setSelectedModel('');
|
||||
setSelectedTrim('');
|
||||
setTrims([]);
|
||||
setEngines([]);
|
||||
setTransmissions([]);
|
||||
setValue('model', '');
|
||||
setValue('trimLevel', '');
|
||||
setValue('transmission', '');
|
||||
setValue('engine', '');
|
||||
} catch (error) {
|
||||
console.error('Failed to load models:', error);
|
||||
setModels([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadModels();
|
||||
}
|
||||
loadModels();
|
||||
}
|
||||
}, [watchedMake, watchedYear, selectedMake, makes, setValue]);
|
||||
}, [watchedMake, watchedYear, selectedMake, setValue]);
|
||||
|
||||
// Load trims when model changes
|
||||
// Load trims and transmissions when model changes
|
||||
useEffect(() => {
|
||||
// Skip during initialization
|
||||
if (isInitializing.current) return;
|
||||
|
||||
if (watchedModel && watchedYear && selectedMake && watchedModel !== selectedModel?.name) {
|
||||
const modelOption = models.find(model => model.name === watchedModel);
|
||||
if (modelOption) {
|
||||
const loadTrims = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const [trimsData, transmissionsData] = await Promise.all([
|
||||
vehiclesApi.getTrims(watchedYear, selectedMake.id, modelOption.id),
|
||||
vehiclesApi.getTransmissions(watchedYear, selectedMake.id, modelOption.id)
|
||||
]);
|
||||
setTrims(trimsData);
|
||||
setTransmissions(transmissionsData);
|
||||
setSelectedModel(modelOption);
|
||||
// Clear deeper selections
|
||||
setEngines([]);
|
||||
setSelectedTrim(undefined);
|
||||
setValue('transmission', '');
|
||||
setValue('engine', '');
|
||||
setValue('trimLevel', '');
|
||||
} catch (error) {
|
||||
console.error('Failed to load detailed data:', error);
|
||||
setTrims([]);
|
||||
setEngines([]);
|
||||
setTransmissions([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
if (watchedModel && watchedYear && selectedMake && watchedModel !== selectedModel) {
|
||||
const loadTrimsAndTransmissions = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const [trimsData, transmissionsData] = await Promise.all([
|
||||
vehiclesApi.getTrims(watchedYear, selectedMake, watchedModel),
|
||||
vehiclesApi.getTransmissions(watchedYear, selectedMake, watchedModel)
|
||||
]);
|
||||
setTrims(trimsData);
|
||||
setTransmissions(transmissionsData);
|
||||
setSelectedModel(watchedModel);
|
||||
|
||||
loadTrims();
|
||||
}
|
||||
// Clear deeper selections
|
||||
setSelectedTrim('');
|
||||
setEngines([]);
|
||||
setValue('trimLevel', '');
|
||||
setValue('engine', '');
|
||||
} catch (error) {
|
||||
console.error('Failed to load trims and transmissions:', error);
|
||||
setTrims([]);
|
||||
setTransmissions([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadTrimsAndTransmissions();
|
||||
}
|
||||
}, [watchedModel, watchedYear, selectedMake, selectedModel, models, setValue]);
|
||||
}, [watchedModel, watchedYear, selectedMake, selectedModel, setValue]);
|
||||
|
||||
// Load engines when trim changes
|
||||
useEffect(() => {
|
||||
@@ -368,25 +331,28 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
|
||||
const trimName = watch('trimLevel');
|
||||
if (trimName && watchedYear && selectedMake && selectedModel) {
|
||||
const trimOption = trims.find(t => t.name === trimName);
|
||||
if (trimOption) {
|
||||
const loadEngines = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const enginesData = await vehiclesApi.getEngines(watchedYear, selectedMake.id, selectedModel.id, trimOption.id);
|
||||
setEngines(enginesData);
|
||||
setSelectedTrim(trimOption);
|
||||
} catch (error) {
|
||||
console.error('Failed to load engines:', error);
|
||||
setEngines([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
loadEngines();
|
||||
}
|
||||
const loadEngines = async () => {
|
||||
setLoadingDropdowns(true);
|
||||
try {
|
||||
const enginesData = await vehiclesApi.getEngines(
|
||||
watchedYear,
|
||||
selectedMake,
|
||||
selectedModel,
|
||||
trimName
|
||||
);
|
||||
setEngines(enginesData);
|
||||
setSelectedTrim(trimName);
|
||||
} catch (error) {
|
||||
console.error('Failed to load engines:', error);
|
||||
setEngines([]);
|
||||
} finally {
|
||||
setLoadingDropdowns(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadEngines();
|
||||
}
|
||||
}, [trims, selectedMake, selectedModel, watchedYear, setValue, watch('trimLevel')]);
|
||||
}, [watchedYear, selectedMake, selectedModel, watch('trimLevel')]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
@@ -431,6 +397,11 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('year', { valueAsNumber: true })}
|
||||
value={selectedYear || ''}
|
||||
onChange={(e) => {
|
||||
const year = parseInt(e.target.value);
|
||||
setValue('year', year);
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
@@ -449,14 +420,27 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('make')}
|
||||
value={selectedMake}
|
||||
onChange={(e) => {
|
||||
const make = e.target.value;
|
||||
setValue('make', make);
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedYear}
|
||||
disabled={loadingDropdowns || !watchedYear || makes.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Make</option>
|
||||
<option value="">
|
||||
{loadingDropdowns
|
||||
? 'Loading...'
|
||||
: !watchedYear
|
||||
? 'Select year first'
|
||||
: makes.length === 0
|
||||
? 'No makes available'
|
||||
: 'Select Make'}
|
||||
</option>
|
||||
{makes.map((make) => (
|
||||
<option key={make.id} value={make.name}>
|
||||
{make.name}
|
||||
<option key={make} value={make}>
|
||||
{make}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -468,14 +452,27 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('model')}
|
||||
value={selectedModel}
|
||||
onChange={(e) => {
|
||||
const model = e.target.value;
|
||||
setValue('model', model);
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedMake || models.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Model</option>
|
||||
<option value="">
|
||||
{loadingDropdowns
|
||||
? 'Loading...'
|
||||
: !watchedMake
|
||||
? 'Select make first'
|
||||
: models.length === 0
|
||||
? 'No models available'
|
||||
: 'Select Model'}
|
||||
</option>
|
||||
{models.map((model) => (
|
||||
<option key={model.id} value={model.name}>
|
||||
{model.name}
|
||||
<option key={model} value={model}>
|
||||
{model}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -490,14 +487,27 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('trimLevel')}
|
||||
value={selectedTrim}
|
||||
onChange={(e) => {
|
||||
const trim = e.target.value;
|
||||
setValue('trimLevel', trim);
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Trim</option>
|
||||
<option value="">
|
||||
{loadingDropdowns
|
||||
? 'Loading...'
|
||||
: !watchedModel
|
||||
? 'Select model first'
|
||||
: trims.length === 0
|
||||
? 'No trims available'
|
||||
: 'Select Trim'}
|
||||
</option>
|
||||
{trims.map((trim) => (
|
||||
<option key={trim.id} value={trim.name}>
|
||||
{trim.name}
|
||||
<option key={trim} value={trim}>
|
||||
{trim}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -511,13 +521,21 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
<select
|
||||
{...register('engine')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedModel || !selectedTrim || engines.length === 0}
|
||||
disabled={loadingDropdowns || !selectedTrim || engines.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Engine</option>
|
||||
<option value="">
|
||||
{loadingDropdowns
|
||||
? 'Loading...'
|
||||
: !selectedTrim
|
||||
? 'Select trim first'
|
||||
: engines.length === 0
|
||||
? 'N/A (Electric)'
|
||||
: 'Select Engine'}
|
||||
</option>
|
||||
{engines.map((engine) => (
|
||||
<option key={engine.id} value={engine.name}>
|
||||
{engine.name}
|
||||
<option key={engine} value={engine}>
|
||||
{engine}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -531,13 +549,21 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
<select
|
||||
{...register('transmission')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || transmissions.length === 0}
|
||||
disabled={loadingDropdowns || !watchedModel || transmissions.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Transmission</option>
|
||||
<option value="">
|
||||
{loadingDropdowns
|
||||
? 'Loading...'
|
||||
: !watchedModel
|
||||
? 'Select model first'
|
||||
: transmissions.length === 0
|
||||
? 'No transmissions available'
|
||||
: 'Select Transmission'}
|
||||
</option>
|
||||
{transmissions.map((transmission) => (
|
||||
<option key={transmission.id} value={transmission.name}>
|
||||
{transmission.name}
|
||||
<option key={transmission} value={transmission}>
|
||||
{transmission}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
@@ -53,11 +53,6 @@ export interface UpdateVehicleRequest {
|
||||
odometerReading?: number;
|
||||
}
|
||||
|
||||
export interface DropdownOption {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface VINDecodeResponse {
|
||||
vin: string;
|
||||
success: boolean;
|
||||
|
||||
Reference in New Issue
Block a user