@taskon/widget-react 0.0.1-beta.2 → 0.0.1-beta.3

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 (43) hide show
  1. package/README.md +55 -16
  2. package/dist/CommunityTaskList.css +432 -628
  3. package/dist/EligibilityInfo.css +944 -431
  4. package/dist/PageBuilder.css +0 -2
  5. package/dist/Quest.css +460 -505
  6. package/dist/TaskOnProvider.css +15 -15
  7. package/dist/UserCenterWidget.css +0 -174
  8. package/dist/UserCenterWidget2.css +870 -102
  9. package/dist/chunks/{CommunityTaskList-BlH1Wdd5.js → CommunityTaskList-C9mPl_31.js} +913 -826
  10. package/dist/chunks/{EligibilityInfo-C7GZ2G5u.js → EligibilityInfo-DGBffKN8.js} +1137 -449
  11. package/dist/chunks/{LeaderboardWidget-CmYfDeHV.js → LeaderboardWidget-DPOQVXkT.js} +15 -10
  12. package/dist/chunks/{PageBuilder-Bw0zSkFh.js → PageBuilder-WCZvxL2j.js} +5 -5
  13. package/dist/chunks/{Quest-DKFZ-pPU.js → Quest-DjGH_8bx.js} +464 -314
  14. package/dist/chunks/{TaskOnProvider-BD6Vp2x8.js → TaskOnProvider-iannERG1.js} +2 -207
  15. package/dist/chunks/{ThemeProvider-wnSXrNQb.js → ThemeProvider-DNJqI2lD.js} +246 -54
  16. package/dist/chunks/UserCenterWidget-B0O-f_xl.js +8344 -0
  17. package/dist/chunks/{UserCenterWidget-Cw6h_5hT.js → UserCenterWidget-CAhgp46j.js} +204 -1001
  18. package/dist/chunks/{WidgetShell-D_5OjvNZ.js → dynamic-import-helper-B2j_dZ4V.js} +607 -40
  19. package/dist/chunks/useToast-CaRkylKe.js +304 -0
  20. package/dist/chunks/{usercenter-ja-uu-XfVF9.js → usercenter-ja-B2465c1O.js} +4 -10
  21. package/dist/chunks/{usercenter-ko-DYgUOVzd.js → usercenter-ko-xAEYxqLg.js} +4 -10
  22. package/dist/community-task.d.ts +34 -3
  23. package/dist/community-task.js +1 -1
  24. package/dist/core.d.ts +40 -3
  25. package/dist/core.js +9 -10
  26. package/dist/dynamic-import-helper.css +186 -0
  27. package/dist/index.d.ts +207 -10
  28. package/dist/index.js +21 -19
  29. package/dist/leaderboard.d.ts +8 -1
  30. package/dist/leaderboard.js +2 -2
  31. package/dist/page-builder.js +1 -1
  32. package/dist/quest.d.ts +8 -2
  33. package/dist/quest.js +1 -1
  34. package/dist/user-center.d.ts +20 -136
  35. package/dist/user-center.js +19 -236
  36. package/package.json +7 -2
  37. package/dist/TipPopover.css +0 -210
  38. package/dist/WidgetShell.css +0 -182
  39. package/dist/chunks/TipPopover-BrW8jo71.js +0 -2926
  40. package/dist/chunks/UserCenterWidget-BE329iS7.js +0 -3546
  41. package/dist/chunks/dynamic-import-helper-DxEFwm31.js +0 -537
  42. package/dist/chunks/useToast-B-wyO5zL.js +0 -93
  43. package/dist/chunks/useWidgetLocale-JDelxtt8.js +0 -74
