Gas Station Feature Finally Working

This commit is contained in:
Eric Gullickson
2025-11-04 21:05:12 -06:00
parent 9a01ebd847
commit 45fea0f307
8 changed files with 433 additions and 56 deletions

View File

@@ -2,7 +2,7 @@
* @ai-summary Desktop stations page with map and list layout
*/
import React, { useState, useMemo } from 'react';
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import {
Grid,
Paper,
@@ -11,7 +11,9 @@ import {
Box,
Alert,
useMediaQuery,
useTheme
useTheme,
CircularProgress,
Typography
} from '@mui/material';
import { Station, StationSearchRequest } from '../types/stations.types';
import {
@@ -24,7 +26,8 @@ import {
StationMap,
StationsList,
SavedStationsList,
StationsSearchForm
StationsSearchForm,
GoogleMapsErrorBoundary
} from '../components';
interface TabPanelProps {
@@ -34,14 +37,19 @@ interface TabPanelProps {
}
const TabPanel: React.FC<TabPanelProps> = ({ children, value, index }) => {
// Only render content when tab is active to prevent IntersectionObserver errors
// on hidden MUI components
if (value !== index) {
return null;
}
return (
<div
role="tabpanel"
hidden={value !== index}
id={`stations-tabpanel-${index}`}
aria-labelledby={`stations-tab-${index}`}
>
{value === index && <Box sx={{ padding: 2 }}>{children}</Box>}
<Box sx={{ padding: 2 }}>{children}</Box>
</div>
);
};
@@ -63,11 +71,51 @@ export const StationsPage: React.FC = () => {
const [currentLocation, setCurrentLocation] = useState<
{ latitude: number; longitude: number } | undefined
>();
const [isPageReady, setIsPageReady] = useState(false);
const [isMapReady, setIsMapReady] = useState(false);
// Queries and mutations
const { mutate: search, isPending: isSearching, error: searchError } = useStationsSearch();
const { data: savedStations = [], isLoading: isSavedLoading, error: savedError } = useSavedStations();
console.log('[DEBUG StationsPage] useSavedStations result:', { data: savedStations, isLoading: isSavedLoading, error: savedError });
const { data: savedStations = [], isLoading: isSavedLoading, error: savedError, isFetching, isSuccess } = useSavedStations();
console.log('[DEBUG StationsPage] useSavedStations result:', {
data: savedStations,
isLoading: isSavedLoading,
isFetching,
isSuccess,
error: savedError
});
// Multi-stage initialization: Wait for auth, data, and DOM
useEffect(() => {
// Stage 1: Wait for saved stations query to settle (loading complete or error)
const isDataReady = !isSavedLoading && !isFetching;
if (isDataReady && !isPageReady) {
console.log('[DEBUG StationsPage] Data ready, waiting for DOM...');
// Stage 2: Wait for DOM to be ready
const timer = setTimeout(() => {
setIsPageReady(true);
console.log('[DEBUG StationsPage] Page ready');
}, 150);
return () => clearTimeout(timer);
}
return undefined;
}, [isSavedLoading, isFetching, isPageReady]);
// Stage 3: Wait for page render to complete before allowing map initialization
useEffect(() => {
if (isPageReady && !isMapReady) {
console.log('[DEBUG StationsPage] Page rendered, enabling map...');
const timer = setTimeout(() => {
setIsMapReady(true);
console.log('[DEBUG StationsPage] Map ready');
}, 100);
return () => clearTimeout(timer);
}
return undefined;
}, [isPageReady, isMapReady]);
const { mutate: saveStation } = useSaveStation();
const { mutate: deleteStation } = useDeleteStation();
@@ -115,6 +163,36 @@ export const StationsPage: React.FC = () => {
deleteStation(placeId);
};
// Handle station selection - wrapped in useCallback to prevent infinite renders
const handleSelectStation = useCallback((station: Station) => {
setMapCenter({
lat: station.latitude,
lng: station.longitude
});
}, []);
// Show comprehensive loading state until everything is ready
if (!isPageReady || !isMapReady) {
return (
<Box
sx={{
padding: 4,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
minHeight: '400px',
gap: 2
}}
>
<CircularProgress size={48} />
<Typography variant="body1" color="textSecondary">
Loading stations...
</Typography>
</Box>
);
}
// If mobile, stack components vertically
if (isMobile) {
return (
@@ -127,13 +205,23 @@ export const StationsPage: React.FC = () => {
<Alert severity="error">{(searchError as any).message || 'Search failed'}</Alert>
)}
<StationMap
stations={searchResults}
savedPlaceIds={savedPlaceIds}
currentLocation={currentLocation}
center={mapCenter || undefined}
height="300px"
/>
{isMapReady ? (
<GoogleMapsErrorBoundary>
<StationMap
key="mobile-station-map"
stations={searchResults}
savedPlaceIds={savedPlaceIds}
currentLocation={currentLocation}
center={mapCenter || undefined}
height="300px"
readyToRender={true}
/>
</GoogleMapsErrorBoundary>
) : (
<Box sx={{ height: '300px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<CircularProgress />
</Box>
)}
<Tabs
value={tabValue}
@@ -160,12 +248,9 @@ export const StationsPage: React.FC = () => {
<TabPanel value={tabValue} index={1}>
<SavedStationsList
stations={savedStations}
onSelectStation={(station) => {
setMapCenter({
lat: station.latitude,
lng: station.longitude
});
}}
loading={isSavedLoading}
error={savedError ? (savedError as any).message : null}
onSelectStation={handleSelectStation}
onDeleteStation={handleDelete}
/>
</TabPanel>
@@ -179,13 +264,23 @@ export const StationsPage: React.FC = () => {
{/* Left: Map (60%) */}
<Grid item xs={12} md={6} sx={{ display: 'flex', flexDirection: 'column' }}>
<Paper sx={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
<StationMap
stations={searchResults}
savedPlaceIds={savedPlaceIds}
currentLocation={currentLocation}
center={mapCenter || undefined}
height="100%"
/>
{isMapReady ? (
<GoogleMapsErrorBoundary>
<StationMap
key="desktop-station-map"
stations={searchResults}
savedPlaceIds={savedPlaceIds}
currentLocation={currentLocation}
center={mapCenter || undefined}
height="100%"
readyToRender={true}
/>
</GoogleMapsErrorBoundary>
) : (
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<CircularProgress />
</Box>
)}
</Paper>
</Grid>
@@ -224,24 +319,16 @@ export const StationsPage: React.FC = () => {
error={searchError ? (searchError as any).message : null}
onSaveStation={handleSave}
onDeleteStation={handleDelete}
onSelectStation={(station) => {
setMapCenter({
lat: station.latitude,
lng: station.longitude
});
}}
onSelectStation={handleSelectStation}
/>
</TabPanel>
<TabPanel value={tabValue} index={1}>
<SavedStationsList
stations={savedStations}
onSelectStation={(station) => {
setMapCenter({
lat: station.latitude,
lng: station.longitude
});
}}
loading={isSavedLoading}
error={savedError ? (savedError as any).message : null}
onSelectStation={handleSelectStation}
onDeleteStation={handleDelete}
/>
</TabPanel>