fix: Wire vehicleId into maintenance page to display schedules (refs #148)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m28s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 10s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m28s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 10s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Maintenance page called useMaintenanceRecords() without a vehicleId, causing the schedules query (enabled: !!vehicleId) to never execute. Added vehicle selector to both desktop and mobile pages, auto-selects first vehicle, and passes selectedVehicleId to the hook. Also fixed stale query invalidation keys in delete handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,12 +2,13 @@
|
|||||||
* @ai-summary Mobile maintenance screen with tabs for records and schedules
|
* @ai-summary Mobile maintenance screen with tabs for records and schedules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { Box, Tabs, Tab } from '@mui/material';
|
import { Box, Tabs, Tab, FormControl, InputLabel, Select, MenuItem } from '@mui/material';
|
||||||
import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard';
|
import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard';
|
||||||
import { Button } from '../../../shared-minimal/components/Button';
|
import { Button } from '../../../shared-minimal/components/Button';
|
||||||
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
|
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
|
||||||
|
import { useVehicles } from '../../vehicles/hooks/useVehicles';
|
||||||
import { MaintenanceRecordForm } from '../components/MaintenanceRecordForm';
|
import { MaintenanceRecordForm } from '../components/MaintenanceRecordForm';
|
||||||
import { MaintenanceRecordsList } from '../components/MaintenanceRecordsList';
|
import { MaintenanceRecordsList } from '../components/MaintenanceRecordsList';
|
||||||
import { MaintenanceRecordEditDialog } from '../components/MaintenanceRecordEditDialog';
|
import { MaintenanceRecordEditDialog } from '../components/MaintenanceRecordEditDialog';
|
||||||
@@ -18,7 +19,17 @@ import type { MaintenanceRecordResponse, UpdateMaintenanceRecordRequest, Mainten
|
|||||||
|
|
||||||
export const MaintenanceMobileScreen: React.FC = () => {
|
export const MaintenanceMobileScreen: React.FC = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { records, schedules, isRecordsLoading, isSchedulesLoading, recordsError, schedulesError, updateRecord, deleteRecord, updateSchedule, deleteSchedule } = useMaintenanceRecords();
|
const { data: vehicles, isLoading: isLoadingVehicles } = useVehicles();
|
||||||
|
const [selectedVehicleId, setSelectedVehicleId] = useState<string>('');
|
||||||
|
|
||||||
|
// Auto-select first vehicle when vehicles load
|
||||||
|
useEffect(() => {
|
||||||
|
if (vehicles && vehicles.length > 0 && !selectedVehicleId) {
|
||||||
|
setSelectedVehicleId(vehicles[0].id);
|
||||||
|
}
|
||||||
|
}, [vehicles, selectedVehicleId]);
|
||||||
|
|
||||||
|
const { records, schedules, isRecordsLoading, isSchedulesLoading, recordsError, schedulesError, updateRecord, deleteRecord, updateSchedule, deleteSchedule } = useMaintenanceRecords(selectedVehicleId || undefined);
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<'records' | 'schedules'>('records');
|
const [activeTab, setActiveTab] = useState<'records' | 'schedules'>('records');
|
||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
@@ -52,7 +63,7 @@ export const MaintenanceMobileScreen: React.FC = () => {
|
|||||||
const handleDelete = async (recordId: string) => {
|
const handleDelete = async (recordId: string) => {
|
||||||
try {
|
try {
|
||||||
await deleteRecord(recordId);
|
await deleteRecord(recordId);
|
||||||
queryClient.refetchQueries({ queryKey: ['maintenanceRecords', 'all'] });
|
queryClient.refetchQueries({ queryKey: ['maintenanceRecords'] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to delete maintenance record:', error);
|
console.error('Failed to delete maintenance record:', error);
|
||||||
}
|
}
|
||||||
@@ -99,6 +110,31 @@ export const MaintenanceMobileScreen: React.FC = () => {
|
|||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<h2 className="text-lg font-semibold text-slate-800 dark:text-avus mb-3">Maintenance</h2>
|
<h2 className="text-lg font-semibold text-slate-800 dark:text-avus mb-3">Maintenance</h2>
|
||||||
|
|
||||||
|
{/* Vehicle Selector */}
|
||||||
|
<Box sx={{ mb: 2 }}>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel id="maintenance-mobile-vehicle-select-label">Vehicle</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="maintenance-mobile-vehicle-select-label"
|
||||||
|
value={selectedVehicleId}
|
||||||
|
onChange={(e) => setSelectedVehicleId(e.target.value as string)}
|
||||||
|
label="Vehicle"
|
||||||
|
disabled={isLoadingVehicles}
|
||||||
|
sx={{ minHeight: 44 }}
|
||||||
|
>
|
||||||
|
{vehicles && vehicles.length > 0 ? (
|
||||||
|
vehicles.map((vehicle) => (
|
||||||
|
<MenuItem key={vehicle.id} value={vehicle.id} sx={{ minHeight: 44 }}>
|
||||||
|
{vehicle.year} {vehicle.make} {vehicle.model}
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<MenuItem disabled>No vehicles available</MenuItem>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* @ai-context Two-column responsive layout following fuel-logs pattern
|
* @ai-context Two-column responsive layout following fuel-logs pattern
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Grid, Typography, Box, Tabs, Tab } from '@mui/material';
|
import { Grid, Typography, Box, Tabs, Tab, FormControl, InputLabel, Select, MenuItem } from '@mui/material';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { MaintenanceRecordForm } from '../components/MaintenanceRecordForm';
|
import { MaintenanceRecordForm } from '../components/MaintenanceRecordForm';
|
||||||
import { MaintenanceRecordsList } from '../components/MaintenanceRecordsList';
|
import { MaintenanceRecordsList } from '../components/MaintenanceRecordsList';
|
||||||
@@ -13,13 +13,24 @@ import { MaintenanceScheduleForm } from '../components/MaintenanceScheduleForm';
|
|||||||
import { MaintenanceSchedulesList } from '../components/MaintenanceSchedulesList';
|
import { MaintenanceSchedulesList } from '../components/MaintenanceSchedulesList';
|
||||||
import { MaintenanceScheduleEditDialog } from '../components/MaintenanceScheduleEditDialog';
|
import { MaintenanceScheduleEditDialog } from '../components/MaintenanceScheduleEditDialog';
|
||||||
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
|
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
|
||||||
|
import { useVehicles } from '../../vehicles/hooks/useVehicles';
|
||||||
import { FormSuspense } from '../../../components/SuspenseWrappers';
|
import { FormSuspense } from '../../../components/SuspenseWrappers';
|
||||||
import type { MaintenanceRecordResponse, UpdateMaintenanceRecordRequest, MaintenanceScheduleResponse, UpdateScheduleRequest } from '../types/maintenance.types';
|
import type { MaintenanceRecordResponse, UpdateMaintenanceRecordRequest, MaintenanceScheduleResponse, UpdateScheduleRequest } from '../types/maintenance.types';
|
||||||
|
|
||||||
export const MaintenancePage: React.FC = () => {
|
export const MaintenancePage: React.FC = () => {
|
||||||
const { records, schedules, isRecordsLoading, isSchedulesLoading, recordsError, schedulesError, updateRecord, deleteRecord, updateSchedule, deleteSchedule } = useMaintenanceRecords();
|
const { data: vehicles, isLoading: isLoadingVehicles } = useVehicles();
|
||||||
|
const [selectedVehicleId, setSelectedVehicleId] = useState<string>('');
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [activeTab, setActiveTab] = useState<'records' | 'schedules'>('records');
|
const [activeTab, setActiveTab] = useState<'records' | 'schedules'>('records');
|
||||||
|
|
||||||
|
// Auto-select first vehicle when vehicles load
|
||||||
|
useEffect(() => {
|
||||||
|
if (vehicles && vehicles.length > 0 && !selectedVehicleId) {
|
||||||
|
setSelectedVehicleId(vehicles[0].id);
|
||||||
|
}
|
||||||
|
}, [vehicles, selectedVehicleId]);
|
||||||
|
|
||||||
|
const { records, schedules, isRecordsLoading, isSchedulesLoading, recordsError, schedulesError, updateRecord, deleteRecord, updateSchedule, deleteSchedule } = useMaintenanceRecords(selectedVehicleId || undefined);
|
||||||
const [editingRecord, setEditingRecord] = useState<MaintenanceRecordResponse | null>(null);
|
const [editingRecord, setEditingRecord] = useState<MaintenanceRecordResponse | null>(null);
|
||||||
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
||||||
const [editingSchedule, setEditingSchedule] = useState<MaintenanceScheduleResponse | null>(null);
|
const [editingSchedule, setEditingSchedule] = useState<MaintenanceScheduleResponse | null>(null);
|
||||||
@@ -52,7 +63,7 @@ export const MaintenancePage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
await deleteRecord(recordId);
|
await deleteRecord(recordId);
|
||||||
// Refetch queries after delete
|
// Refetch queries after delete
|
||||||
queryClient.refetchQueries({ queryKey: ['maintenanceRecords', 'all'] });
|
queryClient.refetchQueries({ queryKey: ['maintenanceRecords'] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to delete maintenance record:', error);
|
console.error('Failed to delete maintenance record:', error);
|
||||||
}
|
}
|
||||||
@@ -130,6 +141,31 @@ export const MaintenancePage: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FormSuspense>
|
<FormSuspense>
|
||||||
|
{/* Vehicle Selector */}
|
||||||
|
<Box sx={{ mb: 3 }}>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel id="maintenance-vehicle-select-label">Vehicle</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="maintenance-vehicle-select-label"
|
||||||
|
value={selectedVehicleId}
|
||||||
|
onChange={(e) => setSelectedVehicleId(e.target.value as string)}
|
||||||
|
label="Vehicle"
|
||||||
|
disabled={isLoadingVehicles}
|
||||||
|
sx={{ minHeight: 56 }}
|
||||||
|
>
|
||||||
|
{vehicles && vehicles.length > 0 ? (
|
||||||
|
vehicles.map((vehicle) => (
|
||||||
|
<MenuItem key={vehicle.id} value={vehicle.id}>
|
||||||
|
{vehicle.year} {vehicle.make} {vehicle.model}
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<MenuItem disabled>No vehicles available</MenuItem>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
|
|||||||
Reference in New Issue
Block a user