Record UX improvements

This commit is contained in:
Eric Gullickson
2025-09-25 15:07:31 -05:00
parent 82c66dafed
commit 56443d5b2f
3 changed files with 241 additions and 32 deletions

View File

@@ -2,9 +2,14 @@
* @ai-summary Mobile vehicle detail screen with Material Design 3
*/
import React from 'react';
import { Box, Typography, Button, Card, CardContent, Divider } from '@mui/material';
import React, { useMemo, useState } from 'react';
import { Box, Typography, Button, Card, CardContent, Divider, FormControl, InputLabel, Select, MenuItem, List, ListItem, ListItemText } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
import { Vehicle } from '../types/vehicles.types';
import { useFuelLogs } from '../../fuel-logs/hooks/useFuelLogs';
import { FuelLogResponse, UpdateFuelLogRequest } from '../../fuel-logs/types/fuel-logs.types';
import { FuelLogEditDialog } from '../../fuel-logs/components/FuelLogEditDialog';
import { fuelLogsApi } from '../../fuel-logs/api/fuel-logs.api';
// Theme colors now defined in Tailwind config
@@ -48,6 +53,55 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
[vehicle.year, vehicle.make, vehicle.model, vehicle.trimLevel].filter(Boolean).join(' ') || 'Vehicle';
const displayModel = vehicle.model || 'Unknown Model';
const [recordFilter, setRecordFilter] = useState<'All' | 'Fuel Logs' | 'Maintenance' | 'Documents'>('All');
const { fuelLogs, isLoading: isFuelLoading } = useFuelLogs(vehicle.id);
const queryClient = useQueryClient();
const [editingLog, setEditingLog] = useState<FuelLogResponse | null>(null);
type VehicleRecord = {
id: string;
type: 'Fuel Logs' | 'Maintenance' | 'Documents';
date: string; // ISO
summary: string;
amount?: string;
};
const records: VehicleRecord[] = useMemo(() => {
const list: VehicleRecord[] = [];
if (fuelLogs && Array.isArray(fuelLogs)) {
for (const log of fuelLogs as FuelLogResponse[]) {
const parts: string[] = [];
if (log.fuelUnits) parts.push(`${Number(log.fuelUnits).toFixed(3)} units`);
if (log.fuelType) parts.push(`${log.fuelType}${log.fuelGrade ? ' ' + log.fuelGrade : ''}`);
if (log.efficiencyLabel) parts.push(log.efficiencyLabel);
const summary = parts.join(' • ');
const amount = (typeof log.totalCost === 'number') ? `$${log.totalCost.toFixed(2)}` : undefined;
list.push({ id: log.id, type: 'Fuel Logs', date: log.dateTime, summary, amount });
}
}
return list.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
}, [fuelLogs]);
const filteredRecords = useMemo(() => {
if (recordFilter === 'All') return records;
return records.filter(r => r.type === recordFilter);
}, [records, recordFilter]);
const openEditLog = (recId: string, type: VehicleRecord['type']) => {
if (type === 'Fuel Logs') {
const log = (fuelLogs as FuelLogResponse[] | undefined)?.find(l => l.id === recId) || null;
setEditingLog(log);
}
};
const handleCloseEdit = () => setEditingLog(null);
const handleSaveEdit = async (id: string, data: UpdateFuelLogRequest) => {
await fuelLogsApi.update(id, data);
await queryClient.invalidateQueries({ queryKey: ['fuelLogs', vehicle.id] });
await queryClient.invalidateQueries({ queryKey: ['fuelLogs'] });
setEditingLog(null);
};
return (
<Box sx={{ pb: 10 }}>
<Button variant="text" onClick={onBack}>
@@ -124,15 +178,62 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
</Card>
</Section>
<Section title="Recent Activity">
<Section title="Vehicle Records">
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
<Typography variant="body2" color="text.secondary">
{isFuelLoading ? 'Loading…' : `${filteredRecords.length} record${filteredRecords.length === 1 ? '' : 's'}`}
</Typography>
<FormControl size="small" sx={{ minWidth: 180 }}>
<InputLabel id="vehicle-records-filter">Filter</InputLabel>
<Select
labelId="vehicle-records-filter"
value={recordFilter}
label="Filter"
onChange={(e) => setRecordFilter(e.target.value as any)}
>
<MenuItem value="All">All</MenuItem>
<MenuItem value="Fuel Logs">Fuel Logs</MenuItem>
<MenuItem value="Maintenance">Maintenance</MenuItem>
<MenuItem value="Documents">Documents</MenuItem>
</Select>
</FormControl>
</Box>
<Card>
<CardContent sx={{ textAlign: 'center', py: 8 }}>
<Typography color="text.secondary" variant="body2">
No recent activity
</Typography>
<CardContent sx={{ p: 0 }}>
{isFuelLoading ? (
<Box sx={{ p: 2 }}>
<Typography color="text.secondary" variant="body2">Loading records</Typography>
</Box>
) : filteredRecords.length === 0 ? (
<Box sx={{ p: 2 }}>
<Typography color="text.secondary" variant="body2">No records found for this filter.</Typography>
</Box>
) : (
<List disablePadding>
{filteredRecords.map(rec => (
<ListItem key={rec.id} divider button onClick={() => openEditLog(rec.id, rec.type)}>
<ListItemText
primary={rec.summary || new Date(rec.date).toLocaleString()}
secondary={`${new Date(rec.date).toLocaleString()}${rec.type}`}
/>
<Typography sx={{ ml: 2 }} color="text.primary">
{rec.amount || '—'}
</Typography>
</ListItem>
))}
</List>
)}
</CardContent>
</Card>
</Section>
{/* Edit Dialog for Fuel Logs */}
<FuelLogEditDialog
open={!!editingLog}
log={editingLog}
onClose={handleCloseEdit}
onSave={handleSaveEdit}
/>
</Box>
);
};
};