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

@@ -2,32 +2,30 @@ import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from '@typescript-eslint/eslint-plugin';
import parser from '@typescript-eslint/parser';
import tseslint from 'typescript-eslint';
export default [
{ ignores: ['dist'] },
export default tseslint.config(
{ ignores: ['dist', 'node_modules'] },
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parser,
},
plugins: {
'@typescript-eslint': tseslint,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['warn', {
'@typescript-eslint/no-unused-vars': ['warn', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
@@ -36,4 +34,4 @@ export default [
'@typescript-eslint/no-explicit-any': 'warn',
},
},
];
);

View File

@@ -12,47 +12,48 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.8.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router-dom": "^6.28.1",
"@auth0/auth0-react": "^2.2.3",
"axios": "^1.6.2",
"zustand": "^4.4.6",
"@tanstack/react-query": "^5.8.4",
"react-hook-form": "^7.48.2",
"@hookform/resolvers": "^3.3.2",
"zod": "^3.22.4",
"date-fns": "^2.30.0",
"axios": "^1.7.9",
"zustand": "^4.5.6",
"@tanstack/react-query": "^5.84.1",
"react-hook-form": "^7.54.2",
"@hookform/resolvers": "^3.9.1",
"zod": "^3.24.1",
"dayjs": "^1.11.13",
"clsx": "^2.0.0",
"react-hot-toast": "^2.4.1",
"react-slick": "^0.30.2",
"slick-carousel": "^1.8.1",
"framer-motion": "^11.0.0",
"@mui/material": "^5.15.0",
"@mui/x-date-pickers": "^6.19.0",
"@mui/x-data-grid": "^6.19.1",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@emotion/cache": "^11.11.0",
"@mui/icons-material": "^5.15.0"
"framer-motion": "^11.15.0",
"@mui/material": "^6.3.0",
"@mui/x-date-pickers": "^7.23.0",
"@mui/x-data-grid": "^7.23.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@emotion/cache": "^11.14.0",
"@mui/icons-material": "^6.3.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"@types/react-slick": "^0.23.13",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"@vitejs/plugin-react": "^4.2.0",
"autoprefixer": "^10.4.16",
"eslint": "^8.54.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.4",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6",
"typescript-eslint": "^8.18.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"eslint": "^9.17.0",
"@eslint/js": "^9.17.0",
"globals": "^15.14.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.16",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"terser": "^5.24.0",
"@emotion/babel-plugin": "^11.11.0",
"typescript": "^5.6.3",
"vite": "^5.0.6",
"typescript": "^5.7.2",
"vite": "^5.4.11",
"jest": "^29.7.0",
"@types/jest": "^29.5.10",
"ts-jest": "^29.1.1",

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>

View File

@@ -46,7 +46,7 @@ export default defineConfig({
'forms': ['react-hook-form', '@hookform/resolvers', 'zod'],
// Utilities
'utils': ['date-fns', 'clsx'],
'utils': ['dayjs', 'clsx'],
// Animation and UI
'animation': ['framer-motion', 'react-hot-toast']