Possible working ETL

This commit is contained in:
Eric Gullickson
2025-12-15 18:19:55 -06:00
parent 1fc69b7779
commit 1e599e334f
110 changed files with 4843 additions and 2078706 deletions

View File

@@ -78,8 +78,6 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
const [selectedModel, setSelectedModel] = useState<string>('');
const [selectedTrim, setSelectedTrim] = useState<string>('');
const [loadingDropdowns, setLoadingDropdowns] = useState(false);
const [decodingVIN, setDecodingVIN] = useState(false);
const [decodeSuccess, setDecodeSuccess] = useState(false);
const hasInitialized = useRef(false);
const isInitializing = useRef(false);
@@ -98,38 +96,6 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
const watchedYear = watch('year');
const watchedMake = watch('make');
const watchedModel = watch('model');
const watchedVIN = watch('vin');
// VIN decode handler
const handleDecodeVIN = async () => {
const vin = watchedVIN;
if (!vin || vin.length !== 17) {
return;
}
setDecodingVIN(true);
setDecodeSuccess(false);
try {
const result = await vehiclesApi.decodeVIN(vin);
if (result.success) {
// Auto-populate fields with decoded values
if (result.year) setValue('year', result.year);
if (result.make) setValue('make', result.make);
if (result.model) setValue('model', result.model);
if (result.transmission) setValue('transmission', result.transmission);
if (result.engine) setValue('engine', result.engine);
if (result.trimLevel) setValue('trimLevel', result.trimLevel);
setDecodeSuccess(true);
setTimeout(() => setDecodeSuccess(false), 3000); // Hide success after 3 seconds
}
} catch (error) {
console.error('VIN decode failed:', error);
} finally {
setDecodingVIN(false);
}
};
// Load years on component mount
useEffect(() => {
@@ -176,25 +142,30 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
return;
}
// Step 3: Set model and load trims + transmissions
// Step 3: Set model and load trims (transmissions loaded after trim selected)
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)
]);
const trimsData = await vehiclesApi.getTrims(initialData.year, initialData.make, initialData.model);
setTrims(trimsData);
setTransmissions(transmissionsData);
if (initialData.trimLevel) {
// Step 4: Set trim and load engines
// Step 4: Set trim and load engines + transmissions
setSelectedTrim(initialData.trimLevel);
const enginesData = await vehiclesApi.getEngines(
initialData.year,
initialData.make,
initialData.model,
initialData.trimLevel
);
const [enginesData, transmissionsData] = await Promise.all([
vehiclesApi.getEngines(
initialData.year,
initialData.make,
initialData.model,
initialData.trimLevel
),
vehiclesApi.getTransmissions(
initialData.year,
initialData.make,
initialData.model,
initialData.trimLevel
)
]);
setEngines(enginesData);
setTransmissions(transmissionsData);
}
isInitializing.current = false;
@@ -289,68 +260,75 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
}
}, [watchedMake, watchedYear, selectedMake, setValue]);
// Load trims and transmissions when model changes
// Load trims when model changes
useEffect(() => {
// Skip during initialization
if (isInitializing.current) return;
if (watchedModel && watchedYear && selectedMake && watchedModel !== selectedModel) {
const loadTrimsAndTransmissions = async () => {
const loadTrims = async () => {
setLoadingDropdowns(true);
try {
const [trimsData, transmissionsData] = await Promise.all([
vehiclesApi.getTrims(watchedYear, selectedMake, watchedModel),
vehiclesApi.getTransmissions(watchedYear, selectedMake, watchedModel)
]);
const trimsData = await vehiclesApi.getTrims(watchedYear, selectedMake, watchedModel);
setTrims(trimsData);
setTransmissions(transmissionsData);
setSelectedModel(watchedModel);
// Clear deeper selections
// Clear deeper selections (trims, transmissions, engines)
setSelectedTrim('');
setTransmissions([]);
setEngines([]);
setValue('trimLevel', '');
setValue('transmission', '');
setValue('engine', '');
} catch (error) {
console.error('Failed to load trims and transmissions:', error);
console.error('Failed to load trims:', error);
setTrims([]);
setTransmissions([]);
} finally {
setLoadingDropdowns(false);
}
};
loadTrimsAndTransmissions();
loadTrims();
}
}, [watchedModel, watchedYear, selectedMake, selectedModel, setValue]);
// Load engines when trim changes
// Load engines and transmissions when trim changes
useEffect(() => {
// Skip during initialization
if (isInitializing.current) return;
const trimName = watch('trimLevel');
if (trimName && watchedYear && selectedMake && selectedModel) {
const loadEngines = async () => {
const loadEnginesAndTransmissions = async () => {
setLoadingDropdowns(true);
try {
const enginesData = await vehiclesApi.getEngines(
watchedYear,
selectedMake,
selectedModel,
trimName
);
const [enginesData, transmissionsData] = await Promise.all([
vehiclesApi.getEngines(
watchedYear,
selectedMake,
selectedModel,
trimName
),
vehiclesApi.getTransmissions(
watchedYear,
selectedMake,
selectedModel,
trimName
)
]);
setEngines(enginesData);
setTransmissions(transmissionsData);
setSelectedTrim(trimName);
} catch (error) {
console.error('Failed to load engines:', error);
console.error('Failed to load engines and transmissions:', error);
setEngines([]);
setTransmissions([]);
} finally {
setLoadingDropdowns(false);
}
};
loadEngines();
loadEnginesAndTransmissions();
}
}, [watchedYear, selectedMake, selectedModel, watch('trimLevel')]);
@@ -361,29 +339,14 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
VIN or License Plate <span className="text-red-500">*</span>
</label>
<p className="text-xs text-gray-600 mb-2">
Enter VIN to auto-fill vehicle details OR manually select from dropdowns below
Enter vehicle VIN (optional)
</p>
<div className="flex flex-col sm:flex-row gap-2">
<input
{...register('vin')}
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 text-base"
placeholder="Enter 17-character VIN (optional if License Plate provided)"
style={{ fontSize: '16px' }}
/>
<Button
type="button"
onClick={handleDecodeVIN}
loading={decodingVIN}
disabled={!watchedVIN || watchedVIN.length !== 17}
variant="secondary"
className="w-full sm:w-auto min-h-[44px]"
>
Decode VIN
</Button>
</div>
{decodeSuccess && (
<p className="mt-1 text-sm text-green-600">VIN decoded successfully! Fields populated.</p>
)}
<input
{...register('vin')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 text-base"
placeholder="Enter 17-character VIN (optional if License Plate provided)"
style={{ fontSize: '16px' }}
/>
{errors.vin && (
<p className="mt-1 text-sm text-red-600">{errors.vin.message}</p>
)}
@@ -549,14 +512,14 @@ 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 || !watchedModel || transmissions.length === 0}
disabled={loadingDropdowns || !selectedTrim || transmissions.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">
{loadingDropdowns
? 'Loading...'
: !watchedModel
? 'Select model first'
: !selectedTrim
? 'Select trim first'
: transmissions.length === 0
? 'No transmissions available'
: 'Select Transmission'}