@blocklet/ui-react 2.9.67 → 2.9.69

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.
Files changed (54) hide show
  1. package/es/@types/index.d.ts +38 -1
  2. package/es/@types/shims.d.ts +6 -0
  3. package/es/Dashboard/index.js +0 -1
  4. package/es/UserCenter/components/settings.js +7 -1
  5. package/es/UserCenter/components/third-party-login/index.d.ts +5 -0
  6. package/es/UserCenter/components/third-party-login/index.js +111 -0
  7. package/es/UserCenter/components/third-party-login/third-party-item.d.ts +13 -0
  8. package/es/UserCenter/components/third-party-login/third-party-item.js +227 -0
  9. package/es/UserCenter/components/user-center.js +22 -17
  10. package/es/UserCenter/components/user-info/index.d.ts +3 -0
  11. package/es/UserCenter/components/user-info/index.js +3 -0
  12. package/es/UserCenter/components/{user-basic-info.d.ts → user-info/user-basic-info.d.ts} +1 -1
  13. package/es/UserCenter/components/{user-basic-info.js → user-info/user-basic-info.js} +1 -1
  14. package/es/UserCenter/components/{user-info.d.ts → user-info/user-info.d.ts} +1 -1
  15. package/es/UserCenter/components/{user-info.js → user-info/user-info.js} +3 -6
  16. package/es/UserCenter/libs/locales.d.ts +20 -0
  17. package/es/UserCenter/libs/locales.js +20 -0
  18. package/es/UserSessions/components/user-sessions.js +1 -4
  19. package/lib/@types/index.d.ts +38 -1
  20. package/lib/@types/shims.d.ts +6 -0
  21. package/lib/Dashboard/index.js +1 -3
  22. package/lib/UserCenter/components/settings.js +8 -1
  23. package/lib/UserCenter/components/third-party-login/index.d.ts +5 -0
  24. package/lib/UserCenter/components/third-party-login/index.js +123 -0
  25. package/lib/UserCenter/components/third-party-login/third-party-item.d.ts +13 -0
  26. package/lib/UserCenter/components/third-party-login/third-party-item.js +235 -0
  27. package/lib/UserCenter/components/user-center.js +23 -16
  28. package/lib/UserCenter/components/user-info/index.d.ts +3 -0
  29. package/lib/UserCenter/components/user-info/index.js +27 -0
  30. package/lib/UserCenter/components/{user-basic-info.d.ts → user-info/user-basic-info.d.ts} +1 -1
  31. package/lib/UserCenter/components/{user-basic-info.js → user-info/user-basic-info.js} +1 -1
  32. package/lib/UserCenter/components/{user-info.d.ts → user-info/user-info.d.ts} +1 -1
  33. package/lib/UserCenter/components/{user-info.js → user-info/user-info.js} +3 -6
  34. package/lib/UserCenter/libs/locales.d.ts +20 -0
  35. package/lib/UserCenter/libs/locales.js +20 -0
  36. package/lib/UserSessions/components/user-sessions.js +1 -4
  37. package/package.json +10 -9
  38. package/src/@types/index.ts +42 -1
  39. package/src/@types/shims.d.ts +6 -0
  40. package/src/Dashboard/index.jsx +2 -1
  41. package/src/UserCenter/components/settings.tsx +7 -1
  42. package/src/UserCenter/components/third-party-login/index.tsx +133 -0
  43. package/src/UserCenter/components/third-party-login/third-party-item.tsx +239 -0
  44. package/src/UserCenter/components/user-center.tsx +24 -17
  45. package/src/UserCenter/components/user-info/index.tsx +3 -0
  46. package/src/UserCenter/components/{user-basic-info.tsx → user-info/user-basic-info.tsx} +2 -2
  47. package/src/UserCenter/components/{user-info.tsx → user-info/user-info.tsx} +4 -7
  48. package/src/UserCenter/libs/locales.ts +22 -0
  49. package/src/UserSessions/components/user-sessions.tsx +0 -3
  50. /package/es/UserCenter/components/{user-info-item.d.ts → user-info/user-info-item.d.ts} +0 -0
  51. /package/es/UserCenter/components/{user-info-item.js → user-info/user-info-item.js} +0 -0
  52. /package/lib/UserCenter/components/{user-info-item.d.ts → user-info/user-info-item.d.ts} +0 -0
  53. /package/lib/UserCenter/components/{user-info-item.js → user-info/user-info-item.js} +0 -0
  54. /package/src/UserCenter/components/{user-info-item.tsx → user-info/user-info-item.tsx} +0 -0
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import type { BoxProps } from '@mui/material';
3
- import type { User } from '../../@types';
3
+ import type { User } from '../../../@types';
4
4
  export default function UserBasicInfo({ user, isMyself, showFullDid, switchPassport, switchProfile, openSettings, ...rest }: {
5
5
  user: User;
6
6
  isMyself?: boolean;
@@ -17,7 +17,7 @@ var _ahooks = require("ahooks");
17
17
  var _util = require("@arcblock/ux/lib/Locale/util");
18
18
  var _context = require("@arcblock/ux/lib/Locale/context");
19
19
  var _noop = _interopRequireDefault(require("lodash/noop"));
20
- var _locales = require("../libs/locales");
20
+ var _locales = require("../../libs/locales");
21
21
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
22
  function UserBasicInfo({
23
23
  user,
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import type { BoxProps } from '@mui/material';
3
- import type { User } from '../../@types';
3
+ import type { User } from '../../../@types';
4
4
  export default function UserInfo({ user, ...rest }: {
5
5
  user: User;
6
6
  } & BoxProps): import("react").JSX.Element;
@@ -16,7 +16,8 @@ var _settingsInputAntennaRounded = _interopRequireDefault(require("@iconify-icon
16
16
  var _RelativeTime = _interopRequireDefault(require("@arcblock/ux/lib/RelativeTime"));
17
17
  var _util = require("@arcblock/ux/lib/Locale/util");
18
18
  var _context = require("@arcblock/ux/lib/Locale/context");
19
- var _locales = require("../libs/locales");
19
+ var _constant = require("@arcblock/ux/lib/Util/constant");
20
+ var _locales = require("../../libs/locales");
20
21
  var _userInfoItem = _interopRequireDefault(require("./user-info-item"));
21
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
23
  function UserInfo({
@@ -30,11 +31,7 @@ function UserInfo({
30
31
  return (0, _util.translate)(_locales.translations, key, locale, "en", data);
31
32
  });
32
33
  const readableProvider = (0, _ahooks.useCreation)(() => {
33
- const nameMap = {
34
- wallet: "DID Wallet",
35
- auth0: "Auth0"
36
- };
37
- return user?.sourceProvider && nameMap[user.sourceProvider] || t("unknown");
34
+ return user?.sourceProvider && _constant.LOGIN_PROVIDER_NAME[user.sourceProvider] || t("unknown");
38
35
  }, [user?.sourceProvider]);
39
36
  const userInfoListData = [];
40
37
  userInfoListData.push({
@@ -31,6 +31,8 @@ export declare const translations: {
31
31
  slack: string;
32
32
  };
33
33
  common: {
34
+ confirm: string;
35
+ cancel: string;
34
36
  required: string;
35
37
  invalid: string;
36
38
  };
@@ -68,6 +70,14 @@ export declare const translations: {
68
70
  };
69
71
  };
70
72
  };
73
+ thirdPartyLogin: {
74
+ title: string;
75
+ connect: string;
76
+ disconnect: string;
77
+ mainProviderCantRemove: string;
78
+ confirmUnbind: string;
79
+ confirmUnbindDescription: string;
80
+ };
71
81
  };
72
82
  en: {
73
83
  settings: string;
@@ -101,6 +111,8 @@ export declare const translations: {
101
111
  slack: string;
102
112
  };
103
113
  common: {
114
+ confirm: string;
115
+ cancel: string;
104
116
  required: string;
105
117
  invalid: string;
106
118
  };
@@ -138,5 +150,13 @@ export declare const translations: {
138
150
  };
139
151
  };
140
152
  };
153
+ thirdPartyLogin: {
154
+ title: string;
155
+ connect: string;
156
+ disconnect: string;
157
+ mainProviderCantRemove: string;
158
+ confirmUnbind: string;
159
+ confirmUnbindDescription: string;
160
+ };
141
161
  };
142
162
  };
@@ -37,6 +37,8 @@ const translations = exports.translations = {
37
37
  slack: "Slack"
38
38
  },
39
39
  common: {
40
+ confirm: "\u786E\u8BA4",
41
+ cancel: "\u53D6\u6D88",
40
42
  required: "\u5FC5\u586B\u7684",
41
43
  invalid: "\u65E0\u6548"
42
44
  },
@@ -73,6 +75,14 @@ const translations = exports.translations = {
73
75
  tag: "\u5DF2\u8FDE\u63A5"
74
76
  }
75
77
  }
78
+ },
79
+ thirdPartyLogin: {
80
+ title: "\u7B2C\u4E09\u65B9\u767B\u5F55",
81
+ connect: "\u7ED1\u5B9A",
82
+ disconnect: "\u89E3\u7ED1",
83
+ mainProviderCantRemove: "\u4E3B\u8D26\u53F7\u4E0D\u5141\u8BB8\u89E3\u7ED1",
84
+ confirmUnbind: "\u786E\u5B9A\u8981\u89E3\u7ED1 {name} \u5417?",
85
+ confirmUnbindDescription: "\u89E3\u7ED1\u540E\u60A8\u5C06\u65E0\u6CD5\u4F7F\u7528 {name} \u767B\u5F55\u81F3\u8BE5\u8D26\u6237\u3002\u5982\u679C\u89E3\u7ED1\u540E\uFF0C\u60A8\u4ECD\u4F7F\u7528 {name} \u767B\u5F55\uFF0C\u4F1A\u81EA\u52A8\u521B\u5EFA\u4E00\u4E2A\u65B0\u8D26\u6237"
76
86
  }
77
87
  },
78
88
  en: {
@@ -107,6 +117,8 @@ const translations = exports.translations = {
107
117
  slack: "Slack"
108
118
  },
109
119
  common: {
120
+ confirm: "Confirm",
121
+ cancel: "Cancel",
110
122
  required: "Required",
111
123
  invalid: "Invalid"
112
124
  },
@@ -143,6 +155,14 @@ const translations = exports.translations = {
143
155
  tag: "Connected"
144
156
  }
145
157
  }
158
+ },
159
+ thirdPartyLogin: {
160
+ title: "Third Party Login",
161
+ connect: "Connect",
162
+ disconnect: "Disconnect",
163
+ mainProviderCantRemove: "Main account not allowed to remove",
164
+ confirmUnbind: "Are you sure to unbind {name}?",
165
+ confirmUnbindDescription: "You will not be able to log in to this account using {name} after unbundling. If you are still logged in with {name} after unbundling, a new account will be created automatically!"
146
166
  }
