dev: DateTimeField
Massimo Melina committed
Oct 3, 2023 at 23:52 UTC
0fa7f43e29852bfa5ed024fd70f627863852e380
4 files changed
+54
-12
admin/package.json
+2
@@ -16,8 +16,10 @@
16
"@mui/lab": "^5.0.0-alpha.142",
17
"@mui/material": "^5.14.8",
18
"@mui/x-data-grid": "^6.13.0",
19
+ "@mui/x-date-pickers": "^6.16.0",
20
"@mui/x-tree-view": "^6.0.0-beta.0",
21
"@gregoranders/csv": "^0.0.12",
22
+ "dayjs": "^1.11.10",
23
"react": "^18.2.0",
24
"react-dom": "^18.2.0",
25
"react-router-dom": "^6.2.1",
admin/src/App.ts
+5
-2
@@ -9,12 +9,15 @@ import { useMyTheme } from './theme'
9
import { useBreakpoint} from './misc'
10
import { LoginRequired } from './LoginRequired'
11
import { Menu } from '@mui/icons-material'
12
+import { LocalizationProvider } from '@mui/x-date-pickers'
13
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
14
15
function App() {
16
return h(ThemeProvider, { theme: useMyTheme() },
17
h(ApplyTheme, {},
16
- h(LoginRequired, {},
17
- h(HashRouter, {}, h(Routed)) ) ) )
18
+ h(LocalizationProvider, { dateAdapter: AdapterDayjs },
19
+ h(LoginRequired, {},
20
+ h(HashRouter, {}, h(Routed)) ) ) ) )
21
}
22
23
function ApplyTheme(props:any) {
admin/src/ArrayField.ts
+27
-10
@@ -1,12 +1,14 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { createElement as h, Fragment, useMemo, useState } from 'react'
4
-import { IconBtn, isOrderedEqual, setHidden, swap } from './misc'
4
+import { Dict, IconBtn, isOrderedEqual, setHidden, swap } from './misc'
5
import { Add, Edit, Delete, ArrowUpward, ArrowDownward, Undo } from '@mui/icons-material'
6
import { formDialog } from './dialog'
7
-import { DataGrid, GridActionsCellItem, GridAlignment } from '@mui/x-data-grid'
7
+import { DataGrid, GridActionsCellItem, GridAlignment, GridColDef } from '@mui/x-data-grid'
8
import { FieldDescriptor, FieldProps, labelFromKey } from '@hfs/mui-grid-form'
9
import { Box, FormHelperText, FormLabel } from '@mui/material'
10
+import { DateTimeField } from './DateTimeField'
11
+import _ from 'lodash'
12
13
type ArrayFieldProps<T> = FieldProps<T[]> & { fields: FieldDescriptor[], height?: number, reorder?: boolean, prepend?: boolean }
14
export function ArrayField<T extends object>({ label, helperText, fields, value, onChange, onError, setApi, reorder, prepend, ...rest }: ArrayFieldProps<T>) {
@@ -14,7 +16,7 @@ export function ArrayField<T extends object>({ label, helperText, fields, value,
16
setHidden({ ...x } as any, x.hasOwnProperty('id') ? { $idx } : { id: $idx })),
17
[JSON.stringify(value)]) //eslint-disable-line
18
const form = {
17
- fields: fields.map(({ $width, $column, ...rest }) => rest)
19
+ fields: fields.map(({ $width, $column, $type, ...rest }) => _.defaults(rest, byType[$type]?.field))
20
}
21
setApi?.({ isEqual: isOrderedEqual }) // don't rely on stringify, as it wouldn't work with non-json values
22
const [undo, setUndo] = useState<typeof value>()
@@ -34,13 +36,17 @@ export function ArrayField<T extends object>({ label, helperText, fields, value,
36
}
37
},
38
columns: [
37
- ...fields.map(f => ({
38
- field: f.k,
39
- headerName: f.headerName ?? (typeof f.label === 'string' ? f.label : labelFromKey(f.k)),
40
- disableColumnMenu: true,
41
- ...f.$width >= 8 ? { width: f.$width } : { flex: f.$width || 1 },
42
- ...f.$column,
43
- })),
39
+ ...fields.map(f => {
40
+ const def = byType[f.$type]?.column
41
+ return ({
42
+ field: f.k,
43
+ headerName: f.headerName ?? (typeof f.label === 'string' ? f.label : labelFromKey(f.k)),
44
+ disableColumnMenu: true,
45
+ ...def,
46
+ ...f.$width ? { [f.$width >= 8 ? 'width' : 'flex']: f.$width } : (!def?.width && !def?.flex && { flex: 1 }),
47
+ ...f.$column,
48
+ })
49
+ }),
50
{
51
field: '',
52
type: 'actions',
@@ -117,3 +123,14 @@ export function ArrayField<T extends object>({ label, helperText, fields, value,
123
}
124
125
}
126
+
127
+const byType: Dict<{ field?: Partial<FieldDescriptor>, column?: Partial<GridColDef> }> = {
128
+ dateTime: {
129
+ field: { comp: DateTimeField },
130
+ column: {
131
+ type: 'dateTime', minWidth: 90, flex: 0.5,
132
+ valueGetter: ({ value }) => value && new Date(value),
133
+ renderCell: ({ value }) => value && h(Box, {}, value.toLocaleDateString(), h('br'), value.toLocaleTimeString())
134
+ }
135
+ }
136
+}
\ No newline at end of file
admin/src/DateTimeField.ts
new
+20
@@ -0,0 +1,20 @@
1
+import { DateTimePicker } from '@mui/x-date-pickers'
2
+import dayjs from 'dayjs'
3
+import { FieldProps } from '@hfs/mui-grid-form'
4
+import { createElement as h } from 'react'
5
+import { Box, FormHelperText } from '@mui/material'
6
+import { objSameKeys } from './misc'
7
+
8
+export function DateTimeField({ onChange, error, helperText, ...rest }: FieldProps<Date>) {
9
+ return h(Box, {},
10
+ h(DateTimePicker, {
11
+ ...objSameKeys(rest, x => x && x instanceof Date ? dayjs(x) : (x ?? null)), // null to not be considered uncontrolled
12
+ sx: { width: '100%', color: 'error.main', ...rest.sx },
13
+ onChange(v: any) {
14
+ onChange(v && new Date(v), { was: rest.value, event: undefined })
15
+ }
16
+ }),
17
+ helperText && h(FormHelperText, { error }, helperText),
18
+ )
19
+}
20
+