Skip to content

Commit 8a100b5

Browse files
committed
[Fix]: Address Issues in Time-Only Column Type Table Component (#1549)
1 parent 76a3b3e commit 8a100b5

File tree

1 file changed

+98
-40
lines changed
  • client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps

1 file changed

+98
-40
lines changed

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { default as TimePicker } from "antd/es/time-picker";
12
import {
23
ColumnTypeCompBuilder,
34
ColumnTypeViewFn,
@@ -7,63 +8,126 @@ import { StringControl } from "comps/controls/codeControl";
78
import { withDefault } from "comps/generators";
89
import { formatPropertyView } from "comps/utils/propertyUtils";
910
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+
}
1852

1953
const childrenMap = {
2054
text: StringControl,
2155
format: withDefault(StringControl, TIME_FORMAT),
2256
inputFormat: withDefault(StringControl, TIME_FORMAT),
23-
prefixIcon: IconControl,
24-
suffixIcon: IconControl,
2557
};
2658

2759
let inputFormat = TIME_FORMAT;
2860

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+
};
31114

32115
export const TimeComp = (function () {
33116
return new ColumnTypeCompBuilder(
34117
childrenMap,
35118
(props, dispatch) => {
36119
inputFormat = props.inputFormat;
37120
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);
58122
},
123+
(nodeValue) => formatTime(nodeValue.text.value, nodeValue.format.value),
59124
getBaseValue
60125
)
61126
.setEditViewFn((props) => (
62-
<DateEdit
127+
<TimeEdit
63128
value={props.value}
64129
onChange={props.onChange}
65130
onChangeEnd={props.onChangeEnd}
66-
showTime={true} // Ensures only time is shown
67131
inputFormat={inputFormat}
68132
/>
69133
))
@@ -73,12 +137,6 @@ export const TimeComp = (function () {
73137
label: trans("table.columnValue"),
74138
tooltip: ColumnValueTooltip,
75139
})}
76-
{children.prefixIcon.propertyView({
77-
label: trans("button.prefixIcon"),
78-
})}
79-
{children.suffixIcon.propertyView({
80-
label: trans("button.suffixIcon"),
81-
})}
82140
{formatPropertyView({ children, placeholder: TIME_FORMAT })}
83141
</>
84142
))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy