fix: Dynamic drop down bugs in firefox
All checks were successful
Deploy to Staging / Build Images (push) Successful in 3m39s
Deploy to Staging / Deploy to Staging (push) Successful in 36s
Deploy to Staging / Verify Staging (push) Successful in 5s
Deploy to Staging / Notify Staging Ready (push) Successful in 5s
Deploy to Staging / Notify Staging Failure (push) Has been skipped

This commit is contained in:
Eric Gullickson
2025-12-31 12:43:22 -06:00
parent c57a05daa5
commit 7e606df012
2 changed files with 51 additions and 51 deletions

View File

@@ -22,11 +22,13 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en
- Make no assumptions.
- Ask clarifying questions.
- Ultrathink
- You will be syncing the desktop and mobile versions of the homepage
- Troubleshoot UX problems when using Firefox
*** CONTEXT ***
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- The vehicles dynamic drop downs are broken on Firefox. The dropdowns don't populate immediately and require selecting and unselecting options to work.
- There is a console error "Error: Can't find the actor ID for objects-manager from root or target actor's form. types.js:559:11"
*** CHANGES TO IMPLEMENT ***

View File

@@ -78,13 +78,14 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
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<string>('');
const [selectedModel, setSelectedModel] = useState<string>('');
const [selectedTrim, setSelectedTrim] = useState<string>('');
const [loadingDropdowns, setLoadingDropdowns] = useState(false);
const hasInitialized = useRef(false);
const isInitializing = useRef(false);
// Track previous values for cascade change detection (replaces useState)
const prevYear = useRef<number | undefined>(undefined);
const prevMake = useRef<string>('');
const prevModel = useRef<string>('');
const prevTrim = useRef<string>('');
const [currentImageUrl, setCurrentImageUrl] = useState<string | undefined>(initialData?.imageUrl);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
@@ -106,6 +107,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
const watchedYear = watch('year');
const watchedMake = watch('make');
const watchedModel = watch('model');
const watchedTrim = watch('trimLevel');
// Load years on component mount
useEffect(() => {
@@ -133,7 +135,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
setLoadingDropdowns(true);
// Step 1: Set year and load makes
setSelectedYear(initialData.year);
prevYear.current = initialData.year;
const makesData = await vehiclesApi.getMakes(initialData.year);
setMakes(makesData);
@@ -143,7 +145,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
}
// Step 2: Set make and load models
setSelectedMake(initialData.make);
prevMake.current = initialData.make;
const modelsData = await vehiclesApi.getModels(initialData.year, initialData.make);
setModels(modelsData);
@@ -153,13 +155,13 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
}
// Step 3: Set model and load trims (transmissions loaded after trim selected)
setSelectedModel(initialData.model);
prevModel.current = initialData.model;
const trimsData = await vehiclesApi.getTrims(initialData.year, initialData.make, initialData.model);
setTrims(trimsData);
if (initialData.trimLevel) {
// Step 4: Set trim and load engines + transmissions
setSelectedTrim(initialData.trimLevel);
prevTrim.current = initialData.trimLevel;
const [enginesData, transmissionsData] = await Promise.all([
vehiclesApi.getEngines(
initialData.year,
@@ -202,18 +204,18 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
// Skip during initialization
if (isInitializing.current) return;
if (watchedYear && watchedYear !== selectedYear) {
if (watchedYear && watchedYear !== prevYear.current) {
const loadMakes = async () => {
setLoadingDropdowns(true);
try {
const makesData = await vehiclesApi.getMakes(watchedYear);
setMakes(makesData);
setSelectedYear(watchedYear);
prevYear.current = watchedYear;
// Clear dependent selections
setSelectedMake('');
setSelectedModel('');
setSelectedTrim('');
prevMake.current = '';
prevModel.current = '';
prevTrim.current = '';
setModels([]);
setTrims([]);
setEngines([]);
@@ -233,24 +235,24 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
loadMakes();
}
}, [watchedYear, selectedYear, setValue]);
}, [watchedYear, setValue]);
// Load models when make changes
useEffect(() => {
// Skip during initialization
if (isInitializing.current) return;
if (watchedMake && watchedYear && watchedMake !== selectedMake) {
if (watchedMake && watchedYear && watchedMake !== prevMake.current) {
const loadModels = async () => {
setLoadingDropdowns(true);
try {
const modelsData = await vehiclesApi.getModels(watchedYear, watchedMake);
setModels(modelsData);
setSelectedMake(watchedMake);
prevMake.current = watchedMake;
// Clear dependent selections
setSelectedModel('');
setSelectedTrim('');
prevModel.current = '';
prevTrim.current = '';
setTrims([]);
setEngines([]);
setTransmissions([]);
@@ -268,23 +270,23 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
loadModels();
}
}, [watchedMake, watchedYear, selectedMake, setValue]);
}, [watchedMake, watchedYear, setValue]);
// Load trims when model changes
useEffect(() => {
// Skip during initialization
if (isInitializing.current) return;
if (watchedModel && watchedYear && selectedMake && watchedModel !== selectedModel) {
if (watchedModel && watchedYear && watchedMake && watchedModel !== prevModel.current) {
const loadTrims = async () => {
setLoadingDropdowns(true);
try {
const trimsData = await vehiclesApi.getTrims(watchedYear, selectedMake, watchedModel);
const trimsData = await vehiclesApi.getTrims(watchedYear, watchedMake, watchedModel);
setTrims(trimsData);
setSelectedModel(watchedModel);
prevModel.current = watchedModel;
// Clear deeper selections (trims, transmissions, engines)
setSelectedTrim('');
// Clear deeper selections (engines, transmissions)
prevTrim.current = '';
setTransmissions([]);
setEngines([]);
setValue('trimLevel', '');
@@ -300,35 +302,34 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
loadTrims();
}
}, [watchedModel, watchedYear, selectedMake, selectedModel, setValue]);
}, [watchedModel, watchedYear, watchedMake, setValue]);
// Load engines and transmissions when trim changes
useEffect(() => {
// Skip during initialization
if (isInitializing.current) return;
const trimName = watch('trimLevel');
if (trimName && watchedYear && selectedMake && selectedModel) {
if (watchedTrim && watchedYear && watchedMake && watchedModel && watchedTrim !== prevTrim.current) {
const loadEnginesAndTransmissions = async () => {
setLoadingDropdowns(true);
try {
const [enginesData, transmissionsData] = await Promise.all([
vehiclesApi.getEngines(
watchedYear,
selectedMake,
selectedModel,
trimName
watchedMake,
watchedModel,
watchedTrim
),
vehiclesApi.getTransmissions(
watchedYear,
selectedMake,
selectedModel,
trimName
watchedMake,
watchedModel,
watchedTrim
)
]);
setEngines(enginesData);
setTransmissions(transmissionsData);
setSelectedTrim(trimName);
prevTrim.current = watchedTrim;
} catch (error) {
console.error('Failed to load engines and transmissions:', error);
setEngines([]);
@@ -340,7 +341,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
loadEnginesAndTransmissions();
}
}, [watchedYear, selectedMake, selectedModel, watch('trimLevel')]);
}, [watchedYear, watchedMake, watchedModel, watchedTrim, setValue]);
const handleImageUpload = async (file: File) => {
if (isEditMode && vehicleId) {
@@ -433,7 +434,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('year', { valueAsNumber: true })}
value={selectedYear || ''}
value={watchedYear || ''}
onChange={(e) => {
const year = parseInt(e.target.value);
setValue('year', year);
@@ -456,10 +457,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('make')}
value={selectedMake}
value={watchedMake || ''}
onChange={(e) => {
const make = e.target.value;
setValue('make', make);
setValue('make', e.target.value);
}}
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
disabled={loadingDropdowns || !watchedYear || makes.length === 0}
@@ -488,10 +488,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('model')}
value={selectedModel}
value={watchedModel || ''}
onChange={(e) => {
const model = e.target.value;
setValue('model', model);
setValue('model', e.target.value);
}}
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
disabled={loadingDropdowns || !watchedMake || models.length === 0}
@@ -523,10 +522,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('trimLevel')}
value={selectedTrim}
value={watchedTrim || ''}
onChange={(e) => {
const trim = e.target.value;
setValue('trimLevel', trim);
setValue('trimLevel', e.target.value);
}}
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
@@ -557,13 +555,13 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
<select
{...register('engine')}
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
disabled={loadingDropdowns || !selectedTrim || engines.length === 0}
disabled={loadingDropdowns || !watchedTrim || engines.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">
{loadingDropdowns
? 'Loading...'
: !selectedTrim
: !watchedTrim
? 'Select trim first'
: engines.length === 0
? 'N/A (Electric)'
@@ -585,13 +583,13 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
<select
{...register('transmission')}
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
disabled={loadingDropdowns || !selectedTrim || transmissions.length === 0}
disabled={loadingDropdowns || !watchedTrim || transmissions.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">
{loadingDropdowns
? 'Loading...'
: !selectedTrim
: !watchedTrim
? 'Select trim first'
: transmissions.length === 0
? 'No transmissions available'