@@ -1,3546 +0,0 @@
1
- import '../UserCenterWidget2.css';var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
5
- import { P as Pagination$1, B as Button, T as Table, u as usePagination } from "./dynamic-import-helper-DxEFwm31.js";
6
- import { useState, useRef, useMemo, useCallback, useEffect, createContext } from "react";
7
- import { toWei, formatTokenAmount as formatTokenAmount$1, USER_CENTER_REWARD_CARD_TYPES, RouletteRewardType, USER_CENTER_PAGE_SIZE, createUserCenterApi, ChainType } from "@taskon/core";
8
- import { b as useTaskOnContext } from "./ThemeProvider-wnSXrNQb.js";
9
- import { u as useWallet } from "./useToast-B-wyO5zL.js";
10
- import { T as TipPopover, u as useChainMap, I as Input } from "./TipPopover-BrW8jo71.js";
11
- import { createPortal } from "react-dom";
12
- import { D as Dialog } from "./WidgetShell-D_5OjvNZ.js";
13
- const SelectContext = createContext({});
14
- function UnfoldIcon({
15
- isOpen,
16
- className
17
- }) {
18
- return /* @__PURE__ */ jsx(
19
- "svg",
20
- {
21
- className: `taskon-select__unfold-icon ${isOpen ? "taskon-select__unfold-icon--rotated" : ""} ${className ?? ""}`,
22
- width: "10",
23
- height: "6",
24
- viewBox: "0 0 10 6",
25
- fill: "none",
26
- children: /* @__PURE__ */ jsx(
27
- "path",
28
- {
29
- d: "M1 1L5 5L9 1",
30
- stroke: "currentColor",
31
- strokeWidth: "1.5",
32
- strokeLinecap: "round",
33
- strokeLinejoin: "round"
34
- }
35
- )
36
- }
37
- );
38
- }
39
- function Select({
40
- options,
41
- value,
42
- placeholder = "Select...",
43
- disabled = false,
44
- type = "default",
45
- menuAlign = "wide",
46
- menuOffsetPx = 10,
47
- menuInBody = true,
48
- showCheckedIcon = false,
49
- showUnfoldIcon = true,
50
- labelClass = "",
51
- noLabelStyle = false,
52
- noSelectedIcon = false,
53
- menuMaxHeight = "178px",
54
- hasError = false,
55
- error: error2,
56
- onChange,
57
- onOpenChange,
58
- beforeSlot,
59
- labelAfterSlot,
60
- afterSlot,
61
- labelSlot,
62
- menuBeforeSlot,
63
- menuAfterSlot,
64
- emptyOptionsSlot,
65
- renderOption
66
- }) {
67
- const [isOpen, setIsOpen] = useState(false);
68
- const [menuStyle, setMenuStyle] = useState({});
69
- const containerRef = useRef(null);
70
- const labelRef = useRef(null);
71
- const menuRef = useRef(null);
72
- const selectedOption = useMemo(() => {
73
- return options.find((opt) => opt.value === value) ?? null;
74
- }, [options, value]);
75
- const displayLabel = useMemo(() => {
76
- if (!selectedOption) return "";
77
- return selectedOption.selectedLabel ?? selectedOption.label;
78
- }, [selectedOption]);
79
- const toggleDropdown = useCallback(() => {
80
- if (disabled) return;
81
- setIsOpen((prev) => {
82
- const newState = !prev;
83
- onOpenChange == null ? void 0 : onOpenChange(newState);
84
- return newState;
85
- });
86
- }, [disabled, onOpenChange]);
87
- const closeDropdown = useCallback(() => {
88
- setIsOpen(false);
89
- onOpenChange == null ? void 0 : onOpenChange(false);
90
- }, [onOpenChange]);
91
- const handleSelect = useCallback(
92
- (option) => {
93
- if (option.disabled) return;
94
- if (option.value === value) {
95
- closeDropdown();
96
- return;
97
- }
98
- onChange == null ? void 0 : onChange(option.value, option);
99
- closeDropdown();
100
- },
101
- [value, onChange, closeDropdown]
102
- );
103
- const updateMenuPosition = useCallback(() => {
104
- if (!labelRef.current || !menuInBody) return;
105
- const rect = labelRef.current.getBoundingClientRect();
106
- window.scrollY || document.documentElement.scrollTop;
107
- window.scrollX || document.documentElement.scrollLeft;
108
- setMenuStyle({
109
- position: "fixed",
110
- top: rect.bottom + menuOffsetPx,
111
- left: rect.left,
112
- width: menuAlign === "wide" ? rect.width : void 0,
113
- minWidth: menuAlign !== "wide" ? rect.width : void 0,
114
- maxHeight: menuMaxHeight,
115
- zIndex: 9999
116
- });
117
- }, [menuInBody, menuOffsetPx, menuAlign, menuMaxHeight]);
118
- useEffect(() => {
119
- if (!isOpen) return;
120
- const handleClickOutside = (event) => {
121
- var _a;
122
- const target = event.target;
123
- if (containerRef.current && !containerRef.current.contains(target)) {
124
- if (menuInBody && ((_a = menuRef.current) == null ? void 0 : _a.contains(target))) {
125
- return;
126
- }
127
- closeDropdown();
128
- }
129
- };
130
- document.addEventListener("mousedown", handleClickOutside);
131
- return () => document.removeEventListener("mousedown", handleClickOutside);
132
- }, [isOpen, menuInBody, closeDropdown]);
133
- useEffect(() => {
134
- if (isOpen && menuInBody) {
135
- updateMenuPosition();
136
- const handleScroll = () => updateMenuPosition();
137
- const handleResize = () => updateMenuPosition();
138
- window.addEventListener("scroll", handleScroll, true);
139
- window.addEventListener("resize", handleResize);
140
- return () => {
141
- window.removeEventListener("scroll", handleScroll, true);
142
- window.removeEventListener("resize", handleResize);
143
- };
144
- }
145
- }, [isOpen, menuInBody, updateMenuPosition]);
146
- const renderMenuContent = () => /* @__PURE__ */ jsxs(
147
- "div",
148
- {
149
- ref: menuRef,
150
- className: `taskon-select__menu taskon-select__menu--${type}`,
151
- style: menuInBody ? menuStyle : { maxHeight: menuMaxHeight },
152
- onClick: (e) => e.stopPropagation(),
153
- children: [
154
- menuBeforeSlot,
155
- options.length === 0 ? emptyOptionsSlot ?? /* @__PURE__ */ jsx("div", { className: "taskon-select__empty", children: "No options" }) : options.map((option, index) => {
156
- const isActive = option.value === value;
157
- if (renderOption) {
158
- return /* @__PURE__ */ jsx(
159
- "div",
160
- {
161
- onClick: () => handleSelect(option),
162
- className: option.disabled ? "taskon-select__option--disabled" : "",
163
- children: renderOption(option, index, isActive)
164
- },
165
- String(option.value)
166
- );
167
- }
168
- return /* @__PURE__ */ jsxs(
169
- "div",
170
- {
171
- className: `taskon-select__option ${isActive ? "taskon-select__option--active" : ""} ${option.disabled ? "taskon-select__option--disabled" : ""} ${option.danger ? "taskon-select__option--danger" : ""}`,
172
- onClick: () => handleSelect(option),
173
- children: [
174
- option.icon && /* @__PURE__ */ jsx(
175
- "img",
176
- {
177
- src: option.icon,
178
- alt: "",
179
- className: "taskon-select__option-icon"
180
- }
181
- ),
182
- /* @__PURE__ */ jsxs("div", { className: "taskon-select__option-content", children: [
183
- /* @__PURE__ */ jsx("div", { className: "taskon-select__option-label", children: option.label }),
184
- option.desc && /* @__PURE__ */ jsx("div", { className: "taskon-select__option-desc", children: option.desc })
185
- ] }),
186
- showCheckedIcon && isActive && /* @__PURE__ */ jsx(
187
- "svg",
188
- {
189
- className: "taskon-select__option-check",
190
- width: "12",
191
- height: "8",
192
- viewBox: "0 0 12 8",
193
- fill: "none",
194
- children: /* @__PURE__ */ jsx(
195
- "path",
196
- {
197
- d: "M1 4L4.5 7.5L11 1",
198
- stroke: "currentColor",
199
- strokeWidth: "1.5",
200
- strokeLinecap: "round",
201
- strokeLinejoin: "round"
202
- }
203
- )
204
- }
205
- )
206
- ]
207
- },
208
- String(option.value)
209
- );
210
- }),
211
- menuAfterSlot
212
- ]
213
- }
214
- );
215
- const showErrorStyle = hasError || !!error2;
216
- const triggerClassName = [
217
- "taskon-select__trigger",
218
- !noLabelStyle && `taskon-select__trigger--${type}`,
219
- isOpen && "taskon-select__trigger--open",
220
- disabled && "taskon-select__trigger--disabled",
221
- showErrorStyle && "taskon-select__trigger--error",
222
- labelClass
223
- ].filter(Boolean).join(" ");
224
- return /* @__PURE__ */ jsx(SelectContext.Provider, { value: { showCheckedIcon }, children: /* @__PURE__ */ jsxs(
225
- "div",
226
- {
227
- ref: containerRef,
228
- className: `taskon-select ${disabled ? "taskon-select--disabled" : ""}`,
229
- children: [
230
- /* @__PURE__ */ jsxs(
231
- "div",
232
- {
233
- ref: labelRef,
234
- className: triggerClassName,
235
- onClick: toggleDropdown,
236
- role: "button",
237
- tabIndex: disabled ? -1 : 0,
238
- onKeyDown: (e) => {
239
- if (e.key === "Enter" || e.key === " ") {
240
- e.preventDefault();
241
- toggleDropdown();
242
- }
243
- },
244
- children: [
245
- beforeSlot,
246
- labelSlot ?? /* @__PURE__ */ jsxs(Fragment, { children: [
247
- (selectedOption == null ? void 0 : selectedOption.icon) && !noSelectedIcon && /* @__PURE__ */ jsx(
248
- "img",
249
- {
250
- src: selectedOption.icon,
251
- alt: "",
252
- className: "taskon-select__trigger-icon"
253
- }
254
- ),
255
- displayLabel ? /* @__PURE__ */ jsx("div", { className: "taskon-select__trigger-text", children: displayLabel }) : /* @__PURE__ */ jsx("div", { className: "taskon-select__trigger-placeholder", children: placeholder })
256
- ] }),
257
- labelAfterSlot,
258
- afterSlot ?? (showUnfoldIcon && !noLabelStyle && /* @__PURE__ */ jsx(UnfoldIcon, { isOpen }))
259
- ]
260
- }
261
- ),
262
- isOpen && (menuInBody ? createPortal(renderMenuContent(), document.body) : renderMenuContent()),
263
- error2 && /* @__PURE__ */ jsx("p", { className: "taskon-select__error", children: error2 })
264
- ]
265
- }
266
- ) });
267
- }
268
- function formatBalance$3(balance) {
269
- const num = parseFloat(balance);
270
- if (isNaN(num) || num === 0) return "0";
271
- return num.toLocaleString(void 0, { maximumFractionDigits: 6 });
272
- }
273
- function WithdrawSelectOption({
274
- label,
275
- icon,
276
- chainIcon,
277
- chainLabel,
278
- balance,
279
- canWithdraw = true,
280
- active,
281
- disabled,
282
- notSupportText = "Token not supported"
283
- }) {
284
- const isBlurred = canWithdraw === false;
285
- return /* @__PURE__ */ jsxs(
286
- "div",
287
- {
288
- className: `taskon-withdraw-option ${disabled ? "taskon-withdraw-option--disabled" : ""}`,
289
- children: [
290
- /* @__PURE__ */ jsxs(
291
- "div",
292
- {
293
- className: `taskon-withdraw-option__content ${isBlurred ? "taskon-withdraw-option__content--blurred" : ""}`,
294
- children: [
295
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-option__chain", children: [
296
- chainIcon && /* @__PURE__ */ jsx(
297
- "img",
298
- {
299
- src: chainIcon,
300
- alt: chainLabel,
301
- className: "taskon-withdraw-option__chain-icon"
302
- }
303
- ),
304
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-option__chain-label", children: chainLabel })
305
- ] }),
306
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-option__token", children: [
307
- icon && /* @__PURE__ */ jsx(
308
- "img",
309
- {
310
- src: icon,
311
- alt: label,
312
- className: "taskon-withdraw-option__token-icon"
313
- }
314
- ),
315
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-option__token-label", children: label })
316
- ] }),
317
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-option__trailing", children: [
318
- balance && /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-option__balance", children: formatBalance$3(balance) }),
319
- /* @__PURE__ */ jsx(
320
- "svg",
321
- {
322
- className: `taskon-withdraw-option__check ${active ? "taskon-withdraw-option__check--visible" : ""}`,
323
- width: "12",
324
- height: "8",
325
- viewBox: "0 0 12 8",
326
- fill: "none",
327
- children: /* @__PURE__ */ jsx(
328
- "path",
329
- {
330
- d: "M1 4L4.5 7.5L11 1",
331
- stroke: "currentColor",
332
- strokeWidth: "1.5",
333
- strokeLinecap: "round",
334
- strokeLinejoin: "round"
335
- }
336
- )
337
- }
338
- )
339
- ] })
340
- ]
341
- }
342
- ),
343
- canWithdraw === false && /* @__PURE__ */ jsx("p", { className: "taskon-withdraw-option__warning", children: notSupportText })
344
- ]
345
- }
346
- );
347
- }
348
- function FormItem({
349
- label,
350
- error: error2,
351
- titleClass,
352
- type = "default",
353
- optional = false,
354
- optionalText = "Optional",
355
- tip,
356
- isWarn = false,
357
- docLabel,
358
- docUrl,
359
- noRowMargin = false,
360
- className,
361
- children,
362
- rowStartSlot,
363
- rowSlot,
364
- tipSlot,
365
- onMounted,
366
- onUnmounted
367
- }) {
368
- useEffect(() => {
369
- onMounted == null ? void 0 : onMounted();
370
- return () => {
371
- onUnmounted == null ? void 0 : onUnmounted();
372
- };
373
- }, [onMounted, onUnmounted]);
374
- const rootClassName = [
375
- "taskon-form-item",
376
- type === "dialog" && "taskon-form-item--dialog",
377
- className
378
- ].filter(Boolean).join(" ");
379
- const rowClassName = [
380
- "taskon-form-item__row",
381
- label && "taskon-form-item__row--has-label",
382
- noRowMargin && "taskon-form-item__row--no-margin",
383
- titleClass
384
- ].filter(Boolean).join(" ");
385
- const errorClassName = [
386
- "taskon-form-item__error",
387
- isWarn && "taskon-form-item__error--warn"
388
- ].filter(Boolean).join(" ");
389
- return /* @__PURE__ */ jsxs(
390
- "div",
391
- {
392
- className: rootClassName,
393
- "data-testid": label ? `form-item-${label}` : void 0,
394
- children: [
395
- /* @__PURE__ */ jsxs("div", { className: rowClassName, children: [
396
- rowStartSlot,
397
- /* @__PURE__ */ jsxs("div", { className: "taskon-form-item__label", children: [
398
- label && /* @__PURE__ */ jsx("span", { children: label }),
399
- optional && /* @__PURE__ */ jsxs("span", { className: "taskon-form-item__optional", children: [
400
- " ",
401
- optionalText
402
- ] }),
403
- tipSlot ?? (tip && /* @__PURE__ */ jsx("span", { className: "taskon-form-item__tip", children: /* @__PURE__ */ jsx(TipPopover, { content: tip }) }))
404
- ] }),
405
- docLabel && docUrl && /* @__PURE__ */ jsxs(
406
- "a",
407
- {
408
- href: docUrl,
409
- target: "_blank",
410
- rel: "noopener noreferrer",
411
- className: "taskon-form-item__doc-link",
412
- children: [
413
- /* @__PURE__ */ jsx("span", { children: docLabel }),
414
- /* @__PURE__ */ jsx(
415
- "svg",
416
- {
417
- className: "taskon-form-item__doc-icon",
418
- width: "8",
419
- height: "9",
420
- viewBox: "0 0 8 9",
421
- fill: "none",
422
- children: /* @__PURE__ */ jsx(
423
- "path",
424
- {
425
- d: "M1 4.5H7M7 4.5L4 1.5M7 4.5L4 7.5",
426
- stroke: "currentColor",
427
- strokeWidth: "1.5",
428
- strokeLinecap: "round",
429
- strokeLinejoin: "round"
430
- }
431
- )
432
- }
433
- )
434
- ]
435
- }
436
- ),
437
- rowSlot
438
- ] }),
439
- children,
440
- error2 && /* @__PURE__ */ jsx("div", { className: errorClassName, children: error2 })
441
- ]
442
- }
443
- );
444
- }
445
- function CheckedIcon() {
446
- return /* @__PURE__ */ jsx(
447
- "svg",
448
- {
449
- className: "taskon-checkbox__icon-checked",
450
- viewBox: "0 0 12 10",
451
- fill: "none",
452
- xmlns: "http://www.w3.org/2000/svg",
453
- children: /* @__PURE__ */ jsx(
454
- "path",
455
- {
456
- d: "M1 5L4.5 8.5L11 1.5",
457
- stroke: "currentColor",
458
- strokeWidth: "2",
459
- strokeLinecap: "round",
460
- strokeLinejoin: "round"
461
- }
462
- )
463
- }
464
- );
465
- }
466
- function Checkbox({
467
- checked,
468
- onChange,
469
- label,
470
- disabled = false,
471
- readonly = false,
472
- round = false,
473
- type = "default",
474
- className = "",
475
- children,
476
- afterSlot
477
- }) {
478
- const handleClick = useCallback(() => {
479
- if (disabled || readonly) {
480
- return;
481
- }
482
- onChange(!checked);
483
- }, [disabled, readonly, checked, onChange]);
484
- const handleKeyDown = useCallback(
485
- (e) => {
486
- if (disabled || readonly) {
487
- return;
488
- }
489
- if (e.key === " " || e.key === "Enter") {
490
- e.preventDefault();
491
- onChange(!checked);
492
- }
493
- },
494
- [disabled, readonly, checked, onChange]
495
- );
496
- const rootClassName = [
497
- "taskon-checkbox",
498
- disabled && "taskon-checkbox--disabled",
499
- readonly && "taskon-checkbox--readonly",
500
- className
501
- ].filter(Boolean).join(" ");
502
- const iconClassName = [
503
- "taskon-checkbox__icon",
504
- checked && "taskon-checkbox__icon--active",
505
- type === "light" && "taskon-checkbox__icon--light",
506
- round && "taskon-checkbox__icon--round"
507
- ].filter(Boolean).join(" ");
508
- return /* @__PURE__ */ jsxs(
509
- "div",
510
- {
511
- className: rootClassName,
512
- onClick: handleClick,
513
- onKeyDown: handleKeyDown,
514
- role: "checkbox",
515
- "aria-checked": checked,
516
- "aria-disabled": disabled,
517
- tabIndex: disabled || readonly ? -1 : 0,
518
- children: [
519
- children,
520
- /* @__PURE__ */ jsx(
521
- "input",
522
- {
523
- type: "checkbox",
524
- className: "taskon-checkbox__input",
525
- checked,
526
- disabled: disabled || readonly,
527
- readOnly: true,
528
- tabIndex: -1
529
- }
530
- ),
531
- /* @__PURE__ */ jsx("div", { className: iconClassName, children: /* @__PURE__ */ jsx(CheckedIcon, {}) }),
532
- label && /* @__PURE__ */ jsx("div", { className: "taskon-checkbox__label", children: label }),
533
- afterSlot
534
- ]
535
- }
536
- );
537
- }
538
- function Switch({
539
- checked,
540
- onChange,
541
- label,
542
- disabled = false,
543
- type = "normal",
544
- className = ""
545
- }) {
546
- const handleClick = useCallback(() => {
547
- if (disabled) {
548
- return;
549
- }
550
- onChange(!checked);
551
- }, [disabled, checked, onChange]);
552
- const handleKeyDown = useCallback(
553
- (e) => {
554
- if (disabled) {
555
- return;
556
- }
557
- if (e.key === " " || e.key === "Enter") {
558
- e.preventDefault();
559
- onChange(!checked);
560
- }
561
- },
562
- [disabled, checked, onChange]
563
- );
564
- const rootClassName = [
565
- "taskon-switch",
566
- type === "highlight" && "taskon-switch--highlight",
567
- disabled && "taskon-switch--disabled",
568
- className
569
- ].filter(Boolean).join(" ");
570
- const buttonClassName = [
571
- "taskon-switch__button",
572
- checked && "taskon-switch__button--active",
573
- disabled && "taskon-switch__button--disabled"
574
- ].filter(Boolean).join(" ");
575
- return /* @__PURE__ */ jsxs(
576
- "div",
577
- {
578
- className: rootClassName,
579
- onClick: handleClick,
580
- onKeyDown: handleKeyDown,
581
- role: "switch",
582
- "aria-checked": checked,
583
- "aria-disabled": disabled,
584
- tabIndex: disabled ? -1 : 0,
585
- children: [
586
- label && /* @__PURE__ */ jsx(
587
- "span",
588
- {
589
- className: `taskon-switch__label ${disabled ? "taskon-switch__label--disabled" : ""}`,
590
- children: label
591
- }
592
- ),
593
- /* @__PURE__ */ jsx("div", { className: buttonClassName, children: /* @__PURE__ */ jsx("div", { className: "taskon-switch__slider" }) })
594
- ]
595
- }
596
- );
597
- }
598
- const tabMyRewards = "My Rewards";
599
- const tabIdentity = "Identity";
600
- const tabActivityHistory = "Activity History";
601
- const tabRewards = "Rewards";
602
- const tabSprintOdysseyHistory = "Sprint & Odyssey History";
603
- const sectionYouHaveEarned = "You have earned";
604
- const rewardToken = "Token";
605
- const rewardXpLevel = "XP & Level";
606
- const rewardNft = "NFT";
607
- const rewardWhitelist = "Whitelist";
608
- const rewardDiscordRole = "Discord Role";
609
- const rewardPoints = "Points";
610
- const withdrawableAssets = "Withdrawable Assets";
611
- const tokenHistory = "Token History";
612
- const withdraw = "Withdraw";
613
- const batchWithdraw = "Batch Withdraw";
614
- const frozenAssets = "Frozen Assets";
615
- const resend = "Resend";
616
- const pendingWithdrawals = "You have {count} pending withdrawals";
617
- const withdrawConfirm = "Confirm Withdrawal";
618
- const withdrawSuccess = "Withdrawal Successful";
619
- const withdrawCanceled = "Withdrawal Canceled";
620
- const gasNotEnough = "Insufficient Gas";
621
- const retry = "Retry";
622
- const confirmWithdraw = "Confirm withdrawal";
623
- const withdrawing = "Processing withdrawal...";
624
- const confirm = "Confirm";
625
- const cancel = "Cancel";
626
- const close = "Close";
627
- const gasFreeWithdraw = "Free Withdraw";
628
- const gasFreeRemaining = "{count} free withdrawals remaining";
629
- const pollingStatus = "Processing via Gas Station...";
630
- const columnDetail = "Detail";
631
- const columnDuration = "Duration";
632
- const activityName = "Activity Name";
633
- const activityTime = "Activity Time";
634
- const level = "Level";
635
- const totalXp = "Total XP";
636
- const xpToNextLevel = "XP to next level";
637
- const xpHistory = "XP History";
638
- const totalPoints = "Total";
639
- const emptyPoints = "No points history yet";
640
- const pointsHistory = "Points History";
641
- const page = "Page";
642
- const of = "of";
643
- const previous = "Previous";
644
- const next = "Next";
645
- const loadMore = "Load More";
646
- const showing = "Showing {start}-{end} of {total}";
647
- const socialAccounts = "Social Media Accounts";
648
- const walletAddresses = "Network List";
649
- const emailAddress = "Email Address";
650
- const bind = "Bind";
651
- const unbind = "Unbind";
652
- const connectWallet = "Connect Wallet";
653
- const binding = "Binding...";
654
- const unbinding = "Unbinding...";
655
- const bindSocialTodo = "OAuth binding will be available soon";
656
- const confirmUnbind = "Confirm Unbind";
657
- const unbindWarning = "Are you sure you want to unbind this account?";
658
- const kycWarning = "This address has been KYC verified. After unbinding, you will need to re-verify KYC if you bind it again.";
659
- const unbindCooldown = "Cannot unbind within 24 hours of binding";
660
- const lastLoginMethod = "Cannot unbind the last login method";
661
- const unbindSuccess = "Unbind successful";
662
- const unbindFailed = "Unbind failed";
663
- const bindSuccess = "Bind successful";
664
- const bindFailed = "Bind failed";
665
- const connectingWallet = "Connecting wallet...";
666
- const signingMessage = "Signing message...";
667
- const emptyIdentity = "No identity options configured";
668
- const linkEmailAccount = "Link Email Account";
669
- const pleaseEnterEmail = "Please enter email address";
670
- const pleaseEnterValidEmail = "Please enter a valid email address";
671
- const verificationCode = "Verification Code";
672
- const pleaseEnterCode = "Please enter verification code";
673
- const pleaseEnterValidCode = "Please enter a valid verification code";
674
- const sendVerificationCode = "Send Verification Code";
675
- const resendCode = "Resend";
676
- const emailAlreadyLinked = "This email is already linked to another account";
677
- const sendCodeSuccess = "Verification code sent";
678
- const sendCodeFailed = "Failed to send verification code";
679
- const columnTokenSymbol = "Token Symbol";
680
- const columnNetwork = "Network";
681
- const columnWithdrawable = "Withdrawable";
682
- const columnAction = "Action";
683
- const ok = "OK";
684
- const claimNft = "Claim NFT";
685
- const linked = "Linked";
686
- const linkPlatformAccount = "Link {platform} Account";
687
- const withdrawCanceledMessage = "Your withdrawal was canceled. You can retry the transaction.";
688
- const frozenTypeCampaign = "Campaign Locked";
689
- const frozenTypeWithdraw = "Pending Withdrawal";
690
- const frozenTypeReferral = "Referral Locked";
691
- const frozenTypeBenefit = "Benefit Locked";
692
- const frozenTypeTgMiniApp = "TG Mini App";
693
- const frozenTypeMilestone = "Milestone Locked";
694
- const loading = "Loading...";
695
- const error = "Something went wrong";
696
- const emptyRewards = "No rewards yet";
697
- const emptyActivityHistory = "No activity history";
698
- const emptyToken = "No tokens yet";
699
- const emptyNft = "No NFTs yet";
700
- const noData = "No data";
701
- const claim = "Claim";
702
- const claimedTxn = "Claimed (Txn)";
703
- const manualDrop = "Manual Drop";
704
- const columnNft = "NFT";
705
- const columnWhitelist = "Whitelist";
706
- const columnDiscordRole = "Discord Role";
707
- const columnTime = "Time";
708
- const columnStatus = "Status";
709
- const columnAmount = "Amount";
710
- const deposited = "Deposited";
711
- const distributedBy = "Distributed by";
712
- const columnTokenType = "Type";
713
- const columnAmountWithdrawable = "Amount Withdrawable";
714
- const columnWithdrawAmount = "Withdraw Amount";
715
- const selectToken = "Select Token";
716
- const tokenAmount = "Token Amount";
717
- const receiveAddress = "Receive Address";
718
- const max = "MAX";
719
- const availableBalance = "Available";
720
- const pleaseSelectToken = "Please select a token";
721
- const pleaseEnterValidAmount = "Please enter a valid amount";
722
- const amountExceedsBalance = "Amount exceeds available balance";
723
- const withdrawingTip = "Please wait while your withdrawal is being processed...";
724
- const claimingNft = "Claiming NFT...";
725
- const claimConnectingWallet = "Connecting wallet...";
726
- const claimSwitchingNetwork = "Switching network...";
727
- const claimGettingSignature = "Getting signature...";
728
- const claimConfirmInWallet = "Please confirm in your wallet";
729
- const claimTransactionPending = "Transaction pending...";
730
- const claimSuccess = "Claim successful!";
731
- const claimFailed = "Claim failed";
732
- const viewOnExplorer = "View on Explorer";
733
- const pendingTransaction = "Pending Transaction";
734
- const pendingTxMessage = "You have a pending transaction";
735
- const continueWaiting = "Continue Waiting";
736
- const claimAgain = "Claim Again";
737
- const errorNoWallet = "No wallet found. Please install a wallet extension.";
738
- const errorAddressMismatch = "Connected wallet address does not match.";
739
- const errorNetworkSwitch = "Failed to switch network. Please switch manually.";
740
- const errorInsufficientGas = "Insufficient gas. Please add more funds to your wallet.";
741
- const enMessages = {
742
- tabMyRewards,
743
- tabIdentity,
744
- tabActivityHistory,
745
- tabRewards,
746
- tabSprintOdysseyHistory,
747
- sectionYouHaveEarned,
748
- rewardToken,
749
- rewardXpLevel,
750
- rewardNft,
751
- rewardWhitelist,
752
- rewardDiscordRole,
753
- rewardPoints,
754
- withdrawableAssets,
755
- tokenHistory,
756
- withdraw,
757
- batchWithdraw,
758
- frozenAssets,
759
- resend,
760
- pendingWithdrawals,
761
- withdrawConfirm,
762
- withdrawSuccess,
763
- withdrawCanceled,
764
- gasNotEnough,
765
- retry,
766
- confirmWithdraw,
767
- withdrawing,
768
- confirm,
769
- cancel,
770
- close,
771
- gasFreeWithdraw,
772
- gasFreeRemaining,
773
- pollingStatus,
774
- columnDetail,
775
- columnDuration,
776
- activityName,
777
- activityTime,
778
- level,
779
- totalXp,
780
- xpToNextLevel,
781
- xpHistory,
782
- totalPoints,
783
- emptyPoints,
784
- pointsHistory,
785
- page,
786
- of,
787
- previous,
788
- next,
789
- loadMore,
790
- showing,
791
- socialAccounts,
792
- walletAddresses,
793
- emailAddress,
794
- bind,
795
- unbind,
796
- connectWallet,
797
- binding,
798
- unbinding,
799
- bindSocialTodo,
800
- confirmUnbind,
801
- unbindWarning,
802
- kycWarning,
803
- unbindCooldown,
804
- lastLoginMethod,
805
- unbindSuccess,
806
- unbindFailed,
807
- bindSuccess,
808
- bindFailed,
809
- connectingWallet,
810
- signingMessage,
811
- emptyIdentity,
812
- linkEmailAccount,
813
- pleaseEnterEmail,
814
- pleaseEnterValidEmail,
815
- verificationCode,
816
- pleaseEnterCode,
817
- pleaseEnterValidCode,
818
- sendVerificationCode,
819
- resendCode,
820
- emailAlreadyLinked,
821
- sendCodeSuccess,
822
- sendCodeFailed,
823
- columnTokenSymbol,
824
- columnNetwork,
825
- columnWithdrawable,
826
- columnAction,
827
- ok,
828
- claimNft,
829
- linked,
830
- linkPlatformAccount,
831
- withdrawCanceledMessage,
832
- frozenTypeCampaign,
833
- frozenTypeWithdraw,
834
- frozenTypeReferral,
835
- frozenTypeBenefit,
836
- frozenTypeTgMiniApp,
837
- frozenTypeMilestone,
838
- loading,
839
- error,
840
- emptyRewards,
841
- emptyActivityHistory,
842
- emptyToken,
843
- emptyNft,
844
- noData,
845
- claim,
846
- claimedTxn,
847
- manualDrop,
848
- columnNft,
849
- columnWhitelist,
850
- columnDiscordRole,
851
- columnTime,
852
- columnStatus,
853
- columnAmount,
854
- deposited,
855
- distributedBy,
856
- columnTokenType,
857
- columnAmountWithdrawable,
858
- columnWithdrawAmount,
859
- selectToken,
860
- tokenAmount,
861
- receiveAddress,
862
- max,
863
- availableBalance,
864
- pleaseSelectToken,
865
- pleaseEnterValidAmount,
866
- amountExceedsBalance,
867
- withdrawingTip,
868
- claimingNft,
869
- claimConnectingWallet,
870
- claimSwitchingNetwork,
871
- claimGettingSignature,
872
- claimConfirmInWallet,
873
- claimTransactionPending,
874
- claimSuccess,
875
- claimFailed,
876
- viewOnExplorer,
877
- pendingTransaction,
878
- pendingTxMessage,
879
- continueWaiting,
880
- claimAgain,
881
- errorNoWallet,
882
- errorAddressMismatch,
883
- errorNetworkSwitch,
884
- errorInsufficientGas
885
- };
886
- const en = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
887
- __proto__: null,
888
- activityName,
889
- activityTime,
890
- amountExceedsBalance,
891
- availableBalance,
892
- batchWithdraw,
893
- bind,
894
- bindFailed,
895
- bindSocialTodo,
896
- bindSuccess,
897
- binding,
898
- cancel,
899
- claim,
900
- claimAgain,
901
- claimConfirmInWallet,
902
- claimConnectingWallet,
903
- claimFailed,
904
- claimGettingSignature,
905
- claimNft,
906
- claimSuccess,
907
- claimSwitchingNetwork,
908
- claimTransactionPending,
909
- claimedTxn,
910
- claimingNft,
911
- close,
912
- columnAction,
913
- columnAmount,
914
- columnAmountWithdrawable,
915
- columnDetail,
916
- columnDiscordRole,
917
- columnDuration,
918
- columnNetwork,
919
- columnNft,
920
- columnStatus,
921
- columnTime,
922
- columnTokenSymbol,
923
- columnTokenType,
924
- columnWhitelist,
925
- columnWithdrawAmount,
926
- columnWithdrawable,
927
- confirm,
928
- confirmUnbind,
929
- confirmWithdraw,
930
- connectWallet,
931
- connectingWallet,
932
- continueWaiting,
933
- default: enMessages,
934
- deposited,
935
- distributedBy,
936
- emailAddress,
937
- emailAlreadyLinked,
938
- emptyActivityHistory,
939
- emptyIdentity,
940
- emptyNft,
941
- emptyPoints,
942
- emptyRewards,
943
- emptyToken,
944
- error,
945
- errorAddressMismatch,
946
- errorInsufficientGas,
947
- errorNetworkSwitch,
948
- errorNoWallet,
949
- frozenAssets,
950
- frozenTypeBenefit,
951
- frozenTypeCampaign,
952
- frozenTypeMilestone,
953
- frozenTypeReferral,
954
- frozenTypeTgMiniApp,
955
- frozenTypeWithdraw,
956
- gasFreeRemaining,
957
- gasFreeWithdraw,
958
- gasNotEnough,
959
- kycWarning,
960
- lastLoginMethod,
961
- level,
962
- linkEmailAccount,
963
- linkPlatformAccount,
964
- linked,
965
- loadMore,
966
- loading,
967
- manualDrop,
968
- max,
969
- next,
970
- noData,
971
- of,
972
- ok,
973
- page,
974
- pendingTransaction,
975
- pendingTxMessage,
976
- pendingWithdrawals,
977
- pleaseEnterCode,
978
- pleaseEnterEmail,
979
- pleaseEnterValidAmount,
980
- pleaseEnterValidCode,
981
- pleaseEnterValidEmail,
982
- pleaseSelectToken,
983
- pointsHistory,
984
- pollingStatus,
985
- previous,
986
- receiveAddress,
987
- resend,
988
- resendCode,
989
- retry,
990
- rewardDiscordRole,
991
- rewardNft,
992
- rewardPoints,
993
- rewardToken,
994
- rewardWhitelist,
995
- rewardXpLevel,
996
- sectionYouHaveEarned,
997
- selectToken,
998
- sendCodeFailed,
999
- sendCodeSuccess,
1000
- sendVerificationCode,
1001
- showing,
1002
- signingMessage,
1003
- socialAccounts,
1004
- tabActivityHistory,
1005
- tabIdentity,
1006
- tabMyRewards,
1007
- tabRewards,
1008
- tabSprintOdysseyHistory,
1009
- tokenAmount,
1010
- tokenHistory,
1011
- totalPoints,
1012
- totalXp,
1013
- unbind,
1014
- unbindCooldown,
1015
- unbindFailed,
1016
- unbindSuccess,
1017
- unbindWarning,
1018
- unbinding,
1019
- verificationCode,
1020
- viewOnExplorer,
1021
- walletAddresses,
1022
- withdraw,
1023
- withdrawCanceled,
1024
- withdrawCanceledMessage,
1025
- withdrawConfirm,
1026
- withdrawSuccess,
1027
- withdrawableAssets,
1028
- withdrawing,
1029
- withdrawingTip,
1030
- xpHistory,
1031
- xpToNextLevel
1032
- }, Symbol.toStringTag, { value: "Module" }));
1033
- function EmptyState({
1034
- message,
1035
- icon,
1036
- className = ""
1037
- }) {
1038
- return /* @__PURE__ */ jsxs("div", { className: `taskon-user-center-empty ${className}`, children: [
1039
- icon && /* @__PURE__ */ jsx("div", { className: "taskon-user-center-empty__icon", children: icon }),
1040
- /* @__PURE__ */ jsx("p", { className: "taskon-user-center-empty__message", children: message })
1041
- ] });
1042
- }
1043
- function LoadingState({
1044
- message = "Loading...",
1045
- className = ""
1046
- }) {
1047
- return /* @__PURE__ */ jsxs("div", { className: `taskon-user-center-loading ${className}`, children: [
1048
- /* @__PURE__ */ jsx("div", { className: "taskon-user-center-loading__spinner" }),
1049
- message && /* @__PURE__ */ jsx("p", { className: "taskon-user-center-loading__message", children: message })
1050
- ] });
1051
- }
1052
- function Pagination({
1053
- page: page2,
1054
- totalPages,
1055
- hasPrevious,
1056
- hasNext,
1057
- onPrevious,
1058
- onNext,
1059
- messages,
1060
- className = "",
1061
- showRange
1062
- }) {
1063
- if (totalPages === 0) {
1064
- return null;
1065
- }
1066
- const paginationMessages = {
1067
- previous: messages.previous,
1068
- next: messages.next,
1069
- page: messages.page,
1070
- of: messages.of,
1071
- showing: messages.showing
1072
- };
1073
- return /* @__PURE__ */ jsx(
1074
- Pagination$1,
1075
- {
1076
- page: page2,
1077
- totalPages,
1078
- hasPrevious,
1079
- hasNext,
1080
- onPrevious,
1081
- onNext,
1082
- messages: paginationMessages,
1083
- className: `taskon-user-center-pagination ${className}`,
1084
- showRange,
1085
- showArrows: true,
1086
- showButtonText: false
1087
- }
1088
- );
1089
- }
1090
- function WithdrawPending({
1091
- count,
1092
- text,
1093
- onClick
1094
- }) {
1095
- if (count <= 0) {
1096
- return null;
1097
- }
1098
- return /* @__PURE__ */ jsxs(
1099
- "div",
1100
- {
1101
- className: "taskon-withdraw-pending",
1102
- role: "status",
1103
- "aria-live": "polite",
1104
- onClick,
1105
- onKeyDown: (e) => {
1106
- if (e.key === "Enter" || e.key === " ") {
1107
- onClick == null ? void 0 : onClick();
1108
- }
1109
- },
1110
- tabIndex: onClick ? 0 : void 0,
1111
- children: [
1112
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-pending__left", children: [
1113
- /* @__PURE__ */ jsx(
1114
- "span",
1115
- {
1116
- className: "taskon-withdraw-pending__count",
1117
- "aria-label": "Number of pending withdrawals",
1118
- children: count
1119
- }
1120
- ),
1121
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-pending__text", children: text })
1122
- ] }),
1123
- /* @__PURE__ */ jsx(
1124
- "svg",
1125
- {
1126
- className: "taskon-withdraw-pending__arrow",
1127
- width: "7",
1128
- height: "14",
1129
- viewBox: "0 0 7 14",
1130
- fill: "none",
1131
- xmlns: "http://www.w3.org/2000/svg",
1132
- "aria-hidden": "true",
1133
- children: /* @__PURE__ */ jsx(
1134
- "path",
1135
- {
1136
- d: "M1 1L6 7L1 13",
1137
- stroke: "currentColor",
1138
- strokeWidth: "2",
1139
- strokeLinecap: "round",
1140
- strokeLinejoin: "round"
1141
- }
1142
- )
1143
- }
1144
- )
1145
- ]
1146
- }
1147
- );
1148
- }
1149
- function formatBalance$2(balance) {
1150
- const num = parseFloat(balance);
1151
- if (isNaN(num) || num === 0) return "0";
1152
- if (num < 1e-4) return "<0.0001";
1153
- if (num >= 1e6) return `${(num / 1e6).toFixed(2)}M`;
1154
- if (num >= 1e3) return `${(num / 1e3).toFixed(2)}K`;
1155
- return num.toLocaleString(void 0, { maximumFractionDigits: 5 });
1156
- }
1157
- function TokenAssetList({
1158
- data,
1159
- loading: loading2,
1160
- error: error2,
1161
- messages,
1162
- pendingWithdrawals: pendingWithdrawals2,
1163
- onWithdraw
1164
- }) {
1165
- if (loading2 && data.length === 0) {
1166
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
1167
- }
1168
- if (error2 && data.length === 0) {
1169
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error2.message }) });
1170
- }
1171
- if (!loading2 && data.length === 0) {
1172
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyToken });
1173
- }
1174
- const columns = [
1175
- {
1176
- key: "token_symbol",
1177
- title: messages.columnTokenSymbol ?? "Token Symbol",
1178
- width: 120,
1179
- render: (_, row) => /* @__PURE__ */ jsxs("div", { className: "taskon-token-assets__symbol-cell", children: [
1180
- /* @__PURE__ */ jsx(
1181
- "img",
1182
- {
1183
- src: row.token_icon,
1184
- alt: row.token_symbol,
1185
- className: "taskon-token-assets__token-icon"
1186
- }
1187
- ),
1188
- /* @__PURE__ */ jsx("span", { className: "taskon-token-assets__symbol", children: row.token_symbol })
1189
- ] })
1190
- },
1191
- {
1192
- key: "chain",
1193
- title: messages.columnNetwork ?? "Network",
1194
- width: 164,
1195
- render: (_, row) => /* @__PURE__ */ jsxs("div", { className: "taskon-token-assets__network-cell", children: [
1196
- /* @__PURE__ */ jsx(
1197
- "img",
1198
- {
1199
- src: row.chain_icon,
1200
- alt: row.chain_label,
1201
- className: "taskon-token-assets__chain-icon"
1202
- }
1203
- ),
1204
- /* @__PURE__ */ jsx("span", { className: "taskon-token-assets__chain", children: row.chain_label })
1205
- ] })
1206
- },
1207
- {
1208
- key: "withdrawable_avail_balance",
1209
- title: messages.columnWithdrawable ?? "Withdrawable",
1210
- width: 142,
1211
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-token-assets__balance", children: formatBalance$2(row.withdrawable_avail_balance) })
1212
- },
1213
- {
1214
- key: "action",
1215
- title: messages.columnAction ?? "Action",
1216
- align: "right",
1217
- render: (_, row) => {
1218
- const isDisabled = !row.can_withdraw;
1219
- return /* @__PURE__ */ jsx(
1220
- Button,
1221
- {
1222
- variant: "outline",
1223
- size: "small",
1224
- onClick: () => onWithdraw == null ? void 0 : onWithdraw(row),
1225
- disabled: isDisabled,
1226
- className: "taskon-token-assets__withdraw-btn",
1227
- children: messages.withdraw
1228
- }
1229
- );
1230
- }
1231
- }
1232
- ];
1233
- return /* @__PURE__ */ jsxs("div", { className: "taskon-token-assets", children: [
1234
- /* @__PURE__ */ jsx(
1235
- WithdrawPending,
1236
- {
1237
- count: pendingWithdrawals2 ?? 0,
1238
- text: messages.pendingWithdrawals.replace("{count}", "").trim()
1239
- }
1240
- ),
1241
- /* @__PURE__ */ jsx(
1242
- Table,
1243
- {
1244
- columns,
1245
- data,
1246
- rowConfig: {
1247
- getRowKey: (row) => `${row.token_id}-${row.chain}`,
1248
- isDisabled: (row) => !row.can_withdraw
1249
- },
1250
- striped: true,
1251
- loading: loading2 && data.length > 0,
1252
- loadingText: messages.loading,
1253
- empty: {
1254
- title: messages.emptyToken
1255
- }
1256
- }
1257
- )
1258
- ] });
1259
- }
1260
- function toWithdrawItem(token, decimals = 18) {
1261
- return {
1262
- tokenId: token.token_id,
1263
- tokenSymbol: token.token_symbol,
1264
- tokenIcon: token.token_icon,
1265
- tokenAddress: token.token_address,
1266
- tokenDecimals: decimals,
1267
- chain: token.chain,
1268
- chainLabel: token.chain_label,
1269
- amount: token.withdrawable_avail_balance,
1270
- // 使用实际精度计算 Wei 单位金额
1271
- amountInWei: toWei(token.withdrawable_avail_balance, decimals)
1272
- };
1273
- }
1274
- function toGasFreeWithdrawItem(token) {
1275
- return {
1276
- tokenId: token.token_id,
1277
- tokenSymbol: token.token_symbol,
1278
- tokenIcon: token.token_icon,
1279
- tokenAddress: token.token_address,
1280
- chain: token.chain,
1281
- chainLabel: token.chain_label,
1282
- amount: token.withdrawable_avail_balance
1283
- };
1284
- }
1285
- function formatDateTime(timestamp) {
1286
- const date = new Date(timestamp);
1287
- const year = date.getFullYear();
1288
- const month = String(date.getMonth() + 1).padStart(2, "0");
1289
- const day = String(date.getDate()).padStart(2, "0");
1290
- const hours = String(date.getHours()).padStart(2, "0");
1291
- const minutes = String(date.getMinutes()).padStart(2, "0");
1292
- const seconds = String(date.getSeconds()).padStart(2, "0");
1293
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
1294
- }
1295
- function formatTokenAmount(amount) {
1296
- return formatTokenAmount$1(amount, {
1297
- showCurrency: true,
1298
- useAbbreviation: true,
1299
- decimals: 2,
1300
- minValue: 0.01,
1301
- zeroText: "0"
1302
- });
1303
- }
1304
- function buildRewardCards(rewards, userInfo) {
1305
- var _a;
1306
- const cards = [];
1307
- const xpPointsId = (_a = userInfo == null ? void 0 : userInfo.points_list[0]) == null ? void 0 : _a.points_info.points_id;
1308
- cards.push({
1309
- type: USER_CENTER_REWARD_CARD_TYPES.Token,
1310
- value: formatTokenAmount(rewards.token_amount),
1311
- rawValue: rewards.token_amount,
1312
- visible: parseFloat(rewards.token_amount) > 0
1313
- });
1314
- if (userInfo && userInfo.points_list.length > 0) {
1315
- const xpPointsInfo = userInfo.points_list[0];
1316
- if (xpPointsInfo) {
1317
- const currentXp = xpPointsInfo.amount;
1318
- const nextLevelXp = userInfo.next_level_limit;
1319
- let percent = 0;
1320
- if (nextLevelXp > 0) {
1321
- if (currentXp >= nextLevelXp) {
1322
- percent = 100;
1323
- } else {
1324
- percent = Number((currentXp / nextLevelXp * 100).toFixed(2));
1325
- }
1326
- }
1327
- cards.push({
1328
- type: USER_CENTER_REWARD_CARD_TYPES.XpLevel,
1329
- value: `Lv.${userInfo.level}`,
1330
- rawValue: userInfo.level,
1331
- visible: true,
1332
- xpLevelData: {
1333
- level: userInfo.level,
1334
- currentXp,
1335
- nextLevelXp,
1336
- percent,
1337
- xpPointsId: xpPointsInfo.points_info.points_id,
1338
- xpPointsName: xpPointsInfo.points_info.points_name,
1339
- xpPointsIcon: xpPointsInfo.points_info.points_icon
1340
- }
1341
- });
1342
- }
1343
- }
1344
- cards.push({
1345
- type: USER_CENTER_REWARD_CARD_TYPES.Nft,
1346
- value: rewards.nft_count.toString(),
1347
- rawValue: rewards.nft_count,
1348
- visible: rewards.nft_count > 0
1349
- });
1350
- cards.push({
1351
- type: USER_CENTER_REWARD_CARD_TYPES.Whitelist,
1352
- value: rewards.whitelist_count.toString(),
1353
- rawValue: rewards.whitelist_count,
1354
- visible: rewards.whitelist_count > 0
1355
- });
1356
- cards.push({
1357
- type: USER_CENTER_REWARD_CARD_TYPES.DiscordRole,
1358
- value: rewards.discord_role_count.toString(),
1359
- rawValue: rewards.discord_role_count,
1360
- visible: rewards.discord_role_count > 0
1361
- });
1362
- if (rewards.points_count && rewards.points_count.length > 0) {
1363
- rewards.points_count.forEach((points) => {
1364
- if (xpPointsId !== void 0 && points.points_id === xpPointsId) {
1365
- return;
1366
- }
1367
- cards.push({
1368
- type: USER_CENTER_REWARD_CARD_TYPES.Points,
1369
- value: points.amount.toLocaleString(),
1370
- rawValue: points.amount,
1371
- visible: points.amount > 0,
1372
- pointsData: points
1373
- });
1374
- });
1375
- }
1376
- if (rewards.lucky_pass_info && parseFloat(rewards.lucky_pass_info.amount) > 0) {
1377
- cards.push({
1378
- type: USER_CENTER_REWARD_CARD_TYPES.Points,
1379
- value: parseFloat(rewards.lucky_pass_info.amount).toLocaleString(),
1380
- rawValue: rewards.lucky_pass_info.amount,
1381
- visible: true,
1382
- pointsData: {
1383
- points_id: 0,
1384
- points_name: "Lucky Pass",
1385
- points_icon: "",
1386
- amount: parseFloat(rewards.lucky_pass_info.amount)
1387
- }
1388
- });
1389
- }
1390
- return cards;
1391
- }
1392
- function formatNumber(val) {
1393
- if (Math.abs(val) >= 1e6) {
1394
- return `${(val / 1e6).toFixed(1)}M`;
1395
- }
1396
- if (Math.abs(val) >= 1e3) {
1397
- return `${(val / 1e3).toFixed(1)}K`;
1398
- }
1399
- return val.toLocaleString();
1400
- }
1401
- function PointsList({
1402
- pointsInfo,
1403
- data,
1404
- loading: loading2,
1405
- error: error2,
1406
- pagination,
1407
- messages,
1408
- className = ""
1409
- }) {
1410
- if (loading2 && data.length === 0) {
1411
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
1412
- }
1413
- if (error2 && data.length === 0) {
1414
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error2.message }) });
1415
- }
1416
- if (!loading2 && data.length === 0) {
1417
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyPoints });
1418
- }
1419
- const columns = [
1420
- {
1421
- key: "detail",
1422
- title: messages.columnDetail,
1423
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-points-list__name", children: row.name })
1424
- },
1425
- {
1426
- key: "time",
1427
- title: messages.columnTime,
1428
- width: 160,
1429
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-points-list__time", children: formatDateTime(row.receive_time) })
1430
- },
1431
- {
1432
- key: "amount",
1433
- title: `${messages.columnAmount} (${pointsInfo.points_name || messages.rewardPoints})`,
1434
- width: 160,
1435
- align: "right",
1436
- render: (_, row) => {
1437
- const isPositive = row.points.amount >= 0;
1438
- return /* @__PURE__ */ jsxs("div", { className: "taskon-points-list__amount-cell", children: [
1439
- row.points.points_icon && /* @__PURE__ */ jsx(
1440
- "img",
1441
- {
1442
- src: row.points.points_icon,
1443
- alt: "",
1444
- className: "taskon-points-list__amount-icon"
1445
- }
1446
- ),
1447
- /* @__PURE__ */ jsxs(
1448
- "span",
1449
- {
1450
- className: `taskon-points-list__amount-value ${isPositive ? "taskon-points-list__amount-value--positive" : "taskon-points-list__amount-value--negative"}`,
1451
- children: [
1452
- isPositive ? "+" : "",
1453
- formatNumber(row.points.amount)
1454
- ]
1455
- }
1456
- )
1457
- ] });
1458
- }
1459
- }
1460
- ];
1461
- return /* @__PURE__ */ jsxs("div", { className: `taskon-points-list ${className}`, children: [
1462
- /* @__PURE__ */ jsxs("div", { className: "taskon-points-list__header", children: [
1463
- pointsInfo.points_icon && /* @__PURE__ */ jsx(
1464
- "img",
1465
- {
1466
- src: pointsInfo.points_icon,
1467
- alt: pointsInfo.points_name,
1468
- className: "taskon-points-list__icon"
1469
- }
1470
- ),
1471
- /* @__PURE__ */ jsx("h3", { className: "taskon-points-list__title", children: pointsInfo.points_name }),
1472
- /* @__PURE__ */ jsxs("div", { className: "taskon-points-list__total", children: [
1473
- /* @__PURE__ */ jsx("span", { className: "taskon-points-list__total-value", children: formatNumber(pointsInfo.amount) }),
1474
- /* @__PURE__ */ jsx("span", { className: "taskon-points-list__total-label", children: messages.totalPoints })
1475
- ] })
1476
- ] }),
1477
- /* @__PURE__ */ jsx("div", { className: "taskon-points-list__table-wrap", children: /* @__PURE__ */ jsx(
1478
- Table,
1479
- {
1480
- columns,
1481
- data,
1482
- rowConfig: {
1483
- getRowKey: (row, index) => `${row.campaign_id ?? row.task_id ?? "item"}-${row.receive_time}-${index}`
1484
- },
1485
- loading: loading2 && data.length > 0,
1486
- loadingText: messages.loading,
1487
- empty: {
1488
- title: messages.emptyPoints
1489
- }
1490
- }
1491
- ) }),
1492
- pagination.totalPages > 1 && /* @__PURE__ */ jsx(
1493
- Pagination,
1494
- {
1495
- page: pagination.page,
1496
- totalPages: pagination.totalPages,
1497
- onPrevious: pagination.goToPrevious,
1498
- onNext: pagination.goToNext,
1499
- hasPrevious: pagination.hasPrevious,
1500
- hasNext: pagination.hasNext,
1501
- messages
1502
- }
1503
- )
1504
- ] });
1505
- }
1506
- function getDetailName(item, _messages) {
1507
- if (item.roulette_reward_type === RouletteRewardType.Spin) {
1508
- return "Telegram Spin";
1509
- }
1510
- if (item.roulette_reward_type === RouletteRewardType.Bonus) {
1511
- return "Telegram Spin Bonus";
1512
- }
1513
- return item.task_name || item.campaign_name || item.milestone_name || "";
1514
- }
1515
- function TokenHistoryTable({
1516
- data,
1517
- loading: loading2,
1518
- error: error2,
1519
- pagination,
1520
- messages
1521
- }) {
1522
- if (loading2 && data.length === 0) {
1523
- return /* @__PURE__ */ jsx(LoadingState, { message: messages.loading });
1524
- }
1525
- if (error2 && data.length === 0) {
1526
- return /* @__PURE__ */ jsx("div", { className: "taskon-user-center-error", children: /* @__PURE__ */ jsx("p", { className: "taskon-user-center-error__message", children: error2.message }) });
1527
- }
1528
- if (!loading2 && data.length === 0) {
1529
- return /* @__PURE__ */ jsx(EmptyState, { message: messages.emptyToken });
1530
- }
1531
- const renderAmount = (item) => {
1532
- var _a;
1533
- const tokenValue = item.reward_value;
1534
- const communityInfo = (_a = item.community_info) == null ? void 0 : _a[0];
1535
- const isDeposited = item.reward_distribute_by === "Taskon";
1536
- const amountText = tokenValue.is_usdt_equal_amount ? `USD In ${tokenValue.token_name}` : tokenValue.token_name;
1537
- return /* @__PURE__ */ jsxs("div", { className: "taskon-token-history__amount", children: [
1538
- /* @__PURE__ */ jsxs("div", { className: "taskon-token-history__token-info", children: [
1539
- /* @__PURE__ */ jsxs("span", { className: "taskon-token-history__token-value", children: [
1540
- "+",
1541
- tokenValue.amount
1542
- ] }),
1543
- /* @__PURE__ */ jsx("span", { className: "taskon-token-history__token-name", children: amountText }),
1544
- tokenValue.chain_label && /* @__PURE__ */ jsx(
1545
- "img",
1546
- {
1547
- className: "taskon-token-history__chain-icon",
1548
- src: tokenValue.token_logo,
1549
- alt: tokenValue.chain_label,
1550
- title: tokenValue.chain_label
1551
- }
1552
- )
1553
- ] }),
1554
- /* @__PURE__ */ jsx("div", { className: "taskon-token-history__distribute", children: isDeposited ? /* @__PURE__ */ jsx("span", { className: "taskon-token-history__deposited", children: messages.deposited }) : /* @__PURE__ */ jsxs("div", { className: "taskon-token-history__distributed-by", children: [
1555
- /* @__PURE__ */ jsx("span", { className: "taskon-token-history__distributed-label", children: messages.distributedBy }),
1556
- (communityInfo == null ? void 0 : communityInfo.community_avatar) && /* @__PURE__ */ jsx(
1557
- "img",
1558
- {
1559
- className: "taskon-token-history__community-avatar",
1560
- src: communityInfo.community_avatar,
1561
- alt: communityInfo.community_name,
1562
- title: communityInfo.community_name
1563
- }
1564
- )
1565
- ] }) })
1566
- ] });
1567
- };
1568
- const columns = [
1569
- {
1570
- key: "detail",
1571
- title: messages.columnDetail,
1572
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__campaign-name", children: getDetailName(row) })
1573
- },
1574
- {
1575
- key: "time",
1576
- title: messages.columnTime,
1577
- width: 160,
1578
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-reward-table__time", children: formatDateTime(row.reward_time) })
1579
- },
1580
- {
1581
- key: "amount",
1582
- title: messages.columnAmount,
1583
- width: 200,
1584
- align: "right",
1585
- render: (_, row) => renderAmount(row)
1586
- }
1587
- ];
1588
- return /* @__PURE__ */ jsxs("div", { className: "taskon-reward-table", children: [
1589
- /* @__PURE__ */ jsx(
1590
- Table,
1591
- {
1592
- columns,
1593
- data,
1594
- rowConfig: {
1595
- getRowKey: (row, index) => `${row.campaign_id}-${row.reward_time}-${index}`
1596
- },
1597
- loading: loading2 && data.length > 0,
1598
- loadingText: messages.loading,
1599
- empty: {
1600
- title: messages.emptyToken
1601
- }
1602
- }
1603
- ),
1604
- pagination.totalPages > 1 && /* @__PURE__ */ jsx(
1605
- Pagination,
1606
- {
1607
- page: pagination.page,
1608
- totalPages: pagination.totalPages,
1609
- onPrevious: pagination.goToPrevious,
1610
- onNext: pagination.goToNext,
1611
- hasPrevious: pagination.hasPrevious,
1612
- hasNext: pagination.hasNext,
1613
- messages
1614
- }
1615
- )
1616
- ] });
1617
- }
1618
- function useRewardDetails(options) {
1619
- const {
1620
- rewardType,
1621
- pageSize = USER_CENTER_PAGE_SIZE,
1622
- mode = "pagination",
1623
- autoLoad = true
1624
- } = options;
1625
- const { client } = useTaskOnContext();
1626
- const [data, setData] = useState([]);
1627
- const [total, setTotal] = useState(0);
1628
- const [loading2, setLoading] = useState(false);
1629
- const [error2, setError] = useState(null);
1630
- const api = useMemo(() => {
1631
- if (!client) return null;
1632
- return createUserCenterApi(client);
1633
- }, [client]);
1634
- const pagination = usePagination({
1635
- total,
1636
- pageSize,
1637
- initialPage: 1,
1638
- mode
1639
- });
1640
- const fetchData = useCallback(
1641
- async (pageNo, append = false) => {
1642
- if (!api) {
1643
- setError(new Error("TaskOn client not initialized"));
1644
- return;
1645
- }
1646
- setLoading(true);
1647
- setError(null);
1648
- try {
1649
- const response = await api.listMyCommunityRewardDetails({
1650
- reward_type: rewardType,
1651
- page: {
1652
- page_no: pageNo - 1,
1653
- // API 使用 0-based 索引
1654
- size: pageSize
1655
- }
1656
- });
1657
- if (append) {
1658
- setData((prev) => [...prev, ...response.data]);
1659
- } else {
1660
- setData(response.data);
1661
- }
1662
- setTotal(response.total);
1663
- } catch (err) {
1664
- setError(
1665
- err instanceof Error ? err : new Error("Failed to fetch reward details")
1666
- );
1667
- } finally {
1668
- setLoading(false);
1669
- }
1670
- },
1671
- [api, rewardType, pageSize]
1672
- );
1673
- const refresh = useCallback(async () => {
1674
- pagination.goToPage(1);
1675
- setData([]);
1676
- await fetchData(1, false);
1677
- }, [fetchData, pagination]);
1678
- useEffect(() => {
1679
- if (autoLoad) {
1680
- fetchData(1, false);
1681
- }
1682
- }, [autoLoad, rewardType, fetchData]);
1683
- useEffect(() => {
1684
- if (mode === "pagination" && pagination.page > 1) {
1685
- fetchData(pagination.page, false);
1686
- }
1687
- }, [mode, pagination.page, fetchData]);
1688
- return {
1689
- data,
1690
- loading: loading2,
1691
- error: error2,
1692
- total,
1693
- pagination,
1694
- refresh
1695
- };
1696
- }
1697
- function useTokenAssets(options = {}) {
1698
- const {
1699
- pageSize = USER_CENTER_PAGE_SIZE,
1700
- mode = "pagination",
1701
- autoLoad = true,
1702
- getAll = false,
1703
- tokenId = 0
1704
- } = options;
1705
- const { client } = useTaskOnContext();
1706
- const [data, setData] = useState([]);
1707
- const [total, setTotal] = useState(0);
1708
- const [pendingWithdrawals2, setPendingWithdrawals] = useState(0);
1709
- const [loading2, setLoading] = useState(false);
1710
- const [error2, setError] = useState(null);
1711
- const api = useMemo(() => {
1712
- if (!client) return null;
1713
- return createUserCenterApi(client);
1714
- }, [client]);
1715
- const pagination = usePagination({
1716
- total,
1717
- pageSize,
1718
- initialPage: 1,
1719
- mode
1720
- });
1721
- const fetchData = useCallback(
1722
- async (pageNo, append = false) => {
1723
- if (!api) {
1724
- setError(new Error("TaskOn client not initialized"));
1725
- return;
1726
- }
1727
- setLoading(true);
1728
- setError(null);
1729
- try {
1730
- const response = await api.getUserTokenBalanceList({
1731
- page: {
1732
- page_no: pageNo - 1,
1733
- // API 使用 0-based 索引
1734
- size: pageSize
1735
- },
1736
- options: {
1737
- get_all: getAll,
1738
- token_id: tokenId
1739
- }
1740
- });
1741
- if (append) {
1742
- setData((prev) => [...prev, ...response.data]);
1743
- } else {
1744
- setData(response.data);
1745
- }
1746
- setTotal(response.total);
1747
- setPendingWithdrawals(response.pending_withdrawals ?? 0);
1748
- } catch (err) {
1749
- setError(
1750
- err instanceof Error ? err : new Error("Failed to fetch token assets")
1751
- );
1752
- } finally {
1753
- setLoading(false);
1754
- }
1755
- },
1756
- [api, pageSize, getAll, tokenId]
1757
- );
1758
- const refresh = useCallback(async () => {
1759
- pagination.goToPage(1);
1760
- setData([]);
1761
- await fetchData(1, false);
1762
- }, [fetchData, pagination]);
1763
- useEffect(() => {
1764
- if (autoLoad) {
1765
- fetchData(1, false);
1766
- }
1767
- }, [autoLoad, fetchData]);
1768
- useEffect(() => {
1769
- if (mode === "pagination" && pagination.page > 1) {
1770
- fetchData(pagination.page, false);
1771
- }
1772
- }, [mode, pagination.page, fetchData]);
1773
- return {
1774
- data,
1775
- loading: loading2,
1776
- error: error2,
1777
- total,
1778
- pendingWithdrawals: pendingWithdrawals2,
1779
- pagination,
1780
- refresh
1781
- };
1782
- }
1783
- const TOKEN_WITHDRAW_ABI = [
1784
- {
1785
- inputs: [
1786
- {
1787
- internalType: "uint256",
1788
- name: "userId",
1789
- type: "uint256"
1790
- },
1791
- {
1792
- components: [
1793
- {
1794
- internalType: "address",
1795
- name: "token",
1796
- type: "address"
1797
- },
1798
- {
1799
- internalType: "uint256",
1800
- name: "amount",
1801
- type: "uint256"
1802
- }
1803
- ],
1804
- internalType: "struct TaskonFund.WithdrawTokenAmount[]",
1805
- name: "tokenAmounts",
1806
- type: "tuple[]"
1807
- },
1808
- {
1809
- internalType: "address",
1810
- name: "receiver",
1811
- type: "address"
1812
- },
1813
- {
1814
- internalType: "uint256",
1815
- name: "nonce",
1816
- type: "uint256"
1817
- },
1818
- {
1819
- internalType: "uint256",
1820
- name: "expiredHeight",
1821
- type: "uint256"
1822
- },
1823
- {
1824
- internalType: "bytes[]",
1825
- name: "sigs",
1826
- type: "bytes[]"
1827
- }
1828
- ],
1829
- name: "withdraw",
1830
- outputs: [],
1831
- stateMutability: "nonpayable",
1832
- type: "function"
1833
- }
1834
- ];
1835
- const WITHDRAW_METHOD = "withdraw";
1836
- var TxErrorType = /* @__PURE__ */ ((TxErrorType2) => {
1837
- TxErrorType2["Canceled"] = "canceled";
1838
- TxErrorType2["ConnectFailed"] = "connect_failed";
1839
- TxErrorType2["AccountMismatch"] = "account_mismatch";
1840
- TxErrorType2["ChainMismatch"] = "chain_mismatch";
1841
- TxErrorType2["BalanceNotEnough"] = "balance_not_enough";
1842
- TxErrorType2["TransactionFailed"] = "transaction_failed";
1843
- TxErrorType2["SignFailed"] = "sign_failed";
1844
- return TxErrorType2;
1845
- })(TxErrorType || {});
1846
- class TransactionError extends Error {
1847
- constructor(type, message, originalError) {
1848
- super(message ?? type);
1849
- /** 错误类型 */
1850
- __publicField(this, "type");
1851
- /** 原始错误 */
1852
- __publicField(this, "originalError");
1853
- this.name = "TransactionError";
1854
- this.type = type;
1855
- this.originalError = originalError;
1856
- }
1857
- /**
1858
- * 检查是否为用户取消
1859
- */
1860
- isCanceled() {
1861
- return this.type === "canceled";
1862
- }
1863
- /**
1864
- * 检查是否为账户不匹配
1865
- */
1866
- isAccountMismatch() {
1867
- return this.type === "account_mismatch";
1868
- }
1869
- /**
1870
- * 检查是否为网络不匹配
1871
- */
1872
- isChainMismatch() {
1873
- return this.type === "chain_mismatch";
1874
- }
1875
- }
1876
- function parseTxError(error2) {
1877
- if (error2 instanceof TransactionError) {
1878
- return error2.type;
1879
- }
1880
- if (error2 instanceof Error) {
1881
- const message = error2.message.toLowerCase();
1882
- if (message.includes("user rejected") || message.includes("user denied") || message.includes("rejected") || message.includes("cancelled") || message.includes("canceled")) {
1883
- return "canceled";
1884
- }
1885
- if (message.includes("insufficient funds") || message.includes("insufficient balance") || message.includes("not enough")) {
1886
- return "balance_not_enough";
1887
- }
1888
- if (message.includes("connect") || message.includes("no provider") || message.includes("not connected")) {
1889
- return "connect_failed";
1890
- }
1891
- }
1892
- const err = error2;
1893
- if (err.code === 4001) {
1894
- return "canceled";
1895
- }
1896
- if (err.code === 4902) {
1897
- return "chain_mismatch";
1898
- }
1899
- return "transaction_failed";
1900
- }
1901
- function isSameAddress(addr1, addr2) {
1902
- if (!addr1 || !addr2) return false;
1903
- return addr1.toLowerCase() === addr2.toLowerCase();
1904
- }
1905
- function useTokenWithdraw(options = {}) {
1906
- const { userAddress, resend: resend2, onSuccess, onCancel, onError, onConnect } = options;
1907
- const { client, userId } = useTaskOnContext();
1908
- const { evmAdapter, connectEvm, evmAddress, evmChainId } = useWallet();
1909
- const { chainMap, isLoaded: chainMapLoaded } = useChainMap();
1910
- const [status, setStatus] = useState("init");
1911
- const [tokens, setTokens] = useState([]);
1912
- const [error2, setError] = useState(null);
1913
- const [errorType, setErrorType] = useState(null);
1914
- const [txHash, setTxHash] = useState(null);
1915
- const [isGasInsufficient, setIsGasInsufficient] = useState(false);
1916
- const [connectedAddress, setConnectedAddress] = useState(null);
1917
- const isResend = !!((resend2 == null ? void 0 : resend2.nonce) && (resend2 == null ? void 0 : resend2.receiverAddress));
1918
- const currentChainRef = useRef(null);
1919
- const api = useMemo(() => {
1920
- if (!client) return null;
1921
- return createUserCenterApi(client);
1922
- }, [client]);
1923
- const getChainInfo = useCallback(
1924
- (chainName) => {
1925
- return chainMap[chainName.toLowerCase()];
1926
- },
1927
- [chainMap]
1928
- );
1929
- const checkAccountAndNetwork = useCallback(
1930
- async (targetChain, targetAddress) => {
1931
- var _a, _b;
1932
- let address = evmAddress;
1933
- if (!address) {
1934
- address = await connectEvm();
1935
- if (!address) {
1936
- throw new TransactionError(
1937
- TxErrorType.ConnectFailed,
1938
- "Failed to connect wallet"
1939
- );
1940
- }
1941
- }
1942
- setConnectedAddress(address);
1943
- onConnect == null ? void 0 : onConnect(address);
1944
- if (targetAddress && !isSameAddress(address, targetAddress)) {
1945
- throw new TransactionError(
1946
- TxErrorType.AccountMismatch,
1947
- `Connected address ${address} does not match target address ${targetAddress}`
1948
- );
1949
- }
1950
- if (targetChain.chain_type !== ChainType.evm) {
1951
- return address;
1952
- }
1953
- const currentChainId = evmChainId ?? ((_a = evmAdapter == null ? void 0 : evmAdapter.getChainId) == null ? void 0 : _a.call(evmAdapter));
1954
- if (currentChainId !== targetChain.id) {
1955
- try {
1956
- await ((_b = evmAdapter == null ? void 0 : evmAdapter.switchNetwork) == null ? void 0 : _b.call(evmAdapter, targetChain.id));
1957
- } catch (err) {
1958
- throw new TransactionError(
1959
- TxErrorType.ChainMismatch,
1960
- `Failed to switch to ${targetChain.label}`,
1961
- err
1962
- );
1963
- }
1964
- }
1965
- return address;
1966
- },
1967
- [evmAddress, evmChainId, evmAdapter, connectEvm, onConnect]
1968
- );
1969
- const initWithdraw = useCallback(
1970
- (token) => {
1971
- if (!token.can_withdraw) {
1972
- setError(new Error("This token cannot be withdrawn"));
1973
- return;
1974
- }
1975
- const chainInfo = getChainInfo(token.chain);
1976
- if (chainInfo) {
1977
- currentChainRef.current = chainInfo;
1978
- }
1979
- setTokens([toWithdrawItem(token)]);
1980
- setError(null);
1981
- setErrorType(null);
1982
- setTxHash(null);
1983
- setIsGasInsufficient(false);
1984
- setConnectedAddress(null);
1985
- setStatus("init");
1986
- },
1987
- [getChainInfo]
1988
- );
1989
- const initBatchWithdraw = useCallback(
1990
- (tokenList) => {
1991
- const withdrawableTokens = tokenList.filter((t) => t.can_withdraw);
1992
- if (withdrawableTokens.length === 0) {
1993
- setError(new Error("No tokens available for withdrawal"));
1994
- return;
1995
- }
1996
- const firstToken = withdrawableTokens[0];
1997
- if (firstToken) {
1998
- const chainInfo = getChainInfo(firstToken.chain);
1999
- if (chainInfo) {
2000
- currentChainRef.current = chainInfo;
2001
- }
2002
- }
2003
- setTokens(withdrawableTokens.map(toWithdrawItem));
2004
- setError(null);
2005
- setErrorType(null);
2006
- setTxHash(null);
2007
- setIsGasInsufficient(false);
2008
- setConnectedAddress(null);
2009
- setStatus("init");
2010
- },
2011
- [getChainInfo]
2012
- );
2013
- const initWithdrawTokens = useCallback(
2014
- (items) => {
2015
- if (items.length === 0) {
2016
- setError(new Error("No tokens to withdraw"));
2017
- return;
2018
- }
2019
- const firstItem = items[0];
2020
- if (firstItem) {
2021
- const chainInfo = getChainInfo(firstItem.chain);
2022
- if (chainInfo) {
2023
- currentChainRef.current = chainInfo;
2024
- }
2025
- }
2026
- setTokens(items);
2027
- setError(null);
2028
- setErrorType(null);
2029
- setTxHash(null);
2030
- setIsGasInsufficient(false);
2031
- setConnectedAddress(null);
2032
- setStatus("init");
2033
- },
2034
- [getChainInfo]
2035
- );
2036
- const checkAndConnect = useCallback(async () => {
2037
- var _a;
2038
- const chainInfo = currentChainRef.current;
2039
- if (!chainInfo) {
2040
- const chainName = (_a = tokens[0]) == null ? void 0 : _a.chain;
2041
- if (!chainName) {
2042
- setError(new Error("No tokens available"));
2043
- return false;
2044
- }
2045
- const info = getChainInfo(chainName);
2046
- if (!info) {
2047
- setError(new Error(`Chain configuration not found for ${chainName}`));
2048
- return false;
2049
- }
2050
- currentChainRef.current = info;
2051
- }
2052
- const chain = currentChainRef.current;
2053
- try {
2054
- const address = await checkAccountAndNetwork(chain, userAddress);
2055
- if (evmAdapter == null ? void 0 : evmAdapter.getBalance) {
2056
- try {
2057
- const balance = await evmAdapter.getBalance();
2058
- const balanceNum = parseFloat(balance);
2059
- if (balanceNum < 1e-3) {
2060
- setIsGasInsufficient(true);
2061
- setStatus("noEnough");
2062
- return false;
2063
- }
2064
- } catch {
2065
- console.warn("Failed to check gas balance");
2066
- }
2067
- }
2068
- setIsGasInsufficient(false);
2069
- setStatus("confirm");
2070
- return true;
2071
- } catch (err) {
2072
- const errType = parseTxError(err);
2073
- setError(err instanceof Error ? err : new Error("Connection failed"));
2074
- setErrorType(errType);
2075
- if (errType === TxErrorType.Canceled) {
2076
- setStatus("cancel");
2077
- } else {
2078
- setStatus("init");
2079
- }
2080
- onError == null ? void 0 : onError(err instanceof Error ? err : new Error("Connection failed"));
2081
- return false;
2082
- }
2083
- }, [
2084
- tokens,
2085
- getChainInfo,
2086
- checkAccountAndNetwork,
2087
- userAddress,
2088
- evmAdapter,
2089
- onError
2090
- ]);
2091
- const confirmWithdraw2 = useCallback(async () => {
2092
- if (!api) {
2093
- setError(new Error("TaskOn client not initialized"));
2094
- return;
2095
- }
2096
- if (!connectedAddress) {
2097
- setError(new Error("Wallet not connected"));
2098
- return;
2099
- }
2100
- if (!userId) {
2101
- setError(new Error("User not logged in"));
2102
- return;
2103
- }
2104
- if (tokens.length === 0) {
2105
- setError(new Error("No tokens to withdraw"));
2106
- return;
2107
- }
2108
- const chainInfo = currentChainRef.current;
2109
- if (!chainInfo) {
2110
- setError(new Error("Chain configuration not found"));
2111
- return;
2112
- }
2113
- if (chainInfo.chain_type !== ChainType.evm) {
2114
- setError(
2115
- new Error(`Withdrawal not supported for ${chainInfo.chain_type} chains yet`)
2116
- );
2117
- return;
2118
- }
2119
- if (!chainInfo.taskonfund_token_contract) {
2120
- setError(new Error("Withdraw contract address not configured"));
2121
- return;
2122
- }
2123
- setStatus("loading");
2124
- setError(null);
2125
- setErrorType(null);
2126
- try {
2127
- const tokenParams = tokens.map((t) => ({
2128
- token_id: t.tokenId,
2129
- amount: t.amount
2130
- }));
2131
- const receiverAddress = isResend ? resend2.receiverAddress : connectedAddress;
2132
- const withdrawResult = await api.tokenWithdraw({
2133
- chain: chainInfo.name,
2134
- receiver_address: receiverAddress,
2135
- tokens: tokenParams,
2136
- // 重发模式:传入原 nonce
2137
- ...isResend && { nonce: resend2.nonce }
2138
- });
2139
- const tokenAmounts = tokens.map((t) => ({
2140
- token: t.tokenAddress,
2141
- // 使用实际精度计算的 Wei 金额
2142
- amount: t.amountInWei || toWei(t.amount, t.tokenDecimals)
2143
- }));
2144
- if (!(evmAdapter == null ? void 0 : evmAdapter.invokeContract)) {
2145
- throw new Error("Wallet adapter does not support contract invocation");
2146
- }
2147
- const hash = await evmAdapter.invokeContract({
2148
- contract: chainInfo.taskonfund_token_contract,
2149
- // 使用类型断言将 readonly 数组转换为 mutable
2150
- abi: TOKEN_WITHDRAW_ABI,
2151
- method: WITHDRAW_METHOD,
2152
- params: [
2153
- userId,
2154
- tokenAmounts,
2155
- withdrawResult.receiver_address,
2156
- withdrawResult.nonce,
2157
- withdrawResult.expired_height,
2158
- withdrawResult.signatures
2159
- ],
2160
- chainId: chainInfo.id
2161
- });
2162
- setTxHash(hash);
2163
- setStatus("success");
2164
- onSuccess == null ? void 0 : onSuccess(hash);
2165
- } catch (err) {
2166
- const errType = parseTxError(err);
2167
- const error22 = err instanceof Error ? err : new Error("Withdrawal failed");
2168
- setError(error22);
2169
- setErrorType(errType);
2170
- if (errType === TxErrorType.Canceled) {
2171
- setStatus("cancel");
2172
- onCancel == null ? void 0 : onCancel();
2173
- } else {
2174
- setStatus("init");
2175
- onError == null ? void 0 : onError(error22);
2176
- }
2177
- }
2178
- }, [
2179
- api,
2180
- connectedAddress,
2181
- userId,
2182
- tokens,
2183
- isResend,
2184
- resend2,
2185
- evmAdapter,
2186
- onSuccess,
2187
- onCancel,
2188
- onError
2189
- ]);
2190
- const cancelWithdraw = useCallback(() => {
2191
- setStatus("cancel");
2192
- onCancel == null ? void 0 : onCancel();
2193
- setTimeout(() => {
2194
- setStatus("init");
2195
- setTokens([]);
2196
- setError(null);
2197
- setErrorType(null);
2198
- setConnectedAddress(null);
2199
- currentChainRef.current = null;
2200
- }, 100);
2201
- }, [onCancel]);
2202
- const reset = useCallback(() => {
2203
- setStatus("init");
2204
- setTokens([]);
2205
- setError(null);
2206
- setErrorType(null);
2207
- setTxHash(null);
2208
- setIsGasInsufficient(false);
2209
- setConnectedAddress(null);
2210
- currentChainRef.current = null;
2211
- }, []);
2212
- return {
2213
- status,
2214
- tokens,
2215
- error: error2,
2216
- errorType,
2217
- txHash,
2218
- isGasInsufficient,
2219
- isResend,
2220
- chainMapLoaded,
2221
- connectedAddress,
2222
- initWithdraw,
2223
- initBatchWithdraw,
2224
- initWithdrawTokens,
2225
- checkAndConnect,
2226
- confirmWithdraw: confirmWithdraw2,
2227
- cancelWithdraw,
2228
- reset
2229
- };
2230
- }
2231
- function usePointsHistory(options) {
2232
- const {
2233
- pointsId,
2234
- pageSize = USER_CENTER_PAGE_SIZE,
2235
- autoLoad = true
2236
- } = options;
2237
- const { client } = useTaskOnContext();
2238
- const [data, setData] = useState([]);
2239
- const [loading2, setLoading] = useState(false);
2240
- const [error2, setError] = useState(null);
2241
- const [total, setTotal] = useState(0);
2242
- const abortControllerRef = useRef(null);
2243
- const pagination = usePagination({
2244
- total,
2245
- pageSize,
2246
- initialPage: 0
2247
- });
2248
- const fetchData = useCallback(
2249
- async (pageNo) => {
2250
- if (!client || !pointsId) {
2251
- return;
2252
- }
2253
- if (abortControllerRef.current) {
2254
- abortControllerRef.current.abort();
2255
- }
2256
- abortControllerRef.current = new AbortController();
2257
- setLoading(true);
2258
- setError(null);
2259
- try {
2260
- const api = createUserCenterApi(client);
2261
- const response = await api.getUserPointsHistory({
2262
- points_id: pointsId,
2263
- page: {
2264
- page_no: pageNo,
2265
- size: pageSize
2266
- }
2267
- });
2268
- setData(response.data);
2269
- setTotal(response.total);
2270
- } catch (err) {
2271
- if (err instanceof Error && err.name === "AbortError") {
2272
- return;
2273
- }
2274
- setError(err instanceof Error ? err : new Error("Unknown error"));
2275
- } finally {
2276
- setLoading(false);
2277
- }
2278
- },
2279
- [client, pointsId, pageSize]
2280
- );
2281
- const refresh = useCallback(() => {
2282
- fetchData(pagination.page);
2283
- }, [fetchData, pagination.page]);
2284
- useEffect(() => {
2285
- if (autoLoad) {
2286
- fetchData(pagination.page);
2287
- }
2288
- }, [autoLoad, fetchData, pagination.page]);
2289
- useEffect(() => {
2290
- return () => {
2291
- if (abortControllerRef.current) {
2292
- abortControllerRef.current.abort();
2293
- }
2294
- };
2295
- }, []);
2296
- return {
2297
- data,
2298
- loading: loading2,
2299
- error: error2,
2300
- total,
2301
- pagination,
2302
- refresh
2303
- };
2304
- }
2305
- function useWithdrawForm(options) {
2306
- const { tokenAssets, initialTokenId, initialChain, getDecimals } = options;
2307
- const resolveDecimals = useCallback(
2308
- (tokenAddress) => {
2309
- if (getDecimals) {
2310
- return getDecimals(tokenAddress);
2311
- }
2312
- return 18;
2313
- },
2314
- [getDecimals]
2315
- );
2316
- const [selectedTokenId, setSelectedTokenId] = useState(initialTokenId || 0);
2317
- const [withdrawAmount, setWithdrawAmount] = useState("");
2318
- const [batchEnabled, setBatchEnabled] = useState(true);
2319
- const [batchTokens, setBatchTokens] = useState([]);
2320
- const selectedToken = useMemo(() => {
2321
- return tokenAssets.find((t) => t.token_id === selectedTokenId) || null;
2322
- }, [tokenAssets, selectedTokenId]);
2323
- const batchableTokenCount = useMemo(() => {
2324
- if (!selectedToken) return 0;
2325
- return tokenAssets.filter(
2326
- (t) => t.chain.toLowerCase() === selectedToken.chain.toLowerCase() && t.token_id !== selectedTokenId && t.can_withdraw && parseFloat(t.withdrawable_avail_balance) > 0
2327
- ).length;
2328
- }, [tokenAssets, selectedToken, selectedTokenId]);
2329
- const validation = useMemo(() => {
2330
- const errors = {};
2331
- if (!selectedToken) {
2332
- errors.token = "Please select a token";
2333
- }
2334
- if (!withdrawAmount || withdrawAmount === "") {
2335
- errors.amount = "Please enter an amount";
2336
- } else {
2337
- const amount = parseFloat(withdrawAmount);
2338
- if (isNaN(amount) || amount <= 0) {
2339
- errors.amount = "Please enter a valid amount";
2340
- } else if (selectedToken && amount > parseFloat(selectedToken.withdrawable_avail_balance)) {
2341
- errors.amount = "Amount exceeds available balance";
2342
- }
2343
- }
2344
- return {
2345
- isValid: Object.keys(errors).length === 0,
2346
- errors
2347
- };
2348
- }, [selectedToken, withdrawAmount]);
2349
- useEffect(() => {
2350
- if (tokenAssets.length === 0) return;
2351
- if (initialTokenId) {
2352
- const token = tokenAssets.find((t) => t.token_id === initialTokenId);
2353
- if (token) {
2354
- setSelectedTokenId(initialTokenId);
2355
- setWithdrawAmount(token.withdrawable_avail_balance);
2356
- return;
2357
- }
2358
- }
2359
- if (initialChain) {
2360
- const token = tokenAssets.find(
2361
- (t) => t.chain.toLowerCase() === initialChain.toLowerCase() && t.can_withdraw && parseFloat(t.withdrawable_avail_balance) > 0
2362
- );
2363
- if (token) {
2364
- setSelectedTokenId(token.token_id);
2365
- setWithdrawAmount(token.withdrawable_avail_balance);
2366
- return;
2367
- }
2368
- }
2369
- const firstAvailable = tokenAssets.find(
2370
- (t) => t.can_withdraw && parseFloat(t.withdrawable_avail_balance) > 0
2371
- );
2372
- if (firstAvailable) {
2373
- setSelectedTokenId(firstAvailable.token_id);
2374
- setWithdrawAmount(firstAvailable.withdrawable_avail_balance);
2375
- }
2376
- }, [tokenAssets, initialTokenId, initialChain]);
2377
- useEffect(() => {
2378
- if (selectedToken) {
2379
- setWithdrawAmount(selectedToken.withdrawable_avail_balance);
2380
- setBatchTokens([]);
2381
- }
2382
- }, [selectedTokenId]);
2383
- const buildWithdrawTokens = useCallback(() => {
2384
- if (!selectedToken) return [];
2385
- const decimals = resolveDecimals(selectedToken.token_address);
2386
- const mainToken = {
2387
- tokenId: selectedToken.token_id,
2388
- tokenSymbol: selectedToken.token_symbol,
2389
- tokenIcon: selectedToken.token_icon,
2390
- tokenAddress: selectedToken.token_address,
2391
- tokenDecimals: decimals,
2392
- chain: selectedToken.chain,
2393
- chainLabel: selectedToken.chain_label,
2394
- amount: withdrawAmount,
2395
- amountInWei: toWei(withdrawAmount || "0", decimals)
2396
- };
2397
- if (batchEnabled && batchTokens.length > 0) {
2398
- return [mainToken, ...batchTokens];
2399
- }
2400
- return [mainToken];
2401
- }, [selectedToken, withdrawAmount, batchEnabled, batchTokens, resolveDecimals]);
2402
- const resetForm = useCallback(() => {
2403
- setSelectedTokenId(0);
2404
- setWithdrawAmount("");
2405
- setBatchEnabled(true);
2406
- setBatchTokens([]);
2407
- }, []);
2408
- return {
2409
- // 状态
2410
- selectedTokenId,
2411
- selectedToken,
2412
- withdrawAmount,
2413
- batchEnabled,
2414
- batchTokens,
2415
- batchableTokenCount,
2416
- validation,
2417
- // 方法
2418
- setSelectedTokenId,
2419
- setWithdrawAmount,
2420
- setBatchEnabled,
2421
- setBatchTokens,
2422
- buildWithdrawTokens,
2423
- resetForm
2424
- };
2425
- }
2426
- function useTokenDecimals(options) {
2427
- const { tokenAssets, autoLoad = true } = options;
2428
- const { client } = useTaskOnContext();
2429
- const [decimalsMap, setDecimalsMap] = useState(/* @__PURE__ */ new Map());
2430
- const [loading2, setLoading] = useState(false);
2431
- const [error2, setError] = useState(null);
2432
- const api = useMemo(() => {
2433
- if (!client) return null;
2434
- return createUserCenterApi(client);
2435
- }, [client]);
2436
- const fetchTokenDecimals = useCallback(
2437
- async (chain, address) => {
2438
- if (!api) {
2439
- console.warn("TaskOn client not initialized, using default decimals 18");
2440
- return 18;
2441
- }
2442
- try {
2443
- const metadata = await api.getTokenMetadata({
2444
- chain,
2445
- address
2446
- });
2447
- return metadata.decimals;
2448
- } catch (err) {
2449
- console.error(`Failed to fetch decimals for ${address}:`, err);
2450
- return 18;
2451
- }
2452
- },
2453
- [api]
2454
- );
2455
- const loadAllDecimals = useCallback(async () => {
2456
- if (!api || tokenAssets.length === 0) return;
2457
- setLoading(true);
2458
- setError(null);
2459
- try {
2460
- const tokensToFetch = tokenAssets.filter(
2461
- (token) => !decimalsMap.has(token.token_address.toLowerCase())
2462
- );
2463
- if (tokensToFetch.length === 0) {
2464
- setLoading(false);
2465
- return;
2466
- }
2467
- const results = await Promise.all(
2468
- tokensToFetch.map(async (token) => {
2469
- const decimals = await fetchTokenDecimals(token.chain, token.token_address);
2470
- return {
2471
- address: token.token_address.toLowerCase(),
2472
- decimals
2473
- };
2474
- })
2475
- );
2476
- setDecimalsMap((prev) => {
2477
- const newMap = new Map(prev);
2478
- results.forEach(({ address, decimals }) => {
2479
- newMap.set(address, decimals);
2480
- });
2481
- return newMap;
2482
- });
2483
- } catch (err) {
2484
- setError(err instanceof Error ? err : new Error("Failed to load token decimals"));
2485
- } finally {
2486
- setLoading(false);
2487
- }
2488
- }, [api, tokenAssets, decimalsMap, fetchTokenDecimals]);
2489
- useEffect(() => {
2490
- if (autoLoad && tokenAssets.length > 0) {
2491
- loadAllDecimals();
2492
- }
2493
- }, [autoLoad, tokenAssets, loadAllDecimals]);
2494
- const getDecimals = useCallback(
2495
- (tokenAddress) => {
2496
- return decimalsMap.get(tokenAddress.toLowerCase()) ?? 18;
2497
- },
2498
- [decimalsMap]
2499
- );
2500
- const refreshDecimals = useCallback(
2501
- async (chain, tokenAddress) => {
2502
- const decimals = await fetchTokenDecimals(chain, tokenAddress);
2503
- setDecimalsMap((prev) => {
2504
- const newMap = new Map(prev);
2505
- newMap.set(tokenAddress.toLowerCase(), decimals);
2506
- return newMap;
2507
- });
2508
- return decimals;
2509
- },
2510
- [fetchTokenDecimals]
2511
- );
2512
- return {
2513
- loading: loading2,
2514
- error: error2,
2515
- getDecimals,
2516
- refreshDecimals,
2517
- decimalsMap
2518
- };
2519
- }
2520
- function TokenRewardContent({
2521
- tokenAssets,
2522
- tokenAssetsLoading,
2523
- tokenAssetsError,
2524
- pendingWithdrawals: pendingWithdrawals2,
2525
- tokenHistory: tokenHistory2,
2526
- tokenHistoryLoading,
2527
- tokenHistoryError,
2528
- tokenHistoryPagination,
2529
- messages,
2530
- onWithdraw,
2531
- onBatchWithdraw
2532
- }) {
2533
- return /* @__PURE__ */ jsxs("div", { className: "taskon-my-rewards", children: [
2534
- /* @__PURE__ */ jsx("div", { className: "taskon-my-rewards__section", children: /* @__PURE__ */ jsx(
2535
- TokenAssetList,
2536
- {
2537
- data: tokenAssets,
2538
- loading: tokenAssetsLoading,
2539
- error: tokenAssetsError,
2540
- messages,
2541
- pendingWithdrawals: pendingWithdrawals2,
2542
- onWithdraw,
2543
- onBatchWithdraw
2544
- }
2545
- ) }),
2546
- /* @__PURE__ */ jsxs("div", { className: "taskon-my-rewards__section", children: [
2547
- /* @__PURE__ */ jsx("h3", { className: "taskon-my-rewards__section-title", children: messages.tokenHistory }),
2548
- /* @__PURE__ */ jsx(
2549
- TokenHistoryTable,
2550
- {
2551
- data: tokenHistory2,
2552
- loading: tokenHistoryLoading,
2553
- error: tokenHistoryError,
2554
- pagination: tokenHistoryPagination,
2555
- messages
2556
- }
2557
- )
2558
- ] })
2559
- ] });
2560
- }
2561
- function formatBalance$1(balance) {
2562
- const num = parseFloat(balance);
2563
- if (isNaN(num) || num === 0) return "0";
2564
- return num.toLocaleString(void 0, { maximumFractionDigits: 6 });
2565
- }
2566
- function TokenSelect({
2567
- tokens,
2568
- value,
2569
- placeholder = "Select Token",
2570
- disabled = false,
2571
- hasError = false,
2572
- notSupportText = "Token not supported",
2573
- onChange
2574
- }) {
2575
- const tokenOptions = useMemo(() => {
2576
- return tokens.map((token) => ({
2577
- label: token.token_symbol,
2578
- icon: token.token_icon,
2579
- value: token.token_id,
2580
- chain_icon: token.chain_icon,
2581
- chain_label: token.chain_label,
2582
- token_balance: token.withdrawable_avail_balance,
2583
- can_withdraw: token.can_withdraw,
2584
- // 不可提现或余额为 0 时禁用选项
2585
- disabled: !token.can_withdraw || parseFloat(token.withdrawable_avail_balance) <= 0,
2586
- token
2587
- }));
2588
- }, [tokens]);
2589
- const selectedToken = useMemo(() => {
2590
- return tokens.find((t) => t.token_id === value) ?? null;
2591
- }, [tokens, value]);
2592
- const handleChange = useCallback(
2593
- (tokenId, option) => {
2594
- const tokenOption = option;
2595
- if (tokenOption.token) {
2596
- onChange(tokenId, tokenOption.token);
2597
- }
2598
- },
2599
- [onChange]
2600
- );
2601
- useEffect(() => {
2602
- if (tokens.length > 0 && !value) {
2603
- const withdrawableTokens = tokens.filter(
2604
- (t) => t.can_withdraw && parseFloat(t.withdrawable_avail_balance) > 0
2605
- );
2606
- const firstToken = withdrawableTokens[0];
2607
- if (firstToken) {
2608
- onChange(firstToken.token_id, firstToken);
2609
- }
2610
- }
2611
- }, [tokens, value, onChange]);
2612
- const renderOption = useCallback(
2613
- (option, _index, active) => {
2614
- const tokenOption = option;
2615
- return /* @__PURE__ */ jsx(
2616
- WithdrawSelectOption,
2617
- {
2618
- value: tokenOption.value,
2619
- label: tokenOption.label,
2620
- icon: tokenOption.icon,
2621
- chainIcon: tokenOption.chain_icon,
2622
- chainLabel: tokenOption.chain_label,
2623
- balance: tokenOption.token_balance,
2624
- canWithdraw: tokenOption.can_withdraw,
2625
- active,
2626
- disabled: tokenOption.disabled,
2627
- notSupportText
2628
- }
2629
- );
2630
- },
2631
- [notSupportText]
2632
- );
2633
- return /* @__PURE__ */ jsx(
2634
- Select,
2635
- {
2636
- options: tokenOptions,
2637
- value,
2638
- placeholder,
2639
- disabled,
2640
- hasError,
2641
- showCheckedIcon: false,
2642
- menuMaxHeight: "240px",
2643
- labelClass: "taskon-token-select__label",
2644
- renderOption,
2645
- onChange: handleChange,
2646
- beforeSlot: selectedToken && /* @__PURE__ */ jsxs("div", { className: "taskon-token-select__chain-info", children: [
2647
- selectedToken.chain_icon && /* @__PURE__ */ jsx(
2648
- "img",
2649
- {
2650
- src: selectedToken.chain_icon,
2651
- alt: selectedToken.chain_label,
2652
- className: "taskon-token-select__chain-icon"
2653
- }
2654
- ),
2655
- /* @__PURE__ */ jsx("span", { className: "taskon-token-select__chain-label", children: selectedToken.chain_label })
2656
- ] }),
2657
- labelAfterSlot: selectedToken && /* @__PURE__ */ jsx("span", { className: "taskon-token-select__balance", children: formatBalance$1(selectedToken.withdrawable_avail_balance) })
2658
- }
2659
- );
2660
- }
2661
- function AmountInput({
2662
- value,
2663
- max: max2,
2664
- decimals = 6,
2665
- placeholder = "0.00",
2666
- disabled = false,
2667
- hasError = false,
2668
- onChange
2669
- }) {
2670
- const formatValue = useCallback(
2671
- (inputValue) => {
2672
- let formatted = inputValue.replace(/[^0-9.]/g, "");
2673
- const parts = formatted.split(".");
2674
- if (parts.length > 2) {
2675
- formatted = (parts[0] ?? "") + "." + parts.slice(1).join("");
2676
- }
2677
- if (parts.length === 2 && parts[1] && parts[1].length > decimals) {
2678
- formatted = (parts[0] ?? "") + "." + parts[1].slice(0, decimals);
2679
- }
2680
- if (max2 && formatted !== "" && parseFloat(formatted) > parseFloat(max2)) {
2681
- formatted = max2;
2682
- }
2683
- return formatted;
2684
- },
2685
- [decimals, max2]
2686
- );
2687
- return /* @__PURE__ */ jsx(
2688
- Input,
2689
- {
2690
- value,
2691
- onChange,
2692
- inputMode: "decimal",
2693
- placeholder,
2694
- disabled,
2695
- hasError,
2696
- formatValue,
2697
- className: "taskon-amount-input"
2698
- }
2699
- );
2700
- }
2701
- function formatAddress(address, prefixLen = 6, suffixLen = 4) {
2702
- if (!address || address.length <= prefixLen + suffixLen) {
2703
- return address || "";
2704
- }
2705
- return `${address.slice(0, prefixLen)}...${address.slice(-suffixLen)}`;
2706
- }
2707
- function ReceiverAddress({
2708
- chainIcon,
2709
- chainLabel,
2710
- address
2711
- }) {
2712
- return /* @__PURE__ */ jsxs("div", { className: "taskon-receiver-address", children: [
2713
- /* @__PURE__ */ jsxs("div", { className: "taskon-receiver-address__chain", children: [
2714
- chainIcon && /* @__PURE__ */ jsx(
2715
- "img",
2716
- {
2717
- src: chainIcon,
2718
- alt: chainLabel || "chain",
2719
- className: "taskon-receiver-address__chain-icon"
2720
- }
2721
- ),
2722
- /* @__PURE__ */ jsx("span", { className: "taskon-receiver-address__chain-label", children: chainLabel || "--" })
2723
- ] }),
2724
- /* @__PURE__ */ jsx("div", { className: "taskon-receiver-address__address", children: address ? formatAddress(address) : "--" })
2725
- ] });
2726
- }
2727
- const PAGE_SIZE = 5;
2728
- function formatBalance(balance) {
2729
- const num = parseFloat(balance);
2730
- if (isNaN(num) || num === 0) return "0";
2731
- return num.toLocaleString(void 0, { maximumFractionDigits: 6 });
2732
- }
2733
- function isLt(a, b) {
2734
- return parseFloat(a || "0") < parseFloat(b || "0");
2735
- }
2736
- function isGt(a, b) {
2737
- return parseFloat(a || "0") > b;
2738
- }
2739
- function BatchTokenTable({
2740
- messages,
2741
- chain,
2742
- excludeTokenId,
2743
- tokenAssets,
2744
- selectedTokens,
2745
- onSelectionChange,
2746
- getDecimals,
2747
- single = false,
2748
- allChecked = false,
2749
- onAllCheckedChange
2750
- }) {
2751
- const [page2, setPage] = useState(0);
2752
- const [internalList, setInternalList] = useState([]);
2753
- const findDecimal = useCallback(
2754
- (address) => {
2755
- return getDecimals ? getDecimals(address) : 18;
2756
- },
2757
- [getDecimals]
2758
- );
2759
- const filteredTokens = useMemo(() => {
2760
- if (!chain) return [];
2761
- return tokenAssets.filter(
2762
- (t) => t.chain.toLowerCase() === chain.toLowerCase() && t.token_id !== excludeTokenId && t.can_withdraw && isGt(t.withdrawable_avail_balance, 0)
2763
- );
2764
- }, [tokenAssets, chain, excludeTokenId]);
2765
- useEffect(() => {
2766
- setInternalList(
2767
- filteredTokens.map((t) => ({
2768
- ...t,
2769
- checked: false,
2770
- qty: t.withdrawable_avail_balance
2771
- }))
2772
- );
2773
- setPage(0);
2774
- }, [filteredTokens]);
2775
- const displayList = useMemo(() => {
2776
- const start = page2 * PAGE_SIZE;
2777
- return internalList.slice(start, start + PAGE_SIZE);
2778
- }, [internalList, page2]);
2779
- const totalPages = Math.ceil(internalList.length / PAGE_SIZE);
2780
- const isChecked = useCallback(
2781
- (tokenId) => {
2782
- return selectedTokens.some((t) => t.tokenId === tokenId);
2783
- },
2784
- [selectedTokens]
2785
- );
2786
- const getAmount = useCallback(
2787
- (tokenId) => {
2788
- const item = selectedTokens.find((t) => t.tokenId === tokenId);
2789
- return (item == null ? void 0 : item.amount) || "";
2790
- },
2791
- [selectedTokens]
2792
- );
2793
- const tokenToWithdrawItem = useCallback(
2794
- (token, amount) => {
2795
- const decimals = findDecimal(token.token_address);
2796
- return {
2797
- tokenId: token.token_id,
2798
- tokenSymbol: token.token_symbol,
2799
- tokenIcon: token.token_icon,
2800
- tokenAddress: token.token_address,
2801
- tokenDecimals: decimals,
2802
- chain: token.chain,
2803
- chainLabel: token.chain_label,
2804
- amount,
2805
- amountInWei: toWei(amount, decimals)
2806
- };
2807
- },
2808
- [findDecimal]
2809
- );
2810
- const handleCheck = useCallback(
2811
- (token, checked) => {
2812
- if (single) {
2813
- if (checked) {
2814
- const newItem = tokenToWithdrawItem(
2815
- token,
2816
- token.withdrawable_avail_balance
2817
- );
2818
- onSelectionChange([newItem]);
2819
- setInternalList(
2820
- (prev) => prev.map((t) => ({
2821
- ...t,
2822
- checked: t.token_id === token.token_id,
2823
- qty: t.withdrawable_avail_balance
2824
- }))
2825
- );
2826
- } else {
2827
- onSelectionChange([]);
2828
- setInternalList(
2829
- (prev) => prev.map((t) => ({
2830
- ...t,
2831
- checked: false,
2832
- qty: t.withdrawable_avail_balance
2833
- }))
2834
- );
2835
- }
2836
- return;
2837
- }
2838
- if (checked) {
2839
- const newItem = tokenToWithdrawItem(
2840
- token,
2841
- token.withdrawable_avail_balance
2842
- );
2843
- onSelectionChange([...selectedTokens, newItem]);
2844
- setInternalList(
2845
- (prev) => prev.map(
2846
- (t) => t.token_id === token.token_id ? { ...t, checked: true, qty: t.withdrawable_avail_balance } : t
2847
- )
2848
- );
2849
- } else {
2850
- onSelectionChange(
2851
- selectedTokens.filter((t) => t.tokenId !== token.token_id)
2852
- );
2853
- setInternalList(
2854
- (prev) => prev.map(
2855
- (t) => t.token_id === token.token_id ? { ...t, checked: false } : t
2856
- )
2857
- );
2858
- }
2859
- },
2860
- [single, selectedTokens, onSelectionChange, tokenToWithdrawItem]
2861
- );
2862
- const handleAmountChange = useCallback(
2863
- (token, value) => {
2864
- let inputValue = value.replace(/[^0-9.]/g, "");
2865
- const parts = inputValue.split(".");
2866
- if (parts.length > 2) {
2867
- inputValue = (parts[0] ?? "") + "." + parts.slice(1).join("");
2868
- }
2869
- const decimals = findDecimal(token.token_address);
2870
- const maxDecimalPlaces = Math.min(decimals, 6);
2871
- if (parts.length === 2 && parts[1] && parts[1].length > maxDecimalPlaces) {
2872
- inputValue = (parts[0] ?? "") + "." + parts[1].slice(0, maxDecimalPlaces);
2873
- }
2874
- const maxAmount = token.withdrawable_avail_balance;
2875
- if (inputValue && !isLt(inputValue, maxAmount) && inputValue !== maxAmount) {
2876
- inputValue = maxAmount;
2877
- }
2878
- const updated = selectedTokens.map((t) => {
2879
- if (t.tokenId === token.token_id) {
2880
- return {
2881
- ...t,
2882
- amount: inputValue,
2883
- amountInWei: toWei(inputValue || "0", decimals)
2884
- };
2885
- }
2886
- return t;
2887
- });
2888
- onSelectionChange(updated);
2889
- setInternalList(
2890
- (prev) => prev.map(
2891
- (t) => t.token_id === token.token_id ? { ...t, qty: inputValue } : t
2892
- )
2893
- );
2894
- },
2895
- [selectedTokens, onSelectionChange, findDecimal]
2896
- );
2897
- const checkAll = useCallback(() => {
2898
- const newItems = internalList.filter((t) => t.can_withdraw).map((t) => tokenToWithdrawItem(t, t.withdrawable_avail_balance));
2899
- onSelectionChange(newItems);
2900
- setInternalList(
2901
- (prev) => prev.map((t) => ({
2902
- ...t,
2903
- checked: t.can_withdraw,
2904
- qty: t.withdrawable_avail_balance
2905
- }))
2906
- );
2907
- }, [internalList, onSelectionChange, tokenToWithdrawItem]);
2908
- const clearAll = useCallback(() => {
2909
- onSelectionChange([]);
2910
- setInternalList(
2911
- (prev) => prev.map((t) => ({
2912
- ...t,
2913
- checked: false,
2914
- qty: t.withdrawable_avail_balance
2915
- }))
2916
- );
2917
- }, [onSelectionChange]);
2918
- const handleCheckAll = useCallback(
2919
- (value) => {
2920
- if (value) {
2921
- checkAll();
2922
- } else {
2923
- clearAll();
2924
- }
2925
- onAllCheckedChange == null ? void 0 : onAllCheckedChange(value);
2926
- },
2927
- [checkAll, clearAll, onAllCheckedChange]
2928
- );
2929
- useEffect(() => {
2930
- if (allChecked) {
2931
- checkAll();
2932
- } else {
2933
- clearAll();
2934
- }
2935
- }, [allChecked]);
2936
- useEffect(() => {
2937
- clearAll();
2938
- if (allChecked) {
2939
- checkAll();
2940
- }
2941
- }, [chain, excludeTokenId]);
2942
- if (internalList.length === 0) {
2943
- return null;
2944
- }
2945
- const canWithdrawCount = internalList.filter((t) => t.can_withdraw).length;
2946
- const isAllSelected = canWithdrawCount > 0 && selectedTokens.length === canWithdrawCount;
2947
- const columns = [
2948
- // 复选框列
2949
- {
2950
- key: "checkbox",
2951
- title: single ? "" : /* @__PURE__ */ jsx(
2952
- Checkbox,
2953
- {
2954
- checked: isAllSelected,
2955
- onChange: handleCheckAll,
2956
- disabled: single
2957
- }
2958
- ),
2959
- width: 50,
2960
- render: (_, row) => {
2961
- const checked = isChecked(row.token_id);
2962
- return /* @__PURE__ */ jsx(
2963
- Checkbox,
2964
- {
2965
- checked,
2966
- onChange: (ck) => handleCheck(row, ck),
2967
- disabled: !row.can_withdraw
2968
- }
2969
- );
2970
- }
2971
- },
2972
- // 序号列
2973
- {
2974
- key: "index",
2975
- title: "#",
2976
- width: 50,
2977
- render: (_, __, rowIndex) => {
2978
- return page2 * PAGE_SIZE + rowIndex + 1;
2979
- }
2980
- },
2981
- // Token 类型列
2982
- {
2983
- key: "token_symbol",
2984
- title: messages.columnTokenType || "Type",
2985
- width: 105,
2986
- align: "center",
2987
- render: (_, row) => /* @__PURE__ */ jsxs("div", { className: "taskon-batch-token-table__token-cell", children: [
2988
- row.token_icon && /* @__PURE__ */ jsx(
2989
- "img",
2990
- {
2991
- src: row.token_icon,
2992
- alt: row.token_symbol,
2993
- className: "taskon-batch-token-table__token-icon"
2994
- }
2995
- ),
2996
- /* @__PURE__ */ jsx("span", { children: row.token_symbol })
2997
- ] })
2998
- },
2999
- // 可提现金额列
3000
- {
3001
- key: "withdrawable_avail_balance",
3002
- title: messages.columnAmountWithdrawable || "Amount Withdrawable",
3003
- width: 120,
3004
- align: "center",
3005
- render: (_, row) => formatBalance(row.withdrawable_avail_balance)
3006
- },
3007
- // 提现金额输入列
3008
- {
3009
- key: "amount",
3010
- title: messages.columnWithdrawAmount || "Withdraw Amount",
3011
- width: 120,
3012
- align: "center",
3013
- render: (_, row) => {
3014
- const checked = isChecked(row.token_id);
3015
- const amount = getAmount(row.token_id) || row.qty;
3016
- return /* @__PURE__ */ jsx(
3017
- Input,
3018
- {
3019
- value: amount,
3020
- onChange: (v) => handleAmountChange(row, v),
3021
- placeholder: "0",
3022
- disabled: !checked,
3023
- inputMode: "decimal",
3024
- className: "taskon-batch-token-table__input",
3025
- formatValue: (v) => {
3026
- let val = v.replace(/[^0-9.]/g, "");
3027
- const parts = val.split(".");
3028
- if (parts.length > 2) {
3029
- val = (parts[0] ?? "") + "." + parts.slice(1).join("");
3030
- }
3031
- return val;
3032
- }
3033
- }
3034
- );
3035
- }
3036
- }
3037
- ];
3038
- return /* @__PURE__ */ jsxs("div", { className: "taskon-batch-token-table", children: [
3039
- /* @__PURE__ */ jsx(
3040
- Table,
3041
- {
3042
- columns,
3043
- data: displayList,
3044
- compact: true,
3045
- borderless: true,
3046
- rowConfig: {
3047
- getRowKey: (row) => row.token_id,
3048
- isDisabled: (row) => !row.can_withdraw,
3049
- rowClassName: (row) => !row.can_withdraw ? "taskon-batch-token-table__row--disabled" : ""
3050
- },
3051
- className: "taskon-batch-token-table__table"
3052
- }
3053
- ),
3054
- totalPages > 1 && /* @__PURE__ */ jsx(
3055
- Pagination$1,
3056
- {
3057
- page: page2,
3058
- totalPages,
3059
- hasPrevious: page2 > 0,
3060
- hasNext: page2 < totalPages - 1,
3061
- onPrevious: () => setPage((p) => Math.max(0, p - 1)),
3062
- onNext: () => setPage((p) => Math.min(totalPages - 1, p + 1)),
3063
- size: "small",
3064
- className: "taskon-batch-token-table__pagination"
3065
- }
3066
- )
3067
- ] });
3068
- }
3069
- function WithdrawFormInit({
3070
- messages,
3071
- tokenAssets,
3072
- tokenAssetsLoading,
3073
- selectedTokenId,
3074
- selectedToken,
3075
- withdrawAmount,
3076
- batchEnabled,
3077
- batchTokens,
3078
- batchableTokenCount,
3079
- userAddress,
3080
- submitting,
3081
- validationErrors,
3082
- getDecimals,
3083
- onTokenChange,
3084
- onAmountChange,
3085
- onBatchEnabledChange,
3086
- onBatchTokensChange,
3087
- onSubmit
3088
- }) {
3089
- const withdrawableTokens = tokenAssets.filter(
3090
- (t) => t.can_withdraw && parseFloat(t.withdrawable_avail_balance) > 0
3091
- );
3092
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-form-init", children: [
3093
- /* @__PURE__ */ jsx("h2", { className: "taskon-withdraw-form-init__title", children: messages.withdraw }),
3094
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-form-init__content", children: [
3095
- /* @__PURE__ */ jsx(FormItem, { label: "Select Token", type: "dialog", error: validationErrors.token, children: /* @__PURE__ */ jsx(
3096
- TokenSelect,
3097
- {
3098
- tokens: withdrawableTokens,
3099
- value: selectedTokenId,
3100
- placeholder: "Select Token",
3101
- disabled: tokenAssetsLoading || submitting,
3102
- hasError: !!validationErrors.token,
3103
- onChange: onTokenChange
3104
- }
3105
- ) }),
3106
- /* @__PURE__ */ jsx(FormItem, { label: "Token Amount", type: "dialog", error: validationErrors.amount, children: /* @__PURE__ */ jsx(
3107
- AmountInput,
3108
- {
3109
- value: withdrawAmount,
3110
- max: selectedToken == null ? void 0 : selectedToken.withdrawable_avail_balance,
3111
- decimals: 6,
3112
- placeholder: "0.00",
3113
- disabled: !selectedToken || submitting,
3114
- hasError: !!validationErrors.amount,
3115
- onChange: onAmountChange
3116
- }
3117
- ) }),
3118
- /* @__PURE__ */ jsx(FormItem, { label: "Receive Address", type: "dialog", children: /* @__PURE__ */ jsx(
3119
- ReceiverAddress,
3120
- {
3121
- chainIcon: selectedToken == null ? void 0 : selectedToken.chain_icon,
3122
- chainLabel: selectedToken == null ? void 0 : selectedToken.chain_label,
3123
- address: userAddress
3124
- }
3125
- ) }),
3126
- batchableTokenCount > 0 && /* @__PURE__ */ jsx(FormItem, { type: "dialog", noRowMargin: true, children: /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-form-init__switch-wrap", children: /* @__PURE__ */ jsx(
3127
- Switch,
3128
- {
3129
- checked: batchEnabled,
3130
- onChange: onBatchEnabledChange,
3131
- label: messages.batchWithdraw,
3132
- disabled: submitting
3133
- }
3134
- ) }) }),
3135
- batchEnabled && selectedToken && batchableTokenCount > 0 && /* @__PURE__ */ jsx(FormItem, { type: "dialog", children: /* @__PURE__ */ jsx(
3136
- BatchTokenTable,
3137
- {
3138
- messages,
3139
- chain: selectedToken.chain,
3140
- excludeTokenId: selectedTokenId,
3141
- tokenAssets,
3142
- selectedTokens: batchTokens,
3143
- onSelectionChange: onBatchTokensChange,
3144
- getDecimals
3145
- }
3146
- ) })
3147
- ] }),
3148
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-form-init__footer", children: /* @__PURE__ */ jsx(
3149
- Button,
3150
- {
3151
- variant: "primary",
3152
- size: "large",
3153
- onClick: onSubmit,
3154
- disabled: submitting || !selectedToken,
3155
- loading: submitting,
3156
- className: "taskon-withdraw-form-init__submit",
3157
- children: submitting ? messages.loading : messages.withdraw
3158
- }
3159
- ) })
3160
- ] });
3161
- }
3162
- function formatAmount(amount) {
3163
- const num = parseFloat(amount);
3164
- if (isNaN(num) || num === 0) return "0";
3165
- return num.toLocaleString(void 0, { maximumFractionDigits: 6 });
3166
- }
3167
- function WithdrawConfirm({
3168
- messages,
3169
- tokens,
3170
- loading: loading2,
3171
- error: error2,
3172
- onConfirm,
3173
- onCancel
3174
- }) {
3175
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm", children: [
3176
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-confirm__header", children: /* @__PURE__ */ jsx("h3", { className: "taskon-withdraw-confirm__title", children: messages.withdrawConfirm }) }),
3177
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm__content", children: [
3178
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-confirm__tokens", children: tokens.map((token) => /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm__token", children: [
3179
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm__token-info", children: [
3180
- token.tokenIcon && /* @__PURE__ */ jsx(
3181
- "img",
3182
- {
3183
- src: token.tokenIcon,
3184
- alt: token.tokenSymbol,
3185
- className: "taskon-withdraw-confirm__token-icon"
3186
- }
3187
- ),
3188
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm__token-details", children: [
3189
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-confirm__token-symbol", children: token.tokenSymbol }),
3190
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-confirm__token-chain", children: token.chainLabel })
3191
- ] })
3192
- ] }),
3193
- /* @__PURE__ */ jsx("span", { className: "taskon-withdraw-confirm__token-amount", children: formatAmount(token.amount) })
3194
- ] }, token.tokenId)) }),
3195
- error2 && /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-confirm__error", children: error2.message })
3196
- ] }),
3197
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-confirm__footer", children: [
3198
- /* @__PURE__ */ jsx(
3199
- Button,
3200
- {
3201
- variant: "secondary",
3202
- onClick: onCancel,
3203
- disabled: loading2,
3204
- children: messages.cancel
3205
- }
3206
- ),
3207
- /* @__PURE__ */ jsx(
3208
- Button,
3209
- {
3210
- variant: "primary",
3211
- onClick: onConfirm,
3212
- disabled: loading2,
3213
- loading: loading2,
3214
- children: loading2 ? messages.loading : messages.confirm
3215
- }
3216
- )
3217
- ] })
3218
- ] });
3219
- }
3220
- function WithdrawLoading({
3221
- messages
3222
- }) {
3223
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-loading", children: [
3224
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-loading__spinner", children: /* @__PURE__ */ jsx(
3225
- "svg",
3226
- {
3227
- viewBox: "0 0 50 50",
3228
- width: "64",
3229
- height: "64",
3230
- className: "taskon-withdraw-loading__circle",
3231
- children: /* @__PURE__ */ jsx(
3232
- "circle",
3233
- {
3234
- cx: "25",
3235
- cy: "25",
3236
- r: "20",
3237
- fill: "none",
3238
- stroke: "currentColor",
3239
- strokeWidth: "4",
3240
- strokeLinecap: "round",
3241
- strokeDasharray: "80, 200",
3242
- strokeDashoffset: "0"
3243
- }
3244
- )
3245
- }
3246
- ) }),
3247
- /* @__PURE__ */ jsx("p", { className: "taskon-withdraw-loading__text", children: messages.withdrawing })
3248
- ] });
3249
- }
3250
- function WithdrawSuccess({
3251
- messages,
3252
- txHash,
3253
- onClose
3254
- }) {
3255
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-success", children: [
3256
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-success__icon", children: /* @__PURE__ */ jsx(
3257
- "svg",
3258
- {
3259
- viewBox: "0 0 24 24",
3260
- fill: "currentColor",
3261
- width: "64",
3262
- height: "64",
3263
- children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" })
3264
- }
3265
- ) }),
3266
- /* @__PURE__ */ jsx("h3", { className: "taskon-withdraw-success__title", children: messages.withdrawSuccess }),
3267
- txHash && /* @__PURE__ */ jsxs("p", { className: "taskon-withdraw-success__tx-hash", children: [
3268
- "TX: ",
3269
- txHash.slice(0, 10),
3270
- "...",
3271
- txHash.slice(-8)
3272
- ] }),
3273
- /* @__PURE__ */ jsx(
3274
- Button,
3275
- {
3276
- variant: "primary",
3277
- onClick: onClose,
3278
- className: "taskon-withdraw-success__btn",
3279
- children: messages.close
3280
- }
3281
- )
3282
- ] });
3283
- }
3284
- function WithdrawCancel({
3285
- messages,
3286
- onRetry,
3287
- onClose
3288
- }) {
3289
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-cancel", children: [
3290
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-cancel__icon", children: /* @__PURE__ */ jsx(
3291
- "svg",
3292
- {
3293
- viewBox: "0 0 24 24",
3294
- fill: "currentColor",
3295
- width: "64",
3296
- height: "64",
3297
- children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" })
3298
- }
3299
- ) }),
3300
- /* @__PURE__ */ jsx("h3", { className: "taskon-withdraw-cancel__title", children: messages.withdrawCanceled }),
3301
- /* @__PURE__ */ jsx("p", { className: "taskon-withdraw-cancel__message", children: messages.withdrawCanceledMessage ?? "Your withdrawal was canceled. You can retry the transaction." }),
3302
- /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-cancel__actions", children: [
3303
- /* @__PURE__ */ jsx(
3304
- Button,
3305
- {
3306
- variant: "secondary",
3307
- onClick: onClose,
3308
- children: messages.close
3309
- }
3310
- ),
3311
- /* @__PURE__ */ jsx(
3312
- Button,
3313
- {
3314
- variant: "primary",
3315
- onClick: onRetry,
3316
- children: messages.retry
3317
- }
3318
- )
3319
- ] })
3320
- ] });
3321
- }
3322
- function WithdrawGasNotEnough({
3323
- messages,
3324
- chainLabel,
3325
- onClose
3326
- }) {
3327
- return /* @__PURE__ */ jsxs("div", { className: "taskon-withdraw-gas-not-enough", children: [
3328
- /* @__PURE__ */ jsx("div", { className: "taskon-withdraw-gas-not-enough__icon", children: /* @__PURE__ */ jsx(
3329
- "svg",
3330
- {
3331
- viewBox: "0 0 24 24",
3332
- fill: "currentColor",
3333
- width: "64",
3334
- height: "64",
3335
- children: /* @__PURE__ */ jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
3336
- }
3337
- ) }),
3338
- /* @__PURE__ */ jsx("h3", { className: "taskon-withdraw-gas-not-enough__title", children: messages.gasNotEnough }),
3339
- /* @__PURE__ */ jsx("p", { className: "taskon-withdraw-gas-not-enough__message", children: chainLabel ? `Please ensure you have enough ${chainLabel} gas to complete this transaction.` : "Please ensure you have enough gas to complete this transaction." }),
3340
- /* @__PURE__ */ jsx(
3341
- Button,
3342
- {
3343
- variant: "primary",
3344
- onClick: onClose,
3345
- className: "taskon-withdraw-gas-not-enough__btn",
3346
- children: messages.close
3347
- }
3348
- )
3349
- ] });
3350
- }
3351
- function getDialogTitle(status, messages) {
3352
- switch (status) {
3353
- case "confirm":
3354
- return messages.withdrawConfirm;
3355
- case "loading":
3356
- return messages.loading;
3357
- case "success":
3358
- return messages.withdrawSuccess;
3359
- case "cancel":
3360
- return messages.withdrawCanceled;
3361
- case "noEnough":
3362
- return messages.gasNotEnough;
3363
- default:
3364
- return messages.withdraw;
3365
- }
3366
- }
3367
- function WithdrawForm({
3368
- open,
3369
- messages,
3370
- tokenAssets,
3371
- tokenAssetsLoading,
3372
- userAddress,
3373
- initialTokenId,
3374
- initialChain,
3375
- onClose,
3376
- onSuccess
3377
- }) {
3378
- const [submitting, setSubmitting] = useState(false);
3379
- const { getDecimals } = useTokenDecimals({
3380
- tokenAssets
3381
- });
3382
- const form = useWithdrawForm({
3383
- tokenAssets,
3384
- initialTokenId,
3385
- initialChain,
3386
- getDecimals
3387
- // 传入精度获取函数
3388
- });
3389
- const withdraw2 = useTokenWithdraw({
3390
- userAddress,
3391
- onSuccess: (txHash) => {
3392
- onSuccess == null ? void 0 : onSuccess(txHash);
3393
- },
3394
- onCancel: () => {
3395
- }
3396
- });
3397
- const handleSubmit = useCallback(async () => {
3398
- if (!form.validation.isValid) {
3399
- return;
3400
- }
3401
- const tokens = form.buildWithdrawTokens();
3402
- if (tokens.length === 0) {
3403
- return;
3404
- }
3405
- try {
3406
- setSubmitting(true);
3407
- withdraw2.initWithdrawTokens(tokens);
3408
- await withdraw2.checkAndConnect();
3409
- } catch (error2) {
3410
- console.error("Submit failed:", error2);
3411
- } finally {
3412
- setSubmitting(false);
3413
- }
3414
- }, [form, withdraw2]);
3415
- const handleConfirm = useCallback(async () => {
3416
- await withdraw2.confirmWithdraw();
3417
- }, [withdraw2]);
3418
- const handleCancel = useCallback(() => {
3419
- withdraw2.cancelWithdraw();
3420
- }, [withdraw2]);
3421
- const handleRetry = useCallback(async () => {
3422
- await withdraw2.confirmWithdraw();
3423
- }, [withdraw2]);
3424
- const handleClose = useCallback(() => {
3425
- withdraw2.reset();
3426
- form.resetForm();
3427
- onClose();
3428
- }, [withdraw2, form, onClose]);
3429
- if (!open) {
3430
- return null;
3431
- }
3432
- const renderContent = () => {
3433
- var _a;
3434
- switch (withdraw2.status) {
3435
- case "init":
3436
- return /* @__PURE__ */ jsx(
3437
- WithdrawFormInit,
3438
- {
3439
- messages,
3440
- tokenAssets,
3441
- tokenAssetsLoading,
3442
- selectedTokenId: form.selectedTokenId,
3443
- selectedToken: form.selectedToken,
3444
- withdrawAmount: form.withdrawAmount,
3445
- batchEnabled: form.batchEnabled,
3446
- batchTokens: form.batchTokens,
3447
- batchableTokenCount: form.batchableTokenCount,
3448
- userAddress,
3449
- submitting,
3450
- validationErrors: form.validation.errors,
3451
- getDecimals,
3452
- onTokenChange: (tokenId, token) => {
3453
- form.setSelectedTokenId(tokenId);
3454
- form.setWithdrawAmount(token.withdrawable_avail_balance);
3455
- },
3456
- onAmountChange: form.setWithdrawAmount,
3457
- onBatchEnabledChange: form.setBatchEnabled,
3458
- onBatchTokensChange: form.setBatchTokens,
3459
- onSubmit: handleSubmit,
3460
- onClose: handleClose
3461
- }
3462
- );
3463
- case "confirm":
3464
- return /* @__PURE__ */ jsx(
3465
- WithdrawConfirm,
3466
- {
3467
- messages,
3468
- tokens: withdraw2.tokens,
3469
- loading: false,
3470
- error: withdraw2.error,
3471
- onConfirm: handleConfirm,
3472
- onCancel: handleCancel
3473
- }
3474
- );
3475
- case "loading":
3476
- return /* @__PURE__ */ jsx(WithdrawLoading, { messages });
3477
- case "success":
3478
- return /* @__PURE__ */ jsx(
3479
- WithdrawSuccess,
3480
- {
3481
- messages,
3482
- txHash: withdraw2.txHash,
3483
- onClose: handleClose
3484
- }
3485
- );
3486
- case "cancel":
3487
- return /* @__PURE__ */ jsx(
3488
- WithdrawCancel,
3489
- {
3490
- messages,
3491
- onRetry: handleRetry,
3492
- onClose: handleClose
3493
- }
3494
- );
3495
- case "noEnough":
3496
- return /* @__PURE__ */ jsx(
3497
- WithdrawGasNotEnough,
3498
- {
3499
- messages,
3500
- chainLabel: (_a = form.selectedToken) == null ? void 0 : _a.chain_label,
3501
- onClose: handleClose
3502
- }
3503
- );
3504
- default:
3505
- return null;
3506
- }
3507
- };
3508
- return /* @__PURE__ */ jsx(
3509
- Dialog,
3510
- {
3511
- open,
3512
- onOpenChange: (isOpen) => {
3513
- if (!isOpen) handleClose();
3514
- },
3515
- title: getDialogTitle(withdraw2.status, messages),
3516
- showCloseButton: withdraw2.status === "init",
3517
- contentClassName: "taskon-withdraw-form__container",
3518
- maxWidth: 480,
3519
- children: renderContent()
3520
- }
3521
- );
3522
- }
3523
- export {
3524
- EmptyState as E,
3525
- LoadingState as L,
3526
- Pagination as P,
3527
- TokenAssetList as T,
3528
- WithdrawForm as W,
3529
- useTokenAssets as a,
3530
- useTokenWithdraw as b,
3531
- usePointsHistory as c,
3532
- toGasFreeWithdrawItem as d,
3533
- buildRewardCards as e,
3534
- formatTokenAmount as f,
3535
- formatDateTime as g,
3536
- TxErrorType as h,
3537
- TransactionError as i,
3538
- isSameAddress as j,
3539
- PointsList as k,
3540
- TokenRewardContent as l,
3541
- enMessages as m,
3542
- en as n,
3543
- parseTxError as p,
3544
- toWithdrawItem as t,
3545
- useRewardDetails as u
3546
- };