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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +61 -47
  2. package/dist/CommunityTaskList.css +9 -1
  3. package/dist/EligibilityInfo.css +48 -75
  4. package/dist/LeaderboardWidget.css +73 -71
  5. package/dist/PageBuilder.css +5 -0
  6. package/dist/Quest.css +18 -14
  7. package/dist/TaskOnProvider.css +289 -0
  8. package/dist/ThemeProvider.css +227 -0
  9. package/dist/UserCenterWidget.css +6 -6
  10. package/dist/UserCenterWidget2.css +1388 -1621
  11. package/dist/{dynamic-import-helper.css → WidgetShell.css} +0 -227
  12. package/dist/chunks/{CommunityTaskList-CrMvOB8w.js → CommunityTaskList-D0uVD8wD.js} +393 -208
  13. package/dist/chunks/{EligibilityInfo-Beww12QX.js → EligibilityInfo-Cf6hx9-a.js} +459 -679
  14. package/dist/chunks/{LeaderboardWidget-DwuSpVl0.js → LeaderboardWidget-DyoiiNS6.js} +274 -252
  15. package/dist/chunks/{PageBuilder-DsX6Tv0N.js → PageBuilder-DoAFPm6-.js} +5 -5
  16. package/dist/chunks/{Quest-CuD2LElS.js → Quest-ySZlYd4u.js} +74 -57
  17. package/dist/chunks/TaskOnProvider-CxtFIs3n.js +2072 -0
  18. package/dist/chunks/{dynamic-import-helper-WmIF58Sb.js → ThemeProvider-CulHkqqY.js} +1282 -555
  19. package/dist/chunks/UserCenterWidget-BJsc_GSZ.js +3246 -0
  20. package/dist/chunks/{UserCenterWidget-CvU6K4AC.js → UserCenterWidget-STq8kpV4.js} +1174 -1386
  21. package/dist/chunks/WidgetShell-8xn-Jivw.js +659 -0
  22. package/dist/chunks/communitytask-es-CBNnS4o2.js +521 -0
  23. package/dist/chunks/communitytask-ja-GRf9cbdx.js +521 -0
  24. package/dist/chunks/communitytask-ko-Bf24PQKI.js +521 -0
  25. package/dist/chunks/{communitytask-ru-DhySaZL8.js → communitytask-ru-CZm2CPoV.js} +211 -1
  26. package/dist/chunks/leaderboardwidget-es-vKjrjQaz.js +146 -0
  27. package/dist/chunks/leaderboardwidget-ja-Q6u0HxKG.js +146 -0
  28. package/dist/chunks/leaderboardwidget-ko-CG6SWgxf.js +146 -0
  29. package/dist/chunks/leaderboardwidget-ru-DCcHcJGz.js +146 -0
  30. package/dist/chunks/{quest-es-D-b5xcme.js → quest-es-Dyyy0zaw.js} +8 -93
  31. package/dist/chunks/{quest-ja-Dxd2vqBF.js → quest-ja-Depog33y.js} +8 -93
  32. package/dist/chunks/{quest-ko-CSmRWgK_.js → quest-ko-BMu3uRQJ.js} +8 -93
  33. package/dist/chunks/{quest-ru-CkEKv1_F.js → quest-ru-xne814Rw.js} +8 -93
  34. package/dist/chunks/useIsMobile-D6Ybur-6.js +30 -0
  35. package/dist/chunks/useToast-BGJhd3BX.js +93 -0
  36. package/dist/chunks/usercenter-es-Dz3Wp2vV.js +512 -0
  37. package/dist/chunks/usercenter-ja-CKE4DJC6.js +512 -0
  38. package/dist/chunks/usercenter-ko-Dtpkn2qb.js +512 -0
  39. package/dist/chunks/usercenter-ru-DnBGee45.js +512 -0
  40. package/dist/community-task.d.ts +0 -390
  41. package/dist/community-task.js +2 -7
  42. package/dist/core.d.ts +38 -20
  43. package/dist/core.js +9 -10
  44. package/dist/index.d.ts +86 -709
  45. package/dist/index.js +22 -28
  46. package/dist/leaderboard.d.ts +0 -498
  47. package/dist/leaderboard.js +2 -16
  48. package/dist/page-builder.js +1 -1
  49. package/dist/quest.d.ts +0 -971
  50. package/dist/quest.js +2 -7
  51. package/dist/user-center.d.ts +0 -1610
  52. package/dist/user-center.js +2 -494
  53. package/package.json +2 -2
  54. package/dist/chunks/TaskOnProvider-xUeP2Nro.js +0 -1243
  55. package/dist/chunks/ThemeProvider-Bt4UZ33y.js +0 -1334
  56. package/dist/chunks/UserCenterWidget-CB0hnj-L.js +0 -3230
  57. package/dist/chunks/communitytask-es-1zawvXEX.js +0 -311
  58. package/dist/chunks/communitytask-ja-CmW6nP-L.js +0 -311
  59. package/dist/chunks/communitytask-ko-BD0hzQSi.js +0 -311
  60. package/dist/chunks/createLocaleLoader-BameiEhU.js +0 -65
  61. package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +0 -119
  62. package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +0 -119
  63. package/dist/chunks/useToast-CaRkylKe.js +0 -304
  64. package/dist/chunks/usercenter-ja-B2465c1O.js +0 -326
  65. package/dist/chunks/usercenter-ko-xAEYxqLg.js +0 -326
@@ -1,12 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import React__default, { useState, useRef, useCallback, useEffect, useContext, useMemo } from "react";
3
3
  import { isUnauthorizedError, TaskReviewResult, formatLongNumber, EligibilityType, Operator, MeetConditionStatus, RewardType, formatUtcTime, ErrorCode, SnsType, createCommunityTaskApi, TaskCardType, ChainType, getSwapDexTitleExpress, UserEligibleStatus, CampaignStatus, MediaType, createQuestApi, CampaignType, formatTokenAmount, TaskTemplateId, EligibilityTemplateId, RecurrenceType, createCommonApi, normalizeTask, formatSwapTokensForDisplay, formatAddress } from "@taskon/core";
4
- import { q as TaskOnContext, d as useTaskOnContext, t as useTaskOnPortalContainer } from "./ThemeProvider-Bt4UZ33y.js";
5
- import { D as Dialog, a as useResolvedWidgetConfig, W as WidgetShell } from "./dynamic-import-helper-WmIF58Sb.js";
6
- import { u as useTranslation, c as createLocaleLoader } from "./createLocaleLoader-BameiEhU.js";
7
- import { d as useToast } from "./useToast-CaRkylKe.js";
8
- import { a as useBindWallet, T as TitleExpress, b as CardDescExpress, c as useNftClaimFlow, R as RewardModuleDialog, B as BlindBoxDialog, d as TaskItem, E as EligibilityInfo, e as Textarea } from "./EligibilityInfo-Beww12QX.js";
9
- import { g as useBindSocialAccount, B as BindWalletDialog, l as useChainMap, s as TipPopover, k as useIsMobile, I as Input } from "./UserCenterWidget-CvU6K4AC.js";
4
+ import { c as useTranslation, e as createLocaleLoader, w as TaskOnContext, h as useTaskOnContext, E as useTaskOnPortalContainer, D as Dialog } from "./ThemeProvider-CulHkqqY.js";
5
+ import { u as useResolvedWidgetConfig, W as WidgetShell } from "./WidgetShell-8xn-Jivw.js";
6
+ import { c as useToast } from "./useToast-BGJhd3BX.js";
7
+ import { u as useBindWallet, T as TitleExpress, C as CardDescExpress, a as useNftClaimFlow, R as RewardModuleDialog, B as BlindBoxDialog, b as TaskItem, E as EligibilityInfo, c as Textarea } from "./EligibilityInfo-Cf6hx9-a.js";
8
+ import { a as useBindSocialAccount, k as useChainMap, p as TipPopover, I as Input } from "./UserCenterWidget-STq8kpV4.js";
9
+ import { u as useIsMobile } from "./useIsMobile-D6Ybur-6.js";
10
10
  import { createPortal } from "react-dom";
