1
+ import { default as TimePicker } from "antd/es/time-picker" ;
1
2
import {
2
3
ColumnTypeCompBuilder ,
3
4
ColumnTypeViewFn ,
@@ -7,63 +8,126 @@ import { StringControl } from "comps/controls/codeControl";
7
8
import { withDefault } from "comps/generators" ;
8
9
import { formatPropertyView } from "comps/utils/propertyUtils" ;
9
10
import { trans } from "i18n" ;
10
- import {
11
- TIME_FORMAT ,
12
- formatTimestamp ,
13
- timestampToHumanReadable ,
14
- } from "util/dateTimeUtils" ;
15
- import { DateEdit } from "./columnDateComp" ;
16
- import { IconControl } from "comps/controls/iconControl" ;
17
- import { hasIcon } from "comps/utils" ;
11
+ import dayjs from "dayjs" ;
12
+ import { useEffect , useRef , useState } from "react" ;
13
+ import styled from "styled-components" ;
14
+ import { TIME_FORMAT } from "util/dateTimeUtils" ;
15
+
16
+ const TimePickerStyled = styled ( TimePicker ) < { $open : boolean } > `
17
+ width: 100%;
18
+ height: 100%;
19
+ position: absolute;
20
+ top: 0;
21
+ padding: 0;
22
+ padding-left: 11px;
23
+ .ant-picker-input {
24
+ height: 100%;
25
+ }
26
+ input {
27
+ padding-right: 18px;
28
+ cursor: pointer;
29
+ }
30
+ &.ant-picker-focused .ant-picker-suffix svg g {
31
+ stroke: ${ ( props ) => props . $open && "#315EFB" } ;
32
+ }
33
+ .ant-picker-suffix {
34
+ height: calc(100% - 1px);
35
+ position: absolute;
36
+ right: 0;
37
+ top: 0.5px;
38
+ display: flex;
39
+ align-items: center;
40
+ padding: 0 3px;
41
+ }
42
+ ` ;
43
+
44
+ const Wrapper = styled . div `
45
+ background: transparent !important;
46
+ ` ;
47
+
48
+ export function formatTime ( time : string , format : string ) {
49
+ const parsedTime = dayjs ( time , TIME_FORMAT ) ;
50
+ return parsedTime . isValid ( ) ? parsedTime . format ( format ) : "" ;
51
+ }
18
52
19
53
const childrenMap = {
20
54
text : StringControl ,
21
55
format : withDefault ( StringControl , TIME_FORMAT ) ,
22
56
inputFormat : withDefault ( StringControl , TIME_FORMAT ) ,
23
- prefixIcon : IconControl ,
24
- suffixIcon : IconControl ,
25
57
} ;
26
58
27
59
let inputFormat = TIME_FORMAT ;
28
60
29
- const getBaseValue : ColumnTypeViewFn < typeof childrenMap , string , string > = ( props ) =>
30
- props . text ;
61
+ const getBaseValue : ColumnTypeViewFn < typeof childrenMap , string , string > = ( props ) => props . text ;
62
+
63
+ type TimeEditProps = {
64
+ value : string ;
65
+ onChange : ( value : string ) => void ;
66
+ onChangeEnd : ( ) => void ;
67
+ inputFormat : string ;
68
+ } ;
69
+
70
+ export const TimeEdit = ( props : TimeEditProps ) => {
71
+ const pickerRef = useRef < any > ( ) ;
72
+ const [ panelOpen , setPanelOpen ] = useState ( true ) ;
73
+ let value = dayjs ( props . value , TIME_FORMAT ) ;
74
+ if ( ! value . isValid ( ) ) {
75
+ value = dayjs ( "00:00:00" , TIME_FORMAT ) ;
76
+ }
77
+
78
+ const [ tempValue , setTempValue ] = useState < dayjs . Dayjs | null > ( value ) ;
79
+
80
+ useEffect ( ( ) => {
81
+ const value = props . value ? dayjs ( props . value , TIME_FORMAT ) : null ;
82
+ setTempValue ( value ) ;
83
+ } , [ props . value ] ) ;
84
+
85
+ return (
86
+ < Wrapper
87
+ onKeyDown = { ( e ) => {
88
+ if ( e . key === "Enter" && ! panelOpen ) {
89
+ props . onChangeEnd ( ) ;
90
+ }
91
+ } }
92
+ onMouseDown = { ( e ) => {
93
+ e . stopPropagation ( ) ;
94
+ e . preventDefault ( ) ;
95
+ } }
96
+ >
97
+ < TimePickerStyled
98
+ ref = { pickerRef }
99
+ $open = { panelOpen }
100
+ format = { props . inputFormat }
101
+ allowClear = { true }
102
+ autoFocus
103
+ value = { tempValue }
104
+ defaultOpen = { true }
105
+ onOpenChange = { ( open ) => setPanelOpen ( open ) }
106
+ onChange = { ( value , timeString ) => {
107
+ props . onChange ( timeString as string ) ;
108
+ } }
109
+ onBlur = { ( ) => props . onChangeEnd ( ) }
110
+ />
111
+ </ Wrapper >
112
+ ) ;
113
+ } ;
31
114
32
115
export const TimeComp = ( function ( ) {
33
116
return new ColumnTypeCompBuilder (
34
117
childrenMap ,
35
118
( props , dispatch ) => {
36
119
inputFormat = props . inputFormat ;
37
120
const value = props . changeValue ?? getBaseValue ( props , dispatch ) ;
38
-
39
- // Convert value to a number if it's a valid timestamp
40
- const timestamp = Number ( value ) ;
41
- const formattedValue = ! isNaN ( timestamp )
42
- ? formatTimestamp ( timestamp )
43
- : timestampToHumanReadable ( timestamp ) ?? value ;
44
-
45
- return (
46
- < >
47
- { hasIcon ( props . prefixIcon ) && < span > { props . prefixIcon } </ span > }
48
- < span > { formattedValue } </ span >
49
- { hasIcon ( props . suffixIcon ) && < span > { props . suffixIcon } </ span > }
50
- </ >
51
- ) ;
52
- } ,
53
- ( nodeValue ) => {
54
- const timestamp = Number ( nodeValue . text . value ) ;
55
- return ! isNaN ( timestamp )
56
- ? timestampToHumanReadable ( timestamp )
57
- : nodeValue . text . value ;
121
+ return formatTime ( value , props . format ) ;
58
122
} ,
123
+ ( nodeValue ) => formatTime ( nodeValue . text . value , nodeValue . format . value ) ,
59
124
getBaseValue
60
125
)
61
126
. setEditViewFn ( ( props ) => (
62
- < DateEdit
127
+ < TimeEdit
63
128
value = { props . value }
64
129
onChange = { props . onChange }
65
130
onChangeEnd = { props . onChangeEnd }
66
- showTime = { true } // Ensures only time is shown
67
131
inputFormat = { inputFormat }
68
132
/>
69
133
) )
@@ -73,12 +137,6 @@ export const TimeComp = (function () {
73
137
label : trans ( "table.columnValue" ) ,
74
138
tooltip : ColumnValueTooltip ,
75
139
} ) }
76
- { children . prefixIcon . propertyView ( {
77
- label : trans ( "button.prefixIcon" ) ,
78
- } ) }
79
- { children . suffixIcon . propertyView ( {
80
- label : trans ( "button.suffixIcon" ) ,
81
- } ) }
82
140
{ formatPropertyView ( { children, placeholder : TIME_FORMAT } ) }
83
141
</ >
84
142
) )
0 commit comments