@blocklet/ui-react 3.1.36 → 3.1.38
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/UserCenter/components/user-info/link-preview-input.js +82 -86
- package/lib/UserCenter/components/user-info/user-basic-info.js +86 -85
- package/lib/UserCenter/components/user-info/utils.d.ts +1 -0
- package/lib/UserCenter/components/user-info/utils.js +49 -43
- package/lib/UserCenter/libs/locales.d.ts +2 -0
- package/lib/UserCenter/libs/locales.js +2 -0
- package/package.json +6 -6
- package/src/UserCenter/components/user-info/link-preview-input.tsx +40 -23
- package/src/UserCenter/components/user-info/user-basic-info.tsx +10 -2
- package/src/UserCenter/components/user-info/utils.ts +13 -0
- package/src/UserCenter/libs/locales.ts +2 -0
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
import { jsx as t, jsxs as
|
|
2
|
-
import { useState as
|
|
3
|
-
import { styled as
|
|
4
|
-
import { Remove as
|
|
5
|
-
import { translate as
|
|
6
|
-
import { useMemoizedFn as
|
|
7
|
-
import { useLocaleContext as
|
|
8
|
-
import
|
|
9
|
-
import { mergeSx as
|
|
10
|
-
import { withoutProtocol as
|
|
11
|
-
import { isValidUrl as
|
|
12
|
-
import { translations as
|
|
13
|
-
import { inputFieldStyle as
|
|
14
|
-
const
|
|
15
|
-
function
|
|
16
|
-
return
|
|
1
|
+
import { jsx as t, jsxs as f } from "react/jsx-runtime";
|
|
2
|
+
import { useState as C, useMemo as k } from "react";
|
|
3
|
+
import { styled as I, Box as p, Typography as y, IconButton as D, Button as U, useTheme as S, FormControl as F, TextField as B } from "@mui/material";
|
|
4
|
+
import { Remove as T, Add as _ } from "@mui/icons-material";
|
|
5
|
+
import { translate as z } from "@arcblock/ux/lib/Locale/util";
|
|
6
|
+
import { useMemoizedFn as E } from "ahooks";
|
|
7
|
+
import { useLocaleContext as M } from "@arcblock/ux/lib/Locale/context";
|
|
8
|
+
import R from "@arcblock/icons/lib/Link";
|
|
9
|
+
import { mergeSx as j } from "@arcblock/ux/lib/Util/style";
|
|
10
|
+
import { withoutProtocol as A } from "ufo";
|
|
11
|
+
import { isValidUrl as h, isDuplicateUrl as P } from "./utils.js";
|
|
12
|
+
import { translations as W } from "../../libs/locales.js";
|
|
13
|
+
import { inputFieldStyle as N, commonInputStyle as V } from "../editable-field.js";
|
|
14
|
+
const x = 10;
|
|
15
|
+
function K(e) {
|
|
16
|
+
return A(e);
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
function O({
|
|
19
19
|
value: e,
|
|
20
|
-
onChange:
|
|
21
|
-
errorMsg:
|
|
20
|
+
onChange: a,
|
|
21
|
+
errorMsg: s
|
|
22
22
|
}) {
|
|
23
|
-
return /* @__PURE__ */ t(
|
|
24
|
-
|
|
23
|
+
return /* @__PURE__ */ t(F, { fullWidth: !0, children: /* @__PURE__ */ t(
|
|
24
|
+
B,
|
|
25
25
|
{
|
|
26
26
|
variant: "outlined",
|
|
27
27
|
value: e,
|
|
28
|
-
onChange: (
|
|
29
|
-
const
|
|
30
|
-
|
|
28
|
+
onChange: (i) => {
|
|
29
|
+
const u = i.target.value;
|
|
30
|
+
a(u);
|
|
31
31
|
},
|
|
32
32
|
fullWidth: !0,
|
|
33
|
-
error: !!
|
|
34
|
-
helperText:
|
|
35
|
-
sx:
|
|
33
|
+
error: !!s,
|
|
34
|
+
helperText: s,
|
|
35
|
+
sx: j(N, s ? {} : V)
|
|
36
36
|
}
|
|
37
37
|
) });
|
|
38
38
|
}
|
|
39
|
-
function
|
|
40
|
-
const { locale:
|
|
41
|
-
const
|
|
42
|
-
return !
|
|
43
|
-
}, [
|
|
44
|
-
(e.length <
|
|
45
|
-
},
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
39
|
+
function X({ links: e = [], onChange: a }) {
|
|
40
|
+
const { locale: s } = M(), n = E((r, o = {}) => z(W, r, s, "en", o)), [i, u] = C([""]), g = k(() => {
|
|
41
|
+
const r = e[e.length - 1];
|
|
42
|
+
return !h(r) || i.length > 0 && i[i.length - 1];
|
|
43
|
+
}, [i, e]), L = () => {
|
|
44
|
+
(e.length < x || !g) && a([...e, ""]);
|
|
45
|
+
}, v = (r) => {
|
|
46
|
+
const o = e.filter((c, d) => d !== r), l = i.filter((c, d) => d !== r);
|
|
47
|
+
u(l), a(o);
|
|
48
|
+
}, b = (r, o) => {
|
|
49
|
+
const l = [...e];
|
|
50
|
+
l[r] = o;
|
|
51
|
+
const c = [...i], d = !!(o && !h(o));
|
|
52
|
+
c[r] = !1, d ? c[r] = d : l.filter((m, w) => m && h(m) && w !== r).some((m) => P(m, o)) && (c[r] = "duplicate"), u(c), a(l);
|
|
53
53
|
};
|
|
54
|
-
return /* @__PURE__ */
|
|
55
|
-
|
|
54
|
+
return /* @__PURE__ */ f(
|
|
55
|
+
p,
|
|
56
56
|
{
|
|
57
57
|
sx: {
|
|
58
58
|
width: "100%"
|
|
59
59
|
},
|
|
60
60
|
children: [
|
|
61
61
|
/* @__PURE__ */ t(
|
|
62
|
-
|
|
62
|
+
p,
|
|
63
63
|
{
|
|
64
64
|
sx: {
|
|
65
65
|
display: "flex",
|
|
@@ -67,38 +67,34 @@ function V({ links: e = [], onChange: i }) {
|
|
|
67
67
|
alignItems: "center",
|
|
68
68
|
gap: 1
|
|
69
69
|
},
|
|
70
|
-
children: /* @__PURE__ */ t(
|
|
70
|
+
children: /* @__PURE__ */ t(y, { variant: "subtitle1", gutterBottom: !0, sx: { mb: 0, fontSize: "12px", color: "text.primary" }, children: n("profile.socialMedia") })
|
|
71
71
|
}
|
|
72
72
|
),
|
|
73
|
-
e.map((
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
e.map((r, o) => {
|
|
74
|
+
let l = "";
|
|
75
|
+
return i[o] === "duplicate" ? l = n("profile.duplicateURL") : i[o] === !0 ? l = n("profile.invalidURL") : l = "", /* @__PURE__ */ f(
|
|
76
|
+
p,
|
|
77
|
+
{
|
|
78
|
+
sx: {
|
|
79
|
+
display: "flex",
|
|
80
|
+
alignItems: "flex-start",
|
|
81
|
+
mb: 1
|
|
82
|
+
},
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ t(O, { value: r, onChange: (c) => b(o, c), errorMsg: l }),
|
|
85
|
+
/* @__PURE__ */ t(D, { onClick: () => v(o), children: /* @__PURE__ */ t(T, { sx: { color: "text.secondary" } }) })
|
|
86
|
+
]
|
|
80
87
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
onChange: (s) => v(r, s),
|
|
87
|
-
errorMsg: a[r] ? n("profile.invalidURL") : ""
|
|
88
|
-
}
|
|
89
|
-
),
|
|
90
|
-
/* @__PURE__ */ t(I, { onClick: () => b(r), children: /* @__PURE__ */ t(B, { sx: { color: "text.secondary" } }) })
|
|
91
|
-
]
|
|
92
|
-
},
|
|
93
|
-
r
|
|
94
|
-
)),
|
|
95
|
-
e.length < h ? /* @__PURE__ */ p(
|
|
96
|
-
k,
|
|
88
|
+
o
|
|
89
|
+
);
|
|
90
|
+
}),
|
|
91
|
+
e.length < x ? /* @__PURE__ */ f(
|
|
92
|
+
U,
|
|
97
93
|
{
|
|
98
94
|
fullWidth: !0,
|
|
99
95
|
variant: "outlined",
|
|
100
|
-
disabled:
|
|
101
|
-
onClick:
|
|
96
|
+
disabled: !!g,
|
|
97
|
+
onClick: L,
|
|
102
98
|
size: "small",
|
|
103
99
|
sx: {
|
|
104
100
|
height: "40px",
|
|
@@ -114,27 +110,27 @@ function V({ links: e = [], onChange: i }) {
|
|
|
114
110
|
}
|
|
115
111
|
},
|
|
116
112
|
children: [
|
|
117
|
-
/* @__PURE__ */ t(
|
|
113
|
+
/* @__PURE__ */ t(_, {}),
|
|
118
114
|
" ",
|
|
119
115
|
/* @__PURE__ */ t("span", { children: n("profile.addLink") })
|
|
120
116
|
]
|
|
121
117
|
}
|
|
122
|
-
) : /* @__PURE__ */ t(
|
|
118
|
+
) : /* @__PURE__ */ t(y, { variant: "subtitle1", gutterBottom: !0, sx: { mb: 0, fontSize: "12px", color: "text.secondary" }, children: n("profile.maxLinkCount", { count: x }) })
|
|
123
119
|
]
|
|
124
120
|
}
|
|
125
121
|
);
|
|
126
122
|
}
|
|
127
|
-
function
|
|
128
|
-
const
|
|
129
|
-
return e ? /* @__PURE__ */ t(
|
|
123
|
+
function $({ link: e }) {
|
|
124
|
+
const s = S().palette.mode === "dark";
|
|
125
|
+
return e ? /* @__PURE__ */ t(R, { width: 20, height: 20, style: { filter: s ? "brightness(0) saturate(100%) invert(1)" : "none" } }) : null;
|
|
130
126
|
}
|
|
131
|
-
function
|
|
127
|
+
function ce({
|
|
132
128
|
editable: e = !1,
|
|
133
|
-
links:
|
|
134
|
-
onChange:
|
|
129
|
+
links: a = [],
|
|
130
|
+
onChange: s
|
|
135
131
|
}) {
|
|
136
|
-
return e ? /* @__PURE__ */ t(
|
|
137
|
-
|
|
132
|
+
return e ? /* @__PURE__ */ t(X, { links: a, onChange: s }) : /* @__PURE__ */ t(
|
|
133
|
+
p,
|
|
138
134
|
{
|
|
139
135
|
sx: {
|
|
140
136
|
width: "100%",
|
|
@@ -142,8 +138,8 @@ function ne({
|
|
|
142
138
|
flexDirection: "column",
|
|
143
139
|
gap: 2
|
|
144
140
|
},
|
|
145
|
-
children:
|
|
146
|
-
|
|
141
|
+
children: a.map((n) => /* @__PURE__ */ f(
|
|
142
|
+
p,
|
|
147
143
|
{
|
|
148
144
|
sx: {
|
|
149
145
|
display: "flex",
|
|
@@ -153,8 +149,8 @@ function ne({
|
|
|
153
149
|
width: "100%"
|
|
154
150
|
},
|
|
155
151
|
children: [
|
|
156
|
-
/* @__PURE__ */ t(
|
|
157
|
-
/* @__PURE__ */ t(
|
|
152
|
+
/* @__PURE__ */ t($, { link: n }),
|
|
153
|
+
/* @__PURE__ */ t(q, { children: /* @__PURE__ */ t(p, { component: "a", href: n, style: { textDecoration: "none" }, target: "_blank", rel: "noopener noreferrer", children: K(n) }) })
|
|
158
154
|
]
|
|
159
155
|
},
|
|
160
156
|
n
|
|
@@ -162,7 +158,7 @@ function ne({
|
|
|
162
158
|
}
|
|
163
159
|
);
|
|
164
160
|
}
|
|
165
|
-
const
|
|
161
|
+
const q = I("span")`
|
|
166
162
|
flex: 1;
|
|
167
163
|
white-space: nowrap;
|
|
168
164
|
overflow: hidden;
|
|
@@ -181,5 +177,5 @@ const O = C("span")`
|
|
|
181
177
|
}
|
|
182
178
|
`;
|
|
183
179
|
export {
|
|
184
|
-
|
|
180
|
+
ce as LinkPreviewInput
|
|
185
181
|
};
|
|
@@ -1,84 +1,85 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { Box as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { useMemoizedFn as
|
|
6
|
-
import { translate as
|
|
7
|
-
import { useLocaleContext as
|
|
8
|
-
import
|
|
9
|
-
import { useState as
|
|
10
|
-
import
|
|
11
|
-
import { parseURL as
|
|
12
|
-
import { KeyboardArrowUp as
|
|
13
|
-
import { translations as
|
|
14
|
-
import { formatAxiosError as
|
|
15
|
-
import { currentTimezone as
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import { client as
|
|
21
|
-
import
|
|
22
|
-
function
|
|
1
|
+
import { jsxs as l, jsx as r, Fragment as T } from "react/jsx-runtime";
|
|
2
|
+
import { Box as c, Typography as y, Divider as F, IconButton as K, Collapse as W } from "@mui/material";
|
|
3
|
+
import O from "@arcblock/ux/lib/Avatar";
|
|
4
|
+
import Q from "@arcblock/ux/lib/DID";
|
|
5
|
+
import { useMemoizedFn as V } from "ahooks";
|
|
6
|
+
import { translate as Y } from "@arcblock/ux/lib/Locale/util";
|
|
7
|
+
import { useLocaleContext as $ } from "@arcblock/ux/lib/Locale/context";
|
|
8
|
+
import q from "lodash/noop";
|
|
9
|
+
import { useState as C, useEffect as z } from "react";
|
|
10
|
+
import j from "@arcblock/ux/lib/Toast";
|
|
11
|
+
import { parseURL as G, joinURL as H } from "ufo";
|
|
12
|
+
import { KeyboardArrowUp as J, KeyboardArrowDown as X } from "@mui/icons-material";
|
|
13
|
+
import { translations as Z } from "../../libs/locales.js";
|
|
14
|
+
import { formatAxiosError as I } from "../../libs/utils.js";
|
|
15
|
+
import { currentTimezone as _, getStatusDuration as P, isValidUrl as M, isDuplicateUrl as tt } from "./utils.js";
|
|
16
|
+
import rt from "./switch-role.js";
|
|
17
|
+
import et from "./metadata.js";
|
|
18
|
+
import ot from "./user-status.js";
|
|
19
|
+
import at from "./user-info.js";
|
|
20
|
+
import { client as R } from "../../../libs/client.js";
|
|
21
|
+
import nt from "./social-actions/index.js";
|
|
22
|
+
function Rt({
|
|
23
23
|
user: t,
|
|
24
|
-
isMyself:
|
|
24
|
+
isMyself: o = !0,
|
|
25
25
|
showFullDid: f = !0,
|
|
26
|
-
switchPassport:
|
|
27
|
-
switchProfile:
|
|
26
|
+
switchPassport: A,
|
|
27
|
+
switchProfile: L,
|
|
28
28
|
isMobile: a = !1,
|
|
29
29
|
onlyProfile: s = !1,
|
|
30
30
|
refreshProfile: u,
|
|
31
|
-
isShowSocialActions:
|
|
31
|
+
isShowSocialActions: k = !1,
|
|
32
32
|
...m
|
|
33
33
|
}) {
|
|
34
|
-
const { locale:
|
|
35
|
-
|
|
34
|
+
const { locale: h } = $(), [x, g] = C(void 0), v = V((i, e = {}) => Y(Z, i, h, "en", e)), [d, w] = C(!a || s);
|
|
35
|
+
z(() => {
|
|
36
36
|
g(t?.metadata?.status);
|
|
37
|
-
}, [t]),
|
|
38
|
-
|
|
37
|
+
}, [t]), z(() => {
|
|
38
|
+
w(!a || s);
|
|
39
39
|
}, [a, s]);
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
40
|
+
const D = async (i) => {
|
|
41
|
+
if (o)
|
|
42
42
|
try {
|
|
43
|
-
if (
|
|
44
|
-
const
|
|
45
|
-
|
|
43
|
+
if (i) {
|
|
44
|
+
const e = P(i);
|
|
45
|
+
i.dateRange = e.length > 0 ? e : x?.dateRange ?? [];
|
|
46
46
|
}
|
|
47
|
-
g(
|
|
47
|
+
g(i), await R.user.saveProfile({
|
|
48
48
|
// @ts-ignore
|
|
49
49
|
metadata: {
|
|
50
50
|
...t?.metadata ?? { joinedAt: t?.createdAt, email: t?.email, phone: t?.phone },
|
|
51
|
-
status:
|
|
51
|
+
status: i || {}
|
|
52
52
|
}
|
|
53
53
|
}), u();
|
|
54
|
-
} catch (
|
|
55
|
-
console.error(
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.error(e), j.error(I(e));
|
|
56
56
|
}
|
|
57
|
-
},
|
|
58
|
-
|
|
57
|
+
}, b = () => {
|
|
58
|
+
w(!d);
|
|
59
59
|
};
|
|
60
60
|
if (!t)
|
|
61
61
|
return null;
|
|
62
|
-
const
|
|
63
|
-
if (!
|
|
62
|
+
const E = async (i) => {
|
|
63
|
+
if (!o)
|
|
64
64
|
return;
|
|
65
|
-
const { metadata:
|
|
65
|
+
const { metadata: e, address: B } = i;
|
|
66
66
|
try {
|
|
67
|
-
const p =
|
|
68
|
-
if (!
|
|
67
|
+
const p = e?.links?.map((n, S) => {
|
|
68
|
+
if (!n.url || !M(n.url) || S > 0 && e.links?.slice(0, S)?.some((N) => tt(N.url, n.url)))
|
|
69
|
+
return null;
|
|
69
70
|
try {
|
|
70
|
-
return
|
|
71
|
+
return G(n.url).protocol || (n.url = H("https://", n.url)), n;
|
|
71
72
|
} catch {
|
|
72
|
-
return console.error("Invalid URL:",
|
|
73
|
+
return console.error("Invalid URL:", n.url), null;
|
|
73
74
|
}
|
|
74
|
-
}).filter((
|
|
75
|
-
|
|
75
|
+
}).filter((n) => !!n) || [];
|
|
76
|
+
e.links = p, await R.user.saveProfile({ metadata: e, address: B }), u();
|
|
76
77
|
} catch (p) {
|
|
77
|
-
console.error(p),
|
|
78
|
+
console.error(p), j.error(I(p));
|
|
78
79
|
}
|
|
79
80
|
};
|
|
80
|
-
return /* @__PURE__ */
|
|
81
|
-
|
|
81
|
+
return /* @__PURE__ */ l(
|
|
82
|
+
c,
|
|
82
83
|
{
|
|
83
84
|
...m,
|
|
84
85
|
sx: {
|
|
@@ -86,8 +87,8 @@ function zt({
|
|
|
86
87
|
...m.sx ?? {}
|
|
87
88
|
},
|
|
88
89
|
children: [
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
-
|
|
90
|
+
/* @__PURE__ */ l(
|
|
91
|
+
c,
|
|
91
92
|
{
|
|
92
93
|
className: "user-info",
|
|
93
94
|
sx: {
|
|
@@ -96,8 +97,8 @@ function zt({
|
|
|
96
97
|
gap: 2
|
|
97
98
|
},
|
|
98
99
|
children: [
|
|
99
|
-
/* @__PURE__ */
|
|
100
|
-
|
|
100
|
+
/* @__PURE__ */ l(
|
|
101
|
+
c,
|
|
101
102
|
{
|
|
102
103
|
className: "user-avatar",
|
|
103
104
|
sx: {
|
|
@@ -108,7 +109,7 @@ function zt({
|
|
|
108
109
|
},
|
|
109
110
|
children: [
|
|
110
111
|
/* @__PURE__ */ r(
|
|
111
|
-
|
|
112
|
+
O,
|
|
112
113
|
{
|
|
113
114
|
src: t?.avatar,
|
|
114
115
|
did: t?.did,
|
|
@@ -121,10 +122,10 @@ function zt({
|
|
|
121
122
|
position: "relative",
|
|
122
123
|
overflow: "hidden",
|
|
123
124
|
flexShrink: 0,
|
|
124
|
-
...
|
|
125
|
+
...o ? {
|
|
125
126
|
cursor: "pointer",
|
|
126
127
|
"&::after": {
|
|
127
|
-
content: `"${
|
|
128
|
+
content: `"${v("switchProfile")}"`,
|
|
128
129
|
color: "white",
|
|
129
130
|
position: "absolute",
|
|
130
131
|
fontSize: "12px",
|
|
@@ -139,33 +140,33 @@ function zt({
|
|
|
139
140
|
}
|
|
140
141
|
} : {}
|
|
141
142
|
},
|
|
142
|
-
onClick:
|
|
143
|
+
onClick: o ? L : q
|
|
143
144
|
}
|
|
144
145
|
),
|
|
145
146
|
/* @__PURE__ */ r(
|
|
146
|
-
|
|
147
|
+
ot,
|
|
147
148
|
{
|
|
148
149
|
isMobile: a,
|
|
149
150
|
size: m.size || (a ? 64 : 100),
|
|
150
|
-
isMyself:
|
|
151
|
-
timezone: t?.metadata?.timezone ||
|
|
152
|
-
status:
|
|
153
|
-
onChange:
|
|
151
|
+
isMyself: o,
|
|
152
|
+
timezone: t?.metadata?.timezone || _,
|
|
153
|
+
status: x,
|
|
154
|
+
onChange: D
|
|
154
155
|
}
|
|
155
156
|
)
|
|
156
157
|
]
|
|
157
158
|
}
|
|
158
159
|
),
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
|
|
160
|
+
/* @__PURE__ */ l(
|
|
161
|
+
c,
|
|
161
162
|
{
|
|
162
163
|
sx: {
|
|
163
164
|
flex: 1,
|
|
164
165
|
overflow: "hidden"
|
|
165
166
|
},
|
|
166
167
|
children: [
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
|
|
168
|
+
/* @__PURE__ */ l(
|
|
169
|
+
y,
|
|
169
170
|
{
|
|
170
171
|
variant: "h6",
|
|
171
172
|
component: "div",
|
|
@@ -190,23 +191,23 @@ function zt({
|
|
|
190
191
|
children: t?.fullName
|
|
191
192
|
}
|
|
192
193
|
),
|
|
193
|
-
|
|
194
|
+
o ? /* @__PURE__ */ r(rt, { user: t, switchPassport: A }) : null
|
|
194
195
|
]
|
|
195
196
|
}
|
|
196
197
|
),
|
|
197
|
-
/* @__PURE__ */ r(
|
|
198
|
+
/* @__PURE__ */ r(Q, { did: t.did, showQrcode: !0, copyable: !0, compact: !f, responsive: !f, locale: h })
|
|
198
199
|
]
|
|
199
200
|
}
|
|
200
201
|
)
|
|
201
202
|
]
|
|
202
203
|
}
|
|
203
204
|
),
|
|
204
|
-
!
|
|
205
|
-
/* @__PURE__ */ r(
|
|
206
|
-
|
|
207
|
-
/* @__PURE__ */ r(
|
|
205
|
+
!o && k ? /* @__PURE__ */ r(c, { sx: { mt: 2 }, children: /* @__PURE__ */ r(nt, { user: t }) }) : null,
|
|
206
|
+
/* @__PURE__ */ r(et, { isMobile: a, isMyself: o, user: t, onSave: E }),
|
|
207
|
+
o ? /* @__PURE__ */ l(T, { children: [
|
|
208
|
+
/* @__PURE__ */ r(F, { sx: { my: a ? 1 : 3 } }),
|
|
208
209
|
a && !s ? /* @__PURE__ */ r(
|
|
209
|
-
|
|
210
|
+
c,
|
|
210
211
|
{
|
|
211
212
|
sx: {
|
|
212
213
|
display: "flex",
|
|
@@ -214,10 +215,10 @@ function zt({
|
|
|
214
215
|
mb: 0
|
|
215
216
|
},
|
|
216
217
|
children: /* @__PURE__ */ r(
|
|
217
|
-
|
|
218
|
+
K,
|
|
218
219
|
{
|
|
219
220
|
size: "small",
|
|
220
|
-
onClick:
|
|
221
|
+
onClick: b,
|
|
221
222
|
sx: {
|
|
222
223
|
backgroundColor: "grey.50",
|
|
223
224
|
"&:hover": {
|
|
@@ -225,14 +226,14 @@ function zt({
|
|
|
225
226
|
opacity: 0.8
|
|
226
227
|
}
|
|
227
228
|
},
|
|
228
|
-
children: d ? /* @__PURE__ */ r(
|
|
229
|
+
children: d ? /* @__PURE__ */ r(J, {}) : /* @__PURE__ */ r(X, {})
|
|
229
230
|
}
|
|
230
231
|
)
|
|
231
232
|
}
|
|
232
233
|
) : null,
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
+
/* @__PURE__ */ l(W, { in: d, timeout: "auto", children: [
|
|
234
235
|
/* @__PURE__ */ r(
|
|
235
|
-
|
|
236
|
+
y,
|
|
236
237
|
{
|
|
237
238
|
component: "p",
|
|
238
239
|
sx: {
|
|
@@ -240,10 +241,10 @@ function zt({
|
|
|
240
241
|
fontSize: "14px",
|
|
241
242
|
mb: 2
|
|
242
243
|
},
|
|
243
|
-
children:
|
|
244
|
+
children: v("profile.justForYou")
|
|
244
245
|
}
|
|
245
246
|
),
|
|
246
|
-
/* @__PURE__ */ r(
|
|
247
|
+
/* @__PURE__ */ r(at, { user: t, isMySelf: o })
|
|
247
248
|
] })
|
|
248
249
|
] }) : null
|
|
249
250
|
]
|
|
@@ -251,5 +252,5 @@ function zt({
|
|
|
251
252
|
);
|
|
252
253
|
}
|
|
253
254
|
export {
|
|
254
|
-
|
|
255
|
+
Rt as default
|
|
255
256
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { withHttps as
|
|
1
|
+
import h from "is-url";
|
|
2
|
+
import { withHttps as c } from "ufo";
|
|
3
3
|
import n from "dayjs";
|
|
4
|
-
import
|
|
4
|
+
import C from "dayjs/plugin/timezone";
|
|
5
5
|
import k from "dayjs/plugin/utc";
|
|
6
|
-
import { DurationEnum as
|
|
6
|
+
import { DurationEnum as s } from "../../../@types/index.js";
|
|
7
7
|
n.extend(k);
|
|
8
|
-
n.extend(
|
|
9
|
-
const
|
|
8
|
+
n.extend(C);
|
|
9
|
+
const l = 3600, m = 1800, d = 600, f = 300, p = 60, b = 1, _ = n.tz.guess(), y = [
|
|
10
10
|
"America/New_York",
|
|
11
11
|
"America/Chicago",
|
|
12
12
|
"America/Denver",
|
|
@@ -28,7 +28,7 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, v = n.tz.guess(), b =
|
|
|
28
28
|
"America/Mexico_City",
|
|
29
29
|
"Africa/Cairo",
|
|
30
30
|
"UTC"
|
|
31
|
-
],
|
|
31
|
+
], O = () => {
|
|
32
32
|
if (typeof Intl < "u" && Intl.supportedValuesOf)
|
|
33
33
|
try {
|
|
34
34
|
return Intl.supportedValuesOf("timeZone");
|
|
@@ -38,58 +38,63 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, v = n.tz.guess(), b =
|
|
|
38
38
|
if (typeof Intl < "u" && Intl.DateTimeFormat)
|
|
39
39
|
try {
|
|
40
40
|
if (new Intl.DateTimeFormat("en", { timeZone: "UTC" }).resolvedOptions().timeZone)
|
|
41
|
-
return
|
|
41
|
+
return y;
|
|
42
42
|
} catch {
|
|
43
43
|
console.warn("Intl.DateTimeFormat timezone support limited");
|
|
44
44
|
}
|
|
45
|
-
return
|
|
46
|
-
},
|
|
45
|
+
return y;
|
|
46
|
+
}, v = () => O().map((e) => {
|
|
47
47
|
try {
|
|
48
|
-
const
|
|
49
|
-
return { label: `GMT${a >= 0 ? "+" : ""}${a}:${
|
|
48
|
+
const t = n.tz(n(), e).utcOffset() / 60, a = Math.floor(t), i = t % 1 * 60;
|
|
49
|
+
return { label: `GMT${a >= 0 ? "+" : ""}${a}:${i === 30 ? "30" : "00"}`, value: e };
|
|
50
50
|
} catch {
|
|
51
51
|
return console.warn(`Timezone ${e} not supported, skipping`), null;
|
|
52
52
|
}
|
|
53
|
-
}).filter((e) => e !== null).sort((e,
|
|
54
|
-
const [a,
|
|
55
|
-
return
|
|
53
|
+
}).filter((e) => e !== null).sort((e, t) => {
|
|
54
|
+
const [a, i] = e.label.replace("GMT", "").split(":").map(Number), [u, g] = t.label.replace("GMT", "").split(":").map(Number), A = a * 60 + i;
|
|
55
|
+
return u * 60 + g - A;
|
|
56
56
|
}).map((e) => ({
|
|
57
57
|
label: `(${e.label}) ${e.value}`,
|
|
58
58
|
value: e.value
|
|
59
|
-
})),
|
|
60
|
-
|
|
59
|
+
})), T = (o) => h(c(o)), z = (o, r) => {
|
|
60
|
+
if (!o || !r || !T(o) || !T(r))
|
|
61
|
+
return !1;
|
|
62
|
+
const e = c(o.trim()), t = c(r.trim());
|
|
63
|
+
return e.toLowerCase() === t.toLowerCase();
|
|
64
|
+
}, D = (o) => {
|
|
65
|
+
let r = o?.dateRange?.map((t) => n(t)) ?? [];
|
|
61
66
|
const e = n();
|
|
62
|
-
switch (
|
|
63
|
-
case
|
|
67
|
+
switch (o?.duration) {
|
|
68
|
+
case s.ThirtyMinutes:
|
|
64
69
|
r = [e, e.add(30, "minutes")];
|
|
65
70
|
break;
|
|
66
|
-
case
|
|
71
|
+
case s.OneHour:
|
|
67
72
|
r = [e, e.add(1, "hour")];
|
|
68
73
|
break;
|
|
69
|
-
case
|
|
74
|
+
case s.FourHours:
|
|
70
75
|
r = [e, e.add(4, "hours")];
|
|
71
76
|
break;
|
|
72
|
-
case
|
|
77
|
+
case s.Today:
|
|
73
78
|
r = [e, e.endOf("day")];
|
|
74
79
|
break;
|
|
75
|
-
case
|
|
80
|
+
case s.ThisWeek:
|
|
76
81
|
r = [e, e.endOf("week")];
|
|
77
82
|
break;
|
|
78
|
-
case
|
|
83
|
+
case s.NoClear:
|
|
79
84
|
r = [e, e];
|
|
80
85
|
break;
|
|
81
86
|
}
|
|
82
|
-
return r.map((
|
|
83
|
-
}, B = (
|
|
87
|
+
return r.map((t) => t.toDate());
|
|
88
|
+
}, B = (o) => {
|
|
84
89
|
const r = n();
|
|
85
|
-
return r.isAfter(n(
|
|
86
|
-
},
|
|
87
|
-
const { duration: r, dateRange: e } =
|
|
88
|
-
return !r || !e ? !1 : r ===
|
|
89
|
-
},
|
|
90
|
-
const r = n(),
|
|
91
|
-
return
|
|
92
|
-
},
|
|
90
|
+
return r.isAfter(n(o[0])) && r.isBefore(n(o[1]));
|
|
91
|
+
}, R = (o) => {
|
|
92
|
+
const { duration: r, dateRange: e } = o ?? {};
|
|
93
|
+
return !r || !e ? !1 : r === s.NoClear || n(e?.[0]).isSame(n(e?.[1]));
|
|
94
|
+
}, x = (o) => {
|
|
95
|
+
const r = n(), t = n(o).diff(r, "seconds"), a = (i) => i * 1e3;
|
|
96
|
+
return t >= l ? a(l) : t >= m ? a(m) : t >= d ? a(d) : t >= f ? a(f) : t >= p ? a(p) : t >= b ? a(b) : 0;
|
|
97
|
+
}, $ = {
|
|
93
98
|
color: "text.primary",
|
|
94
99
|
borderColor: "grey.100",
|
|
95
100
|
backgroundColor: "background.default",
|
|
@@ -99,7 +104,7 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, v = n.tz.guess(), b =
|
|
|
99
104
|
},
|
|
100
105
|
py: 0.5,
|
|
101
106
|
borderRadius: 1
|
|
102
|
-
},
|
|
107
|
+
}, H = {
|
|
103
108
|
color: "primary.contrastText",
|
|
104
109
|
borderColor: "primary.main",
|
|
105
110
|
backgroundColor: "primary.main",
|
|
@@ -111,13 +116,14 @@ const u = 3600, l = 1800, m = 600, d = 300, f = 60, p = 1, v = n.tz.guess(), b =
|
|
|
111
116
|
borderRadius: 1
|
|
112
117
|
};
|
|
113
118
|
export {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
_ as currentTimezone,
|
|
120
|
+
$ as defaultButtonStyle,
|
|
121
|
+
D as getStatusDuration,
|
|
122
|
+
x as getTimeRemaining,
|
|
123
|
+
v as getTimezones,
|
|
124
|
+
z as isDuplicateUrl,
|
|
125
|
+
R as isNotClear,
|
|
126
|
+
T as isValidUrl,
|
|
121
127
|
B as isWithinTimeRange,
|
|
122
|
-
|
|
128
|
+
H as primaryButtonStyle
|
|
123
129
|
};
|
|
@@ -142,6 +142,7 @@ export declare const translations: {
|
|
|
142
142
|
selectEndTime: string;
|
|
143
143
|
pleaseSelectTime: string;
|
|
144
144
|
invalidURL: string;
|
|
145
|
+
duplicateURL: string;
|
|
145
146
|
socialMedia: string;
|
|
146
147
|
timezonePhase: {
|
|
147
148
|
dawn: string;
|
|
@@ -325,6 +326,7 @@ export declare const translations: {
|
|
|
325
326
|
cleanStatus: string;
|
|
326
327
|
quickSettings: string;
|
|
327
328
|
invalidURL: string;
|
|
329
|
+
duplicateURL: string;
|
|
328
330
|
socialMedia: string;
|
|
329
331
|
timezonePhase: {
|
|
330
332
|
dawn: string;
|
|
@@ -142,6 +142,7 @@ const e = {
|
|
|
142
142
|
selectEndTime: "选择结束时间",
|
|
143
143
|
pleaseSelectTime: "请选择时间",
|
|
144
144
|
invalidURL: "无效的 URL",
|
|
145
|
+
duplicateURL: "URL 已存在",
|
|
145
146
|
socialMedia: "社交链接",
|
|
146
147
|
timezonePhase: {
|
|
147
148
|
dawn: "凌晨",
|
|
@@ -325,6 +326,7 @@ const e = {
|
|
|
325
326
|
cleanStatus: "Clean status",
|
|
326
327
|
quickSettings: "Quick Settings",
|
|
327
328
|
invalidURL: "Invalid URL",
|
|
329
|
+
duplicateURL: "URL already exists",
|
|
328
330
|
socialMedia: "Social Media",
|
|
329
331
|
timezonePhase: {
|
|
330
332
|
dawn: "AM",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/ui-react",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.38",
|
|
4
4
|
"description": "Some useful front-end web components that can be used in Blocklets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@abtnode/constant": "^1.16.49-beta-20250823-082650-626c1473",
|
|
37
37
|
"@abtnode/util": "^1.16.49-beta-20250823-082650-626c1473",
|
|
38
|
-
"@arcblock/bridge": "3.1.
|
|
39
|
-
"@arcblock/icons": "3.1.
|
|
40
|
-
"@arcblock/react-hooks": "3.1.
|
|
38
|
+
"@arcblock/bridge": "3.1.38",
|
|
39
|
+
"@arcblock/icons": "3.1.38",
|
|
40
|
+
"@arcblock/react-hooks": "3.1.38",
|
|
41
41
|
"@arcblock/ws": "^1.21.3",
|
|
42
42
|
"@blocklet/constant": "^1.16.49-beta-20250823-082650-626c1473",
|
|
43
43
|
"@blocklet/did-space-react": "^1.1.16",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"access": "public"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@arcblock/did-connect-react": "3.1.
|
|
86
|
+
"@arcblock/did-connect-react": "3.1.38",
|
|
87
87
|
"@types/dompurify": "^3.2.0",
|
|
88
88
|
"@types/ua-parser-js": "^0.7.39",
|
|
89
89
|
"@types/validator": "^13.15.2",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"jest": "^29.7.0",
|
|
92
92
|
"unbuild": "^2.0.0"
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "4fce76ba2f0fa12201695ce69a27d52eead5606a"
|
|
95
95
|
}
|
|
@@ -7,7 +7,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
|
7
7
|
import LinkIcon from '@arcblock/icons/lib/Link';
|
|
8
8
|
import { mergeSx } from '@arcblock/ux/lib/Util/style';
|
|
9
9
|
import { withoutProtocol } from 'ufo';
|
|
10
|
-
import { isValidUrl } from './utils';
|
|
10
|
+
import { isDuplicateUrl, isValidUrl } from './utils';
|
|
11
11
|
import { translations } from '../../libs/locales';
|
|
12
12
|
import { commonInputStyle, inputFieldStyle } from '../editable-field';
|
|
13
13
|
|
|
@@ -61,7 +61,7 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
61
61
|
const t = useMemoizedFn((key, data = {}) => {
|
|
62
62
|
return translate(translations, key, locale, 'en', data);
|
|
63
63
|
});
|
|
64
|
-
const [errors, setErrors] = useState([
|
|
64
|
+
const [errors, setErrors] = useState<(boolean | string)[]>(['']); // 记录 URL 输入错误状态
|
|
65
65
|
|
|
66
66
|
const isLastError = useMemo(() => {
|
|
67
67
|
const lastLink = links[links.length - 1];
|
|
@@ -89,7 +89,18 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
89
89
|
|
|
90
90
|
// 校验 URL 是否有效
|
|
91
91
|
const updatedErrors = [...errors];
|
|
92
|
-
|
|
92
|
+
const isInvalidUrl = !!(value && !isValidUrl(value));
|
|
93
|
+
updatedErrors[index] = false;
|
|
94
|
+
// 如果 URL 有效,则校验是否重复
|
|
95
|
+
if (!isInvalidUrl) {
|
|
96
|
+
const validLinks = updatedLinks.filter((l, i) => l && isValidUrl(l) && i !== index);
|
|
97
|
+
const isDuplicate = validLinks.some((v) => isDuplicateUrl(v, value));
|
|
98
|
+
if (isDuplicate) {
|
|
99
|
+
updatedErrors[index] = 'duplicate';
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
updatedErrors[index] = isInvalidUrl; // 如果有输入但格式错误,标记错误
|
|
103
|
+
}
|
|
93
104
|
setErrors(updatedErrors);
|
|
94
105
|
onChange(updatedLinks);
|
|
95
106
|
};
|
|
@@ -110,30 +121,36 @@ function DynamicLinkForm({ links = [], onChange }: { links?: string[]; onChange:
|
|
|
110
121
|
{t('profile.socialMedia')}
|
|
111
122
|
</Typography>
|
|
112
123
|
</Box>
|
|
113
|
-
{links.map((link, index) =>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
{links.map((link, index) => {
|
|
125
|
+
let errorMsg = '';
|
|
126
|
+
if (errors[index] === 'duplicate') {
|
|
127
|
+
errorMsg = t('profile.duplicateURL');
|
|
128
|
+
} else if (errors[index] === true) {
|
|
129
|
+
errorMsg = t('profile.invalidURL');
|
|
130
|
+
} else {
|
|
131
|
+
errorMsg = '';
|
|
132
|
+
}
|
|
133
|
+
return (
|
|
134
|
+
<Box
|
|
135
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
136
|
+
key={index}
|
|
137
|
+
sx={{
|
|
138
|
+
display: 'flex',
|
|
139
|
+
alignItems: 'flex-start',
|
|
140
|
+
mb: 1,
|
|
141
|
+
}}>
|
|
142
|
+
<LinkInput value={link} onChange={(value) => handleInputChange(index, value)} errorMsg={errorMsg} />
|
|
143
|
+
<IconButton onClick={() => handleRemoveLink(index)}>
|
|
144
|
+
<RemoveIcon sx={{ color: 'text.secondary' }} />
|
|
145
|
+
</IconButton>
|
|
146
|
+
</Box>
|
|
147
|
+
);
|
|
148
|
+
})}
|
|
132
149
|
{links.length < MAX_LINK_COUNT ? (
|
|
133
150
|
<Button
|
|
134
151
|
fullWidth
|
|
135
152
|
variant="outlined"
|
|
136
|
-
disabled={isLastError}
|
|
153
|
+
disabled={!!isLastError}
|
|
137
154
|
onClick={handleAddLink}
|
|
138
155
|
size="small"
|
|
139
156
|
sx={{
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { translations } from '../../libs/locales';
|
|
19
19
|
import type { User, UserAddress, UserMetadata } from '../../../@types';
|
|
20
20
|
import { formatAxiosError } from '../../libs/utils';
|
|
21
|
-
import { currentTimezone, getStatusDuration, isValidUrl } from './utils';
|
|
21
|
+
import { currentTimezone, getStatusDuration, isValidUrl, isDuplicateUrl } from './utils';
|
|
22
22
|
import SwitchRole from './switch-role';
|
|
23
23
|
import UserMetadataComponent from './metadata';
|
|
24
24
|
import UserStatus from './user-status';
|
|
@@ -106,9 +106,17 @@ export default function UserBasicInfo({
|
|
|
106
106
|
try {
|
|
107
107
|
const newLinks =
|
|
108
108
|
metadata?.links
|
|
109
|
-
?.map((link) => {
|
|
109
|
+
?.map((link, index) => {
|
|
110
110
|
if (!link.url || !isValidUrl(link.url)) return null;
|
|
111
111
|
|
|
112
|
+
// 去重:如果 URL 相同则跳过(忽略协议和大 小写)
|
|
113
|
+
if (index > 0) {
|
|
114
|
+
const prevLinks = metadata.links?.slice(0, index);
|
|
115
|
+
if (prevLinks?.some((l) => isDuplicateUrl(l.url, link.url))) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
112
120
|
try {
|
|
113
121
|
const parsedUrl = parseURL(link.url);
|
|
114
122
|
// 如果没有协议,添加 https
|
|
@@ -109,6 +109,19 @@ export const isValidUrl = (url: string) => {
|
|
|
109
109
|
return isUrl(withHttps(url)); // 补充协议后在进行验证是否是合法的url
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
+
export const isDuplicateUrl = (url1: string, url2: string) => {
|
|
113
|
+
if (!url1 || !url2) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (!isValidUrl(url1) || !isValidUrl(url2)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const parsedUrl1 = withHttps(url1.trim());
|
|
121
|
+
const parsedUrl2 = withHttps(url2.trim());
|
|
122
|
+
return parsedUrl1.toLowerCase() === parsedUrl2.toLowerCase();
|
|
123
|
+
};
|
|
124
|
+
|
|
112
125
|
/**
|
|
113
126
|
* 根据 duration 类型,计算出date range
|
|
114
127
|
* @param status
|
|
@@ -144,6 +144,7 @@ export const translations = {
|
|
|
144
144
|
selectEndTime: '选择结束时间',
|
|
145
145
|
pleaseSelectTime: '请选择时间',
|
|
146
146
|
invalidURL: '无效的 URL',
|
|
147
|
+
duplicateURL: 'URL 已存在',
|
|
147
148
|
socialMedia: '社交链接',
|
|
148
149
|
timezonePhase: {
|
|
149
150
|
dawn: '凌晨',
|
|
@@ -330,6 +331,7 @@ export const translations = {
|
|
|
330
331
|
cleanStatus: 'Clean status',
|
|
331
332
|
quickSettings: 'Quick Settings',
|
|
332
333
|
invalidURL: 'Invalid URL',
|
|
334
|
+
duplicateURL: 'URL already exists',
|
|
333
335
|
socialMedia: 'Social Media',
|
|
334
336
|
timezonePhase: {
|
|
335
337
|
dawn: 'AM',
|