11
11
  import '../CommunityTaskList.css';function CardSelector({
12
12
  options,
@@ -142,6 +142,76 @@ const community_points = "Points";
142
142
  const community_token = "Token";
143
143
  const community_dex = "DEX";
144
144
  const community_rule_max = "(Max {val} {name})";
145
+ const taskchain_event_ended = "Event Ended";
146
+ const taskchain_login_required = "Login Required";
147
+ const taskchain_login_prompt = "Please login to participate in this task chain";
148
+ const taskchain_login_button = "Login";
149
+ const taskchain_not_eligible_title = "Not Eligible";
150
+ const taskchain_not_eligible_desc = "You don't meet the requirements to participate in this task chain.";
151
+ const taskchain_oops = "Oops!";
152
+ const taskchain_error_load_chain = "Failed to load task chain";
153
+ const taskchain_error_load_campaign_info = "Failed to load campaign info";
154
+ const taskchain_error_load_user_status = "Failed to load user status";
155
+ const taskchain_loading = "Loading...";
156
+ const taskchain_back = "Back";
157
+ const taskchain_next = "Next";
158
+ const taskchain_no_task_available = "No task available";
159
+ const taskchain_spots_left = "Spots left";
160
+ const taskchain_won = "Won";
161
+ const taskchain_ended = "Ended";
162
+ const taskchain_locked = "Locked";
163
+ const taskchain_unlock_prefix = "Complete the";
164
+ const taskchain_unlock_day_challenge = "Day {day} challenge";
165
+ const taskchain_unlock_suffix = "then wait until next day to unlock";
166
+ const taskchain_goal = "Goal";
167
+ const taskchain_token_fallback = "Token";
168
+ const taskchain_points_fallback = "Points";
169
+ const taskchain_nft_fallback = "NFT";
170
+ const taskchain_blindbox_submit_failed = "Failed to submit campaign. Please try again.";
171
+ const taskchain_blindbox_claim_failed = "Failed to claim reward. Please try again.";
172
+ const taskchain_blindbox_title_missed = "Oops! Better Luck Next Time!";
173
+ const taskchain_blindbox_title_won = "Congratulations!";
174
+ const taskchain_blindbox_subtitle_missed = "Rewards Missed";
175
+ const taskchain_blindbox_subtitle_won = "You Have Won";
176
+ const taskchain_blindbox_preparing_reward = "Preparing your reward...";
177
+ const taskchain_blindbox_submitting = "Submitting...";
178
+ const taskchain_blindbox_retry_submit = "Retry submit";
179
+ const taskchain_reward_submit_failed = "Failed to submit campaign. Please try again.";
180
+ const taskchain_reward_congratulations = "Congratulations!";
181
+ const taskchain_reward_you_won = "You have won";
182
+ const taskchain_reward_claiming = "Claiming...";
183
+ const taskchain_reward_claim = "Claim Reward";
184
+ const taskchain_nft_claim_failed = "Failed to claim NFT";
185
+ const taskchain_reward_token_label = "Reward Token";
186
+ const taskchain_value_label = "Value";
187
+ const taskchain_reward_type_cap = "Cap";
188
+ const taskchain_reward_type_nft = "NFT";
189
+ const taskchain_nft_cta_mint = "Mint";
190
+ const taskchain_nft_cta_view = "View my NFT";
191
+ const taskchain_nft_claim_not_supported = "NFT claim is not supported for this reward type yet.";
192
+ const taskchain_nft_alt = "NFT";
193
+ const taskchain_chain_alt = "Chain";
194
+ const taskchain_nft_claim_dialog_claim_nft = "Claim NFT";
195
+ const taskchain_nft_claim_dialog_claiming_nft = "Claiming NFT...";
196
+ const taskchain_nft_claim_dialog_connecting_wallet = "Connecting wallet...";
197
+ const taskchain_nft_claim_dialog_switching_network = "Switching network...";
198
+ const taskchain_nft_claim_dialog_getting_signature = "Getting signature...";
199
+ const taskchain_nft_claim_dialog_confirm_in_wallet = "Please confirm in your wallet";
200
+ const taskchain_nft_claim_dialog_tx_pending = "Transaction pending...";
201
+ const taskchain_nft_claim_dialog_success = "Claim successful!";
202
+ const taskchain_nft_claim_dialog_failed = "Claim failed";
203
+ const taskchain_nft_claim_dialog_canceled = "Transaction was rejected by user.";
204
+ const taskchain_nft_claim_dialog_view_explorer = "View on Explorer";
205
+ const taskchain_nft_claim_dialog_retry = "Retry";
206
+ const taskchain_nft_claim_dialog_close = "Close";
207
+ const taskchain_nft_pending_dialog_title = "Pending Transaction";
208
+ const taskchain_nft_pending_dialog_desc = "You have already claimed this NFT, please wait for this transaction to be confirmed.";
209
+ const taskchain_nft_pending_dialog_check_explorer = "You can check this transaction on explorer:";
210
+ const taskchain_nft_pending_dialog_hash_label = "Transaction hash:";
211
+ const taskchain_nft_pending_dialog_claim_again_warn = '"Claim Again" will send a new transaction it is only recommended when you are sure there is something wrong with the current transaction.';
212
+ const taskchain_nft_pending_dialog_receive_address_fixed = "This receive address can't be changed:";
213
+ const taskchain_nft_pending_dialog_claim_again = "Claim Again";
214
+ const taskchain_nft_pending_dialog_continue_waiting = "Continue Waiting";
145
215
  const enMessages = {
146
216
  once_tag,
147
217
  daily_tag,
@@ -244,21 +314,91 @@ const enMessages = {
244
314
  community_points,
245
315
  community_token,
246
316
  community_dex,
247
- community_rule_max
317
+ community_rule_max,
318
+ taskchain_event_ended,
319
+ taskchain_login_required,
320
+ taskchain_login_prompt,
321
+ taskchain_login_button,
322
+ taskchain_not_eligible_title,
323
+ taskchain_not_eligible_desc,
324
+ taskchain_oops,
325
+ taskchain_error_load_chain,
326
+ taskchain_error_load_campaign_info,
327
+ taskchain_error_load_user_status,
328
+ taskchain_loading,
329
+ taskchain_back,
330
+ taskchain_next,
331
+ taskchain_no_task_available,
332
+ taskchain_spots_left,
333
+ taskchain_won,
334
+ taskchain_ended,
335
+ taskchain_locked,
336
+ taskchain_unlock_prefix,
337
+ taskchain_unlock_day_challenge,
338
+ taskchain_unlock_suffix,
339
+ taskchain_goal,
340
+ taskchain_token_fallback,
341
+ taskchain_points_fallback,
342
+ taskchain_nft_fallback,
343
+ taskchain_blindbox_submit_failed,
344
+ taskchain_blindbox_claim_failed,
345
+ taskchain_blindbox_title_missed,
346
+ taskchain_blindbox_title_won,
347
+ taskchain_blindbox_subtitle_missed,
348
+ taskchain_blindbox_subtitle_won,
349
+ taskchain_blindbox_preparing_reward,
350
+ taskchain_blindbox_submitting,
351
+ taskchain_blindbox_retry_submit,
352
+ taskchain_reward_submit_failed,
353
+ taskchain_reward_congratulations,
354
+ taskchain_reward_you_won,
355
+ taskchain_reward_claiming,
356
+ taskchain_reward_claim,
357
+ taskchain_nft_claim_failed,
358
+ taskchain_reward_token_label,
359
+ taskchain_value_label,
360
+ taskchain_reward_type_cap,
361
+ taskchain_reward_type_nft,
362
+ taskchain_nft_cta_mint,
363
+ taskchain_nft_cta_view,
364
+ taskchain_nft_claim_not_supported,
365
+ taskchain_nft_alt,
366
+ taskchain_chain_alt,
367
+ taskchain_nft_claim_dialog_claim_nft,
368
+ taskchain_nft_claim_dialog_claiming_nft,
369
+ taskchain_nft_claim_dialog_connecting_wallet,
370
+ taskchain_nft_claim_dialog_switching_network,
371
+ taskchain_nft_claim_dialog_getting_signature,
372
+ taskchain_nft_claim_dialog_confirm_in_wallet,
373
+ taskchain_nft_claim_dialog_tx_pending,
374
+ taskchain_nft_claim_dialog_success,
375
+ taskchain_nft_claim_dialog_failed,
376
+ taskchain_nft_claim_dialog_canceled,
377
+ taskchain_nft_claim_dialog_view_explorer,
378
+ taskchain_nft_claim_dialog_retry,
379
+ taskchain_nft_claim_dialog_close,
380
+ taskchain_nft_pending_dialog_title,
381
+ taskchain_nft_pending_dialog_desc,
382
+ taskchain_nft_pending_dialog_check_explorer,
383
+ taskchain_nft_pending_dialog_hash_label,
384
+ taskchain_nft_pending_dialog_claim_again_warn,
385
+ taskchain_nft_pending_dialog_receive_address_fixed,
386
+ taskchain_nft_pending_dialog_claim_again,
387
+ taskchain_nft_pending_dialog_continue_waiting
248
388
  };
249
389
  const loadMessages = createLocaleLoader(
250
390
  enMessages,
251
391
  {
252
- ko: () => import("./communitytask-ko-BD0hzQSi.js").then((module) => ({
392
+ ko: () => import("./communitytask-ko-Bf24PQKI.js").then((module) => ({
253
393
  default: module.default
254
394
  })),
255
- ja: () => import("./communitytask-ja-CmW6nP-L.js").then((module) => ({
395
+ ja: () => import("./communitytask-ja-GRf9cbdx.js").then((module) => ({
256
396
  default: module.default
257
397
  })),
258
- ru: () => import("./communitytask-ru-DhySaZL8.js").then((module) => ({
398
+ ru: () => import("./communitytask-ru-CZm2CPoV.js").then((module) => ({
259
399
  default: module.default
260
400
  })),
261
- es: () => import("./communitytask-es-1zawvXEX.js").then((module) => ({
401
+ es: () => import("./communitytask-es-CBNnS4o2.js").then((module) => ({
262
402
  default: module.default
263
403
  }))
264
404
  }
@@ -303,7 +443,6 @@ function ClaimButton({
303
443
  }) {
304
444
  const { t } = useCommunityTaskLocale();
305
445
  const [internalLoading, setInternalLoading] = useState(false);
306
- const [showWalletDialog, setShowWalletDialog] = useState(false);
307
446
  const needBindCheck = !claimDialog;
308
447
  const reAuthRef = useRef(null);
309
448
  const executeClaimAction = useCallback(async (token) => {
@@ -335,20 +474,13 @@ function ClaimButton({
335
474
  onAuthSuccess: handleAuthSuccess
336
475
  });
337
476
  reAuthRef.current = reAuth;
338
- const { bindIfNeed: bindWalletIfNeed, bindWithProvider, isBinding: isBindingWallet } = useBindWallet({
477
+ const { bindIfNeed: bindWalletIfNeed, isBinding: isBindingWallet } = useBindWallet({
339
478
  chainType: needBindCheck ? chainType : void 0,
340
479
  onSuccess: async () => {
341
- setShowWalletDialog(false);
342
480
  await executeClaimAction();
343
481
  },
344
- onFailed: onBindFailed,
345
- onNeedWalletDialog: () => {
346
- setShowWalletDialog(true);
347
- }
482
+ onFailed: onBindFailed
348
483
  });
349
- const handleWalletConnect = useCallback(async (address, provider) => {
350
- await bindWithProvider(address, provider);
351
- }, [bindWithProvider]);
352
484
  const buttonLabel = (() => {
353
485
  if (customLabel) return customLabel;
354
486
  if (mini) return t("update");
@@ -391,46 +523,35 @@ function ClaimButton({
391
523
  },
392
524
  [isDisabled, claimDialog, onShowDialog, snsType, chainType, bindSocialIfNeed, bindWalletIfNeed, executeClaimAction]
393
525
  );
394
- return /* @__PURE__ */ jsxs(Fragment, { children: [
395
- /* @__PURE__ */ jsx(
396
- "button",
397
- {
398
- type: "button",
399
- className: buttonClass,
400
- disabled: isDisabled,
401
- onClick: handleClick,
402
- children: isSubmitting || internalLoading || isWaitingAuth || isBindingWallet ? /* @__PURE__ */ jsx("span", { className: mini ? "taskon-community-task-claim-mini-loading" : "taskon-community-task-claim-loading", children: /* @__PURE__ */ jsx(
403
- "svg",
404
- {
405
- className: mini ? "taskon-community-task-claim-mini-spinner" : "taskon-community-task-claim-spinner",
406
- viewBox: "0 0 24 24",
407
- fill: "none",
408
- children: /* @__PURE__ */ jsx(
409
- "circle",
410
- {
411
- cx: "12",
412
- cy: "12",
413
- r: "10",
414
- stroke: "currentColor",
415
- strokeWidth: "3",
416
- strokeLinecap: "round",
417
- strokeDasharray: "31.4 31.4"
418
- }
419
- )
420
- }
421
- ) }) : buttonLabel
422
- }
423
- ),
424
- /* @__PURE__ */ jsx(
425
- BindWalletDialog,
426
- {
427
- open: showWalletDialog,
428
- onOpenChange: setShowWalletDialog,
429
- onConnect: handleWalletConnect,
430
- onError: onBindFailed
431
- }
432
- )
433
- ] });
526
+ return /* @__PURE__ */ jsx(
527
+ "button",
528
+ {
529
+ type: "button",
530
+ className: buttonClass,
531
+ disabled: isDisabled,
532
+ onClick: handleClick,
533
+ children: isSubmitting || internalLoading || isWaitingAuth || isBindingWallet ? /* @__PURE__ */ jsx("span", { className: mini ? "taskon-community-task-claim-mini-loading" : "taskon-community-task-claim-loading", children: /* @__PURE__ */ jsx(
534
+ "svg",
535
+ {
536
+ className: mini ? "taskon-community-task-claim-mini-spinner" : "taskon-community-task-claim-spinner",
537
+ viewBox: "0 0 24 24",
538
+ fill: "none",
539
+ children: /* @__PURE__ */ jsx(
540
+ "circle",
541
+ {
542
+ cx: "12",
543
+ cy: "12",
544
+ r: "10",
545
+ stroke: "currentColor",
546
+ strokeWidth: "3",
547
+ strokeLinecap: "round",
548
+ strokeDasharray: "31.4 31.4"
549
+ }
550
+ )
551
+ }
552
+ ) }) : buttonLabel
553
+ }
554
+ );
434
555
  }
435
556
  function formatCountdown$1(valueMillSec) {
436
557
  if (valueMillSec <= 0) {
@@ -2687,6 +2808,7 @@ function TaskChainCard({
2687
2808
  className = "",
2688
2809
  onOpen
2689
2810
  }) {
2811
+ const { t } = useCommunityTaskLocale();
2690
2812
  const isLocked = useMemo(() => {
2691
2813
  return isLockedByPreDayChallenge(meetConditions);
2692
2814
  }, [meetConditions]);
@@ -2712,10 +2834,10 @@ function TaskChainCard({
2712
2834
  });
2713
2835
  return {
2714
2836
  icon: params.token_icon || TOKEN_ICON,
2715
- name: params.token_name || "",
2837
+ name: params.token_name || t("taskchain_token_fallback"),
2716
2838
  amount
2717
2839
  };
2718
- }, [taskChain.reward_list]);
2840
+ }, [taskChain.reward_list, t]);
2719
2841
  const pointsReward = useMemo(() => {
2720
2842
  const reward = taskChain.reward_list.find(
2721
2843
  (r) => r.reward_type === RewardType.GTCPoints
@@ -2725,10 +2847,10 @@ function TaskChainCard({
2725
2847
  if (!params) return null;
2726
2848
  return {
2727
2849
  icon: params.points_icon || POINTS_ICON,
2728
- name: params.points_name || "Points",
2850
+ name: params.points_name || t("taskchain_points_fallback"),
2729
2851
  amount: params.amount || 0
2730
2852
  };
2731
- }, [taskChain.reward_list]);
2853
+ }, [taskChain.reward_list, t]);
2732
2854
  const nftReward = useMemo(() => {
2733
2855
  const reward = taskChain.reward_list.find(
2734
2856
  (r) => r.reward_type === RewardType.BMintedNft
@@ -2739,9 +2861,9 @@ function TaskChainCard({
2739
2861
  const icon = params.media_type === MediaType.Video || !params.nft_cdn_image ? NFT_ICON$1 : getMiniNftCdnUrl$1(params.nft_cdn_image);
2740
2862
  return {
2741
2863
  icon,
2742
- name: params.nft_collection_name || "NFT"
2864
+ name: params.nft_collection_name || t("taskchain_nft_fallback")
2743
2865
  };
2744
- }, [taskChain.reward_list]);
2866
+ }, [taskChain.reward_list, t]);
2745
2867
  const handleClick = useCallback(() => {
2746
2868
  if (disabled || isEnded || isLocked) return;
2747
2869
  onOpen == null ? void 0 : onOpen(taskChain.id);
@@ -2765,7 +2887,7 @@ function TaskChainCard({
2765
2887
  children: [
2766
2888
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-card-name", children: taskChain.name }),
2767
2889
  taskChain.token_reward_quantity > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-card-spots", children: [
2768
- /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-card-spots-label", children: "Spots left" }),
2890
+ /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-card-spots-label", children: t("taskchain_spots_left") }),
2769
2891
  /* @__PURE__ */ jsxs("span", { children: [
2770
2892
  taskChain.token_reward_left_quantity,
2771
2893
  "/",
@@ -2818,15 +2940,15 @@ function TaskChainCard({
2818
2940
  )
2819
2941
  ] })
2820
2942
  ] }),
2821
- isCompleted && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-card-won", children: "Won" })
2943
+ isCompleted && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-card-won", children: t("taskchain_won") })
2822
2944
  ] }),
2823
- isEnded && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-card-overlay taskon-taskchain-card-overlay--ended", children: /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-card-overlay-text", children: "Ended" }) }),
2945
+ isEnded && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-card-overlay taskon-taskchain-card-overlay--ended", children: /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-card-overlay-text", children: t("taskchain_ended") }) }),
2824
2946
  isLocked && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-card-overlay taskon-taskchain-card-overlay--locked", children: [
2825
2947
  /* @__PURE__ */ jsx(
2826
2948
  "img",
2827
2949
  {
2828
2950
  src: LOCK_ICON,
2829
- alt: "Locked",
2951
+ alt: t("taskchain_locked"),
2830
2952
  className: "taskon-taskchain-card-lock-icon"
2831
2953
  }
2832
2954
  ),
@@ -2835,22 +2957,19 @@ function TaskChainCard({
2835
2957
  "img",
2836
2958
  {
2837
2959
  src: LOCK_ICON,
2838
- alt: "Locked",
2960
+ alt: t("taskchain_locked"),
2839
2961
  className: "taskon-taskchain-card-lock-icon"
2840
2962
  }
2841
2963
  ),
2842
2964
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-card-lock-text", children: [
2843
2965
  /* @__PURE__ */ jsxs("div", { children: [
2844
- "Complete the",
2966
+ t("taskchain_unlock_prefix"),
2845
2967
  " ",
2846
- /* @__PURE__ */ jsxs("span", { className: "taskon-taskchain-card-lock-highlight", children: [
2847
- "Day ",
2848
- previousDayNumber,
2849
- " challenge"
2850
- ] }),
2851
- ","
2968
+ /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-card-lock-highlight", children: t("taskchain_unlock_day_challenge", {
2969
+ day: previousDayNumber
2970
+ }) })
2852
2971
  ] }),
2853
- /* @__PURE__ */ jsx("div", { children: "then wait until next day to unlock" })
2972
+ /* @__PURE__ */ jsx("div", { children: t("taskchain_unlock_suffix") })
2854
2973
  ] })
2855
2974
  ] })
2856
2975
  ] })
@@ -2896,6 +3015,7 @@ function useTaskChainStore(options) {
2896
3015
  function useTaskChainDetail(options) {
2897
3016
  const { campaignId, enabled = true } = options;
2898
3017
  const { client, isLoggedIn } = useTaskOnContext();
3018
+ const { t } = useCommunityTaskLocale();
2899
3019
  const [campaign, setCampaign] = useState(null);
2900
3020
  const [userStatus, setUserStatus] = useState(null);
2901
3021
  const [campaignStatusInfo, setCampaignStatusInfo] = useState(null);
@@ -2911,22 +3031,22 @@ function useTaskChainDetail(options) {
2911
3031
  const result = await api.getCampaignInfo({ campaign_id: campaignId });
2912
3032
  setCampaign(result);
2913
3033
  } catch (err) {
2914
- const errorMessage = err instanceof Error ? err.message : "Failed to load campaign info";
3034
+ const errorMessage = err instanceof Error ? err.message : t("taskchain_error_load_campaign_info");
2915
3035
  setError(errorMessage);
2916
3036
  console.error("[useTaskChainDetail] Error loading campaign:", err);
2917
3037
  }
2918
- }, [enabled, api, campaignId]);
3038
+ }, [enabled, api, campaignId, t]);
2919
3039
  const fetchUserStatus = useCallback(async () => {
2920
3040
  if (!enabled || !api || !campaignId || !isLoggedIn) return;
2921
3041
  try {
2922
3042
  const result = await api.getUserCampaignStatus({ campaign_id: campaignId });
2923
3043
  setUserStatus(result);
2924
3044
  } catch (err) {
2925
- const errorMessage = err instanceof Error ? err.message : "Failed to load user status";
3045
+ const errorMessage = err instanceof Error ? err.message : t("taskchain_error_load_user_status");
2926
3046
  setError(errorMessage);
2927
3047
  console.error("[useTaskChainDetail] Error loading user status:", err);
2928
3048
  }
2929
- }, [enabled, api, campaignId, isLoggedIn]);
3049
+ }, [enabled, api, campaignId, isLoggedIn, t]);
2930
3050
  const fetchCampaignStatusInfo = useCallback(async () => {
2931
3051
  if (!enabled || !api || !campaignId) return;
2932
3052
  try {
@@ -3004,6 +3124,7 @@ function StepIndicator({
3004
3124
  children,
3005
3125
  className = ""
3006
3126
  }) {
3127
+ const { t } = useCommunityTaskLocale();
3007
3128
  const stepBars = Array.from({ length: count }, (_, index) => {
3008
3129
  const isCompleted = index < currentStep + 1;
3009
3130
  return /* @__PURE__ */ jsx(
@@ -3020,35 +3141,22 @@ function StepIndicator({
3020
3141
  "img",
3021
3142
  {
3022
3143
  src: FLAG_ICON,
3023
- alt: "Goal",
3144
+ alt: t("taskchain_goal"),
3024
3145
  className: "taskon-taskchain-step-indicator-flag"
3025
3146
  }
3026
3147
  ),
3027
3148
  children
3028
3149
  ] });
3029
3150
  }
3030
- function formatDate(timestamp) {
3151
+ function formatDate(timestamp, locale) {
3031
3152
  const ts = typeof timestamp === "string" ? parseInt(timestamp, 10) : timestamp;
3032
3153
  const ms = ts < 1e12 ? ts * 1e3 : ts;
3033
3154
  const date = new Date(ms);
3034
- const months = [
3035
- "Jan",
3036
- "Feb",
3037
- "Mar",
3038
- "Apr",
3039
- "May",
3040
- "Jun",
3041
- "Jul",
3042
- "Aug",
3043
- "Sep",
3044
- "Oct",
3045
- "Nov",
3046
- "Dec"
3047
- ];
3048
- const month = months[date.getMonth()];
3049
- const day = date.getDate().toString().padStart(2, "0");
3050
- const year = date.getFullYear();
3051
- return `${month} ${day}, ${year}`;
3155
+ return new Intl.DateTimeFormat(locale, {
3156
+ year: "numeric",
3157
+ month: "short",
3158
+ day: "2-digit"
3159
+ }).format(date);
3052
3160
  }
3053
3161
  function IconDate() {
3054
3162
  return /* @__PURE__ */ jsxs(
@@ -3086,14 +3194,16 @@ function TaskChainDetailTime({
3086
3194
  campaignStatusInfo,
3087
3195
  className = ""
3088
3196
  }) {
3197
+ const { locale } = useTaskOnContext();
3198
+ const { t } = useCommunityTaskLocale();
3089
3199
  const timeRange = useMemo(() => {
3090
3200
  if (!campaign) return "";
3091
3201
  const { start_time, end_time } = campaign;
3092
3202
  if (!start_time || !end_time) return "";
3093
- const startStr = formatDate(start_time);
3094
- const endStr = formatDate(end_time);
3203
+ const startStr = formatDate(start_time, locale);
3204
+ const endStr = formatDate(end_time, locale);
3095
3205
  return `${startStr} - ${endStr}`;
3096
- }, [campaign]);
3206
+ }, [campaign, locale]);
3097
3207
  const spots = useMemo(() => {
3098
3208
  var _a, _b, _c, _d;
3099
3209
  if (!(campaign == null ? void 0 : campaign.winner_rewards) || !((_a = campaignStatusInfo == null ? void 0 : campaignStatusInfo.statistics) == null ? void 0 : _a.winner_number))
@@ -3132,7 +3242,7 @@ function TaskChainDetailTime({
3132
3242
  ] }),
3133
3243
  timeRange && spots && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-time-divider" }),
3134
3244
  spots && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-time-item", children: [
3135
- /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-time-label", children: "Left Spots" }),
3245
+ /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-time-label", children: t("taskchain_spots_left") }),
3136
3246
  /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-time-value", children: spots })
3137
3247
  ] })
3138
3248
  ] }) });
