@blocklet/ui-react 3.0.15 → 3.0.17

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.
@@ -132,6 +132,7 @@ export type Session = {
132
132
  refresh: Function;
133
133
  useOAuth: Function;
134
134
  usePasskey: Function;
135
+ withSecondaryAuth: Function;
135
136
  };
136
137
  export type WebhookType = 'slack' | 'api';
137
138
  export type WebhookItemData = {
@@ -1 +1,3 @@
1
- export default function DangerZone(): import("react/jsx-runtime").JSX.Element;
1
+ export default function DangerZone({ onDestroySelf }: {
2
+ onDestroySelf?: () => void;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,80 +1,37 @@
1
- import { jsxs as l, Fragment as D, jsx as s } from "react/jsx-runtime";
2
- import { use as L } from "react";
3
- import { Box as a, Typography as p, Button as w } from "@mui/material";
4
- import { useLocaleContext as E } from "@arcblock/ux/lib/Locale/context";
5
- import { translate as I } from "@arcblock/ux/lib/Locale/util";
6
- import { useMemoizedFn as d, useCreation as R } from "ahooks";
7
- import { useConfirm as v } from "@arcblock/ux/lib/Dialog";
8
- import { SessionContext as S } from "@arcblock/did-connect/lib/Session";
9
- import { LOGIN_PROVIDER as _ } from "@blocklet/constant";
10
- import m from "@arcblock/ux/lib/Toast";
11
- import { translations as B } from "../libs/locales.js";
12
- import { client as y } from "../../libs/client.js";
13
- function N() {
14
- const { confirmApi: g, confirmHolder: x } = v(), { locale: f } = E(), { session: n, connectApi: u } = L(S), e = d((r, o = {}) => I(B, r, f, "en", o)), h = R(() => {
15
- if (["true", !0].includes(window?.blocklet?.ALLOW_SKIP_DESTROY_MYSELF_VERIFY))
16
- return !1;
17
- const r = n?.user?.connectedAccounts || [], o = [_.WALLET];
18
- return !!r.some((t) => o.includes(t.provider));
19
- }, [n?.user]), A = d(() => new Promise((r, o) => {
20
- const t = n?.user?.did;
21
- u.open({
22
- locale: f,
23
- action: "destroy-myself",
24
- forceConnected: !0,
25
- saveConnect: !1,
26
- autoConnect: !1,
27
- // 暂不允许使用 passkey 进行验证
28
- passkeyBehavior: "none",
1
+ import { jsxs as a, Fragment as f, jsx as o } from "react/jsx-runtime";
2
+ import { use as u } from "react";
3
+ import { Box as s, Typography as c, Button as h } from "@mui/material";
4
+ import { useLocaleContext as x } from "@arcblock/ux/lib/Locale/context";
5
+ import { translate as g } from "@arcblock/ux/lib/Locale/util";
6
+ import { useMemoizedFn as l } from "ahooks";
7
+ import { useConfirm as y } from "@arcblock/ux/lib/Dialog";
8
+ import { SessionContext as v } from "@arcblock/did-connect/lib/Session";
9
+ import w from "@arcblock/ux/lib/Toast";
10
+ import { translations as C } from "../libs/locales.js";
11
+ function S({ onDestroySelf: t = void 0 }) {
12
+ const { confirmHolder: m } = y(), { locale: d } = x(), { session: e } = u(v), r = l((n, i = {}) => g(C, n, d, "en", i)), p = l(async () => {
13
+ if (!t || typeof t != "function")
14
+ return;
15
+ const n = e.withSecondaryAuth(t, {
29
16
  extraParams: {
30
- removeUserDid: t
31
- },
32
- messages: {
33
- title: e("destroyMyself.title"),
34
- scan: e("destroyMyself.scan"),
35
- confirm: e("destroyMyself.confirm"),
36
- success: e("destroyMyself.success")
37
- },
38
- // @ts-expect-error 该 did-connect 后端api 将结果塞在了 result 中,并做了加密,所以已经变成一个字符串了
39
- onSuccess: ({ result: c }, C = (i) => i) => {
40
- const i = C(c);
41
- r(i);
42
- },
43
- onClose: () => {
44
- u.close(), o(new Error(e("destroyMyself.abort")));
45
- }
46
- });
47
- })), M = d(() => {
48
- g.open({
49
- title: e("dangerZone.deleteAccount"),
50
- content: e("dangerZone.deleteAccountDescription"),
51
- confirmButtonText: e("common.confirm"),
52
- confirmButtonProps: {
53
- color: "error"
54
- },
55
- cancelButtonText: e("common.cancel"),
56
- async onConfirm(r) {
57
- let o;
58
- try {
59
- if (h)
60
- o = await A();
61
- else if (y?.user?.destroyMyself instanceof Function)
62
- o = await y.user.destroyMyself();
63
- else {
64
- m.error(e("notImplemented"));
65
- return;
66
- }
67
- o?.did === n?.user?.did ? n.logout(r) : m.error(e("destroyMyself.error"));
68
- } catch (t) {
69
- const c = t?.response?.data.error || t?.message || e("destroyMyself.error");
70
- m.error(c);
17
+ locale: d,
18
+ removeUserDid: e?.user?.did,
19
+ input: {
20
+ user: { did: e?.user?.did },
21
+ teamDid: window?.blocklet?.did
71
22
  }
72
- }
23
+ },
24
+ operation: "destroySelf"
73
25
  });
26
+ try {
27
+ await n(), e.logout();
28
+ } catch (i) {
29
+ w.error(i?.message || r("destroyMyself.error"));
30
+ }
74
31
  });
75
- return /* @__PURE__ */ l(D, { children: [
76
- /* @__PURE__ */ s(a, { children: /* @__PURE__ */ l(
77
- a,
32
+ return /* @__PURE__ */ a(f, { children: [
33
+ /* @__PURE__ */ o(s, { children: /* @__PURE__ */ a(
34
+ s,
78
35
  {
79
36
  sx: {
80
37
  display: "flex",
@@ -84,36 +41,36 @@ function N() {
84
41
  flexWrap: "wrap"
85
42
  },
86
43
  children: [
87
- /* @__PURE__ */ l(a, { children: [
88
- /* @__PURE__ */ s(
89
- p,
44
+ /* @__PURE__ */ a(s, { children: [
45
+ /* @__PURE__ */ o(
46
+ c,
90
47
  {
91
48
  variant: "h6",
92
49
  sx: {
93
50
  fontSize: "0.875rem !important",
94
51
  fontWeight: "bold"
95
52
  },
96
- children: e("dangerZone.deleteAccount")
53
+ children: r("dangerZone.deleteAccount")
97
54
  }
98
55
  ),
99
- /* @__PURE__ */ s(
100
- p,
56
+ /* @__PURE__ */ o(
57
+ c,
101
58
  {
102
59
  variant: "caption",
103
60
  sx: {
104
61
  color: "text.secondary"
105
62
  },
106
- children: e("dangerZone.deleteAccountDescription")
63
+ children: r("dangerZone.deleteAccountDescription")
107
64
  }
108
65
  )
109
66
  ] }),
110
- /* @__PURE__ */ s(w, { variant: "contained", color: "error", size: "small", onClick: M, children: e("dangerZone.delete") })
67
+ /* @__PURE__ */ o(h, { variant: "contained", color: "error", size: "small", onClick: p, children: r("dangerZone.delete") })
111
68
  ]
112
69
  }
113
70
  ) }),
114
- x
71
+ m
115
72
  ] });
116
73
  }
117
74
  export {
118
- N as default
75
+ S as default
119
76
  };
@@ -7,4 +7,5 @@ export default function Settings({ user, settings, onSave, isMobile, ...rest }:
7
7
  userCenterTabs: UserCenterTab[];
8
8
  };
9
9
  isMobile: boolean;
10
+ onDestroySelf?: () => void;
10
11
  } & BoxProps): import("react/jsx-runtime").JSX.Element;
@@ -1,82 +1,83 @@
1
- import { jsx as o, jsxs as g } from "react/jsx-runtime";
2
- import { useEffect as h } from "react";
3
- import { Box as i, Typography as v } from "@mui/material";
4
- import { useMemoizedFn as x, useCreation as f } from "ahooks";
5
- import { translate as b } from "@arcblock/ux/lib/Locale/util";
6
- import { useLocaleContext as y } from "@arcblock/ux/lib/Locale/context";
7
- import { mergeSx as C } from "@arcblock/ux/lib/Util/style";
8
- import S from "@arcblock/react-hooks/lib/useBrowser";
9
- import { translations as w } from "../libs/locales.js";
10
- import L from "./notification.js";
11
- import P from "./privacy.js";
12
- import T from "../../UserSessions/components/user-sessions.js";
13
- import B from "./third-party-login/index.js";
1
+ import { jsx as o, jsxs as h } from "react/jsx-runtime";
2
+ import { useEffect as y } from "react";
3
+ import { Box as s, Typography as v } from "@mui/material";
4
+ import { ROLES as x } from "@abtnode/constant";
5
+ import { useMemoizedFn as b, useCreation as l } from "ahooks";
6
+ import { translate as S } from "@arcblock/ux/lib/Locale/util";
7
+ import { useLocaleContext as C } from "@arcblock/ux/lib/Locale/context";
8
+ import { mergeSx as w } from "@arcblock/ux/lib/Util/style";
9
+ import L from "@arcblock/react-hooks/lib/useBrowser";
10
+ import { translations as P } from "../libs/locales.js";
11
+ import D from "./notification.js";
12
+ import T from "./privacy.js";
13
+ import B from "../../UserSessions/components/user-sessions.js";
14
+ import E from "./third-party-login/index.js";
14
15
  import M from "./config-profile.js";
15
- import U from "./danger-zone.js";
16
- import { client as W } from "../../libs/client.js";
17
- function O({
18
- user: n,
19
- settings: s,
20
- onSave: a,
21
- isMobile: l,
22
- ...m
16
+ import W from "./danger-zone.js";
17
+ import { client as O } from "../../libs/client.js";
18
+ function Y({
19
+ user: r,
20
+ settings: a,
21
+ onSave: m,
22
+ isMobile: c,
23
+ ...i
23
24
  }) {
24
- const { locale: p } = y(), d = S().arcSphere, t = x((e, r = {}) => b(w, e, p, "en", r)), c = f(() => (s?.userCenterTabs || []).map((r) => ({
25
- key: r.value,
26
- name: r.label,
27
- value: r.protected,
28
- isPrivate: r.isPrivate
29
- })), [s?.userCenterTabs]), u = f(() => [
25
+ const { locale: p } = C(), d = L().arcSphere, n = b((e, t = {}) => S(P, e, p, "en", t)), u = l(() => r.passports?.some((e) => e.role === x.OWNER), [r]), f = l(() => (a?.userCenterTabs || []).map((t) => ({
26
+ key: t.value,
27
+ name: t.label,
28
+ value: t.protected,
29
+ isPrivate: t.isPrivate
30
+ })), [a?.userCenterTabs]), g = l(() => [
30
31
  d ? void 0 : {
31
- label: t("commonSetting.title"),
32
+ label: n("commonSetting.title"),
32
33
  value: "common",
33
- content: /* @__PURE__ */ o(M, { user: n, onSave: a })
34
+ content: /* @__PURE__ */ o(M, { user: r, onSave: m })
34
35
  },
35
36
  {
36
- label: t("notificationManagement"),
37
+ label: n("notificationManagement"),
37
38
  value: "notification",
38
- content: /* @__PURE__ */ o(L, { user: n, isMobile: l })
39
+ content: /* @__PURE__ */ o(D, { user: r, isMobile: c })
39
40
  },
40
41
  {
41
- label: t("thirdPartyLogin.title"),
42
+ label: n("thirdPartyLogin.title"),
42
43
  value: "thirdPartyLogin",
43
- content: /* @__PURE__ */ o(B, { user: n })
44
+ content: /* @__PURE__ */ o(E, { user: r })
44
45
  },
45
46
  {
46
- label: t("privacyManagement"),
47
+ label: n("privacyManagement"),
47
48
  value: "privacy",
48
- content: /* @__PURE__ */ o(P, { configList: c, onSave: a })
49
+ content: /* @__PURE__ */ o(T, { configList: f, onSave: m })
49
50
  },
50
51
  {
51
- label: t("sessionManagement"),
52
+ label: n("sessionManagement"),
52
53
  value: "session",
53
54
  content: /* @__PURE__ */ o(
54
- T,
55
+ B,
55
56
  {
56
- user: n,
57
+ user: r,
57
58
  showUser: !1,
58
- getUserSessions: (e) => W.userSession.getMyLoginSessions({}, e)
59
+ getUserSessions: (e) => O.userSession.getMyLoginSessions({}, e)
59
60
  }
60
61
  )
61
62
  },
62
- {
63
- label: t("dangerZone.title"),
63
+ !u && i.onDestroySelf && typeof i.onDestroySelf == "function" ? {
64
+ label: n("dangerZone.title"),
64
65
  value: "dangerZone",
65
- content: /* @__PURE__ */ o(U, {}),
66
+ content: /* @__PURE__ */ o(W, { onDestroySelf: i.onDestroySelf }),
66
67
  sx: {
67
68
  borderColor: "error.main"
68
69
  }
69
- }
70
- ].filter(Boolean), [n, c, l]);
71
- return h(() => {
70
+ } : null
71
+ ].filter(Boolean), [r, f, c]);
72
+ return y(() => {
72
73
  const e = window.location.hash.slice(1);
73
74
  e && document.getElementById(e)?.scrollIntoView({ behavior: "smooth" });
74
75
  }, []), /* @__PURE__ */ o(
75
- i,
76
+ s,
76
77
  {
77
- ...m,
78
+ ...i,
78
79
  sx: {
79
- ...m?.sx,
80
+ ...i?.sx,
80
81
  display: "flex",
81
82
  flexDirection: "column",
82
83
  gap: 2.5,
@@ -85,11 +86,11 @@ function O({
85
86
  },
86
87
  maxWidth: "100%"
87
88
  },
88
- children: u.map((e) => e ? /* @__PURE__ */ g(
89
- i,
89
+ children: g.map((e) => e ? /* @__PURE__ */ h(
90
+ s,
90
91
  {
91
92
  id: e.value,
92
- sx: C(
93
+ sx: w(
93
94
  {
94
95
  border: "1px solid",
95
96
  borderColor: "divider",
@@ -113,7 +114,7 @@ function O({
113
114
  }
114
115
  ),
115
116
  /* @__PURE__ */ o(
116
- i,
117
+ s,
117
118
  {
118
119
  sx: {
119
120
  mt: 2.5
@@ -129,5 +130,5 @@ function O({
129
130
  );
130
131
  }
131
132
  export {
132
- O as default
133
+ Y as default
133
134
  };
@@ -1,5 +1,6 @@
1
1
  import { BoxProps } from '@mui/material';
2
- export default function UserCenter({ children, notLoginContent, currentTab, contentProps, disableAutoRedirect, hideFooter, headerProps, footerProps, userDid, stickySidebar, embed, onlyProfile, }: {
2
+ export default function UserCenter({ children, notLoginContent, currentTab, contentProps, disableAutoRedirect, hideFooter, headerProps, footerProps, userDid, stickySidebar, embed, onlyProfile, // 只显示 profile 页面,用于 ArcSphere 只需要显示 Profile 的内容
3
+ onDestroySelf, }: {
3
4
  readonly children: any;
4
5
  readonly notLoginContent?: any;
5
6
  readonly currentTab: string;
@@ -13,4 +14,5 @@ export default function UserCenter({ children, notLoginContent, currentTab, cont
13
14
  readonly stickySidebar?: boolean;
14
15
  readonly embed?: boolean;
15
16
  readonly onlyProfile?: boolean;
17
+ readonly onDestroySelf?: () => void;
16
18
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -1,24 +1,24 @@
1
1
  import { jsx as e, jsxs as f, Fragment as D } from "react/jsx-runtime";
2
- import { use as fe } from "react";
3
- import { Box as a, Typography as pe, CircularProgress as me, Divider as he } from "@mui/material";
2
+ import { use as pe } from "react";
3
+ import { Box as a, Typography as me, CircularProgress as he, Divider as xe } from "@mui/material";
4
4
  import { useMemoizedFn as y, useCreation as d, useRequest as Y } from "ahooks";
5
- import xe from "p-wait-for";
6
- import { SessionContext as ge } from "@arcblock/did-connect/lib/Session";
7
- import ve from "@arcblock/ux/lib/Tabs";
5
+ import ge from "p-wait-for";
6
+ import { SessionContext as ve } from "@arcblock/did-connect/lib/Session";
7
+ import be from "@arcblock/ux/lib/Tabs";
8
8
  import M from "@arcblock/ux/lib/Empty";
9
- import be from "@arcblock/ux/lib/Button";
10
- import we from "@arcblock/ux/lib/Result";
11
- import { useConfirm as ye } from "@arcblock/ux/lib/Dialog";
12
- import { translate as Ce } from "@arcblock/ux/lib/Locale/util";
13
- import { useLocaleContext as ke } from "@arcblock/ux/lib/Locale/context";
14
- import { ErrorFallback as Pe } from "@arcblock/ux/lib/ErrorBoundary";
9
+ import we from "@arcblock/ux/lib/Button";
10
+ import ye from "@arcblock/ux/lib/Result";
11
+ import { useConfirm as Ce } from "@arcblock/ux/lib/Dialog";
12
+ import { translate as ke } from "@arcblock/ux/lib/Locale/util";
13
+ import { useLocaleContext as Pe } from "@arcblock/ux/lib/Locale/context";
14
+ import { ErrorFallback as Se } from "@arcblock/ux/lib/ErrorBoundary";
15
15
  import { styled as oe } from "@arcblock/ux/lib/Theme";
16
- import Se from "lodash/cloneDeep";
17
- import { joinURL as C, getQuery as De, withoutTrailingSlash as Z, withQuery as $ } from "ufo";
16
+ import De from "lodash/cloneDeep";
17
+ import { joinURL as C, getQuery as Me, withoutTrailingSlash as Z, withQuery as $ } from "ufo";
18
18
  import { PROFILE_URL as k } from "@arcblock/ux/lib/Util/constant";
19
- import Me from "../../Footer/index.js";
19
+ import Te from "../../Footer/index.js";
20
20
  import ee from "../../Header/index.js";
21
- import { translations as Te } from "../libs/locales.js";
21
+ import { translations as We } from "../libs/locales.js";
22
22
  import re from "./user-info/user-basic-info.js";
23
23
  import "@mui/icons-material";
24
24
  import "@iconify/react";
@@ -30,14 +30,14 @@ import "@iconify-icons/material-symbols/settings-input-antenna-rounded";
30
30
  import "@arcblock/ux/lib/RelativeTime";
31
31
  import "@arcblock/ux/lib/UserCard/Content/shorten-label";
32
32
  import "./user-info/switch-role.js";
33
- import { formatBlockletInfo as We, getLink as T, getLocalizedNavigation as ze } from "../../blocklets.js";
34
- import Ae from "./passport.js";
35
- import Ue from "./settings.js";
33
+ import { formatBlockletInfo as ze, getLink as T, getLocalizedNavigation as Ae } from "../../blocklets.js";
34
+ import Ue from "./passport.js";
35
+ import Le from "./settings.js";
36
36
  import { client as te } from "../../libs/client.js";
37
- import Le from "../../hooks/use-mobile.js";
38
- import { ConfigUserSpaceProvider as Be } from "../../contexts/config-user-space.js";
39
- import Fe from "./storage/index.js";
40
- import Re from "./nft.js";
37
+ import Be from "../../hooks/use-mobile.js";
38
+ import { ConfigUserSpaceProvider as Fe } from "../../contexts/config-user-space.js";
39
+ import Re from "./storage/index.js";
40
+ import Ie from "./nft.js";
41
41
  const W = C(k, "/nfts"), z = C(k, "/settings"), A = C(k, "/did-spaces"), ie = oe(a)(({ theme: v }) => ({
42
42
  flex: 1,
43
43
  boxSizing: "border-box",
@@ -64,7 +64,7 @@ const W = C(k, "/nfts"), z = C(k, "/settings"), A = C(k, "/did-spaces"), ie = oe
64
64
  }
65
65
  }
66
66
  }));
67
- function Sr({
67
+ function Dr({
68
68
  children: v,
69
69
  notLoginContent: L = null,
70
70
  currentTab: h,
@@ -76,18 +76,19 @@ function Sr({
76
76
  userDid: P = void 0,
77
77
  stickySidebar: R = !1,
78
78
  embed: I = !1,
79
- onlyProfile: w = !1
79
+ onlyProfile: w = !1,
80
80
  // 只显示 profile 页面,用于 ArcSphere 只需要显示 Profile 的内容
81
+ onDestroySelf: le = void 0
81
82
  }) {
82
- const { locale: x } = ke(), l = Le({ key: "md" }), g = y((r, o = {}) => Ce(Te, r, x, "en", o)), t = fe(ge)?.session, p = d(() => {
83
+ const { locale: x } = Pe(), l = Be({ key: "md" }), g = y((r, o = {}) => ke(We, r, x, "en", o)), t = pe(ve)?.session, p = d(() => {
83
84
  if (P)
84
85
  return P;
85
- const r = window.location.href, o = De(r);
86
+ const r = window.location.href, o = Me(r);
86
87
  return o?.did ? Array.isArray(o.did) ? o.did[0] : o.did : t?.user?.did;
87
88
  }, [t?.user?.did, P]), i = d(() => t?.user ? p === t?.user?.did : !1, [p, t?.user?.did]), n = Y(
88
89
  // eslint-disable-next-line consistent-return
89
90
  async () => {
90
- if (await xe(() => t?.initialized), i)
91
+ if (await ge(() => t?.initialized), i)
91
92
  return t.user;
92
93
  if (p)
93
94
  return te.user.getUserPublicInfo({ did: p });
@@ -101,7 +102,7 @@ function Sr({
101
102
  refreshDeps: [p, n.data, h],
102
103
  loadingDelay: 300
103
104
  }
104
- ), { confirmHolder: H } = ye({
105
+ ), { confirmHolder: H } = Ce({
105
106
  fullScreen: l,
106
107
  sx: {
107
108
  ".MuiDialog-paper": {
@@ -122,9 +123,9 @@ function Sr({
122
123
  }
123
124
  }
124
125
  }), N = d(() => {
125
- const r = Se(window.blocklet);
126
+ const r = De(window.blocklet);
126
127
  try {
127
- return We(r);
128
+ return ze(r);
128
129
  } catch (o) {
129
130
  return console.error("Failed to format blocklet info", o, r), r;
130
131
  }
@@ -157,7 +158,7 @@ function Sr({
157
158
  ]), o;
158
159
  }, [i, x]), c = d(() => {
159
160
  const r = N?.navigation?.userCenter || [];
160
- return (ze(r, x) || []).concat(_).map((u) => {
161
+ return (Ae(r, x) || []).concat(_).map((u) => {
161
162
  const X = u.value ?? u._rawLink ?? u.link ?? u.url;
162
163
  return {
163
164
  value: X,
@@ -169,21 +170,22 @@ function Sr({
169
170
  // icon: x.icon,
170
171
  };
171
172
  }).filter((u) => i || !u.isPrivate);
172
- }, [N, n.data, m?.data, x, _, i]), s = d(() => c.find((r) => Z(r.value) === Z(h)), [c]), le = y((r) => {
173
+ }, [N, n.data, m?.data, x, _, i]), s = d(() => c.find((r) => Z(r.value) === Z(h)), [c]), de = y((r) => {
173
174
  const o = c.find((b) => b.value === r);
174
175
  o && (window.location.href = $(o.url, {
175
176
  did: i ? void 0 : p
176
177
  }));
177
178
  }), E = d(() => /* @__PURE__ */ e(
178
- Ue,
179
+ Le,
179
180
  {
180
181
  user: n.data,
181
182
  settings: { userCenterTabs: c },
182
183
  onSave: async (r) => r === "privacy" ? (await m.runAsync(), m.data) : (r === "profile" && await t.refresh(), null),
183
- isMobile: l
184
+ isMobile: l,
185
+ onDestroySelf: le
184
186
  }
185
- ), [n.data, c, m.data, m.runAsync]), O = d(() => s && s?.value === z, [s]), q = d(() => s && s?.value === C(k, "/profile") || s?.value === W, [s]), de = d(() => s && s?.value === A, [s]), ce = t.useOAuth(), ue = t.usePasskey(), Q = y(() => {
186
- t?.user?.sourceProvider === "passkey" ? ue.switchPassport(t.user) : ["google", "apple", "email", "github"].includes(t?.user?.sourceProvider ?? "") ? ce.switchOAuthPassport(t.user) : t && t.switchPassport();
187
+ ), [n.data, c, m.data, m.runAsync]), O = d(() => s && s?.value === z, [s]), q = d(() => s && s?.value === C(k, "/profile") || s?.value === W, [s]), ce = d(() => s && s?.value === A, [s]), ue = t.useOAuth(), fe = t.usePasskey(), Q = y(() => {
188
+ t?.user?.sourceProvider === "passkey" ? fe.switchPassport(t.user) : ["google", "apple", "email", "github"].includes(t?.user?.sourceProvider ?? "") ? ue.switchOAuthPassport(t.user) : t && t.switchPassport();
187
189
  }), S = d(() => q ? /* @__PURE__ */ f(
188
190
  a,
189
191
  {
@@ -195,7 +197,7 @@ function Sr({
195
197
  children: [
196
198
  i ? /* @__PURE__ */ f(a, { sx: { border: "1px solid", borderColor: "divider", borderRadius: 1.5, p: 2 }, children: [
197
199
  /* @__PURE__ */ e(
198
- pe,
200
+ me,
199
201
  {
200
202
  sx: {
201
203
  color: "text.primary",
@@ -205,12 +207,12 @@ function Sr({
205
207
  children: g("passport")
206
208
  }
207
209
  ),
208
- /* @__PURE__ */ e(Ae, { user: n.data })
210
+ /* @__PURE__ */ e(Ue, { user: n.data })
209
211
  ] }) : null,
210
- /* @__PURE__ */ e(Re, { user: n.data })
212
+ /* @__PURE__ */ e(Ie, { user: n.data })
211
213
  ]
212
214
  }
213
- ) : O && i ? E : de && i ? /* @__PURE__ */ e(Be, { children: /* @__PURE__ */ e(Fe, {}) }) : null, [O, q, n, i, R, E]), G = d(() => /* @__PURE__ */ e(
215
+ ) : O && i ? E : ce && i ? /* @__PURE__ */ e(Fe, { children: /* @__PURE__ */ e(Re, {}) }) : null, [O, q, n, i, R, E]), G = d(() => /* @__PURE__ */ e(
214
216
  a,
215
217
  {
216
218
  sx: {
@@ -234,7 +236,7 @@ function Sr({
234
236
  alignItems: "center",
235
237
  flex: 1
236
238
  },
237
- children: /* @__PURE__ */ e(me, {})
239
+ children: /* @__PURE__ */ e(he, {})
238
240
  }
239
241
  ) : (
240
242
  // eslint-disable-next-line react/jsx-no-useless-fragment
@@ -247,11 +249,11 @@ function Sr({
247
249
  return null;
248
250
  if (n.error) {
249
251
  if (n.error?.response?.status === 404)
250
- return /* @__PURE__ */ e(a, { sx: { width: "100%" }, children: /* @__PURE__ */ e(we, { status: 404, description: g("noUserFound") }) });
252
+ return /* @__PURE__ */ e(a, { sx: { width: "100%" }, children: /* @__PURE__ */ e(ye, { status: 404, description: g("noUserFound") }) });
251
253
  const b = {
252
254
  message: n.error.response?.data?.error || n.error.message || "error occurred"
253
255
  };
254
- return /* @__PURE__ */ e(a, { sx: { width: "100%" }, children: /* @__PURE__ */ e(Pe, { error: b }) });
256
+ return /* @__PURE__ */ e(a, { sx: { width: "100%" }, children: /* @__PURE__ */ e(Se, { error: b }) });
255
257
  }
256
258
  return !p && !n.data ? L || /* @__PURE__ */ e(a, { sx: { width: "100%" }, children: /* @__PURE__ */ f(
257
259
  a,
@@ -265,7 +267,7 @@ function Sr({
265
267
  },
266
268
  children: [
267
269
  /* @__PURE__ */ e(M, { children: g("viewAfterLogin") }),
268
- /* @__PURE__ */ e(be, { size: "small", variant: "contained", onClick: () => t.login(), children: g("loginNow") })
270
+ /* @__PURE__ */ e(we, { size: "small", variant: "contained", onClick: () => t.login(), children: g("loginNow") })
269
271
  ]
270
272
  }
271
273
  ) }) : I ? /* @__PURE__ */ f(U, { children: [
@@ -322,19 +324,20 @@ function Sr({
322
324
  },
323
325
  children: [
324
326
  /* @__PURE__ */ e(
325
- ve,
327
+ be,
326
328
  {
327
329
  orientation: "horizontal",
328
330
  variant: "line",
329
331
  tabs: c,
330
332
  current: s?.value ?? h,
331
- onChange: le,
333
+ onChange: de,
334
+ enableTabClick: !0,
332
335
  sx: {
333
336
  mb: 2,
334
337
  ".MuiTabs-flexContainer": {
335
338
  gap: 3,
336
339
  ".MuiButtonBase-root": {
337
- padding: l ? "16px 4px" : "40px 4px 32px 4px",
340
+ padding: l ? "16px 4px" : "32px 4px 16px 4px",
338
341
  fontSize: 16
339
342
  },
340
343
  ".MuiTab-root": {
@@ -365,7 +368,7 @@ function Sr({
365
368
  ]
366
369
  }
367
370
  ),
368
- !l && /* @__PURE__ */ e(he, { orientation: "vertical", sx: { ml: 5 } }),
371
+ !l && /* @__PURE__ */ e(xe, { orientation: "vertical", sx: { ml: 5 } }),
369
372
  /* @__PURE__ */ e(
370
373
  re,
371
374
  {
@@ -424,7 +427,7 @@ function Sr({
424
427
  H
425
428
  ] }),
426
429
  ne ? null : /* @__PURE__ */ e(
427
- Me,
430
+ Te,
428
431
  {
429
432
  bordered: !0,
430
433
  ...ae,
@@ -440,5 +443,5 @@ function Sr({
440
443
  );
441
444
  }
442
445
  export {
443
- Sr as default
446
+ Dr as default
444
447
  };
@@ -1,72 +1,72 @@
1
1
  import { jsx as i } from "react/jsx-runtime";
2
- import R from "prop-types";
3
- import { useMemo as O, useCallback as h, useEffect as _ } from "react";
4
- import { IconButton as $, Badge as g } from "@mui/material";
5
- import { useSnackbar as B } from "notistack";
6
- import D from "@arcblock/icons/lib/Notification";
2
+ import O from "prop-types";
3
+ import { useMemo as _, useCallback as h, useEffect as $ } from "react";
4
+ import { IconButton as g, Badge as B } from "@mui/material";
5
+ import { useSnackbar as D } from "notistack";
6
+ import S from "@arcblock/icons/lib/Notification";
7
7
  import { useCreation as s } from "ahooks";
8
- import { WELLKNOWN_SERVICE_PATH_PREFIX as S, EVENTS as y } from "@abtnode/constant";
9
- import V from "@arcblock/react-hooks/lib/useBrowser";
10
- import { joinURL as x, withQuery as U } from "ufo";
8
+ import { WELLKNOWN_SERVICE_PATH_PREFIX as V, EVENTS as y } from "@abtnode/constant";
9
+ import x from "@arcblock/react-hooks/lib/useBrowser";
10
+ import { joinURL as U, withQuery as I } from "ufo";
11
11
  import { useListenWsClient as j } from "./ws.js";
12
12
  import F from "../Notifications/Snackbar.js";
13
13
  import { compareVersions as H } from "../utils.js";
14
- const v = x(S, "user", "notifications"), K = (r) => U(v, {
14
+ const b = U(V, "user", "notifications"), K = (r) => I(b, {
15
15
  id: r.id,
16
16
  severity: r.severity || "all",
17
17
  componentDid: r.source === "system" ? "system" : r.componentDid || "all"
18
18
  });
19
19
  function P({ session: r = {} }) {
20
- const { unReadCount: b, user: w, setUnReadCount: n } = r, e = s(() => w?.did, [w]), { enqueueSnackbar: E } = B(), c = V(), k = O(() => c.arcSphere || c.wallet, [c]), N = s(() => window.blocklet?.serverVersion, []), t = j("user"), l = s(
20
+ const { unReadCount: c, user: w, setUnReadCount: n } = r, e = s(() => w?.did, [w]), { enqueueSnackbar: E } = D(), l = x(), k = _(() => l.arcSphere || l.wallet, [l]), N = s(() => window.blocklet?.serverVersion, []), t = j("user"), d = s(
21
21
  () => `${window.blocklet.did}/${e}/${y.NOTIFICATION_BLOCKLET_CREATE}`,
22
22
  [e]
23
23
  ), u = s(
24
24
  () => `${window.blocklet.did}/${e}/${y.NOTIFICATION_BLOCKLET_READ}`,
25
25
  [e]
26
- ), d = h(
26
+ ), a = h(
27
27
  (o) => {
28
- const { receivers: m } = o ?? {}, { receiver: f } = m[0] ?? {};
29
- if (f === e) {
30
- n((C) => C + 1);
31
- const p = H(N, "1.16.42-beta-20250407");
32
- if (!k && o.source === "component" && p) {
33
- const C = K(o), { severity: T, description: I } = o || {}, L = ["error", "warning"].includes(T) || o.sticky;
34
- E(I, {
28
+ const { receivers: f } = o ?? {}, { receiver: p } = f[0] ?? {};
29
+ if (p === e) {
30
+ n((v) => v + 1);
31
+ const C = H(N, "1.16.42-beta-20250407");
32
+ if (!k && o.source === "component" && C) {
33
+ const v = K(o), { severity: T, description: L } = o || {}, A = ["error", "warning"].includes(T) || o.sticky;
34
+ E(L, {
35
35
  variant: T,
36
- autoHideDuration: L ? null : 5e3,
36
+ autoHideDuration: A ? null : 5e3,
37
37
  // eslint-disable-next-line react/no-unstable-nested-components
38
- content: (A) => /* @__PURE__ */ i(F, { viewAllUrl: C, keyId: A, notification: o })
38
+ content: (R) => /* @__PURE__ */ i(F, { viewAllUrl: v, keyId: R, notification: o })
39
39
  });
40
40
  }
41
41
  }
42
42
  },
43
43
  [e, n, E, N, k]
44
- ), a = h(
44
+ ), m = h(
45
45
  (o) => {
46
- const { receiver: m, readCount: f } = o ?? {};
47
- m === e && n((p) => Math.max(p - f, 0));
46
+ const { receiver: f, readCount: p } = o ?? {};
47
+ f === e && n((C) => Math.max(C - p, 0));
48
48
  },
49
49
  [e, n]
50
50
  );
51
- return _(() => (t && (t.on(l, d), t.on(u, a)), () => {
52
- t && (t.off(l, d), t.off(u, a));
53
- }), [t, n, d, l, a, u]), !r.user || !v ? null : /* @__PURE__ */ i(
54
- $,
51
+ return $(() => (t && (t.on(d, a), t.on(u, m)), () => {
52
+ t && (t.off(d, a), t.off(u, m));
53
+ }), [t, n, a, d, m, u]), !r.user || !b ? null : /* @__PURE__ */ i(
54
+ g,
55
55
  {
56
56
  size: "medium",
57
57
  variant: "outlined",
58
- href: v,
58
+ href: I(b, { read: c <= 0 }),
59
59
  sx: {
60
60
  "&:hover": {
61
61
  borderRadius: "50%"
62
62
  }
63
63
  },
64
- children: /* @__PURE__ */ i(g, { badgeContent: b, color: "error", invisible: b === 0, children: /* @__PURE__ */ i(D, { style: { width: "auto", height: 24 } }) })
64
+ children: /* @__PURE__ */ i(B, { badgeContent: c, color: "error", invisible: c === 0, children: /* @__PURE__ */ i(S, { style: { width: "auto", height: 24 } }) })
65
65
  }
66
66
  );
67
67
  }
68
68
  P.propTypes = {
69
- session: R.object
69
+ session: O.object
70
70
  };
71
71
  export {
72
72
  P as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "3.0.15",
3
+ "version": "3.0.17",
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.45",
37
37
  "@abtnode/util": "^1.16.45",
38
- "@arcblock/bridge": "3.0.15",
39
- "@arcblock/icons": "3.0.15",
40
- "@arcblock/react-hooks": "3.0.15",
38
+ "@arcblock/bridge": "3.0.17",
39
+ "@arcblock/icons": "3.0.17",
40
+ "@arcblock/react-hooks": "3.0.17",
41
41
  "@arcblock/ws": "^1.20.15",
42
42
  "@blocklet/constant": "^1.16.45",
43
43
  "@blocklet/did-space-react": "^1.1.0",
@@ -90,5 +90,5 @@
90
90
  "jest": "^29.7.0",
91
91
  "unbuild": "^2.0.0"
92
92
  },
93
- "gitHead": "56670fd3ff4223fcdaaf1b38eb2e993217344328"
93
+ "gitHead": "4c0ab1335d46f38cc05e804c6ae099dfd6fa9ad8"
94
94
  }
@@ -151,6 +151,7 @@ export type Session = {
151
151
  refresh: Function;
152
152
  useOAuth: Function;
153
153
  usePasskey: Function;
154
+ withSecondaryAuth: Function;
154
155
  };
155
156
 
156
157
  export type WebhookType = 'slack' | 'api';
@@ -2,103 +2,45 @@ import { use } from 'react';
2
2
  import { Box, Button, Typography } from '@mui/material';
3
3
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
4
  import { translate } from '@arcblock/ux/lib/Locale/util';
5
- import { useCreation, useMemoizedFn } from 'ahooks';
5
+ import { useMemoizedFn } from 'ahooks';
6
6
  import { useConfirm } from '@arcblock/ux/lib/Dialog';
7
7
  import { SessionContext } from '@arcblock/did-connect/lib/Session';
8
- import { LOGIN_PROVIDER } from '@blocklet/constant';
9
8
  import Toast from '@arcblock/ux/lib/Toast';
10
- import type { ConnectProps } from '@arcblock/did-connect/lib/types';
11
9
 
12
10
  import { translations } from '../libs/locales';
13
- import { client } from '../../libs/client';
14
11
  import type { SessionContext as TSessionContext } from '../../@types';
15
12
 
16
- export default function DangerZone() {
17
- const { confirmApi, confirmHolder } = useConfirm();
13
+ export default function DangerZone({ onDestroySelf = undefined }: { onDestroySelf?: () => void }) {
14
+ const { confirmHolder } = useConfirm();
18
15
 
19
16
  const { locale } = useLocaleContext();
20
- const { session, connectApi } = use<TSessionContext>(SessionContext);
17
+ const { session } = use<TSessionContext>(SessionContext);
21
18
  const t = useMemoizedFn((key, data = {}) => {
22
19
  return translate(translations, key, locale, 'en', data);
23
20
  });
24
- const isNeedVerify = useCreation(() => {
25
- if (['true', true].includes(window?.blocklet?.ALLOW_SKIP_DESTROY_MYSELF_VERIFY)) {
26
- return false;
27
- }
28
- const connectedAccounts = session?.user?.connectedAccounts || [];
29
- const ALLOW_VERIFY_PROVIDERS = [LOGIN_PROVIDER.WALLET];
30
- if (connectedAccounts.some((x) => ALLOW_VERIFY_PROVIDERS.includes(x.provider))) {
31
- return true;
32
- }
33
21
 
34
- return false;
35
- }, [session?.user]);
22
+ const handleRemoveMyself = useMemoizedFn(async () => {
23
+ if (!onDestroySelf || typeof onDestroySelf !== 'function') {
24
+ return;
25
+ }
36
26
 
37
- const handleVerify = useMemoizedFn(() => {
38
- return new Promise<{ did: string }>((resolve, reject) => {
39
- const userDid = session?.user?.did;
40
- connectApi.open({
41
- locale: locale as ConnectProps['locale'],
42
- action: 'destroy-myself',
43
- forceConnected: true,
44
- saveConnect: false,
45
- autoConnect: false,
46
- // 暂不允许使用 passkey 进行验证
47
- passkeyBehavior: 'none',
48
- extraParams: {
49
- removeUserDid: userDid,
50
- },
51
- messages: {
52
- title: t('destroyMyself.title'),
53
- scan: t('destroyMyself.scan'),
54
- confirm: t('destroyMyself.confirm'),
55
- success: t('destroyMyself.success'),
56
- },
57
- // @ts-expect-error 该 did-connect 后端api 将结果塞在了 result 中,并做了加密,所以已经变成一个字符串了
58
- onSuccess: ({ result }: { result: string }, decrypt = (x: string) => x) => {
59
- const decryptResult = decrypt(result) as unknown as { did: string };
60
- resolve(decryptResult);
61
- },
62
- onClose: () => {
63
- connectApi.close();
64
- reject(new Error(t('destroyMyself.abort')));
27
+ const handle = session.withSecondaryAuth(onDestroySelf, {
28
+ extraParams: {
29
+ locale,
30
+ removeUserDid: session?.user?.did,
31
+ input: {
32
+ user: { did: session?.user?.did },
33
+ teamDid: window?.blocklet?.did,
65
34
  },
66
- });
67
- });
68
- });
69
-
70
- const handleDeleteAccount = useMemoizedFn(() => {
71
- confirmApi.open({
72
- title: t('dangerZone.deleteAccount'),
73
- content: t('dangerZone.deleteAccountDescription'),
74
- confirmButtonText: t('common.confirm'),
75
- confirmButtonProps: {
76
- color: 'error',
77
- },
78
- cancelButtonText: t('common.cancel'),
79
- async onConfirm(close: () => void) {
80
- let result;
81
- try {
82
- if (isNeedVerify) {
83
- result = await handleVerify();
84
- } else if (client?.user?.destroyMyself instanceof Function) {
85
- result = await client.user.destroyMyself();
86
- } else {
87
- Toast.error(t('notImplemented'));
88
- return;
89
- }
90
- if (result?.did === session?.user?.did) {
91
- // TODO: 前端执行退出等清理操作
92
- session.logout(close);
93
- } else {
94
- Toast.error(t('destroyMyself.error'));
95
- }
96
- } catch (error: any) {
97
- const errorMessage = error?.response?.data.error || error?.message || t('destroyMyself.error');
98
- Toast.error(errorMessage);
99
- }
100
35
  },
36
+ operation: 'destroySelf',
101
37
  });
38
+ try {
39
+ await handle();
40
+ session.logout();
41
+ } catch (error: any) {
42
+ Toast.error(error?.message || t('destroyMyself.error'));
43
+ }
102
44
  });
103
45
 
104
46
  return (
@@ -129,7 +71,7 @@ export default function DangerZone() {
129
71
  {t('dangerZone.deleteAccountDescription')}
130
72
  </Typography>
131
73
  </Box>
132
- <Button variant="contained" color="error" size="small" onClick={handleDeleteAccount}>
74
+ <Button variant="contained" color="error" size="small" onClick={handleRemoveMyself}>
133
75
  {t('dangerZone.delete')}
134
76
  </Button>
135
77
  </Box>
@@ -1,6 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import { Box, Typography } from '@mui/material';
3
3
  import type { BoxProps } from '@mui/material';
4
+ import { ROLES } from '@abtnode/constant';
4
5
  import { useCreation, useMemoizedFn } from 'ahooks';
5
6
  import { translate } from '@arcblock/ux/lib/Locale/util';
6
7
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
@@ -29,6 +30,7 @@ export default function Settings({
29
30
  userCenterTabs: UserCenterTab[];
30
31
  };
31
32
  isMobile: boolean;
33
+ onDestroySelf?: () => void;
32
34
  } & BoxProps) {
33
35
  const { locale } = useLocaleContext();
34
36
  const browser = useBrowser();
@@ -36,6 +38,11 @@ export default function Settings({
36
38
  const t = useMemoizedFn((key, data = {}) => {
37
39
  return translate(translations, key, locale, 'en', data);
38
40
  });
41
+
42
+ const isOwner = useCreation(() => {
43
+ return user.passports?.some((x) => x.role === ROLES.OWNER);
44
+ }, [user]);
45
+
39
46
  const privacyConfigList = useCreation(() => {
40
47
  const userCenterTabs = settings?.userCenterTabs || [];
41
48
  return userCenterTabs.map((item) => {
@@ -84,14 +91,16 @@ export default function Settings({
84
91
  />
85
92
  ),
86
93
  },
87
- {
88
- label: t('dangerZone.title'),
89
- value: 'dangerZone',
90
- content: <DangerZone />,
91
- sx: {
92
- borderColor: 'error.main',
93
- },
94
- },
94
+ !isOwner && rest.onDestroySelf && typeof rest.onDestroySelf === 'function'
95
+ ? {
96
+ label: t('dangerZone.title'),
97
+ value: 'dangerZone',
98
+ content: <DangerZone onDestroySelf={rest.onDestroySelf} />,
99
+ sx: {
100
+ borderColor: 'error.main',
101
+ },
102
+ }
103
+ : null,
95
104
  ].filter(Boolean);
96
105
  }, [user, privacyConfigList, isMobile]);
97
106
 
@@ -90,6 +90,7 @@ export default function UserCenter({
90
90
  stickySidebar = false,
91
91
  embed = false,
92
92
  onlyProfile = false, // 只显示 profile 页面,用于 ArcSphere 只需要显示 Profile 的内容
93
+ onDestroySelf = undefined,
93
94
  }: {
94
95
  readonly children: any;
95
96
  readonly notLoginContent?: any;
@@ -105,6 +106,7 @@ export default function UserCenter({
105
106
  readonly stickySidebar?: boolean;
106
107
  readonly embed?: boolean;
107
108
  readonly onlyProfile?: boolean;
109
+ readonly onDestroySelf?: () => void;
108
110
  }) {
109
111
  const { locale } = useLocaleContext();
110
112
  const isMobile = useMobile({ key: 'md' });
@@ -287,6 +289,7 @@ export default function UserCenter({
287
289
  return null;
288
290
  }}
289
291
  isMobile={isMobile}
292
+ onDestroySelf={onDestroySelf}
290
293
  />
291
294
  );
292
295
  }, [userState.data, userCenterTabs, privacyState.data, privacyState.runAsync]);
@@ -523,12 +526,13 @@ export default function UserCenter({
523
526
  tabs={userCenterTabs}
524
527
  current={currentActiveTab?.value ?? currentTab}
525
528
  onChange={handleChangeTab}
529
+ enableTabClick
526
530
  sx={{
527
531
  mb: 2,
528
532
  '.MuiTabs-flexContainer': {
529
533
  gap: 3,
530
534
  '.MuiButtonBase-root': {
531
- padding: isMobile ? '16px 4px' : '40px 4px 32px 4px',
535
+ padding: isMobile ? '16px 4px' : '32px 4px 16px 4px',
532
536
  fontSize: 16,
533
537
  },
534
538
  '.MuiTab-root': {
@@ -107,7 +107,7 @@ export default function NotificationAddon({ session = {} }) {
107
107
  <IconButton
108
108
  size="medium"
109
109
  variant="outlined"
110
- href={viewAllUrl}
110
+ href={withQuery(viewAllUrl, { read: unReadCount <= 0 })}
111
111
  sx={{
112
112
  '&:hover': {
113
113
  borderRadius: '50%',