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
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:
@@ -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.
|
||||
- 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 ***
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user