@blocklet/ui-react 2.12.13 → 2.12.14
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/lib/@types/index.d.ts +2 -1
- package/lib/@types/index.js +1 -0
- package/lib/UserCenter/components/editable-field.d.ts +2 -1
- package/lib/UserCenter/components/editable-field.js +5 -1
- package/lib/UserCenter/components/status-dialog/date-picker.d.ts +10 -0
- package/lib/UserCenter/components/status-dialog/date-picker.js +52 -0
- package/lib/UserCenter/components/status-dialog/index.d.ts +12 -0
- package/lib/UserCenter/components/status-dialog/index.js +238 -0
- package/lib/UserCenter/components/status-selector/menu-item.d.ts +2 -0
- package/lib/UserCenter/components/user-center.js +8 -3
- package/lib/UserCenter/components/user-info/clock.js +3 -2
- package/lib/UserCenter/components/user-info/metadata.js +15 -62
- package/lib/UserCenter/components/user-info/timezone-select.d.ts +8 -0
- package/lib/UserCenter/components/user-info/timezone-select.js +99 -0
- package/lib/UserCenter/components/user-info/user-basic-info.js +4 -14
- package/lib/UserCenter/components/user-info/user-status.d.ts +2 -1
- package/lib/UserCenter/components/user-info/user-status.js +49 -14
- package/lib/UserCenter/components/user-info/utils.d.ts +23 -0
- package/lib/UserCenter/components/user-info/utils.js +25 -1
- package/lib/UserCenter/libs/locales.d.ts +12 -0
- package/lib/UserCenter/libs/locales.js +18 -6
- package/package.json +4 -4
- package/src/@types/index.ts +1 -0
- package/src/UserCenter/components/editable-field.tsx +6 -0
- package/src/UserCenter/components/status-dialog/date-picker.tsx +67 -0
- package/src/UserCenter/components/status-dialog/index.tsx +280 -0
- package/src/UserCenter/components/status-selector/menu-item.tsx +2 -0
- package/src/UserCenter/components/user-center.tsx +7 -2
- package/src/UserCenter/components/user-info/clock.tsx +3 -2
- package/src/UserCenter/components/user-info/metadata.tsx +17 -70
- package/src/UserCenter/components/user-info/timezone-select.tsx +114 -0
- package/src/UserCenter/components/user-info/user-basic-info.tsx +4 -11
- package/src/UserCenter/components/user-info/user-status.tsx +57 -13
- package/src/UserCenter/components/user-info/utils.ts +29 -1
- package/src/UserCenter/libs/locales.ts +14 -2
|
@@ -12,7 +12,7 @@ import { temp as colors } from "@arcblock/ux/lib/Colors";
|
|
|
12
12
|
import { parseURL, joinURL } from "ufo";
|
|
13
13
|
import { translations } from "../../libs/locales.js";
|
|
14
14
|
import { formatAxiosError } from "../../libs/utils.js";
|
|
15
|
-
import { getStatusDuration, isValidUrl } from "./utils.js";
|
|
15
|
+
import { currentTimezone, getStatusDuration, isValidUrl } from "./utils.js";
|
|
16
16
|
import SwitchRole from "./switch-role.js";
|
|
17
17
|
import UserMetadataComponent from "./metadata.js";
|
|
18
18
|
import UserStatus from "./user-status.js";
|
|
@@ -49,7 +49,7 @@ export default function UserBasicInfo({
|
|
|
49
49
|
// @ts-ignore
|
|
50
50
|
metadata: {
|
|
51
51
|
...user?.metadata ?? { joinedAt: user?.createdAt, email: user?.email, phone: user?.phone },
|
|
52
|
-
status: v
|
|
52
|
+
status: v || {}
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
} catch (err) {
|
|
@@ -146,6 +146,7 @@ export default function UserBasicInfo({
|
|
|
146
146
|
isMobile,
|
|
147
147
|
size: rest.size || (isMobile ? 64 : 100),
|
|
148
148
|
isMyself,
|
|
149
|
+
timezone: user?.metadata?.timezone || currentTimezone,
|
|
149
150
|
status: userStatus,
|
|
150
151
|
onChange: onUpdateUserStatus
|
|
151
152
|
}
|
|
@@ -178,18 +179,7 @@ export default function UserBasicInfo({
|
|
|
178
179
|
]
|
|
179
180
|
}
|
|
180
181
|
),
|
|
181
|
-
/* @__PURE__ */ jsx(
|
|
182
|
-
DID,
|
|
183
|
-
{
|
|
184
|
-
did: user.did,
|
|
185
|
-
showQrcode: true,
|
|
186
|
-
copyable: true,
|
|
187
|
-
compact: !showFullDid,
|
|
188
|
-
responsive: !showFullDid,
|
|
189
|
-
locale,
|
|
190
|
-
style: { maxWidth: 260 }
|
|
191
|
-
}
|
|
192
|
-
)
|
|
182
|
+
/* @__PURE__ */ jsx(DID, { did: user.did, showQrcode: true, copyable: true, compact: !showFullDid, responsive: !showFullDid, locale })
|
|
193
183
|
]
|
|
194
184
|
}
|
|
195
185
|
)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { UserMetadata } from '../../../@types';
|
|
2
|
-
export default function UserStatus({ isMobile, size, isMyself, status, onChange, }: {
|
|
2
|
+
export default function UserStatus({ isMobile, size, isMyself, status, onChange, timezone, }: {
|
|
3
3
|
isMobile?: boolean;
|
|
4
4
|
size: number;
|
|
5
5
|
isMyself: boolean;
|
|
6
6
|
status: UserMetadata['status'];
|
|
7
7
|
onChange: (v: UserMetadata['status']) => void;
|
|
8
|
+
timezone?: string;
|
|
8
9
|
}): import("react").JSX.Element;
|
|
@@ -2,14 +2,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import Badge from "@mui/material/Badge";
|
|
3
3
|
import Box from "@mui/material/Box";
|
|
4
4
|
import styled from "@emotion/styled";
|
|
5
|
-
import { lazy, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
|
6
6
|
import { useCreation, useMemoizedFn, useInterval, useUnmount } from "ahooks";
|
|
7
7
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
8
8
|
import Tooltip from "@mui/material/Tooltip";
|
|
9
9
|
import { translate } from "@arcblock/ux/lib/Locale/util";
|
|
10
10
|
import { formatToDatetime } from "@arcblock/ux/lib/Util";
|
|
11
11
|
import { DurationEnum, StatusEnum } from "../../../@types/index.js";
|
|
12
|
-
import
|
|
12
|
+
import StatusDialog from "../status-dialog/index.js";
|
|
13
13
|
import { translations } from "../../libs/locales.js";
|
|
14
14
|
import { getTimeRemaining, isWithinTimeRange } from "./utils.js";
|
|
15
15
|
const MeetingIcon = lazy(() => import("@arcblock/icons/lib/Meeting"));
|
|
@@ -24,12 +24,35 @@ const StatusIconMap = {
|
|
|
24
24
|
[StatusEnum.OffSick]: OffSickIcon,
|
|
25
25
|
[StatusEnum.WorkingRemotely]: WorkingRemotelyIcon
|
|
26
26
|
};
|
|
27
|
+
const QuickSettings = {
|
|
28
|
+
[StatusEnum.Meeting]: {
|
|
29
|
+
duration: DurationEnum.OneHour,
|
|
30
|
+
durationName: "userStatus.duration.OneHour"
|
|
31
|
+
},
|
|
32
|
+
[StatusEnum.Community]: {
|
|
33
|
+
duration: DurationEnum.ThirtyMinutes,
|
|
34
|
+
durationName: "userStatus.duration.ThirtyMinutes"
|
|
35
|
+
},
|
|
36
|
+
[StatusEnum.Holiday]: {
|
|
37
|
+
duration: DurationEnum.ThisWeek,
|
|
38
|
+
durationName: "userStatus.duration.ThisWeek"
|
|
39
|
+
},
|
|
40
|
+
[StatusEnum.OffSick]: {
|
|
41
|
+
duration: DurationEnum.Today,
|
|
42
|
+
durationName: "userStatus.duration.Today"
|
|
43
|
+
},
|
|
44
|
+
[StatusEnum.WorkingRemotely]: {
|
|
45
|
+
duration: DurationEnum.ThisWeek,
|
|
46
|
+
durationName: "userStatus.duration.ThisWeek"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
27
49
|
export default function UserStatus({
|
|
28
50
|
isMobile,
|
|
29
51
|
size,
|
|
30
52
|
isMyself,
|
|
31
53
|
status,
|
|
32
|
-
onChange
|
|
54
|
+
onChange,
|
|
55
|
+
timezone
|
|
33
56
|
}) {
|
|
34
57
|
const { locale } = useLocaleContext();
|
|
35
58
|
const t = useMemoizedFn((key, data = {}) => {
|
|
@@ -74,12 +97,16 @@ export default function UserStatus({
|
|
|
74
97
|
}, [t]);
|
|
75
98
|
const statusData = useCreation(() => {
|
|
76
99
|
const durationData = getDurationData();
|
|
77
|
-
return Object.keys(StatusEnum).map((key) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
return Object.keys(StatusEnum).map((key) => {
|
|
101
|
+
const quickSetting = QuickSettings[StatusEnum[key]];
|
|
102
|
+
return {
|
|
103
|
+
id: StatusEnum[key],
|
|
104
|
+
name: t(`userStatus.${key}`),
|
|
105
|
+
icon: StatusIconMap[StatusEnum[key]],
|
|
106
|
+
...quickSetting ? { duration: quickSetting.duration, durationName: t(quickSetting.durationName) } : {},
|
|
107
|
+
children: durationData
|
|
108
|
+
};
|
|
109
|
+
});
|
|
83
110
|
}, [t, getDurationData]);
|
|
84
111
|
const onOpenStatusSelector = (event) => {
|
|
85
112
|
if (!isMyself) {
|
|
@@ -94,9 +121,7 @@ export default function UserStatus({
|
|
|
94
121
|
if (!isMyself) {
|
|
95
122
|
return;
|
|
96
123
|
}
|
|
97
|
-
|
|
98
|
-
onChange(v);
|
|
99
|
-
}
|
|
124
|
+
onChange(v);
|
|
100
125
|
onCloseStatusSelector();
|
|
101
126
|
};
|
|
102
127
|
const StatusIcon = StatusIconMap[status?.value];
|
|
@@ -121,10 +146,20 @@ export default function UserStatus({
|
|
|
121
146
|
alignItems: "center",
|
|
122
147
|
justifyContent: "center",
|
|
123
148
|
onClick: onOpenStatusSelector,
|
|
124
|
-
children: StatusIcon ? /* @__PURE__ */ jsx(StatusIcon, { style: { width: 16, height: 16 } }) : /* @__PURE__ */ jsx(Badge, { color: "success", variant: "dot" })
|
|
149
|
+
children: StatusIcon ? /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(StatusIcon, { style: { width: 16, height: 16 } }) }) : /* @__PURE__ */ jsx(Badge, { color: "success", variant: "dot" })
|
|
125
150
|
}
|
|
126
151
|
) }),
|
|
127
|
-
/* @__PURE__ */ jsx(
|
|
152
|
+
open && /* @__PURE__ */ jsx(
|
|
153
|
+
StatusDialog,
|
|
154
|
+
{
|
|
155
|
+
selected: status,
|
|
156
|
+
data: statusData,
|
|
157
|
+
open,
|
|
158
|
+
onSelect: onStatusChange,
|
|
159
|
+
onClose: onCloseStatusSelector,
|
|
160
|
+
timezone
|
|
161
|
+
}
|
|
162
|
+
)
|
|
128
163
|
] });
|
|
129
164
|
}
|
|
130
165
|
const StatusDiv = styled("div")`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UserMetadata } from '../../../@types';
|
|
2
|
+
export declare const currentTimezone: any;
|
|
2
3
|
export declare const getTimezones: () => any;
|
|
3
4
|
export declare const isValidUrl: (url: string) => boolean;
|
|
4
5
|
/**
|
|
@@ -17,3 +18,25 @@ export declare const isWithinTimeRange: (dateRange: [Date, Date]) => any;
|
|
|
17
18
|
* 获取当前时间距离结束时间还有多久
|
|
18
19
|
*/
|
|
19
20
|
export declare const getTimeRemaining: (date: Date) => number;
|
|
21
|
+
export declare const defaultButtonStyle: {
|
|
22
|
+
color: string;
|
|
23
|
+
borderColor: string;
|
|
24
|
+
backgroundColor: string;
|
|
25
|
+
'&:hover': {
|
|
26
|
+
borderColor: string;
|
|
27
|
+
backgroundColor: string;
|
|
28
|
+
};
|
|
29
|
+
py: number;
|
|
30
|
+
borderRadius: string;
|
|
31
|
+
};
|
|
32
|
+
export declare const primaryButtonStyle: {
|
|
33
|
+
color: string;
|
|
34
|
+
borderColor: string;
|
|
35
|
+
backgroundColor: string;
|
|
36
|
+
'&:hover': {
|
|
37
|
+
borderColor: string;
|
|
38
|
+
backgroundColor: string;
|
|
39
|
+
};
|
|
40
|
+
py: number;
|
|
41
|
+
borderRadius: string;
|
|
42
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import moment from "moment-timezone";
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
|
+
import { temp as colors } from "@arcblock/ux/lib/Colors";
|
|
3
4
|
import { DurationEnum } from "../../../@types/index.js";
|
|
4
5
|
const HOUR = 3600;
|
|
5
6
|
const MINUTES_30 = 1800;
|
|
@@ -7,6 +8,7 @@ const MINUTES_10 = 600;
|
|
|
7
8
|
const MINUTES_5 = 300;
|
|
8
9
|
const MINUTES_1 = 60;
|
|
9
10
|
const SECOND = 1;
|
|
11
|
+
export const currentTimezone = moment.tz.guess();
|
|
10
12
|
export const getTimezones = () => {
|
|
11
13
|
const timezones = moment.tz.names();
|
|
12
14
|
const formattedTimezones = timezones.map((tz) => {
|
|
@@ -32,7 +34,7 @@ export const isValidUrl = (url) => {
|
|
|
32
34
|
return urlPattern.test(url);
|
|
33
35
|
};
|
|
34
36
|
export const getStatusDuration = (status) => {
|
|
35
|
-
let dateRange = [];
|
|
37
|
+
let dateRange = status?.dateRange?.map((d) => dayjs(d)) ?? [];
|
|
36
38
|
const current = dayjs();
|
|
37
39
|
switch (status?.duration) {
|
|
38
40
|
case DurationEnum.ThirtyMinutes:
|
|
@@ -84,3 +86,25 @@ export const getTimeRemaining = (date) => {
|
|
|
84
86
|
}
|
|
85
87
|
return 0;
|
|
86
88
|
};
|
|
89
|
+
export const defaultButtonStyle = {
|
|
90
|
+
color: colors.foregroundsFgBase,
|
|
91
|
+
borderColor: colors.strokeBorderBase,
|
|
92
|
+
backgroundColor: colors.buttonsButtonNeutral,
|
|
93
|
+
"&:hover": {
|
|
94
|
+
borderColor: colors.strokeBorderBase,
|
|
95
|
+
backgroundColor: colors.buttonsButtonNeutralHover
|
|
96
|
+
},
|
|
97
|
+
py: 0.5,
|
|
98
|
+
borderRadius: "8px"
|
|
99
|
+
};
|
|
100
|
+
export const primaryButtonStyle = {
|
|
101
|
+
color: colors.buttonsButtonNeutral,
|
|
102
|
+
borderColor: colors.foregroundsFgInteractive,
|
|
103
|
+
backgroundColor: colors.foregroundsFgInteractive,
|
|
104
|
+
"&:hover": {
|
|
105
|
+
borderColor: colors.foregroundsFgInteractive,
|
|
106
|
+
backgroundColor: colors.foregroundsFgInteractive
|
|
107
|
+
},
|
|
108
|
+
py: 0.5,
|
|
109
|
+
borderRadius: "8px"
|
|
110
|
+
};
|
|
@@ -110,12 +110,14 @@ export declare const translations: {
|
|
|
110
110
|
FourHours: string;
|
|
111
111
|
Today: string;
|
|
112
112
|
ThisWeek: string;
|
|
113
|
+
Custom: string;
|
|
113
114
|
};
|
|
114
115
|
};
|
|
115
116
|
profile: {
|
|
116
117
|
addLink: string;
|
|
117
118
|
location: string;
|
|
118
119
|
timezone: string;
|
|
120
|
+
bio: string;
|
|
119
121
|
setStatus: string;
|
|
120
122
|
localTime: string;
|
|
121
123
|
email: string;
|
|
@@ -125,6 +127,10 @@ export declare const translations: {
|
|
|
125
127
|
editProfile: string;
|
|
126
128
|
removeStatusAfter: string;
|
|
127
129
|
justForYou: string;
|
|
130
|
+
cleanStatus: string;
|
|
131
|
+
quickSettings: string;
|
|
132
|
+
selectEndTime: string;
|
|
133
|
+
pleaseSelectTime: string;
|
|
128
134
|
};
|
|
129
135
|
};
|
|
130
136
|
en: {
|
|
@@ -238,12 +244,14 @@ export declare const translations: {
|
|
|
238
244
|
FourHours: string;
|
|
239
245
|
Today: string;
|
|
240
246
|
ThisWeek: string;
|
|
247
|
+
Custom: string;
|
|
241
248
|
};
|
|
242
249
|
};
|
|
243
250
|
profile: {
|
|
244
251
|
addLink: string;
|
|
245
252
|
location: string;
|
|
246
253
|
timezone: string;
|
|
254
|
+
bio: string;
|
|
247
255
|
setStatus: string;
|
|
248
256
|
localTime: string;
|
|
249
257
|
email: string;
|
|
@@ -254,6 +262,10 @@ export declare const translations: {
|
|
|
254
262
|
removeStatusAfter: string;
|
|
255
263
|
justForYou: string;
|
|
256
264
|
maxInputLength: string;
|
|
265
|
+
selectEndTime: string;
|
|
266
|
+
pleaseSelectTime: string;
|
|
267
|
+
cleanStatus: string;
|
|
268
|
+
quickSettings: string;
|
|
257
269
|
};
|
|
258
270
|
};
|
|
259
271
|
};
|
|
@@ -109,13 +109,15 @@ export const translations = {
|
|
|
109
109
|
OneHour: "1\u5C0F\u65F6",
|
|
110
110
|
FourHours: "4\u5C0F\u65F6",
|
|
111
111
|
Today: "\u4ECA\u5929",
|
|
112
|
-
ThisWeek: "\u672C\u5468"
|
|
112
|
+
ThisWeek: "\u672C\u5468",
|
|
113
|
+
Custom: "\u81EA\u5B9A\u4E49\u65F6\u95F4"
|
|
113
114
|
}
|
|
114
115
|
},
|
|
115
116
|
profile: {
|
|
116
117
|
addLink: "\u6DFB\u52A0\u8FDE\u63A5",
|
|
117
118
|
location: "\u4F4D\u7F6E",
|
|
118
119
|
timezone: "\u65F6\u533A",
|
|
120
|
+
bio: "\u4E2A\u4EBA\u7B80\u4ECB",
|
|
119
121
|
setStatus: "\u8BBE\u7F6E\u72B6\u6001",
|
|
120
122
|
localTime: "\u5F53\u5730\u65F6\u95F4:",
|
|
121
123
|
email: "\u90AE\u7BB1\u5730\u5740",
|
|
@@ -123,8 +125,12 @@ export const translations = {
|
|
|
123
125
|
phone: "\u7535\u8BDD\u53F7\u7801",
|
|
124
126
|
phoneInvalid: "\u7535\u8BDD\u53F7\u7801\u683C\u5F0F\u4E0D\u6B63\u786E",
|
|
125
127
|
editProfile: "\u7F16\u8F91\u8D44\u6599",
|
|
126
|
-
removeStatusAfter: "\u79FB\u9664\u72B6\u6001",
|
|
127
|
-
justForYou: "\u4EC5\u5BF9\u60A8\u53EF\u89C1"
|
|
128
|
+
removeStatusAfter: "\u5728...\u4E4B\u540E\u79FB\u9664\u72B6\u6001",
|
|
129
|
+
justForYou: "\u4EC5\u5BF9\u60A8\u53EF\u89C1",
|
|
130
|
+
cleanStatus: "\u6E05\u9664\u72B6\u6001",
|
|
131
|
+
quickSettings: "\u5FEB\u6377\u8BBE\u7F6E",
|
|
132
|
+
selectEndTime: "\u9009\u62E9\u7ED3\u675F\u65F6\u95F4",
|
|
133
|
+
pleaseSelectTime: "\u8BF7\u9009\u62E9\u65F6\u95F4"
|
|
128
134
|
}
|
|
129
135
|
},
|
|
130
136
|
en: {
|
|
@@ -237,13 +243,15 @@ export const translations = {
|
|
|
237
243
|
OneHour: "1 hour",
|
|
238
244
|
FourHours: "4 hours",
|
|
239
245
|
Today: "Today",
|
|
240
|
-
ThisWeek: "This Week"
|
|
246
|
+
ThisWeek: "This Week",
|
|
247
|
+
Custom: "Custom"
|
|
241
248
|
}
|
|
242
249
|
},
|
|
243
250
|
profile: {
|
|
244
251
|
addLink: "Add link",
|
|
245
252
|
location: "Location",
|
|
246
253
|
timezone: "Timezone",
|
|
254
|
+
bio: "Bio",
|
|
247
255
|
setStatus: "Set a Status",
|
|
248
256
|
localTime: "Local Time: ",
|
|
249
257
|
email: "Email",
|
|
@@ -251,9 +259,13 @@ export const translations = {
|
|
|
251
259
|
phone: "Phone",
|
|
252
260
|
phoneInvalid: "Phone number is invalid",
|
|
253
261
|
editProfile: "Edit Profile",
|
|
254
|
-
removeStatusAfter: "Remove status after",
|
|
262
|
+
removeStatusAfter: "Remove status after...",
|
|
255
263
|
justForYou: "Visible to you only",
|
|
256
|
-
maxInputLength: "Max input length is"
|
|
264
|
+
maxInputLength: "Max input length is",
|
|
265
|
+
selectEndTime: "Select end time",
|
|
266
|
+
pleaseSelectTime: "Please select time",
|
|
267
|
+
cleanStatus: "Clean status",
|
|
268
|
+
quickSettings: "Quick Settings"
|
|
257
269
|
}
|
|
258
270
|
}
|
|
259
271
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/ui-react",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.14",
|
|
4
4
|
"description": "Some useful front-end web components that can be used in Blocklets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@abtnode/constant": "^1.16.39",
|
|
36
|
-
"@arcblock/bridge": "^2.12.
|
|
37
|
-
"@arcblock/react-hooks": "^2.12.
|
|
36
|
+
"@arcblock/bridge": "^2.12.14",
|
|
37
|
+
"@arcblock/react-hooks": "^2.12.14",
|
|
38
38
|
"@arcblock/ws": "^1.19.15",
|
|
39
39
|
"@blocklet/did-space-react": "^1.0.26",
|
|
40
40
|
"@iconify-icons/logos": "^1.2.36",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"jest": "^29.7.0",
|
|
88
88
|
"unbuild": "^2.0.0"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "ac2b40cdc5ca3cf446e5a1ced41d5eada7860cbd"
|
|
91
91
|
}
|
package/src/@types/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ interface EditableFieldProps {
|
|
|
24
24
|
style?: React.CSSProperties;
|
|
25
25
|
verified?: boolean;
|
|
26
26
|
errorMsg?: string;
|
|
27
|
+
canEdit?: boolean;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const inputFieldStyle = {
|
|
@@ -63,6 +64,7 @@ function EditableField({
|
|
|
63
64
|
inline = true,
|
|
64
65
|
style = {},
|
|
65
66
|
verified = false,
|
|
67
|
+
canEdit = true,
|
|
66
68
|
}: EditableFieldProps) {
|
|
67
69
|
const { locale } = useLocaleContext();
|
|
68
70
|
const t = useMemoizedFn((key, data = {}) => {
|
|
@@ -131,6 +133,10 @@ function EditableField({
|
|
|
131
133
|
);
|
|
132
134
|
}, [value, handleChange, component, placeholder, rows, children]);
|
|
133
135
|
|
|
136
|
+
if (!canEdit && editable) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
134
140
|
if (!editable) {
|
|
135
141
|
return value ? (
|
|
136
142
|
<Tooltip title={tooltip} placement="top">
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { TextField, FormControl, FormHelperText } from '@mui/material';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import { useCreation } from 'ahooks';
|
|
5
|
+
|
|
6
|
+
interface DateTimeInputProps {
|
|
7
|
+
value: Date;
|
|
8
|
+
onChange: (value: Date) => void;
|
|
9
|
+
error?: boolean;
|
|
10
|
+
helperText?: string;
|
|
11
|
+
label?: string;
|
|
12
|
+
timezone?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function DateTimeInput({ value, onChange, error, helperText, label, timezone }: DateTimeInputProps) {
|
|
16
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
17
|
+
const minDateTime = dayjs().format('YYYY-MM-DDTHH:mm');
|
|
18
|
+
|
|
19
|
+
const formatValue = useCreation(() => {
|
|
20
|
+
let date = dayjs();
|
|
21
|
+
if (value) {
|
|
22
|
+
date = timezone ? dayjs(value).tz(timezone) : dayjs(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return date.format('YYYY-MM-DD HH:mm');
|
|
26
|
+
}, [value, timezone]);
|
|
27
|
+
|
|
28
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
29
|
+
onChange(new Date(e.target.value));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// 处理点击事件
|
|
33
|
+
const handleClick = () => {
|
|
34
|
+
// 通过编程方式触发原生日期选择器
|
|
35
|
+
inputRef.current?.showPicker();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<FormControl fullWidth error={error}>
|
|
40
|
+
<TextField
|
|
41
|
+
inputRef={inputRef}
|
|
42
|
+
type="datetime-local"
|
|
43
|
+
value={formatValue}
|
|
44
|
+
onChange={handleChange}
|
|
45
|
+
inputProps={{
|
|
46
|
+
min: minDateTime,
|
|
47
|
+
style: { cursor: 'pointer' },
|
|
48
|
+
}}
|
|
49
|
+
label={label}
|
|
50
|
+
error={error}
|
|
51
|
+
onClick={handleClick}
|
|
52
|
+
InputLabelProps={{
|
|
53
|
+
shrink: true,
|
|
54
|
+
}}
|
|
55
|
+
sx={{
|
|
56
|
+
'& .MuiInputBase-root': {
|
|
57
|
+
cursor: 'pointer',
|
|
58
|
+
},
|
|
59
|
+
'& .MuiOutlinedInput-notchedOutline': {
|
|
60
|
+
cursor: 'pointer',
|
|
61
|
+
},
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
{helperText && <FormHelperText>{helperText}</FormHelperText>}
|
|
65
|
+
</FormControl>
|
|
66
|
+
);
|
|
67
|
+
}
|