@blocklet/ui-react 2.12.12 → 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/Footer/links.js +2 -1
- package/lib/Header/index.js +2 -1
- 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/lib/blocklets.js +7 -9
- package/package.json +4 -4
- package/src/@types/index.ts +1 -0
- package/src/Footer/links.jsx +2 -1
- package/src/Header/index.tsx +7 -1
- 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
- package/src/blocklets.js +7 -9
|
@@ -2,7 +2,7 @@
|
|
|
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';
|
|
@@ -11,9 +11,10 @@ import { SvgIconProps } from '@mui/material/SvgIcon';
|
|
|
11
11
|
import { formatToDatetime } from '@arcblock/ux/lib/Util';
|
|
12
12
|
import type { UserMetadata } from '../../../@types';
|
|
13
13
|
import { DurationEnum, StatusEnum } from '../../../@types';
|
|
14
|
-
import
|
|
14
|
+
import StatusDialog from '../status-dialog';
|
|
15
15
|
import { translations } from '../../libs/locales';
|
|
16
16
|
import { getTimeRemaining, isWithinTimeRange } from './utils';
|
|
17
|
+
import { StatusItem } from '../status-selector/menu-item';
|
|
17
18
|
|
|
18
19
|
const MeetingIcon = lazy(() => import('@arcblock/icons/lib/Meeting'));
|
|
19
20
|
const CommunityIcon = lazy(() => import('@arcblock/icons/lib/Community'));
|
|
@@ -29,18 +30,43 @@ const StatusIconMap: Record<StatusEnum, React.FC<SvgIconProps> | undefined> = {
|
|
|
29
30
|
[StatusEnum.WorkingRemotely]: WorkingRemotelyIcon,
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
const QuickSettings = {
|
|
34
|
+
[StatusEnum.Meeting]: {
|
|
35
|
+
duration: DurationEnum.OneHour,
|
|
36
|
+
durationName: 'userStatus.duration.OneHour',
|
|
37
|
+
},
|
|
38
|
+
[StatusEnum.Community]: {
|
|
39
|
+
duration: DurationEnum.ThirtyMinutes,
|
|
40
|
+
durationName: 'userStatus.duration.ThirtyMinutes',
|
|
41
|
+
},
|
|
42
|
+
[StatusEnum.Holiday]: {
|
|
43
|
+
duration: DurationEnum.ThisWeek,
|
|
44
|
+
durationName: 'userStatus.duration.ThisWeek',
|
|
45
|
+
},
|
|
46
|
+
[StatusEnum.OffSick]: {
|
|
47
|
+
duration: DurationEnum.Today,
|
|
48
|
+
durationName: 'userStatus.duration.Today',
|
|
49
|
+
},
|
|
50
|
+
[StatusEnum.WorkingRemotely]: {
|
|
51
|
+
duration: DurationEnum.ThisWeek,
|
|
52
|
+
durationName: 'userStatus.duration.ThisWeek',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
32
56
|
export default function UserStatus({
|
|
33
57
|
isMobile,
|
|
34
58
|
size,
|
|
35
59
|
isMyself,
|
|
36
60
|
status,
|
|
37
61
|
onChange,
|
|
62
|
+
timezone,
|
|
38
63
|
}: {
|
|
39
64
|
isMobile?: boolean;
|
|
40
65
|
size: number;
|
|
41
66
|
isMyself: boolean;
|
|
42
67
|
status: UserMetadata['status'];
|
|
43
68
|
onChange: (v: UserMetadata['status']) => void;
|
|
69
|
+
timezone?: string;
|
|
44
70
|
}) {
|
|
45
71
|
const { locale } = useLocaleContext();
|
|
46
72
|
const t = useMemoizedFn((key, data = {}) => {
|
|
@@ -94,12 +120,17 @@ export default function UserStatus({
|
|
|
94
120
|
|
|
95
121
|
const statusData = useCreation(() => {
|
|
96
122
|
const durationData = getDurationData();
|
|
97
|
-
return Object.keys(StatusEnum).map((key) =>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
return Object.keys(StatusEnum).map((key) => {
|
|
124
|
+
const quickSetting = QuickSettings[StatusEnum[key as keyof typeof StatusEnum]];
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
id: StatusEnum[key as keyof typeof StatusEnum],
|
|
128
|
+
name: t(`userStatus.${key}`),
|
|
129
|
+
icon: StatusIconMap[StatusEnum[key as keyof typeof StatusEnum]],
|
|
130
|
+
...(quickSetting ? { duration: quickSetting.duration, durationName: t(quickSetting.durationName) } : {}),
|
|
131
|
+
children: durationData,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
103
134
|
}, [t, getDurationData]);
|
|
104
135
|
|
|
105
136
|
const onOpenStatusSelector = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
@@ -117,9 +148,7 @@ export default function UserStatus({
|
|
|
117
148
|
if (!isMyself) {
|
|
118
149
|
return;
|
|
119
150
|
}
|
|
120
|
-
|
|
121
|
-
onChange(v);
|
|
122
|
-
}
|
|
151
|
+
onChange(v);
|
|
123
152
|
onCloseStatusSelector();
|
|
124
153
|
};
|
|
125
154
|
|
|
@@ -148,10 +177,25 @@ export default function UserStatus({
|
|
|
148
177
|
alignItems="center"
|
|
149
178
|
justifyContent="center"
|
|
150
179
|
onClick={onOpenStatusSelector}>
|
|
151
|
-
{StatusIcon ?
|
|
180
|
+
{StatusIcon ? (
|
|
181
|
+
<Suspense fallback={null}>
|
|
182
|
+
<StatusIcon style={{ width: 16, height: 16 }} />
|
|
183
|
+
</Suspense>
|
|
184
|
+
) : (
|
|
185
|
+
<Badge color="success" variant="dot" />
|
|
186
|
+
)}
|
|
152
187
|
</Box>
|
|
153
188
|
</Tooltip>
|
|
154
|
-
|
|
189
|
+
{open && (
|
|
190
|
+
<StatusDialog
|
|
191
|
+
selected={status}
|
|
192
|
+
data={statusData as StatusItem[]}
|
|
193
|
+
open={open}
|
|
194
|
+
onSelect={onStatusChange}
|
|
195
|
+
onClose={onCloseStatusSelector}
|
|
196
|
+
timezone={timezone}
|
|
197
|
+
/>
|
|
198
|
+
)}
|
|
155
199
|
</StatusDiv>
|
|
156
200
|
);
|
|
157
201
|
}
|
|
@@ -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, UserMetadata } from '../../../@types';
|
|
4
5
|
|
|
5
6
|
const HOUR = 3600;
|
|
@@ -8,6 +9,9 @@ const MINUTES_10 = 600;
|
|
|
8
9
|
const MINUTES_5 = 300;
|
|
9
10
|
const MINUTES_1 = 60;
|
|
10
11
|
const SECOND = 1;
|
|
12
|
+
|
|
13
|
+
export const currentTimezone = moment.tz.guess();
|
|
14
|
+
|
|
11
15
|
export const getTimezones = () => {
|
|
12
16
|
const timezones = moment.tz.names();
|
|
13
17
|
|
|
@@ -46,7 +50,7 @@ export const isValidUrl = (url: string) => {
|
|
|
46
50
|
* @returns
|
|
47
51
|
*/
|
|
48
52
|
export const getStatusDuration = (status: UserMetadata['status']) => {
|
|
49
|
-
let dateRange: dayjs.Dayjs[] = [];
|
|
53
|
+
let dateRange: dayjs.Dayjs[] = status?.dateRange?.map((d) => dayjs(d)) ?? [];
|
|
50
54
|
const current = dayjs();
|
|
51
55
|
switch (status?.duration) {
|
|
52
56
|
case DurationEnum.ThirtyMinutes:
|
|
@@ -112,3 +116,27 @@ export const getTimeRemaining = (date: Date) => {
|
|
|
112
116
|
|
|
113
117
|
return 0; // 如果时间已过期,返回0
|
|
114
118
|
};
|
|
119
|
+
|
|
120
|
+
export const defaultButtonStyle = {
|
|
121
|
+
color: colors.foregroundsFgBase,
|
|
122
|
+
borderColor: colors.strokeBorderBase,
|
|
123
|
+
backgroundColor: colors.buttonsButtonNeutral,
|
|
124
|
+
'&:hover': {
|
|
125
|
+
borderColor: colors.strokeBorderBase,
|
|
126
|
+
backgroundColor: colors.buttonsButtonNeutralHover,
|
|
127
|
+
},
|
|
128
|
+
py: 0.5,
|
|
129
|
+
borderRadius: '8px',
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const primaryButtonStyle = {
|
|
133
|
+
color: colors.buttonsButtonNeutral,
|
|
134
|
+
borderColor: colors.foregroundsFgInteractive,
|
|
135
|
+
backgroundColor: colors.foregroundsFgInteractive,
|
|
136
|
+
'&:hover': {
|
|
137
|
+
borderColor: colors.foregroundsFgInteractive,
|
|
138
|
+
backgroundColor: colors.foregroundsFgInteractive,
|
|
139
|
+
},
|
|
140
|
+
py: 0.5,
|
|
141
|
+
borderRadius: '8px',
|
|
142
|
+
};
|
|
@@ -112,12 +112,14 @@ export const translations = {
|
|
|
112
112
|
FourHours: '4小时',
|
|
113
113
|
Today: '今天',
|
|
114
114
|
ThisWeek: '本周',
|
|
115
|
+
Custom: '自定义时间',
|
|
115
116
|
},
|
|
116
117
|
},
|
|
117
118
|
profile: {
|
|
118
119
|
addLink: '添加连接',
|
|
119
120
|
location: '位置',
|
|
120
121
|
timezone: '时区',
|
|
122
|
+
bio: '个人简介',
|
|
121
123
|
setStatus: '设置状态',
|
|
122
124
|
localTime: '当地时间:',
|
|
123
125
|
email: '邮箱地址',
|
|
@@ -125,8 +127,12 @@ export const translations = {
|
|
|
125
127
|
phone: '电话号码',
|
|
126
128
|
phoneInvalid: '电话号码格式不正确',
|
|
127
129
|
editProfile: '编辑资料',
|
|
128
|
-
removeStatusAfter: '
|
|
130
|
+
removeStatusAfter: '在...之后移除状态',
|
|
129
131
|
justForYou: '仅对您可见',
|
|
132
|
+
cleanStatus: '清除状态',
|
|
133
|
+
quickSettings: '快捷设置',
|
|
134
|
+
selectEndTime: '选择结束时间',
|
|
135
|
+
pleaseSelectTime: '请选择时间',
|
|
130
136
|
},
|
|
131
137
|
},
|
|
132
138
|
en: {
|
|
@@ -242,12 +248,14 @@ export const translations = {
|
|
|
242
248
|
FourHours: '4 hours',
|
|
243
249
|
Today: 'Today',
|
|
244
250
|
ThisWeek: 'This Week',
|
|
251
|
+
Custom: 'Custom',
|
|
245
252
|
},
|
|
246
253
|
},
|
|
247
254
|
profile: {
|
|
248
255
|
addLink: 'Add link',
|
|
249
256
|
location: 'Location',
|
|
250
257
|
timezone: 'Timezone',
|
|
258
|
+
bio: 'Bio',
|
|
251
259
|
setStatus: 'Set a Status',
|
|
252
260
|
localTime: 'Local Time: ',
|
|
253
261
|
email: 'Email',
|
|
@@ -255,9 +263,13 @@ export const translations = {
|
|
|
255
263
|
phone: 'Phone',
|
|
256
264
|
phoneInvalid: 'Phone number is invalid',
|
|
257
265
|
editProfile: 'Edit Profile',
|
|
258
|
-
removeStatusAfter: 'Remove status after',
|
|
266
|
+
removeStatusAfter: 'Remove status after...',
|
|
259
267
|
justForYou: 'Visible to you only',
|
|
260
268
|
maxInputLength: 'Max input length is',
|
|
269
|
+
selectEndTime: 'Select end time',
|
|
270
|
+
pleaseSelectTime: 'Please select time',
|
|
271
|
+
cleanStatus: 'Clean status',
|
|
272
|
+
quickSettings: 'Quick Settings',
|
|
261
273
|
},
|
|
262
274
|
},
|
|
263
275
|
};
|
package/src/blocklets.js
CHANGED
|
@@ -45,15 +45,12 @@ export const getLocalizedNavigation = (navigation, locale = 'en') => {
|
|
|
45
45
|
if (!navigation?.length) {
|
|
46
46
|
return navigation;
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return title;
|
|
48
|
+
const trans = (text, _locale) => {
|
|
49
|
+
if (text && typeof text === 'object') {
|
|
50
|
+
return text[_locale] || text?.en || text?.zh;
|
|
52
51
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
return title;
|
|
52
|
+
|
|
53
|
+
return text;
|
|
57
54
|
};
|
|
58
55
|
|
|
59
56
|
return mapRecursive(
|
|
@@ -61,7 +58,8 @@ export const getLocalizedNavigation = (navigation, locale = 'en') => {
|
|
|
61
58
|
(item) => {
|
|
62
59
|
return {
|
|
63
60
|
...item,
|
|
64
|
-
title:
|
|
61
|
+
title: trans(item.title, locale),
|
|
62
|
+
description: trans(item.description, locale),
|
|
65
63
|
// 仅对叶结点进行处理
|
|
66
64
|
link: !item.items?.length ? getLink(item.link, locale) : item.link,
|
|
67
65
|
_rawLink: item.link,
|