chore: restructure Fuel Logs to list-first with add dialog (refs #168)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* @ai-summary Dialog wrapper for FuelLogForm to create new fuel logs
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Dialog, DialogTitle, DialogContent, IconButton, useMediaQuery } from '@mui/material';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import { FuelLogForm } from './FuelLogForm';
|
||||||
|
|
||||||
|
interface AddFuelLogDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AddFuelLogDialog: React.FC<AddFuelLogDialogProps> = ({ open, onClose }) => {
|
||||||
|
const isSmallScreen = useMediaQuery('(max-width:600px)');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
fullScreen={isSmallScreen}
|
||||||
|
PaperProps={{
|
||||||
|
sx: { maxHeight: isSmallScreen ? '100%' : '90vh' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
Log Fuel
|
||||||
|
<IconButton
|
||||||
|
aria-label="close"
|
||||||
|
onClick={onClose}
|
||||||
|
sx={{ minWidth: 44, minHeight: 44 }}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent sx={{ p: { xs: 1, sm: 2 } }}>
|
||||||
|
<FuelLogForm onSuccess={onClose} />
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Grid, Typography, Box } from '@mui/material';
|
import { Typography, Box, Button as MuiButton } from '@mui/material';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { FuelLogForm } from '../components/FuelLogForm';
|
|
||||||
import { FuelLogsList } from '../components/FuelLogsList';
|
import { FuelLogsList } from '../components/FuelLogsList';
|
||||||
import { FuelLogEditDialog } from '../components/FuelLogEditDialog';
|
import { FuelLogEditDialog } from '../components/FuelLogEditDialog';
|
||||||
|
import { AddFuelLogDialog } from '../components/AddFuelLogDialog';
|
||||||
import { useFuelLogs } from '../hooks/useFuelLogs';
|
import { useFuelLogs } from '../hooks/useFuelLogs';
|
||||||
import { FuelStatsCard } from '../components/FuelStatsCard';
|
import { FuelStatsCard } from '../components/FuelStatsCard';
|
||||||
import { FormSuspense } from '../../../components/SuspenseWrappers';
|
|
||||||
import { FuelLogResponse, UpdateFuelLogRequest } from '../types/fuel-logs.types';
|
import { FuelLogResponse, UpdateFuelLogRequest } from '../types/fuel-logs.types';
|
||||||
import { fuelLogsApi } from '../api/fuel-logs.api';
|
import { fuelLogsApi } from '../api/fuel-logs.api';
|
||||||
|
|
||||||
@@ -14,9 +14,7 @@ export const FuelLogsPage: React.FC = () => {
|
|||||||
const { fuelLogs, isLoading, error } = useFuelLogs();
|
const { fuelLogs, isLoading, error } = useFuelLogs();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [editingLog, setEditingLog] = useState<FuelLogResponse | null>(null);
|
const [editingLog, setEditingLog] = useState<FuelLogResponse | null>(null);
|
||||||
|
const [showAddDialog, setShowAddDialog] = useState(false);
|
||||||
// DEBUG: Log page renders
|
|
||||||
console.log('[FuelLogsPage] Render - fuel logs count:', fuelLogs?.length, 'isLoading:', isLoading, 'error:', !!error);
|
|
||||||
|
|
||||||
const handleEdit = (log: FuelLogResponse) => {
|
const handleEdit = (log: FuelLogResponse) => {
|
||||||
setEditingLog(log);
|
setEditingLog(log);
|
||||||
@@ -24,9 +22,6 @@ export const FuelLogsPage: React.FC = () => {
|
|||||||
|
|
||||||
const handleDelete = async (_logId: string) => {
|
const handleDelete = async (_logId: string) => {
|
||||||
try {
|
try {
|
||||||
console.log('[FuelLogsPage] handleDelete called - using targeted query updates');
|
|
||||||
// Use targeted invalidation instead of broad invalidation
|
|
||||||
// This prevents unnecessary re-renders of the form
|
|
||||||
queryClient.refetchQueries({ queryKey: ['fuelLogs', 'all'] });
|
queryClient.refetchQueries({ queryKey: ['fuelLogs', 'all'] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to refresh fuel logs after delete:', error);
|
console.error('Failed to refresh fuel logs after delete:', error);
|
||||||
@@ -35,15 +30,12 @@ export const FuelLogsPage: React.FC = () => {
|
|||||||
|
|
||||||
const handleSaveEdit = async (id: string, data: UpdateFuelLogRequest) => {
|
const handleSaveEdit = async (id: string, data: UpdateFuelLogRequest) => {
|
||||||
try {
|
try {
|
||||||
console.log('[FuelLogsPage] handleSaveEdit called - using targeted query updates');
|
|
||||||
await fuelLogsApi.update(id, data);
|
await fuelLogsApi.update(id, data);
|
||||||
// Use targeted refetch instead of broad invalidation
|
|
||||||
// This prevents unnecessary re-renders of the form
|
|
||||||
queryClient.refetchQueries({ queryKey: ['fuelLogs', 'all'] });
|
queryClient.refetchQueries({ queryKey: ['fuelLogs', 'all'] });
|
||||||
setEditingLog(null);
|
setEditingLog(null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to update fuel log:', error);
|
console.error('Failed to update fuel log:', error);
|
||||||
throw error; // Re-throw to let the dialog handle the error
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,22 +70,36 @@ export const FuelLogsPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormSuspense>
|
<Box>
|
||||||
<Grid container spacing={2}>
|
{/* Header with Add button */}
|
||||||
<Grid item xs={12} md={6}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||||
<FuelLogForm />
|
<Typography variant="h5" sx={{ fontWeight: 600 }}>Fuel Logs</Typography>
|
||||||
</Grid>
|
<MuiButton
|
||||||
<Grid item xs={12} md={6}>
|
variant="contained"
|
||||||
<Typography variant="h6" gutterBottom>Summary</Typography>
|
startIcon={<AddIcon />}
|
||||||
<FuelStatsCard logs={fuelLogs} />
|
onClick={() => setShowAddDialog(true)}
|
||||||
<Typography variant="h6" sx={{ mt: 3 }} gutterBottom>Recent Fuel Logs</Typography>
|
>
|
||||||
<FuelLogsList
|
Add Fuel Log
|
||||||
logs={fuelLogs}
|
</MuiButton>
|
||||||
onEdit={handleEdit}
|
</Box>
|
||||||
onDelete={handleDelete}
|
|
||||||
/>
|
{/* Summary Stats */}
|
||||||
</Grid>
|
<Box sx={{ mb: 3 }}>
|
||||||
</Grid>
|
<FuelStatsCard logs={fuelLogs} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Fuel Logs List */}
|
||||||
|
<FuelLogsList
|
||||||
|
logs={fuelLogs}
|
||||||
|
onEdit={handleEdit}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Add Dialog */}
|
||||||
|
<AddFuelLogDialog
|
||||||
|
open={showAddDialog}
|
||||||
|
onClose={() => setShowAddDialog(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Edit Dialog */}
|
{/* Edit Dialog */}
|
||||||
<FuelLogEditDialog
|
<FuelLogEditDialog
|
||||||
@@ -102,6 +108,6 @@ export const FuelLogsPage: React.FC = () => {
|
|||||||
onClose={handleCloseEdit}
|
onClose={handleCloseEdit}
|
||||||
onSave={handleSaveEdit}
|
onSave={handleSaveEdit}
|
||||||
/>
|
/>
|
||||||
</FormSuspense>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user