-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: 'VehiclesList' component to handle static vehicle data
- Added static vehicle list to manage delays in database fetching. - Included timeout to handle database initialization delay for a better user experience. - Updated useEffect dependencies for better component re-rendering. - Enhanced error handling with 'DataStatusDialog' component.
- Loading branch information
Showing
1 changed file
with
75 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,107 @@ | ||
import React, { useEffect, useCallback } from 'react'; | ||
import React, { useState, useEffect, useCallback } from 'react'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
|
||
import Spinner from 'react-bootstrap/Spinner'; | ||
import { FaSpinner } from 'react-icons/fa6'; | ||
|
||
import SplideCarousel from './SplideCarousel'; | ||
import { fetchVehicles } from './vehiclesThunk'; | ||
|
||
import '../../styles/features/vehicles/VehiclesList.scss'; | ||
import DataStatusDialog from '../../components/DataStatusDialog'; | ||
|
||
const VehiclesList = () => { | ||
function VehiclesList() { | ||
const dispatch = useDispatch(); | ||
const { loading, error, vehiclesList } = useSelector( | ||
(state) => state.vehicles, | ||
); | ||
|
||
const [staticVehicleList, setStaticVehicleList] = useState([]); | ||
const [databaseOnDelay, setDatabaseOnDelay] = useState(false); | ||
|
||
// ? useCallback to avoid creating a new function on every render | ||
// ? since useEffect uses the function as a dependency. | ||
const reFetchVehicles = useCallback(() => { | ||
dispatch(fetchVehicles()); | ||
}, [dispatch]); | ||
|
||
useEffect(() => { | ||
reFetchVehicles(); | ||
}, [reFetchVehicles]); | ||
// ! The inclusion of 'staticVehicleList' in the dependency array ensures that | ||
// ! the details page displays correctly when a vehicle is selected. | ||
// * This is because, when the 'staticVehicleList' is updated, it also resets | ||
// * the 'vehicle' state to null, allowing for the selection of a new vehicle. | ||
// ! This behavior is specific to the handling of static vehicle data, | ||
// * ensuring that the component re-renders with the appropriate data | ||
// * (dynamic or static) each time a vehicle is selected. | ||
}, [reFetchVehicles, staticVehicleList]); | ||
|
||
const { loading, error, vehiclesList } = useSelector( | ||
(state) => state.vehicles, | ||
); | ||
// * Where the database is currently hosted, it takes a few seconds to | ||
// * initialize and become active. This useEffect hook will check if the | ||
// * initial fetch for the vehicles list is still loading | ||
// * after X seconds, if so it will fetch the static vehicle list from | ||
// * the JSON file which then will be rendered at the 'if (databaseOnDelay) {}' block. | ||
// * for a better user experience. | ||
useEffect(() => { | ||
const timeout = setTimeout(() => { | ||
if (loading) { | ||
setDatabaseOnDelay(true); | ||
} | ||
}, 3000); | ||
|
||
if (loading) { | ||
return () => clearTimeout(timeout); | ||
}, [loading]); | ||
|
||
useEffect(() => { | ||
if (databaseOnDelay) { | ||
import('../../json/vehicles.json') | ||
.then((module) => { | ||
setStaticVehicleList(module.data); | ||
}) | ||
.catch((error) => { | ||
// eslint-disable-next-line no-console | ||
console.error('An error occurred while importing the module:', error); | ||
}); | ||
} | ||
}, [databaseOnDelay]); | ||
|
||
if (loading && databaseOnDelay) { | ||
return ( | ||
<div className="loading-error-wrapper"> | ||
<Spinner animation="grow" variant="danger" /> | ||
<p> | ||
The project database is currently hosted on Render.com and is in a | ||
dormant state. Kindly allow a few moments for the database to | ||
initialize and become active. | ||
</p> | ||
<h3>Loading...</h3> | ||
</div> | ||
<> | ||
<div className="vehicles__list--wrapper"> | ||
<SplideCarousel vehiclesList={staticVehicleList} /> | ||
</div> | ||
|
||
<DataStatusDialog reFetchFunction={reFetchVehicles} /> | ||
</> | ||
); | ||
} | ||
|
||
if (error) { | ||
const isCentered = true; | ||
return ( | ||
<div className="loading-error-wrapper"> | ||
<h3>Sorry, something went wrong...</h3> | ||
<button type="button" className="btn" onClick={reFetchVehicles}> | ||
Refresh | ||
</button> | ||
<DataStatusDialog | ||
isCentered={isCentered} | ||
paragraph="An error occurred while getting the updated list of vehicles. | ||
We are sincerely sorry for the inconvenience." | ||
strongText="Please try again later." | ||
status="Error" | ||
reFetchFunction={reFetchVehicles} | ||
/> | ||
); | ||
} | ||
|
||
if (!loading && vehiclesList.length > 0) { | ||
return ( | ||
<div className="vehicles__list--wrapper"> | ||
<SplideCarousel vehiclesList={vehiclesList} /> | ||
</div> | ||
); | ||
} | ||
|
||
return vehiclesList.length > 0 ? ( | ||
return ( | ||
<div className="vehicles__list--wrapper"> | ||
<SplideCarousel vehiclesList={vehiclesList} /> | ||
</div> | ||
) : ( | ||
<div className="loading-error-wrapper"> | ||
<h3>No vehicles found</h3> | ||
<button type="button" className="btn" onClick={reFetchVehicles}> | ||
Refresh | ||
</button> | ||
<div className="loader-indicator visible"> | ||
<FaSpinner /> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
} | ||
|
||
export default VehiclesList; |