({
drivesTable: {
@@ -22,22 +23,32 @@ const styles = () => ({
});
const DriveList = (props) => {
- const { dispatch, classes, device, routes } = props;
-
+ const { dispatch, classes, device, routes, lastRoutes } = props;
+ let emptyContent;
let content;
if (!routes || routes.length === 0) {
- content = ;
- } else {
+ emptyContent = ;
+ }
+
+ // we clean up routes during data fetching, fallback to using lastRoutes to display current data
+ const displayRoutes = routes || lastRoutes
+ if (displayRoutes && displayRoutes.length){
// sort routes by start_time_utc_millis with the latest drive first
// Workaround upstream sorting issue for now
// possibly from https://github.com/commaai/connect/issues/451
- routes.sort((a, b) => b.start_time_utc_millis - a.start_time_utc_millis);
+ displayRoutes.sort((a, b) => b.start_time_utc_millis - a.start_time_utc_millis);
+ const routesSize = displayRoutes.length
content = (
- {routes.map((drive) => (
-
- ))}
+ {displayRoutes.map((drive, index) => {
+ // when the second to last item is in view, we fetch the next routes
+ return (index === routesSize - 2 ?
+ dispatch(checkRoutesDataWithLookBack())}>
+
+ :
+ )
+ })}
);
}
@@ -46,12 +57,14 @@ const DriveList = (props) => {
dispatch(checkRoutesData())} minInterval={60} />
{content}
+ {emptyContent}
);
};
const stateToProps = Obstruction({
routes: 'routes',
+ lastRoutes : 'lastRoutes',
device: 'device',
});
diff --git a/src/components/ScrollIntoView/index.jsx b/src/components/ScrollIntoView/index.jsx
new file mode 100644
index 00000000..293a494a
--- /dev/null
+++ b/src/components/ScrollIntoView/index.jsx
@@ -0,0 +1,39 @@
+import React, { useEffect, useRef } from 'react';
+
+const ScrollIntoView = ({ onInView, children, key }) => {
+ const elementRef = useRef(null);
+
+ useEffect(() => {
+ const options = {
+ root: null, // relative to the viewport
+ rootMargin: '0px',
+ threshold: 0.1 // 10% of the target's visibility
+ };
+
+ const observer = new IntersectionObserver((entries) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ onInView();
+ }
+ });
+ }, options);
+
+ if (elementRef.current) {
+ observer.observe(elementRef.current);
+ }
+
+ return () => {
+ if (observer && elementRef.current) {
+ observer.unobserve(elementRef.current);
+ }
+ };
+ }, [onInView]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default ScrollIntoView;
diff --git a/src/initialState.js b/src/initialState.js
index caefd0c0..f104b79b 100644
--- a/src/initialState.js
+++ b/src/initialState.js
@@ -5,7 +5,7 @@ export function getDefaultFilter() {
d.setHours(d.getHours() + 1, 0, 0, 0);
return {
- start: (new Date(d.getTime() - 1000 * 60 * 60 * 24 * 14)).getTime(),
+ start: (new Date(d.getTime() - 1000 * 60 * 60 * 24 * 10)).getTime(),
end: d.getTime(),
};
}
@@ -39,6 +39,7 @@ export default {
end: null,
},
currentRoute: null,
+ lastRoutes: null,
profile: null,
devices: null,
diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js
index fc0fdb39..6a0d5ae3 100644
--- a/src/reducers/globalState.js
+++ b/src/reducers/globalState.js
@@ -319,6 +319,7 @@ export default function reducer(_state, action) {
.reduce((obj, id) => { obj[id] = state.filesUploading[id]; return obj; }, {});
break;
case Types.ACTION_ROUTES_METADATA:
+ state.lastRoutes = action.routes
state.routes = action.routes;
state.routesMeta = {
dongleId: action.dongleId,