@arcblock/did-connect-react 3.2.0 → 3.2.2
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/OAuth/bind-conflict-alert.js +29 -0
- package/lib/OAuth/context.js +163 -130
- package/lib/package.json.js +1 -1
- package/package.json +8 -8
- package/src/OAuth/bind-conflict-alert.jsx +37 -0
- package/src/OAuth/context.jsx +45 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsxs as s, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as a } from "react";
|
|
3
|
+
import { Box as d, Typography as m } from "@mui/material";
|
|
4
|
+
import p from "prop-types";
|
|
5
|
+
import c from "@arcblock/ux/lib/UserCard";
|
|
6
|
+
import { withQuery as l, joinURL as f } from "ufo";
|
|
7
|
+
import { useMemoizedFn as u } from "ahooks";
|
|
8
|
+
import { BLOCKLET_SERVICE_PATH_PREFIX as x } from "../constant.js";
|
|
9
|
+
function h({ data: e }) {
|
|
10
|
+
const { message: i, data: o } = e, t = a(() => new URLSearchParams(window.location.search).get("locale") || "en", []), n = u(() => {
|
|
11
|
+
window.open(
|
|
12
|
+
l(f(x, "user"), {
|
|
13
|
+
locale: t,
|
|
14
|
+
did: o.did
|
|
15
|
+
}),
|
|
16
|
+
"_blank"
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
return /* @__PURE__ */ s(d, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
20
|
+
/* @__PURE__ */ r(m, { sx: { fontSize: 14, color: "text.secondary" }, children: i }),
|
|
21
|
+
/* @__PURE__ */ r(c, { showDid: !0, did: o.did, onAvatarClick: n })
|
|
22
|
+
] });
|
|
23
|
+
}
|
|
24
|
+
h.propTypes = {
|
|
25
|
+
data: p.object.isRequired
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
h as default
|
|
29
|
+
};
|
package/lib/OAuth/context.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { createContext as
|
|
5
|
-
import
|
|
6
|
-
import { useReactive as
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { joinURL as
|
|
10
|
-
import { translate as
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
1
|
+
import { jsxs as J, jsx as E } from "react/jsx-runtime";
|
|
2
|
+
import h from "prop-types";
|
|
3
|
+
import Q from "lodash/isUndefined";
|
|
4
|
+
import { createContext as Z, use as ee } from "react";
|
|
5
|
+
import l from "@arcblock/ux/lib/Toast";
|
|
6
|
+
import { useReactive as v, useMemoizedFn as u, useCreation as te, useLatest as oe } from "ahooks";
|
|
7
|
+
import O from "lodash/noop";
|
|
8
|
+
import B from "lodash/omit";
|
|
9
|
+
import { joinURL as re } from "ufo";
|
|
10
|
+
import { translate as ne } from "@arcblock/ux/lib/Locale/util";
|
|
11
|
+
import ie from "@arcblock/ux/lib/Dialog/use-confirm";
|
|
12
|
+
import { getBlockletData as S, getFederatedEnabled as C, getMaster as R } from "@arcblock/ux/lib/Util/federated";
|
|
13
|
+
import { BLOCKLET_SERVICE_PATH_PREFIX as F, LOGIN_PROVIDER_NAME as f } from "@arcblock/ux/lib/Util/constant";
|
|
14
|
+
import { createAxios as se, openPopup as ae, runPopup as de, sleep as ce, getApiErrorMessage as m } from "../utils.js";
|
|
15
|
+
import { parseResponse as ue, PassportSwitcher as le } from "../components/PassportSwitcher.js";
|
|
16
|
+
import pe from "../Session/hooks/use-mobile.js";
|
|
17
|
+
import he from "./bind-conflict-alert.js";
|
|
18
|
+
const D = Z({}), { Provider: fe, Consumer: Te } = D, k = `${F}/api/oauth`, be = {
|
|
16
19
|
zh: {
|
|
17
20
|
bindOAuth: "绑定第三方登录",
|
|
18
21
|
bind: "绑定",
|
|
@@ -24,7 +27,10 @@ const E = $({}), { Provider: de, Consumer: Le } = E, C = `${B}/api/oauth`, ce =
|
|
|
24
27
|
unbindOAuthFailed: "绑定 {provider} 失败",
|
|
25
28
|
loginRequired: "授权请求被拒绝",
|
|
26
29
|
cancelAuth: "取消授权",
|
|
27
|
-
noPassports: "没有可更换的通行证"
|
|
30
|
+
noPassports: "没有可更换的通行证",
|
|
31
|
+
confirm: "我知道了",
|
|
32
|
+
ALREADY_EXIST: "当前账户已存在",
|
|
33
|
+
ALREADY_BIND: "当前账户绑定过 {provider}"
|
|
28
34
|
},
|
|
29
35
|
en: {
|
|
30
36
|
bindOAuth: "Bind third party login",
|
|
@@ -37,31 +43,41 @@ const E = $({}), { Provider: de, Consumer: Le } = E, C = `${B}/api/oauth`, ce =
|
|
|
37
43
|
unbindOAuthFailed: "Unbind {provider} failed",
|
|
38
44
|
loginRequired: "You have declined the authentication request",
|
|
39
45
|
cancelAuth: "Cancel authentication",
|
|
40
|
-
noPassports: "No passports to switch"
|
|
46
|
+
noPassports: "No passports to switch",
|
|
47
|
+
confirm: "I know",
|
|
48
|
+
ALREADY_EXIST: "Your account already exists",
|
|
49
|
+
ALREADY_BIND: "Your account is already bind to {provider}"
|
|
41
50
|
}
|
|
42
51
|
};
|
|
43
|
-
function
|
|
52
|
+
function Ae({
|
|
44
53
|
children: w,
|
|
45
54
|
locale: p = "en",
|
|
46
|
-
onBindOAuth: T =
|
|
47
|
-
onUnbindOAuth:
|
|
48
|
-
onSwitchPassport:
|
|
49
|
-
session:
|
|
55
|
+
onBindOAuth: T = O,
|
|
56
|
+
onUnbindOAuth: _ = O,
|
|
57
|
+
onSwitchPassport: I = O,
|
|
58
|
+
session: Y = null
|
|
50
59
|
}) {
|
|
51
|
-
const
|
|
60
|
+
const x = pe(), { confirmApi: M, confirmHolder: N } = ie({
|
|
61
|
+
maxWidth: !1,
|
|
62
|
+
PaperProps: {
|
|
63
|
+
style: {
|
|
64
|
+
minWidth: x ? "100%" : 600
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}), r = v({
|
|
52
68
|
baseUrl: "/",
|
|
53
69
|
bindFnSession: void 0,
|
|
54
70
|
bindAuthLoading: !1,
|
|
55
71
|
unbindAuthLoading: !1
|
|
56
|
-
}),
|
|
72
|
+
}), c = v({
|
|
57
73
|
open: !1,
|
|
58
74
|
currentUser: null,
|
|
59
75
|
passports: [],
|
|
60
76
|
selectedPassport: void 0,
|
|
61
77
|
reset() {
|
|
62
|
-
|
|
78
|
+
c.open = !1, c.currentUser = null, c.passports = [], c.selectedPassport = void 0;
|
|
63
79
|
}
|
|
64
|
-
}), b =
|
|
80
|
+
}), b = v({
|
|
65
81
|
user: null,
|
|
66
82
|
// loginLoading: false,
|
|
67
83
|
checking: !1,
|
|
@@ -72,172 +88,189 @@ function ue({
|
|
|
72
88
|
reset({ status: t = "" } = {}) {
|
|
73
89
|
b.loading = !!t, b.checking = !1, b.error = "", b.status = t;
|
|
74
90
|
}
|
|
75
|
-
}),
|
|
91
|
+
}), i = u((t, e = {}) => ne(be, t, p, "en", e)), j = te(() => se({
|
|
76
92
|
// NOTICE: 请求必须向当前站点发起
|
|
77
|
-
baseURL:
|
|
78
|
-
}), [
|
|
79
|
-
if (
|
|
93
|
+
baseURL: k
|
|
94
|
+
}), [r.baseUrl, k]), A = oe(j), P = u(async () => {
|
|
95
|
+
if (r.baseUrl === "/")
|
|
80
96
|
return window.blocklet;
|
|
81
97
|
try {
|
|
82
|
-
if (new URL(
|
|
98
|
+
if (new URL(r.baseUrl).host === window.location.host)
|
|
83
99
|
return window.blocklet;
|
|
84
100
|
} catch {
|
|
85
101
|
}
|
|
86
|
-
return await S(
|
|
87
|
-
}), U =
|
|
88
|
-
const e = await P(),
|
|
89
|
-
return
|
|
90
|
-
}),
|
|
102
|
+
return await S(r.baseUrl);
|
|
103
|
+
}), U = u(async ({ sourceAppPid: t } = {}) => {
|
|
104
|
+
const e = await P(), o = C(e), n = R(e);
|
|
105
|
+
return o && n?.appPid && t === n?.appPid ? (await S(n.appUrl))?.settings?.oauth || {} : e?.settings?.oauth || {};
|
|
106
|
+
}), X = u(async ({ sourceAppPid: t } = {}) => {
|
|
91
107
|
const e = await U({ sourceAppPid: t });
|
|
92
|
-
return Object.entries(e).map(([n,
|
|
93
|
-
}),
|
|
94
|
-
const e = re(
|
|
108
|
+
return Object.entries(e).map(([n, a]) => ({ ...a, provider: n })).filter((n) => n.enabled).sort((n, a) => n?.order !== void 0 && a?.order !== void 0 ? n.order - a.order : n?.order !== void 0 ? -1 : 1);
|
|
109
|
+
}), L = u(async ({ provider: t } = {}) => {
|
|
110
|
+
const e = ae(re(r.baseUrl, F, "/oauth/login", t), {
|
|
95
111
|
name: "oauth-login:popup",
|
|
96
112
|
offsetX: 650,
|
|
97
113
|
height: 700,
|
|
98
114
|
width: 500
|
|
99
115
|
});
|
|
100
116
|
try {
|
|
101
|
-
const
|
|
117
|
+
const o = await de({
|
|
102
118
|
popup: e,
|
|
103
119
|
closeTimeout: 0
|
|
104
120
|
});
|
|
105
|
-
return
|
|
106
|
-
} catch (
|
|
107
|
-
throw
|
|
121
|
+
return o?.response ? o.response?.code : null;
|
|
122
|
+
} catch (o) {
|
|
123
|
+
throw o?.message === "Popup closed" ? new Error(i("cancelAuth")) : o;
|
|
108
124
|
}
|
|
109
|
-
}),
|
|
110
|
-
|
|
125
|
+
}), q = async ({ session: t, oauthItem: e } = {}) => {
|
|
126
|
+
r.bindFnSession = t, r.bindAuthLoading = !0;
|
|
111
127
|
try {
|
|
112
|
-
const
|
|
113
|
-
await
|
|
128
|
+
const o = await L(e), n = r.bindFnSession?.user?.sourceAppPid;
|
|
129
|
+
await A.current.post("/bind", {
|
|
114
130
|
locale: p,
|
|
115
131
|
provider: e.provider,
|
|
116
|
-
code:
|
|
132
|
+
code: o,
|
|
117
133
|
sourceAppPid: n
|
|
118
|
-
}),
|
|
119
|
-
} catch (
|
|
120
|
-
|
|
134
|
+
}), l.success(i("bindOAuthSucceed", { provider: f[e.provider] })), T(e);
|
|
135
|
+
} catch (o) {
|
|
136
|
+
if (o.response?.status === 409) {
|
|
137
|
+
const { data: a = {} } = o.response || {}, { code: d } = a || {};
|
|
138
|
+
["ALREADY_EXIST", "ALREADY_BIND"].includes(d) ? M.open({
|
|
139
|
+
title: i(d, { provider: e.provider }),
|
|
140
|
+
showCancelButton: !1,
|
|
141
|
+
confirmButtonText: i("confirm"),
|
|
142
|
+
content: /* @__PURE__ */ E(he, { data: a }),
|
|
143
|
+
onConfirm(s) {
|
|
144
|
+
s();
|
|
145
|
+
}
|
|
146
|
+
}) : l.error(
|
|
147
|
+
m(o, i("bindOAuthFailed", { provider: f[e.provider] }))
|
|
148
|
+
);
|
|
149
|
+
} else
|
|
150
|
+
l.error(
|
|
151
|
+
m(o, i("bindOAuthFailed", { provider: f[e.provider] }))
|
|
152
|
+
);
|
|
121
153
|
} finally {
|
|
122
|
-
|
|
154
|
+
r.bindAuthLoading = !1;
|
|
123
155
|
}
|
|
124
|
-
},
|
|
125
|
-
|
|
156
|
+
}, W = async ({ session: t, connectedAccount: e }) => {
|
|
157
|
+
r.unbindAuthLoading = !0;
|
|
126
158
|
try {
|
|
127
|
-
const
|
|
128
|
-
await
|
|
159
|
+
const o = t?.user?.sourceAppPid;
|
|
160
|
+
await A.current.post("/unbind", {
|
|
129
161
|
locale: p,
|
|
130
|
-
connectedAccount:
|
|
131
|
-
sourceAppPid:
|
|
132
|
-
}),
|
|
133
|
-
|
|
134
|
-
provider:
|
|
162
|
+
connectedAccount: B(e, ["showProvider"]),
|
|
163
|
+
sourceAppPid: o
|
|
164
|
+
}), l.success(
|
|
165
|
+
i("unbindOAuthSucceed", {
|
|
166
|
+
provider: f[e.showProvider || e.provider]
|
|
135
167
|
})
|
|
136
|
-
),
|
|
137
|
-
} catch (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
provider:
|
|
168
|
+
), _(e);
|
|
169
|
+
} catch (o) {
|
|
170
|
+
l.error(
|
|
171
|
+
m(
|
|
172
|
+
o,
|
|
173
|
+
i("unbindOAuthFailed", {
|
|
174
|
+
provider: f[e.showProvider || e.provider]
|
|
143
175
|
})
|
|
144
176
|
)
|
|
145
177
|
);
|
|
146
178
|
} finally {
|
|
147
|
-
|
|
179
|
+
r.unbindAuthLoading = !1;
|
|
148
180
|
}
|
|
149
|
-
},
|
|
181
|
+
}, z = async (t = {}) => {
|
|
150
182
|
try {
|
|
151
|
-
const { data: e } = await
|
|
152
|
-
e.length > 0 ? (
|
|
183
|
+
const { data: e } = await A.current.get("/passports");
|
|
184
|
+
e.length > 0 ? (c.open = !0, c.currentUser = t, c.passports = e || []) : l.error(i("noPassports"));
|
|
153
185
|
} catch (e) {
|
|
154
|
-
|
|
186
|
+
l.error(e.message || i("getPassportFailed"));
|
|
155
187
|
}
|
|
156
|
-
},
|
|
157
|
-
|
|
188
|
+
}, H = u((...t) => {
|
|
189
|
+
c.reset(), I(...t);
|
|
158
190
|
}), V = (t) => {
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
const n =
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
else if (
|
|
165
|
-
const
|
|
166
|
-
|
|
191
|
+
r.baseUrl = t || "/";
|
|
192
|
+
}, G = u(async ({ provider: t } = {}, { action: e = "login", ...o } = {}) => {
|
|
193
|
+
const n = r.baseUrl;
|
|
194
|
+
if (o?.sourceAppPid === window.blocklet?.appPid)
|
|
195
|
+
r.baseUrl = window.blocklet?.appUrl || "/";
|
|
196
|
+
else if (o?.sourceAppPid) {
|
|
197
|
+
const d = await P(), s = C(d), g = R(d);
|
|
198
|
+
s && g?.appPid && o?.sourceAppPid === g?.appPid && (r.baseUrl = g.appUrl);
|
|
167
199
|
}
|
|
168
|
-
const
|
|
200
|
+
const a = window?.blocklet?.componentId;
|
|
169
201
|
try {
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
172
|
-
const
|
|
173
|
-
...
|
|
202
|
+
const d = await L({ provider: t });
|
|
203
|
+
if (r.baseUrl = n, await ce(100), d) {
|
|
204
|
+
const s = {
|
|
205
|
+
...o,
|
|
174
206
|
action: e,
|
|
175
207
|
locale: p,
|
|
176
|
-
code:
|
|
208
|
+
code: d,
|
|
177
209
|
provider: t,
|
|
178
|
-
componentId:
|
|
210
|
+
componentId: a
|
|
179
211
|
};
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
return
|
|
212
|
+
Q(s.inviter) && window.localStorage.getItem("inviter") && (s.inviter = window.localStorage.getItem("inviter"));
|
|
213
|
+
const g = ["connect-to-did-space", "connect-to-did-domain"].includes(s.action) ? "login" : s.action, { data: $ } = await A.current.post("/login", { ...s, action: g }), y = ue($);
|
|
214
|
+
return y.provider = t, y;
|
|
183
215
|
}
|
|
184
|
-
return
|
|
185
|
-
} catch (
|
|
186
|
-
const
|
|
187
|
-
throw
|
|
216
|
+
return r.baseUrl = n, null;
|
|
217
|
+
} catch (d) {
|
|
218
|
+
const s = m(d, i("loginOAuthFailed", { provider: f[t] }));
|
|
219
|
+
throw r.baseUrl = n, new Error(s);
|
|
188
220
|
}
|
|
189
|
-
}),
|
|
221
|
+
}), K = u(() => {
|
|
190
222
|
});
|
|
191
|
-
return /* @__PURE__ */
|
|
192
|
-
|
|
223
|
+
return /* @__PURE__ */ J(
|
|
224
|
+
fe,
|
|
193
225
|
{
|
|
194
226
|
value: {
|
|
195
227
|
locale: p,
|
|
196
228
|
getOAuthConfigs: U,
|
|
197
|
-
getOAuthConfigList:
|
|
198
|
-
bindOAuth:
|
|
199
|
-
unbindOAuth:
|
|
200
|
-
loginOAuth:
|
|
201
|
-
logoutOAuth:
|
|
202
|
-
switchOAuthPassport:
|
|
203
|
-
baseUrl:
|
|
229
|
+
getOAuthConfigList: X,
|
|
230
|
+
bindOAuth: q,
|
|
231
|
+
unbindOAuth: W,
|
|
232
|
+
loginOAuth: G,
|
|
233
|
+
logoutOAuth: K,
|
|
234
|
+
switchOAuthPassport: z,
|
|
235
|
+
baseUrl: r.baseUrl,
|
|
204
236
|
setBaseUrl: V,
|
|
205
237
|
oauthState: b,
|
|
206
|
-
unbindAuthLoading:
|
|
207
|
-
bindAuthLoading:
|
|
208
|
-
t:
|
|
238
|
+
unbindAuthLoading: r.unbindAuthLoading,
|
|
239
|
+
bindAuthLoading: r.bindAuthLoading,
|
|
240
|
+
t: i
|
|
209
241
|
},
|
|
210
242
|
children: [
|
|
211
243
|
w,
|
|
212
|
-
|
|
213
|
-
|
|
244
|
+
N,
|
|
245
|
+
/* @__PURE__ */ E(
|
|
246
|
+
le,
|
|
214
247
|
{
|
|
215
|
-
api:
|
|
248
|
+
api: A.current,
|
|
216
249
|
locale: p,
|
|
217
|
-
switchState:
|
|
218
|
-
onSwitchPassport:
|
|
219
|
-
session:
|
|
250
|
+
switchState: c,
|
|
251
|
+
onSwitchPassport: H,
|
|
252
|
+
session: Y
|
|
220
253
|
}
|
|
221
254
|
)
|
|
222
255
|
]
|
|
223
256
|
}
|
|
224
257
|
);
|
|
225
258
|
}
|
|
226
|
-
function
|
|
227
|
-
const w =
|
|
228
|
-
return
|
|
259
|
+
function _e() {
|
|
260
|
+
const w = ee(D);
|
|
261
|
+
return B(w, ["locale", "getToken"]);
|
|
229
262
|
}
|
|
230
|
-
|
|
231
|
-
children:
|
|
232
|
-
locale:
|
|
233
|
-
onBindOAuth:
|
|
234
|
-
onUnbindOAuth:
|
|
235
|
-
onSwitchPassport:
|
|
236
|
-
session:
|
|
263
|
+
Ae.propTypes = {
|
|
264
|
+
children: h.node.isRequired,
|
|
265
|
+
locale: h.string,
|
|
266
|
+
onBindOAuth: h.func,
|
|
267
|
+
onUnbindOAuth: h.func,
|
|
268
|
+
onSwitchPassport: h.func,
|
|
269
|
+
session: h.object
|
|
237
270
|
};
|
|
238
271
|
export {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
272
|
+
Te as OAuthConsumer,
|
|
273
|
+
D as OAuthContext,
|
|
274
|
+
Ae as OAuthProvider,
|
|
275
|
+
_e as useOAuth
|
|
243
276
|
};
|
package/lib/package.json.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/did-connect-react",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "Client side library to work with DID Connect by ArcBlock.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"url": "https://github.com/ArcBlock/ux/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@arcblock/bridge": "3.2.
|
|
36
|
-
"@arcblock/did": "^1.27.
|
|
37
|
-
"@arcblock/icons": "3.2.
|
|
38
|
-
"@arcblock/react-hooks": "3.2.
|
|
39
|
-
"@arcblock/ws": "^1.27.
|
|
35
|
+
"@arcblock/bridge": "3.2.2",
|
|
36
|
+
"@arcblock/did": "^1.27.3",
|
|
37
|
+
"@arcblock/icons": "3.2.2",
|
|
38
|
+
"@arcblock/react-hooks": "3.2.2",
|
|
39
|
+
"@arcblock/ws": "^1.27.3",
|
|
40
40
|
"@fontsource/lexend": "^5.2.9",
|
|
41
41
|
"@iconify-icons/logos": "^1.2.36",
|
|
42
42
|
"@iconify-icons/material-symbols": "^1.2.58",
|
|
43
43
|
"@iconify/react": "^5.2.1",
|
|
44
|
-
"@ocap/util": "^1.27.
|
|
44
|
+
"@ocap/util": "^1.27.3",
|
|
45
45
|
"@simplewebauthn/browser": "^13.1.0",
|
|
46
46
|
"ahooks": "^3.8.5",
|
|
47
47
|
"axios": "^1.10.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"eslint-plugin-react-hooks": "^4.6.2",
|
|
81
81
|
"jest": "^29.7.0"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "d6da30f57d7f5f855462aa75b4189fb8be48fecc"
|
|
84
84
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { Box, Typography } from '@mui/material';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import UserCard from '@arcblock/ux/lib/UserCard';
|
|
5
|
+
import { joinURL, withQuery } from 'ufo';
|
|
6
|
+
import { useMemoizedFn } from 'ahooks';
|
|
7
|
+
|
|
8
|
+
import { BLOCKLET_SERVICE_PATH_PREFIX } from '../constant';
|
|
9
|
+
|
|
10
|
+
export default function BindConflictAlert({ data }) {
|
|
11
|
+
const { message, data: userInfo } = data;
|
|
12
|
+
|
|
13
|
+
const locale = useMemo(() => {
|
|
14
|
+
return new URLSearchParams(window.location.search).get('locale') || 'en';
|
|
15
|
+
}, []);
|
|
16
|
+
|
|
17
|
+
const visitUser = useMemoizedFn(() => {
|
|
18
|
+
window.open(
|
|
19
|
+
withQuery(joinURL(BLOCKLET_SERVICE_PATH_PREFIX, 'user'), {
|
|
20
|
+
locale,
|
|
21
|
+
did: userInfo.did,
|
|
22
|
+
}),
|
|
23
|
+
'_blank'
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
29
|
+
<Typography sx={{ fontSize: 14, color: 'text.secondary' }}>{message}</Typography>
|
|
30
|
+
<UserCard showDid did={userInfo.did} onAvatarClick={visitUser} />
|
|
31
|
+
</Box>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
BindConflictAlert.propTypes = {
|
|
36
|
+
data: PropTypes.object.isRequired,
|
|
37
|
+
};
|
package/src/OAuth/context.jsx
CHANGED
|
@@ -7,6 +7,7 @@ import noop from 'lodash/noop';
|
|
|
7
7
|
import omit from 'lodash/omit';
|
|
8
8
|
import { joinURL } from 'ufo';
|
|
9
9
|
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
10
|
+
import useConfirm from '@arcblock/ux/lib/Dialog/use-confirm';
|
|
10
11
|
import { getFederatedEnabled, getMaster, getBlockletData } from '@arcblock/ux/lib/Util/federated';
|
|
11
12
|
import { LOGIN_PROVIDER_NAME, BLOCKLET_SERVICE_PATH_PREFIX } from '@arcblock/ux/lib/Util/constant';
|
|
12
13
|
|
|
@@ -14,6 +15,9 @@ import { LOGIN_PROVIDER_NAME, BLOCKLET_SERVICE_PATH_PREFIX } from '@arcblock/ux/
|
|
|
14
15
|
import { getApiErrorMessage, createAxios, openPopup, runPopup, sleep } from '../utils';
|
|
15
16
|
import { PassportSwitcher, parseResponse } from '../components/PassportSwitcher';
|
|
16
17
|
|
|
18
|
+
import useMobile from '../Session/hooks/use-mobile';
|
|
19
|
+
import BindConflictAlert from './bind-conflict-alert';
|
|
20
|
+
|
|
17
21
|
const OAuthContext = createContext({});
|
|
18
22
|
const { Provider, Consumer: OAuthConsumer } = OAuthContext;
|
|
19
23
|
|
|
@@ -32,6 +36,9 @@ const translations = {
|
|
|
32
36
|
loginRequired: '授权请求被拒绝',
|
|
33
37
|
cancelAuth: '取消授权',
|
|
34
38
|
noPassports: '没有可更换的通行证',
|
|
39
|
+
confirm: '我知道了',
|
|
40
|
+
ALREADY_EXIST: '当前账户已存在',
|
|
41
|
+
ALREADY_BIND: '当前账户绑定过 {provider}',
|
|
35
42
|
},
|
|
36
43
|
en: {
|
|
37
44
|
bindOAuth: 'Bind third party login',
|
|
@@ -45,6 +52,9 @@ const translations = {
|
|
|
45
52
|
loginRequired: 'You have declined the authentication request',
|
|
46
53
|
cancelAuth: 'Cancel authentication',
|
|
47
54
|
noPassports: 'No passports to switch',
|
|
55
|
+
confirm: 'I know',
|
|
56
|
+
ALREADY_EXIST: 'Your account already exists',
|
|
57
|
+
ALREADY_BIND: 'Your account is already bind to {provider}',
|
|
48
58
|
},
|
|
49
59
|
};
|
|
50
60
|
|
|
@@ -56,6 +66,15 @@ function OAuthProvider({
|
|
|
56
66
|
onSwitchPassport = noop,
|
|
57
67
|
session = null,
|
|
58
68
|
}) {
|
|
69
|
+
const isMobile = useMobile();
|
|
70
|
+
const { confirmApi, confirmHolder } = useConfirm({
|
|
71
|
+
maxWidth: false,
|
|
72
|
+
PaperProps: {
|
|
73
|
+
style: {
|
|
74
|
+
minWidth: isMobile ? '100%' : 600,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
59
78
|
const state = useReactive({
|
|
60
79
|
baseUrl: '/',
|
|
61
80
|
bindFnSession: undefined,
|
|
@@ -189,7 +208,31 @@ function OAuthProvider({
|
|
|
189
208
|
Toast.success(t('bindOAuthSucceed', { provider: LOGIN_PROVIDER_NAME[oauthItem.provider] }));
|
|
190
209
|
onBindOAuth(oauthItem);
|
|
191
210
|
} catch (err) {
|
|
192
|
-
|
|
211
|
+
// 对已存在的错误类型特殊处理
|
|
212
|
+
const statusCode = err.response?.status;
|
|
213
|
+
if (statusCode === 409) {
|
|
214
|
+
const { data = {} } = err.response || {};
|
|
215
|
+
const { code } = data || {};
|
|
216
|
+
if (['ALREADY_EXIST', 'ALREADY_BIND'].includes(code)) {
|
|
217
|
+
confirmApi.open({
|
|
218
|
+
title: t(code, { provider: oauthItem.provider }),
|
|
219
|
+
showCancelButton: false,
|
|
220
|
+
confirmButtonText: t('confirm'),
|
|
221
|
+
content: <BindConflictAlert data={data} />,
|
|
222
|
+
onConfirm(close) {
|
|
223
|
+
close();
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
Toast.error(
|
|
228
|
+
getApiErrorMessage(err, t('bindOAuthFailed', { provider: LOGIN_PROVIDER_NAME[oauthItem.provider] }))
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
Toast.error(
|
|
233
|
+
getApiErrorMessage(err, t('bindOAuthFailed', { provider: LOGIN_PROVIDER_NAME[oauthItem.provider] }))
|
|
234
|
+
);
|
|
235
|
+
}
|
|
193
236
|
} finally {
|
|
194
237
|
state.bindAuthLoading = false;
|
|
195
238
|
}
|
|
@@ -326,6 +369,7 @@ function OAuthProvider({
|
|
|
326
369
|
t,
|
|
327
370
|
}}>
|
|
328
371
|
{children}
|
|
372
|
+
{confirmHolder}
|
|
329
373
|
<PassportSwitcher
|
|
330
374
|
api={api.current}
|
|
331
375
|
locale={locale}
|