147
167
  }
148
168
  };
@@ -208,10 +208,7 @@ function UserSessions({
208
208
  options: {
209
209
  customBodyRenderLite: rawIndex => {
210
210
  const x = safeData[rawIndex];
211
- return x.createdAt ?
212
- // @ts-ignore FIXME: @zhanghan 新版 js-sdk 会提供这个属性的提示
213
- /* @__PURE__ */
214
- (0, _jsxRuntime.jsx)(_RelativeTime.default, {
211
+ return x.createdAt ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_RelativeTime.default, {
215
212
  value: x.createdAt,
216
213
  relativeRange: 3 * 86400 * 1e3,
217
214
  locale
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "2.9.67",
3
+ "version": "2.9.69",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -62,13 +62,14 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@arcblock/bridge": "^2.9.67",
66
- "@arcblock/did-connect": "^2.9.67",
67
- "@arcblock/react-hooks": "^2.9.67",
68
- "@arcblock/ux": "^2.9.67",
69
- "@blocklet/js-sdk": "1.16.25-beta-be3a37f4",
65
+ "@arcblock/bridge": "^2.9.69",
66
+ "@arcblock/did-connect": "^2.9.69",
67
+ "@arcblock/react-hooks": "^2.9.69",
68
+ "@arcblock/ux": "^2.9.69",
69
+ "@blocklet/js-sdk": "^1.16.25",
70
70
  "@emotion/react": "^11.10.4",
71
71
  "@emotion/styled": "^11.10.4",
72
+ "@iconify-icons/logos": "^1.2.36",
72
73
  "@iconify-icons/material-symbols": "^1.2.58",
73
74
  "@iconify/react": "^4.1.1",
74
75
  "ahooks": "^3.7.10",
@@ -84,7 +85,6 @@
84
85
  "prop-types": "^15.8.1",
85
86
  "react-error-boundary": "^3.1.4",
86
87
  "react-placeholder": "^4.1.0",
87
- "react-router-dom": "^6.22.3",
88
88
  "ua-parser-js": "^1.0.37",
89
89
  "ufo": "^1.3.2",
90
90
  "url-join": "^4.0.1"
@@ -92,7 +92,8 @@
92
92
  "peerDependencies": {
93
93
  "@mui/icons-material": ">=5.15.0",
94
94
  "@mui/material": ">=5.15.0",
95
- "react": ">=18.2.0"
95
+ "react": ">=18.2.0",
96
+ "react-router-dom": ">=6.22.3"
96
97
  },
97
98
  "publishConfig": {
98
99
  "access": "public"
@@ -108,5 +109,5 @@
108
109
  "jest": "^28.1.3",
109
110
  "unbuild": "^2.0.0"
110
111
  },
111
- "gitHead": "d9517b055c9631ac47474119674ad845e4e7c03b"
112
+ "gitHead": "375716410d5c6dc796fbd8dcd3240b846a5e1b33"
112
113
  }
@@ -1,21 +1,61 @@
1
1
  import type { Axios } from 'axios';
2
2
  import type { UserPublicInfo } from '@blocklet/js-sdk';
3
+ import { OAUTH_PROVIDER } from '@arcblock/ux/lib/Util/constant';
3
4
 
4
5
  export type SessionContext = {
5
6
  session: Session;
6
7
  api: Axios;
7
8
  };
8
9
 
10
+ export type OAuthAccount = {
11
+ provider: keyof typeof OAUTH_PROVIDER;
12
+ id: string;
13
+ did: string;
14
+ pk: string;
15
+ lastLoginAt: string;
16
+ firstLoginAt: string;
17
+ order?: number;
18
+ userInfo?: {
19
+ email: string;
20
+ emailVerified: boolean;
21
+ name: string;
22
+ picture: string;
23
+ sub: string;
24
+ extraData: Object;
25
+ };
26
+ };
27
+
28
+ export type WalletAccount = {
29
+ provider: 'wallet';
30
+ did: string;
31
+ pk: string;
32
+ lastLoginAt: string;
33
+ firstLoginAt: string;
34
+ };
35
+
36
+ export type NFTAccount = {
37
+ provider: 'nft';
38
+ did: string;
39
+ pk: string;
40
+ owner: string;
41
+ lastLoginAt: string;
42
+ firstLoginAt: string;
43
+ };
44
+
45
+ export type ConnectedAccount = OAuthAccount | WalletAccount | NFTAccount;
46
+
9
47
  export type User = UserPublicInfo & {
10
48
  role: string;
11
49
  email?: string;
12
50
  phone?: string;
13
51
  sourceProvider?: string;
52
+ sourceAppPid?: string;
14
53
  lastLoginAt?: string;
15
54
  lastLoginIp?: string;
16
55
  createdAt?: string;
17
56
  passports?: any[];
18
57
  didSpace?: Record<string, any>;
58
+ connectedAccounts?: any[];
19
59
  };
20
60
 
21
61
  export type UserCenterTab = {
@@ -29,7 +69,7 @@ export type UserCenterTab = {
29
69
  export type Session = {
30
70
  loading: boolean;
31
71
  initialized: boolean;
32
- user: User;
72
+ user?: User;
33
73
  login: any;
34
74
  logout: any;
35
75
  switch: any;
@@ -38,6 +78,7 @@ export type Session = {
38
78
  switchPassport: any;
39
79
 
40
80
  refresh: Function;
81
+ useOAuth: Function;
41
82
  };
42
83
 
43
84
  export type WebhookType = 'slack' | 'api';
@@ -1,5 +1,11 @@
1
1
  declare module '@arcblock/ux/*';
2
+ declare module '@arcblock/ux/lib/DID';
3
+ declare module '@arcblock/ux/lib/Tabs';
4
+ declare module '@arcblock/ux/lib/Switch';
5
+ declare module '@arcblock/ux/lib/ErrorBoundary';
6
+
2
7
  declare module '@arcblock/did-connect/*';
8
+ declare module '@arcblock/did-connect/lib/Session';
3
9
 
4
10
  declare module 'is-url';
5
11
  declare module 'url-join';
@@ -77,7 +77,8 @@ function Dashboard({ meta, fallbackUrl, invalidPathFallback, headerAddons, sessi
77
77
  if (invalidPathFallback) {
78
78
  invalidPathFallback();
79
79
  } else {
80
- window.location.href = flattened[0]?.url || publicPath;
80
+ // FIXME: @zhanghan 暂时取消跳转首个 url 的行为
81
+ // window.location.href = flattened[0]?.url || publicPath;
81
82
  }
82
83
  }
83
84
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -12,6 +12,7 @@ import Privacy from './privacy';
12
12
  import { User, UserCenterTab } from '../../@types';
13
13
  import DidSpace from './storage';
14
14
  import { UserSessions } from '../../UserSessions';
15
+ import ThirdPartyLogin from './third-party-login';
15
16
 
16
17
  export default function Settings({
17
18
  user,
@@ -46,6 +47,11 @@ export default function Settings({
46
47
  value: 'notification',
47
48
  content: <Notification user={user} />,
48
49
  },
50
+ {
51
+ label: t('thirdPartyLogin.title'),
52
+ value: 'thirdPartyLogin',
53
+ content: <ThirdPartyLogin user={user} />,
54
+ },
49
55
  {
50
56
  label: t('privacyManagement'),
51
57
  value: 'privacy',
@@ -73,7 +79,7 @@ export default function Settings({
73
79
 
74
80
  const currentTab = useCreation(() => {
75
81
  return tabs.find((x) => x.value === currentState.tab);
76
- }, [currentState.tab]);
82
+ }, [currentState.tab, tabs]);
77
83
  const handleChangeTab = useMemoizedFn((value) => {
78
84
  currentState.tab = value;
79
85
  });
@@ -0,0 +1,133 @@
1
+ import { useContext, useState } from 'react';
2
+ import { List } from '@mui/material';
3
+ import { useAsyncEffect, useCreation } from 'ahooks';
4
+ import { getConnectedAccounts, getSourceProvider } from '@arcblock/ux/lib/SessionUser/libs/utils';
5
+ import { LOGIN_PROVIDER } from '@arcblock/ux/lib/Util/constant';
6
+ import { SessionContext } from '@arcblock/did-connect/lib/Session';
7
+
8
+ import type { ConnectedAccount, OAuthAccount, User, SessionContext as TSessionContext } from '../../../@types';
9
+ import ThirdPartyItem from './third-party-item';
10
+
11
+ type ConnectedAccountProps = OAuthAccount & {
12
+ enabled: boolean;
13
+ };
14
+
15
+ export default function ThirdPartyLogin({ user }: { user: User }) {
16
+ const { session } = useContext<TSessionContext>(SessionContext);
17
+ const [oauthConfigs, setOauthConfigs] = useState<Record<string, ConnectedAccountProps>>({});
18
+ const { getOAuthConfigs } = session.useOAuth();
19
+ useAsyncEffect(async () => {
20
+ const data = await getOAuthConfigs({
21
+ sourceAppPid: user?.sourceAppPid,
22
+ });
23
+ setOauthConfigs(data);
24
+ }, [user?.sourceAppPid]);
25
+
26
+ const availableProviders = useCreation(() => {
27
+ const oauthList = Object.keys(oauthConfigs)
28
+ .map((x) => {
29
+ return {
30
+ ...oauthConfigs[x],
31
+ provider: x,
32
+ };
33
+ })
34
+ .filter((x) => x.enabled);
35
+ return oauthList;
36
+ }, [oauthConfigs]);
37
+
38
+ /**
39
+ * 1. 如果 connectedAccount 中存在 auth0,则应该将 auth0 转换为 google, apple, github 中的一种。如果可以转换,则标记需要移除 auth0;如果无法转换,则保留 auth0
40
+ * 2. 如果标记移除了 auth0,则还需要对 sourceProvider 进行转换,转换的值为 google, apple, github 中的一种
41
+ * 3. 如果标记移除了 auth0,还需要将 auth0 的 userInfo 数据添加到转换后的 provider 上
42
+ */
43
+ const normalizedAccounts = useCreation(() => {
44
+ const connectedAccounts: ConnectedAccount[] = getConnectedAccounts(user);
45
+ let removeAuth0 = false;
46
+ let patchProvider = '';
47
+ let sourceProvider = getSourceProvider(user);
48
+ const auth0ConnectedAccount = connectedAccounts.find((x) => x.provider === LOGIN_PROVIDER.AUTH0) as OAuthAccount;
49
+ if (auth0ConnectedAccount) {
50
+ if (auth0ConnectedAccount.id.startsWith('google-oauth2|')) {
51
+ if (!connectedAccounts.some((x) => x.provider === 'google')) {
52
+ removeAuth0 = true;
53
+ patchProvider = LOGIN_PROVIDER.GOOGLE;
54
+ if (sourceProvider === LOGIN_PROVIDER.AUTH0) {
55
+ sourceProvider = LOGIN_PROVIDER.GOOGLE;
56
+ }
57
+ }
58
+ }
59
+ if (auth0ConnectedAccount.id.startsWith('appleid|')) {
60
+ if (!connectedAccounts.some((x) => x.provider === LOGIN_PROVIDER.APPLE)) {
61
+ removeAuth0 = true;
62
+ patchProvider = LOGIN_PROVIDER.APPLE;
63
+ if (sourceProvider === LOGIN_PROVIDER.AUTH0) {
64
+ sourceProvider = LOGIN_PROVIDER.APPLE;
65
+ }
66
+ }
67
+ }
68
+ if (auth0ConnectedAccount.id.startsWith('github|')) {
69
+ if (!connectedAccounts.some((x) => x.provider === LOGIN_PROVIDER.GITHUB)) {
70
+ removeAuth0 = true;
71
+ patchProvider = LOGIN_PROVIDER.GITHUB;
72
+ if (sourceProvider === LOGIN_PROVIDER.AUTH0) {
73
+ sourceProvider = LOGIN_PROVIDER.GITHUB;
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ const transformedProviders = availableProviders
80
+ .map((x) => {
81
+ if (x.provider === LOGIN_PROVIDER.AUTH0 && removeAuth0) {
82
+ return null;
83
+ }
84
+ const findConnectedAccount =
85
+ removeAuth0 && x.provider === patchProvider
86
+ ? (connectedAccounts.find((i) => i.provider === LOGIN_PROVIDER.AUTH0) as OAuthAccount)
87
+ : (connectedAccounts.find((i) => i.provider === x.provider) as OAuthAccount);
88
+ if (findConnectedAccount) {
89
+ return {
90
+ ...x,
91
+ provider: x.provider,
92
+ did: findConnectedAccount.did,
93
+ pk: findConnectedAccount.pk,
94
+ userInfo: findConnectedAccount.userInfo,
95
+ _bind: true,
96
+ _rawProvider: findConnectedAccount.provider,
97
+ _mainProvider: x.provider === sourceProvider,
98
+ };
99
+ }
100
+ return {
101
+ ...x,
102
+ provider: x.provider,
103
+ _rawProvider: x.provider,
104
+ _mainProvider: x.provider === sourceProvider,
105
+ };
106
+ })
107
+ .filter(Boolean)
108
+ .sort((a, b) => {
109
+ if (a?.order !== undefined && b?.order !== undefined) {
110
+ return a.order - b.order;
111
+ }
112
+ if (a?.order !== undefined) {
113
+ return -1;
114
+ }
115
+ return 1;
116
+ });
117
+ return transformedProviders;
118
+ }, [user?.connectedAccounts, availableProviders]);
119
+
120
+ return (
121
+ <List
122
+ dense
123
+ sx={{
124
+ gap: 1,
125
+ display: 'flex',
126
+ flexDirection: 'column',
127
+ }}>
128
+ {normalizedAccounts.map((account) => {
129
+ return <ThirdPartyItem key={account?.provider} item={account as OAuthAccount} />;
130
+ })}
131
+ </List>
132
+ );
133
+ }