Almost ready

This commit is contained in:
Eric Gullickson
2025-11-08 15:34:29 -06:00
parent bb4a356b9e
commit 408a0736c0
7 changed files with 66 additions and 60 deletions

View File

@@ -25,12 +25,12 @@ Maintain professional documentation standards without emoji usage.
File: `frontend/package.json` File: `frontend/package.json`
- Add `"{package}": "{version}"` to dependencies - Add `"{package}": "{version}"` to dependencies
- No npm install needed - handled by container rebuild - No npm install needed - handled by container rebuild
- Testing: `make rebuild` then verify container starts - Testing: Instruct user to rebuild the containers and report back build errors
### 2. Container-Validated Development Workflow (Production-only) ### 2. Container-Validated Development Workflow (Production-only)
```bash ```bash
# After each change: # After each change:
make rebuild # Rebuilds containers with new dependencies Instruct user to rebuild the containers and report back build errors
make logs # Monitor for build/runtime errors make logs # Monitor for build/runtime errors
``` ```

View File

@@ -130,8 +130,22 @@ export class StationsService {
const enriched = await Promise.all( const enriched = await Promise.all(
savedStations.map(async (saved: SavedStation) => { savedStations.map(async (saved: SavedStation) => {
const station = await this.repository.getCachedStation(saved.stationId); const station = await this.repository.getCachedStation(saved.stationId);
// Flatten station data into top level to match frontend SavedStation type
// Frontend expects SavedStation to extend Station
return { return {
...saved, ...saved,
// Merge cached station data at top level (with fallbacks if cache miss)
name: station?.name || saved.nickname || 'Saved Station',
address: station?.address || '',
latitude: station?.latitude || 0,
longitude: station?.longitude || 0,
rating: station?.rating,
photoUrl: station?.photoUrl,
priceRegular: station?.priceRegular,
pricePremium: station?.pricePremium,
priceDiesel: station?.priceDiesel,
// Keep nested station for compatibility
station station
}; };
}) })

View File

@@ -11,7 +11,7 @@ Project documentation hub for the 5-container single-tenant architecture with in
- Testing (containers only): `docs/TESTING.md` - Testing (containers only): `docs/TESTING.md`
- Database Migration: `docs/DATABASE-MIGRATION.md` - Database Migration: `docs/DATABASE-MIGRATION.md`
- Admin feature: `docs/ADMIN.md` - Role management, APIs, catalog CRUD, station oversight - Admin feature: `docs/ADMIN.md` - Role management, APIs, catalog CRUD, station oversight
- Development commands: `Makefile`, `docker-compose.yml` - Development Environment: `docker-compose.yml`
- Application features (start at each README): - Application features (start at each README):
- `backend/src/features/admin/README.md` - Admin role management and oversight - `backend/src/features/admin/README.md` - Admin role management and oversight
- `backend/src/features/platform/README.md` - Vehicle data and VIN decoding - `backend/src/features/platform/README.md` - Vehicle data and VIN decoding

View File

@@ -84,14 +84,14 @@ export const FuelLogsPage: React.FC = () => {
<FuelLogForm /> <FuelLogForm />
</Grid> </Grid>
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Typography variant="h6" gutterBottom>Recent Fuel Logs</Typography> <Typography variant="h6" gutterBottom>Summary</Typography>
<FuelStatsCard logs={fuelLogs} />
<Typography variant="h6" sx={{ mt: 3 }} gutterBottom>Recent Fuel Logs</Typography>
<FuelLogsList <FuelLogsList
logs={fuelLogs} logs={fuelLogs}
onEdit={handleEdit} onEdit={handleEdit}
onDelete={handleDelete} onDelete={handleDelete}
/> />
<Typography variant="h6" sx={{ mt: 3 }} gutterBottom>Summary</Typography>
<FuelStatsCard logs={fuelLogs} />
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -1,10 +1,10 @@
/** /**
* @ai-summary Reusable checkbox group for maintenance subtype selection * @ai-summary Multi-select dropdown for maintenance subtype selection
* @ai-context Responsive grid layout with proper mobile touch targets * @ai-context Material-UI Autocomplete with proper mobile touch targets
*/ */
import React from 'react'; import React from 'react';
import { FormGroup, FormControlLabel, Checkbox, Box } from '@mui/material'; import { Autocomplete, TextField, Chip } from '@mui/material';
import { MaintenanceCategory, getSubtypesForCategory } from '../types/maintenance.types'; import { MaintenanceCategory, getSubtypesForCategory } from '../types/maintenance.types';
interface SubtypeCheckboxGroupProps { interface SubtypeCheckboxGroupProps {
@@ -20,52 +20,44 @@ export const SubtypeCheckboxGroup: React.FC<SubtypeCheckboxGroupProps> = ({
}) => { }) => {
const availableSubtypes = getSubtypesForCategory(category); const availableSubtypes = getSubtypesForCategory(category);
const handleToggle = (subtype: string) => {
const newSelected = selected.includes(subtype)
? selected.filter((s) => s !== subtype)
: [...selected, subtype];
onChange(newSelected);
};
return ( return (
<Box <Autocomplete
multiple
options={Array.from(availableSubtypes)}
value={selected}
onChange={(_, newValue) => onChange(newValue)}
disableCloseOnSelect
renderInput={(params) => (
<TextField
{...params}
label="Select Subtypes"
placeholder={selected.length === 0 ? 'Choose one or more...' : ''}
sx={{ sx={{
display: 'grid', '& .MuiOutlinedInput-root': {
gridTemplateColumns: { minHeight: 56,
xs: '1fr',
sm: 'repeat(2, 1fr)',
md: 'repeat(3, 1fr)',
},
gap: 1,
}}
>
<FormGroup>
{availableSubtypes.map((subtype) => (
<FormControlLabel
key={subtype}
control={
<Checkbox
checked={selected.includes(subtype)}
onChange={() => handleToggle(subtype)}
sx={{
minWidth: 44,
minHeight: 44,
'& .MuiSvgIcon-root': {
fontSize: 24,
}, },
}} }}
/> />
} )}
label={subtype} renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
label={option}
{...getTagProps({ index })}
key={option}
sx={{ sx={{
height: 32,
fontSize: { xs: 13, sm: 14 },
}}
/>
))
}
sx={{
'& .MuiAutocomplete-option': {
minHeight: 44, minHeight: 44,
'& .MuiFormControlLabel-label': {
fontSize: { xs: 14, sm: 16 }, fontSize: { xs: 14, sm: 16 },
}, },
}} }}
/> />
))}
</FormGroup>
</Box>
); );
}; };

View File

@@ -86,14 +86,14 @@ export const MaintenancePage: React.FC = () => {
return ( return (
<FormSuspense> <FormSuspense>
<Grid container spacing={2}> <Grid container spacing={3}>
{/* Left Column: Form */} {/* Top: Form */}
<Grid item xs={12} md={6}> <Grid item xs={12}>
<MaintenanceRecordForm /> <MaintenanceRecordForm />
</Grid> </Grid>
{/* Right Column: Records List */} {/* Bottom: Records List */}
<Grid item xs={12} md={6}> <Grid item xs={12}>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
Recent Maintenance Records Recent Maintenance Records
</Typography> </Typography>

View File

@@ -46,6 +46,7 @@ export const StationMap: React.FC<StationMapProps> = ({
const infoWindows = useRef<google.maps.InfoWindow[]>([]); const infoWindows = useRef<google.maps.InfoWindow[]>([]);
const currentLocationMarker = useRef<google.maps.marker.AdvancedMarkerElement | null>(null); const currentLocationMarker = useRef<google.maps.marker.AdvancedMarkerElement | null>(null);
const isInitializing = useRef<boolean>(false); const isInitializing = useRef<boolean>(false);
const mapIdRef = useRef<string | null>(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -368,4 +369,3 @@ export const StationMap: React.FC<StationMapProps> = ({
}; };
export default StationMap; export default StationMap;
const mapIdRef = useRef<string | null>(null);