feat: Scheduled Maintenance feature complete

This commit is contained in:
Eric Gullickson
2025-12-22 14:12:33 -06:00
parent c017b8816f
commit 91b4534e76
44 changed files with 2740 additions and 117 deletions

View File

@@ -4,20 +4,26 @@
*/
import React, { useState } from 'react';
import { Grid, Typography, Box } from '@mui/material';
import { Grid, Typography, Box, Tabs, Tab } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
import { MaintenanceRecordForm } from '../components/MaintenanceRecordForm';
import { MaintenanceRecordsList } from '../components/MaintenanceRecordsList';
import { MaintenanceRecordEditDialog } from '../components/MaintenanceRecordEditDialog';
import { MaintenanceScheduleForm } from '../components/MaintenanceScheduleForm';
import { MaintenanceSchedulesList } from '../components/MaintenanceSchedulesList';
import { MaintenanceScheduleEditDialog } from '../components/MaintenanceScheduleEditDialog';
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
import { FormSuspense } from '../../../components/SuspenseWrappers';
import type { MaintenanceRecordResponse, UpdateMaintenanceRecordRequest } from '../types/maintenance.types';
import type { MaintenanceRecordResponse, UpdateMaintenanceRecordRequest, MaintenanceScheduleResponse, UpdateScheduleRequest } from '../types/maintenance.types';
export const MaintenancePage: React.FC = () => {
const { records, isRecordsLoading, recordsError, updateRecord, deleteRecord } = useMaintenanceRecords();
const { records, schedules, isRecordsLoading, isSchedulesLoading, recordsError, schedulesError, updateRecord, deleteRecord, updateSchedule, deleteSchedule } = useMaintenanceRecords();
const queryClient = useQueryClient();
const [activeTab, setActiveTab] = useState<'records' | 'schedules'>('records');
const [editingRecord, setEditingRecord] = useState<MaintenanceRecordResponse | null>(null);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [editingSchedule, setEditingSchedule] = useState<MaintenanceScheduleResponse | null>(null);
const [scheduleEditDialogOpen, setScheduleEditDialogOpen] = useState(false);
const handleEdit = (record: MaintenanceRecordResponse) => {
setEditingRecord(record);
@@ -52,7 +58,43 @@ export const MaintenancePage: React.FC = () => {
}
};
if (isRecordsLoading) {
const handleScheduleEdit = (schedule: MaintenanceScheduleResponse) => {
setEditingSchedule(schedule);
setScheduleEditDialogOpen(true);
};
const handleScheduleEditSave = async (id: string, data: UpdateScheduleRequest) => {
try {
await updateSchedule({ id, data });
// Refetch queries after update
queryClient.refetchQueries({ queryKey: ['maintenanceSchedules'] });
setScheduleEditDialogOpen(false);
setEditingSchedule(null);
} catch (error) {
console.error('Failed to update maintenance schedule:', error);
throw error; // Re-throw to let dialog handle the error
}
};
const handleScheduleEditClose = () => {
setScheduleEditDialogOpen(false);
setEditingSchedule(null);
};
const handleScheduleDelete = async (scheduleId: string) => {
try {
await deleteSchedule(scheduleId);
// Refetch queries after delete
queryClient.refetchQueries({ queryKey: ['maintenanceSchedules'] });
} catch (error) {
console.error('Failed to delete maintenance schedule:', error);
}
};
const isLoading = activeTab === 'records' ? isRecordsLoading : isSchedulesLoading;
const hasError = activeTab === 'records' ? recordsError : schedulesError;
if (isLoading) {
return (
<Box
sx={{
@@ -62,12 +104,14 @@ export const MaintenancePage: React.FC = () => {
height: '50vh',
}}
>
<Typography color="text.secondary">Loading maintenance records...</Typography>
<Typography color="text.secondary">
Loading maintenance {activeTab}...
</Typography>
</Box>
);
}
if (recordsError) {
if (hasError) {
return (
<Box
sx={{
@@ -78,7 +122,7 @@ export const MaintenancePage: React.FC = () => {
}}
>
<Typography color="error">
Failed to load maintenance records. Please try again.
Failed to load maintenance {activeTab}. Please try again.
</Typography>
</Box>
);
@@ -86,32 +130,72 @@ export const MaintenancePage: React.FC = () => {
return (
<FormSuspense>
<Grid container spacing={3}>
{/* Top: Form */}
<Grid item xs={12}>
<MaintenanceRecordForm />
</Grid>
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
<Tabs
value={activeTab}
onChange={(_, v) => setActiveTab(v as 'records' | 'schedules')}
aria-label="Maintenance tabs"
>
<Tab label="Records" value="records" />
<Tab label="Schedules" value="schedules" />
</Tabs>
</Box>
{/* Bottom: Records List */}
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
Recent Maintenance Records
</Typography>
<MaintenanceRecordsList
records={records}
onEdit={handleEdit}
onDelete={handleDelete}
/>
</Grid>
</Grid>
{activeTab === 'records' && (
<Grid container spacing={3}>
{/* Top: Form */}
<Grid item xs={12}>
<MaintenanceRecordForm />
</Grid>
{/* Edit Dialog */}
{/* Bottom: Records List */}
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
Recent Maintenance Records
</Typography>
<MaintenanceRecordsList
records={records}
onEdit={handleEdit}
onDelete={handleDelete}
/>
</Grid>
</Grid>
)}
{activeTab === 'schedules' && (
<Grid container spacing={3}>
{/* Top: Form */}
<Grid item xs={12}>
<MaintenanceScheduleForm />
</Grid>
{/* Bottom: Schedules List */}
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
Maintenance Schedules
</Typography>
<MaintenanceSchedulesList
schedules={schedules || []}
onEdit={handleScheduleEdit}
onDelete={handleScheduleDelete}
/>
</Grid>
</Grid>
)}
{/* Edit Dialogs */}
<MaintenanceRecordEditDialog
open={editDialogOpen}
record={editingRecord}
onClose={handleEditClose}
onSave={handleEditSave}
/>
<MaintenanceScheduleEditDialog
open={scheduleEditDialogOpen}
schedule={editingSchedule}
onClose={handleScheduleEditClose}
onSave={handleScheduleEditSave}
/>
</FormSuspense>
);
};