goobs-frontend 0.9.23 → 0.9.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/components/DataGrid/Table/ColumnHeaderRow/index.tsx +29 -6
- package/src/components/Field/Date/index.tsx +398 -16
- package/src/components/Field/Dropdown/MultiSelect/index.tsx +113 -6
- package/src/components/Field/Text/index.tsx +38 -48
- package/src/components/ProjectBoard/forms/AddTask/administrator/companyDropdown/index.tsx +107 -79
- package/src/components/ProjectBoard/forms/AddTask/administrator/companyProvided/index.tsx +103 -76
- package/src/components/ProjectBoard/forms/AddTask/company/customerDropdown/index.tsx +121 -86
- package/src/components/ProjectBoard/forms/AddTask/company/customerProvided/index.tsx +104 -76
- package/src/components/ProjectBoard/forms/AddTask/customer/index.tsx +80 -19
- package/src/components/ProjectBoard/forms/AddTask/noUser/index.tsx +51 -5
- package/src/components/ProjectBoard/forms/ShowTask/client.tsx +10 -3
- package/src/index.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goobs-frontend",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A comprehensive React-based libary that extends the functionality of Material-UI",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"otplib": "^12",
|
|
38
38
|
"react-datepicker": "^8",
|
|
39
39
|
"react-qr-code": "^2",
|
|
40
|
-
"slate": "^0.
|
|
41
|
-
"slate-dom": "^0.
|
|
42
|
-
"slate-history": "^0.
|
|
43
|
-
"slate-react": "^0.
|
|
40
|
+
"slate": "^0.114",
|
|
41
|
+
"slate-dom": "^0.114",
|
|
42
|
+
"slate-history": "^0.113",
|
|
43
|
+
"slate-react": "^0.114",
|
|
44
44
|
"storybook": "^8",
|
|
45
45
|
"zod": "^3",
|
|
46
46
|
"zod-formik-adapter": "^1"
|
|
@@ -38,8 +38,7 @@ const ColumnHeaderRow: React.FC<ColumnHeaderRowProps> = ({
|
|
|
38
38
|
// If we're mobile, just render a single dropdown + "select all" checkbox
|
|
39
39
|
if (isMobile) {
|
|
40
40
|
const mobileOptions = allColumns.map(col => ({
|
|
41
|
-
value: col.field,
|
|
42
|
-
label: col.headerName ?? col.field,
|
|
41
|
+
value: col.headerName ?? col.field,
|
|
43
42
|
}))
|
|
44
43
|
|
|
45
44
|
// Find the currently-selected column as an object
|
|
@@ -47,7 +46,19 @@ const ColumnHeaderRow: React.FC<ColumnHeaderRowProps> = ({
|
|
|
47
46
|
mobileOptions.find(opt => opt.value === selectedOverflowField) || null
|
|
48
47
|
|
|
49
48
|
const handleMobileChange = (value: { value: string } | null) => {
|
|
50
|
-
|
|
49
|
+
if (value && value.value) {
|
|
50
|
+
// Try to find a column with matching headerName first
|
|
51
|
+
const matchingColumn = allColumns.find(
|
|
52
|
+
col => col.headerName === value.value || col.field === value.value
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// If found, use its field property, otherwise use the value directly
|
|
56
|
+
setSelectedOverflowField(
|
|
57
|
+
matchingColumn ? matchingColumn.field : value.value
|
|
58
|
+
)
|
|
59
|
+
} else {
|
|
60
|
+
setSelectedOverflowField('')
|
|
61
|
+
}
|
|
51
62
|
}
|
|
52
63
|
|
|
53
64
|
return (
|
|
@@ -107,7 +118,20 @@ const ColumnHeaderRow: React.FC<ColumnHeaderRowProps> = ({
|
|
|
107
118
|
// Desktop logic
|
|
108
119
|
// ---------------------------
|
|
109
120
|
const handleOverflowChange = (value: { value: string } | null) => {
|
|
110
|
-
|
|
121
|
+
// If using headerName for value in dropdown, we need to find the corresponding field
|
|
122
|
+
if (value && value.value) {
|
|
123
|
+
// Try to find a column with matching headerName first
|
|
124
|
+
const matchingColumn = overflowDesktopColumns.find(
|
|
125
|
+
col => col.headerName === value.value || col.field === value.value
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
// If found, use its field property, otherwise use the value directly
|
|
129
|
+
setSelectedOverflowField(
|
|
130
|
+
matchingColumn ? matchingColumn.field : value.value
|
|
131
|
+
)
|
|
132
|
+
} else {
|
|
133
|
+
setSelectedOverflowField('')
|
|
134
|
+
}
|
|
111
135
|
}
|
|
112
136
|
|
|
113
137
|
return (
|
|
@@ -150,8 +174,7 @@ const ColumnHeaderRow: React.FC<ColumnHeaderRowProps> = ({
|
|
|
150
174
|
<SearchableDropdown
|
|
151
175
|
label="More Columns"
|
|
152
176
|
options={overflowDesktopColumns.map(oc => ({
|
|
153
|
-
value: oc.field,
|
|
154
|
-
label: oc.headerName ?? oc.field,
|
|
177
|
+
value: oc.headerName ?? oc.field,
|
|
155
178
|
}))}
|
|
156
179
|
defaultValue={selectedOverflowField}
|
|
157
180
|
onChange={handleOverflowChange}
|
|
@@ -4,11 +4,38 @@ import DatePicker from 'react-datepicker'
|
|
|
4
4
|
import 'react-datepicker/dist/react-datepicker.css'
|
|
5
5
|
import CalendarTodayIcon from '@mui/icons-material/CalendarToday'
|
|
6
6
|
import TextField, { TextFieldProps } from '../../Field/Text'
|
|
7
|
+
import { Box } from '@mui/material'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* DateRange interface for range mode
|
|
11
|
+
*/
|
|
12
|
+
export interface DateRange {
|
|
13
|
+
start: Date | null
|
|
14
|
+
end: Date | null
|
|
15
|
+
}
|
|
7
16
|
|
|
8
17
|
export interface DateFieldProps
|
|
9
18
|
extends Omit<TextFieldProps, 'onChange' | 'value' | 'endAdornment'> {
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Callback when date changes
|
|
21
|
+
*/
|
|
22
|
+
onChange?: (date: Date | null | DateRange) => void
|
|
23
|
+
/**
|
|
24
|
+
* Current date value
|
|
25
|
+
*/
|
|
26
|
+
value?: Date | null | DateRange
|
|
27
|
+
/**
|
|
28
|
+
* Whether to show date range picker instead of single date
|
|
29
|
+
*/
|
|
30
|
+
isRange?: boolean
|
|
31
|
+
/**
|
|
32
|
+
* Start date label (for range mode)
|
|
33
|
+
*/
|
|
34
|
+
startLabel?: string
|
|
35
|
+
/**
|
|
36
|
+
* End date label (for range mode)
|
|
37
|
+
*/
|
|
38
|
+
endLabel?: string
|
|
12
39
|
}
|
|
13
40
|
|
|
14
41
|
interface CustomInputProps {
|
|
@@ -35,6 +62,9 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
35
62
|
onChange,
|
|
36
63
|
label = 'Select Date',
|
|
37
64
|
value,
|
|
65
|
+
isRange = false,
|
|
66
|
+
startLabel = 'Start Date',
|
|
67
|
+
endLabel = 'End Date',
|
|
38
68
|
...rest
|
|
39
69
|
}) => {
|
|
40
70
|
const formatDate = (date: Date | null) => {
|
|
@@ -49,22 +79,45 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
49
79
|
return ''
|
|
50
80
|
}
|
|
51
81
|
|
|
52
|
-
|
|
82
|
+
// Initialize state based on whether in range mode or single date mode
|
|
83
|
+
const [selectedDate, setSelectedDate] = useState<Date | null>(
|
|
84
|
+
isRange ? null : (value as Date | null) || new Date()
|
|
85
|
+
)
|
|
86
|
+
const [dateRange, setDateRange] = useState<DateRange>(
|
|
87
|
+
isRange
|
|
88
|
+
? (value as DateRange) || { start: new Date(), end: new Date() }
|
|
89
|
+
: { start: new Date(), end: new Date() }
|
|
90
|
+
)
|
|
53
91
|
const [isOpen, setIsOpen] = useState(false)
|
|
54
|
-
const [
|
|
92
|
+
const [isStartDateOpen, setIsStartDateOpen] = useState(false)
|
|
93
|
+
const [isEndDateOpen, setIsEndDateOpen] = useState(false)
|
|
94
|
+
const [inputValue, setInputValue] = useState(
|
|
95
|
+
isRange ? '' : formatDate(selectedDate)
|
|
96
|
+
)
|
|
97
|
+
const [startDateInputValue, setStartDateInputValue] = useState(
|
|
98
|
+
formatDate(dateRange.start)
|
|
99
|
+
)
|
|
100
|
+
const [endDateInputValue, setEndDateInputValue] = useState(
|
|
101
|
+
formatDate(dateRange.end)
|
|
102
|
+
)
|
|
55
103
|
|
|
104
|
+
// Single date mode handlers
|
|
56
105
|
const handleChange = (date: Date | null) => {
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
onChange
|
|
106
|
+
if (!isRange) {
|
|
107
|
+
if (date) {
|
|
108
|
+
setSelectedDate(date)
|
|
109
|
+
setInputValue(formatDate(date))
|
|
110
|
+
setIsOpen(false)
|
|
111
|
+
if (onChange) {
|
|
112
|
+
onChange(date)
|
|
113
|
+
}
|
|
63
114
|
}
|
|
64
115
|
}
|
|
65
116
|
}
|
|
66
117
|
|
|
67
118
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
119
|
+
if (isRange) return // Only for single date mode
|
|
120
|
+
|
|
68
121
|
const input = e.target
|
|
69
122
|
const newValue = e.target.value
|
|
70
123
|
const selectionStart = input.selectionStart || 0
|
|
@@ -103,6 +156,117 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
103
156
|
}, 0)
|
|
104
157
|
}
|
|
105
158
|
|
|
159
|
+
// Range mode handlers
|
|
160
|
+
const handleStartDateChange = (date: Date | null) => {
|
|
161
|
+
if (isRange && date) {
|
|
162
|
+
const newRange = { ...dateRange, start: date }
|
|
163
|
+
setDateRange(newRange)
|
|
164
|
+
setStartDateInputValue(formatDate(date))
|
|
165
|
+
setIsStartDateOpen(false)
|
|
166
|
+
if (onChange) {
|
|
167
|
+
onChange(newRange)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const handleEndDateChange = (date: Date | null) => {
|
|
173
|
+
if (isRange && date) {
|
|
174
|
+
const newRange = { ...dateRange, end: date }
|
|
175
|
+
setDateRange(newRange)
|
|
176
|
+
setEndDateInputValue(formatDate(date))
|
|
177
|
+
setIsEndDateOpen(false)
|
|
178
|
+
if (onChange) {
|
|
179
|
+
onChange(newRange)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const handleStartDateInputChange = (
|
|
185
|
+
e: React.ChangeEvent<HTMLInputElement>
|
|
186
|
+
) => {
|
|
187
|
+
if (!isRange) return
|
|
188
|
+
|
|
189
|
+
const input = e.target
|
|
190
|
+
const newValue = e.target.value
|
|
191
|
+
const selectionStart = input.selectionStart || 0
|
|
192
|
+
|
|
193
|
+
setStartDateInputValue(newValue)
|
|
194
|
+
|
|
195
|
+
const parts = newValue.split('/')
|
|
196
|
+
if (parts.length === 3) {
|
|
197
|
+
const month = parseInt(parts[0], 10)
|
|
198
|
+
const day = parseInt(parts[1], 10)
|
|
199
|
+
const year = parseInt(parts[2], 10)
|
|
200
|
+
|
|
201
|
+
if (!isNaN(month) && !isNaN(day) && !isNaN(year)) {
|
|
202
|
+
const newDate = new Date(year, month - 1, day)
|
|
203
|
+
if (
|
|
204
|
+
newDate.getMonth() === month - 1 &&
|
|
205
|
+
newDate.getDate() === day &&
|
|
206
|
+
newDate.getFullYear() === year
|
|
207
|
+
) {
|
|
208
|
+
const newRange = { ...dateRange, start: newDate }
|
|
209
|
+
setDateRange(newRange)
|
|
210
|
+
if (onChange) {
|
|
211
|
+
onChange(newRange)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
setTimeout(() => {
|
|
218
|
+
if (selectionStart <= 2) {
|
|
219
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
220
|
+
} else if (selectionStart <= 5) {
|
|
221
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
222
|
+
} else {
|
|
223
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
224
|
+
}
|
|
225
|
+
}, 0)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const handleEndDateInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
229
|
+
if (!isRange) return
|
|
230
|
+
|
|
231
|
+
const input = e.target
|
|
232
|
+
const newValue = e.target.value
|
|
233
|
+
const selectionStart = input.selectionStart || 0
|
|
234
|
+
|
|
235
|
+
setEndDateInputValue(newValue)
|
|
236
|
+
|
|
237
|
+
const parts = newValue.split('/')
|
|
238
|
+
if (parts.length === 3) {
|
|
239
|
+
const month = parseInt(parts[0], 10)
|
|
240
|
+
const day = parseInt(parts[1], 10)
|
|
241
|
+
const year = parseInt(parts[2], 10)
|
|
242
|
+
|
|
243
|
+
if (!isNaN(month) && !isNaN(day) && !isNaN(year)) {
|
|
244
|
+
const newDate = new Date(year, month - 1, day)
|
|
245
|
+
if (
|
|
246
|
+
newDate.getMonth() === month - 1 &&
|
|
247
|
+
newDate.getDate() === day &&
|
|
248
|
+
newDate.getFullYear() === year
|
|
249
|
+
) {
|
|
250
|
+
const newRange = { ...dateRange, end: newDate }
|
|
251
|
+
setDateRange(newRange)
|
|
252
|
+
if (onChange) {
|
|
253
|
+
onChange(newRange)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
if (selectionStart <= 2) {
|
|
261
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
262
|
+
} else if (selectionStart <= 5) {
|
|
263
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
264
|
+
} else {
|
|
265
|
+
input.setSelectionRange(selectionStart, selectionStart)
|
|
266
|
+
}
|
|
267
|
+
}, 0)
|
|
268
|
+
}
|
|
269
|
+
|
|
106
270
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
107
271
|
const input = e.currentTarget
|
|
108
272
|
const selectionStart = input.selectionStart || 0
|
|
@@ -118,7 +282,120 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
118
282
|
|
|
119
283
|
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
120
284
|
e.preventDefault()
|
|
121
|
-
|
|
285
|
+
|
|
286
|
+
if (!isRange) {
|
|
287
|
+
// Single date mode
|
|
288
|
+
const newDate = new Date(selectedDate || new Date())
|
|
289
|
+
const increment = e.key === 'ArrowUp' ? 1 : -1
|
|
290
|
+
|
|
291
|
+
switch (selectedPart) {
|
|
292
|
+
case 'month':
|
|
293
|
+
newDate.setMonth(newDate.getMonth() + increment)
|
|
294
|
+
break
|
|
295
|
+
case 'day':
|
|
296
|
+
newDate.setDate(newDate.getDate() + increment)
|
|
297
|
+
break
|
|
298
|
+
case 'year':
|
|
299
|
+
newDate.setFullYear(newDate.getFullYear() + increment)
|
|
300
|
+
break
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
setSelectedDate(newDate)
|
|
304
|
+
setInputValue(formatDate(newDate))
|
|
305
|
+
if (onChange) {
|
|
306
|
+
onChange(newDate)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
switch (selectedPart) {
|
|
312
|
+
case 'month':
|
|
313
|
+
input.setSelectionRange(0, 2)
|
|
314
|
+
break
|
|
315
|
+
case 'day':
|
|
316
|
+
input.setSelectionRange(3, 5)
|
|
317
|
+
break
|
|
318
|
+
case 'year':
|
|
319
|
+
input.setSelectionRange(6, 10)
|
|
320
|
+
break
|
|
321
|
+
}
|
|
322
|
+
}, 0)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const handleStartDateKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
327
|
+
if (!isRange) return
|
|
328
|
+
|
|
329
|
+
const input = e.currentTarget
|
|
330
|
+
const selectionStart = input.selectionStart || 0
|
|
331
|
+
|
|
332
|
+
let selectedPart: 'month' | 'day' | 'year'
|
|
333
|
+
if (selectionStart <= 2) {
|
|
334
|
+
selectedPart = 'month'
|
|
335
|
+
} else if (selectionStart <= 5) {
|
|
336
|
+
selectedPart = 'day'
|
|
337
|
+
} else {
|
|
338
|
+
selectedPart = 'year'
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
342
|
+
e.preventDefault()
|
|
343
|
+
const newDate = new Date(dateRange.start || new Date())
|
|
344
|
+
const increment = e.key === 'ArrowUp' ? 1 : -1
|
|
345
|
+
|
|
346
|
+
switch (selectedPart) {
|
|
347
|
+
case 'month':
|
|
348
|
+
newDate.setMonth(newDate.getMonth() + increment)
|
|
349
|
+
break
|
|
350
|
+
case 'day':
|
|
351
|
+
newDate.setDate(newDate.getDate() + increment)
|
|
352
|
+
break
|
|
353
|
+
case 'year':
|
|
354
|
+
newDate.setFullYear(newDate.getFullYear() + increment)
|
|
355
|
+
break
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const newRange = { ...dateRange, start: newDate }
|
|
359
|
+
setDateRange(newRange)
|
|
360
|
+
setStartDateInputValue(formatDate(newDate))
|
|
361
|
+
if (onChange) {
|
|
362
|
+
onChange(newRange)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
switch (selectedPart) {
|
|
367
|
+
case 'month':
|
|
368
|
+
input.setSelectionRange(0, 2)
|
|
369
|
+
break
|
|
370
|
+
case 'day':
|
|
371
|
+
input.setSelectionRange(3, 5)
|
|
372
|
+
break
|
|
373
|
+
case 'year':
|
|
374
|
+
input.setSelectionRange(6, 10)
|
|
375
|
+
break
|
|
376
|
+
}
|
|
377
|
+
}, 0)
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const handleEndDateKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
382
|
+
if (!isRange) return
|
|
383
|
+
|
|
384
|
+
const input = e.currentTarget
|
|
385
|
+
const selectionStart = input.selectionStart || 0
|
|
386
|
+
|
|
387
|
+
let selectedPart: 'month' | 'day' | 'year'
|
|
388
|
+
if (selectionStart <= 2) {
|
|
389
|
+
selectedPart = 'month'
|
|
390
|
+
} else if (selectionStart <= 5) {
|
|
391
|
+
selectedPart = 'day'
|
|
392
|
+
} else {
|
|
393
|
+
selectedPart = 'year'
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
397
|
+
e.preventDefault()
|
|
398
|
+
const newDate = new Date(dateRange.end || new Date())
|
|
122
399
|
const increment = e.key === 'ArrowUp' ? 1 : -1
|
|
123
400
|
|
|
124
401
|
switch (selectedPart) {
|
|
@@ -133,10 +410,11 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
133
410
|
break
|
|
134
411
|
}
|
|
135
412
|
|
|
136
|
-
|
|
137
|
-
|
|
413
|
+
const newRange = { ...dateRange, end: newDate }
|
|
414
|
+
setDateRange(newRange)
|
|
415
|
+
setEndDateInputValue(formatDate(newDate))
|
|
138
416
|
if (onChange) {
|
|
139
|
-
onChange(
|
|
417
|
+
onChange(newRange)
|
|
140
418
|
}
|
|
141
419
|
|
|
142
420
|
setTimeout(() => {
|
|
@@ -170,7 +448,23 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
170
448
|
|
|
171
449
|
const handleIconClick = (e: React.MouseEvent) => {
|
|
172
450
|
e.stopPropagation()
|
|
173
|
-
|
|
451
|
+
if (!isRange) {
|
|
452
|
+
setIsOpen(true)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const handleStartIconClick = (e: React.MouseEvent) => {
|
|
457
|
+
e.stopPropagation()
|
|
458
|
+
if (isRange) {
|
|
459
|
+
setIsStartDateOpen(true)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const handleEndIconClick = (e: React.MouseEvent) => {
|
|
464
|
+
e.stopPropagation()
|
|
465
|
+
if (isRange) {
|
|
466
|
+
setIsEndDateOpen(true)
|
|
467
|
+
}
|
|
174
468
|
}
|
|
175
469
|
|
|
176
470
|
const calendarIcon = (
|
|
@@ -187,6 +481,94 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
187
481
|
/>
|
|
188
482
|
)
|
|
189
483
|
|
|
484
|
+
const startCalendarIcon = (
|
|
485
|
+
<CalendarTodayIcon
|
|
486
|
+
onClick={handleStartIconClick}
|
|
487
|
+
sx={{
|
|
488
|
+
cursor: 'pointer',
|
|
489
|
+
'&:hover': {
|
|
490
|
+
opacity: 0.8,
|
|
491
|
+
},
|
|
492
|
+
fontSize: '20px',
|
|
493
|
+
color: 'black',
|
|
494
|
+
}}
|
|
495
|
+
/>
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
const endCalendarIcon = (
|
|
499
|
+
<CalendarTodayIcon
|
|
500
|
+
onClick={handleEndIconClick}
|
|
501
|
+
sx={{
|
|
502
|
+
cursor: 'pointer',
|
|
503
|
+
'&:hover': {
|
|
504
|
+
opacity: 0.8,
|
|
505
|
+
},
|
|
506
|
+
fontSize: '20px',
|
|
507
|
+
color: 'black',
|
|
508
|
+
}}
|
|
509
|
+
/>
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
if (isRange) {
|
|
513
|
+
return (
|
|
514
|
+
<Box sx={{ display: 'flex', flexDirection: 'row', gap: 2 }}>
|
|
515
|
+
<Box sx={{ flex: 1 }}>
|
|
516
|
+
<TextField
|
|
517
|
+
label={startLabel}
|
|
518
|
+
value={startDateInputValue}
|
|
519
|
+
onChange={handleStartDateInputChange}
|
|
520
|
+
endAdornment={startCalendarIcon}
|
|
521
|
+
slotProps={{
|
|
522
|
+
input: {
|
|
523
|
+
readOnly: false,
|
|
524
|
+
style: { cursor: 'text', height: '40px' },
|
|
525
|
+
onKeyDown: handleStartDateKeyDown,
|
|
526
|
+
onClick: handleClick,
|
|
527
|
+
},
|
|
528
|
+
}}
|
|
529
|
+
{...rest}
|
|
530
|
+
/>
|
|
531
|
+
<DatePicker
|
|
532
|
+
selected={dateRange.start ?? undefined}
|
|
533
|
+
onChange={handleStartDateChange}
|
|
534
|
+
dateFormat="MM/dd/yyyy"
|
|
535
|
+
customInput={<CustomInput />}
|
|
536
|
+
open={isStartDateOpen}
|
|
537
|
+
onClickOutside={() => setIsStartDateOpen(false)}
|
|
538
|
+
shouldCloseOnSelect
|
|
539
|
+
/>
|
|
540
|
+
</Box>
|
|
541
|
+
<Box sx={{ flex: 1 }}>
|
|
542
|
+
<TextField
|
|
543
|
+
label={endLabel}
|
|
544
|
+
value={endDateInputValue}
|
|
545
|
+
onChange={handleEndDateInputChange}
|
|
546
|
+
endAdornment={endCalendarIcon}
|
|
547
|
+
slotProps={{
|
|
548
|
+
input: {
|
|
549
|
+
readOnly: false,
|
|
550
|
+
style: { cursor: 'text', height: '40px' },
|
|
551
|
+
onKeyDown: handleEndDateKeyDown,
|
|
552
|
+
onClick: handleClick,
|
|
553
|
+
},
|
|
554
|
+
}}
|
|
555
|
+
{...rest}
|
|
556
|
+
/>
|
|
557
|
+
<DatePicker
|
|
558
|
+
selected={dateRange.end ?? undefined}
|
|
559
|
+
onChange={handleEndDateChange}
|
|
560
|
+
dateFormat="MM/dd/yyyy"
|
|
561
|
+
customInput={<CustomInput />}
|
|
562
|
+
open={isEndDateOpen}
|
|
563
|
+
onClickOutside={() => setIsEndDateOpen(false)}
|
|
564
|
+
shouldCloseOnSelect
|
|
565
|
+
minDate={dateRange.start ?? undefined}
|
|
566
|
+
/>
|
|
567
|
+
</Box>
|
|
568
|
+
</Box>
|
|
569
|
+
)
|
|
570
|
+
}
|
|
571
|
+
|
|
190
572
|
return (
|
|
191
573
|
<>
|
|
192
574
|
<TextField
|
|
@@ -205,7 +587,7 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
205
587
|
{...rest}
|
|
206
588
|
/>
|
|
207
589
|
<DatePicker
|
|
208
|
-
selected={selectedDate}
|
|
590
|
+
selected={selectedDate ?? undefined}
|
|
209
591
|
onChange={handleChange}
|
|
210
592
|
dateFormat="MM/dd/yyyy"
|
|
211
593
|
customInput={<CustomInput />}
|