@@ -3168,6 +3278,7 @@ function RewardDisplay({
3168
3278
  winnerRewardsSimple,
3169
3279
  className = ""
3170
3280
  }) {
3281
+ const { t } = useCommunityTaskLocale();
3171
3282
  const allRewards = useMemo(() => {
3172
3283
  return (winnerRewards == null ? void 0 : winnerRewards.flatMap(
3173
3284
  (reward) => (reward.winner_layer_rewards || []).flatMap((layer) => layer.rewards || [])
@@ -3201,17 +3312,28 @@ function RewardDisplay({
3201
3312
  totalWinners: tokenMaxWinners
3202
3313
  });
3203
3314
  }, [tokenParam, tokenHasBlindBox, tokenMaxWinners]);
3315
+ const tokenName = useMemo(
3316
+ () => (tokenParam == null ? void 0 : tokenParam.token_name) || t("taskchain_token_fallback"),
3317
+ [tokenParam == null ? void 0 : tokenParam.token_name, t]
3318
+ );
3204
3319
  const pointParam = useMemo(() => {
3205
3320
  const target = allRewards.find(
3206
3321
  (reward) => reward.reward_type === RewardType.Points || reward.reward_type === RewardType.GTCPoints
3207
3322
  );
3208
3323
  return (target == null ? void 0 : target.reward_params) || null;
3209
3324
  }, [allRewards]);
3325
+ const pointsName = useMemo(
3326
+ () => (pointParam == null ? void 0 : pointParam.points_name) || t("taskchain_points_fallback"),
3327
+ [pointParam == null ? void 0 : pointParam.points_name, t]
3328
+ );
3210
3329
  const mintedNftReward = useMemo(() => {
3211
3330
  const target = allRewards.find((reward) => reward.reward_type === RewardType.BMintedNft);
3212
3331
  return (target == null ? void 0 : target.reward_params) || null;
3213
3332
  }, [allRewards]);
3214
- const mintedNftName = useMemo(() => (mintedNftReward == null ? void 0 : mintedNftReward.nft_collection_name) || "NFT", [mintedNftReward]);
3333
+ const mintedNftName = useMemo(
3334
+ () => (mintedNftReward == null ? void 0 : mintedNftReward.nft_collection_name) || t("taskchain_nft_fallback"),
3335
+ [mintedNftReward == null ? void 0 : mintedNftReward.nft_collection_name, t]
3336
+ );
3215
3337
  const mintedNftImage = useMemo(() => {
3216
3338
  if (!mintedNftReward) return "";
3217
3339
  if (mintedNftReward.media_type === "video") return "";
@@ -3231,14 +3353,14 @@ function RewardDisplay({
3231
3353
  "img",
3232
3354
  {
3233
3355
  src: tokenParam.token_icon || DEFAULT_TOKEN_ICON$2,
3234
- alt: tokenParam.token_name || "Token",
3356
+ alt: tokenName,
3235
3357
  className: "taskon-taskchain-reward-display-icon"
3236
3358
  }
3237
3359
  ),
3238
3360
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-reward-display-text taskon-taskchain-reward-display-text--token", children: [
3239
3361
  tokenAmountDisplay,
3240
3362
  " ",
3241
- tokenParam.token_name
3363
+ tokenName
3242
3364
  ] })
3243
3365
  ] }),
