@taskon/widget-react 0.0.1-beta.5 → 0.0.1-beta.7

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 (65) hide show
  1. package/README.md +61 -47
  2. package/dist/CommunityTaskList.css +9 -1
  3. package/dist/EligibilityInfo.css +48 -75
  4. package/dist/LeaderboardWidget.css +73 -71
  5. package/dist/PageBuilder.css +5 -0
  6. package/dist/Quest.css +18 -14
  7. package/dist/TaskOnProvider.css +289 -0
  8. package/dist/ThemeProvider.css +227 -0
  9. package/dist/UserCenterWidget.css +6 -6
  10. package/dist/UserCenterWidget2.css +1388 -1621
  11. package/dist/{dynamic-import-helper.css → WidgetShell.css} +0 -227
  12. package/dist/chunks/{CommunityTaskList-CrMvOB8w.js → CommunityTaskList-D0uVD8wD.js} +393 -208
  13. package/dist/chunks/{EligibilityInfo-Beww12QX.js → EligibilityInfo-Cf6hx9-a.js} +459 -679
  14. package/dist/chunks/{LeaderboardWidget-DwuSpVl0.js → LeaderboardWidget-DyoiiNS6.js} +274 -252
  15. package/dist/chunks/{PageBuilder-DsX6Tv0N.js → PageBuilder-DoAFPm6-.js} +5 -5
  16. package/dist/chunks/{Quest-CuD2LElS.js → Quest-ySZlYd4u.js} +74 -57
  17. package/dist/chunks/TaskOnProvider-CxtFIs3n.js +2072 -0
  18. package/dist/chunks/{dynamic-import-helper-WmIF58Sb.js → ThemeProvider-CulHkqqY.js} +1282 -555
  19. package/dist/chunks/UserCenterWidget-BJsc_GSZ.js +3246 -0
  20. package/dist/chunks/{UserCenterWidget-CvU6K4AC.js → UserCenterWidget-STq8kpV4.js} +1174 -1386
  21. package/dist/chunks/WidgetShell-8xn-Jivw.js +659 -0
  22. package/dist/chunks/communitytask-es-CBNnS4o2.js +521 -0
  23. package/dist/chunks/communitytask-ja-GRf9cbdx.js +521 -0
  24. package/dist/chunks/communitytask-ko-Bf24PQKI.js +521 -0
  25. package/dist/chunks/{communitytask-ru-DhySaZL8.js → communitytask-ru-CZm2CPoV.js} +211 -1
  26. package/dist/chunks/leaderboardwidget-es-vKjrjQaz.js +146 -0
  27. package/dist/chunks/leaderboardwidget-ja-Q6u0HxKG.js +146 -0
  28. package/dist/chunks/leaderboardwidget-ko-CG6SWgxf.js +146 -0
  29. package/dist/chunks/leaderboardwidget-ru-DCcHcJGz.js +146 -0
  30. package/dist/chunks/{quest-es-D-b5xcme.js → quest-es-Dyyy0zaw.js} +8 -93
  31. package/dist/chunks/{quest-ja-Dxd2vqBF.js → quest-ja-Depog33y.js} +8 -93
  32. package/dist/chunks/{quest-ko-CSmRWgK_.js → quest-ko-BMu3uRQJ.js} +8 -93
  33. package/dist/chunks/{quest-ru-CkEKv1_F.js → quest-ru-xne814Rw.js} +8 -93
  34. package/dist/chunks/useIsMobile-D6Ybur-6.js +30 -0
  35. package/dist/chunks/useToast-BGJhd3BX.js +93 -0
  36. package/dist/chunks/usercenter-es-Dz3Wp2vV.js +512 -0
  37. package/dist/chunks/usercenter-ja-CKE4DJC6.js +512 -0
  38. package/dist/chunks/usercenter-ko-Dtpkn2qb.js +512 -0
  39. package/dist/chunks/usercenter-ru-DnBGee45.js +512 -0
  40. package/dist/community-task.d.ts +0 -390
  41. package/dist/community-task.js +2 -7
  42. package/dist/core.d.ts +38 -20
  43. package/dist/core.js +9 -10
  44. package/dist/index.d.ts +86 -709
  45. package/dist/index.js +22 -28
  46. package/dist/leaderboard.d.ts +0 -498
  47. package/dist/leaderboard.js +2 -16
  48. package/dist/page-builder.js +1 -1
  49. package/dist/quest.d.ts +0 -971
  50. package/dist/quest.js +2 -7
  51. package/dist/user-center.d.ts +0 -1610
  52. package/dist/user-center.js +2 -494
  53. package/package.json +2 -2
  54. package/dist/chunks/TaskOnProvider-xUeP2Nro.js +0 -1243
  55. package/dist/chunks/ThemeProvider-Bt4UZ33y.js +0 -1334
  56. package/dist/chunks/UserCenterWidget-CB0hnj-L.js +0 -3230
  57. package/dist/chunks/communitytask-es-1zawvXEX.js +0 -311
  58. package/dist/chunks/communitytask-ja-CmW6nP-L.js +0 -311
  59. package/dist/chunks/communitytask-ko-BD0hzQSi.js +0 -311
  60. package/dist/chunks/createLocaleLoader-BameiEhU.js +0 -65
  61. package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +0 -119
  62. package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +0 -119
  63. package/dist/chunks/useToast-CaRkylKe.js +0 -304
  64. package/dist/chunks/usercenter-ja-B2465c1O.js +0 -326
  65. package/dist/chunks/usercenter-ko-xAEYxqLg.js +0 -326
