/** * @ai-summary Mobile vehicle detail screen with Material Design 3 */ import React, { useMemo, useState } from 'react'; import { Box, Typography, Button, Card, CardContent, Divider, FormControl, InputLabel, Select, MenuItem, List, ListItem, ListItemButton, Dialog, DialogTitle, DialogContent } 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'; import { MaintenanceRecordForm } from '../../maintenance/components/MaintenanceRecordForm'; import { VehicleImage } from '../components/VehicleImage'; import { OwnershipCostsList } from '../../ownership-costs'; import { getVehicleLabel } from '@/core/utils/vehicleDisplay'; interface VehicleDetailMobileProps { vehicle: Vehicle; onBack: () => void; onLogFuel?: () => void; onEdit?: () => void; } const Section: React.FC<{ title: string; children: React.ReactNode }> = ({ title, children }) => ( {title} {children} ); export const VehicleDetailMobile: React.FC = ({ vehicle, onBack, onLogFuel, onEdit }) => { const displayName = getVehicleLabel(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(null); const [showMaintenanceDialog, setShowMaintenanceDialog] = useState(false); // Unit conversions are now handled by the backend type VehicleRecord = { id: string; type: 'Fuel Logs' | 'Maintenance' | 'Documents'; date: string; // ISO summary: string; amount?: string; secondary?: string; }; const records: VehicleRecord[] = useMemo(() => { const list: VehicleRecord[] = []; if (fuelLogs && Array.isArray(fuelLogs)) { // Build a map of prior odometer readings to compute trip distance when missing const logsAsc = [...(fuelLogs as FuelLogResponse[])].sort( (a, b) => new Date(a.dateTime).getTime() - new Date(b.dateTime).getTime() ); const prevOdoById = new Map(); let lastOdo: number | undefined = undefined; for (const l of logsAsc) { prevOdoById.set(l.id, lastOdo); if (typeof l.odometerReading === 'number' && !isNaN(l.odometerReading)) { lastOdo = l.odometerReading; } } for (const log of fuelLogs as FuelLogResponse[]) { // Use efficiency from API response (backend calculates this properly) let efficiency = ''; if (typeof log.efficiency === 'number' && log.efficiency > 0) { // DEBUG: Log what the backend is actually returning console.log('🔍 Fuel Log API Response:', { efficiency: log.efficiency, efficiencyLabel: log.efficiencyLabel, logId: log.id }); // Backend returns efficiency in correct units based on user preference efficiency = `${log.efficiencyLabel || 'MPG'}: ${log.efficiency.toFixed(3)}`; } // Secondary line components const secondaryParts: string[] = []; // Grade label (prefer grade only) if (log.fuelGrade) { secondaryParts.push(`Grade: ${log.fuelGrade}`); } else if (log.fuelType) { const ft = String(log.fuelType); secondaryParts.push(ft.charAt(0).toUpperCase() + ft.slice(1)); } // Date secondaryParts.push(new Date(log.dateTime).toLocaleDateString()); // Type secondaryParts.push('Fuel Log'); const summary = efficiency; // Primary line shows MPG/km/L from backend const secondary = secondaryParts.join(' • '); // Secondary line shows Grade • Date • Type const amount = (typeof log.totalCost === 'number') ? `$${log.totalCost.toFixed(2)}` : undefined; // DEBUG: Log the final display values console.log('🎯 Display Summary:', { summary, efficiency, logId: log.id }); list.push({ id: log.id, type: 'Fuel Logs', date: log.dateTime, summary, amount, secondary }); } } 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 ( {displayName} {displayName} {displayModel} {vehicle.licensePlate && ( {vehicle.licensePlate} )}
{vehicle.vin && ( VIN {vehicle.vin} )} {vehicle.year && ( Year {vehicle.year} )} {vehicle.make && ( Make {vehicle.make} )} {vehicle.model && ( Model {vehicle.model} )} Odometer {vehicle.odometerReading.toLocaleString()} mi
{isFuelLoading ? 'Loading…' : `${filteredRecords.length} record${filteredRecords.length === 1 ? '' : 's'}`} Filter {isFuelLoading ? ( Loading records… ) : filteredRecords.length === 0 ? ( No records found for this filter. ) : ( {filteredRecords.map(rec => ( openEditLog(rec.id, rec.type)}> {/* Primary line: MPG/km-L and amount */} {rec.summary || 'MPG: —'} {rec.amount || '—'} {/* Secondary line: Grade • Date • Type */} {rec.secondary || `${new Date(rec.date).toLocaleDateString()} • ${rec.type}`} ))} )}
{/* Edit Dialog for Fuel Logs */} {/* Add Maintenance Dialog */} setShowMaintenanceDialog(false)} maxWidth="md" fullWidth fullScreen PaperProps={{ sx: { maxHeight: '90vh' } }} > Add Maintenance { setShowMaintenanceDialog(false); queryClient.invalidateQueries({ queryKey: ['maintenanceRecords', vehicle.id] }); queryClient.invalidateQueries({ queryKey: ['maintenanceRecords'] }); }} />
); };