3244
3366
  pointParam && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-reward-display-item", children: [
@@ -3246,14 +3368,14 @@ function RewardDisplay({
3246
3368
  "img",
3247
3369
  {
3248
3370
  src: pointParam.points_icon,
3249
- alt: pointParam.points_name || "Points",
3371
+ alt: pointsName,
3250
3372
  className: "taskon-taskchain-reward-display-icon"
3251
3373
  }
3252
3374
  ),
3253
3375
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-reward-display-text taskon-taskchain-reward-display-text--points", children: [
3254
3376
  pointParam.amount,
3255
3377
  " ",
3256
- pointParam.points_name
3378
+ pointsName
3257
3379
  ] })
3258
3380
  ] }),
3259
3381
  mintedNftReward && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-reward-display-item", children: [
@@ -3318,33 +3440,39 @@ function getMiniNftCdnUrl(url) {
3318
3440
  const separator = url.includes("?") ? "&" : "?";
3319
3441
  return `${url}${separator}x-oss-process=image/resize,m_fill,h_160,w_160`;
3320
3442
  }
3321
- const TASKCHAIN_NFT_CLAIM_MESSAGES = {
3322
- claimDialog: {
3323
- claimNft: "Claim NFT",
3324
- claimingNft: "Claiming NFT...",
3325
- claimConnectingWallet: "Connecting wallet...",
3326
- claimSwitchingNetwork: "Switching network...",
3327
- claimGettingSignature: "Getting signature...",
3328
- claimConfirmInWallet: "Please confirm in your wallet",
3329
- claimTransactionPending: "Transaction pending...",
3330
- claimSuccess: "Claim successful!",
3331
- claimFailed: "Claim failed",
3332
- claimCanceled: "Transaction was rejected by user.",
3333
- viewOnExplorer: "View on Explorer",
3334
- retry: "Retry",
3335
- close: "Close"
3336
- },
3337
- pendingDialog: {
3338
- pendingTransaction: "Pending Transaction",
3339
- claimPendingTitle: "You have already claimed this NFT, please wait for this transaction to be confirmed.",
3340
- claimPendingCheckExplorer: "You can check this transaction on explorer:",
3341
- claimPendingHashLabel: "Transaction hash:",
3342
- claimPendingClaimAgainWarn: '"Claim Again" will send a new transaction it is only recommended when you are sure there is something wrong with the current transaction.',
3343
- claimPendingReceiveAddressNoChange: "This receive address can’t be changed:",
3344
- claimAgain: "Claim Again",
3345
- continueWaiting: "Continue Waiting"
3346
- }
3347
- };
3443
+ function buildTaskChainNftClaimMessages(t) {
3444
+ return {
3445
+ claimDialog: {
3446
+ claimNft: t("taskchain_nft_claim_dialog_claim_nft"),
3447
+ claimingNft: t("taskchain_nft_claim_dialog_claiming_nft"),
3448
+ claimConnectingWallet: t("taskchain_nft_claim_dialog_connecting_wallet"),
3449
+ claimSwitchingNetwork: t("taskchain_nft_claim_dialog_switching_network"),
3450
+ claimGettingSignature: t("taskchain_nft_claim_dialog_getting_signature"),
3451
+ claimConfirmInWallet: t("taskchain_nft_claim_dialog_confirm_in_wallet"),
3452
+ claimTransactionPending: t("taskchain_nft_claim_dialog_tx_pending"),
3453
+ claimSuccess: t("taskchain_nft_claim_dialog_success"),
3454
+ claimFailed: t("taskchain_nft_claim_dialog_failed"),
3455
+ claimCanceled: t("taskchain_nft_claim_dialog_canceled"),
3456
+ viewOnExplorer: t("taskchain_nft_claim_dialog_view_explorer"),
3457
+ retry: t("taskchain_nft_claim_dialog_retry"),
3458
+ close: t("taskchain_nft_claim_dialog_close")
3459
+ },
3460
+ pendingDialog: {
3461
+ pendingTransaction: t("taskchain_nft_pending_dialog_title"),
3462
+ claimPendingTitle: t("taskchain_nft_pending_dialog_desc"),
3463
+ claimPendingCheckExplorer: t("taskchain_nft_pending_dialog_check_explorer"),
3464
+ claimPendingHashLabel: t("taskchain_nft_pending_dialog_hash_label"),
3465
+ claimPendingClaimAgainWarn: t(
3466
+ "taskchain_nft_pending_dialog_claim_again_warn"
3467
+ ),
3468
+ claimPendingReceiveAddressNoChange: t(
3469
+ "taskchain_nft_pending_dialog_receive_address_fixed"
3470
+ ),
3471
+ claimAgain: t("taskchain_nft_pending_dialog_claim_again"),
3472
+ continueWaiting: t("taskchain_nft_pending_dialog_continue_waiting")
3473
+ }
3474
+ };
3475
+ }
3348
3476
  function RightChevronIcon({ className }) {
3349
3477
  return /* @__PURE__ */ jsx(
3350
3478
  "svg",
@@ -3368,11 +3496,11 @@ function RightChevronIcon({ className }) {
3368
3496
  }
3369
3497
  );
3370
3498
  }
