Updated packages. Changed date picker package to Day.JS and applied it across whole app.

This commit is contained in:
Eric Gullickson
2025-12-18 16:07:30 -06:00
parent 843825a956
commit 0e85cf48c3
17 changed files with 197 additions and 135 deletions

View File

@@ -15,12 +15,15 @@ import {
Divider,
} from '@mui/material';
import { Close, ChevronLeft, ChevronRight } from '@mui/icons-material';
import { formatDistanceToNow } from 'date-fns';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import { useAuditLogStream } from '../hooks/useAuditLogStream';
import { AdminSkeleton } from './AdminSkeleton';
import { EmptyState } from './EmptyState';
import { ErrorState } from './ErrorState';
dayjs.extend(relativeTime);
/**
* Props for AuditLogDrawer component
*/
@@ -154,9 +157,7 @@ export const AuditLogDrawer: React.FC<AuditLogDrawerProps> = ({
component="span"
color="text.secondary"
>
{formatDistanceToNow(new Date(log.createdAt), {
addSuffix: true,
})}
{dayjs(log.createdAt).fromNow()}
</Typography>
{log.resourceType && (
<Typography
@@ -193,10 +194,7 @@ export const AuditLogDrawer: React.FC<AuditLogDrawerProps> = ({
}}
>
<Typography variant="body2" color="text.secondary">
Updated{' '}
{formatDistanceToNow(lastUpdated, {
addSuffix: true,
})}
Updated {dayjs(lastUpdated).fromNow()}
</Typography>
<Box>
<IconButton

View File

@@ -21,12 +21,15 @@ import {
ChevronLeft,
ChevronRight,
} from '@mui/icons-material';
import { formatDistanceToNow } from 'date-fns';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import { useAuditLogStream } from '../hooks/useAuditLogStream';
import { AdminSkeleton } from './AdminSkeleton';
import { EmptyState } from './EmptyState';
import { ErrorState } from './ErrorState';
dayjs.extend(relativeTime);
/**
* Props for AuditLogPanel component
*/
@@ -148,9 +151,7 @@ export const AuditLogPanel: React.FC<AuditLogPanelProps> = ({
component="span"
color="text.secondary"
>
{formatDistanceToNow(new Date(log.createdAt), {
addSuffix: true,
})}
{dayjs(log.createdAt).fromNow()}
</Typography>
{log.resourceType && (
<Typography
@@ -186,10 +187,7 @@ export const AuditLogPanel: React.FC<AuditLogPanelProps> = ({
}}
>
<Typography variant="caption" color="text.secondary">
Updated{' '}
{formatDistanceToNow(lastUpdated, {
addSuffix: true,
})}
Updated {dayjs(lastUpdated).fromNow()}
</Typography>
<Box>
<IconButton

View File

@@ -1,5 +1,9 @@
import React from 'react';
import { Button } from '../../../shared-minimal/components/Button';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import dayjs from 'dayjs';
import { useCreateDocument } from '../hooks/useDocuments';
import { documentsApi } from '../api/documents.api';
import type { DocumentType } from '../types/documents.types';
@@ -144,6 +148,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
};
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<form onSubmit={handleSubmit} className="w-full">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex flex-col">
@@ -207,21 +212,39 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
</div>
<div className="flex flex-col">
<label className="text-sm font-medium text-slate-700 mb-1">Effective Date</label>
<input
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
type="date"
value={effectiveDate}
onChange={(e) => setEffectiveDate(e.target.value)}
<DatePicker
label="Effective Date"
value={effectiveDate ? dayjs(effectiveDate) : null}
onChange={(newValue) => setEffectiveDate(newValue?.format('YYYY-MM-DD') || '')}
format="MM/DD/YYYY"
slotProps={{
textField: {
fullWidth: true,
sx: {
'& .MuiOutlinedInput-root': {
minHeight: 44,
},
},
},
}}
/>
</div>
<div className="flex flex-col">
<label className="text-sm font-medium text-slate-700 mb-1">Expiration Date</label>
<input
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
type="date"
value={expirationDate}
onChange={(e) => setExpirationDate(e.target.value)}
<DatePicker
label="Expiration Date"
value={expirationDate ? dayjs(expirationDate) : null}
onChange={(newValue) => setExpirationDate(newValue?.format('YYYY-MM-DD') || '')}
format="MM/DD/YYYY"
slotProps={{
textField: {
fullWidth: true,
sx: {
'& .MuiOutlinedInput-root': {
minHeight: 44,
},
},
},
}}
/>
</div>
@@ -282,12 +305,21 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
/>
</div>
<div className="flex flex-col">
<label className="text-sm font-medium text-slate-700 mb-1">Expiration Date</label>
<input
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
type="date"
value={registrationExpirationDate}
onChange={(e) => setRegistrationExpirationDate(e.target.value)}
<DatePicker
label="Expiration Date"
value={registrationExpirationDate ? dayjs(registrationExpirationDate) : null}
onChange={(newValue) => setRegistrationExpirationDate(newValue?.format('YYYY-MM-DD') || '')}
format="MM/DD/YYYY"
slotProps={{
textField: {
fullWidth: true,
sx: {
'& .MuiOutlinedInput-root': {
minHeight: 44,
},
},
},
}}
/>
</div>
<div className="flex flex-col md:col-span-2">
@@ -336,6 +368,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
<Button type="button" variant="secondary" onClick={onCancel} className="min-h-[44px]">Cancel</Button>
</div>
</form>
</LocalizationProvider>
);
};

View File

@@ -16,8 +16,9 @@ import {
useMediaQuery
} from '@mui/material';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import dayjs from 'dayjs';
import { FuelLogResponse, UpdateFuelLogRequest, FuelType } from '../types/fuel-logs.types';
import { useFuelGrades } from '../hooks/useFuelGrades';
@@ -135,7 +136,7 @@ export const FuelLogEditDialog: React.FC<FuelLogEditDialogProps> = ({
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Dialog
open={open}
onClose={handleCancel}
@@ -154,9 +155,9 @@ export const FuelLogEditDialog: React.FC<FuelLogEditDialogProps> = ({
<Grid item xs={12}>
<DateTimePicker
label="Date & Time"
value={formData.dateTime ? new Date(formData.dateTime) : null}
value={formData.dateTime ? dayjs(formData.dateTime) : null}
onChange={(newValue) => handleInputChange('dateTime', newValue?.toISOString() || '')}
format="MM/dd/yyyy hh:mm a"
format="MM/DD/YYYY hh:mm a"
slotProps={{
textField: {
fullWidth: true,

View File

@@ -4,8 +4,9 @@ import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { Grid, Card, CardHeader, CardContent, TextField, Box, Button, CircularProgress, ToggleButton, ToggleButtonGroup } from '@mui/material';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import dayjs from 'dayjs';
import { VehicleSelector } from './VehicleSelector';
import { DistanceInput } from './DistanceInput';
import { FuelTypeSelector } from './FuelTypeSelector';
@@ -143,7 +144,7 @@ const FuelLogFormComponent: React.FC<{ onSuccess?: () => void; initial?: Partial
}, [useOdometer, setValue]);
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Card>
<CardHeader title="Add Fuel Log" subheader={<UnitSystemDisplay unitSystem={userSettings?.unitSystem} showLabel="Displaying in" />} />
<CardContent>
@@ -161,9 +162,9 @@ const FuelLogFormComponent: React.FC<{ onSuccess?: () => void; initial?: Partial
<Controller name="dateTime" control={control} render={({ field }) => (
<DateTimePicker
label="Date & Time"
value={field.value ? new Date(field.value) : null}
value={field.value ? dayjs(field.value) : null}
onChange={(newValue) => field.onChange(newValue?.toISOString() || '')}
format="MM/dd/yyyy hh:mm a"
format="MM/DD/YYYY hh:mm a"
slotProps={{
textField: {
fullWidth: true,

View File

@@ -21,8 +21,9 @@ import {
useMediaQuery,
} from '@mui/material';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import dayjs from 'dayjs';
import {
MaintenanceRecordResponse,
UpdateMaintenanceRecordRequest,
@@ -149,7 +150,7 @@ export const MaintenanceRecordEditDialog: React.FC<MaintenanceRecordEditDialogPr
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Dialog
open={open}
onClose={handleCancel}
@@ -221,11 +222,11 @@ export const MaintenanceRecordEditDialog: React.FC<MaintenanceRecordEditDialogPr
<Grid item xs={12} sm={6}>
<DatePicker
label="Service Date *"
value={formData.date ? new Date(formData.date) : null}
value={formData.date ? dayjs(formData.date) : null}
onChange={(newValue) =>
handleInputChange('date', newValue?.toISOString().split('T')[0] || '')
}
format="MM/dd/yyyy"
format="MM/DD/YYYY"
slotProps={{
textField: {
fullWidth: true,

View File

@@ -25,8 +25,9 @@ import {
InputAdornment,
} from '@mui/material';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import dayjs from 'dayjs';
import { useMaintenanceRecords } from '../hooks/useMaintenanceRecords';
import { useVehicles } from '../../vehicles/hooks/useVehicles';
import { SubtypeCheckboxGroup } from './SubtypeCheckboxGroup';
@@ -135,7 +136,7 @@ export const MaintenanceRecordForm: React.FC = () => {
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Card>
<CardHeader title="Add Maintenance Record" />
<CardContent>
@@ -238,11 +239,11 @@ export const MaintenanceRecordForm: React.FC = () => {
render={({ field }) => (
<DatePicker
label="Date *"
value={field.value ? new Date(field.value) : null}
value={field.value ? dayjs(field.value) : null}
onChange={(newValue) =>
field.onChange(newValue?.toISOString().split('T')[0] || '')
}
format="MM/dd/yyyy"
format="MM/DD/YYYY"
slotProps={{
textField: {
fullWidth: true,

View File

@@ -3,7 +3,7 @@
*/
import React, { useMemo, useState } from 'react';
import { Box, Typography, Button, Card, CardContent, Divider, FormControl, InputLabel, Select, MenuItem, List, ListItem } from '@mui/material';
import { Box, Typography, Button, Card, CardContent, Divider, FormControl, InputLabel, Select, MenuItem, List, ListItem, ListItemButton } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
import { Vehicle } from '../types/vehicles.types';
import { useFuelLogs } from '../../fuel-logs/hooks/useFuelLogs';
@@ -250,22 +250,24 @@ export const VehicleDetailMobile: React.FC<VehicleDetailMobileProps> = ({
) : (
<List disablePadding>
{filteredRecords.map(rec => (
<ListItem key={rec.id} divider button onClick={() => openEditLog(rec.id, rec.type)}>
<Box sx={{ flexGrow: 1 }}>
{/* Primary line: MPG/km-L and amount */}
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="body1" color="text.primary">
{rec.summary || 'MPG: —'}
</Typography>
<Typography variant="body1" color="text.primary">
{rec.amount || '—'}
<ListItem key={rec.id} divider disablePadding>
<ListItemButton onClick={() => openEditLog(rec.id, rec.type)}>
<Box sx={{ flexGrow: 1 }}>
{/* Primary line: MPG/km-L and amount */}
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="body1" color="text.primary">
{rec.summary || 'MPG: —'}
</Typography>
<Typography variant="body1" color="text.primary">
{rec.amount || '—'}
</Typography>
</Box>
{/* Secondary line: Grade • Date • Type */}
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.25 }}>
{rec.secondary || `${new Date(rec.date).toLocaleDateString()}${rec.type}`}
</Typography>
</Box>
{/* Secondary line: Grade • Date • Type */}
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.25 }}>
{rec.secondary || `${new Date(rec.date).toLocaleDateString()}${rec.type}`}
</Typography>
</Box>
</ListItemButton>
</ListItem>
))}
</List>