@@ -1,3230 +0,0 @@
1
- import { T as Table, u as usePagination, D as Dialog, B as Button, a as useResolvedWidgetConfig, W as WidgetShell, _ as __variableDynamicImportRuntimeHelper } from "./dynamic-import-helper-WmIF58Sb.js";
2
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
- import { useState, useRef, useCallback, useLayoutEffect, useMemo, useEffect } from "react";
4
- import { UserCenterRewardCardType, USER_CENTER_PAGE_SIZE, createUserCenterApi, SnsType, createUserApi, VerifyCodeType, getChainName, truncateAddress, filterEnabledAccounts, filterEnabledWallets, USER_CENTER_REWARD_CARD_TYPES, RewardType, toWei, LockedType, filterEnabledTabs, UserCenterTabType } from "@taskon/core";
5
- import { d as useTaskOnContext, b as useWidgetLocale } from "./ThemeProvider-Bt4UZ33y.js";
6
- import { L as LoadingState, E as EmptyState, P as Pagination, e as formatDateTime, A as AssetImage, d as buildRewardCards, g as useBindSocialAccount, I as Input, a as useTokenAssets, u as useRewardDetails, c as usePointsHistory, W as WithdrawForm, h as PointsList, N as NftRewardContent, i as TokenRewardContent, j as enMessages } from "./UserCenterWidget-CvU6K4AC.js";
7
- import { u as useWallet, d as useToast } from "./useToast-CaRkylKe.js";
8
- import '../UserCenterWidget.css';function Tabs({
9
- items,
10
- activeKey,
11
- defaultActiveKey,
12
- onChange,
13
- className = "",
14
- style,
15
- gap = 40
16
- }) {
17
- var _a;
18
- const [internalActiveKey, setInternalActiveKey] = useState(
19
- defaultActiveKey ?? ((_a = items[0]) == null ? void 0 : _a.key) ?? ""
20
- );
21
- const currentActiveKey = activeKey ?? internalActiveKey;
22
- const tabsRef = useRef(null);
23
- const [indicatorStyle, setIndicatorStyle] = useState({});
24
- const updateIndicator = useCallback(() => {
25
- if (!tabsRef.current) return;
26
- const activeTab = tabsRef.current.querySelector(
27
- `.taskon-tabs__tab--active`
28
- );
29
- if (activeTab) {
30
- setIndicatorStyle({
31
- width: activeTab.offsetWidth,
32
- transform: `translateX(${activeTab.offsetLeft}px)`
33
- });
34
- }
35
- }, []);
36
- useLayoutEffect(() => {
37
- updateIndicator();
38
- }, [currentActiveKey, updateIndicator]);
39
- useLayoutEffect(() => {
40
- window.addEventListener("resize", updateIndicator);
41
- return () => window.removeEventListener("resize", updateIndicator);
42
- }, [updateIndicator]);
43
- const handleTabClick = (item) => {
44
- if (item.disabled) return;
45
- if (activeKey === void 0) {
46
- setInternalActiveKey(item.key);
47
- }
48
- onChange == null ? void 0 : onChange(item.key);
49
- };
50
- return /* @__PURE__ */ jsxs(
51
- "div",
52
- {
53
- ref: tabsRef,
54
- className: `taskon-tabs ${className}`,
55
- style: { ...style, "--taskon-tabs-gap": `${gap}px` },
56
- children: [
57
- /* @__PURE__ */ jsx("div", { className: "taskon-tabs__list", children: items.map((item) => /* @__PURE__ */ jsx(
58
- "button",
59
- {
60
- type: "button",
61
- className: `taskon-tabs__tab ${currentActiveKey === item.key ? "taskon-tabs__tab--active" : ""} ${item.disabled ? "taskon-tabs__tab--disabled" : ""}`,
62
- onClick: () => handleTabClick(item),
63
- disabled: item.disabled,
64
- "aria-selected": currentActiveKey === item.key,
65
- role: "tab",
66
- children: item.label
67
- },
68
- item.key
69
- )) }),
70
- /* @__PURE__ */ jsx("div", { className: "taskon-tabs__indicator", style: indicatorStyle })
71
- ]
72
- }
73
- );
74
- }
75
- function formatTimeRange(startTime, endTime) {
76
- const formatDate = (timestamp) => {
77
- const date = new Date(timestamp);
78
- const year = date.getFullYear();
79
- const month = String(date.getMonth() + 1).padStart(2, "0");
80
- const day = String(date.getDate()).padStart(2, "0");
81
- const hours = String(date.getHours()).padStart(2, "0");
82
- const minutes = String(date.getMinutes()).padStart(2, "0");
83
- const seconds = String(date.getSeconds()).padStart(2, "0");
84
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
85
- };
86
- return `${formatDate(startTime)} - ${formatDate(endTime)}`;
87
- }
88
- function ActivityHistoryList({
89
- data,
90
- loading,
91
- error,
92
- pagination,
93
- messages,
94
- mode = "pagination",
95
- onItemClick,
96
- onRetry
97
- }) {
98
- const columns = useMemo(
99
- () => [
100
- {
101
- key: "campaign_name",
102
- title: messages.activityName,
103
- cellClassName: "taskon-activity-history__cell--name",
104
- render: (_value, row) => /* @__PURE__ */ jsxs("div", { className: "taskon-activity-history__name-cell", children: [
105
- /* @__PURE__ */ jsx("span", { className: "taskon-activity-history__campaign-name", children: row.campaign_name }),
106
- /* @__PURE__ */ jsx("span", { className: "taskon-activity-history__campaign-type", children: row.campaign_type })
107
- ] })
108
- },
109
- {
110
- key: "time",
111
- title: messages.activityTime,
112
- width: "380px",
113
- align: "right",
114
- cellClassName: "taskon-activity-history__cell--time",
115
- render: (_value, row) => formatTimeRange(row.start_time, row.end_time)
116
- }
117
- ],
118
- [messages.activityName, messages.activityTime]
119
- );
120
- const rowConfig = useMemo(
121
- () => ({
122
- getRowKey: (row) => `${row.campaign_type}-${row.campaign_id}`,
123
- onRowClick: onItemClick
124
- }),
125
- [onItemClick]
126
- );
127
- if (loading && data.length === 0) {
128
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
129
- }
130
- if (error && data.length === 0) {
131
- return /* @__PURE__ */ jsxs("div", { className: "taskon-user-center-error", children: [
132
- /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error.message }),
133
- onRetry && /* @__PURE__ */ jsx(
134
- "button",
135
- {
136
- type: "button",
137
- className: "taskon-user-center-error__retry",
138
- onClick: onRetry,
139
- children: messages.retry
140
- }
141
- )
142
- ] });
143
- }
144
- if (!loading && data.length === 0) {
145
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyActivityHistory });
146
- }
147
- return /* @__PURE__ */ jsxs("div", { className: "taskon-activity-history", children: [
148
- /* @__PURE__ */ jsx(
149
- Table,
150
- {
151
- columns,
152
- data,
153
- rowConfig,
154
- className: "taskon-activity-history__table",
155
- compact: true,
156
- loading,
157
- loadingText: messages.loading
158
- }
159
- ),
160
- mode === "pagination" ? /* @__PURE__ */ jsx(
161
- Pagination,
162
- {
163
- page: pagination.page,
164
- totalPages: pagination.totalPages,
165
- onPrevious: pagination.goToPrevious,
166
- onNext: pagination.goToNext,
167
- hasPrevious: pagination.hasPrevious,
168
- hasNext: pagination.hasNext,
169
- messages
170
- }
171
- ) : pagination.hasMore && /* @__PURE__ */ jsx("div", { className: "taskon-activity-history__load-more", children: /* @__PURE__ */ jsx(
172
- "button",
173
- {
174
- type: "button",
175
- className: "taskon-activity-history__load-more-btn",
176
- onClick: pagination.loadMore,
177
- disabled: loading,
178
- children: loading ? messages.loading : messages.loadMore
179
- }
180
- ) })
181
- ] });
182
- }
183
- function getCardTitle(type, messages, pointsData, xpLevelData) {
184
- var _a;
185
- switch (type) {
186
- case UserCenterRewardCardType.Token:
187
- return messages.rewardToken;
188
- case UserCenterRewardCardType.Nft:
189
- return messages.rewardNft;
190
- case UserCenterRewardCardType.Whitelist:
191
- return messages.rewardWhitelist;
192
- case UserCenterRewardCardType.DiscordRole:
193
- return messages.rewardDiscordRole;
194
- case UserCenterRewardCardType.Points:
195
- return (pointsData == null ? void 0 : pointsData.points_name) ?? messages.rewardPoints;
196
- case UserCenterRewardCardType.XpLevel: {
197
- const xpPointsName = (_a = xpLevelData == null ? void 0 : xpLevelData.xpPointsName) == null ? void 0 : _a.trim();
198
- if (xpPointsName) {
199
- return `${xpPointsName} & ${messages.level}`;
200
- }
201
- return messages.rewardXpLevel;
202
- }
203
- default:
204
- return type;
205
- }
206
- }
207
- function getCardIconUrl(type, pointsData) {
208
- if (type === UserCenterRewardCardType.Points && (pointsData == null ? void 0 : pointsData.points_icon)) {
209
- return pointsData.points_icon;
210
- }
211
- return null;
212
- }
213
- function TokenIcon() {
214
- return /* @__PURE__ */ jsxs("svg", { width: "25", height: "28", viewBox: "0 0 25 28", fill: "none", children: [
215
- /* @__PURE__ */ jsx("path", { d: "M12.5 2L3 10H22L12.5 2Z", fill: "url(#token-gem-top)" }),
216
- /* @__PURE__ */ jsx("path", { d: "M3 10L12.5 26L12.5 10H3Z", fill: "url(#token-gem-left)" }),
217
- /* @__PURE__ */ jsx("path", { d: "M22 10L12.5 26L12.5 10H22Z", fill: "url(#token-gem-right)" }),
218
- /* @__PURE__ */ jsx("path", { d: "M12.5 2L8 10H17L12.5 2Z", fill: "url(#token-gem-highlight)", fillOpacity: "0.6" }),
219
- /* @__PURE__ */ jsxs("defs", { children: [
220
- /* @__PURE__ */ jsxs("linearGradient", { id: "token-gem-top", x1: "12.5", y1: "2", x2: "12.5", y2: "10", gradientUnits: "userSpaceOnUse", children: [
221
- /* @__PURE__ */ jsx("stop", { stopColor: "#81D4FA" }),
222
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#4FC3F7" })
223
- ] }),
224
- /* @__PURE__ */ jsxs("linearGradient", { id: "token-gem-left", x1: "3", y1: "10", x2: "12.5", y2: "26", gradientUnits: "userSpaceOnUse", children: [
225
- /* @__PURE__ */ jsx("stop", { stopColor: "#4FC3F7" }),
226
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#0288D1" })
227
- ] }),
228
- /* @__PURE__ */ jsxs("linearGradient", { id: "token-gem-right", x1: "22", y1: "10", x2: "12.5", y2: "26", gradientUnits: "userSpaceOnUse", children: [
229
- /* @__PURE__ */ jsx("stop", { stopColor: "#29B6F6" }),
230
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#0277BD" })
231
- ] }),
232
- /* @__PURE__ */ jsxs("linearGradient", { id: "token-gem-highlight", x1: "12.5", y1: "2", x2: "12.5", y2: "10", gradientUnits: "userSpaceOnUse", children: [
233
- /* @__PURE__ */ jsx("stop", { stopColor: "#E1F5FE" }),
234
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#81D4FA" })
235
- ] })
236
- ] })
237
- ] });
238
- }
239
- function NftIcon() {
240
- return /* @__PURE__ */ jsx("span", { className: "taskon-asset-card__icon-nft", children: "NFT" });
241
- }
242
- function WhitelistIcon() {
243
- return /* @__PURE__ */ jsx("span", { className: "taskon-asset-card__icon-wl", children: "WL" });
244
- }
245
- function DiscordRoleIcon() {
246
- return /* @__PURE__ */ jsx("svg", { width: "28", height: "22", viewBox: "0 0 28 22", fill: "none", children: /* @__PURE__ */ jsx(
247
- "path",
248
- {
249
- d: "M23.7 1.84A23.15 23.15 0 0018 0a.09.09 0 00-.09.04c-.25.44-.52 1.01-.71 1.46a21.37 21.37 0 00-6.4 0 14.77 14.77 0 00-.72-1.46.09.09 0 00-.1-.04 23.08 23.08 0 00-5.7 1.84.08.08 0 00-.04.03C.62 7.86-.37 13.68.12 19.41a.1.1 0 00.04.07 23.26 23.26 0 007 3.54.1.1 0 00.1-.04c.54-.74.97-1.52 1.33-2.33a.09.09 0 00-.05-.13 15.32 15.32 0 01-2.19-1.04.1.1 0 01-.01-.15c.15-.11.3-.22.43-.34a.09.09 0 01.09-.01c4.6 2.1 9.57 2.1 14.12 0a.09.09 0 01.1.01c.14.12.28.23.43.34a.1.1 0 01-.01.15c-.7.41-1.42.75-2.19 1.04a.09.09 0 00-.05.13c.38.81.8 1.59 1.32 2.33a.1.1 0 00.1.04 23.17 23.17 0 007.01-3.54.1.1 0 00.04-.07c.58-6.07-.97-11.84-4.13-16.84a.08.08 0 00-.04-.03zM9.36 15.91c-1.39 0-2.52-1.27-2.52-2.83s1.11-2.83 2.52-2.83c1.42 0 2.55 1.29 2.52 2.83 0 1.56-1.11 2.83-2.52 2.83zm9.32 0c-1.39 0-2.52-1.27-2.52-2.83s1.11-2.83 2.52-2.83c1.42 0 2.55 1.29 2.52 2.83 0 1.56-1.1 2.83-2.52 2.83z",
250
- fill: "#ffffff"
251
- }
252
- ) });
253
- }
254
- function XpLevelIcon() {
255
- return /* @__PURE__ */ jsxs("svg", { width: "26", height: "26", viewBox: "0 0 26 26", fill: "none", children: [
256
- /* @__PURE__ */ jsx(
257
- "path",
258
- {
259
- d: "M13 2L15.9 8.9L23 9.5L17.5 14.4L19.1 21.5L13 17.8L6.9 21.5L8.5 14.4L3 9.5L10.1 8.9L13 2Z",
260
- fill: "url(#xp-gradient)",
261
- stroke: "#F59E0B",
262
- strokeWidth: "1.5",
263
- strokeLinejoin: "round"
264
- }
265
- ),
266
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "xp-gradient", x1: "13", y1: "2", x2: "13", y2: "21.5", gradientUnits: "userSpaceOnUse", children: [
267
- /* @__PURE__ */ jsx("stop", { stopColor: "#FDE68A" }),
268
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#F59E0B" })
269
- ] }) })
270
- ] });
271
- }
272
- function PointsIcon() {
273
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: [
274
- /* @__PURE__ */ jsx(
275
- "path",
276
- {
277
- d: "M12 2L14.4 8.6L21.5 9.2L16.2 13.8L17.8 20.8L12 17.1L6.2 20.8L7.8 13.8L2.5 9.2L9.6 8.6L12 2Z",
278
- fill: "url(#points-gradient)"
279
- }
280
- ),
281
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "points-gradient", x1: "12", y1: "2", x2: "12", y2: "20.8", gradientUnits: "userSpaceOnUse", children: [
282
- /* @__PURE__ */ jsx("stop", { stopColor: "#A78BFA" }),
283
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#7C3AED" })
284
- ] }) })
285
- ] });
286
- }
287
- function DefaultIcon({
288
- type
289
- }) {
290
- switch (type) {
291
- case UserCenterRewardCardType.Token:
292
- return /* @__PURE__ */ jsx(TokenIcon, {});
293
- case UserCenterRewardCardType.Nft:
294
- return /* @__PURE__ */ jsx(NftIcon, {});
295
- case UserCenterRewardCardType.Whitelist:
296
- return /* @__PURE__ */ jsx(WhitelistIcon, {});
297
- case UserCenterRewardCardType.DiscordRole:
298
- return /* @__PURE__ */ jsx(DiscordRoleIcon, {});
299
- case UserCenterRewardCardType.Points:
300
- return /* @__PURE__ */ jsx(PointsIcon, {});
301
- case UserCenterRewardCardType.XpLevel:
302
- return /* @__PURE__ */ jsx(XpLevelIcon, {});
303
- default:
304
- return /* @__PURE__ */ jsx(PointsIcon, {});
305
- }
306
- }
307
- function needsLightBackground(type) {
308
- return type === UserCenterRewardCardType.Whitelist;
309
- }
310
- function AssetCard({
311
- type,
312
- value,
313
- selected = false,
314
- onClick,
315
- messages,
316
- pointsData,
317
- xpLevelData
318
- }) {
319
- const title = getCardTitle(type, messages, pointsData, xpLevelData);
320
- const iconUrl = getCardIconUrl(type, pointsData);
321
- const iconClassName = `taskon-asset-card__icon${needsLightBackground(type) ? " taskon-asset-card__icon--light" : ""}`;
322
- return /* @__PURE__ */ jsxs(
323
- "button",
324
- {
325
- type: "button",
326
- className: `taskon-asset-card ${selected ? "taskon-asset-card--selected" : ""}`,
327
- onClick,
328
- "aria-pressed": selected,
329
- children: [
330
- /* @__PURE__ */ jsx("div", { className: iconClassName, children: iconUrl ? /* @__PURE__ */ jsx("img", { src: iconUrl, alt: title, className: "taskon-asset-card__icon-img" }) : /* @__PURE__ */ jsx(DefaultIcon, { type }) }),
331
- /* @__PURE__ */ jsxs("div", { className: "taskon-asset-card__content", children: [
332
- /* @__PURE__ */ jsx("span", { className: "taskon-asset-card__title", children: title }),
333
- /* @__PURE__ */ jsx("span", { className: "taskon-asset-card__value", children: value })
334
- ] })
335
- ]
336
- }
337
- );
338
- }
339
- function AssetCarousel({
340
- cards,
341
- selectedCard,
342
- selectedPointsId,
343
- onSelectCard,
344
- messages
345
- }) {
346
- const containerRef = useRef(null);
347
- const [showLeftArrow, setShowLeftArrow] = useState(false);
348
- const [showRightArrow, setShowRightArrow] = useState(false);
349
- const visibleCards = cards.filter((card) => card.visible);
350
- const checkScrollArrows = useCallback(() => {
351
- const container = containerRef.current;
352
- if (!container) return;
353
- const { scrollLeft, scrollWidth, clientWidth } = container;
354
- setShowLeftArrow(scrollLeft > 0);
355
- setShowRightArrow(scrollLeft + clientWidth < scrollWidth - 1);
356
- }, []);
357
- useCallback(
358
- (direction) => {
359
- const container = containerRef.current;
360
- if (!container) return;
361
- const scrollAmount = 200;
362
- const newScrollLeft = direction === "left" ? container.scrollLeft - scrollAmount : container.scrollLeft + scrollAmount;
363
- container.scrollTo({
364
- left: newScrollLeft,
365
- behavior: "smooth"
366
- });
367
- },
368
- []
369
- );
370
- const isCardSelected = useCallback(
371
- (card) => {
372
- if (selectedCard !== card.type) return false;
373
- if (card.type === "Points" && card.pointsData) {
374
- return selectedPointsId === card.pointsData.points_id;
375
- }
376
- return true;
377
- },
378
- [selectedCard, selectedPointsId]
379
- );
380
- useEffect(() => {
381
- const container = containerRef.current;
382
- if (!container) return;
383
- checkScrollArrows();
384
- container.addEventListener("scroll", checkScrollArrows);
385
- window.addEventListener("resize", checkScrollArrows);
386
- return () => {
387
- container.removeEventListener("scroll", checkScrollArrows);
388
- window.removeEventListener("resize", checkScrollArrows);
389
- };
390
- }, [checkScrollArrows, visibleCards]);
391
- if (visibleCards.length === 0) {
392
- return /* @__PURE__ */ jsx("div", { className: "taskon-asset-carousel--empty" });
393
- }
394
- return /* @__PURE__ */ jsxs("div", { className: "taskon-asset-carousel", children: [
395
- /* @__PURE__ */ jsx("h3", { className: "taskon-asset-carousel__title", children: messages.sectionYouHaveEarned ?? "You have earned" }),
396
- /* @__PURE__ */ jsx("div", { ref: containerRef, className: "taskon-asset-carousel__container", children: visibleCards.map((card, index) => {
397
- var _a;
398
- return /* @__PURE__ */ jsx(
399
- AssetCard,
400
- {
401
- type: card.type,
402
- value: card.value,
403
- selected: isCardSelected(card),
404
- onClick: () => {
405
- var _a2;
406
- return onSelectCard(card.type, (_a2 = card.pointsData) == null ? void 0 : _a2.points_id);
407
- },
408
- messages,
409
- pointsData: card.pointsData,
410
- xpLevelData: card.xpLevelData
411
- },
412
- `${card.type}-${((_a = card.pointsData) == null ? void 0 : _a.points_id) ?? index}`
413
- );
414
- }) })
415
- ] });
416
- }
417
- function ProgressBar({
418
- value,
419
- max,
420
- showPercent = false,
421
- showValues = false,
422
- height = 8,
423
- className = "",
424
- color,
425
- backgroundColor
426
- }) {
427
- const percent = max > 0 ? Math.min(100, Math.max(0, value / max * 100)) : 0;
428
- const formatValue = (val) => {
429
- if (val >= 1e6) {
430
- return `${(val / 1e6).toFixed(1)}M`;
431
- }
432
- if (val >= 1e3) {
433
- return `${(val / 1e3).toFixed(1)}K`;
434
- }
435
- return val.toLocaleString();
436
- };
437
- const containerStyle = {
438
- height: `${height}px`,
439
- ...backgroundColor && { backgroundColor }
440
- };
441
- const fillStyle = {
442
- width: `${percent}%`,
443
- ...color && { backgroundColor: color }
444
- };
445
- return /* @__PURE__ */ jsxs("div", { className: `taskon-progress-bar ${className}`, children: [
446
- /* @__PURE__ */ jsx("div", { className: "taskon-progress-bar__container", style: containerStyle, children: /* @__PURE__ */ jsx("div", { className: "taskon-progress-bar__fill", style: fillStyle }) }),
447
- (showPercent || showValues) && /* @__PURE__ */ jsxs("div", { className: "taskon-progress-bar__info", children: [
448
- showValues && /* @__PURE__ */ jsxs("span", { className: "taskon-progress-bar__values", children: [
449
- formatValue(value),
450
- " / ",
451
- formatValue(max)
452
- ] }),
453
- showPercent && /* @__PURE__ */ jsxs("span", { className: "taskon-progress-bar__percent", children: [
454
- percent.toFixed(0),
455
- "%"
456
- ] })
457
- ] })
458
- ] });
459
- }
460
- function formatNumber(val) {
461
- if (Math.abs(val) >= 1e6) {
462
- return `${(val / 1e6).toFixed(1)}M`;
463
- }
464
- if (Math.abs(val) >= 1e3) {
465
- return `${(val / 1e3).toFixed(1)}K`;
466
- }
467
- return val.toLocaleString();
468
- }
469
- function XpLevelCard({
470
- xpData,
471
- historyData,
472
- historyLoading,
473
- historyError,
474
- pagination,
475
- messages,
476
- className = ""
477
- }) {
478
- var _a;
479
- const { level, currentXp, nextLevelXp, totalXp } = xpData;
480
- const pointsName = ((_a = xpData.pointsName) == null ? void 0 : _a.trim()) || "XP";
481
- const xpToNext = Math.max(0, nextLevelXp - currentXp);
482
- const columns = [
483
- {
484
- key: "detail",
485
- title: messages.columnDetail,
486
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-points-list__name", children: row.name })
487
- },
488
- {
489
- key: "time",
490
- title: messages.columnTime,
491
- width: 160,
492
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-points-list__time", children: formatDateTime(row.receive_time) })
493
- },
494
- {
495
- key: "amount",
496
- title: `${messages.columnAmount} (${pointsName})`,
497
- width: 160,
498
- align: "right",
499
- render: (_, row) => {
500
- const isPositive = row.points.amount >= 0;
501
- return /* @__PURE__ */ jsxs("div", { className: "taskon-points-list__amount-cell", children: [
502
- row.points.points_icon && /* @__PURE__ */ jsx(
503
- "img",
504
- {
505
- src: row.points.points_icon,
506
- alt: "",
507
- className: "taskon-points-list__amount-icon"
508
- }
509
- ),
510
- /* @__PURE__ */ jsxs(
511
- "span",
512
- {
513
- className: `taskon-points-list__amount-value ${isPositive ? "taskon-points-list__amount-value--positive" : "taskon-points-list__amount-value--negative"}`,
514
- children: [
515
- isPositive ? "+" : "",
516
- formatNumber(row.points.amount)
517
- ]
518
- }
519
- )
520
- ] });
521
- }
522
- }
523
- ];
524
- return /* @__PURE__ */ jsxs("div", { className: `taskon-xp-level-card ${className}`, children: [
525
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__header", children: [
526
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__level", children: [
527
- /* @__PURE__ */ jsx("div", { className: "taskon-xp-level-card__level-badge", children: level }),
528
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__level-info", children: [
529
- /* @__PURE__ */ jsx("span", { className: "taskon-xp-level-card__level-label", children: messages.level }),
530
- /* @__PURE__ */ jsxs("span", { className: "taskon-xp-level-card__level-value", children: [
531
- messages.level,
532
- " ",
533
- level
534
- ] })
535
- ] })
536
- ] }),
537
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__xp", children: [
538
- /* @__PURE__ */ jsx("span", { className: "taskon-xp-level-card__xp-label", children: messages.totalXp }),
539
- /* @__PURE__ */ jsxs("span", { className: "taskon-xp-level-card__xp-value", children: [
540
- formatNumber(totalXp),
541
- " ",
542
- pointsName
543
- ] })
544
- ] })
545
- ] }),
546
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__progress", children: [
547
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__progress-label", children: [
548
- /* @__PURE__ */ jsxs("span", { children: [
549
- formatNumber(currentXp),
550
- " / ",
551
- formatNumber(nextLevelXp),
552
- " ",
553
- pointsName
554
- ] }),
555
- /* @__PURE__ */ jsxs("span", { children: [
556
- messages.xpToNextLevel,
557
- ": ",
558
- formatNumber(xpToNext),
559
- " ",
560
- pointsName
561
- ] })
562
- ] }),
563
- /* @__PURE__ */ jsx(ProgressBar, { value: currentXp, max: nextLevelXp, height: 10 })
564
- ] }),
565
- /* @__PURE__ */ jsxs("div", { className: "taskon-xp-level-card__history", children: [
566
- /* @__PURE__ */ jsx("h4", { className: "taskon-xp-level-card__history-title", children: messages.xpHistory }),
567
- historyLoading && historyData.length === 0 && /* @__PURE__ */ jsx(LoadingState, { message: messages.loading }),
568
- historyError && historyData.length === 0 && /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: historyError.message }) }),
569
- !historyLoading && !historyError && historyData.length === 0 && /* @__PURE__ */ jsx(EmptyState, { message: messages.noData }),
570
- historyData.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
571
- /* @__PURE__ */ jsx("div", { className: "taskon-xp-level-card__table-wrap", children: /* @__PURE__ */ jsx(
572
- Table,
573
- {
574
- columns,
575
- data: historyData,
576
- rowConfig: {
577
- getRowKey: (row, index) => `${row.campaign_id ?? row.task_id ?? "item"}-${row.receive_time}-${index}`
578
- },
579
- loading: historyLoading && historyData.length > 0,
580
- loadingText: messages.loading,
581
- empty: {
582
- title: messages.noData
583
- }
584
- }
585
- ) }),
586
- pagination.totalPages > 1 && /* @__PURE__ */ jsx(
587
- Pagination,
588
- {
589
- page: pagination.page,
590
- totalPages: pagination.totalPages,
591
- onPrevious: pagination.goToPrevious,
592
- onNext: pagination.goToNext,
593
- hasPrevious: pagination.hasPrevious,
594
- hasNext: pagination.hasNext,
595
- messages
596
- }
597
- )
598
- ] })
599
- ] })
600
- ] });
601
- }
602
- function WhitelistTable({
603
- data,
604
- loading,
605
- error,
606
- pagination,
607
- messages
608
- }) {
609
- if (loading && data.length === 0) {
610
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
611
- }
612
- if (error && data.length === 0) {
613
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error.message }) });
614
- }
615
- if (!loading && data.length === 0) {
616
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.noData });
617
- }
618
- const columns = [
619
- {
620
- key: "whitelist",
621
- title: messages.columnWhitelist,
622
- width: 100,
623
- render: (_, row) => {
624
- const wlValue = row.reward_value;
625
- return /* @__PURE__ */ jsx(
626
- AssetImage,
627
- {
628
- src: wlValue.nft_image,
629
- chain: wlValue.chain,
630
- alt: "Whitelist",
631
- size: 60,
632
- useWhitelistDefault: !wlValue.nft_image
633
- }
634
- );
635
- }
636
- },
637
- {
638
- key: "detail",
639
- title: messages.columnDetail,
640
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__campaign-name", children: row.campaign_name })
641
- },
642
- {
643
- key: "time",
644
- title: messages.columnTime,
645
- width: 160,
646
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__time", children: formatDateTime(row.reward_time) })
647
- },
648
- {
649
- key: "status",
650
- title: messages.columnStatus,
651
- width: 120,
652
- align: "right",
653
- render: () => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__manual-drop", children: messages.manualDrop })
654
- }
655
- ];
656
- return /* @__PURE__ */ jsxs("div", { className: "taskon-reward-table", children: [
657
- /* @__PURE__ */ jsx(
658
- Table,
659
- {
660
- columns,
661
- data,
662
- rowConfig: {
663
- getRowKey: (row, index) => `${row.campaign_id}-${row.reward_time}-${index}`
664
- },
665
- loading: loading && data.length > 0,
666
- loadingText: messages.loading,
667
- empty: {
668
- title: messages.noData
669
- }
670
- }
671
- ),
672
- pagination.totalPages > 1 && /* @__PURE__ */ jsx(
673
- Pagination,
674
- {
675
- page: pagination.page,
676
- totalPages: pagination.totalPages,
677
- onPrevious: pagination.goToPrevious,
678
- onNext: pagination.goToNext,
679
- hasPrevious: pagination.hasPrevious,
680
- hasNext: pagination.hasNext,
681
- messages
682
- }
683
- )
684
- ] });
685
- }
686
- function DiscordRoleTable({
687
- data,
688
- loading,
689
- error,
690
- pagination,
691
- messages
692
- }) {
693
- if (loading && data.length === 0) {
694
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
695
- }
696
- if (error && data.length === 0) {
697
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error.message }) });
698
- }
699
- if (!loading && data.length === 0) {
700
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.noData });
701
- }
702
- const columns = [
703
- {
704
- key: "discordRole",
705
- title: messages.columnDiscordRole,
706
- width: 160,
707
- render: (_, row) => {
708
- const dcValue = row.reward_value;
709
- return /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__role-name", children: dcValue.role_name });
710
- }
711
- },
712
- {
713
- key: "detail",
714
- title: messages.columnDetail,
715
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__campaign-name", children: row.milestone_name || row.campaign_name })
716
- },
717
- {
718
- key: "time",
719
- title: messages.columnTime,
720
- width: 160,
721
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__time", children: formatDateTime(row.reward_time) })
722
- },
723
- {
724
- key: "status",
725
- title: messages.columnStatus,
726
- width: 120,
727
- align: "right",
728
- render: () => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__manual-drop", children: messages.manualDrop })
729
- }
730
- ];
731
- return /* @__PURE__ */ jsxs("div", { className: "taskon-reward-table", children: [
732
- /* @__PURE__ */ jsx(
733
- Table,
734
- {
735
- columns,
736
- data,
737
- rowConfig: {
738
- getRowKey: (row, index) => `${row.campaign_id}-${row.reward_time}-${index}`
739
- },
740
- loading: loading && data.length > 0,
741
- loadingText: messages.loading,
742
- empty: {
743
- title: messages.noData
744
- }
745
- }
746
- ),
747
- pagination.totalPages > 1 && /* @__PURE__ */ jsx(
748
- Pagination,
749
- {
750
- page: pagination.page,
751
- totalPages: pagination.totalPages,
752
- onPrevious: pagination.goToPrevious,
753
- onNext: pagination.goToNext,
754
- hasPrevious: pagination.hasPrevious,
755
- hasNext: pagination.hasNext,
756
- messages
757
- }
758
- )
759
- ] });
760
- }
761
- function useActivityHistory(options = {}) {
762
- const {
763
- pageSize = USER_CENTER_PAGE_SIZE,
764
- mode = "pagination",
765
- autoLoad = true
766
- } = options;
767
- const { client } = useTaskOnContext();
768
- const [data, setData] = useState([]);
769
- const [total, setTotal] = useState(0);
770
- const [loading, setLoading] = useState(false);
771
- const [error, setError] = useState(null);
772
- const isInitialLoad = useRef(true);
773
- const lastFetchedPage = useRef(null);
774
- const api = useMemo(() => {
775
- if (!client) return null;
776
- return createUserCenterApi(client);
777
- }, [client]);
778
- const pagination = usePagination({
779
- total,
780
- pageSize,
781
- initialPage: 0,
782
- // 使用 0-based 索引
783
- mode
784
- });
785
- const fetchData = useCallback(
786
- async (pageNo, append = false) => {
787
- if (!api) {
788
- setError(new Error("TaskOn client not initialized"));
789
- return;
790
- }
791
- if (lastFetchedPage.current === pageNo && !append) {
792
- return;
793
- }
794
- setLoading(true);
795
- setError(null);
796
- lastFetchedPage.current = pageNo;
797
- try {
798
- const response = await api.getMyCampaignHistory({
799
- page: {
800
- page_no: pageNo,
801
- // API 使用 0-based 索引
802
- size: pageSize
803
- }
804
- });
805
- if (append) {
806
- setData((prev) => [...prev, ...response.data]);
807
- } else {
808
- setData(response.data);
809
- }
810
- setTotal(response.total);
811
- } catch (err) {
812
- setError(
813
- err instanceof Error ? err : new Error("Failed to fetch activity history")
814
- );
815
- } finally {
816
- setLoading(false);
817
- }
818
- },
819
- [api, pageSize]
820
- );
821
- const refresh = useCallback(async () => {
822
- pagination.goToPage(0);
823
- setData([]);
824
- lastFetchedPage.current = null;
825
- await fetchData(0, false);
826
- }, [fetchData, pagination]);
827
- useEffect(() => {
828
- if (autoLoad && isInitialLoad.current) {
829
- isInitialLoad.current = false;
830
- fetchData(0, false);
831
- }
832
- }, [autoLoad, fetchData]);
833
- useEffect(() => {
834
- if (isInitialLoad.current) {
835
- return;
836
- }
837
- if (mode === "pagination") {
838
- fetchData(pagination.page, false);
839
- }
840
- }, [mode, pagination.page, fetchData]);
841
- useEffect(() => {
842
- if (mode === "infinite" && pagination.loadedCount > pageSize) {
843
- const nextPage = Math.ceil(pagination.loadedCount / pageSize) - 1;
844
- fetchData(nextPage, true);
845
- }
846
- }, [mode, pagination.loadedCount, pageSize, fetchData]);
847
- return {
848
- data,
849
- loading,
850
- error,
851
- total,
852
- pagination,
853
- refresh
854
- };
855
- }
856
- function useUserRewards(options = {}) {
857
- const { autoLoad = true } = options;
858
- const { client } = useTaskOnContext();
859
- const [rewards, setRewards] = useState(null);
860
- const [userInfo, setUserInfo] = useState(null);
861
- const [selectedCard, setSelectedCard] = useState(null);
862
- const [loading, setLoading] = useState(false);
863
- const [error, setError] = useState(null);
864
- const api = useMemo(() => {
865
- if (!client) return null;
866
- return createUserCenterApi(client);
867
- }, [client]);
868
- const cards = useMemo(() => {
869
- if (!rewards) return [];
870
- return buildRewardCards(rewards, userInfo);
871
- }, [rewards, userInfo]);
872
- const fetchData = useCallback(async () => {
873
- if (!api) {
874
- setError(new Error("TaskOn client not initialized"));
875
- return;
876
- }
877
- setLoading(true);
878
- setError(null);
879
- try {
880
- const [rewardsResponse, userInfoResponse] = await Promise.all([
881
- api.getMyCommunityRewards({}),
882
- api.getCUserInfo({})
883
- ]);
884
- setRewards(rewardsResponse);
885
- setUserInfo(userInfoResponse);
886
- const builtCards = buildRewardCards(rewardsResponse, userInfoResponse);
887
- const firstVisibleCard = builtCards.find((c) => c.visible);
888
- if (firstVisibleCard && !selectedCard) {
889
- setSelectedCard(firstVisibleCard.type);
890
- }
891
- } catch (err) {
892
- setError(
893
- err instanceof Error ? err : new Error("Failed to fetch rewards")
894
- );
895
- } finally {
896
- setLoading(false);
897
- }
898
- }, [api, selectedCard]);
899
- const selectCard = useCallback((type) => {
900
- setSelectedCard(type);
901
- }, []);
902
- const refresh = useCallback(async () => {
903
- await fetchData();
904
- }, [fetchData]);
905
- useEffect(() => {
906
- if (autoLoad) {
907
- fetchData();
908
- }
909
- }, [autoLoad, fetchData]);
910
- return {
911
- rewards,
912
- userInfo,
913
- cards,
914
- selectedCard,
915
- selectCard,
916
- loading,
917
- error,
918
- refresh
919
- };
920
- }
921
- function useFrozenAssets(options) {
922
- const { tokenId, pageSize = USER_CENTER_PAGE_SIZE, autoLoad = true } = options;
923
- const { client } = useTaskOnContext();
924
- const [data, setData] = useState([]);
925
- const [total, setTotal] = useState(0);
926
- const [loading, setLoading] = useState(false);
927
- const [error, setError] = useState(null);
928
- const api = useMemo(() => {
929
- if (!client) return null;
930
- return createUserCenterApi(client);
931
- }, [client]);
932
- const pagination = usePagination({
933
- total,
934
- pageSize,
935
- initialPage: 0,
936
- mode: "pagination"
937
- });
938
- const skipNextPageEffectRef = useRef(false);
939
- const fetchData = useCallback(
940
- async (pageNo) => {
941
- if (!api) {
942
- setError(new Error("TaskOn client not initialized"));
943
- return;
944
- }
945
- if (!tokenId) {
946
- setError(new Error("Token ID is required"));
947
- return;
948
- }
949
- setLoading(true);
950
- setError(null);
951
- try {
952
- const response = await api.getLockedTokenList({
953
- token_id: tokenId,
954
- page: {
955
- page_no: pageNo,
956
- // API 使用 0-based 索引
957
- size: pageSize
958
- }
959
- });
960
- setData(response.data);
961
- setTotal(response.total);
962
- } catch (err) {
963
- setError(
964
- err instanceof Error ? err : new Error("Failed to fetch frozen assets")
965
- );
966
- } finally {
967
- setLoading(false);
968
- }
969
- },
970
- [api, tokenId, pageSize]
971
- );
972
- const refresh = useCallback(async () => {
973
- if (autoLoad && pagination.page !== 0) {
974
- skipNextPageEffectRef.current = true;
975
- }
976
- pagination.goToPage(0);
977
- await fetchData(0);
978
- }, [autoLoad, fetchData, pagination]);
979
- const canResend = useCallback((item) => {
980
- return item.type === "Withdraw" && Boolean(item.nonce) && Boolean(item.receiver_address);
981
- }, []);
982
- useEffect(() => {
983
- if (!autoLoad || !tokenId) {
984
- return;
985
- }
986
- if (skipNextPageEffectRef.current) {
987
- skipNextPageEffectRef.current = false;
988
- return;
989
- }
990
- fetchData(pagination.page);
991
- }, [autoLoad, tokenId, pagination.page, fetchData]);
992
- return {
993
- data,
994
- loading,
995
- error,
996
- total,
997
- pagination,
998
- refresh,
999
- canResend
1000
- };
1001
- }
1002
- const SNS_TYPE_MAP = {
1003
- Twitter: "Twitter",
1004
- Discord: "Discord",
1005
- Telegram: "Telegram",
1006
- Email: "Email",
1007
- Reddit: "Reddit"
1008
- };
1009
- const CHAIN_TYPE_MAP = {
1010
- evm: "evm",
1011
- solana: "solana",
1012
- sui: "sui",
1013
- aptos: "aptos",
1014
- btc: "btc",
1015
- starknet: "starknet",
1016
- tron: "tron",
1017
- ton: "ton",
1018
- nibiru: "nibiru",
1019
- kaspa: "kaspa"
1020
- };
1021
- const ALL_SOCIAL_TYPES = [
1022
- SnsType.Twitter,
1023
- SnsType.Discord,
1024
- SnsType.Telegram,
1025
- SnsType.Email,
1026
- SnsType.Reddit
1027
- ];
1028
- const ALL_CHAIN_TYPES = [
1029
- "evm",
1030
- "solana",
1031
- "sui",
1032
- "aptos",
1033
- "btc",
1034
- "starknet",
1035
- "tron",
1036
- "ton",
1037
- "nibiru",
1038
- "kaspa"
1039
- ];
1040
- function getSocialProfileUrl(snsType, username) {
1041
- switch (snsType) {
1042
- case SnsType.Twitter:
1043
- return `https://twitter.com/${username}`;
1044
- case SnsType.Discord:
1045
- return null;
1046
- case SnsType.Telegram:
1047
- return `https://t.me/${username}`;
1048
- case SnsType.Reddit:
1049
- return `https://reddit.com/user/${username}`;
1050
- case SnsType.Email:
1051
- return null;
1052
- default:
1053
- return null;
1054
- }
1055
- }
1056
- function useIdentityData() {
1057
- const { userInfo } = useTaskOnContext();
1058
- const rawSns = (userInfo == null ? void 0 : userInfo.sns) ?? [];
1059
- const rawAddresses = (userInfo == null ? void 0 : userInfo.address) ?? [];
1060
- const isLoaded = userInfo !== null;
1061
- const socialAccounts = useMemo(() => {
1062
- return ALL_SOCIAL_TYPES.map((snsType) => {
1063
- const boundAccount = rawSns.find((s) => s.sns_type === snsType);
1064
- const accountType = SNS_TYPE_MAP[snsType];
1065
- return {
1066
- accountType: accountType ?? snsType,
1067
- snsType,
1068
- isBound: !!boundAccount,
1069
- account: boundAccount ?? null,
1070
- profileUrl: boundAccount ? getSocialProfileUrl(snsType, boundAccount.sns_user_name) : null
1071
- };
1072
- });
1073
- }, [rawSns]);
1074
- const walletAddresses = useMemo(() => {
1075
- return ALL_CHAIN_TYPES.map((chainType) => {
1076
- const boundAddress = rawAddresses.find((a) => a.chain_type === chainType);
1077
- const widgetChainType = CHAIN_TYPE_MAP[chainType];
1078
- return {
1079
- chainType: widgetChainType ?? chainType,
1080
- coreChainType: chainType,
1081
- isBound: !!boundAddress,
1082
- address: boundAddress ?? null,
1083
- isPrimary: (boundAddress == null ? void 0 : boundAddress.is_primary) ?? false,
1084
- // 暂时没有 KYC 信息,后续可扩展
1085
- isKycVerified: void 0
1086
- };
1087
- });
1088
- }, [rawAddresses]);
1089
- const totalBoundCount = useMemo(() => {
1090
- const boundSocialCount = socialAccounts.filter((a) => a.isBound).length;
1091
- const boundWalletCount = walletAddresses.filter((a) => a.isBound).length;
1092
- return boundSocialCount + boundWalletCount;
1093
- }, [socialAccounts, walletAddresses]);
1094
- return {
1095
- socialAccounts,
1096
- walletAddresses,
1097
- rawSns,
1098
- rawAddresses,
1099
- isLoaded,
1100
- totalBoundCount
1101
- };
1102
- }
1103
- function useUnbindSocial(options = {}) {
1104
- const { onUnbindSuccess, onUnbindError } = options;
1105
- const { client, refreshUserInfo } = useTaskOnContext();
1106
- const [unbindStatus, setUnbindStatus] = useState("idle");
1107
- const [error, setError] = useState(null);
1108
- const [processingType, setProcessingType] = useState(null);
1109
- const api = useMemo(() => {
1110
- if (!client) return null;
1111
- return createUserApi(client);
1112
- }, [client]);
1113
- const unbind = useCallback(
1114
- async (snsId, type) => {
1115
- if (!api) {
1116
- const err = new Error("TaskOn client not initialized");
1117
- setError(err);
1118
- onUnbindError == null ? void 0 : onUnbindError(err);
1119
- return false;
1120
- }
1121
- setProcessingType(type);
1122
- setUnbindStatus("loading");
1123
- setError(null);
1124
- try {
1125
- const result = await api.unbindSNS({
1126
- sns_id: snsId,
1127
- sns_type: type
1128
- });
1129
- if (result) {
1130
- await refreshUserInfo();
1131
- setUnbindStatus("success");
1132
- onUnbindSuccess == null ? void 0 : onUnbindSuccess();
1133
- return true;
1134
- } else {
1135
- const err = new Error("Unbind failed");
1136
- setUnbindStatus("error");
1137
- setError(err);
1138
- onUnbindError == null ? void 0 : onUnbindError(err);
1139
- return false;
1140
- }
1141
- } catch (err) {
1142
- const error2 = err instanceof Error ? err : new Error("Unbind failed");
1143
- setUnbindStatus("error");
1144
- setError(error2);
1145
- onUnbindError == null ? void 0 : onUnbindError(error2);
1146
- return false;
1147
- } finally {
1148
- setProcessingType(null);
1149
- }
1150
- },
1151
- [api, refreshUserInfo, onUnbindSuccess, onUnbindError]
1152
- );
1153
- const reset = useCallback(() => {
1154
- setUnbindStatus("idle");
1155
- setError(null);
1156
- setProcessingType(null);
1157
- }, []);
1158
- return {
1159
- unbindStatus,
1160
- error,
1161
- processingType,
1162
- unbind,
1163
- reset
1164
- };
1165
- }
1166
- const COUNTDOWN_SECONDS = 60;
1167
- const EMAIL_REGEX$1 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1168
- const SNS_BIND_DUPLICATE_ERROR = 10016;
1169
- const INVALID_EMAIL_VERIFY_CODE = 10017;
1170
- function useBindEmail(options = {}) {
1171
- const { onSendCodeSuccess, onSendCodeError, onBindSuccess, onBindError } = options;
1172
- const { client, refreshUserInfo } = useTaskOnContext();
1173
- const [status, setStatus] = useState("idle");
1174
- const [countdown, setCountdown] = useState(0);
1175
- const [error, setError] = useState(null);
1176
- const [isEmailDuplicate, setIsEmailDuplicate] = useState(false);
1177
- const [isCodeInvalid, setIsCodeInvalid] = useState(false);
1178
- const [email, setEmail] = useState("");
1179
- const countdownTimerRef = useRef(null);
1180
- const api = useMemo(() => {
1181
- if (!client) return null;
1182
- return createUserApi(client);
1183
- }, [client]);
1184
- const startCountdown = useCallback(() => {
1185
- setCountdown(COUNTDOWN_SECONDS);
1186
- countdownTimerRef.current = setInterval(() => {
1187
- setCountdown((prev) => {
1188
- if (prev <= 1) {
1189
- if (countdownTimerRef.current) {
1190
- clearInterval(countdownTimerRef.current);
1191
- countdownTimerRef.current = null;
1192
- }
1193
- return 0;
1194
- }
1195
- return prev - 1;
1196
- });
1197
- }, 1e3);
1198
- }, []);
1199
- const stopCountdown = useCallback(() => {
1200
- if (countdownTimerRef.current) {
1201
- clearInterval(countdownTimerRef.current);
1202
- countdownTimerRef.current = null;
1203
- }
1204
- setCountdown(0);
1205
- }, []);
1206
- useEffect(() => {
1207
- return () => {
1208
- if (countdownTimerRef.current) {
1209
- clearInterval(countdownTimerRef.current);
1210
- }
1211
- };
1212
- }, []);
1213
- const open = useCallback(() => {
1214
- setStatus("inputEmail");
1215
- setError(null);
1216
- setIsEmailDuplicate(false);
1217
- setIsCodeInvalid(false);
1218
- }, []);
1219
- const close = useCallback(() => {
1220
- setStatus("idle");
1221
- setError(null);
1222
- setIsEmailDuplicate(false);
1223
- setIsCodeInvalid(false);
1224
- setEmail("");
1225
- stopCountdown();
1226
- }, [stopCountdown]);
1227
- const clearError = useCallback(() => {
1228
- setError(null);
1229
- setIsEmailDuplicate(false);
1230
- setIsCodeInvalid(false);
1231
- }, []);
1232
- const sendCode = useCallback(
1233
- async (emailAddress) => {
1234
- if (!api) {
1235
- const err = new Error("TaskOn client not initialized");
1236
- setError(err);
1237
- onSendCodeError == null ? void 0 : onSendCodeError(err);
1238
- return false;
1239
- }
1240
- if (!EMAIL_REGEX$1.test(emailAddress)) {
1241
- const err = new Error("Invalid email format");
1242
- setError(err);
1243
- onSendCodeError == null ? void 0 : onSendCodeError(err);
1244
- return false;
1245
- }
1246
- setStatus("sendingCode");
1247
- setError(null);
1248
- setIsEmailDuplicate(false);
1249
- try {
1250
- const result = await api.requestEmailVerifyCode({
1251
- email: emailAddress,
1252
- type: VerifyCodeType.Bind
1253
- });
1254
- if (result) {
1255
- setStatus("inputCode");
1256
- setEmail(emailAddress);
1257
- startCountdown();
1258
- onSendCodeSuccess == null ? void 0 : onSendCodeSuccess();
1259
- return true;
1260
- } else {
1261
- const err = new Error("Failed to send verification code");
1262
- setStatus("inputEmail");
1263
- setError(err);
1264
- onSendCodeError == null ? void 0 : onSendCodeError(err);
1265
- return false;
1266
- }
1267
- } catch (err) {
1268
- const error2 = err;
1269
- if (error2.code === SNS_BIND_DUPLICATE_ERROR) {
1270
- setIsEmailDuplicate(true);
1271
- }
1272
- setStatus("inputEmail");
1273
- setError(error2);
1274
- onSendCodeError == null ? void 0 : onSendCodeError(error2);
1275
- return false;
1276
- }
1277
- },
1278
- [api, onSendCodeSuccess, onSendCodeError, startCountdown]
1279
- );
1280
- const bind = useCallback(
1281
- async (emailAddress, code) => {
1282
- if (!api) {
1283
- const err = new Error("TaskOn client not initialized");
1284
- setError(err);
1285
- onBindError == null ? void 0 : onBindError(err);
1286
- return null;
1287
- }
1288
- setStatus("submitting");
1289
- setError(null);
1290
- setIsCodeInvalid(false);
1291
- try {
1292
- const result = await api.bindSNS({
1293
- sns_type: SnsType.Email,
1294
- token: code,
1295
- sns_user_name: emailAddress
1296
- });
1297
- if (result.result) {
1298
- await refreshUserInfo();
1299
- setStatus("success");
1300
- onBindSuccess == null ? void 0 : onBindSuccess(result);
1301
- return result;
1302
- } else {
1303
- const err = new Error("Email is already linked to another account");
1304
- setStatus("inputCode");
1305
- setError(err);
1306
- onBindError == null ? void 0 : onBindError(err);
1307
- return null;
1308
- }
1309
- } catch (err) {
1310
- const error2 = err;
1311
- if (error2.code === INVALID_EMAIL_VERIFY_CODE) {
1312
- setIsCodeInvalid(true);
1313
- }
1314
- setStatus("inputCode");
1315
- setError(error2);
1316
- onBindError == null ? void 0 : onBindError(error2);
1317
- return null;
1318
- }
1319
- },
1320
- [api, refreshUserInfo, onBindSuccess, onBindError]
1321
- );
1322
- const reset = useCallback(() => {
1323
- setStatus("idle");
1324
- setError(null);
1325
- setIsEmailDuplicate(false);
1326
- setIsCodeInvalid(false);
1327
- setEmail("");
1328
- stopCountdown();
1329
- }, [stopCountdown]);
1330
- return {
1331
- status,
1332
- countdown,
1333
- error,
1334
- isEmailDuplicate,
1335
- isCodeInvalid,
1336
- email,
1337
- open,
1338
- close,
1339
- setEmail,
1340
- sendCode,
1341
- bind,
1342
- reset,
1343
- clearError
1344
- };
1345
- }
1346
- function generateSignMessage(action, address, nonce) {
1347
- return `TaskOn ${action} wallet
1348
- Address: ${address}
1349
- Nonce: ${nonce}`;
1350
- }
1351
- function generateNonce() {
1352
- return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
1353
- }
1354
- function useBindWallet(options = {}) {
1355
- const {
1356
- onBindSuccess,
1357
- onBindError,
1358
- onUnbindSuccess,
1359
- onUnbindError
1360
- } = options;
1361
- const { client, refreshUserInfo } = useTaskOnContext();
1362
- const {
1363
- connectEvm,
1364
- signEvmMessage,
1365
- evmAddress: connectedAddress,
1366
- isEvmConnected: isConnected
1367
- } = useWallet();
1368
- const [bindStatus, setBindStatus] = useState("idle");
1369
- const [unbindStatus, setUnbindStatus] = useState("idle");
1370
- const [error, setError] = useState(null);
1371
- const [processingChain, setProcessingChain] = useState(null);
1372
- const api = useMemo(() => {
1373
- if (!client) return null;
1374
- return createUserApi(client);
1375
- }, [client]);
1376
- const bind = useCallback(
1377
- async (chainType) => {
1378
- if (!api) {
1379
- const err = new Error("TaskOn client not initialized");
1380
- setError(err);
1381
- onBindError == null ? void 0 : onBindError(err);
1382
- return false;
1383
- }
1384
- setProcessingChain(chainType);
1385
- setBindStatus("connecting");
1386
- setError(null);
1387
- try {
1388
- let walletAddress = connectedAddress;
1389
- if (!isConnected || !walletAddress) {
1390
- setBindStatus("connecting");
1391
- const connectResult = await connectEvm();
1392
- if (!connectResult) {
1393
- throw new Error("Failed to connect wallet");
1394
- }
1395
- walletAddress = connectResult;
1396
- }
1397
- if (!walletAddress) {
1398
- throw new Error("No wallet address available");
1399
- }
1400
- const nonce = generateNonce();
1401
- const message = generateSignMessage("bind", walletAddress, nonce);
1402
- setBindStatus("signing");
1403
- const signature = await signEvmMessage(message);
1404
- if (!signature) {
1405
- throw new Error("Failed to sign message");
1406
- }
1407
- setBindStatus("submitting");
1408
- const result = await api.bindAddress({
1409
- chain_type: chainType,
1410
- address: walletAddress,
1411
- nonce,
1412
- sig: signature
1413
- });
1414
- if (result) {
1415
- await refreshUserInfo();
1416
- setBindStatus("success");
1417
- onBindSuccess == null ? void 0 : onBindSuccess();
1418
- return true;
1419
- } else {
1420
- throw new Error("Bind wallet failed");
1421
- }
1422
- } catch (err) {
1423
- const error2 = err instanceof Error ? err : new Error("Bind wallet failed");
1424
- setBindStatus("error");
1425
- setError(error2);
1426
- onBindError == null ? void 0 : onBindError(error2);
1427
- return false;
1428
- } finally {
1429
- setProcessingChain(null);
1430
- }
1431
- },
1432
- [
1433
- api,
1434
- refreshUserInfo,
1435
- connectEvm,
1436
- signEvmMessage,
1437
- connectedAddress,
1438
- isConnected,
1439
- onBindSuccess,
1440
- onBindError
1441
- ]
1442
- );
1443
- const unbind = useCallback(
1444
- async (chainType, address) => {
1445
- if (!api) {
1446
- const err = new Error("TaskOn client not initialized");
1447
- setError(err);
1448
- onUnbindError == null ? void 0 : onUnbindError(err);
1449
- return false;
1450
- }
1451
- setProcessingChain(chainType);
1452
- setUnbindStatus("connecting");
1453
- setError(null);
1454
- try {
1455
- let walletAddress = connectedAddress;
1456
- if (!isConnected || !walletAddress) {
1457
- setUnbindStatus("connecting");
1458
- const connectResult = await connectEvm();
1459
- if (!connectResult) {
1460
- throw new Error("Failed to connect wallet");
1461
- }
1462
- walletAddress = connectResult;
1463
- }
1464
- if ((walletAddress == null ? void 0 : walletAddress.toLowerCase()) !== address.toLowerCase()) {
1465
- throw new Error(
1466
- "Connected wallet address does not match the address to unbind. Please connect the correct wallet."
1467
- );
1468
- }
1469
- const nonce = generateNonce();
1470
- const message = generateSignMessage("unbind", address, nonce);
1471
- setUnbindStatus("signing");
1472
- const signature = await signEvmMessage(message);
1473
- if (!signature) {
1474
- throw new Error("Failed to sign message");
1475
- }
1476
- setUnbindStatus("submitting");
1477
- const result = await api.unbindAddress({
1478
- chain_type: chainType,
1479
- address,
1480
- nonce,
1481
- sig: signature
1482
- });
1483
- if (result) {
1484
- await refreshUserInfo();
1485
- setUnbindStatus("success");
1486
- onUnbindSuccess == null ? void 0 : onUnbindSuccess();
1487
- return true;
1488
- } else {
1489
- throw new Error("Unbind wallet failed");
1490
- }
1491
- } catch (err) {
1492
- const error2 = err instanceof Error ? err : new Error("Unbind wallet failed");
1493
- setUnbindStatus("error");
1494
- setError(error2);
1495
- onUnbindError == null ? void 0 : onUnbindError(error2);
1496
- return false;
1497
- } finally {
1498
- setProcessingChain(null);
1499
- }
1500
- },
1501
- [
1502
- api,
1503
- refreshUserInfo,
1504
- connectEvm,
1505
- signEvmMessage,
1506
- connectedAddress,
1507
- isConnected,
1508
- onUnbindSuccess,
1509
- onUnbindError
1510
- ]
1511
- );
1512
- const reset = useCallback(() => {
1513
- setBindStatus("idle");
1514
- setUnbindStatus("idle");
1515
- setError(null);
1516
- setProcessingChain(null);
1517
- }, []);
1518
- return {
1519
- bindStatus,
1520
- unbindStatus,
1521
- error,
1522
- processingChain,
1523
- bind,
1524
- unbind,
1525
- reset
1526
- };
1527
- }
1528
- const OAUTH_SNS_TYPES = ["Twitter", "Discord", "Telegram"];
1529
- function useOAuthBindings(options = {}) {
1530
- const { onSuccess, onFailed } = options;
1531
- const {
1532
- bindIfNeed: bindTwitter,
1533
- isWaitingAuth: isTwitterBinding
1534
- } = useBindSocialAccount({
1535
- snsType: "Twitter",
1536
- onSuccess,
1537
- onFailed
1538
- });
1539
- const {
1540
- bindIfNeed: bindDiscord,
1541
- isWaitingAuth: isDiscordBinding
1542
- } = useBindSocialAccount({
1543
- snsType: "Discord",
1544
- onSuccess,
1545
- onFailed
1546
- });
1547
- const {
1548
- bindIfNeed: bindTelegram,
1549
- isWaitingAuth: isTelegramBinding
1550
- } = useBindSocialAccount({
1551
- snsType: "Telegram",
1552
- onSuccess,
1553
- onFailed
1554
- });
1555
- const bind = useCallback(
1556
- (snsType) => {
1557
- switch (snsType) {
1558
- case "Twitter":
1559
- bindTwitter();
1560
- break;
1561
- case "Discord":
1562
- bindDiscord();
1563
- break;
1564
- case "Telegram":
1565
- bindTelegram();
1566
- break;
1567
- default:
1568
- console.warn(`[useOAuthBindings] Unsupported snsType: ${snsType}`);
1569
- }
1570
- },
1571
- [bindTwitter, bindDiscord, bindTelegram]
1572
- );
1573
- const isBinding = useCallback(
1574
- (snsType) => {
1575
- switch (snsType.toLowerCase()) {
1576
- case "twitter":
1577
- return isTwitterBinding;
1578
- case "discord":
1579
- return isDiscordBinding;
1580
- case "telegram":
1581
- return isTelegramBinding;
1582
- default:
1583
- return false;
1584
- }
1585
- },
1586
- [isTwitterBinding, isDiscordBinding, isTelegramBinding]
1587
- );
1588
- const isOAuthSupported = useCallback((snsType) => {
1589
- return OAUTH_SNS_TYPES.includes(snsType);
1590
- }, []);
1591
- return {
1592
- bind,
1593
- isBinding,
1594
- isOAuthSupported
1595
- };
1596
- }
1597
- const UNBIND_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
1598
- const MIN_LOGIN_METHODS = 1;
1599
- function isInCooldown(bindTime) {
1600
- const now = Date.now();
1601
- return now - bindTime < UNBIND_COOLDOWN_MS;
1602
- }
1603
- function getCooldownRemaining(bindTime) {
1604
- const now = Date.now();
1605
- const elapsed = now - bindTime;
1606
- const remaining = UNBIND_COOLDOWN_MS - elapsed;
1607
- return Math.max(0, remaining);
1608
- }
1609
- function formatCooldownTime(ms) {
1610
- const hours = Math.ceil(ms / (60 * 60 * 1e3));
1611
- if (hours <= 1) {
1612
- return "less than 1 hour";
1613
- }
1614
- return `${hours} hours`;
1615
- }
1616
- function useDisableUnlink() {
1617
- const { totalBoundCount } = useIdentityData();
1618
- const isLastLoginMethod = totalBoundCount <= MIN_LOGIN_METHODS;
1619
- const checkSocialUnlink = useMemo(() => {
1620
- return (account) => {
1621
- if (isLastLoginMethod) {
1622
- return {
1623
- disabled: true,
1624
- reason: "lastLoginMethod",
1625
- message: "Cannot unbind the last login method. You must keep at least one login method.",
1626
- cooldownRemaining: null,
1627
- needsKycWarning: false
1628
- };
1629
- }
1630
- const bindTimeMs = account.bind_time;
1631
- if (isInCooldown(bindTimeMs)) {
1632
- const remaining = getCooldownRemaining(bindTimeMs);
1633
- return {
1634
- disabled: true,
1635
- reason: "cooldown",
1636
- message: `Cannot unbind within 24 hours of binding. Please wait ${formatCooldownTime(remaining)}.`,
1637
- cooldownRemaining: remaining,
1638
- needsKycWarning: false
1639
- };
1640
- }
1641
- return {
1642
- disabled: false,
1643
- reason: null,
1644
- message: null,
1645
- cooldownRemaining: null,
1646
- needsKycWarning: false
1647
- };
1648
- };
1649
- }, [isLastLoginMethod]);
1650
- const checkWalletUnlink = useMemo(() => {
1651
- return (address, isKycVerified = false) => {
1652
- if (isLastLoginMethod) {
1653
- return {
1654
- disabled: true,
1655
- reason: "lastLoginMethod",
1656
- message: "Cannot unbind the last login method. You must keep at least one login method.",
1657
- cooldownRemaining: null,
1658
- needsKycWarning: false
1659
- };
1660
- }
1661
- const bindTimeMs = address.bind_time;
1662
- if (isInCooldown(bindTimeMs)) {
1663
- const remaining = getCooldownRemaining(bindTimeMs);
1664
- return {
1665
- disabled: true,
1666
- reason: "cooldown",
1667
- message: `Cannot unbind within 24 hours of binding. Please wait ${formatCooldownTime(remaining)}.`,
1668
- cooldownRemaining: remaining,
1669
- needsKycWarning: isKycVerified
1670
- };
1671
- }
1672
- if (isKycVerified) {
1673
- return {
1674
- disabled: false,
1675
- reason: "kycVerified",
1676
- message: "This address has been KYC verified. Unbinding will clear your KYC verification status.",
1677
- cooldownRemaining: null,
1678
- needsKycWarning: true
1679
- };
1680
- }
1681
- return {
1682
- disabled: false,
1683
- reason: null,
1684
- message: null,
1685
- cooldownRemaining: null,
1686
- needsKycWarning: false
1687
- };
1688
- };
1689
- }, [isLastLoginMethod]);
1690
- return {
1691
- checkSocialUnlink,
1692
- checkWalletUnlink,
1693
- totalBoundCount,
1694
- isLastLoginMethod
1695
- };
1696
- }
1697
- const twitterIcon = new URL("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAH3SURBVHgBzZeNkYIwEIXjVYAdcB1QAtcBVqBWcFoBdgBWgB1YAtcBJUAHlrCXxxEnEzaQIMi9mR0zIT+fSd4GhDBERLGMTEZN86uSUcgIhU3yYdABvEuYK+AgKnq/KgXz0bGkMiLxfkXd3GJDf/tVi3X1hRVJzdrz+Sw2mw0b2+1WNE0jXHU8Htt+u91uqFkiiDkbj8eDoigi2YCCIKAwDNtAGXVxHDsdgMvl0rZHX4w5oFrYnlRV9ZwYZQWIQVGX5zkNCc8VRF3XNCYx9DDLst4/0gHLsmT7oV6tpgvEKAiEbcCgp9NpEFAJEyvQ+/1OrhoFsQ3MAaKt2ro0TclHoyAQAMylNgH18+ML4QwC4Z+bjtEBkyRpy/idImcQm2MUoKNNXweBdDdwlkbemCovEEg5BglPt7QJuDgI5GvpxUDUFplJjQNcDEQ/E+YK6Ja2Zd3ZQHSb7vf7nmWLopi0RV4g5m1qszQHOBuIDqFfZNwF53NLe4FwKV6XSmqw9BDgSyCut6l6kdIdwwFOAvG5TW2O4QC9QKbcplxSc7W0FWTqbaqSGveuO2RpgNRmpcdLb09orybm4nA4cN0qfNfkssG3WFc3gMSyUIp19fkhP35+ZOEq1tNVMjRtif7BR/hTHYxbPp5HeQ/CAApl3GiZFao7gNic9xdG16HkLDPmwQAAAABJRU5ErkJggg==", import.meta.url).href;
1698
- const discordIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='25'%20viewBox='0%200%2024%2025'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20y='0.187012'%20width='24'%20height='24.2243'%20rx='8'%20fill='%237870FF'/%3e%3cpath%20d='M18.7627%206.96988C16.7288%205.45184%2014.7966%205.34341%2014.4915%205.34341L14.2881%205.56027C16.6271%206.21086%2017.9492%207.4036%2018.0508%207.51203C14.3898%205.56027%2010.322%205.45184%206.66102%206.96988C6.15254%207.18674%205.84746%207.4036%205.74576%207.4036C5.94915%207.29517%207.16949%206.10243%209.71186%205.45184L9.50847%205.23498C9.50847%205.23498%207.47458%205.12655%205.23729%206.86145C5.23729%206.86145%203%2010.8734%203%2015.9697C3%2015.9697%204.32203%2018.2467%207.67797%2018.3551C7.67797%2018.3551%208.18644%2017.7046%208.69492%2017.054C6.9661%2016.5118%206.15254%2015.3191%206.05085%2015.2106L6.66102%2015.5359C8.49153%2016.2949%2010.4237%2017.3793%2013.9831%2016.7287C14.6949%2016.6202%2015.5085%2016.4034%2016.2203%2016.0781C16.7288%2015.7528%2017.339%2015.5359%2017.9492%2015.1022C17.8475%2015.2106%2017.0339%2016.4034%2015.2034%2016.9455C15.6102%2017.5961%2016.2203%2018.2467%2016.2203%2018.2467C19.678%2018.1383%2021%2015.8612%2021%2016.0781C21%2011.0903%2018.7627%206.96988%2018.7627%206.96988ZM9.20339%2014.3432C8.38983%2014.3432%207.67797%2013.5842%207.67797%2012.6083C7.67797%2011.6324%208.38983%2010.8734%209.20339%2010.8734C10.0169%2010.8734%2010.7288%2011.7408%2010.7288%2012.6083C10.7288%2013.5842%2010.0169%2014.3432%209.20339%2014.3432ZM14.7966%2014.3432C13.9831%2014.3432%2013.2712%2013.5842%2013.2712%2012.6083C13.2712%2011.6324%2013.9831%2010.8734%2014.7966%2010.8734C15.7119%2010.8734%2016.4237%2011.7408%2016.4237%2012.6083C16.4237%2013.5842%2015.7119%2014.3432%2014.7966%2014.3432Z'%20fill='white'/%3e%3c/svg%3e", import.meta.url).href;
1699
- const telegramIcon = new URL("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%3e%3crect%20y='0.000396729'%20width='24'%20height='24'%20rx='8'%20fill='%2354AEFF'/%3e%3cpath%20d='M18.9513%206.24633L16.5438%2017.617C16.377%2018.424%2015.8902%2018.6174%2015.21%2018.2439L11.542%2015.5296L9.76804%2017.2435C9.56797%2017.4436%209.40125%2017.617%209.03445%2017.617C8.55428%2017.617%208.63431%2017.4369%208.47425%2016.9835L7.20714%2012.8553L3.57252%2011.7216C2.78558%2011.4882%202.77891%2010.948%203.74592%2010.5545L17.9243%205.08592C18.5711%204.79915%2019.1914%205.24598%2018.9446%206.23966L18.9513%206.24633Z'%20fill='white'/%3e%3c/svg%3e", import.meta.url).href;
1700
- const redditIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cg%20id='Group%2048098228'%3e%3crect%20id='Rectangle%206202'%20y='0.000488281'%20width='24'%20height='24'%20rx='8'%20fill='%23FF4500'/%3e%3cpath%20id='Vector'%20d='M20.0319%2012.242C20.0319%2011.2761%2019.2031%2010.4913%2018.185%2010.4913C17.7441%2010.4913%2017.3313%2010.6436%2016.9987%2010.9114L16.9658%2010.9306C15.7642%2010.2012%2014.1714%209.73623%2012.4103%209.67371L13.4612%206.83847L16.0864%207.43325C16.0881%208.22042%2016.763%208.86009%2017.5934%208.86009C18.4255%208.86009%2019.102%208.21882%2019.102%207.43005C19.102%206.64128%2018.4255%206%2017.5951%206C16.9626%206%2016.4231%206.37034%2016.1995%206.89298L13.0893%206.18837L11.7987%209.6673C9.96066%209.69936%208.29575%2010.1707%207.05007%2010.9242C6.71195%2010.6442%206.28667%2010.4911%205.84768%2010.4913C4.82725%2010.4905%204%2011.2761%204%2012.2412C4%2012.8384%204.32465%2013.3899%204.8521%2013.7113C4.82003%2013.8853%204.79919%2014.0616%204.79919%2014.2412C4.79919%2016.7694%208.03042%2018.8255%2012.0015%2018.8255C15.9734%2018.8255%2019.2055%2016.7694%2019.2055%2014.242C19.2055%2014.0681%2019.187%2013.8965%2019.1566%2013.7274C19.6968%2013.4083%2020.0319%2012.8488%2020.0319%2012.242ZM14.4512%2014.5089C13.8243%2014.5089%2013.3169%2014.028%2013.3169%2013.4332C13.3169%2012.8392%2013.8243%2012.3575%2014.4512%2012.3575C15.078%2012.3575%2015.5863%2012.8384%2015.5863%2013.4332C15.5863%2014.028%2015.0772%2014.5089%2014.4512%2014.5089ZM14.6764%2016.3438C14.6428%2016.3758%2013.8292%2017.1614%2011.9887%2017.1614C10.1386%2017.1614%209.39954%2016.3662%209.36748%2016.3318C9.3428%2016.3048%209.32396%2016.273%209.31214%2016.2384C9.30032%2016.2039%209.29577%2016.1672%209.29878%2016.1308C9.30179%2016.0943%209.3123%2016.0589%209.32964%2016.0268C9.34697%2015.9946%209.37078%2015.9663%209.39954%2015.9438C9.45882%2015.8964%209.53372%2015.873%209.60941%2015.8782C9.68511%2015.8834%209.7561%2015.9168%209.80836%2015.9718C9.82439%2015.9895%2010.4416%2016.6131%2011.9887%2016.6131C13.5622%2016.6131%2014.2524%2015.9678%2014.2596%2015.9614C14.3147%2015.9094%2014.3873%2015.88%2014.4631%2015.8791C14.5388%2015.8782%2014.6122%2015.9059%2014.6684%2015.9566C14.6955%2015.9808%2014.7174%2016.0103%2014.7325%2016.0433C14.7477%2016.0763%2014.756%2016.1121%2014.7567%2016.1485C14.7575%2016.1848%2014.7507%2016.2209%2014.7369%2016.2545C14.7231%2016.2881%2014.7025%2016.3185%2014.6764%2016.3438ZM8.57871%2013.4332C8.57871%2012.8392%209.08612%2012.3575%209.71457%2012.3575C10.3398%2012.3575%2010.8488%2012.8384%2010.8488%2013.4332C10.8488%2014.028%2010.3398%2014.5089%209.71457%2014.5089C9.08692%2014.5089%208.57871%2014.028%208.57871%2013.4332Z'%20fill='white'/%3e%3c/g%3e%3c/svg%3e", import.meta.url).href;
1701
- const emailIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='25'%20viewBox='0%200%2024%2025'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='24'%20height='24.2243'%20rx='8'%20fill='%23DD9F00'/%3e%3cpath%20d='M5.14286%2015.2063L9.41607%2012L4%207.93687V16.0612L4.89286%2015.3919L5.14286%2015.2063ZM12%2012.4631L18.8571%207.32L19.8393%206.585C19.6393%206.23437%2019.275%206%2018.8571%206H5.14286C4.75893%206%204.41964%206.19875%204.2125%206.5025L5.14286%207.32L12%2012.4631ZM13.6%2012.7369L12%2013.9369L10.4%2012.7369L5.14286%2016.68L4.89286%2016.8956L4.20536%2017.4862C4.41071%2017.7975%204.75536%2018%205.14286%2018H18.8571C19.2768%2018%2019.6429%2017.7638%2019.8411%2017.4113L18.8571%2016.68L13.6%2012.7369ZM14.5821%2012L20%2016.0631V7.93687L14.5821%2012Z'%20fill='white'/%3e%3c/svg%3e", import.meta.url).href;
1702
- const SOCIAL_ICONS = {
1703
- [SnsType.Twitter]: twitterIcon,
1704
- [SnsType.Discord]: discordIcon,
1705
- [SnsType.Telegram]: telegramIcon,
1706
- [SnsType.Reddit]: redditIcon,
1707
- [SnsType.Email]: emailIcon
1708
- };
1709
- function SocialIcon({
1710
- type,
1711
- size = 24,
1712
- className = ""
1713
- }) {
1714
- const iconSrc = SOCIAL_ICONS[type];
1715
- if (iconSrc) {
1716
- return /* @__PURE__ */ jsx(
1717
- "img",
1718
- {
1719
- src: iconSrc,
1720
- alt: type,
1721
- width: size,
1722
- height: size,
1723
- className: `taskon-social-icon ${className}`,
1724
- style: { objectFit: "contain" }
1725
- }
1726
- );
1727
- }
1728
- return /* @__PURE__ */ jsx(
1729
- "svg",
1730
- {
1731
- width: size,
1732
- height: size,
1733
- viewBox: "0 0 24 24",
1734
- fill: "none",
1735
- xmlns: "http://www.w3.org/2000/svg",
1736
- className,
1737
- style: { color: "var(--taskon-color-text-secondary)" },
1738
- children: /* @__PURE__ */ jsx(
1739
- "path",
1740
- {
1741
- d: "M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1ZM8 13h8v-2H8v2Zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5Z",
1742
- fill: "currentColor"
1743
- }
1744
- )
1745
- }
1746
- );
1747
- }
1748
- function ChainIcon({ chain }) {
1749
- if (chain === "evm") {
1750
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1751
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "white" }),
1752
- /* @__PURE__ */ jsx("path", { d: "M12 4L6 12L12 9.5V4Z", fill: "#343434" }),
1753
- /* @__PURE__ */ jsx("path", { d: "M12 4L18 12L12 9.5V4Z", fill: "#8C8C8C" }),
1754
- /* @__PURE__ */ jsx("path", { d: "M12 16.5L6 12L12 14.5V16.5Z", fill: "#3C3C3B" }),
1755
- /* @__PURE__ */ jsx("path", { d: "M12 16.5L18 12L12 14.5V16.5Z", fill: "#8C8C8C" }),
1756
- /* @__PURE__ */ jsx("path", { d: "M12 17.5L6 13L12 20V17.5Z", fill: "#141414" }),
1757
- /* @__PURE__ */ jsx("path", { d: "M12 17.5L18 13L12 20V17.5Z", fill: "#393939" })
1758
- ] });
1759
- }
1760
- if (chain === "sui") {
1761
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1762
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#4DA2FF" }),
1763
- /* @__PURE__ */ jsx("path", { d: "M16.5 8.5C15.5 7.5 14 7 12.5 7.5C11 8 10 9 9.5 10.5C9 12 9 13.5 9.5 15C10 16.5 11 17.5 12.5 18C14 18.5 15.5 18 16.5 17", stroke: "white", strokeWidth: "2", strokeLinecap: "round" }),
1764
- /* @__PURE__ */ jsx("circle", { cx: "15", cy: "10", r: "1.5", fill: "white" })
1765
- ] });
1766
- }
1767
- if (chain === "solana") {
1768
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1769
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "black" }),
1770
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "solana-grad", x1: "4", y1: "20", x2: "20", y2: "4", children: [
1771
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#9945FF" }),
1772
- /* @__PURE__ */ jsx("stop", { offset: "50%", stopColor: "#14F195" }),
1773
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#00D1FF" })
1774
- ] }) }),
1775
- /* @__PURE__ */ jsx("path", { d: "M6 15.5L8.5 13H18L15.5 15.5H6Z", fill: "url(#solana-grad)" }),
1776
- /* @__PURE__ */ jsx("path", { d: "M6 8.5L8.5 11H18L15.5 8.5H6Z", fill: "url(#solana-grad)" }),
1777
- /* @__PURE__ */ jsx("path", { d: "M6 12L8.5 9.5H18L15.5 12H6Z", fill: "url(#solana-grad)" })
1778
- ] });
1779
- }
1780
- if (chain === "starknet") {
1781
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1782
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#EC796B" }),
1783
- /* @__PURE__ */ jsx("path", { d: "M12 6L8 10L12 8L16 10L12 6Z", fill: "white" }),
1784
- /* @__PURE__ */ jsx("path", { d: "M8 10L12 14L8 12V10Z", fill: "white", fillOpacity: "0.6" }),
1785
- /* @__PURE__ */ jsx("path", { d: "M16 10L12 14L16 12V10Z", fill: "white", fillOpacity: "0.8" }),
1786
- /* @__PURE__ */ jsx("path", { d: "M12 14L8 12L12 18L16 12L12 14Z", fill: "white" })
1787
- ] });
1788
- }
1789
- if (chain === "aptos") {
1790
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1791
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "white" }),
1792
- /* @__PURE__ */ jsx("path", { d: "M16 8H14L12 12L10 8H8L11 14H9V16H15V14H13L16 8Z", fill: "black" })
1793
- ] });
1794
- }
1795
- if (chain === "btc") {
1796
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1797
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#F7931A" }),
1798
- /* @__PURE__ */ jsx("path", { d: "M15.5 10.5C15.5 8.5 14 8 12 8V6H11V8H10V6H9V8H7V10H8.5V14H7V16H9V18H10V16H11V18H12V16C14.5 16 16 15 16 13C16 11.5 15 11 15.5 10.5ZM10 10H12C13 10 13.5 10.5 13.5 11C13.5 11.5 13 12 12 12H10V10ZM12.5 14H10V12H12.5C13.5 12 14 12.5 14 13C14 13.5 13.5 14 12.5 14Z", fill: "white" })
1799
- ] });
1800
- }
1801
- if (chain === "tron") {
1802
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1803
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#FF0013" }),
1804
- /* @__PURE__ */ jsx("path", { d: "M7 7L12 19L17 7H7Z", fill: "white" }),
1805
- /* @__PURE__ */ jsx("path", { d: "M9 9L12 16L15 9H9Z", fill: "#FF0013" })
1806
- ] });
1807
- }
1808
- if (chain === "ton") {
1809
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1810
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#0088CC" }),
1811
- /* @__PURE__ */ jsx("path", { d: "M12 6L6 18H10L12 14L14 18H18L12 6Z", fill: "white" })
1812
- ] });
1813
- }
1814
- if (chain === "nibiru") {
1815
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1816
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#1E1E2F" }),
1817
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5", stroke: "#7B68EE", strokeWidth: "2" }),
1818
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2", fill: "#7B68EE" })
1819
- ] });
1820
- }
1821
- if (chain === "kaspa") {
1822
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1823
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#49EACB" }),
1824
- /* @__PURE__ */ jsx("path", { d: "M8 8L12 12L8 16M12 12L16 8M12 12L16 16", stroke: "white", strokeWidth: "2", strokeLinecap: "round" })
1825
- ] });
1826
- }
1827
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1828
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#4B5563" }),
1829
- /* @__PURE__ */ jsx("path", { d: "M12 6C8.69 6 6 8.69 6 12s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm0 10c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z", fill: "white" })
1830
- ] });
1831
- }
1832
- function EvmChainIcons() {
1833
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-chain-icons", children: [
1834
- /* @__PURE__ */ jsx(ChainIcon, { chain: "evm" }),
1835
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1836
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#213147" }),
1837
- /* @__PURE__ */ jsx("path", { d: "M12 6L16.5 12L12 18L7.5 12L12 6Z", fill: "#28A0F0" }),
1838
- /* @__PURE__ */ jsx("path", { d: "M12 6L7.5 12L12 14.5V6Z", fill: "white" })
1839
- ] }),
1840
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1841
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#8247E5" }),
1842
- /* @__PURE__ */ jsx("path", { d: "M15.5 9L12 7L8.5 9V13L12 15L15.5 13V9Z", stroke: "white", strokeWidth: "1.5" }),
1843
- /* @__PURE__ */ jsx("path", { d: "M12 11L15.5 9M12 11L8.5 9M12 11V15", stroke: "white", strokeWidth: "1.5" })
1844
- ] }),
1845
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1846
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#F3BA2F" }),
1847
- /* @__PURE__ */ jsx("path", { d: "M12 7L9.5 9.5L10.5 10.5L12 9L13.5 10.5L14.5 9.5L12 7Z", fill: "white" }),
1848
- /* @__PURE__ */ jsx("path", { d: "M7 12L8 11L9 12L8 13L7 12Z", fill: "white" }),
1849
- /* @__PURE__ */ jsx("path", { d: "M17 12L16 11L15 12L16 13L17 12Z", fill: "white" }),
1850
- /* @__PURE__ */ jsx("path", { d: "M12 17L14.5 14.5L13.5 13.5L12 15L10.5 13.5L9.5 14.5L12 17Z", fill: "white" }),
1851
- /* @__PURE__ */ jsx("path", { d: "M12 11L11 12L12 13L13 12L12 11Z", fill: "white" })
1852
- ] }),
1853
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1854
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#FF0420" }),
1855
- /* @__PURE__ */ jsx("circle", { cx: "10", cy: "12", r: "3", fill: "white" }),
1856
- /* @__PURE__ */ jsx("path", { d: "M14 9H17V10.5H15V11.5H17V13H15V15H14V9Z", fill: "white" })
1857
- ] }),
1858
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1859
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#E84142" }),
1860
- /* @__PURE__ */ jsx("path", { d: "M8 16L12 8L16 16H13L12 14L11 16H8Z", fill: "white" })
1861
- ] }),
1862
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1863
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#0052FF" }),
1864
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5", stroke: "white", strokeWidth: "2" }),
1865
- /* @__PURE__ */ jsx("path", { d: "M12 9V12H15", stroke: "white", strokeWidth: "2", strokeLinecap: "round" })
1866
- ] }),
1867
- /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1868
- /* @__PURE__ */ jsx("rect", { width: "24", height: "24", rx: "8", fill: "#121212" }),
1869
- /* @__PURE__ */ jsx("path", { d: "M7 17V7H9V15H17V17H7Z", fill: "white" })
1870
- ] }),
1871
- /* @__PURE__ */ jsx("div", { className: "taskon-network-chain-icons__more", children: /* @__PURE__ */ jsxs("svg", { width: "12", height: "3", viewBox: "0 0 12 3", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1872
- /* @__PURE__ */ jsx("circle", { cx: "1.5", cy: "1.5", r: "1.5", fill: "#666" }),
1873
- /* @__PURE__ */ jsx("circle", { cx: "6", cy: "1.5", r: "1.5", fill: "#666" }),
1874
- /* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "1.5", r: "1.5", fill: "#666" })
1875
- ] }) })
1876
- ] });
1877
- }
1878
- function ArrowButton({
1879
- onClick,
1880
- disabled,
1881
- isLoading,
1882
- title
1883
- }) {
1884
- return /* @__PURE__ */ jsx(
1885
- "button",
1886
- {
1887
- className: "taskon-identity-social-btn",
1888
- onClick,
1889
- disabled: disabled || isLoading,
1890
- title,
1891
- children: isLoading ? /* @__PURE__ */ jsx("span", { className: "taskon-identity-social-btn__spinner" }) : /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1892
- /* @__PURE__ */ jsx("path", { d: "M10.8225 4.44751L15.375 9.00001L10.8225 13.5525", stroke: "currentColor", strokeWidth: "1.5", strokeMiterlimit: "10", strokeLinecap: "round", strokeLinejoin: "round" }),
1893
- /* @__PURE__ */ jsx("path", { d: "M2.625 9H15.2475", stroke: "currentColor", strokeWidth: "1.5", strokeMiterlimit: "10", strokeLinecap: "round", strokeLinejoin: "round" })
1894
- ] })
1895
- }
1896
- );
1897
- }
1898
- function CopyButton({ text }) {
1899
- const [copied, setCopied] = useState(false);
1900
- const handleCopy = useCallback(() => {
1901
- navigator.clipboard.writeText(text).then(() => {
1902
- setCopied(true);
1903
- setTimeout(() => setCopied(false), 2e3);
1904
- });
1905
- }, [text]);
1906
- return /* @__PURE__ */ jsx(
1907
- "button",
1908
- {
1909
- className: "taskon-network-copy-btn",
1910
- onClick: handleCopy,
1911
- title: copied ? "Copied!" : "Copy",
1912
- children: copied ? (
1913
- // 复制成功图标(勾选)
1914
- /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M3 7L6 10L11 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
1915
- ) : (
1916
- // 复制图标
1917
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1918
- /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
1919
- /* @__PURE__ */ jsx("path", { d: "M2 10V3C2 2.44772 2.44772 2 3 2H10", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1920
- ] })
1921
- )
1922
- }
1923
- );
1924
- }
1925
- function SocialAccountItem({
1926
- data,
1927
- onBind,
1928
- onUnbind,
1929
- isLoading,
1930
- disabled,
1931
- disabledReason,
1932
- messages
1933
- }) {
1934
- const displayText = data.isBound && data.account ? data.account.sns_user_name : (messages.linkPlatformAccount ?? "Link {platform} Account").replace("{platform}", data.snsType);
1935
- return /* @__PURE__ */ jsxs(
1936
- "div",
1937
- {
1938
- className: `taskon-identity-social-item ${data.isBound ? "taskon-identity-social-item--bound" : ""} ${data.isBound && disabled ? "taskon-identity-social-item--unlink-disabled" : ""}`,
1939
- children: [
1940
- /* @__PURE__ */ jsxs("div", { className: "taskon-identity-social-item__content", children: [
1941
- /* @__PURE__ */ jsx("div", { className: "taskon-identity-social-item__icon", children: /* @__PURE__ */ jsx(SocialIcon, { type: data.snsType }) }),
1942
- /* @__PURE__ */ jsx("div", { className: "taskon-identity-social-item__text", children: data.isBound && data.profileUrl ? /* @__PURE__ */ jsx(
1943
- "a",
1944
- {
1945
- href: data.profileUrl,
1946
- target: "_blank",
1947
- rel: "noopener noreferrer",
1948
- className: "taskon-identity-social-item__link",
1949
- children: displayText
1950
- }
1951
- ) : /* @__PURE__ */ jsx("span", { className: "taskon-identity-social-item__name", children: displayText }) })
1952
- ] }),
1953
- data.isBound ? /* @__PURE__ */ jsxs(Fragment, { children: [
1954
- /* @__PURE__ */ jsx("span", { className: "taskon-identity-social-item__linked", children: messages.linked ?? "Linked" }),
1955
- !disabled && /* @__PURE__ */ jsx(
1956
- "button",
1957
- {
1958
- className: "taskon-identity-social-item__unlink-btn",
1959
- onClick: onUnbind,
1960
- disabled: isLoading,
1961
- "aria-label": messages.unbind ?? "Unbind",
1962
- children: isLoading ? /* @__PURE__ */ jsx("span", { className: "taskon-identity-social-btn__spinner" }) : /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M11 3L3 11M3 3L11 11", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1963
- }
1964
- )
1965
- ] }) : (
1966
- /* 未绑定状态:显示箭头按钮 */
1967
- /* @__PURE__ */ jsx(
1968
- ArrowButton,
1969
- {
1970
- onClick: onBind,
1971
- disabled: false,
1972
- isLoading
1973
- }
1974
- )
1975
- )
1976
- ]
1977
- }
1978
- );
1979
- }
1980
- function WalletItem({
1981
- data,
1982
- addresses,
1983
- onBind,
1984
- onUnbind,
1985
- isLoading,
1986
- disabled,
1987
- disabledReason,
1988
- messages
1989
- }) {
1990
- const name = getChainName(data.coreChainType);
1991
- const isEvm = data.coreChainType === "evm";
1992
- if (isEvm && addresses && addresses.length > 0) {
1993
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-card taskon-network-card--multi", children: [
1994
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__header", children: /* @__PURE__ */ jsx("span", { className: "taskon-network-card__label", children: "EVM Chain" }) }),
1995
- /* @__PURE__ */ jsx(EvmChainIcons, {}),
1996
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__addresses", children: addresses.map((addr, index) => {
1997
- var _a, _b, _c;
1998
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-address-row", children: [
1999
- /* @__PURE__ */ jsxs("div", { className: "taskon-network-address-row__left", children: [
2000
- /* @__PURE__ */ jsx("span", { className: `taskon-network-address-row__addr ${!addr.isPrimary ? "taskon-network-address-row__addr--secondary" : ""}`, children: truncateAddress(((_a = addr.address) == null ? void 0 : _a.address) ?? "") }),
2001
- /* @__PURE__ */ jsx(CopyButton, { text: ((_b = addr.address) == null ? void 0 : _b.address) ?? "" })
2002
- ] }),
2003
- /* @__PURE__ */ jsx("div", { className: "taskon-network-address-row__divider" }),
2004
- /* @__PURE__ */ jsxs("div", { className: "taskon-network-address-row__right", children: [
2005
- /* @__PURE__ */ jsx("span", { className: `taskon-network-address-row__type ${addr.isPrimary ? "taskon-network-address-row__type--primary" : "taskon-network-address-row__type--secondary"}`, children: addr.isPrimary ? "Primary Address" : "Secondary Address" }),
2006
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "taskon-network-address-row__edit", children: [
2007
- /* @__PURE__ */ jsx("path", { d: "M2 12H4L10.5 5.5L8.5 3.5L2 10V12Z", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" }),
2008
- /* @__PURE__ */ jsx("path", { d: "M8.5 3.5L10.5 5.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
2009
- ] })
2010
- ] }),
2011
- /* @__PURE__ */ jsx(
2012
- "button",
2013
- {
2014
- className: "taskon-network-unbind-badge",
2015
- onClick: () => {
2016
- var _a2;
2017
- return onUnbind((_a2 = addr.address) == null ? void 0 : _a2.address);
2018
- },
2019
- disabled: isLoading || disabled,
2020
- title: disabledReason,
2021
- children: messages.unbind ?? "Unbind"
2022
- }
2023
- )
2024
- ] }, ((_c = addr.address) == null ? void 0 : _c.address) ?? index);
2025
- }) })
2026
- ] });
2027
- }
2028
- if (isEvm && !data.isBound) {
2029
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-card taskon-network-card--multi", children: [
2030
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__header", children: /* @__PURE__ */ jsx("span", { className: "taskon-network-card__label", children: "EVM Chain" }) }),
2031
- /* @__PURE__ */ jsx(EvmChainIcons, {}),
2032
- /* @__PURE__ */ jsx(
2033
- "button",
2034
- {
2035
- className: "taskon-network-connect-btn",
2036
- onClick: onBind,
2037
- disabled: isLoading,
2038
- children: isLoading ? messages.loading : messages.connectWallet ?? "Connect Wallet"
2039
- }
2040
- )
2041
- ] });
2042
- }
2043
- if (data.isBound && data.address) {
2044
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-card taskon-network-card--single", children: [
2045
- /* @__PURE__ */ jsx(
2046
- "button",
2047
- {
2048
- className: "taskon-network-unbind-badge taskon-network-unbind-badge--corner",
2049
- onClick: () => onUnbind(),
2050
- disabled: isLoading || disabled,
2051
- title: disabledReason,
2052
- children: messages.unbind ?? "Unbind"
2053
- }
2054
- ),
2055
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__header", children: /* @__PURE__ */ jsx("span", { className: "taskon-network-card__label", children: name }) }),
2056
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__chain-icon", children: /* @__PURE__ */ jsx(ChainIcon, { chain: data.coreChainType }) }),
2057
- /* @__PURE__ */ jsxs("div", { className: "taskon-network-address-input", children: [
2058
- /* @__PURE__ */ jsx("span", { className: "taskon-network-address-input__text", children: truncateAddress(data.address.address) }),
2059
- /* @__PURE__ */ jsx(CopyButton, { text: data.address.address })
2060
- ] })
2061
- ] });
2062
- }
2063
- return /* @__PURE__ */ jsxs("div", { className: "taskon-network-card taskon-network-card--single", children: [
2064
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__header", children: /* @__PURE__ */ jsx("span", { className: "taskon-network-card__label", children: name }) }),
2065
- /* @__PURE__ */ jsx("div", { className: "taskon-network-card__chain-icon", children: /* @__PURE__ */ jsx(ChainIcon, { chain: data.coreChainType }) }),
2066
- /* @__PURE__ */ jsx(
2067
- "button",
2068
- {
2069
- className: "taskon-network-connect-btn",
2070
- onClick: onBind,
2071
- disabled: isLoading,
2072
- children: isLoading ? messages.loading : messages.connectWallet ?? "Connect Wallet"
2073
- }
2074
- )
2075
- ] });
2076
- }
2077
- function WarningIcon() {
2078
- return /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx(
2079
- "path",
2080
- {
2081
- d: "M12 9V13M12 17H12.01M10.29 3.86L1.82 18C1.64 18.3 1.55 18.65 1.55 19C1.56 19.35 1.65 19.69 1.82 20C2 20.3 2.25 20.56 2.55 20.73C2.85 20.91 3.19 21 3.54 21H20.46C20.81 21 21.15 20.91 21.45 20.73C21.75 20.56 22 20.3 22.18 20C22.35 19.69 22.44 19.35 22.45 19C22.45 18.65 22.36 18.3 22.18 18L13.71 3.86C13.53 3.56 13.28 3.32 12.98 3.15C12.68 2.98 12.34 2.89 12 2.89C11.66 2.89 11.32 2.98 11.02 3.15C10.72 3.32 10.47 3.56 10.29 3.86Z",
2082
- stroke: "currentColor",
2083
- strokeWidth: "2",
2084
- strokeLinecap: "round",
2085
- strokeLinejoin: "round"
2086
- }
2087
- ) });
2088
- }
2089
- function ConfirmUnlinkDialog({
2090
- open,
2091
- onOpenChange,
2092
- onConfirm,
2093
- onCancel,
2094
- loading = false,
2095
- messages
2096
- }) {
2097
- return /* @__PURE__ */ jsx(
2098
- Dialog,
2099
- {
2100
- open,
2101
- onOpenChange,
2102
- title: messages.confirmUnbind,
2103
- showCloseButton: false,
2104
- maxWidth: 400,
2105
- children: /* @__PURE__ */ jsxs("div", { className: "taskon-confirm-unlink", children: [
2106
- /* @__PURE__ */ jsx("div", { className: "taskon-confirm-unlink__icon", children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
2107
- /* @__PURE__ */ jsxs("div", { className: "taskon-confirm-unlink__text", children: [
2108
- /* @__PURE__ */ jsx("h4", { className: "taskon-confirm-unlink__title", children: messages.confirmUnbind }),
2109
- /* @__PURE__ */ jsx("p", { className: "taskon-confirm-unlink__description", children: messages.unbindWarning })
2110
- ] }),
2111
- /* @__PURE__ */ jsxs("div", { className: "taskon-confirm-unlink__actions", children: [
2112
- /* @__PURE__ */ jsx(
2113
- "button",
2114
- {
2115
- className: "taskon-confirm-unlink__btn taskon-confirm-unlink__btn--cancel",
2116
- onClick: onCancel,
2117
- disabled: loading,
2118
- children: messages.cancel
2119
- }
2120
- ),
2121
- /* @__PURE__ */ jsx(
2122
- "button",
2123
- {
2124
- className: "taskon-confirm-unlink__btn taskon-confirm-unlink__btn--confirm",
2125
- onClick: onConfirm,
2126
- disabled: loading,
2127
- children: loading ? messages.unbinding : messages.confirm
2128
- }
2129
- )
2130
- ] })
2131
- ] })
2132
- }
2133
- );
2134
- }
2135
- function SocialAccountsSection({
2136
- accounts,
2137
- messages,
2138
- onBind,
2139
- onUnbind,
2140
- isProcessing,
2141
- checkUnlink,
2142
- onShowWarning
2143
- }) {
2144
- if (accounts.length === 0) {
2145
- return null;
2146
- }
2147
- const [confirmTarget, setConfirmTarget] = useState(null);
2148
- const showConfirm = confirmTarget !== null;
2149
- const handleBind = useCallback(
2150
- (account) => {
2151
- onBind(account.snsType);
2152
- },
2153
- [onBind]
2154
- );
2155
- const handleUnbind = useCallback(
2156
- (account) => {
2157
- if (!account.account) return;
2158
- const check = checkUnlink(account.account);
2159
- if (check.disabled) {
2160
- onShowWarning(check.message ?? messages.unbindFailed);
2161
- return;
2162
- }
2163
- setConfirmTarget(account);
2164
- },
2165
- [checkUnlink, onShowWarning, messages]
2166
- );
2167
- const handleConfirmUnbind = useCallback(() => {
2168
- if (!(confirmTarget == null ? void 0 : confirmTarget.account)) return;
2169
- onUnbind(confirmTarget.account.sns_id, confirmTarget.snsType);
2170
- setConfirmTarget(null);
2171
- }, [confirmTarget, onUnbind]);
2172
- return /* @__PURE__ */ jsxs("section", { className: "taskon-identity-social-section", children: [
2173
- /* @__PURE__ */ jsx("h3", { className: "taskon-identity-social-section__title", children: messages.socialAccounts ?? "Social Media Accounts" }),
2174
- /* @__PURE__ */ jsx("div", { className: "taskon-identity-social-grid", children: accounts.map((account) => {
2175
- const check = account.account ? checkUnlink(account.account) : { disabled: false, message: null };
2176
- return /* @__PURE__ */ jsx(
2177
- SocialAccountItem,
2178
- {
2179
- data: account,
2180
- onBind: () => handleBind(account),
2181
- onUnbind: () => handleUnbind(account),
2182
- isLoading: isProcessing(account.snsType),
2183
- disabled: check.disabled,
2184
- disabledReason: check.message ?? void 0,
2185
- messages
2186
- },
2187
- account.snsType
2188
- );
2189
- }) }),
2190
- /* @__PURE__ */ jsx(
2191
- ConfirmUnlinkDialog,
2192
- {
2193
- open: showConfirm,
2194
- onOpenChange: (open) => {
2195
- if (!open) setConfirmTarget(null);
2196
- },
2197
- onConfirm: handleConfirmUnbind,
2198
- onCancel: () => setConfirmTarget(null),
2199
- loading: confirmTarget ? isProcessing(confirmTarget.snsType) : false,
2200
- messages
2201
- }
2202
- )
2203
- ] });
2204
- }
2205
- function WalletsSection({
2206
- wallets,
2207
- rawAddresses,
2208
- messages,
2209
- onBind,
2210
- onUnbind,
2211
- isProcessing,
2212
- checkUnlink,
2213
- onShowWarning,
2214
- onShowInfo
2215
- }) {
2216
- if (wallets.length === 0) {
2217
- return null;
2218
- }
2219
- const evmAddresses = useMemo(() => {
2220
- return rawAddresses.filter((addr) => addr.chain_type === "evm").map((addr) => ({
2221
- chainType: "EVM",
2222
- // UserCenterChainType.EVM
2223
- coreChainType: "evm",
2224
- isBound: true,
2225
- address: addr,
2226
- isPrimary: addr.is_primary ?? false,
2227
- isKycVerified: void 0
2228
- }));
2229
- }, [rawAddresses]);
2230
- const [confirmTarget, setConfirmTarget] = useState(null);
2231
- const showConfirm = confirmTarget !== null;
2232
- const handleBind = useCallback(
2233
- (wallet) => {
2234
- onBind(wallet.coreChainType);
2235
- },
2236
- [onBind]
2237
- );
2238
- const handleUnbind = useCallback(
2239
- (wallet, specificAddress) => {
2240
- var _a;
2241
- const addressToUnbind = specificAddress ?? ((_a = wallet.address) == null ? void 0 : _a.address);
2242
- if (!addressToUnbind || !wallet.address) return;
2243
- const check = checkUnlink(wallet.address, wallet.isKycVerified);
2244
- if (check.disabled) {
2245
- onShowWarning(check.message ?? messages.unbindFailed);
2246
- return;
2247
- }
2248
- if (check.needsKycWarning) {
2249
- onShowInfo(messages.kycWarning);
2250
- }
2251
- setConfirmTarget({ wallet, address: addressToUnbind });
2252
- },
2253
- [checkUnlink, onShowWarning, onShowInfo, messages]
2254
- );
2255
- const handleConfirmUnbind = useCallback(() => {
2256
- if (!confirmTarget) return;
2257
- onUnbind(confirmTarget.wallet.coreChainType, confirmTarget.address);
2258
- setConfirmTarget(null);
2259
- }, [confirmTarget, onUnbind]);
2260
- return /* @__PURE__ */ jsxs("section", { className: "taskon-network-section", children: [
2261
- /* @__PURE__ */ jsx("h3", { className: "taskon-network-section__title", children: messages.walletAddresses ?? "Network List" }),
2262
- /* @__PURE__ */ jsx("div", { className: "taskon-network-grid", children: wallets.map((wallet) => {
2263
- const check = wallet.address ? checkUnlink(wallet.address, wallet.isKycVerified) : { disabled: false, message: null };
2264
- const isEvm = wallet.coreChainType === "evm";
2265
- return /* @__PURE__ */ jsx(
2266
- WalletItem,
2267
- {
2268
- data: wallet,
2269
- addresses: isEvm && evmAddresses.length > 0 ? evmAddresses : void 0,
2270
- onBind: () => handleBind(wallet),
2271
- onUnbind: (addr) => handleUnbind(wallet, addr),
2272
- isLoading: isProcessing(wallet.chainType),
2273
- disabled: check.disabled,
2274
- disabledReason: check.message ?? void 0,
2275
- messages
2276
- },
2277
- wallet.coreChainType
2278
- );
2279
- }) }),
2280
- /* @__PURE__ */ jsx(
2281
- ConfirmUnlinkDialog,
2282
- {
2283
- open: showConfirm,
2284
- onOpenChange: (open) => {
2285
- if (!open) setConfirmTarget(null);
2286
- },
2287
- onConfirm: handleConfirmUnbind,
2288
- onCancel: () => setConfirmTarget(null),
2289
- loading: confirmTarget ? isProcessing(confirmTarget.wallet.chainType) : false,
2290
- messages
2291
- }
2292
- )
2293
- ] });
2294
- }
2295
- const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2296
- function EmailBindDialog({
2297
- visible,
2298
- status,
2299
- countdown,
2300
- isEmailDuplicate,
2301
- isCodeInvalid,
2302
- messages,
2303
- onClose,
2304
- onSendCode,
2305
- onBind,
2306
- onClearError
2307
- }) {
2308
- const [email, setEmail] = useState("");
2309
- const [code, setCode] = useState("");
2310
- const isEmailValid = useMemo(() => EMAIL_REGEX.test(email), [email]);
2311
- const isCodeValid = useMemo(() => code.length >= 4, [code]);
2312
- const isSending = status === "sendingCode";
2313
- const isSubmitting = status === "submitting";
2314
- const showCodeInput = status === "inputCode" || status === "submitting" || status === "success";
2315
- const emailError = useMemo(() => {
2316
- if (isEmailDuplicate) {
2317
- return messages.emailAlreadyLinked ?? "This email is already linked to another account";
2318
- }
2319
- if (email && !isEmailValid) {
2320
- return messages.pleaseEnterValidEmail ?? "Please enter a valid email address";
2321
- }
2322
- return void 0;
2323
- }, [isEmailDuplicate, email, isEmailValid, messages]);
2324
- const codeError = useMemo(() => {
2325
- if (isCodeInvalid) {
2326
- return messages.pleaseEnterValidCode ?? "Please enter a valid verification code";
2327
- }
2328
- return void 0;
2329
- }, [isCodeInvalid, messages]);
2330
- const handleEmailChange = useCallback(
2331
- (value) => {
2332
- setEmail(value);
2333
- onClearError();
2334
- },
2335
- [onClearError]
2336
- );
2337
- const handleCodeChange = useCallback(
2338
- (value) => {
2339
- const numericValue = value.replace(/[^0-9]/g, "").slice(0, 6);
2340
- setCode(numericValue);
2341
- onClearError();
2342
- },
2343
- [onClearError]
2344
- );
2345
- const handleSendCode = useCallback(async () => {
2346
- if (!isEmailValid || isSending) return;
2347
- await onSendCode(email);
2348
- }, [email, isEmailValid, isSending, onSendCode]);
2349
- const handleBind = useCallback(async () => {
2350
- if (!isEmailValid || !isCodeValid || isSubmitting) return;
2351
- const result = await onBind(email, code);
2352
- if (result == null ? void 0 : result.result) {
2353
- setEmail("");
2354
- setCode("");
2355
- onClose();
2356
- }
2357
- }, [email, code, isEmailValid, isCodeValid, isSubmitting, onBind, onClose]);
2358
- const handleClose = useCallback(() => {
2359
- setEmail("");
2360
- setCode("");
2361
- onClose();
2362
- }, [onClose]);
2363
- return /* @__PURE__ */ jsx(
2364
- Dialog,
2365
- {
2366
- open: visible,
2367
- onOpenChange: (open) => {
2368
- if (!open) handleClose();
2369
- },
2370
- title: messages.linkEmailAccount ?? "Link Email Account",
2371
- showCloseButton: true,
2372
- maxWidth: 400,
2373
- children: /* @__PURE__ */ jsxs("div", { className: "taskon-email-bind-dialog", children: [
2374
- /* @__PURE__ */ jsx("h2", { className: "taskon-email-bind-dialog__title", children: messages.linkEmailAccount ?? "Link Email Account" }),
2375
- /* @__PURE__ */ jsxs("div", { className: "taskon-email-bind-dialog__field", children: [
2376
- /* @__PURE__ */ jsx("label", { className: "taskon-email-bind-dialog__label", children: messages.emailAddress ?? "Email Address" }),
2377
- /* @__PURE__ */ jsx(
2378
- Input,
2379
- {
2380
- type: "email",
2381
- value: email,
2382
- onChange: handleEmailChange,
2383
- placeholder: messages.pleaseEnterEmail ?? "Please enter email address",
2384
- maxLength: 64,
2385
- disabled: showCodeInput,
2386
- error: emailError,
2387
- onBlur: () => setEmail(email.trim())
2388
- }
2389
- )
2390
- ] }),
2391
- showCodeInput && /* @__PURE__ */ jsxs("div", { className: "taskon-email-bind-dialog__field", children: [
2392
- /* @__PURE__ */ jsx("label", { className: "taskon-email-bind-dialog__label", children: messages.verificationCode ?? "Verification Code" }),
2393
- /* @__PURE__ */ jsx(
2394
- Input,
2395
- {
2396
- type: "text",
2397
- inputMode: "numeric",
2398
- value: code,
2399
- onChange: handleCodeChange,
2400
- placeholder: messages.pleaseEnterCode ?? "Please enter verification code",
2401
- maxLength: 6,
2402
- disabled: isSubmitting,
2403
- error: codeError,
2404
- rightSlot: /* @__PURE__ */ jsx(
2405
- Button,
2406
- {
2407
- variant: "ghost",
2408
- size: "small",
2409
- disabled: countdown > 0 || isSending,
2410
- loading: isSending,
2411
- onClick: handleSendCode,
2412
- children: countdown > 0 ? `${messages.resendCode ?? "Resend"} (${countdown}s)` : messages.resendCode ?? "Resend"
2413
- }
2414
- )
2415
- }
2416
- )
2417
- ] }),
2418
- /* @__PURE__ */ jsx("div", { className: "taskon-email-bind-dialog__actions", children: !showCodeInput ? (
2419
- /* 发送验证码按钮 */
2420
- /* @__PURE__ */ jsx(
2421
- Button,
2422
- {
2423
- variant: "primary",
2424
- size: "large",
2425
- disabled: !isEmailValid || isSending,
2426
- loading: isSending,
2427
- onClick: handleSendCode,
2428
- style: { width: "100%" },
2429
- children: messages.sendVerificationCode ?? "Send Verification Code"
2430
- }
2431
- )
2432
- ) : (
2433
- /* 确认绑定按钮 */
2434
- /* @__PURE__ */ jsx(
2435
- Button,
2436
- {
2437
- variant: "primary",
2438
- size: "large",
2439
- disabled: !isEmailValid || !isCodeValid || isSubmitting,
2440
- loading: isSubmitting,
2441
- onClick: handleBind,
2442
- style: { width: "100%" },
2443
- children: messages.confirm ?? "Confirm"
2444
- }
2445
- )
2446
- ) })
2447
- ] })
2448
- }
2449
- );
2450
- }
2451
- function EmailSection({
2452
- emailAccount,
2453
- messages,
2454
- onUnbind,
2455
- isUnbinding,
2456
- checkUnlink,
2457
- onShowSuccess,
2458
- onShowError,
2459
- onShowWarning
2460
- }) {
2461
- const [dialogVisible, setDialogVisible] = useState(false);
2462
- const {
2463
- status: emailBindStatus,
2464
- countdown: emailCountdown,
2465
- isEmailDuplicate,
2466
- isCodeInvalid,
2467
- sendCode: sendEmailCode,
2468
- bind: bindEmail,
2469
- reset: resetEmailBind,
2470
- clearError: clearEmailError
2471
- } = useBindEmail({
2472
- onSendCodeSuccess: () => {
2473
- onShowSuccess(messages.sendCodeSuccess ?? "Verification code sent");
2474
- },
2475
- onSendCodeError: (error) => {
2476
- if (!error.message.includes("duplicate")) {
2477
- onShowError(messages.sendCodeFailed ?? "Failed to send verification code");
2478
- }
2479
- },
2480
- onBindSuccess: () => {
2481
- onShowSuccess(messages.bindSuccess);
2482
- setDialogVisible(false);
2483
- },
2484
- onBindError: () => {
2485
- onShowError(messages.bindFailed);
2486
- }
2487
- });
2488
- const handleBind = useCallback(() => {
2489
- setDialogVisible(true);
2490
- }, []);
2491
- const handleUnbind = useCallback(() => {
2492
- if (!emailAccount.account) return;
2493
- const check2 = checkUnlink(emailAccount.account);
2494
- if (check2.disabled) {
2495
- onShowWarning(check2.message ?? messages.unbindFailed);
2496
- return;
2497
- }
2498
- onUnbind(emailAccount.account.sns_id, "Email");
2499
- }, [emailAccount, checkUnlink, onUnbind, onShowWarning, messages]);
2500
- const handleDialogClose = useCallback(() => {
2501
- setDialogVisible(false);
2502
- resetEmailBind();
2503
- }, [resetEmailBind]);
2504
- const check = emailAccount.account ? checkUnlink(emailAccount.account) : { disabled: false, message: null };
2505
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2506
- /* @__PURE__ */ jsxs("section", { className: "taskon-identity-email-section", children: [
2507
- /* @__PURE__ */ jsx("h3", { className: "taskon-identity-email-section__title", children: messages.emailAddress ?? "Email Address" }),
2508
- /* @__PURE__ */ jsx("div", { className: "taskon-identity-email-card", children: /* @__PURE__ */ jsx(
2509
- SocialAccountItem,
2510
- {
2511
- data: emailAccount,
2512
- onBind: handleBind,
2513
- onUnbind: handleUnbind,
2514
- isLoading: isUnbinding,
2515
- disabled: check.disabled,
2516
- disabledReason: check.message ?? void 0,
2517
- messages
2518
- }
2519
- ) })
2520
- ] }),
2521
- /* @__PURE__ */ jsx(
2522
- EmailBindDialog,
2523
- {
2524
- visible: dialogVisible,
2525
- status: emailBindStatus,
2526
- countdown: emailCountdown,
2527
- isEmailDuplicate,
2528
- isCodeInvalid,
2529
- messages,
2530
- onClose: handleDialogClose,
2531
- onSendCode: sendEmailCode,
2532
- onBind: bindEmail,
2533
- onClearError: clearEmailError
2534
- }
2535
- )
2536
- ] });
2537
- }
2538
- const USER_CENTER_WALLET_ACCOUNT_TYPE = String(SnsType.All).toLowerCase();
2539
- const isWalletAccountType = (accountType) => accountType.toLowerCase() === USER_CENTER_WALLET_ACCOUNT_TYPE;
2540
- function IdentityContent({
2541
- config,
2542
- messages
2543
- }) {
2544
- var _a, _b, _c, _d;
2545
- const identityTab = config.find((t) => t.tab === "Identity");
2546
- const enabledAccounts = identityTab ? filterEnabledAccounts(identityTab) : [];
2547
- const enabledWallets = identityTab ? filterEnabledWallets(identityTab) : [];
2548
- const identityParams = identityTab && !Array.isArray(identityTab.params) ? identityTab.params : void 0;
2549
- const walletAccountOption = (_a = identityParams == null ? void 0 : identityParams.accountOptions) == null ? void 0 : _a.find(
2550
- (account) => isWalletAccountType(String(account.account))
2551
- );
2552
- const isWalletAccountEnabled = walletAccountOption ? walletAccountOption.enabled !== false : true;
2553
- const hasExplicitAccountConfig = (((_b = identityParams == null ? void 0 : identityParams.accountOptions) == null ? void 0 : _b.length) ?? 0) > 0;
2554
- const hasExplicitWalletConfig = (((_c = walletAccountOption == null ? void 0 : walletAccountOption.walletOptions) == null ? void 0 : _c.length) ?? 0) > 0 || (((_d = identityParams == null ? void 0 : identityParams.walletOptions) == null ? void 0 : _d.length) ?? 0) > 0;
2555
- const { socialAccounts, walletAddresses, rawAddresses, isLoaded } = useIdentityData();
2556
- const { checkSocialUnlink, checkWalletUnlink } = useDisableUnlink();
2557
- const { toast } = useToast();
2558
- const {
2559
- unbind: unbindSocial,
2560
- unbindStatus: socialUnbindStatus,
2561
- processingType: socialProcessingType
2562
- } = useUnbindSocial({
2563
- onUnbindSuccess: () => {
2564
- toast.success(messages.unbindSuccess);
2565
- },
2566
- onUnbindError: () => {
2567
- toast.error(messages.unbindFailed);
2568
- }
2569
- });
2570
- const { bind: bindOAuth, isBinding: isOAuthBinding, isOAuthSupported } = useOAuthBindings({
2571
- onSuccess: () => {
2572
- toast.success(messages.bindSuccess);
2573
- },
2574
- onFailed: (error) => {
2575
- toast.error(error || messages.bindFailed);
2576
- }
2577
- });
2578
- const {
2579
- bind: bindWallet,
2580
- unbind: unbindWallet,
2581
- bindStatus: walletBindStatus,
2582
- unbindStatus: walletUnbindStatus,
2583
- processingChain: walletProcessingChain
2584
- } = useBindWallet({
2585
- onBindSuccess: () => {
2586
- toast.success(messages.bindSuccess);
2587
- },
2588
- onUnbindSuccess: () => {
2589
- toast.success(messages.unbindSuccess);
2590
- },
2591
- onBindError: () => {
2592
- toast.error(messages.bindFailed);
2593
- },
2594
- onUnbindError: () => {
2595
- toast.error(messages.unbindFailed);
2596
- }
2597
- });
2598
- const enabledSocialAccountTypes = useMemo(() => {
2599
- return new Set(
2600
- enabledAccounts.filter((account) => !isWalletAccountType(String(account.account))).map((account) => String(account.account).toLowerCase())
2601
- );
2602
- }, [enabledAccounts]);
2603
- const enabledWalletChainTypes = useMemo(() => {
2604
- return new Set(
2605
- enabledWallets.map((wallet) => String(wallet.chain).toLowerCase())
2606
- );
2607
- }, [enabledWallets]);
2608
- const filteredSocialAccounts = useMemo(() => {
2609
- return socialAccounts.filter((account) => {
2610
- if (isWalletAccountType(String(account.snsType))) {
2611
- return false;
2612
- }
2613
- if (!hasExplicitAccountConfig) {
2614
- return true;
2615
- }
2616
- return enabledSocialAccountTypes.has(account.snsType.toLowerCase());
2617
- });
2618
- }, [socialAccounts, hasExplicitAccountConfig, enabledSocialAccountTypes]);
2619
- const filteredWalletAddresses = useMemo(() => {
2620
- if (!isWalletAccountEnabled) {
2621
- return [];
2622
- }
2623
- if (!hasExplicitWalletConfig) {
2624
- return walletAddresses;
2625
- }
2626
- return walletAddresses.filter((wallet) => {
2627
- return enabledWalletChainTypes.has(wallet.coreChainType.toLowerCase());
2628
- });
2629
- }, [walletAddresses, hasExplicitWalletConfig, enabledWalletChainTypes, isWalletAccountEnabled]);
2630
- const emailAccount = useMemo(() => {
2631
- return filteredSocialAccounts.find((a) => a.snsType === SnsType.Email);
2632
- }, [filteredSocialAccounts]);
2633
- const socialAccountsWithoutEmail = useMemo(() => {
2634
- return filteredSocialAccounts.filter((a) => a.snsType !== SnsType.Email);
2635
- }, [filteredSocialAccounts]);
2636
- const handleSocialBind = useCallback(
2637
- (snsType) => {
2638
- if (isOAuthSupported(snsType)) {
2639
- bindOAuth(snsType);
2640
- return;
2641
- }
2642
- toast.info(messages.bindSocialTodo ?? "This binding method is not yet supported");
2643
- },
2644
- [bindOAuth, isOAuthSupported, toast, messages]
2645
- );
2646
- const isSocialProcessing = useCallback(
2647
- (snsType) => {
2648
- if (isOAuthBinding(snsType)) return true;
2649
- return String(socialProcessingType).toLowerCase() === snsType.toLowerCase() && socialUnbindStatus === "loading";
2650
- },
2651
- [isOAuthBinding, socialProcessingType, socialUnbindStatus]
2652
- );
2653
- const handleWalletBind = useCallback(
2654
- (chainType) => {
2655
- bindWallet(chainType);
2656
- },
2657
- [bindWallet]
2658
- );
2659
- const handleWalletUnbind = useCallback(
2660
- (chainType, address) => {
2661
- unbindWallet(chainType, address);
2662
- },
2663
- [unbindWallet]
2664
- );
2665
- const isWalletProcessing = useCallback(
2666
- (chainType) => {
2667
- return String(walletProcessingChain) === String(chainType) && (walletBindStatus !== "idle" || walletUnbindStatus !== "idle");
2668
- },
2669
- [walletProcessingChain, walletBindStatus, walletUnbindStatus]
2670
- );
2671
- const isEmailUnbinding = useMemo(() => {
2672
- return socialProcessingType === SnsType.Email && socialUnbindStatus === "loading";
2673
- }, [socialProcessingType, socialUnbindStatus]);
2674
- if (!isLoaded) {
2675
- return /* @__PURE__ */ jsx("div", { className: "taskon-identity", children: /* @__PURE__ */ jsx("div", { className: "taskon-identity-loading", children: messages.loading }) });
2676
- }
2677
- const isEmpty = socialAccountsWithoutEmail.length === 0 && !emailAccount && filteredWalletAddresses.length === 0;
2678
- return /* @__PURE__ */ jsxs("div", { className: "taskon-identity", children: [
2679
- /* @__PURE__ */ jsx(
2680
- SocialAccountsSection,
2681
- {
2682
- accounts: socialAccountsWithoutEmail,
2683
- messages,
2684
- onBind: handleSocialBind,
2685
- onUnbind: unbindSocial,
2686
- isProcessing: isSocialProcessing,
2687
- checkUnlink: checkSocialUnlink,
2688
- onShowWarning: toast.warning
2689
- }
2690
- ),
2691
- /* @__PURE__ */ jsx(
2692
- WalletsSection,
2693
- {
2694
- wallets: filteredWalletAddresses,
2695
- rawAddresses,
2696
- messages,
2697
- onBind: handleWalletBind,
2698
- onUnbind: handleWalletUnbind,
2699
- isProcessing: isWalletProcessing,
2700
- checkUnlink: checkWalletUnlink,
2701
- onShowWarning: toast.warning,
2702
- onShowInfo: toast.info
2703
- }
2704
- ),
2705
- emailAccount && /* @__PURE__ */ jsx(
2706
- EmailSection,
2707
- {
2708
- emailAccount,
2709
- messages,
2710
- onUnbind: unbindSocial,
2711
- isUnbinding: isEmailUnbinding,
2712
- checkUnlink: checkSocialUnlink,
2713
- onShowSuccess: toast.success,
2714
- onShowError: toast.error,
2715
- onShowWarning: toast.warning
2716
- }
2717
- ),
2718
- isEmpty && /* @__PURE__ */ jsx("div", { className: "taskon-identity-empty", children: messages.noData ?? "No identity options configured" })
2719
- ] });
2720
- }
2721
- function MyRewardsContent({
2722
- messages,
2723
- defaultRewardCard,
2724
- defaultPointId
2725
- }) {
2726
- const { toast } = useToast();
2727
- const { client } = useTaskOnContext();
2728
- const [selectedPointsId, setSelectedPointsId] = useState(null);
2729
- const hasUserSelectedRef = useRef(false);
2730
- const appliedDefaultKeyRef = useRef(null);
2731
- const [showWithdrawForm, setShowWithdrawForm] = useState(false);
2732
- const [selectedTokenForWithdraw, setSelectedTokenForWithdraw] = useState(null);
2733
- const [viewingFrozenToken, setViewingFrozenToken] = useState(null);
2734
- const [resendParams, setResendParams] = useState(void 0);
2735
- const {
2736
- cards,
2737
- selectedCard,
2738
- selectCard,
2739
- loading: rewardsLoading,
2740
- error: rewardsError
2741
- } = useUserRewards({});
2742
- const selectedPointsData = useMemo(() => {
2743
- if (selectedCard !== USER_CENTER_REWARD_CARD_TYPES.Points) return null;
2744
- const selectedCardData = cards.find(
2745
- (c) => {
2746
- var _a;
2747
- return c.type === selectedCard && ((_a = c.pointsData) == null ? void 0 : _a.points_id) === selectedPointsId;
2748
- }
2749
- );
2750
- return (selectedCardData == null ? void 0 : selectedCardData.pointsData) ?? null;
2751
- }, [selectedCard, cards, selectedPointsId]);
2752
- const selectedXpLevelData = useMemo(() => {
2753
- if (selectedCard !== USER_CENTER_REWARD_CARD_TYPES.XpLevel) return null;
2754
- const xpLevelCard = cards.find(
2755
- (c) => c.type === USER_CENTER_REWARD_CARD_TYPES.XpLevel
2756
- );
2757
- return (xpLevelCard == null ? void 0 : xpLevelCard.xpLevelData) ?? null;
2758
- }, [selectedCard, cards]);
2759
- const {
2760
- data: tokenAssets,
2761
- loading: tokenAssetsLoading,
2762
- error: tokenAssetsError,
2763
- pendingWithdrawals,
2764
- refresh: refreshTokenAssets
2765
- } = useTokenAssets({
2766
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Token
2767
- });
2768
- const {
2769
- data: tokenHistory,
2770
- loading: tokenHistoryLoading,
2771
- error: tokenHistoryError,
2772
- pagination: tokenHistoryPagination
2773
- } = useRewardDetails({
2774
- rewardType: RewardType.Token,
2775
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Token
2776
- });
2777
- const {
2778
- data: frozenAssets,
2779
- loading: frozenAssetsLoading,
2780
- error: frozenAssetsError,
2781
- pagination: frozenAssetsPagination,
2782
- canResend
2783
- } = useFrozenAssets({
2784
- tokenId: (viewingFrozenToken == null ? void 0 : viewingFrozenToken.token_id) ?? 0,
2785
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Token && !!(viewingFrozenToken == null ? void 0 : viewingFrozenToken.token_id)
2786
- });
2787
- const userCenterApi = useMemo(() => {
2788
- if (!client) return null;
2789
- return createUserCenterApi(client);
2790
- }, [client]);
2791
- const {
2792
- data: nftList,
2793
- loading: nftLoading,
2794
- error: nftError,
2795
- pagination: nftPagination,
2796
- refresh: refreshNftList
2797
- } = useRewardDetails({
2798
- rewardType: RewardType.Nft,
2799
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Nft
2800
- });
2801
- const {
2802
- data: whitelistList,
2803
- loading: whitelistLoading,
2804
- error: whitelistError,
2805
- pagination: whitelistPagination
2806
- } = useRewardDetails({
2807
- rewardType: RewardType.Whitelist,
2808
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Whitelist
2809
- });
2810
- const {
2811
- data: discordRoleList,
2812
- loading: discordRoleLoading,
2813
- error: discordRoleError,
2814
- pagination: discordRolePagination
2815
- } = useRewardDetails({
2816
- rewardType: RewardType.DiscordRole,
2817
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.DiscordRole
2818
- });
2819
- const {
2820
- data: pointsHistory,
2821
- loading: pointsLoading,
2822
- error: pointsError,
2823
- pagination: pointsPagination
2824
- } = usePointsHistory({
2825
- pointsId: (selectedPointsData == null ? void 0 : selectedPointsData.points_id) ?? 0,
2826
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.Points && !!selectedPointsData
2827
- });
2828
- const {
2829
- data: xpLevelHistory,
2830
- loading: xpLevelHistoryLoading,
2831
- error: xpLevelHistoryError,
2832
- pagination: xpLevelHistoryPagination
2833
- } = usePointsHistory({
2834
- pointsId: (selectedXpLevelData == null ? void 0 : selectedXpLevelData.xpPointsId) ?? 0,
2835
- autoLoad: selectedCard === USER_CENTER_REWARD_CARD_TYPES.XpLevel && !!selectedXpLevelData
2836
- });
2837
- const handleWithdraw = (token) => {
2838
- setResendParams(void 0);
2839
- setSelectedTokenForWithdraw(token);
2840
- setShowWithdrawForm(true);
2841
- };
2842
- const handleBatchWithdraw = () => {
2843
- setResendParams(void 0);
2844
- setSelectedTokenForWithdraw(null);
2845
- setShowWithdrawForm(true);
2846
- };
2847
- const handleViewFrozen = (token) => {
2848
- setViewingFrozenToken(token);
2849
- };
2850
- const handleCloseFrozenAssets = () => {
2851
- setViewingFrozenToken(null);
2852
- };
2853
- const handleResendFrozenAsset = async (item) => {
2854
- if (!viewingFrozenToken || !userCenterApi) {
2855
- return;
2856
- }
2857
- if (item.type !== LockedType.Withdraw) {
2858
- return;
2859
- }
2860
- if (!item.nonce || !item.receiver_address) {
2861
- toast.error(messages.error ?? "Missing resend payload");
2862
- return;
2863
- }
2864
- try {
2865
- const requests = await userCenterApi.getTokenWithdrawByNonce({
2866
- chain: viewingFrozenToken.chain,
2867
- nonce: item.nonce
2868
- });
2869
- const withdrawableRequests = requests.filter((request) => request.can_withdraw);
2870
- if (withdrawableRequests.length === 0) {
2871
- toast.error(messages.emptyToken ?? "No tokens available for resend");
2872
- return;
2873
- }
2874
- setResendParams({
2875
- nonce: item.nonce,
2876
- receiverAddress: item.receiver_address,
2877
- tokens: withdrawableRequests
2878
- });
2879
- setSelectedTokenForWithdraw(viewingFrozenToken);
2880
- setShowWithdrawForm(true);
2881
- } catch (error) {
2882
- toast.error(error instanceof Error ? error.message : "Failed to load resend details");
2883
- }
2884
- };
2885
- const handleSelectCard = (type, pointsId) => {
2886
- hasUserSelectedRef.current = true;
2887
- selectCard(type);
2888
- setSelectedPointsId(pointsId ?? null);
2889
- };
2890
- useEffect(() => {
2891
- var _a, _b;
2892
- if (!defaultRewardCard) return;
2893
- if (hasUserSelectedRef.current) return;
2894
- if (cards.length === 0) return;
2895
- const applyKey = `${defaultRewardCard}:${defaultPointId ?? ""}`;
2896
- if (appliedDefaultKeyRef.current === applyKey) return;
2897
- const visibleDefaultCard = cards.find(
2898
- (card) => card.visible && card.type === defaultRewardCard
2899
- );
2900
- if (!visibleDefaultCard) {
2901
- appliedDefaultKeyRef.current = applyKey;
2902
- return;
2903
- }
2904
- selectCard(defaultRewardCard);
2905
- if (defaultRewardCard === USER_CENTER_REWARD_CARD_TYPES.Points) {
2906
- const matchedPointsCard = cards.find(
2907
- (card) => {
2908
- var _a2;
2909
- return card.type === USER_CENTER_REWARD_CARD_TYPES.Points && ((_a2 = card.pointsData) == null ? void 0 : _a2.points_id) === defaultPointId;
2910
- }
2911
- );
2912
- if (((_a = matchedPointsCard == null ? void 0 : matchedPointsCard.pointsData) == null ? void 0 : _a.points_id) != null) {
2913
- setSelectedPointsId(matchedPointsCard.pointsData.points_id);
2914
- } else if (((_b = visibleDefaultCard.pointsData) == null ? void 0 : _b.points_id) != null) {
2915
- setSelectedPointsId(visibleDefaultCard.pointsData.points_id);
2916
- }
2917
- } else {
2918
- setSelectedPointsId(null);
2919
- }
2920
- appliedDefaultKeyRef.current = applyKey;
2921
- }, [cards, defaultPointId, defaultRewardCard, selectCard]);
2922
- useEffect(() => {
2923
- if (selectedCard !== USER_CENTER_REWARD_CARD_TYPES.Token) {
2924
- setViewingFrozenToken(null);
2925
- }
2926
- }, [selectedCard]);
2927
- if (rewardsLoading && cards.length === 0) {
2928
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
2929
- }
2930
- if (rewardsError && cards.length === 0) {
2931
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: rewardsError.message }) });
2932
- }
2933
- const hasVisibleCards = cards.some((c) => c.visible);
2934
- if (!rewardsLoading && !hasVisibleCards) {
2935
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyRewards });
2936
- }
2937
- const renderSelectedContent = () => {
2938
- switch (selectedCard) {
2939
- case USER_CENTER_REWARD_CARD_TYPES.Token:
2940
- return /* @__PURE__ */ jsx(
2941
- TokenRewardContent,
2942
- {
2943
- tokenAssets,
2944
- tokenAssetsLoading,
2945
- tokenAssetsError,
2946
- pendingWithdrawals,
2947
- tokenHistory,
2948
- tokenHistoryLoading,
2949
- tokenHistoryError,
2950
- tokenHistoryPagination,
2951
- messages,
2952
- onWithdraw: handleWithdraw,
2953
- onBatchWithdraw: handleBatchWithdraw,
2954
- onViewFrozen: handleViewFrozen,
2955
- showFrozenAssets: !!viewingFrozenToken,
2956
- frozenAssets,
2957
- frozenAssetsLoading,
2958
- frozenAssetsError,
2959
- frozenAssetsPagination,
2960
- canResendFrozenAsset: canResend,
2961
- onResendFrozenAsset: handleResendFrozenAsset,
2962
- onCloseFrozenAssets: handleCloseFrozenAssets
2963
- }
2964
- );
2965
- case USER_CENTER_REWARD_CARD_TYPES.XpLevel:
2966
- if (!selectedXpLevelData) {
2967
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.noData });
2968
- }
2969
- return /* @__PURE__ */ jsx(
2970
- XpLevelCard,
2971
- {
2972
- xpData: {
2973
- level: selectedXpLevelData.level,
2974
- currentXp: selectedXpLevelData.currentXp,
2975
- nextLevelXp: selectedXpLevelData.nextLevelXp,
2976
- totalXp: selectedXpLevelData.currentXp,
2977
- pointsName: selectedXpLevelData.xpPointsName
2978
- },
2979
- historyData: xpLevelHistory,
2980
- historyLoading: xpLevelHistoryLoading,
2981
- historyError: xpLevelHistoryError,
2982
- pagination: xpLevelHistoryPagination,
2983
- messages
2984
- }
2985
- );
2986
- case USER_CENTER_REWARD_CARD_TYPES.Nft:
2987
- return /* @__PURE__ */ jsx(
2988
- NftRewardContent,
2989
- {
2990
- nftList,
2991
- loading: nftLoading,
2992
- error: nftError,
2993
- pagination: nftPagination,
2994
- messages,
2995
- onClaimSuccess: () => {
2996
- refreshNftList();
2997
- }
2998
- }
2999
- );
3000
- case USER_CENTER_REWARD_CARD_TYPES.Whitelist:
3001
- return /* @__PURE__ */ jsx(
3002
- WhitelistTable,
3003
- {
3004
- data: whitelistList,
3005
- loading: whitelistLoading,
3006
- error: whitelistError,
3007
- pagination: whitelistPagination,
3008
- messages
3009
- }
3010
- );
3011
- case USER_CENTER_REWARD_CARD_TYPES.DiscordRole:
3012
- return /* @__PURE__ */ jsx(
3013
- DiscordRoleTable,
3014
- {
3015
- data: discordRoleList,
3016
- loading: discordRoleLoading,
3017
- error: discordRoleError,
3018
- pagination: discordRolePagination,
3019
- messages
3020
- }
3021
- );
3022
- case USER_CENTER_REWARD_CARD_TYPES.Points:
3023
- if (!selectedPointsData) {
3024
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyPoints });
3025
- }
3026
- return /* @__PURE__ */ jsx(
3027
- PointsList,
3028
- {
3029
- pointsInfo: selectedPointsData,
3030
- data: pointsHistory,
3031
- loading: pointsLoading,
3032
- error: pointsError,
3033
- pagination: pointsPagination,
3034
- messages
3035
- }
3036
- );
3037
- default:
3038
- return null;
3039
- }
3040
- };
3041
- return /* @__PURE__ */ jsxs("div", { className: "taskon-my-rewards", children: [
3042
- /* @__PURE__ */ jsx(
3043
- AssetCarousel,
3044
- {
3045
- cards,
3046
- selectedCard,
3047
- selectedPointsId,
3048
- onSelectCard: handleSelectCard,
3049
- messages
3050
- }
3051
- ),
3052
- renderSelectedContent(),
3053
- /* @__PURE__ */ jsx(
3054
- WithdrawForm,
3055
- {
3056
- open: showWithdrawForm,
3057
- messages,
3058
- tokenAssets,
3059
- tokenAssetsLoading,
3060
- initialTokenId: selectedTokenForWithdraw == null ? void 0 : selectedTokenForWithdraw.token_id,
3061
- initialChain: selectedTokenForWithdraw == null ? void 0 : selectedTokenForWithdraw.chain,
3062
- resend: resendParams ? {
3063
- nonce: resendParams.nonce,
3064
- receiverAddress: resendParams.receiverAddress
3065
- } : void 0,
3066
- resendTokenItems: resendParams ? resendParams.tokens.map((request) => {
3067
- const matchedToken = tokenAssets.find(
3068
- (token) => token.token_id === request.token_id && token.chain.toLowerCase() === request.chain.toLowerCase()
3069
- );
3070
- return {
3071
- tokenId: request.token_id,
3072
- tokenSymbol: request.token_symbol,
3073
- tokenIcon: (matchedToken == null ? void 0 : matchedToken.token_icon) ?? "",
3074
- tokenAddress: request.token_address,
3075
- tokenDecimals: request.token_decimals,
3076
- chain: request.chain,
3077
- chainLabel: (matchedToken == null ? void 0 : matchedToken.chain_label) ?? request.chain,
3078
- amount: request.token_amount,
3079
- amountInWei: toWei(request.token_amount, request.token_decimals)
3080
- };
3081
- }) : void 0,
3082
- onClose: () => {
3083
- setResendParams(void 0);
3084
- setShowWithdrawForm(false);
3085
- },
3086
- onSuccess: () => {
3087
- refreshTokenAssets();
3088
- setResendParams(void 0);
3089
- setShowWithdrawForm(false);
3090
- }
3091
- }
3092
- )
3093
- ] });
3094
- }
3095
- function ActivityHistoryContent({
3096
- messages
3097
- }) {
3098
- const { data, loading, error, pagination, refresh } = useActivityHistory({
3099
- mode: "pagination"
3100
- });
3101
- return /* @__PURE__ */ jsx(
3102
- ActivityHistoryList,
3103
- {
3104
- data,
3105
- loading,
3106
- error,
3107
- pagination,
3108
- messages,
3109
- mode: "pagination",
3110
- onRetry: refresh
3111
- }
3112
- );
3113
- }
3114
- function mergeUserCenterConfig(props, cloud) {
3115
- const resolved = props.config ?? cloud ?? null;
3116
- const normalized = Array.isArray(resolved) && resolved.length > 0 ? resolved : null;
3117
- return {
3118
- config: normalized
3119
- };
3120
- }
3121
- const TAB_LABEL_KEYS = {
3122
- [UserCenterTabType.MyRewards]: "tabMyRewards",
3123
- [UserCenterTabType.Identity]: "tabIdentity",
3124
- [UserCenterTabType.ActivityHistory]: "tabActivityHistory"
3125
- };
3126
- const TAB_DEFAULT_LABELS = {
3127
- [UserCenterTabType.MyRewards]: "My Rewards",
3128
- [UserCenterTabType.Identity]: "Identity",
3129
- [UserCenterTabType.ActivityHistory]: "Activity History"
3130
- };
3131
- function UserCenterWidget(props) {
3132
- const { widgetId, themeMode } = props;
3133
- const { functionConfig, cloudTheme, isConfigLoading, configError } = useResolvedWidgetConfig(widgetId);
3134
- const mergedConfig = useMemo(() => {
3135
- return mergeUserCenterConfig(
3136
- props,
3137
- functionConfig ?? null
3138
- );
3139
- }, [props.config, functionConfig]);
3140
- const resolvedConfig = mergedConfig.config;
3141
- const isConfigured = Array.isArray(resolvedConfig) && resolvedConfig.length > 0;
3142
- return /* @__PURE__ */ jsx(
3143
- WidgetShell,
3144
- {
3145
- widgetId,
3146
- isConfigLoading,
3147
- cloudTheme,
3148
- themeMode,
3149
- className: "taskon-user-center",
3150
- errorMessage: configError ?? (!isConfigured ? "未配置" : void 0),
3151
- children: Array.isArray(resolvedConfig) && resolvedConfig.length > 0 ? /* @__PURE__ */ jsx(
3152
- UserCenterWidgetInner,
3153
- {
3154
- ...props,
3155
- config: resolvedConfig
3156
- }
3157
- ) : null
3158
- }
3159
- );
3160
- }
3161
- function UserCenterWidgetInner({
3162
- config,
3163
- defaultTab,
3164
- defaultRewardCard,
3165
- defaultPointId,
3166
- onTabChange,
3167
- className = "",
3168
- style
3169
- }) {
3170
- var _a;
3171
- const { isInitializing } = useTaskOnContext();
3172
- const { messages, isLoading: isLocaleLoading } = useWidgetLocale({
3173
- widgetId: "UserCenterWidget",
3174
- defaultMessages: enMessages,
3175
- loadMessages: (locale) => __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./locales/en.json": () => import("./UserCenterWidget-CvU6K4AC.js").then((n) => n.w), "./locales/ja.json": () => import("./usercenter-ja-B2465c1O.js"), "./locales/ko.json": () => import("./usercenter-ko-xAEYxqLg.js") }), `./locales/${locale}.json`, 3)
3176
- });
3177
- const enabledTabs = useMemo(() => filterEnabledTabs(config), [config]);
3178
- const tabItems = useMemo(() => {
3179
- return enabledTabs.map((tabConfig) => ({
3180
- key: tabConfig.tab,
3181
- label: messages[TAB_LABEL_KEYS[tabConfig.tab]] ?? TAB_DEFAULT_LABELS[tabConfig.tab]
3182
- }));
3183
- }, [enabledTabs, messages]);
3184
- const initialTab = defaultTab && enabledTabs.some((t) => t.tab === defaultTab) ? defaultTab : ((_a = enabledTabs[0]) == null ? void 0 : _a.tab) ?? UserCenterTabType.MyRewards;
3185
- const [activeTab, setActiveTab] = useState(initialTab);
3186
- const handleTabChange = (tab) => {
3187
- setActiveTab(tab);
3188
- onTabChange == null ? void 0 : onTabChange(tab);
3189
- };
3190
- if (isInitializing || isLocaleLoading) {
3191
- return /* @__PURE__ */ jsx("div", { className: `taskon-user-center ${className}`, style, children: /* @__PURE__ */ jsx(LoadingState, { message: messages.loading }) });
3192
- }
3193
- if (enabledTabs.length === 0) {
3194
- return /* @__PURE__ */ jsx("div", { className: `taskon-user-center ${className}`, style, children: /* @__PURE__ */ jsx("div", { className: "taskon-user-center-empty", children: messages.noData }) });
3195
- }
3196
- return /* @__PURE__ */ jsxs("div", { className: `taskon-user-center ${className}`, style, children: [
3197
- /* @__PURE__ */ jsx(Tabs, { items: tabItems, activeKey: activeTab, onChange: handleTabChange }),
3198
- /* @__PURE__ */ jsxs("div", { className: "taskon-user-center-content", children: [
3199
- activeTab === UserCenterTabType.MyRewards && /* @__PURE__ */ jsx(
3200
- MyRewardsContent,
3201
- {
3202
- config,
3203
- messages,
3204
- defaultRewardCard,
3205
- defaultPointId
3206
- }
3207
- ),
3208
- activeTab === UserCenterTabType.Identity && /* @__PURE__ */ jsx(IdentityContent, { config, messages }),
3209
- activeTab === UserCenterTabType.ActivityHistory && /* @__PURE__ */ jsx(
3210
- ActivityHistoryContent,
3211
- {
3212
- messages
3213
- }
3214
- )
3215
- ] })
3216
- ] });
3217
- }
3218
- export {
3219
- ActivityHistoryList as A,
3220
- UserCenterWidget as U,
3221
- AssetCard as a,
3222
- AssetCarousel as b,
3223
- useUserRewards as c,
3224
- useFrozenAssets as d,
3225
- useIdentityData as e,
3226
- useUnbindSocial as f,
3227
- useBindWallet as g,
3228
- useDisableUnlink as h,
3229
- useActivityHistory as u
3230
- };