Compare commits
3 Commits
f6e3963b99
...
9f5c81a14e
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f5c81a14e | |||
|
|
55b8b67a6e | ||
|
|
a49f419eab |
@@ -12,6 +12,9 @@ import { FuelLogResponse, UpdateFuelLogRequest } from '../../fuel-logs/types/fue
|
||||
import { FuelLogEditDialog } from '../../fuel-logs/components/FuelLogEditDialog';
|
||||
import { fuelLogsApi } from '../../fuel-logs/api/fuel-logs.api';
|
||||
import { MaintenanceRecordForm } from '../../maintenance/components/MaintenanceRecordForm';
|
||||
import { useMaintenanceRecords } from '../../maintenance/hooks/useMaintenanceRecords';
|
||||
import { getCategoryDisplayName } from '../../maintenance/types/maintenance.types';
|
||||
import type { MaintenanceRecordResponse } from '../../maintenance/types/maintenance.types';
|
||||
import { VehicleImage } from '../components/VehicleImage';
|
||||
import { OwnershipCostsList } from '../../ownership-costs';
|
||||
import { getVehicleLabel } from '@/core/utils/vehicleDisplay';
|
||||
@@ -46,6 +49,7 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
|
||||
|
||||
const [recordFilter, setRecordFilter] = useState<'All' | 'Fuel Logs' | 'Maintenance' | 'Documents'>('All');
|
||||
const { fuelLogs, isLoading: isFuelLoading } = useFuelLogs(vehicle.id);
|
||||
const { records: maintenanceRecords, isRecordsLoading: isMaintenanceLoading } = useMaintenanceRecords(vehicle.id);
|
||||
const queryClient = useQueryClient();
|
||||
const [editingLog, setEditingLog] = useState<FuelLogResponse | null>(null);
|
||||
const [showMaintenanceDialog, setShowMaintenanceDialog] = useState(false);
|
||||
@@ -124,8 +128,36 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (maintenanceRecords && Array.isArray(maintenanceRecords)) {
|
||||
for (const rec of maintenanceRecords as MaintenanceRecordResponse[]) {
|
||||
const catLabel = getCategoryDisplayName(rec.category);
|
||||
const subtypes = Array.isArray(rec.subtypes) ? rec.subtypes : [];
|
||||
const subtypeText = subtypes.length
|
||||
? `${subtypes.slice(0, 3).join(', ')}${subtypes.length > 3 ? ` +${subtypes.length - 3}` : ''}`
|
||||
: '';
|
||||
const summary = subtypeText ? `${catLabel} — ${subtypeText}` : catLabel;
|
||||
const secondaryParts: string[] = [];
|
||||
if (rec.shopName) secondaryParts.push(rec.shopName);
|
||||
secondaryParts.push(new Date(rec.date).toLocaleDateString());
|
||||
secondaryParts.push('Maintenance');
|
||||
const secondary = secondaryParts.join(' • ');
|
||||
// Backend returns numeric/decimal columns as strings via node-postgres; coerce.
|
||||
const costNum = rec.cost != null ? Number(rec.cost) : NaN;
|
||||
const amount = Number.isFinite(costNum) ? `$${costNum.toFixed(2)}` : undefined;
|
||||
list.push({
|
||||
id: rec.id,
|
||||
type: 'Maintenance',
|
||||
date: rec.date,
|
||||
summary,
|
||||
amount,
|
||||
secondary
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return list.sort((a, b) => b.date.localeCompare(a.date));
|
||||
}, [fuelLogs]);
|
||||
}, [fuelLogs, maintenanceRecords]);
|
||||
|
||||
const filteredRecords = useMemo(() => {
|
||||
if (recordFilter === 'All') return records;
|
||||
@@ -243,7 +275,7 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
|
||||
<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'}`}
|
||||
{(isFuelLoading || isMaintenanceLoading) ? 'Loading…' : `${filteredRecords.length} record${filteredRecords.length === 1 ? '' : 's'}`}
|
||||
</Typography>
|
||||
<FormControl size="small" sx={{ minWidth: 180 }}>
|
||||
<InputLabel id="vehicle-records-filter">Filter</InputLabel>
|
||||
@@ -262,7 +294,7 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
|
||||
</Box>
|
||||
<Card>
|
||||
<CardContent sx={{ p: 0 }}>
|
||||
{isFuelLoading ? (
|
||||
{(isFuelLoading || isMaintenanceLoading) ? (
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Typography color="text.secondary" variant="body2">Loading records…</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -23,6 +23,9 @@ import { FuelLogResponse, UpdateFuelLogRequest } from '../../fuel-logs/types/fue
|
||||
import { FuelLogEditDialog } from '../../fuel-logs/components/FuelLogEditDialog';
|
||||
import { FuelLogForm } from '../../fuel-logs/components/FuelLogForm';
|
||||
import { MaintenanceRecordForm } from '../../maintenance/components/MaintenanceRecordForm';
|
||||
import { useMaintenanceRecords } from '../../maintenance/hooks/useMaintenanceRecords';
|
||||
import { getCategoryDisplayName } from '../../maintenance/types/maintenance.types';
|
||||
import type { MaintenanceRecordResponse } from '../../maintenance/types/maintenance.types';
|
||||
// Unit conversions now handled by backend
|
||||
import { fuelLogsApi } from '../../fuel-logs/api/fuel-logs.api';
|
||||
import { OwnershipCostsList } from '../../ownership-costs';
|
||||
@@ -60,6 +63,7 @@ export const VehicleDetailPage: React.FC = () => {
|
||||
|
||||
const { fuelLogs, isLoading: isFuelLoading } = useFuelLogs(id);
|
||||
const { data: documents, isLoading: isDocumentsLoading } = useDocumentsByVehicle(id);
|
||||
const { records: maintenanceRecords, isRecordsLoading: isMaintenanceLoading } = useMaintenanceRecords(id);
|
||||
const { mutateAsync: deleteDocument } = useDeleteDocument();
|
||||
const { mutateAsync: removeVehicleFromDocument } = useRemoveVehicleFromDocument();
|
||||
const queryClient = useQueryClient();
|
||||
@@ -133,8 +137,26 @@ export const VehicleDetailPage: React.FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (maintenanceRecords && Array.isArray(maintenanceRecords)) {
|
||||
for (const rec of maintenanceRecords as MaintenanceRecordResponse[]) {
|
||||
const catLabel = getCategoryDisplayName(rec.category);
|
||||
const subtypes = Array.isArray(rec.subtypes) ? rec.subtypes : [];
|
||||
const subtypeText = subtypes.length
|
||||
? `${subtypes.slice(0, 3).join(', ')}${subtypes.length > 3 ? ` +${subtypes.length - 3}` : ''}`
|
||||
: '';
|
||||
const parts: string[] = [catLabel];
|
||||
if (subtypeText) parts.push(subtypeText);
|
||||
if (rec.shopName) parts.push(rec.shopName);
|
||||
const summary = parts.join(' • ');
|
||||
// Backend returns numeric/decimal columns as strings via node-postgres; coerce.
|
||||
const costNum = rec.cost != null ? Number(rec.cost) : NaN;
|
||||
const amount = Number.isFinite(costNum) ? `$${costNum.toFixed(2)}` : undefined;
|
||||
list.push({ id: rec.id, type: 'Maintenance', date: rec.date, summary, amount });
|
||||
}
|
||||
}
|
||||
|
||||
return list.sort((a, b) => b.date.localeCompare(a.date));
|
||||
}, [fuelLogs, documents]);
|
||||
}, [fuelLogs, documents, maintenanceRecords]);
|
||||
|
||||
const filteredRecords = useMemo(() => {
|
||||
if (recordFilter === 'All') return records;
|
||||
@@ -475,22 +497,22 @@ export const VehicleDetailPage: React.FC = () => {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{(isFuelLoading || isDocumentsLoading) && (
|
||||
{(isFuelLoading || isDocumentsLoading || isMaintenanceLoading) && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={5}>
|
||||
<Typography color="text.secondary">Loading records…</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{!isFuelLoading && !isDocumentsLoading && filteredRecords.length === 0 && (
|
||||
{!isFuelLoading && !isDocumentsLoading && !isMaintenanceLoading && filteredRecords.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={5}>
|
||||
<Typography color="text.secondary">No records found for this filter.</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{!isFuelLoading && !isDocumentsLoading && filteredRecords.map((rec) => (
|
||||
<TableRow key={rec.id} hover sx={{ cursor: rec.type === 'Documents' ? 'default' : 'pointer' }} onClick={() => handleRowClick(rec.id, rec.type)}>
|
||||
{!isFuelLoading && !isDocumentsLoading && !isMaintenanceLoading && filteredRecords.map((rec) => (
|
||||
<TableRow key={rec.id} hover sx={{ cursor: rec.type === 'Fuel Logs' ? 'pointer' : 'default' }} onClick={() => handleRowClick(rec.id, rec.type)}>
|
||||
<TableCell>{dayjs(rec.date).format('M/D/YYYY')}</TableCell>
|
||||
<TableCell>{rec.type}</TableCell>
|
||||
<TableCell>{rec.summary}</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user