3371
- function getClaimedRewardDisplay(reward) {
3499
+ function getClaimedRewardDisplay(reward, labels) {
3372
3500
  if (reward.reward_type === RewardType.Token) {
3373
3501
  const rewardValue = reward.reward_value;
3374
3502
  const icon = DEFAULT_TOKEN_ICON$1;
3375
- const name = (rewardValue == null ? void 0 : rewardValue.token_name) || "Token";
3503
+ const name = (rewardValue == null ? void 0 : rewardValue.token_name) || labels.token;
3376
3504
  const rawAmount = (rewardValue == null ? void 0 : rewardValue.amount) || "0";
3377
3505
  const amount = formatLongNumber(Number(rawAmount) || 0) || rawAmount;
3378
3506
  return {
@@ -3385,7 +3513,7 @@ function getClaimedRewardDisplay(reward) {
3385
3513
  if (reward.reward_type === RewardType.GTCPoints || reward.reward_type === RewardType.Points) {
3386
3514
  const rewardValue = reward.reward_value;
3387
3515
  const icon = (rewardValue == null ? void 0 : rewardValue.points_icon) || "";
3388
- const name = (rewardValue == null ? void 0 : rewardValue.points_name) || "Points";
3516
+ const name = (rewardValue == null ? void 0 : rewardValue.points_name) || labels.points;
3389
3517
  const amount = (rewardValue == null ? void 0 : rewardValue.amount) != null ? String(rewardValue.amount) : "0";
3390
3518
  return {
3391
3519
  icon,
@@ -3407,8 +3535,20 @@ function TaskChainClaimedRewards({
3407
3535
  className
3408
3536
  }) {
3409
3537
  const { toast } = useToast();
3538
+ const { t } = useCommunityTaskLocale();
3410
3539
  const [isTokenRewardPopupOpen, setIsTokenRewardPopupOpen] = useState(false);
3411
3540
  const [isViewMyNftPopupOpen, setIsViewMyNftPopupOpen] = useState(false);
3541
+ const nftClaimMessages = useMemo(
3542
+ () => buildTaskChainNftClaimMessages(t),
3543
+ [t]
3544
+ );
3545
+ const rewardLabels = useMemo(
3546
+ () => ({
3547
+ token: t("taskchain_token_fallback"),
3548
+ points: t("taskchain_points_fallback")
3549
+ }),
3550
+ [t]
3551
+ );
3412
3552
  const {
3413
3553
  claimNftReward,
3414
3554
  isSupportedNftRewardType,
@@ -3416,15 +3556,12 @@ function TaskChainClaimedRewards({
3416
3556
  } = useNftClaimFlow({
3417
3557
  campaignId,
3418
3558
  targetType: campaignType === CampaignType.Event ? "event" : "campaign",
3419
- messages: TASKCHAIN_NFT_CLAIM_MESSAGES,
3559
+ messages: nftClaimMessages,
3420
3560
  onClaimSuccess: async () => {
3421
3561
  await (onClaimedNft == null ? void 0 : onClaimedNft());
3422
3562
  },
3423
3563
  onClaimError: (error2) => {
3424
- toast.error(error2.message || "Failed to claim NFT");
3425
- },
3426
- onWalletError: (errorMessage) => {
3427
- toast.error(errorMessage);
3564
+ toast.error(error2.message || t("taskchain_nft_claim_failed"));
3428
3565
  }
3429
3566
  });
3430
3567
  const nftClaimedRewards = useMemo(() => {
@@ -3475,12 +3612,12 @@ function TaskChainClaimedRewards({
3475
3612
  {
3476
3613
  className: `taskon-taskchain-claimed-card ${isMultiClaimed ? "taskon-taskchain-claimed-card--multi" : ""}`,
3477
3614
  children: otherClaimedRewards.map((reward, index) => {
3478
- const display = getClaimedRewardDisplay(reward);
3615
+ const display = getClaimedRewardDisplay(reward, rewardLabels);
3479
3616
  const isToken = reward.reward_type === RewardType.Token;
3480
3617
  if (isToken) {
3481
3618
  const tokenRewardValue = reward.reward_value;
3482
3619
  const rawAmount = (tokenRewardValue == null ? void 0 : tokenRewardValue.amount) || "0";
3483
- const tokenName = (tokenRewardValue == null ? void 0 : tokenRewardValue.token_name) || "Token";
3620
+ const tokenName = (tokenRewardValue == null ? void 0 : tokenRewardValue.token_name) || t("taskchain_token_fallback");
3484
3621
  const formattedAmount = formatLongNumber(Number(rawAmount) || 0) || rawAmount;
3485
3622
  const usdValue = formatTokenAmount(
3486
3623
  Number(rawAmount) * tokenPrice,
@@ -3490,7 +3627,7 @@ function TaskChainClaimedRewards({
3490
3627
  );
3491
3628
  const tooltipContent = /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-token-tooltip", children: [
3492
3629
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-token-tooltip-row", children: [
3493
- /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-token-tooltip-label", children: "Reward Token" }),
3630
+ /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-token-tooltip-label", children: t("taskchain_reward_token_label") }),
3494
3631
  /* @__PURE__ */ jsxs("span", { className: "taskon-taskchain-token-tooltip-value", children: [
3495
3632
  formattedAmount,
3496
3633
  " ",
@@ -3498,7 +3635,7 @@ function TaskChainClaimedRewards({
3498
3635
  ] })
3499
3636
  ] }),
3500
3637
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-token-tooltip-row", children: [
3501
- /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-token-tooltip-label", children: "Value" }),
3638
+ /* @__PURE__ */ jsx("span", { className: "taskon-taskchain-token-tooltip-label", children: t("taskchain_value_label") }),
3502
3639
  /* @__PURE__ */ jsxs("span", { className: "taskon-taskchain-token-tooltip-usd", children: [
3503
3640
  "≈$",
3504
3641
  usdValue
@@ -3569,13 +3706,13 @@ function TaskChainClaimedRewards({
3569
3706
  nftClaimedRewards.length > 0 && /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-claimed-nft-list", children: nftClaimedRewards.map((reward, index) => {
3570
3707
  var _a;
3571
3708
  const nftValue = reward.reward_value;
3572
- const rewardTypeLabel = reward.reward_type === RewardType.Cap ? "Cap" : "NFT";
3709
+ const rewardTypeLabel = reward.reward_type === RewardType.Cap ? t("taskchain_reward_type_cap") : t("taskchain_reward_type_nft");
3573
3710
  const nftName = (nftValue == null ? void 0 : nftValue.collection_name) || (nftValue == null ? void 0 : nftValue.title) || rewardTypeLabel;
3574
3711
  const nftImage = (nftValue == null ? void 0 : nftValue.media_type) === "video" ? "" : (nftValue == null ? void 0 : nftValue.collection_image) ? getMiniNftCdnUrl(nftValue.collection_image) : "";
3575
3712
  const chainIcon = (nftValue == null ? void 0 : nftValue.chain_icon) || "";
3576
3713
  const claimable = ((_a = reward.reward_value) == null ? void 0 : _a.claimable) ?? false;
3577
3714
  const isNftClaimSupported = isSupportedNftRewardType(reward.reward_type);
3578
- const ctaLabel = claimable ? "Mint" : "View my NFT";
3715
+ const ctaLabel = claimable ? t("taskchain_nft_cta_mint") : t("taskchain_nft_cta_view");
3579
3716
  return /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-claimed-nft-card", children: [
3580
3717
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-claimed-nft-info", children: [
3581
3718
  /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-claimed-nft-image-wrap", children: [
@@ -3583,14 +3720,14 @@ function TaskChainClaimedRewards({
3583
3720
  "img",
3584
3721
  {
3585
3722
  src: nftImage,
3586
- alt: "nft",
3723
+ alt: t("taskchain_nft_alt"),
3587
3724
  className: "taskon-taskchain-claimed-nft-image"
3588
3725
  }
3589
3726
  ) : /* @__PURE__ */ jsx(
3590
3727
  "img",
3591
3728
  {
3592
3729
  src: DEFAULT_NFT_ICON,
3593
- alt: "nft",
3730
+ alt: t("taskchain_nft_alt"),
3594
3731
  className: "taskon-taskchain-claimed-nft-image taskon-taskchain-claimed-nft-image--fallback"
3595
3732
  }
3596
3733
  ),
@@ -3598,7 +3735,7 @@ function TaskChainClaimedRewards({
3598
3735
  "img",
3599
3736
  {
3600
3737
  src: chainIcon,
3601
- alt: "chain",
3738
+ alt: t("taskchain_chain_alt"),
3602
3739
  className: "taskon-taskchain-claimed-nft-chain"
3603
3740
  }
3604
3741
  )
@@ -3615,7 +3752,7 @@ function TaskChainClaimedRewards({
3615
3752
  className: "taskon-taskchain-claimed-nft-btn",
3616
3753
  onClick: () => {
3617
3754
  if (!isNftClaimSupported) {
3618
- toast.info("NFT claim is not supported for this reward type yet.");
3755
+ toast.info(t("taskchain_nft_claim_not_supported"));
3619
3756
  return;
3620
3757
  }
3621
3758
  if (!claimable) {
@@ -3731,13 +3868,13 @@ function triggerConfetti(container) {
3731
3868
  function sleep(ms) {
3732
3869
  return new Promise((resolve) => setTimeout(resolve, ms));
3733
3870
  }
3734
- function getExpectedRewardDisplay(reward) {
3871
+ function getExpectedRewardDisplay(reward, labels) {
3735
3872
  const params = reward.reward_params;
3736
3873
  if (reward.reward_type === RewardType.Token && params) {
3737
3874
  const tokenParams = params;
3738
3875
  const icon = tokenParams.token_icon || DEFAULT_TOKEN_ICON;
3739
3876
  const amount = tokenParams.per_amount || tokenParams.total_amount || "";
3740
- const name = tokenParams.token_name || "";
3877
+ const name = tokenParams.token_name || labels.token;
3741
3878
  return {
3742
3879
  icon,
3743
3880
  text: `+ ${amount} ${name}`.trim(),
@@ -3748,7 +3885,7 @@ function getExpectedRewardDisplay(reward) {
3748
3885
  const pointsParams = params;
3749
3886
  const icon = pointsParams.points_icon || "";
3750
3887
  const amount = pointsParams.amount != null ? String(pointsParams.amount) : "";
3751
- const name = pointsParams.points_name || "Points";
3888
+ const name = pointsParams.points_name || labels.points;
3752
3889
  return {
3753
3890
  icon,
3754
3891
  text: `+ ${amount} ${name}`.trim(),
@@ -3758,7 +3895,7 @@ function getExpectedRewardDisplay(reward) {
3758
3895
  if (reward.reward_type === RewardType.BMintedNft && params) {
3759
3896
  const nftParams = params;
3760
3897
  const icon = nftParams.media_type === "video" ? "" : nftParams.nft_cdn_image || "";
3761
- const name = nftParams.nft_collection_name || "NFT";
3898
+ const name = nftParams.nft_collection_name || labels.nft;
3762
3899
  return { icon, text: name, colorClass: "" };
3763
3900
  }
3764
3901
  return { icon: "", text: "", colorClass: "" };
@@ -3774,6 +3911,7 @@ function TaskChainRewardStep({
3774
3911
  }) {
3775
3912
  const { client } = useTaskOnContext();
3776
3913
  const { toast } = useToast();
3914
+ const { t } = useCommunityTaskLocale();
3777
3915
  const containerRef = useRef(null);
3778
3916
  const isMobile = useIsMobile();
3779
3917
  const initialIsClaimed = useMemo(
@@ -3823,6 +3961,14 @@ function TaskChainRewardStep({
3823
3961
  }
3824
3962
  return 0;
3825
3963
  }, [expectedRewards]);
3964
+ const rewardLabels = useMemo(
3965
+ () => ({
3966
+ token: t("taskchain_token_fallback"),
3967
+ points: t("taskchain_points_fallback"),
3968
+ nft: t("taskchain_nft_fallback")
3969
+ }),
3970
+ [t]
3971
+ );
3826
3972
  const switchToClaimedView = useCallback(async () => {
3827
3973
  setShouldAnimate(true);
3828
3974
  if (containerRef.current) {
@@ -3845,11 +3991,11 @@ function TaskChainRewardStep({
3845
3991
  await switchToClaimedView();
3846
3992
  } catch (error2) {
3847
3993
  console.error("Failed to claim reward:", error2);
3848
- toast.error("Failed to submit campaign. Please try again.");
3994
+ toast.error(t("taskchain_reward_submit_failed"));
3849
3995
  } finally {
3850
3996
  setIsLoading(false);
3851
3997
  }
3852
- }, [isLoading, campaign, api, refetchUserStatus, switchToClaimedView, toast]);
3998
+ }, [isLoading, campaign, api, refetchUserStatus, switchToClaimedView, toast, t]);
3853
3999
  const scatterStyles = useMemo(() => {
3854
4000
  const total = expectedRewards.length;
3855
4001
  return expectedRewards.map((_, index) => {
@@ -3864,8 +4010,8 @@ function TaskChainRewardStep({
3864
4010
  });
3865
4011
  }, [expectedRewards, isSpread, isMobile]);
3866
4012
  return /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-reward-step", ref: containerRef, children: /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-reward-content", children: [
3867
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-reward-title", children: "Congratulations!" }),
3868
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-reward-subtitle", children: "You have won" }),
4013
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-reward-title", children: t("taskchain_reward_congratulations") }),
4014
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-reward-subtitle", children: t("taskchain_reward_you_won") }),
3869
4015
  showClaimedContent && /* @__PURE__ */ jsxs(
3870
4016
  "div",
3871
4017
  {
@@ -3889,7 +4035,7 @@ function TaskChainRewardStep({
3889
4035
  type: "button",
3890
4036
  className: "taskon-taskchain-btn taskon-taskchain-btn--secondary",
3891
4037
  onClick: onClose,
3892
- children: "Back"
4038
+ children: t("taskchain_back")
3893
4039
  }
3894
4040
  ) })
3895
4041
  ]
@@ -3901,7 +4047,7 @@ function TaskChainRewardStep({
3901
4047
  className: `taskon-taskchain-reward-unclaimed ${isClaimAnimating ? "taskon-taskchain-reward-unclaimed--exit" : ""}`,
3902
4048
  children: [
3903
4049
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-win-rewards", children: expectedRewards.map((reward, index) => {
3904
- const display = getExpectedRewardDisplay(reward);
4050
+ const display = getExpectedRewardDisplay(reward, rewardLabels);
3905
4051
  const style = scatterStyles[index];
3906
4052
  return /* @__PURE__ */ jsxs(
3907
4053
  "div",
@@ -3940,7 +4086,7 @@ function TaskChainRewardStep({
3940
4086
  className: "taskon-taskchain-btn taskon-taskchain-btn--primary",
3941
4087
  onClick: handleClaim,
3942
4088
  disabled: isLoading,
3943
- children: isLoading ? "Claiming..." : "Claim Reward"
4089
+ children: isLoading ? t("taskchain_reward_claiming") : t("taskchain_reward_claim")
3944
4090
  }
3945
4091
  ) })
3946
4092
  }
@@ -3999,6 +4145,7 @@ function TaskChainBlindBoxStep({
3999
4145
  }) {
4000
4146
  const { client } = useTaskOnContext();
4001
4147
  const { toast } = useToast();
4148
+ const { t } = useCommunityTaskLocale();
4002
4149
  const blindBoxDialogRef = useRef(null);
4003
4150
  const [isSubmitting, setIsSubmitting] = useState(false);
4004
4151
  const [isClaiming, setIsClaiming] = useState(false);
@@ -4060,7 +4207,7 @@ function TaskChainBlindBoxStep({
4060
4207
  await refetchUserStatus();
4061
4208
  } catch (error2) {
4062
4209
  console.error("Failed to submit campaign:", error2);
4063
- toast.error("Failed to submit campaign. Please try again.");
4210
+ toast.error(t("taskchain_blindbox_submit_failed"));
4064
4211
  setShowManualSubmit(true);
4065
4212
  } finally {
4066
4213
  setIsSubmitting(false);
@@ -4068,7 +4215,7 @@ function TaskChainBlindBoxStep({
4068
4215
  }
4069
4216
  })();
4070
4217
  await submitPromiseRef.current;
4071
- }, [campaign, api, isSubmitting, refetchUserStatus, toast]);
4218
+ }, [campaign, api, isSubmitting, refetchUserStatus, toast, t]);
4072
4219
  const handleBlindBoxOpened = useCallback(async () => {
4073
4220
  var _a;
4074
4221
  if (!campaign || !api || isClaiming) return;
@@ -4081,12 +4228,12 @@ function TaskChainBlindBoxStep({
4081
4228
  await refetchUserStatus();
4082
4229
  } catch (error2) {
4083
4230
  console.error("Failed to claim blind box:", error2);
4084
- toast.error("Failed to claim reward. Please try again.");
4231
+ toast.error(t("taskchain_blindbox_claim_failed"));
4085
4232
  (_a = blindBoxDialogRef.current) == null ? void 0 : _a.resetToUnopened();
4086
4233
  } finally {
4087
4234
  setIsClaiming(false);
4088
4235
  }
4089
- }, [campaign, api, isClaiming, refetchUserStatus, toast]);
4236
+ }, [campaign, api, isClaiming, refetchUserStatus, toast, t]);
4090
4237
  useEffect(() => {
4091
4238
  var _a;
4092
4239
  const isQualifier = ((_a = userStatus == null ? void 0 : userStatus.user_status) == null ? void 0 : _a.is_qualifier) ?? false;
@@ -4095,8 +4242,8 @@ function TaskChainBlindBoxStep({
4095
4242
  }
4096
4243
  }, [campaign, api]);
4097
4244
  if (userBlindBoxStatus === "claimed") {
4098
- const title = isOpenedButNotWon ? "Oops! Better Luck Next Time!" : "Congratulations!";
4099
- const subtitle = isOpenedButNotWon ? "Rewards Missed" : "You Have Won";
4245
+ const title = isOpenedButNotWon ? t("taskchain_blindbox_title_missed") : t("taskchain_blindbox_title_won");
4246
+ const subtitle = isOpenedButNotWon ? t("taskchain_blindbox_subtitle_missed") : t("taskchain_blindbox_subtitle_won");
4100
4247
  const displayRewards = emptyReward ? [emptyReward, ...userRewards] : userRewards;
4101
4248
  return /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-blindbox-step", children: /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-blindbox-result", children: [
4102
4249
  /* @__PURE__ */ jsx("h2", { className: "taskon-taskchain-blindbox-result-title", children: title }),
@@ -4120,7 +4267,7 @@ function TaskChainBlindBoxStep({
4120
4267
  type: "button",
4121
4268
  className: "taskon-taskchain-btn taskon-taskchain-btn--secondary",
4122
4269
  onClick: onClose,
4123
- children: "Back"
4270
+ children: t("taskchain_back")
4124
4271
  }
4125
4272
  ) })
4126
4273
  ] }) });
@@ -4138,7 +4285,7 @@ function TaskChainBlindBoxStep({
4138
4285
  if (isSubmitting && userBlindBoxStatus === "none") {
4139
4286
  return /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-blindbox-step", children: /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-blindbox-loading", children: [
4140
4287
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-spinner" }),
4141
- /* @__PURE__ */ jsx("div", { children: "Preparing your reward..." })
4288
+ /* @__PURE__ */ jsx("div", { children: t("taskchain_blindbox_preparing_reward") })
4142
4289
  ] }) });
4143
4290
  }
4144
4291
  if (showManualSubmit && userBlindBoxStatus === "none") {
@@ -4149,7 +4296,7 @@ function TaskChainBlindBoxStep({
4149
4296
  className: "taskon-taskchain-blindbox-btn",
4150
4297
  onClick: handleSubmitCampaign,
4151
4298
  disabled: isSubmitting,
4152
- children: isSubmitting ? "Submitting..." : "Retry submit"
4299
+ children: isSubmitting ? t("taskchain_blindbox_submitting") : t("taskchain_blindbox_retry_submit")
4153
4300
  }
4154
4301
  ) }) });
4155
4302
  }
@@ -4173,6 +4320,7 @@ function TaskChainMain({
4173
4320
  rewardDisplayMode,
4174
4321
  rewardRedirectUrl
4175
4322
  }) {
4323
+ const { t } = useCommunityTaskLocale();
4176
4324
  const handleVerifyAttempted = useCallback(
4177
4325
  async (_taskId, success) => {
4178
4326
  if (!task) return;
@@ -4211,7 +4359,7 @@ function TaskChainMain({
4211
4359
  );
4212
4360
  }
4213
4361
  if (!task) {
4214
- return /* @__PURE__ */ jsx("div", { children: "No task available" });
4362
+ return /* @__PURE__ */ jsx("div", { children: t("taskchain_no_task_available") });
4215
4363
  }
4216
4364
  return /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-main", children: /* @__PURE__ */ jsx(
4217
4365
  TaskItem,
@@ -4237,6 +4385,7 @@ function NotEligible({
4237
4385
  className = ""
4238
4386
  }) {
4239
4387
  const { client } = useTaskOnContext();
4388
+ const { t } = useCommunityTaskLocale();
4240
4389
  const [isRefreshing, setIsRefreshing] = useState(false);
4241
4390
  const filteredEligs = useMemo(() => {
4242
4391
  if (!(campaign == null ? void 0 : campaign.eligs)) return [];
@@ -4262,12 +4411,12 @@ function NotEligible({
4262
4411
  if (!campaign || !userStatus) {
4263
4412
  return /* @__PURE__ */ jsxs("div", { className: `taskon-taskchain-not-eligible ${className}`, children: [
4264
4413
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-emoji", children: "🔒" }),
4265
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-title", children: "Not Eligible" }),
4266
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-desc", children: "You don't meet the requirements to participate in this task chain." })
4414
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-title", children: t("taskchain_not_eligible_title") }),
4415
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-desc", children: t("taskchain_not_eligible_desc") })
4267
4416
  ] });
4268
4417
  }
4269
4418
  return /* @__PURE__ */ jsxs("div", { className: `taskon-taskchain-not-eligible ${className}`, children: [
4270
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-oops", children: "Oops!" }),
4419
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-oops", children: t("taskchain_oops") }),
4271
4420
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-not-eligible-panel", children: /* @__PURE__ */ jsx(
4272
4421
  EligibilityInfo,
4273
4422
  {
@@ -4290,6 +4439,7 @@ const endedImageUrl = new URL("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJ0
4290
4439
  function ActionEndedMask({
4291
4440
  className = ""
4292
4441
  }) {
4442
+ const { t } = useCommunityTaskLocale();
4293
4443
  return /* @__PURE__ */ jsxs("div", { className: `taskon-taskchain-ended-mask ${className}`, children: [
4294
4444
  /* @__PURE__ */ jsx(
4295
4445
  "img",
@@ -4299,13 +4449,14 @@ function ActionEndedMask({
4299
4449
  alt: ""
4300
4450
  }
4301
4451
  ),
4302
- /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-ended-mask-title", children: "Event Ended" })
4452
+ /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-ended-mask-title", children: t("taskchain_event_ended") })
4303
4453
  ] });
4304
4454
  }
4305
4455
  function NeedLoginMask({
4306
4456
  onRequestLogin,
4307
4457
  className = ""
4308
4458
  }) {
4459
+ const { t } = useCommunityTaskLocale();
4309
4460
  return /* @__PURE__ */ jsxs(
4310
4461
  "div",
4311
4462
  {
@@ -4339,7 +4490,7 @@ function NeedLoginMask({
4339
4490
  color: "var(--taskon-color-text)",
4340
4491
  marginBottom: "8px"
4341
4492
  },
4342
- children: "Login Required"
4493
+ children: t("taskchain_login_required")
4343
4494
  }
4344
4495
  ),
4345
4496
  /* @__PURE__ */ jsx(
@@ -4352,7 +4503,7 @@ function NeedLoginMask({
4352
4503
  maxWidth: "300px",
4353
4504
  lineHeight: 1.5
4354
4505
  },
4355
- children: "Please login to participate in this task chain"
4506
+ children: t("taskchain_login_prompt")
4356
4507
  }
4357
4508
  ),
4358
4509
  /* @__PURE__ */ jsx(
@@ -4377,7 +4528,7 @@ function NeedLoginMask({
4377
4528
  onMouseOut: (e) => {
4378
4529
  e.currentTarget.style.opacity = "1";
4379
4530
  },
4380
- children: "Login"
4531
+ children: t("taskchain_login_button")
4381
4532
  }
4382
4533
  )
4383
4534
  ]
@@ -4402,6 +4553,7 @@ function TaskChainDetail({
4402
4553
  }) {
4403
4554
  var _a, _b;
4404
4555
  const { isLoggedIn, requestLogin, client } = useTaskOnContext();
4556
+ const { t } = useCommunityTaskLocale();
4405
4557
  const wasLoggedInRef = useRef(isLoggedIn);
4406
4558
  const totalSteps = useMemo(() => {
4407
4559
  var _a2;
@@ -4438,24 +4590,33 @@ function TaskChainDetail({
4438
4590
  const shouldShowEndedMask = useMemo(() => {
4439
4591
  return isEnded && !isAllTasksCompleted;
4440
4592
  }, [isEnded, isAllTasksCompleted]);
4593
+ const canShowNavigation = useMemo(() => {
4594
+ return isLoggedIn && !shouldShowEndedMask && isEligible;
4595
+ }, [isLoggedIn, shouldShowEndedMask, isEligible]);
4441
4596
  const showBackButton = useMemo(() => {
4442
- return totalSteps > 1 && stepIndex > 0 && !isRewardStep;
4443
- }, [totalSteps, stepIndex, isRewardStep]);
4597
+ return canShowNavigation && totalSteps > 1 && stepIndex > 0 && !isRewardStep;
4598
+ }, [canShowNavigation, totalSteps, stepIndex, isRewardStep]);
4444
4599
  const showNextButton = useMemo(() => {
4445
4600
  var _a2;
4446
4601
  const taskCount = ((_a2 = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _a2.length) || 0;
4447
- return totalSteps > 1 && stepIndex < taskCount - 1;
4448
- }, [totalSteps, stepIndex, (_b = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _b.length]);
4602
+ return canShowNavigation && totalSteps > 1 && stepIndex < taskCount - 1;
4603
+ }, [canShowNavigation, totalSteps, stepIndex, (_b = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _b.length]);
4449
4604
  const handleBack = useCallback(() => {
4605
+ if (!canShowNavigation) {
4606
+ return;
4607
+ }
4450
4608
  if (stepIndex > 0) {
4451
4609
  onStepChange(stepIndex - 1);
4452
4610
  }
4453
- }, [stepIndex, onStepChange]);
4611
+ }, [canShowNavigation, stepIndex, onStepChange]);
4454
4612
  const handleNext = useCallback(() => {
4613
+ if (!canShowNavigation) {
4614
+ return;
4615
+ }
4455
4616
  if (stepIndex < totalSteps - 1) {
4456
4617
  onStepChange(stepIndex + 1);
4457
4618
  }
4458
- }, [stepIndex, totalSteps, onStepChange]);
4619
+ }, [canShowNavigation, stepIndex, totalSteps, onStepChange]);
4459
4620
  useEffect(() => {
4460
4621
  if (isAllTasksCompleted && !isRewardStep && campaign) {
4461
4622
  onStepChange(campaign.tasks.length);
@@ -4480,7 +4641,7 @@ function TaskChainDetail({
4480
4641
  if (isLoading) {
4481
4642
  return /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-detail", children: /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-detail-loading", children: [
4482
4643
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-spinner" }),
4483
- /* @__PURE__ */ jsx("div", { children: "Loading..." })
4644
+ /* @__PURE__ */ jsx("div", { children: t("taskchain_loading") })
4484
4645
  ] }) });
4485
4646
  }
4486
4647
  const renderContent = () => {
@@ -4565,7 +4726,7 @@ function TaskChainDetail({
4565
4726
  type: "button",
4566
4727
  className: "taskon-taskchain-btn taskon-taskchain-btn--secondary",
4567
4728
  onClick: handleBack,
4568
- children: "Back"
4729
+ children: t("taskchain_back")
4569
4730
  }
4570
4731
  ),
4571
4732
  showNextButton && /* @__PURE__ */ jsx(
@@ -4574,7 +4735,7 @@ function TaskChainDetail({
4574
4735
  type: "button",
4575
4736
  className: "taskon-taskchain-btn taskon-taskchain-btn--primary",
4576
4737
  onClick: handleNext,
4577
- children: "Next"
4738
+ children: t("taskchain_next")
4578
4739
  }
4579
4740
  )
4580
4741
  ] })
@@ -4705,6 +4866,7 @@ function TaskChainDialog({
4705
4866
  rewardRedirectUrl
4706
4867
  }) {
4707
4868
  var _a, _b;
4869
+ const { t } = useCommunityTaskLocale();
4708
4870
  const {
4709
4871
  campaign,
4710
4872
  userStatus,
@@ -4768,7 +4930,7 @@ function TaskChainDialog({
4768
4930
  }, [(_b = userStatus == null ? void 0 : userStatus.user_status) == null ? void 0 : _b.is_winner, onUpdate]);
4769
4931
  return /* @__PURE__ */ jsx(BottomDialog, { open, onClose, top: "6vh", children: /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-dialog-content", children: [
4770
4932
  error2 && /* @__PURE__ */ jsxs("div", { className: "taskon-taskchain-dialog-error", children: [
4771
- /* @__PURE__ */ jsx("div", { children: "Failed to load task chain" }),
4933
+ /* @__PURE__ */ jsx("div", { children: t("taskchain_error_load_chain") }),
4772
4934
  /* @__PURE__ */ jsx("div", { className: "taskon-taskchain-dialog-error-detail", children: error2 })
4773
4935
  ] }),
4774
4936
  !error2 && /* @__PURE__ */ jsx(
@@ -6745,6 +6907,12 @@ function mergeCommunityTaskConfig(props, cloud) {
6745
6907
  rewardRedirectUrl: props.rewardRedirectUrl ?? (cloud == null ? void 0 : cloud.rewardRedirectUrl) ?? ""
6746
6908
  };
6747
6909
  }
6910
+ function toSectorIdsKey(sectorIds) {
6911
+ if (!sectorIds || sectorIds.length === 0) {
6912
+ return "all";
6913
+ }
6914
+ return sectorIds.join(",");
6915
+ }
6748
6916
  function findTaskByIdFromCards(data, taskId) {
6749
6917
  for (const sectorItem of data) {
6750
6918
  const found = sectorItem.cards.find((card) => card.card_info.id === taskId);
@@ -6826,8 +6994,10 @@ function CommunityTaskListInner(props) {
6826
6994
  rewardDisplayMode = "popup",
6827
6995
  rewardRedirectUrl = ""
6828
6996
  } = props;
6829
- const { client, userToken } = useTaskOnContext();
6997
+ const { client, userToken, isSessionReady } = useTaskOnContext();
6830
6998
  const { t } = useCommunityTaskLocale();
6999
+ const inFlightLoadKeyRef = useRef(null);
7000
+ const lastSuccessfulLoadKeyRef = useRef(null);
6831
7001
  const [taskCards, setTaskCards] = useState(
6832
7002
  []
6833
7003
  );
@@ -6875,11 +7045,25 @@ function CommunityTaskListInner(props) {
6875
7045
  }, [initialTaskChainId]);
6876
7046
  useEffect(() => {
6877
7047
  const loadTasks = async () => {
7048
+ if (!isSessionReady) {
7049
+ setError(null);
7050
+ setIsLoading(true);
7051
+ return;
7052
+ }
6878
7053
  if (!client) {
6879
- setError(t("client_not_initialized"));
7054
+ setError({ type: "localized", key: "client_not_initialized" });
6880
7055
  setIsLoading(false);
6881
7056
  return;
6882
7057
  }
7058
+ const clientToken = client.getUserToken();
7059
+ const loadKey = [
7060
+ isPreview ? "preview" : "normal",
7061
+ toSectorIdsKey(sectorIds),
7062
+ clientToken ?? "anonymous"
7063
+ ].join("|");
7064
+ if (inFlightLoadKeyRef.current === loadKey) return;
7065
+ if (lastSuccessfulLoadKeyRef.current === loadKey) return;
7066
+ inFlightLoadKeyRef.current = loadKey;
6883
7067
  try {
6884
7068
  setIsLoading(true);
6885
7069
  setError(null);
@@ -6889,15 +7073,21 @@ function CommunityTaskListInner(props) {
6889
7073
  ...sectorIds && sectorIds.length > 0 ? { sector_id: sectorIds } : {}
6890
7074
  });
6891
7075
  setTaskCards(data);
7076
+ lastSuccessfulLoadKeyRef.current = loadKey;
6892
7077
  } catch (err) {
6893
- setError(err instanceof Error ? err.message : t("failed_to_load"));
7078
+ setError(
7079
+ err instanceof Error ? { type: "raw", message: err.message } : { type: "localized", key: "failed_to_load" }
7080
+ );
6894
7081
  console.error("Failed to load community tasks:", err);
6895
7082
  } finally {
7083
+ if (inFlightLoadKeyRef.current === loadKey) {
7084
+ inFlightLoadKeyRef.current = null;
7085
+ }
6896
7086
  setIsLoading(false);
6897
7087
  }
6898
7088
  };
6899
7089
  loadTasks();
6900
- }, [client, isPreview, userToken, sectorIds, t]);
7090
+ }, [client, isSessionReady, isPreview, userToken, sectorIds]);
6901
7091
  const selectorOptions = React__default.useMemo(() => {
6902
7092
  const sectors = taskCards.map((item) => item.sector);
6903
7093
  let options = sectors.map((sector) => ({
@@ -7161,7 +7351,8 @@ function CommunityTaskListInner(props) {
7161
7351
  const isDialogOpen = openTask !== null || openTaskId !== null;
7162
7352
  const currentSelectorValue = selectedSectorId ?? void 0;
7163
7353
  if (error2) {
7164
- return /* @__PURE__ */ jsx("div", { className: "taskon-community-list", children: /* @__PURE__ */ jsx("div", { className: "taskon-community-list-error", children: error2 }) });
7354
+ const errorMessage = error2.type === "raw" ? error2.message : t(error2.key);
7355
+ return /* @__PURE__ */ jsx("div", { className: "taskon-community-list", children: /* @__PURE__ */ jsx("div", { className: "taskon-community-list-error", children: errorMessage }) });
7165
7356
  }
7166
7357
  return /* @__PURE__ */ jsxs("div", { className: "taskon-community-list", children: [
7167
7358
  showSectorTab && !isLoading && /* @__PURE__ */ jsx(
@@ -7229,11 +7420,5 @@ function CommunityTaskListInner(props) {
7229
7420
  ] });
7230
7421
  }
7231
7422
  export {
7232
- BaseTask as B,
7233
- CardSelector as C,
7234
- TemplateTask as T,
7235
- CommunityTaskList as a,
7236
- useTaskTime as b,
7237
- useSubmitTask as c,
7238
- useTaskReward as u
7423
+ CommunityTaskList as C
7239
7424
  };