@taskon/widget-react 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +118 -64
  2. package/dist/CommunityTaskList.css +2694 -2951
  3. package/dist/EligibilityInfo.css +2221 -1332
  4. package/dist/LeaderboardWidget.css +403 -198
  5. package/dist/PageBuilder.css +57 -0
  6. package/dist/Quest.css +1347 -1477
  7. package/dist/TaskOnProvider.css +337 -29
  8. package/dist/ThemeProvider.css +228 -0
  9. package/dist/UserCenterWidget.css +168 -0
  10. package/dist/UserCenterWidget2.css +4917 -0
  11. package/dist/WidgetShell.css +417 -130
  12. package/dist/chunks/{CommunityTaskList-CrH6r4Av.js → CommunityTaskList-2nFy6l6m.js} +2612 -2074
  13. package/dist/chunks/{EligibilityInfo-DesW9-k9.js → EligibilityInfo-CKTl_cdU.js} +2714 -4077
  14. package/dist/chunks/{LeaderboardWidget-BSGpHKTk.js → LeaderboardWidget-DyoiiNS6.js} +288 -349
  15. package/dist/chunks/PageBuilder-DHM3Il6f.js +150 -0
  16. package/dist/chunks/{Quest-uSIVq78I.js → Quest-Dqx4OCat.js} +1380 -726
  17. package/dist/chunks/TaskOnProvider-CxtFIs3n.js +2072 -0
  18. package/dist/chunks/{WidgetShell-NlOgn1x5.js → ThemeProvider-CulHkqqY.js} +1397 -103
  19. package/dist/chunks/UserCenterWidget-SE5hqpnZ.js +8335 -0
  20. package/dist/chunks/UserCenterWidget-XL6LZRZM.js +3259 -0
  21. package/dist/chunks/{Table-CWGf2FKV.js → WidgetShell-8xn-Jivw.js} +237 -27
  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-CZm2CPoV.js +521 -0
  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-Dyyy0zaw.js +863 -0
  31. package/dist/chunks/quest-ja-Depog33y.js +863 -0
  32. package/dist/chunks/quest-ko-BMu3uRQJ.js +863 -0
  33. package/dist/chunks/quest-ru-xne814Rw.js +863 -0
  34. package/dist/chunks/taskwidget-es-Do9b3Mqw.js +245 -0
  35. package/dist/chunks/taskwidget-ja-CqSu-yWA.js +245 -0
  36. package/dist/chunks/taskwidget-ko-EHgXFV4B.js +245 -0
  37. package/dist/chunks/taskwidget-ru-CMbLQDK4.js +245 -0
  38. package/dist/chunks/useIsMobile-D6Ybur-6.js +30 -0
  39. package/dist/chunks/usercenter-es-Dz3Wp2vV.js +512 -0
  40. package/dist/chunks/usercenter-ja-CKE4DJC6.js +512 -0
  41. package/dist/chunks/usercenter-ko-Dtpkn2qb.js +512 -0
  42. package/dist/chunks/usercenter-ru-DnBGee45.js +512 -0
  43. package/dist/community-task.d.ts +29 -388
  44. package/dist/community-task.js +2 -7
  45. package/dist/core.d.ts +95 -28
  46. package/dist/core.js +11 -12
  47. package/dist/index.d.ts +260 -602
  48. package/dist/index.js +28 -7361
  49. package/dist/leaderboard.d.ts +5 -496
  50. package/dist/leaderboard.js +2 -15
  51. package/dist/page-builder.d.ts +20 -0
  52. package/dist/page-builder.js +4 -0
  53. package/dist/quest.d.ts +20 -292
  54. package/dist/quest.js +2 -5
  55. package/dist/user-center.d.ts +56 -0
  56. package/dist/user-center.js +4 -0
  57. package/package.json +22 -3
  58. package/dist/Table.css +0 -389
  59. package/dist/chunks/TaskOnProvider-QMwxGL44.js +0 -1435
  60. package/dist/chunks/ThemeProvider-Cs8IUVQj.js +0 -1118
  61. package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +0 -119
  62. package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +0 -119
  63. package/dist/chunks/useWidgetLocale-BVcopbZS.js +0 -74
  64. package/dist/chunks/usercenter-ja-DBj_dtuz.js +0 -329
  65. package/dist/chunks/usercenter-ko-DYTkHAld.js +0 -329
  66. package/dist/index.css +0 -3662
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import React__default, { useState, useMemo, useCallback, useEffect, useRef } from "react";
3
- import { RewardType, UserEligibleStatus, EligibilityTemplateId, SnsType, ChainType, QuestAutomaticallyWinnerDrawType, QuestWinnerDrawType, QuestWinnerRangeType, createQuestApi, QuestRewardsDistributeType, QuestRewardType, createLeaderboardApi, MediaType, RewardDistributedByType } from "@taskon/core";
4
- import { b as useTaskOnContext } from "./ThemeProvider-Cs8IUVQj.js";
5
- import { D as Dialog, u as useResolvedWidgetConfig, W as WidgetShell } from "./WidgetShell-NlOgn1x5.js";
3
+ import { RewardType, UserEligibleStatus, EligibilityTemplateId, SnsType, ChainType, QuestAutomaticallyWinnerDrawType, QuestWinnerDrawType, QuestWinnerRangeType, createQuestApi, QuestRewardsDistributeType, QuestRewardType, createLeaderboardApi, MediaType, RewardDistributedByType, ApiError, ErrorCode, CampaignType } from "@taskon/core";
4
+ import { D as Dialog, E as useTaskOnPortalContainer, h as useTaskOnContext } from "./ThemeProvider-CulHkqqY.js";
5
+ import { d as useTaskWidgetLocale, b as TaskItem, e as useQuestLocale, I as I18nT, f as EligibilityList, g as getDefaultExportFromCjs, s as sanitizeHtml, R as RewardModuleDialog, u as useBindWallet, a as useNftClaimFlow, E as EligibilityInfo, B as BlindBoxDialog } from "./EligibilityInfo-CKTl_cdU.js";
6
+ import { B as Button, T as Table, P as Pagination, u as useResolvedWidgetConfig, W as WidgetShell } from "./WidgetShell-8xn-Jivw.js";
6
7
  import { c as useToast } from "./useToast-BGJhd3BX.js";
7
- import { e as TaskItem, g as EligibilityList, h as getDefaultExportFromCjs, R as Root2, i as Trigger, P as Portal, C as Content2, s as sanitizeHtml, I as InfoIcon, A as Arrow2, T as TipPopover, u as useBindSocialAccount, b as useBindWallet, E as EligibilityInfo, d as BlindBoxDialog, B as BlindBoxRewardDialog } from "./EligibilityInfo-DesW9-k9.js";
8
- import { B as Button, T as Table, P as Pagination } from "./Table-CWGf2FKV.js";
8
+ import { R as Root2, h as Trigger, i as Portal, C as Content2, r as InfoIcon, j as Arrow2, p as TipPopover, q as ConfirmNoticeDialog, a as useBindSocialAccount } from "./UserCenterWidget-SE5hqpnZ.js";
9
9
  import '../Quest.css';function ButtonTabs({
10
10
  items,
11
11
  activeKey,
@@ -131,7 +131,7 @@ function GreenCheckIcon() {
131
131
  "path",
132
132
  {
133
133
  d: "M1 4L4.5 7.5L11 1",
134
- stroke: "#22c55e",
134
+ stroke: "currentColor",
135
135
  strokeWidth: "2",
136
136
  strokeLinecap: "round",
137
137
  strokeLinejoin: "round"
@@ -143,6 +143,7 @@ function GreenCheckIcon() {
143
143
  function CompletedCount({
144
144
  current,
145
145
  total,
146
+ completedLabel = "Completed",
146
147
  className
147
148
  }) {
148
149
  const isAllCompleted = current >= total && total > 0;
@@ -153,7 +154,8 @@ function CompletedCount({
153
154
  /* @__PURE__ */ jsx("span", { className: current > 0 ? "taskon-completed-count-em" : "", children: current }),
154
155
  "/",
155
156
  total,
156
- ") Completed"
157
+ ") ",
158
+ completedLabel
157
159
  ] })
158
160
  ] });
159
161
  }
@@ -195,6 +197,7 @@ function TaskList({
195
197
  optionalTasks = [],
196
198
  userTaskStatus,
197
199
  onTaskCompleted,
200
+ onVerifyAttempted,
198
201
  onBeforeVerify,
199
202
  disabled = false,
200
203
  minOptionalTasks,
@@ -205,8 +208,11 @@ function TaskList({
205
208
  isUserSubmitter,
206
209
  ownerName,
207
210
  isEnded,
211
+ onCooldownComplete,
208
212
  className
209
213
  }) {
214
+ const { t } = useTaskWidgetLocale();
215
+ const countPlaceholder = "__COUNT__";
210
216
  const completionStatus = useCompletionStatus(
211
217
  mandatoryTasks,
212
218
  optionalTasks,
@@ -216,12 +222,13 @@ function TaskList({
216
222
  return /* @__PURE__ */ jsxs("div", { className: `taskon-task-list ${className || ""}`, children: [
217
223
  mandatoryTasks.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-task-list-section taskon-task-list-section--mandatory", children: [
218
224
  showLabels && /* @__PURE__ */ jsxs("div", { className: "taskon-task-list-section-header", children: [
219
- /* @__PURE__ */ jsx("div", { className: "taskon-task-list-section-label", children: /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-title", children: "Mandatory Tasks" }) }),
225
+ /* @__PURE__ */ jsx("div", { className: "taskon-task-list-section-label", children: /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-title", children: t("mandatory_tasks") }) }),
220
226
  /* @__PURE__ */ jsx(
221
227
  CompletedCount,
222
228
  {
223
229
  current: completionStatus.mandatoryCompleted,
224
- total: completionStatus.mandatoryTotal
230
+ total: completionStatus.mandatoryTotal,
231
+ completedLabel: t("completed")
225
232
  }
226
233
  )
227
234
  ] }),
@@ -232,6 +239,7 @@ function TaskList({
232
239
  task,
233
240
  userStatus: userTaskStatus == null ? void 0 : userTaskStatus[task.id],
234
241
  onCompleted: onTaskCompleted,
242
+ onVerifyAttempted,
235
243
  onBeforeVerify,
236
244
  disabled,
237
245
  isStarted,
@@ -239,7 +247,8 @@ function TaskList({
239
247
  hasRanking,
240
248
  isUserSubmitter,
241
249
  ownerName,
242
- isEnded
250
+ isEnded,
251
+ onCooldownComplete
243
252
  },
244
253
  task.id
245
254
  )) })
@@ -247,27 +256,36 @@ function TaskList({
247
256
  optionalTasks.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-task-list-section taskon-task-list-section--optional", children: [
248
257
  /* @__PURE__ */ jsxs("div", { className: "taskon-task-list-section-header", children: [
249
258
  /* @__PURE__ */ jsxs("div", { className: "taskon-task-list-section-label", children: [
250
- /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-title", children: "Optional Tasks" }),
251
- minOptionalTasks !== void 0 && minOptionalTasks > 0 && /* @__PURE__ */ jsxs("span", { className: "taskon-task-list-section-hint", children: [
252
- "(Min.",
253
- " ",
254
- /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint-em", children: minOptionalTasks }),
255
- " ",
256
- "Required)"
257
- ] }),
258
- !minOptionalTasks && minOptionalPoints !== void 0 && minOptionalPoints > 0 && /* @__PURE__ */ jsxs("span", { className: "taskon-task-list-section-hint", children: [
259
- "(Min.",
260
- " ",
261
- /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint-em", children: minOptionalPoints }),
262
- " ",
263
- "Points Required)"
264
- ] })
259
+ /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-title", children: t("optional_tasks") }),
260
+ minOptionalTasks !== void 0 && minOptionalTasks > 0 && /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint", children: (() => {
261
+ const text = t("min_required", {
262
+ count: countPlaceholder
263
+ });
264
+ const [before, after] = text.split(countPlaceholder);
265
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
266
+ before,
267
+ /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint-em", children: minOptionalTasks }),
268
+ after
269
+ ] });
270
+ })() }),
271
+ !minOptionalTasks && minOptionalPoints !== void 0 && minOptionalPoints > 0 && /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint", children: (() => {
272
+ const text = t("min_points_required", {
273
+ count: countPlaceholder
274
+ });
275
+ const [before, after] = text.split(countPlaceholder);
276
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
277
+ before,
278
+ /* @__PURE__ */ jsx("span", { className: "taskon-task-list-section-hint-em", children: minOptionalPoints }),
279
+ after
280
+ ] });
281
+ })() })
265
282
  ] }),
266
283
  /* @__PURE__ */ jsx(
267
284
  CompletedCount,
268
285
  {
269
286
  current: completionStatus.optionalCompleted,
270
- total: completionStatus.optionalTotal
287
+ total: completionStatus.optionalTotal,
288
+ completedLabel: t("completed")
271
289
  }
272
290
  )
273
291
  ] }),
@@ -278,6 +296,7 @@ function TaskList({
278
296
  task,
279
297
  userStatus: userTaskStatus == null ? void 0 : userTaskStatus[task.id],
280
298
  onCompleted: onTaskCompleted,
299
+ onVerifyAttempted,
281
300
  onBeforeVerify,
282
301
  disabled,
283
302
  isStarted,
@@ -285,12 +304,102 @@ function TaskList({
285
304
  hasRanking,
286
305
  isUserSubmitter,
287
306
  ownerName,
288
- isEnded
307
+ isEnded,
308
+ onCooldownComplete
289
309
  },
290
310
  task.id
291
311
  )) })
292
312
  ] }),
293
- mandatoryTasks.length === 0 && optionalTasks.length === 0 && /* @__PURE__ */ jsx("div", { className: "taskon-task-list-empty", children: /* @__PURE__ */ jsx("p", { children: "No tasks available" }) })
313
+ mandatoryTasks.length === 0 && optionalTasks.length === 0 && /* @__PURE__ */ jsx("div", { className: "taskon-task-list-empty", children: /* @__PURE__ */ jsx("p", { children: t("no_tasks_available") }) })
314
+ ] });
315
+ }
316
+ function formatAmount(amount) {
317
+ const num = typeof amount === "string" ? parseFloat(amount) : amount;
318
+ if (isNaN(num)) return "0";
319
+ if (num >= 1e9) {
320
+ return `${(num / 1e9).toFixed(2)}B`;
321
+ }
322
+ if (num >= 1e6) {
323
+ return `${(num / 1e6).toFixed(2)}M`;
324
+ }
325
+ if (num >= 1e3) {
326
+ return `${(num / 1e3).toFixed(2)}K`;
327
+ }
328
+ if (num < 1 && num > 0) {
329
+ return num.toFixed(6).replace(/\.?0+$/, "");
330
+ }
331
+ return num.toFixed(2).replace(/\.?0+$/, "");
332
+ }
333
+ function formatUsdValue(amount, price) {
334
+ if (!price || price <= 0) return null;
335
+ const num = typeof amount === "string" ? parseFloat(amount) : amount;
336
+ if (isNaN(num) || num <= 0) return null;
337
+ const value = num * price;
338
+ return `≈ $${formatAmount(value)}`;
339
+ }
340
+ function RewardCard$2({
341
+ reward,
342
+ tokenPrice
343
+ }) {
344
+ const { t } = useQuestLocale();
345
+ if (reward.reward_type !== RewardType.Token) {
346
+ return null;
347
+ }
348
+ const tokenValue = reward.reward_value;
349
+ const amount = tokenValue.amount || "0";
350
+ const tokenName = tokenValue.token_name || t("token_name");
351
+ const tokenLogo = tokenValue.token_logo;
352
+ const usdValue = formatUsdValue(amount, tokenPrice);
353
+ return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-blindbox-reward-card", children: [
354
+ tokenLogo && /* @__PURE__ */ jsx(
355
+ "img",
356
+ {
357
+ className: "taskon-quest-blindbox-reward-card-icon",
358
+ src: tokenLogo,
359
+ alt: tokenName
360
+ }
361
+ ),
362
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-blindbox-reward-card-amount", children: [
363
+ "+ ",
364
+ formatAmount(amount),
365
+ " ",
366
+ tokenName
367
+ ] }),
368
+ usdValue && /* @__PURE__ */ jsx("div", { className: "taskon-quest-blindbox-reward-card-value", children: usdValue })
369
+ ] });
370
+ }
371
+ function BlindBoxRewardDialog(props) {
372
+ const { t } = useQuestLocale();
373
+ const { rewards, emptyReward, tokenPrice, loading, onClose } = props;
374
+ const hasRewards = rewards.length > 0;
375
+ const title = hasRewards ? t("congratulations") : t("oops_better_luck_next_time");
376
+ const subtitle = hasRewards ? t("won") : t("rewards_missed");
377
+ const displayRewards = useMemo(() => {
378
+ if (hasRewards) {
379
+ return rewards;
380
+ }
381
+ return emptyReward ? [emptyReward] : [];
382
+ }, [hasRewards, rewards, emptyReward]);
383
+ return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-blindbox-reward", children: [
384
+ /* @__PURE__ */ jsx("h2", { className: "taskon-quest-blindbox-reward-title", children: title }),
385
+ /* @__PURE__ */ jsx("p", { className: "taskon-quest-blindbox-reward-subtitle", children: subtitle }),
386
+ displayRewards.length > 0 && /* @__PURE__ */ jsx("div", { className: "taskon-quest-blindbox-reward-list", children: displayRewards.map((reward, index) => /* @__PURE__ */ jsx(
387
+ RewardCard$2,
388
+ {
389
+ reward,
390
+ tokenPrice
391
+ },
392
+ `${reward.reward_id}-${index}`
393
+ )) }),
394
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-blindbox-reward-btn-wrap", children: /* @__PURE__ */ jsx(
395
+ "button",
396
+ {
397
+ className: "taskon-quest-blindbox-reward-btn",
398
+ disabled: loading,
399
+ onClick: onClose,
400
+ children: loading ? t("loading") : t("close")
401
+ }
402
+ ) })
294
403
  ] });
295
404
  }
296
405
  const BLIND_BOX_DISTRIBUTE_TYPE = "BlindBox";
@@ -370,6 +479,7 @@ function EligsNotPassDialog({
370
479
  onRefresh,
371
480
  isRefreshing = false
372
481
  }) {
482
+ const { t } = useQuestLocale();
373
483
  const [isExpanded, setIsExpanded] = useState(true);
374
484
  const [currentDetails, setCurrentDetails] = useState(details);
375
485
  const isEligible = useMemo(() => {
@@ -386,7 +496,7 @@ function EligsNotPassDialog({
386
496
  const eligibleDetails = useMemo(() => {
387
497
  return currentDetails.map((d) => d.is_pass);
388
498
  }, [currentDetails]);
389
- const expressLabel = eligibilityExpress === "and" ? "all" : "any";
499
+ const expressLabel = eligibilityExpress === "and" ? t("all") : t("any");
390
500
  const handleRefresh = async () => {
391
501
  if (onRefresh) {
392
502
  await onRefresh();
@@ -400,7 +510,7 @@ function EligsNotPassDialog({
400
510
  {
401
511
  open,
402
512
  onOpenChange: (isOpen) => !isOpen && onClose(),
403
- title: isEligible ? "Congratulations" : "Oops",
513
+ title: isEligible ? t("congratulations") : t("oops"),
404
514
  showCloseButton: true,
405
515
  maxWidth: 400,
406
516
  contentClassName: "taskon-eligs-dialog",
@@ -414,17 +524,22 @@ function EligsNotPassDialog({
414
524
  className: "taskon-eligs-dialog-icon"
415
525
  }
416
526
  ),
417
- /* @__PURE__ */ jsx("h3", { className: "taskon-eligs-dialog-title", children: isEligible ? "Congratulations" : "Oops" })
527
+ /* @__PURE__ */ jsx("h3", { className: "taskon-eligs-dialog-title", children: isEligible ? t("congratulations") : t("oops") })
418
528
  ] }),
419
529
  /* @__PURE__ */ jsx(
420
530
  "p",
421
531
  {
422
532
  className: `taskon-eligs-dialog-desc ${isEligible ? "taskon-eligs-dialog-desc--success" : ""}`,
423
- children: isEligible ? "Awesome! You already meet the requirements." : /* @__PURE__ */ jsxs(Fragment, { children: [
424
- "Before you join please meet ",
425
- /* @__PURE__ */ jsx("span", { className: "taskon-eligs-dialog-highlight", children: expressLabel }),
426
- " the following Eligibilities"
427
- ] })
533
+ children: isEligible ? t("awesome_already_meet_requirements") : /* @__PURE__ */ jsx(
534
+ I18nT,
535
+ {
536
+ t,
537
+ i18nKey: "before_join_please_meet_express_following_eligibilities",
538
+ components: {
539
+ express: /* @__PURE__ */ jsx("span", { className: "taskon-eligs-dialog-highlight", children: expressLabel })
540
+ }
541
+ }
542
+ )
428
543
  }
429
544
  ),
430
545
  /* @__PURE__ */ jsxs("div", { className: "taskon-eligs-dialog-eligs", children: [
@@ -443,7 +558,7 @@ function EligsNotPassDialog({
443
558
  className: "taskon-eligs-dialog-eligs-icon"
444
559
  }
445
560
  ),
446
- /* @__PURE__ */ jsx("span", { className: "taskon-eligs-dialog-eligs-label", children: "Meet Eligibilities Below" }),
561
+ /* @__PURE__ */ jsx("span", { className: "taskon-eligs-dialog-eligs-label", children: t("meet_eligibilities_below") }),
447
562
  /* @__PURE__ */ jsx(ArrowIcon$1, { expanded: isExpanded })
448
563
  ]
449
564
  }
@@ -470,8 +585,8 @@ function EligsNotPassDialog({
470
585
  disabled: isRefreshing,
471
586
  children: isRefreshing ? /* @__PURE__ */ jsxs("span", { className: "taskon-eligs-dialog-loading", children: [
472
587
  /* @__PURE__ */ jsx("span", { className: "taskon-eligs-dialog-spinner" }),
473
- "Refreshing..."
474
- ] }) : isEligible || !onRefresh ? "OK" : "Refresh"
588
+ t("refreshing")
589
+ ] }) : isEligible || !onRefresh ? t("ok") : t("refresh")
475
590
  }
476
591
  )
477
592
  ] })
@@ -479,7 +594,7 @@ function EligsNotPassDialog({
479
594
  );
480
595
  }
481
596
  const CHAIN_TYPE_LABELS$1 = {
482
- evm: "EVM Chain",
597
+ evm: "evm_chain",
483
598
  btc: "Bitcoin",
484
599
  starknet: "Starknet",
485
600
  solana: "Solana",
@@ -491,12 +606,15 @@ const CHAIN_TYPE_LABELS$1 = {
491
606
  ton: "TON"
492
607
  };
493
608
  const SNS_TYPE_LABELS = {
494
- twitter: "X (Twitter)",
495
- discord: "Discord",
609
+ twitter: "x_twitter",
610
+ discord: "discord",
496
611
  telegram: "Telegram"
497
612
  };
498
613
  function BindItem$1({ type, bindType, isBinding, isBound, onBind }) {
499
- const label = type === "chain" ? CHAIN_TYPE_LABELS$1[bindType.toLowerCase()] || bindType : SNS_TYPE_LABELS[bindType.toLowerCase()] || bindType;
614
+ const { t } = useQuestLocale();
615
+ const chainLabelKey = CHAIN_TYPE_LABELS$1[bindType.toLowerCase()];
616
+ const snsLabelKey = SNS_TYPE_LABELS[bindType.toLowerCase()];
617
+ const label = type === "chain" ? chainLabelKey ? t(chainLabelKey) : bindType : snsLabelKey ? t(snsLabelKey) : bindType;
500
618
  return /* @__PURE__ */ jsxs("div", { className: `taskon-eligs-bind-item ${isBound ? "taskon-eligs-bind-item--bound" : ""}`, children: [
501
619
  /* @__PURE__ */ jsx("span", { className: "taskon-eligs-bind-item-label", children: label }),
502
620
  isBound ? /* @__PURE__ */ jsxs("span", { className: "taskon-eligs-bind-item-status", children: [
@@ -510,7 +628,7 @@ function BindItem$1({ type, bindType, isBinding, isBound, onBind }) {
510
628
  strokeLinejoin: "round"
511
629
  }
512
630
  ) }),
513
- "Bound"
631
+ t("bound")
514
632
  ] }) : /* @__PURE__ */ jsx(
515
633
  "button",
516
634
  {
@@ -519,8 +637,8 @@ function BindItem$1({ type, bindType, isBinding, isBound, onBind }) {
519
637
  disabled: isBinding,
520
638
  children: isBinding ? /* @__PURE__ */ jsxs(Fragment, { children: [
521
639
  /* @__PURE__ */ jsx("svg", { className: "taskon-eligs-bind-item-spinner", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeDasharray: "31.4 31.4" }) }),
522
- "Binding..."
523
- ] }) : "Bind"
640
+ t("binding")
641
+ ] }) : t("bind")
524
642
  }
525
643
  )
526
644
  ] });
@@ -530,13 +648,12 @@ function EligsBindDialog({
530
648
  chainTypes,
531
649
  snsTypes,
532
650
  campaign,
533
- skippable = false,
534
651
  onClose,
535
- onSkip,
536
652
  onAllBind,
537
653
  onBindChain,
538
654
  onBindSns
539
655
  }) {
656
+ const { t } = useQuestLocale();
540
657
  const [notBoundChains, setNotBoundChains] = useState(chainTypes);
541
658
  const [notBoundSns, setNotBoundSns] = useState(snsTypes);
542
659
  const [bindingType, setBindingType] = useState(null);
@@ -559,7 +676,7 @@ function EligsBindDialog({
559
676
  try {
560
677
  const success = await onBindChain(chainType);
561
678
  if (success) {
562
- setNotBoundChains((prev) => prev.filter((t) => t !== chainType));
679
+ setNotBoundChains((prev) => prev.filter((t2) => t2 !== chainType));
563
680
  }
564
681
  } finally {
565
682
  setBindingType(null);
@@ -570,19 +687,15 @@ function EligsBindDialog({
570
687
  try {
571
688
  const success = await onBindSns(snsType);
572
689
  if (success) {
573
- setNotBoundSns((prev) => prev.filter((t) => t !== snsType));
690
+ setNotBoundSns((prev) => prev.filter((t2) => t2 !== snsType));
574
691
  }
575
692
  } finally {
576
693
  setBindingType(null);
577
694
  }
578
695
  }, [onBindSns]);
579
696
  const handleClose = useCallback(() => {
580
- if (skippable) {
581
- onSkip == null ? void 0 : onSkip();
582
- } else {
583
- onClose();
584
- }
585
- }, [skippable, onSkip, onClose]);
697
+ onClose();
698
+ }, [onClose]);
586
699
  return /* @__PURE__ */ jsx(
587
700
  Dialog,
588
701
  {
@@ -592,12 +705,12 @@ function EligsBindDialog({
592
705
  handleClose();
593
706
  }
594
707
  },
595
- title: "Bind Required Accounts",
708
+ title: t("bind_required_accounts"),
596
709
  showCloseButton: true,
597
710
  maxWidth: 560,
598
711
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-eligs-bind-dialog", children: [
599
712
  campaign.eligs && campaign.eligs.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-eligs-bind-eligs-section", children: [
600
- /* @__PURE__ */ jsx("h3", { className: "taskon-eligs-bind-section-title", children: "Quest Eligibility" }),
713
+ /* @__PURE__ */ jsx("h3", { className: "taskon-eligs-bind-section-title", children: t("quest_eligibility") }),
601
714
  /* @__PURE__ */ jsx(
602
715
  EligibilityList,
603
716
  {
@@ -611,9 +724,9 @@ function EligsBindDialog({
611
724
  }
612
725
  )
613
726
  ] }),
614
- /* @__PURE__ */ jsx("p", { className: "taskon-eligs-bind-tip", children: skippable ? "Please bind the following accounts to verify eligibility. You can skip this step and continue with tasks." : "Please bind the following accounts to verify eligibility." }),
727
+ /* @__PURE__ */ jsx("p", { className: "taskon-eligs-bind-tip", children: t("please_bind_following_accounts_verify_eligibility") }),
615
728
  chainTypes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-eligs-bind-section", children: [
616
- /* @__PURE__ */ jsx("h4", { className: "taskon-eligs-bind-section-subtitle", children: "Wallet Address" }),
729
+ /* @__PURE__ */ jsx("h4", { className: "taskon-eligs-bind-section-subtitle", children: t("wallet_address") }),
617
730
  /* @__PURE__ */ jsx("div", { className: "taskon-eligs-bind-list", children: chainTypes.map((chainType) => /* @__PURE__ */ jsx(
618
731
  BindItem$1,
619
732
  {
@@ -627,7 +740,7 @@ function EligsBindDialog({
627
740
  )) })
628
741
  ] }),
629
742
  snsTypes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-eligs-bind-section", children: [
630
- /* @__PURE__ */ jsx("h4", { className: "taskon-eligs-bind-section-subtitle", children: "Social Accounts" }),
743
+ /* @__PURE__ */ jsx("h4", { className: "taskon-eligs-bind-section-subtitle", children: t("social_accounts") }),
631
744
  /* @__PURE__ */ jsx("div", { className: "taskon-eligs-bind-list", children: snsTypes.map((snsType) => /* @__PURE__ */ jsx(
632
745
  BindItem$1,
633
746
  {
@@ -639,20 +752,13 @@ function EligsBindDialog({
639
752
  },
640
753
  snsType
641
754
  )) })
642
- ] }),
643
- skippable && /* @__PURE__ */ jsx(
644
- "button",
645
- {
646
- className: "taskon-eligs-bind-skip-btn",
647
- onClick: onSkip,
648
- children: "Continue with Tasks"
649
- }
650
- )
755
+ ] })
651
756
  ] })
652
757
  }
653
758
  );
654
759
  }
655
760
  function useQuestDetail(options) {
761
+ const { t } = useQuestLocale();
656
762
  const {
657
763
  api,
658
764
  campaignId,
@@ -682,14 +788,14 @@ function useQuestDetail(options) {
682
788
  const result = await api.getCampaignInfo(params);
683
789
  setData(result);
684
790
  } catch (err) {
685
- const errorMessage = err instanceof Error ? err.message : "Failed to load quest detail";
791
+ const errorMessage = err instanceof Error ? err.message : t("failed_load_quest_detail");
686
792
  setError(errorMessage);
687
793
  setData(null);
688
794
  console.error("[useQuestDetail] Error:", err);
689
795
  } finally {
690
796
  setIsLoading(false);
691
797
  }
692
- }, [enabled, api, campaignId, channel, kolHandle, inviteCode, boostId]);
798
+ }, [enabled, api, campaignId, channel, kolHandle, inviteCode, boostId, t]);
693
799
  useEffect(() => {
694
800
  fetchDetail();
695
801
  }, [fetchDetail]);
@@ -701,7 +807,15 @@ function useQuestDetail(options) {
701
807
  };
702
808
  }
703
809
  function useQuestUserStatus(options) {
704
- const { api, campaignId, channel, kolHandle, enabled = true } = options;
810
+ const { t } = useQuestLocale();
811
+ const {
812
+ api,
813
+ campaignId,
814
+ channel,
815
+ kolHandle,
816
+ enabled = true,
817
+ authToken
818
+ } = options;
705
819
  const [data, setData] = useState(null);
706
820
  const [isLoading, setIsLoading] = useState(false);
707
821
  const [error, setError] = useState(null);
@@ -720,14 +834,14 @@ function useQuestUserStatus(options) {
720
834
  const result = await api.getUserCampaignStatus(params);
721
835
  setData(result);
722
836
  } catch (err) {
723
- const errorMessage = err instanceof Error ? err.message : "Failed to load user status";
837
+ const errorMessage = err instanceof Error ? err.message : t("failed_load_user_status");
724
838
  setError(errorMessage);
725
839
  setData(null);
726
840
  console.error("[useQuestUserStatus] Error:", err);
727
841
  } finally {
728
842
  setIsLoading(false);
729
843
  }
730
- }, [enabled, api, campaignId, channel, kolHandle]);
844
+ }, [enabled, api, campaignId, channel, kolHandle, authToken, t]);
731
845
  const updateTaskStatus = useCallback(
732
846
  (taskId, isAsync = false) => {
733
847
  setData((prev) => {
@@ -766,6 +880,7 @@ function useQuestUserStatus(options) {
766
880
  };
767
881
  }
768
882
  function useQuestStatus(options) {
883
+ const { t } = useQuestLocale();
769
884
  const { api, campaignId, channel, kolHandle, enabled = true } = options;
770
885
  const [data, setData] = useState(null);
771
886
  const [isLoading, setIsLoading] = useState(false);
@@ -785,14 +900,14 @@ function useQuestStatus(options) {
785
900
  const result = await api.getCampaignStatusInfo(params);
786
901
  setData(result);
787
902
  } catch (err) {
788
- const errorMessage = err instanceof Error ? err.message : "Failed to load quest status";
903
+ const errorMessage = err instanceof Error ? err.message : t("failed_load_quest_status");
789
904
  setError(errorMessage);
790
905
  setData(null);
791
906
  console.error("[useQuestStatus] Error:", err);
792
907
  } finally {
793
908
  setIsLoading(false);
794
909
  }
795
- }, [enabled, api, campaignId, channel, kolHandle]);
910
+ }, [enabled, api, campaignId, channel, kolHandle, t]);
796
911
  useEffect(() => {
797
912
  fetchStatus();
798
913
  }, [fetchStatus]);
@@ -981,17 +1096,6 @@ function useEligibilityRefresh(options) {
981
1096
  bindPromiseResolveRef.current = null;
982
1097
  }
983
1098
  }, []);
984
- const skipEligsBind = useCallback(() => {
985
- setEligsBindInfo(null);
986
- if (continueAfterBindRef.current) {
987
- continueAfterBindRef.current();
988
- continueAfterBindRef.current = null;
989
- }
990
- if (bindPromiseResolveRef.current) {
991
- bindPromiseResolveRef.current(true);
992
- bindPromiseResolveRef.current = null;
993
- }
994
- }, []);
995
1099
  const onAllEligsBind = useCallback(() => {
996
1100
  setEligsBindInfo(null);
997
1101
  if (continueAfterBindRef.current) {
@@ -1004,7 +1108,9 @@ function useEligibilityRefresh(options) {
1004
1108
  }
1005
1109
  }, []);
1006
1110
  const checkEligibilityAndNotify = useCallback(async () => {
1007
- if (!api || !campaign) return true;
1111
+ if (!api || !campaign) {
1112
+ return false;
1113
+ }
1008
1114
  if (!campaign.eligs || campaign.eligs.length === 0) {
1009
1115
  return true;
1010
1116
  }
@@ -1027,7 +1133,7 @@ function useEligibilityRefresh(options) {
1027
1133
  return false;
1028
1134
  } catch (error) {
1029
1135
  console.error("[useEligibilityRefresh] checkEligibility failed:", error);
1030
- return true;
1136
+ return false;
1031
1137
  }
1032
1138
  }, [api, campaign, campaignId, onEligibilityFailed]);
1033
1139
  const refreshInDialog = useCallback(async () => {
@@ -1058,7 +1164,10 @@ function useEligibilityRefresh(options) {
1058
1164
  }
1059
1165
  setIsRefreshing(true);
1060
1166
  try {
1061
- await checkEligibilityAndNotify();
1167
+ const passed = await checkEligibilityAndNotify();
1168
+ if (!passed) {
1169
+ return;
1170
+ }
1062
1171
  await onRefresh();
1063
1172
  } finally {
1064
1173
  setIsRefreshing(false);
@@ -1078,8 +1187,7 @@ function useEligibilityRefresh(options) {
1078
1187
  continueAfterBindRef.current = runEligibilityCheck;
1079
1188
  setEligsBindInfo({
1080
1189
  chainTypes,
1081
- snsTypes,
1082
- skippable: false
1190
+ snsTypes
1083
1191
  });
1084
1192
  return;
1085
1193
  }
@@ -1107,8 +1215,7 @@ function useEligibilityRefresh(options) {
1107
1215
  bindPromiseResolveRef.current = resolve;
1108
1216
  setEligsBindInfo({
1109
1217
  chainTypes,
1110
- snsTypes,
1111
- skippable: false
1218
+ snsTypes
1112
1219
  });
1113
1220
  });
1114
1221
  if (!bindCompleted) {
@@ -1136,7 +1243,6 @@ function useEligibilityRefresh(options) {
1136
1243
  // 绑定弹窗相关
1137
1244
  eligsBindInfo,
1138
1245
  closeEligsBindDialog,
1139
- skipEligsBind,
1140
1246
  onAllEligsBind
1141
1247
  };
1142
1248
  }
@@ -1159,7 +1265,7 @@ function getNeedBindChainTypeList(requiredChainTypes, userProfile) {
1159
1265
  (chainType) => requiredChainTypes.includes(chainType) && !boundChainTypes.includes(chainType)
1160
1266
  );
1161
1267
  }
1162
- function validateTaskCompletion(campaign, userStatus) {
1268
+ function validateTaskCompletion(campaign, userStatus, t) {
1163
1269
  const { tasks, min_finished_optional_task_num, min_finished_optional_task_points } = campaign;
1164
1270
  const { task_status_details } = userStatus;
1165
1271
  const notCompletedMandatory = tasks.find(
@@ -1171,7 +1277,7 @@ function validateTaskCompletion(campaign, userStatus) {
1171
1277
  if (notCompletedMandatory) {
1172
1278
  return {
1173
1279
  type: "mandatory",
1174
- message: "Please complete all mandatory tasks"
1280
+ message: t("please_complete_mandatory_tasks")
1175
1281
  };
1176
1282
  }
1177
1283
  if (min_finished_optional_task_num && min_finished_optional_task_num > 0) {
@@ -1185,7 +1291,7 @@ function validateTaskCompletion(campaign, userStatus) {
1185
1291
  if (completedCount < min_finished_optional_task_num) {
1186
1292
  return {
1187
1293
  type: "optional_count",
1188
- message: "Please complete more optional tasks",
1294
+ message: t("please_complete_optional_tasks"),
1189
1295
  required: min_finished_optional_task_num,
1190
1296
  current: completedCount
1191
1297
  };
@@ -1202,7 +1308,12 @@ function validateTaskCompletion(campaign, userStatus) {
1202
1308
  if (totalPoints < min_finished_optional_task_points) {
1203
1309
  return {
1204
1310
  type: "optional_points",
1205
- message: `Please earn at least ${min_finished_optional_task_points} points from optional tasks`,
1311
+ message: t(
1312
+ "please_earn_least_count_points_optional_tasks",
1313
+ {
1314
+ count: min_finished_optional_task_points
1315
+ }
1316
+ ),
1206
1317
  required: min_finished_optional_task_points,
1207
1318
  current: totalPoints
1208
1319
  };
@@ -1247,6 +1358,7 @@ function isDiscordBound(userProfile) {
1247
1358
  return (userProfile == null ? void 0 : userProfile.sns.some((item) => item.sns_type === SnsType.Discord)) || false;
1248
1359
  }
1249
1360
  function useCompleteValidation(options) {
1361
+ const { t } = useQuestLocale();
1250
1362
  const {
1251
1363
  api,
1252
1364
  campaign,
@@ -1337,7 +1449,11 @@ function useCompleteValidation(options) {
1337
1449
  onLogin == null ? void 0 : onLogin();
1338
1450
  return false;
1339
1451
  }
1340
- const taskError = validateTaskCompletion(campaign, userStatus);
1452
+ const taskError = validateTaskCompletion(
1453
+ campaign,
1454
+ userStatus,
1455
+ t
1456
+ );
1341
1457
  if (taskError) {
1342
1458
  setTaskValidationError(taskError);
1343
1459
  return false;
@@ -1352,9 +1468,7 @@ function useCompleteValidation(options) {
1352
1468
  eligsBindResolveRef.current = resolve;
1353
1469
  setEligsBindInfo({
1354
1470
  chainTypes,
1355
- snsTypes,
1356
- skippable: false
1357
- // Eligs binding is not skippable
1471
+ snsTypes
1358
1472
  });
1359
1473
  });
1360
1474
  if (!bindCompleted) {
@@ -1368,17 +1482,16 @@ function useCompleteValidation(options) {
1368
1482
  campaign_id: campaign.id
1369
1483
  });
1370
1484
  if (!result.result) {
1371
- const handled = onEligibilityFailed == null ? void 0 : onEligibilityFailed({
1485
+ onEligibilityFailed == null ? void 0 : onEligibilityFailed({
1372
1486
  eligs: campaign.eligs,
1373
1487
  eligibilityExpress: campaign.eligibility_express || "and",
1374
1488
  details: result.details
1375
1489
  });
1376
- if (!handled) {
1377
- return false;
1378
- }
1490
+ return false;
1379
1491
  }
1380
1492
  } catch (error) {
1381
1493
  console.error("[useCompleteValidation] checkEligibility failed:", error);
1494
+ return false;
1382
1495
  }
1383
1496
  }
1384
1497
  const rewardChainTypes = getRewardChainTypes(campaign.winner_rewards);
@@ -1407,12 +1520,15 @@ function useCompleteValidation(options) {
1407
1520
  }
1408
1521
  if (hasDiscordRoleReward(campaign.winner_rewards)) {
1409
1522
  if (!isDiscordBound(userProfile)) {
1410
- await new Promise((resolve) => {
1523
+ const discordResult = await new Promise((resolve) => {
1411
1524
  discordBindResolveRef.current = resolve;
1412
1525
  setDiscordBindInfo({
1413
1526
  campaignId: campaign.id
1414
1527
  });
1415
1528
  });
1529
+ if (!discordResult) {
1530
+ return false;
1531
+ }
1416
1532
  }
1417
1533
  }
1418
1534
  return true;
@@ -1423,7 +1539,8 @@ function useCompleteValidation(options) {
1423
1539
  userProfile,
1424
1540
  isLoggedIn,
1425
1541
  onLogin,
1426
- onEligibilityFailed
1542
+ onEligibilityFailed,
1543
+ t
1427
1544
  ]);
1428
1545
  return {
1429
1546
  validateBeforeComplete,
@@ -1501,16 +1618,17 @@ function formatLongNumber$1(input, symbol = true) {
1501
1618
  }
1502
1619
  return String(Math.round(num * 100) / 100);
1503
1620
  }
1504
- function getRewardSymbol(info) {
1621
+ function getRewardSymbol(info, t) {
1505
1622
  var _a;
1623
+ const translate = t ?? ((key) => key);
1506
1624
  if (info.reward_type === RewardType.Points) {
1507
- return "Points";
1625
+ return translate("points");
1508
1626
  }
1509
1627
  if (info.reward_type === RewardType.GTCPoints) {
1510
- return ((_a = info.points_info) == null ? void 0 : _a.points_name) || "Points";
1628
+ return ((_a = info.points_info) == null ? void 0 : _a.points_name) || translate("points");
1511
1629
  }
1512
1630
  if (info.reward_type === RewardType.Whitelist) {
1513
- return "WL";
1631
+ return translate("whitelist");
1514
1632
  }
1515
1633
  if (info.reward_type === RewardType.Token) {
1516
1634
  return info.reward_symbol || "";
@@ -1525,26 +1643,47 @@ function getRewardSymbol(info) {
1525
1643
  return "EXP";
1526
1644
  }
1527
1645
  if (info.reward_type === RewardType.DiscordRole) {
1528
- return "Discord Role";
1646
+ return translate("discord_role");
1529
1647
  }
1530
1648
  return "";
1531
1649
  }
1532
- function formatRewardLabel(info) {
1650
+ function formatRewardLabel(info, t) {
1651
+ const translate = t ?? ((key) => key);
1533
1652
  if (info.reward_type === RewardType.Points || info.reward_type === RewardType.GTCPoints) {
1534
1653
  const amount = info.reward_amount ? formatLongNumber$1(info.reward_amount) : "?";
1535
- return `${amount} ${getRewardSymbol(info)}`;
1654
+ return `${amount} ${getRewardSymbol(info, translate)}`;
1536
1655
  }
1537
1656
  if (info.reward_type === RewardType.Token) {
1538
1657
  if (info.is_usdt_equal) {
1539
- return `$${info.reward_amount || ""} USD in ${info.reward_symbol}`;
1658
+ return `${info.reward_amount || ""} ${translate("usd_token_name", {
1659
+ token_name: info.reward_symbol || ""
1660
+ })}`.trim();
1540
1661
  }
1541
1662
  const amount = info.reward_amount ? formatLongNumber$1(info.reward_amount) : "?";
1542
- return `${amount} ${getRewardSymbol(info)}`;
1663
+ return `${amount} ${getRewardSymbol(info, translate)}`;
1543
1664
  }
1544
- return getRewardSymbol(info);
1665
+ return getRewardSymbol(info, translate);
1545
1666
  }
1546
- function getDefaultShareText(shareUrl) {
1547
- return `Check this out: ${shareUrl}`;
1667
+ function addUrlParam(url, key, value) {
1668
+ try {
1669
+ const urlObj = new URL(url);
1670
+ urlObj.searchParams.set(key, value);
1671
+ return urlObj.href;
1672
+ } catch {
1673
+ return url;
1674
+ }
1675
+ }
1676
+ function getDefaultShareText(campaignName) {
1677
+ return `Join the ${campaignName || "quest"} with me 🙌`;
1678
+ }
1679
+ function buildFinalShareText(shareUrl, shareText, shareAutoAppendLink, campaignName) {
1680
+ const baseText = shareText || getDefaultShareText(campaignName);
1681
+ if (shareAutoAppendLink) {
1682
+ const linkWithUtm = addUrlParam(shareUrl, "utm_source", "x");
1683
+ return `${baseText}
1684
+ ${linkWithUtm}`;
1685
+ }
1686
+ return baseText;
1548
1687
  }
1549
1688
  function getTwitterShareUrl(content) {
1550
1689
  return `https://x.com/intent/tweet?text=${encodeURIComponent(content)}`;
@@ -3760,6 +3899,7 @@ function QrCodeDialog({
3760
3899
  endTime,
3761
3900
  winnerRewardsSimple
3762
3901
  }) {
3902
+ const { t } = useQuestLocale();
3763
3903
  const [qrCodeUrl, setQrCodeUrl] = useState("");
3764
3904
  const posterRef = useRef(null);
3765
3905
  useEffect(() => {
@@ -3792,7 +3932,7 @@ function QrCodeDialog({
3792
3932
  link.href = dataUrl;
3793
3933
  link.click();
3794
3934
  } catch (error) {
3795
- console.error("Failed to download poster:", error);
3935
+ console.error("failed_download_poster", error);
3796
3936
  }
3797
3937
  };
3798
3938
  return /* @__PURE__ */ jsx(
@@ -3802,7 +3942,7 @@ function QrCodeDialog({
3802
3942
  onOpenChange: (isOpen) => !isOpen && onClose(),
3803
3943
  showCloseButton: true,
3804
3944
  contentClassName: "taskon-quest-qr-dialog-content",
3805
- title: "Share QR Code",
3945
+ title: t("share_qr_code"),
3806
3946
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-dialog", children: [
3807
3947
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-qr-poster-outer", children: /* @__PURE__ */ jsxs("div", { ref: posterRef, className: "taskon-quest-qr-poster", children: [
3808
3948
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-poster-header", children: [
@@ -3832,13 +3972,16 @@ function QrCodeDialog({
3832
3972
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-poster-footer", children: [
3833
3973
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-info", children: [
3834
3974
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-reward-title", children: [
3835
- "Reward",
3975
+ t("reward"),
3836
3976
  /* @__PURE__ */ jsx(ArrowRightIcon, {})
3837
3977
  ] }),
3838
3978
  winnerRewardsSimple && winnerRewardsSimple.length > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-rewards-list", children: [
3839
3979
  "🎁",
3840
3980
  winnerRewardsSimple.map((reward, index) => /* @__PURE__ */ jsxs("span", { className: "taskon-quest-qr-reward-item", children: [
3841
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-qr-reward-label", children: formatRewardLabel(reward) }),
3981
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-qr-reward-label", children: formatRewardLabel(
3982
+ reward,
3983
+ t
3984
+ ) }),
3842
3985
  reward.chain_icon && /* @__PURE__ */ jsx(
3843
3986
  "img",
3844
3987
  {
@@ -3856,12 +3999,12 @@ function QrCodeDialog({
3856
3999
  /* @__PURE__ */ jsx("span", { children: timeRangeText })
3857
4000
  ] })
3858
4001
  ] }),
3859
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-qr-code", children: qrCodeUrl && /* @__PURE__ */ jsx("img", { src: qrCodeUrl, alt: "QR Code" }) })
4002
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-qr-code", children: qrCodeUrl && /* @__PURE__ */ jsx("img", { src: qrCodeUrl, alt: t("qr_code") }) })
3860
4003
  ] })
3861
4004
  ] }) }),
3862
4005
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-qr-actions", children: [
3863
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }),
3864
- /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleDownload, children: "Save" })
4006
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: t("close") }),
4007
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleDownload, children: t("save") })
3865
4008
  ] })
3866
4009
  ] })
3867
4010
  }
@@ -3902,7 +4045,7 @@ function TwitterIcon() {
3902
4045
  "path",
3903
4046
  {
3904
4047
  d: "M23 8.66667C22.6516 9.33333 22.071 10 21.2581 10.4444V10.8889C21.2581 16.4444 16.4968 21 10.6903 21C8.71613 21 6.74194 20.4444 5 19.4444C5.34839 19.4444 5.58065 19.5556 5.92903 19.4444C7.67097 19.4444 9.29677 18.8889 10.5742 17.8889C8.94839 17.8889 7.55484 16.8889 7.09032 15.4444C7.32258 15.4444 7.55484 15.5556 7.7871 15.5556C8.13548 15.5556 8.48387 15.5556 8.71613 15.4444C6.97419 15.1111 5.69677 13.6667 5.69677 12C6.16129 12.2222 6.74194 12.4444 7.32258 12.4444C6.39355 11.7778 5.8129 10.6667 5.8129 9.44444C5.8129 8.77778 6.04516 8.22222 6.27742 7.66667C8.13548 9.88889 10.9226 11.2222 13.9419 11.3333C13.8258 11.1111 13.8258 10.7778 13.8258 10.5556C13.8258 8.55556 15.4516 7 17.5419 7C18.5871 7 19.5161 7.44444 20.2129 8.11111C21.0258 8 21.8387 7.66667 22.5355 7.22222C22.3032 8 21.7226 8.77778 20.9097 9.22222C21.6065 9.11111 22.4194 8.88889 23 8.66667Z",
3905
- fill: "#54AEFF"
4048
+ fill: "currentColor"
3906
4049
  }
3907
4050
  )
3908
4051
  }
@@ -3922,7 +4065,7 @@ function CopyLinkIcon() {
3922
4065
  "path",
3923
4066
  {
3924
4067
  d: "M11.6875 16.3149L17.3178 10.6846",
3925
- stroke: "#00FFA3",
4068
+ stroke: "currentColor",
3926
4069
  strokeWidth: "2",
3927
4070
  strokeLinecap: "round",
3928
4071
  strokeLinejoin: "round"
@@ -3932,7 +4075,7 @@ function CopyLinkIcon() {
3932
4075
  "path",
3933
4076
  {
3934
4077
  d: "M9.57364 12.7959L8.16607 14.2035C6.61131 15.7582 6.61131 18.279 8.16607 19.8338C9.72083 21.3885 12.2416 21.3885 13.7964 19.8338L15.2039 18.4262",
3935
- stroke: "#00FFA3",
4078
+ stroke: "currentColor",
3936
4079
  strokeWidth: "2",
3937
4080
  strokeLinecap: "round",
3938
4081
  strokeLinejoin: "round"
@@ -3942,7 +4085,7 @@ function CopyLinkIcon() {
3942
4085
  "path",
3943
4086
  {
3944
4087
  d: "M13.7969 8.57364L15.2044 7.16607C16.7592 5.61131 19.28 5.61131 20.8347 7.16607C22.3895 8.72083 22.3895 11.2416 20.8347 12.7964L19.4272 14.2039",
3945
- stroke: "#00FFA3",
4088
+ stroke: "currentColor",
3946
4089
  strokeWidth: "2",
3947
4090
  strokeLinecap: "round",
3948
4091
  strokeLinejoin: "round"
@@ -3965,7 +4108,7 @@ function QrCodeIcon() {
3965
4108
  "path",
3966
4109
  {
3967
4110
  d: "M22 14.4429V18.943H17.5V15.9547H16V22H14.5V14.4613H19V17.4486H20.5V14.4429H22ZM12.5 14.4613V21.9308H5V14.4613H12.5ZM22 20.4369V21.9308H17.5V20.4369H22ZM11 15.9552H6.5V20.4369H11V15.9552ZM9.5 17.4491V18.943H8V17.4491H9.5ZM12.5 5V12.4695H5V5H12.5ZM22 5V12.4695H14.5V5H22ZM11 6.49389H6.5V10.9756H11V6.49389ZM20.5 6.49389H16V10.9756H20.5V6.49389ZM9.5 7.98779V9.48168H8V7.98779H9.5ZM19 7.98779V9.48168H17.5V7.98779H19Z",
3968
- fill: "#FFD465"
4111
+ fill: "currentColor"
3969
4112
  }
3970
4113
  )
3971
4114
  }
@@ -3974,6 +4117,7 @@ function QrCodeIcon() {
3974
4117
  function ShareDropdown({
3975
4118
  shareUrl,
3976
4119
  shareText,
4120
+ shareAutoAppendLink,
3977
4121
  campaignName,
3978
4122
  bannerUrl,
3979
4123
  communityName,
@@ -3982,18 +4126,29 @@ function ShareDropdown({
3982
4126
  endTime,
3983
4127
  winnerRewardsSimple
3984
4128
  }) {
4129
+ const { t } = useQuestLocale();
4130
+ const portalContainer = useTaskOnPortalContainer();
3985
4131
  const { toast } = useToast();
3986
4132
  const [qrDialogOpen, setQrDialogOpen] = useState(false);
3987
4133
  const [popoverOpen, setPopoverOpen] = useState(false);
4134
+ const resolvedUrl = shareUrl || window.location.href;
3988
4135
  const handleShareTwitter = () => {
3989
- const text = shareText || getDefaultShareText(shareUrl);
4136
+ const resolvedShareText = shareText || t("join_campaignname_me", {
4137
+ campaignName: campaignName || t("quest")
4138
+ });
4139
+ const text = buildFinalShareText(
4140
+ resolvedUrl,
4141
+ resolvedShareText,
4142
+ shareAutoAppendLink,
4143
+ campaignName
4144
+ );
3990
4145
  shareToTwitter(text);
3991
4146
  setPopoverOpen(false);
3992
4147
  };
3993
4148
  const handleCopyLink = async () => {
3994
- const success = await copyToClipboard$3(shareUrl);
4149
+ const success = await copyToClipboard$3(resolvedUrl);
3995
4150
  if (success) {
3996
- toast.success("Link copied!");
4151
+ toast.success(t("link_copied"));
3997
4152
  }
3998
4153
  setPopoverOpen(false);
3999
4154
  };
@@ -4003,38 +4158,38 @@ function ShareDropdown({
4003
4158
  };
4004
4159
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4005
4160
  /* @__PURE__ */ jsxs(Root2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
4006
- /* @__PURE__ */ jsx(Trigger, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "taskon-quest-share-trigger", "aria-label": "Share", children: /* @__PURE__ */ jsx(ShareIcon, {}) }) }),
4007
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(Content2, { className: "taskon-quest-share-menu", sideOffset: 8, children: [
4161
+ /* @__PURE__ */ jsx(Trigger, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "taskon-quest-share-trigger", "aria-label": t("share"), children: /* @__PURE__ */ jsx(ShareIcon, {}) }) }),
4162
+ /* @__PURE__ */ jsx(Portal, { container: portalContainer ?? void 0, children: /* @__PURE__ */ jsxs(Content2, { className: "taskon-quest-share-menu", sideOffset: 8, children: [
4008
4163
  /* @__PURE__ */ jsxs(
4009
4164
  "button",
4010
4165
  {
4011
- className: "taskon-quest-share-menu-item",
4166
+ className: "taskon-quest-share-menu-item taskon-quest-share-menu-item--twitter",
4012
4167
  onClick: handleShareTwitter,
4013
4168
  children: [
4014
4169
  /* @__PURE__ */ jsx(TwitterIcon, {}),
4015
- /* @__PURE__ */ jsx("span", { children: "Twitter" })
4170
+ /* @__PURE__ */ jsx("span", { children: t("twitter") })
4016
4171
  ]
4017
4172
  }
4018
4173
  ),
4019
4174
  /* @__PURE__ */ jsxs(
4020
4175
  "button",
4021
4176
  {
4022
- className: "taskon-quest-share-menu-item",
4177
+ className: "taskon-quest-share-menu-item taskon-quest-share-menu-item--copy",
4023
4178
  onClick: handleCopyLink,
4024
4179
  children: [
4025
4180
  /* @__PURE__ */ jsx(CopyLinkIcon, {}),
4026
- /* @__PURE__ */ jsx("span", { children: "Copy Link" })
4181
+ /* @__PURE__ */ jsx("span", { children: t("copy_link") })
4027
4182
  ]
4028
4183
  }
4029
4184
  ),
4030
4185
  /* @__PURE__ */ jsxs(
4031
4186
  "button",
4032
4187
  {
4033
- className: "taskon-quest-share-menu-item",
4188
+ className: "taskon-quest-share-menu-item taskon-quest-share-menu-item--qr",
4034
4189
  onClick: handleShowQrCode,
4035
4190
  children: [
4036
4191
  /* @__PURE__ */ jsx(QrCodeIcon, {}),
4037
- /* @__PURE__ */ jsx("span", { children: "QR Code" })
4192
+ /* @__PURE__ */ jsx("span", { children: t("qr_code") })
4038
4193
  ]
4039
4194
  }
4040
4195
  )
@@ -4045,7 +4200,7 @@ function ShareDropdown({
4045
4200
  {
4046
4201
  open: qrDialogOpen,
4047
4202
  onClose: () => setQrDialogOpen(false),
4048
- shareUrl,
4203
+ shareUrl: resolvedUrl,
4049
4204
  campaignName,
4050
4205
  bannerUrl,
4051
4206
  communityName,
@@ -4090,16 +4245,16 @@ function QuestTitle({
4090
4245
  show = true,
4091
4246
  shareUrl,
4092
4247
  shareText,
4248
+ showShare,
4249
+ shareAutoAppendLink,
4093
4250
  bannerUrl,
4094
4251
  communityName,
4095
4252
  communityAvatar,
4096
4253
  winnerRewardsSimple
4097
4254
  }) {
4255
+ const { t } = useQuestLocale();
4098
4256
  const countdownTarget = !isStarted ? startTime : isActive ? endTime : void 0;
4099
4257
  const countdown = useCountdown(countdownTarget);
4100
- if (!show) {
4101
- return null;
4102
- }
4103
4258
  const startDate = new Date(startTime);
4104
4259
  const endDate = new Date(endTime);
4105
4260
  const formatDateTime = (date) => {
@@ -4112,10 +4267,10 @@ function QuestTitle({
4112
4267
  };
4113
4268
  const offset = -startDate.getTimezoneOffset() / 60;
4114
4269
  const offsetString = offset >= 0 ? `+${offset}` : String(offset);
4115
- const countdownLabel = isEnded ? "ENDED" : !isStarted ? "Starts In" : "Ends In";
4270
+ const countdownLabel = isEnded ? t("ended") : !isStarted ? t("starts") : t("ends");
4116
4271
  const hasValidCountdown = !isEnded && countdown && countdown.totalSeconds > 0;
4117
4272
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-header-title-section", children: [
4118
- /* @__PURE__ */ jsx("h1", { className: "taskon-quest-title", children: title }),
4273
+ show && /* @__PURE__ */ jsx("h1", { className: "taskon-quest-title", children: title }),
4119
4274
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-header-meta", children: [
4120
4275
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-countdown", children: [
4121
4276
  hasValidCountdown && /* @__PURE__ */ jsx("span", { className: "taskon-quest-countdown-icon", children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
@@ -4130,18 +4285,23 @@ function QuestTitle({
4130
4285
  ] }),
4131
4286
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-countdown-divider" }),
4132
4287
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-time-range", children: [
4133
- "(UTC",
4134
- offsetString,
4135
- ") ",
4136
- formatDateTime(startDate),
4137
- " ~ ",
4138
- formatDateTime(endDate)
4288
+ /* @__PURE__ */ jsxs("span", { className: "taskon-quest-time-range-timezone", children: [
4289
+ "(UTC",
4290
+ offsetString,
4291
+ ")"
4292
+ ] }),
4293
+ /* @__PURE__ */ jsxs("span", { className: "taskon-quest-time-range-values", children: [
4294
+ /* @__PURE__ */ jsx("span", { children: formatDateTime(startDate) }),
4295
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-time-range-separator", "aria-hidden": "true", children: "~" }),
4296
+ /* @__PURE__ */ jsx("span", { children: formatDateTime(endDate) })
4297
+ ] })
4139
4298
  ] }),
4140
- shareUrl && /* @__PURE__ */ jsx(
4299
+ showShare && /* @__PURE__ */ jsx(
4141
4300
  ShareDropdown,
4142
4301
  {
4143
4302
  shareUrl,
4144
4303
  shareText,
4304
+ shareAutoAppendLink,
4145
4305
  campaignName: title,
4146
4306
  bannerUrl,
4147
4307
  communityName,
@@ -4158,6 +4318,7 @@ function QuestDescription({
4158
4318
  description,
4159
4319
  show = true
4160
4320
  }) {
4321
+ const { t } = useQuestLocale();
4161
4322
  const [isExpanded, setIsExpanded] = useState(false);
4162
4323
  const sanitizedHtml = useMemo(() => {
4163
4324
  if (!description) return "";
@@ -4179,7 +4340,7 @@ function QuestDescription({
4179
4340
  {
4180
4341
  className: "taskon-quest-desc-more",
4181
4342
  onClick: () => setIsExpanded(!isExpanded),
4182
- children: isExpanded ? "Show less" : "Read more"
4343
+ children: isExpanded ? t("show_less") : t("read")
4183
4344
  }
4184
4345
  )
4185
4346
  ] });
@@ -4196,6 +4357,8 @@ function QuestHeader({
4196
4357
  showDescription = true,
4197
4358
  shareUrl,
4198
4359
  shareText,
4360
+ showShare,
4361
+ shareAutoAppendLink,
4199
4362
  communityName,
4200
4363
  communityAvatar,
4201
4364
  winnerRewardsSimple
@@ -4214,6 +4377,8 @@ function QuestHeader({
4214
4377
  show: showTitle,
4215
4378
  shareUrl,
4216
4379
  shareText,
4380
+ showShare,
4381
+ shareAutoAppendLink,
4217
4382
  bannerUrl,
4218
4383
  communityName,
4219
4384
  communityAvatar,
@@ -4253,8 +4418,8 @@ function ArrowDownIcon() {
4253
4418
  y2: "-4.69753e-06",
4254
4419
  gradientUnits: "userSpaceOnUse",
4255
4420
  children: [
4256
- /* @__PURE__ */ jsx("stop", { stopColor: "#00FFA3" }),
4257
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#00FFA3", stopOpacity: "0.19" })
4421
+ /* @__PURE__ */ jsx("stop", { stopColor: "currentColor" }),
4422
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "currentColor", stopOpacity: "0.19" })
4258
4423
  ]
4259
4424
  }
4260
4425
  ) })
@@ -4266,6 +4431,7 @@ function ParticipantsInfo({
4266
4431
  participantCount,
4267
4432
  className
4268
4433
  }) {
4434
+ const { t } = useQuestLocale();
4269
4435
  const [isDialogOpen, setIsDialogOpen] = useState(false);
4270
4436
  if (participantCount === 0) {
4271
4437
  return null;
@@ -4278,15 +4444,15 @@ function ParticipantsInfo({
4278
4444
  type: "button",
4279
4445
  className: "taskon-quest-participants-info-header",
4280
4446
  onClick: () => setIsDialogOpen(true),
4281
- "aria-label": "View participants info details",
4447
+ "aria-label": t("view_participants_info_details"),
4282
4448
  children: [
4283
- /* @__PURE__ */ jsx("h3", { className: "taskon-quest-participants-info-title", children: "Participants Info" }),
4449
+ /* @__PURE__ */ jsx("h3", { className: "taskon-quest-participants-info-title", children: t("participants_info") }),
4284
4450
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-participants-info-icon", children: /* @__PURE__ */ jsx(InfoIcon, {}) })
4285
4451
  ]
4286
4452
  }
4287
4453
  ),
4288
4454
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-info-row", children: [
4289
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-participants-info-label", children: "Participants" }),
4455
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-participants-info-label", children: t("participants_2") }),
4290
4456
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-participants-info-value", children: formattedParticipantCount })
4291
4457
  ] }),
4292
4458
  /* @__PURE__ */ jsx(
@@ -4294,36 +4460,48 @@ function ParticipantsInfo({
4294
4460
  {
4295
4461
  open: isDialogOpen,
4296
4462
  onOpenChange: setIsDialogOpen,
4297
- title: "Participants",
4463
+ title: t("participants_2"),
4298
4464
  maxWidth: 480,
4299
4465
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog", children: [
4300
- /* @__PURE__ */ jsx("h2", { className: "taskon-quest-participants-dialog-title", children: "Participants" }),
4466
+ /* @__PURE__ */ jsx("h2", { className: "taskon-quest-participants-dialog-title", children: t("participants_2") }),
4301
4467
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-section", children: [
4302
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-subtitle", children: "What is Participants?" }),
4303
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-desc", children: "Participants: any user who complete at least 1 task of this quest." })
4468
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-subtitle", children: t("what_participants") }),
4469
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-desc", children: t("participants_any_user_who_complete_least_1_task_quest") })
4304
4470
  ] }),
4305
4471
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-section", children: [
4306
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-subtitle", children: "How is winner be selected?" }),
4307
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-desc", children: "Winner is generated from the following chart." })
4472
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-subtitle", children: t("how_winner_selected") }),
4473
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-desc", children: t("winner_generated_following_chart") })
4308
4474
  ] }),
4309
4475
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-chart", children: [
4310
4476
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-arrow-wrap", children: /* @__PURE__ */ jsx(ArrowDownIcon, {}) }),
4311
4477
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-cards", children: [
4312
4478
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card taskon-quest-participants-dialog-card--level1", children: [
4313
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: "Participants" }),
4314
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-desc", children: "*Who completes at least 1 task." })
4479
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: t("participants_2") }),
4480
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card-desc", children: [
4481
+ "*",
4482
+ t("who_completes_least_1_task")
4483
+ ] })
4315
4484
  ] }),
4316
4485
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card taskon-quest-participants-dialog-card--level2", children: [
4317
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: "Submitters" }),
4318
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-desc", children: "*Who completes the quest." })
4486
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: t("submitters") }),
4487
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card-desc", children: [
4488
+ "*",
4489
+ t("who_completes_quest")
4490
+ ] })
4319
4491
  ] }),
4320
4492
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card taskon-quest-participants-dialog-card--level3", children: [
4321
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: "Qualifiers" }),
4322
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-desc", children: "*All the tasks of this quest is verified as valid, some tasks may verified by quest creator not by TaskOn." })
4493
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: t("qualifiers") }),
4494
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card-desc", children: [
4495
+ "*",
4496
+ t("tasks_quest_verified_valid_some_tasks_may_verified_quest")
4497
+ ] })
4323
4498
  ] }),
4324
4499
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card taskon-quest-participants-dialog-card--level4", children: [
4325
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: "👑 Winners" }),
4326
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-desc", children: "*Only Qualifier can be selected as winner, the select method depends on the settings such as FCFS." })
4500
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-participants-dialog-card-title", children: t("winners_2") }),
4501
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-participants-dialog-card-desc", children: [
4502
+ "*",
4503
+ t("qualifier_selected_winner_select_method_depends_settings_fcfs")
4504
+ ] })
4327
4505
  ] })
4328
4506
  ] })
4329
4507
  ] }),
@@ -4334,7 +4512,7 @@ function ParticipantsInfo({
4334
4512
  size: "large",
4335
4513
  className: "taskon-quest-participants-dialog-btn",
4336
4514
  onClick: () => setIsDialogOpen(false),
4337
- children: "Confirm"
4515
+ children: t("confirm")
4338
4516
  }
4339
4517
  )
4340
4518
  ] })
@@ -4342,14 +4520,14 @@ function ParticipantsInfo({
4342
4520
  )
4343
4521
  ] });
4344
4522
  }
4345
- function getRewardTypeLabel$1(rewardType, pointName) {
4523
+ function getRewardTypeLabel$1(rewardType, pointName, t) {
4346
4524
  if ([RewardType.BMintedNft, RewardType.Cap, RewardType.Nft].includes(
4347
4525
  rewardType
4348
4526
  )) {
4349
4527
  return "NFT:";
4350
4528
  }
4351
4529
  if (rewardType === String(RewardType.DiscordRole)) {
4352
- return "Discord Role:";
4530
+ return `${t("discord_role")}:`;
4353
4531
  }
4354
4532
  if (rewardType === String(RewardType.Exp)) {
4355
4533
  return "EXP:";
@@ -4361,14 +4539,14 @@ function getRewardTypeLabel$1(rewardType, pointName) {
4361
4539
  return `${pointName}:`;
4362
4540
  }
4363
4541
  if (rewardType === String(RewardType.Token)) {
4364
- return "Token:";
4542
+ return `${t("token_name")}:`;
4365
4543
  }
4366
4544
  if (rewardType === String(RewardType.Whitelist)) {
4367
- return "Whitelist";
4545
+ return t("whitelist");
4368
4546
  }
4369
4547
  return String(rewardType);
4370
4548
  }
4371
- function getRewardLabel$1(data) {
4549
+ function getRewardLabel$1(data, t) {
4372
4550
  const { reward_type, reward_symbol, amount, chain_label, is_usdt_equal } = data;
4373
4551
  if ([
4374
4552
  RewardType.BMintedNft,
@@ -4386,7 +4564,9 @@ function getRewardLabel$1(data) {
4386
4564
  }
4387
4565
  if (reward_type === String(RewardType.Token)) {
4388
4566
  if (is_usdt_equal) {
4389
- return `$${amount || ""} in ${reward_symbol}`;
4567
+ return `${amount || ""} ${t("usd_token_name", {
4568
+ token_name: reward_symbol || ""
4569
+ })}`.trim();
4390
4570
  }
4391
4571
  return `${amount || ""} ${reward_symbol} ${chain_label || ""}`.trim();
4392
4572
  }
@@ -4397,13 +4577,21 @@ function getRewardLabel$1(data) {
4397
4577
  }
4398
4578
  function WinnerRewardLabel({
4399
4579
  data,
4400
- pointName = "Points"
4580
+ pointName
4401
4581
  }) {
4582
+ const { t } = useQuestLocale();
4583
+ const resolvedPointName = pointName || t("points");
4402
4584
  const typeLabel = useMemo(
4403
- () => getRewardTypeLabel$1(data.reward_type, pointName),
4404
- [data.reward_type, pointName]
4585
+ () => getRewardTypeLabel$1(data.reward_type, resolvedPointName, t),
4586
+ [data.reward_type, resolvedPointName, t]
4587
+ );
4588
+ const valueLabel = useMemo(
4589
+ () => getRewardLabel$1(
4590
+ data,
4591
+ t
4592
+ ),
4593
+ [data, t]
4405
4594
  );
4406
- const valueLabel = useMemo(() => getRewardLabel$1(data), [data]);
4407
4595
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-winner-reward-label", children: [
4408
4596
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-winner-reward-label-type", children: typeLabel }),
4409
4597
  valueLabel && /* @__PURE__ */ jsx("span", { className: "taskon-quest-winner-reward-label-value", children: valueLabel })
@@ -4429,32 +4617,32 @@ function getHowToSelectWinner$1(group) {
4429
4617
  }
4430
4618
  function getWinnerSelectionLabel$1(howToSelect) {
4431
4619
  const labels = {
4432
- FCFS: "FCFS",
4433
- LuckyDraw: "Lucky Draw",
4434
- PointRanking: "Ranking",
4435
- ManualUpload: "Manually Upload",
4436
- OpenToAll: "Open to All"
4620
+ FCFS: "fcfs",
4621
+ LuckyDraw: "lucky_draw",
4622
+ PointRanking: "ranking_2",
4623
+ ManualUpload: "manually_upload",
4624
+ OpenToAll: "open"
4437
4625
  };
4438
4626
  return labels[howToSelect];
4439
4627
  }
4440
- function formatRankingLabel(ranking) {
4628
+ function formatRankingLabel(ranking, t) {
4441
4629
  if (ranking.range_type === QuestWinnerRangeType.Number) {
4442
4630
  if (ranking.from < 2) {
4443
- return `Top ${ranking.to}`;
4631
+ return t("top_2", { to: ranking.to });
4444
4632
  }
4445
- return `Top ${ranking.from}-${ranking.to}`;
4633
+ return t("top", { from: ranking.from, to: ranking.to });
4446
4634
  } else {
4447
4635
  if (ranking.from === 0) {
4448
- return `Top ${ranking.to}%`;
4636
+ return t("top_percent_2", { to: ranking.to });
4449
4637
  }
4450
- return `Top ${ranking.from}%-${ranking.to}%`;
4638
+ return t("top_percent", { from: ranking.from, to: ranking.to });
4451
4639
  }
4452
4640
  }
4453
- function getTierLabel(layerIndex, isCurrentLayer) {
4641
+ function getTierLabel(layerIndex, isCurrentLayer, t) {
4454
4642
  if (isCurrentLayer) {
4455
- return "You are here";
4643
+ return t("here");
4456
4644
  }
4457
- return `Tier ${layerIndex + 1}`;
4645
+ return t("tier_index", { index: layerIndex + 1 });
4458
4646
  }
4459
4647
  function calculateFcfsAvailable(rewardLayer, currentWinner) {
4460
4648
  var _a;
@@ -4536,9 +4724,11 @@ function WinnerListModal({
4536
4724
  onClose,
4537
4725
  campaignId,
4538
4726
  winnerRewards,
4539
- pointsName = "Points"
4727
+ pointsName
4540
4728
  }) {
4729
+ const { t } = useQuestLocale();
4541
4730
  const { client } = useTaskOnContext();
4731
+ const resolvedPointsName = pointsName || t("points");
4542
4732
  const api = useMemo(() => {
4543
4733
  if (!client) return null;
4544
4734
  return createQuestApi(client);
@@ -4553,13 +4743,14 @@ function WinnerListModal({
4553
4743
  const tabItems = useMemo(() => {
4554
4744
  return winnerRewards.map((item, index) => {
4555
4745
  const howToSelect = getHowToSelectWinner$1(item);
4746
+ const label = getWinnerSelectionLabel$1(howToSelect);
4556
4747
  return {
4557
4748
  key: index,
4558
- label: getWinnerSelectionLabel$1(howToSelect),
4749
+ label: t(label),
4559
4750
  type: howToSelect
4560
4751
  };
4561
4752
  });
4562
- }, [winnerRewards]);
4753
+ }, [winnerRewards, t]);
4563
4754
  const currentType = useMemo(() => {
4564
4755
  var _a;
4565
4756
  return ((_a = tabItems[currentIndex]) == null ? void 0 : _a.type) || "FCFS";
@@ -4589,7 +4780,7 @@ function WinnerListModal({
4589
4780
  }
4590
4781
  setPage(pageNo);
4591
4782
  } catch (err) {
4592
- setError(err instanceof Error ? err.message : "Failed to load winners");
4783
+ setError(err instanceof Error ? err.message : t("failed_load_winners"));
4593
4784
  if (!append) {
4594
4785
  setTotal(0);
4595
4786
  setList([]);
@@ -4598,7 +4789,7 @@ function WinnerListModal({
4598
4789
  setLoading(false);
4599
4790
  }
4600
4791
  },
4601
- [api, campaignId, currentIndex, loading]
4792
+ [api, campaignId, currentIndex, loading, t]
4602
4793
  );
4603
4794
  useEffect(() => {
4604
4795
  if (isOpen && api) {
@@ -4644,13 +4835,14 @@ function WinnerListModal({
4644
4835
  onOpenChange: (open) => {
4645
4836
  if (!open) onClose();
4646
4837
  },
4647
- title: "Winners",
4838
+ title: t("winners"),
4648
4839
  showCloseButton: true,
4649
4840
  contentClassName: "taskon-quest-winner-modal",
4650
4841
  maxWidth: 600,
4651
4842
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-winner-content", children: [
4652
4843
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-winner-header", children: /* @__PURE__ */ jsxs("h2", { className: "taskon-quest-winner-title", children: [
4653
- "Winners (",
4844
+ t("winners"),
4845
+ " (",
4654
4846
  total.toLocaleString(),
4655
4847
  ")"
4656
4848
  ] }) }),
@@ -4671,16 +4863,16 @@ function WinnerListModal({
4671
4863
  variant: "primary",
4672
4864
  size: "small",
4673
4865
  onClick: () => loadPage(0, false),
4674
- children: "Retry"
4866
+ children: t("retry")
4675
4867
  }
4676
4868
  )
4677
4869
  ] }),
4678
4870
  !error && /* @__PURE__ */ jsxs("div", { ref: scrollRef, className: "taskon-quest-winner-list", children: [
4679
4871
  /* @__PURE__ */ jsxs("table", { className: "taskon-quest-winner-table", children: [
4680
4872
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
4681
- showPosition && /* @__PURE__ */ jsx("th", { children: "Position" }),
4682
- /* @__PURE__ */ jsx("th", { children: "User" }),
4683
- /* @__PURE__ */ jsx("th", { children: "Rewards" })
4873
+ showPosition && /* @__PURE__ */ jsx("th", { children: t("position") }),
4874
+ /* @__PURE__ */ jsx("th", { children: t("user") }),
4875
+ /* @__PURE__ */ jsx("th", { children: t("rewards") })
4684
4876
  ] }) }),
4685
4877
  /* @__PURE__ */ jsxs("tbody", { children: [
4686
4878
  list.map((item, index) => {
@@ -4694,7 +4886,7 @@ function WinnerListModal({
4694
4886
  WinnerRewardLabel,
4695
4887
  {
4696
4888
  data: reward,
4697
- pointName: pointsName
4889
+ pointName: resolvedPointsName
4698
4890
  },
4699
4891
  `${reward.reward_type}-${rewardIndex}`
4700
4892
  )) }) })
@@ -4705,14 +4897,14 @@ function WinnerListModal({
4705
4897
  {
4706
4898
  colSpan: showPosition ? 3 : 2,
4707
4899
  className: "taskon-quest-winner-empty",
4708
- children: "No winners yet"
4900
+ children: t("no_winners")
4709
4901
  }
4710
4902
  ) })
4711
4903
  ] })
4712
4904
  ] }),
4713
4905
  loading && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-winner-loading", children: [
4714
4906
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-winner-loading-spinner" }),
4715
- /* @__PURE__ */ jsx("span", { children: "Loading..." })
4907
+ /* @__PURE__ */ jsx("span", { children: t("loading") })
4716
4908
  ] })
4717
4909
  ] })
4718
4910
  ] })
@@ -4741,6 +4933,7 @@ function ChainIcon({
4741
4933
  size = 16,
4742
4934
  chains
4743
4935
  }) {
4936
+ const portalContainer = useTaskOnPortalContainer();
4744
4937
  const [open, setOpen] = useState(false);
4745
4938
  const timeoutRef = useRef(null);
4746
4939
  const chainInfo = findChainInfo(chain, chains);
@@ -4772,7 +4965,7 @@ function ChainIcon({
4772
4965
  onMouseLeave: handleMouseLeave
4773
4966
  }
4774
4967
  ) }),
4775
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(
4968
+ /* @__PURE__ */ jsx(Portal, { container: portalContainer ?? void 0, children: /* @__PURE__ */ jsxs(
4776
4969
  Content2,
4777
4970
  {
4778
4971
  className: "taskon-quest-rewards-chain-tooltip",
@@ -4806,6 +4999,8 @@ function getIsBrc20(chain, tokenAddress, chains) {
4806
4999
  return (chainInfo == null ? void 0 : chainInfo.chain_type) === "btc" && tokenAddress !== BTC_CONTRACT;
4807
5000
  }
4808
5001
  function TokenInfo({ rewardInfo, chains }) {
5002
+ const { t } = useQuestLocale();
5003
+ const portalContainer = useTaskOnPortalContainer();
4809
5004
  const params = rewardInfo.reward_params;
4810
5005
  const distributeType = rewardInfo.reward_distribute_type;
4811
5006
  const [open, setOpen] = useState(false);
@@ -4815,7 +5010,7 @@ function TokenInfo({ rewardInfo, chains }) {
4815
5010
  const isBrc20 = getIsBrc20(params.chain, params.token_address, chains);
4816
5011
  const totalAmount = formatTokenAmount(params.total_amount);
4817
5012
  const perAmount = params.per_amount;
4818
- const tokenNameDisplay = params.is_usdt_equal_amount ? `USD in ${params.token_name}` : params.token_name;
5013
+ const tokenNameDisplay = params.is_usdt_equal_amount ? t("usd_token_name", { token_name: params.token_name }) : params.token_name;
4819
5014
  const handleMouseEnter = () => {
4820
5015
  if (timeoutRef.current) {
4821
5016
  clearTimeout(timeoutRef.current);
@@ -4840,9 +5035,9 @@ function TokenInfo({ rewardInfo, chains }) {
4840
5035
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-token", children: [
4841
5036
  isBlindBox && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-token-blindbox", children: [
4842
5037
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-token-blindbox-icon", children: "✨" }),
4843
- /* @__PURE__ */ jsx("span", { children: "Smart Blind Box" })
5038
+ /* @__PURE__ */ jsx("span", { children: t("smart_blind_box") })
4844
5039
  ] }),
4845
- /* @__PURE__ */ jsx(BaseRow, { label: "Total Rewards Pool", children: /* @__PURE__ */ jsxs(Root2, { open, onOpenChange: setOpen, children: [
5040
+ /* @__PURE__ */ jsx(BaseRow, { label: t("total_rewards_pool"), children: /* @__PURE__ */ jsxs(Root2, { open, onOpenChange: setOpen, children: [
4846
5041
  /* @__PURE__ */ jsx(Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
4847
5042
  "div",
4848
5043
  {
@@ -4865,7 +5060,7 @@ function TokenInfo({ rewardInfo, chains }) {
4865
5060
  ]
4866
5061
  }
4867
5062
  ) }),
4868
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(
5063
+ /* @__PURE__ */ jsx(Portal, { container: portalContainer ?? void 0, children: /* @__PURE__ */ jsxs(
4869
5064
  Content2,
4870
5065
  {
4871
5066
  className: "taskon-quest-rewards-popover-content",
@@ -4875,12 +5070,11 @@ function TokenInfo({ rewardInfo, chains }) {
4875
5070
  onMouseEnter: handleMouseEnter,
4876
5071
  onMouseLeave: handleMouseLeave,
4877
5072
  children: [
4878
- params.is_usdt_equal_amount && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-popover-name", children: [
4879
- "Equivalent amounts of ",
4880
- params.token_name
4881
- ] }),
5073
+ params.is_usdt_equal_amount && /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-name", children: t("equivalent_amounts_token_name", {
5074
+ token_name: params.token_name
5075
+ }) }),
4882
5076
  params.token_address && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-popover-address", children: [
4883
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: "Contract Address" }),
5077
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: t("contract_address") }),
4884
5078
  /* @__PURE__ */ jsxs(
4885
5079
  "button",
4886
5080
  {
@@ -4900,8 +5094,8 @@ function TokenInfo({ rewardInfo, chains }) {
4900
5094
  ) })
4901
5095
  ] }) }),
4902
5096
  distributeType !== QuestRewardsDistributeType.PointProportionally && (distributeType === QuestRewardsDistributeType.Random || distributeType === QuestRewardsDistributeType.BlindBox || Number(params.per_amount) > 0) && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-token-per", children: [
4903
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-token-per-label", children: "Rewards Per Winner" }),
4904
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-token-per-value", children: distributeType === QuestRewardsDistributeType.Random || distributeType === QuestRewardsDistributeType.BlindBox ? "Random Amount" : `${perAmount} ${params.token_name}` })
5097
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-token-per-label", children: t("rewards_per_winner") }),
5098
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-token-per-value", children: distributeType === QuestRewardsDistributeType.Random || distributeType === QuestRewardsDistributeType.BlindBox ? t("random_amount") : `${perAmount} ${params.token_name}` })
4905
5099
  ] })
4906
5100
  ] });
4907
5101
  }
@@ -4914,6 +5108,8 @@ async function copyToClipboard$1(text) {
4914
5108
  }
4915
5109
  }
4916
5110
  function NftInfo({ rewardInfo, chains }) {
5111
+ const { t } = useQuestLocale();
5112
+ const portalContainer = useTaskOnPortalContainer();
4917
5113
  const params = rewardInfo.reward_params;
4918
5114
  const [open, setOpen] = useState(false);
4919
5115
  const [copied, setCopied] = useState(false);
@@ -4960,7 +5156,7 @@ function NftInfo({ rewardInfo, chains }) {
4960
5156
  ]
4961
5157
  }
4962
5158
  ) }),
4963
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(
5159
+ /* @__PURE__ */ jsx(Portal, { container: portalContainer ?? void 0, children: /* @__PURE__ */ jsxs(
4964
5160
  Content2,
4965
5161
  {
4966
5162
  className: "taskon-quest-rewards-popover-content",
@@ -4972,7 +5168,7 @@ function NftInfo({ rewardInfo, chains }) {
4972
5168
  children: [
4973
5169
  params.nft_collection_name && /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-name", children: params.nft_collection_name }),
4974
5170
  params.nft_address && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-popover-address", children: [
4975
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: "Contract Address" }),
5171
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: t("contract_address") }),
4976
5172
  /* @__PURE__ */ jsxs(
4977
5173
  "button",
4978
5174
  {
@@ -5001,6 +5197,8 @@ async function copyToClipboard(text) {
5001
5197
  }
5002
5198
  }
5003
5199
  function MintedNftInfo({ rewardInfo, chains }) {
5200
+ const { t } = useQuestLocale();
5201
+ const portalContainer = useTaskOnPortalContainer();
5004
5202
  const params = rewardInfo.reward_params;
5005
5203
  const [open, setOpen] = useState(false);
5006
5204
  const [copied, setCopied] = useState(false);
@@ -5047,7 +5245,7 @@ function MintedNftInfo({ rewardInfo, chains }) {
5047
5245
  ]
5048
5246
  }
5049
5247
  ) }),
5050
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(
5248
+ /* @__PURE__ */ jsx(Portal, { container: portalContainer ?? void 0, children: /* @__PURE__ */ jsxs(
5051
5249
  Content2,
5052
5250
  {
5053
5251
  className: "taskon-quest-rewards-popover-content",
@@ -5059,7 +5257,7 @@ function MintedNftInfo({ rewardInfo, chains }) {
5059
5257
  children: [
5060
5258
  params.nft_collection_name && /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-name", children: params.nft_collection_name }),
5061
5259
  params.nft_address && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-popover-address", children: [
5062
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: "Contract Address" }),
5260
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-popover-address-title", children: t("contract_address") }),
5063
5261
  /* @__PURE__ */ jsxs(
5064
5262
  "button",
5065
5263
  {
@@ -5092,8 +5290,9 @@ function CapInfo({ rewardInfo, chains }) {
5092
5290
  ) }) });
5093
5291
  }
5094
5292
  function WhitelistInfo({ rewardInfo, chains }) {
5293
+ const { t } = useQuestLocale();
5095
5294
  const params = rewardInfo.reward_params;
5096
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-whitelist", children: /* @__PURE__ */ jsx(BaseRow, { label: "Whitelist", children: params.chain && /* @__PURE__ */ jsx(
5295
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-whitelist", children: /* @__PURE__ */ jsx(BaseRow, { label: t("whitelist"), children: params.chain && /* @__PURE__ */ jsx(
5097
5296
  ChainIcon,
5098
5297
  {
5099
5298
  chain: params.chain,
@@ -5104,9 +5303,10 @@ function WhitelistInfo({ rewardInfo, chains }) {
5104
5303
  ) }) });
5105
5304
  }
5106
5305
  function PointsInfo({ rewardInfo }) {
5306
+ const { t } = useQuestLocale();
5107
5307
  const params = rewardInfo.reward_params;
5108
5308
  const formattedAmount = formatLargeNumber(params.amount);
5109
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-points", children: /* @__PURE__ */ jsx(BaseRow, { label: "Points/Winner", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-points-info", children: [
5309
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-points", children: /* @__PURE__ */ jsx(BaseRow, { label: t("points_winner"), children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-points-info", children: [
5110
5310
  params.points_icon && /* @__PURE__ */ jsx(
5111
5311
  "img",
5112
5312
  {
@@ -5120,21 +5320,23 @@ function PointsInfo({ rewardInfo }) {
5120
5320
  ] }) }) });
5121
5321
  }
5122
5322
  function ExpInfo({ rewardInfo }) {
5323
+ const { t } = useQuestLocale();
5123
5324
  const params = rewardInfo.reward_params;
5124
5325
  const formattedAmount = formatLargeNumber(params.per_amount);
5125
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-exp", children: /* @__PURE__ */ jsx(BaseRow, { label: "EXP/Winner", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-exp-info", children: [
5326
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-exp", children: /* @__PURE__ */ jsx(BaseRow, { label: t("exp_winner"), children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-exp-info", children: [
5126
5327
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-exp-amount", children: formattedAmount }),
5127
5328
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-exp-label", children: "EXP" })
5128
5329
  ] }) }) });
5129
5330
  }
5130
5331
  function DiscordRoleInfo({ rewardInfo }) {
5332
+ const { t } = useQuestLocale();
5131
5333
  const params = rewardInfo.reward_params;
5132
5334
  const handleClick = () => {
5133
5335
  if (params.discord_server_url) {
5134
5336
  window.open(params.discord_server_url, "_blank", "noopener,noreferrer");
5135
5337
  }
5136
5338
  };
5137
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-discord-role", children: /* @__PURE__ */ jsx(BaseRow, { label: "Discord Role", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-discord-role-info", children: [
5339
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-discord-role", children: /* @__PURE__ */ jsx(BaseRow, { label: t("discord_role"), children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-discord-role-info", children: [
5138
5340
  /* @__PURE__ */ jsx(
5139
5341
  "span",
5140
5342
  {
@@ -5144,7 +5346,7 @@ function DiscordRoleInfo({ rewardInfo }) {
5144
5346
  children: params.role_name
5145
5347
  }
5146
5348
  ),
5147
- params.not_official_discord && /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-discord-role-warning", children: "⚠️ Not Official" })
5349
+ params.not_official_discord && /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-discord-role-warning", children: t("official") })
5148
5350
  ] }) }) });
5149
5351
  }
5150
5352
  function TheReward({ rewardInfo, chains }) {
@@ -5178,6 +5380,7 @@ function WinnerCount({
5178
5380
  currentWinner,
5179
5381
  rankingLabel
5180
5382
  }) {
5383
+ const { t } = useQuestLocale();
5181
5384
  const maxWinners = rewardLayer.max_winners;
5182
5385
  if (howToSelectWinner === "OpenToAll") {
5183
5386
  return null;
@@ -5192,7 +5395,7 @@ function WinnerCount({
5192
5395
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-winner-separator", children: "/" }),
5193
5396
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-winner-total", children: maxWinners })
5194
5397
  ] }),
5195
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-winner-label", children: "Available" })
5398
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-winner-label", children: t("available") })
5196
5399
  ] });
5197
5400
  }
5198
5401
  case "PointRanking":
@@ -5203,11 +5406,12 @@ function WinnerCount({
5203
5406
  return /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-winner-count", children: maxWinners });
5204
5407
  }
5205
5408
  };
5206
- return /* @__PURE__ */ jsx(BaseRow, { label: "Winners", children: renderContent() });
5409
+ return /* @__PURE__ */ jsx(BaseRow, { label: t("winners"), children: renderContent() });
5207
5410
  }
5208
5411
  function GasStationProgress({
5209
5412
  gasStation
5210
5413
  }) {
5414
+ const { t } = useQuestLocale();
5211
5415
  if (!gasStation.gas_covered) {
5212
5416
  return null;
5213
5417
  }
@@ -5216,7 +5420,7 @@ function GasStationProgress({
5216
5420
  gasStation.used_gas_amount
5217
5421
  );
5218
5422
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-gas", children: [
5219
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-gas-label", children: "Limited spots for gas free claiming!" }),
5423
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-gas-label", children: t("limited_spots_gas_free_claiming") }),
5220
5424
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-gas-bar", children: /* @__PURE__ */ jsx(
5221
5425
  "div",
5222
5426
  {
@@ -5230,8 +5434,10 @@ function GasStationProgress({
5230
5434
  function NftPreview({
5231
5435
  imageUrl,
5232
5436
  mediaType = "Image",
5233
- alt = "NFT Preview"
5437
+ alt
5234
5438
  }) {
5439
+ const { t } = useQuestLocale();
5440
+ const previewAlt = alt || t("nft_preview");
5235
5441
  if (!imageUrl) {
5236
5442
  return null;
5237
5443
  }
@@ -5249,7 +5455,7 @@ function NftPreview({
5249
5455
  "img",
5250
5456
  {
5251
5457
  src: imageUrl,
5252
- alt,
5458
+ alt: previewAlt,
5253
5459
  className: "taskon-quest-rewards-preview-image",
5254
5460
  loading: "lazy"
5255
5461
  }
@@ -5265,18 +5471,19 @@ function EstimatedRewards({
5265
5471
  isEnded,
5266
5472
  finalReward
5267
5473
  }) {
5474
+ const { t } = useQuestLocale();
5268
5475
  const rewardLabel = useMemo(() => {
5269
5476
  if (!isEnded) {
5270
- return "Your Estimated Rewards";
5477
+ return t("estimated_rewards");
5271
5478
  }
5272
5479
  if (!isCompleted) {
5273
5480
  return "";
5274
5481
  }
5275
5482
  if (finalReward) {
5276
- return "Your Final Rewards";
5483
+ return t("final_rewards");
5277
5484
  }
5278
- return "Your Estimated Rewards";
5279
- }, [isEnded, isCompleted, finalReward]);
5485
+ return t("estimated_rewards");
5486
+ }, [isEnded, isCompleted, finalReward, t]);
5280
5487
  if (!rewardLabel) {
5281
5488
  return null;
5282
5489
  }
@@ -5306,24 +5513,15 @@ function EstimatedRewards({
5306
5513
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-estimated-symbol", children: rewardSymbol })
5307
5514
  ] })
5308
5515
  ] }),
5309
- /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-estimated-formula", children: [
5310
- "= Total Rewards Pool * Your ",
5311
- pointName,
5312
- " / Total ",
5516
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-estimated-formula", children: t("eq_total_rewards_pool_pointname_total_pointname", {
5313
5517
  pointName
5314
- ] }),
5518
+ }) }),
5315
5519
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-estimated-row", children: [
5316
- /* @__PURE__ */ jsxs("span", { className: "taskon-quest-rewards-estimated-label", children: [
5317
- "Your ",
5318
- pointName
5319
- ] }),
5520
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-estimated-label", children: t("pointname", { pointName }) }),
5320
5521
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-estimated-points", children: formattedUserPoints })
5321
5522
  ] }),
5322
5523
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-estimated-total", children: [
5323
- /* @__PURE__ */ jsxs("span", { children: [
5324
- "Total ",
5325
- pointName
5326
- ] }),
5524
+ /* @__PURE__ */ jsx("span", { children: t("total_pointname", { pointName }) }),
5327
5525
  /* @__PURE__ */ jsx("span", { children: formattedTotalPoints })
5328
5526
  ] }),
5329
5527
  !isCompleted && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-estimated-mask", children: [
@@ -5335,29 +5533,31 @@ function EstimatedRewards({
5335
5533
  alt: ""
5336
5534
  }
5337
5535
  ),
5338
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-estimated-mask-title", children: "Complete to qualify for rewards!" }),
5339
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-estimated-mask-subtitle", children: "Once qualified, every point counts toward better rewards!" })
5536
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-estimated-mask-title", children: t("complete_qualify_rewards") }),
5537
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-estimated-mask-subtitle", children: t("once_qualified_every_point_counts_toward_better_rewards") })
5340
5538
  ] })
5341
5539
  ] });
5342
5540
  }
5343
5541
  function RankingPoint({
5344
5542
  userStatus,
5345
- pointsName = "Points"
5543
+ pointsName
5346
5544
  }) {
5347
5545
  var _a, _b;
5546
+ const { t } = useQuestLocale();
5547
+ const resolvedPointsName = pointsName || t("points");
5348
5548
  const ranking = userStatus.ranking;
5349
5549
  const tier = userStatus.tier;
5350
5550
  const points = ((_a = userStatus.current_point) == null ? void 0 : _a.amount) ?? 0;
5351
- const displayPointsName = ((_b = userStatus.current_point) == null ? void 0 : _b.points_name) || pointsName;
5551
+ const displayPointsName = ((_b = userStatus.current_point) == null ? void 0 : _b.points_name) || resolvedPointsName;
5352
5552
  const hasValidRanking = ranking >= 0;
5353
5553
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point", children: [
5354
5554
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-row", children: [
5355
5555
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-label", children: [
5356
- "Your Ranking",
5556
+ t("ranking"),
5357
5557
  /* @__PURE__ */ jsx(
5358
5558
  TipPopover,
5359
5559
  {
5360
- content: "You will be ranked only after completing all mandatory tasks in this quest.",
5560
+ content: t("ranked_after_completing_mandatory_tasks_quest"),
5361
5561
  side: "top",
5362
5562
  className: "taskon-quest-rewards-ranking-point-tip-icon"
5363
5563
  }
@@ -5365,21 +5565,20 @@ function RankingPoint({
5365
5565
  ] }),
5366
5566
  hasValidRanking ? /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-value", children: [
5367
5567
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-ranking-point-number", children: ranking }),
5368
- tier > 0 && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-tier", children: [
5369
- "Tier ",
5370
- tier
5371
- ] })
5372
- ] }) : /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-tip", children: [
5373
- "Complete all ",
5374
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-ranking-point-tip-highlight", children: "REQUIRED" }),
5375
- " tasks to secure a valid ranking."
5376
- ] })
5568
+ tier > 0 && /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-ranking-point-tier", children: t("tier_index", { index: tier }) })
5569
+ ] }) : /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-ranking-point-tip", children: /* @__PURE__ */ jsx(
5570
+ I18nT,
5571
+ {
5572
+ t,
5573
+ i18nKey: "complete_required_tasks_secure_valid_ranking",
5574
+ components: {
5575
+ required: /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-ranking-point-tip-highlight", children: t("required") })
5576
+ }
5577
+ }
5578
+ ) })
5377
5579
  ] }),
5378
5580
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-row taskon-quest-rewards-ranking-point-row--points", children: [
5379
- /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-ranking-point-label", children: [
5380
- "Your ",
5381
- displayPointsName
5382
- ] }),
5581
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-ranking-point-label", children: t("pointname", { pointName: displayPointsName }) }),
5383
5582
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-ranking-point-amount", children: points })
5384
5583
  ] })
5385
5584
  ] });
@@ -5387,8 +5586,10 @@ function RankingPoint({
5387
5586
  function RewardBonus({
5388
5587
  extraBonus,
5389
5588
  qualifierRewards,
5390
- pointName = "Points"
5589
+ pointName
5391
5590
  }) {
5591
+ const { t } = useQuestLocale();
5592
+ const resolvedPointName = pointName || t("points");
5392
5593
  const qualifierPointParams = useMemo(() => {
5393
5594
  const pointsReward = qualifierRewards == null ? void 0 : qualifierRewards.find(
5394
5595
  (item) => item.reward_type === QuestRewardType.Points || item.reward_type === QuestRewardType.GTCPoints
@@ -5400,13 +5601,16 @@ function RewardBonus({
5400
5601
  return null;
5401
5602
  }
5402
5603
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-bonus", children: [
5403
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-bonus-title", children: "Bonus" }),
5604
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-bonus-title", children: t("bonus") }),
5404
5605
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-bonus-card", children: [
5405
- extraBonus && /* @__PURE__ */ jsx(BaseRow, { label: "Winner Bonus", children: /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-bonus-desc", children: extraBonus }) }),
5406
- qualifierPointParams && /* @__PURE__ */ jsx(BaseRow, { label: "Qualifier Point", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-bonus-value", children: [
5606
+ extraBonus && /* @__PURE__ */ jsx(BaseRow, { label: t("winner_bonus"), children: /* @__PURE__ */ jsx("div", { className: "taskon-quest-rewards-bonus-desc", children: extraBonus }) }),
5607
+ qualifierPointParams && /* @__PURE__ */ jsx(BaseRow, { label: t("qualifier_point"), children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-bonus-value", children: [
5407
5608
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-bonus-amount", children: qualifierPointParams.amount }),
5408
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-bonus-name", children: qualifierPointParams.points_name || pointName }),
5409
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-bonus-unit", children: "/Qualifier" })
5609
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-bonus-name", children: qualifierPointParams.points_name || resolvedPointName }),
5610
+ /* @__PURE__ */ jsxs("span", { className: "taskon-quest-rewards-bonus-unit", children: [
5611
+ "/",
5612
+ t("qualifiers")
5613
+ ] })
5410
5614
  ] }) })
5411
5615
  ] })
5412
5616
  ] });
@@ -5615,10 +5819,7 @@ function formatLongStr$1(str, separator = "...", prefixLen = 6, suffixLen = 6) {
5615
5819
  if (str.length <= prefixLen + suffixLen + 2) return str;
5616
5820
  return `${str.slice(0, prefixLen)}${separator}${str.slice(-suffixLen)}`;
5617
5821
  }
5618
- const NA_TIPS = "You will be ranked only after completing all mandatory tasks in this quest.";
5619
- const UNRANKED_TIP = "You are not ranked yet.";
5620
- const NOT_QUALIFIED_TIP = "You are not qualified for rewards in this tier.";
5621
- function getRewardTypeLabel(rewardType, pointsName) {
5822
+ function getRewardTypeLabel(rewardType, pointsName, t) {
5622
5823
  if (!rewardType) return "";
5623
5824
  switch (rewardType) {
5624
5825
  case RewardType.Nft:
@@ -5626,21 +5827,21 @@ function getRewardTypeLabel(rewardType, pointsName) {
5626
5827
  case RewardType.Cap:
5627
5828
  return "NFT:";
5628
5829
  case RewardType.DiscordRole:
5629
- return "Discord Role:";
5830
+ return `${t("discord_role")}:`;
5630
5831
  case RewardType.Exp:
5631
5832
  return "EXP:";
5632
5833
  case RewardType.GTCPoints:
5633
5834
  case RewardType.Points:
5634
5835
  return `${pointsName}:`;
5635
5836
  case RewardType.Token:
5636
- return "Token:";
5837
+ return `${t("token_name")}:`;
5637
5838
  case RewardType.Whitelist:
5638
- return "Whitelist";
5839
+ return t("whitelist");
5639
5840
  default:
5640
5841
  return "";
5641
5842
  }
5642
5843
  }
5643
- function getRewardLabel(row) {
5844
+ function getRewardLabel(row, t) {
5644
5845
  const { rewardType, rewardSymbol, rewardAmount, chainLabel, isUsdtEqual } = row;
5645
5846
  if (!rewardType) {
5646
5847
  return rewardAmount ? `${rewardAmount} ${rewardSymbol || ""}` : "";
@@ -5658,7 +5859,9 @@ function getRewardLabel(row) {
5658
5859
  return rewardAmount || "";
5659
5860
  case RewardType.Token:
5660
5861
  if (isUsdtEqual) {
5661
- return `${rewardAmount} USD in ${rewardSymbol}`;
5862
+ return `${rewardAmount || ""} ${t("usd_token_name", {
5863
+ token_name: rewardSymbol || ""
5864
+ })}`.trim();
5662
5865
  }
5663
5866
  return `${rewardAmount} ${rewardSymbol}${chainLabel ? ` ${chainLabel}` : ""}`;
5664
5867
  case RewardType.Whitelist:
@@ -5668,25 +5871,44 @@ function getRewardLabel(row) {
5668
5871
  }
5669
5872
  }
5670
5873
  function RewardCell({ row }) {
5874
+ const { t } = useQuestLocale();
5875
+ const translate = t;
5671
5876
  if (row.winnerLayer !== void 0 && row.winnerLayer < 0) {
5672
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-leaderboard-reward-cell", children: /* @__PURE__ */ jsx(TipPopover, { content: NOT_QUALIFIED_TIP, side: "top", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-not-qualified", children: "Not Qualified" }) }) });
5877
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-leaderboard-reward-cell", children: /* @__PURE__ */ jsx(
5878
+ TipPopover,
5879
+ {
5880
+ content: t("qualified_rewards_tier"),
5881
+ side: "top",
5882
+ children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-not-qualified", children: t("qualified") })
5883
+ }
5884
+ ) });
5673
5885
  }
5674
5886
  if (!row.rewardAmount) {
5675
5887
  return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-no-reward", children: "--" });
5676
5888
  }
5677
- const typeLabel = getRewardTypeLabel(row.rewardType, row.pointsName);
5678
- const rewardLabel = getRewardLabel(row);
5889
+ const typeLabel = getRewardTypeLabel(row.rewardType, row.pointsName, translate);
5890
+ const rewardLabel = getRewardLabel(row, translate);
5679
5891
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-leaderboard-reward-cell", children: [
5680
5892
  typeLabel && /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-reward-type", children: typeLabel }),
5681
5893
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-reward", children: rewardLabel })
5682
5894
  ] });
5683
5895
  }
5684
5896
  function RankBadge({ rank }) {
5897
+ const { t } = useQuestLocale();
5685
5898
  if (rank < 0) {
5686
- return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-rank taskon-quest-leaderboard-rank--unranked", children: /* @__PURE__ */ jsx(TipPopover, { content: NA_TIPS, side: "top", children: /* @__PURE__ */ jsx("span", { children: "N/A" }) }) });
5899
+ return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-rank taskon-quest-leaderboard-rank--unranked", children: /* @__PURE__ */ jsx(
5900
+ TipPopover,
5901
+ {
5902
+ content: t(
5903
+ "ranked_after_completing_mandatory_tasks_quest"
5904
+ ),
5905
+ side: "top",
5906
+ children: /* @__PURE__ */ jsx("span", { children: t("na") })
5907
+ }
5908
+ ) });
5687
5909
  }
5688
5910
  if (rank === 0) {
5689
- return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-rank taskon-quest-leaderboard-rank--unranked", children: /* @__PURE__ */ jsx(TipPopover, { content: UNRANKED_TIP, side: "top", children: /* @__PURE__ */ jsx("span", { children: "Unranked" }) }) });
5911
+ return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-rank taskon-quest-leaderboard-rank--unranked", children: /* @__PURE__ */ jsx(TipPopover, { content: t("ranked"), side: "top", children: /* @__PURE__ */ jsx("span", { children: t("unranked") }) }) });
5690
5912
  }
5691
5913
  if (rank === 1) {
5692
5914
  return /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-rank", children: /* @__PURE__ */ jsx(Rank1Icon, { size: 24 }) });
@@ -5703,8 +5925,9 @@ function UserCell({
5703
5925
  userName,
5704
5926
  isCurrentUser
5705
5927
  }) {
5928
+ const { t } = useQuestLocale();
5706
5929
  if (isCurrentUser) {
5707
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-leaderboard-user taskon-quest-leaderboard-user--current", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-user-badge", children: "YOU" }) });
5930
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-leaderboard-user taskon-quest-leaderboard-user--current", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-user-badge", children: t("you") }) });
5708
5931
  }
5709
5932
  return /* @__PURE__ */ jsx("div", { className: "taskon-quest-leaderboard-user", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-user-name", children: formatLongStr$1(userName) }) });
5710
5933
  }
@@ -5731,10 +5954,12 @@ function LeaderboardModal({
5731
5954
  isOpen,
5732
5955
  onClose,
5733
5956
  campaignId,
5734
- pointsName = "Points",
5957
+ pointsName,
5735
5958
  className = ""
5736
5959
  }) {
5960
+ const { t } = useQuestLocale();
5737
5961
  const { client, userId } = useTaskOnContext();
5962
+ const resolvedPointsName = pointsName || t("points");
5738
5963
  const [data, setData] = useState(null);
5739
5964
  const [loading, setLoading] = useState(false);
5740
5965
  const [error, setError] = useState(null);
@@ -5753,11 +5978,11 @@ function LeaderboardModal({
5753
5978
  });
5754
5979
  setData(result);
5755
5980
  } catch (err) {
5756
- setError(err instanceof Error ? err.message : "Failed to load leaderboard");
5981
+ setError(err instanceof Error ? err.message : t("failed_load_leaderboard"));
5757
5982
  } finally {
5758
5983
  setLoading(false);
5759
5984
  }
5760
- }, [client, isOpen, campaignId, page]);
5985
+ }, [client, isOpen, campaignId, page, t]);
5761
5986
  useEffect(() => {
5762
5987
  if (isOpen) {
5763
5988
  fetchData();
@@ -5777,15 +6002,21 @@ function LeaderboardModal({
5777
6002
  if (!data) return 0;
5778
6003
  return Math.ceil(data.total / PAGE_SIZE);
5779
6004
  }, [data]);
5780
- const positionTip = `The rankings are based on the total ${pointsName} earned from all tasks within this quest. In instances of tied ${pointsName}, submitters are ranked according to chronological order.`;
5781
- const tierTip = NA_TIPS;
5782
- const pointsTip = `${pointsName} collected from all tasks completed during the quest.`;
6005
+ const positionTip = t(
6006
+ "rankings_based_total_pointsname_earned_tasks_within_quest_instances",
6007
+ { pointsName: resolvedPointsName }
6008
+ );
6009
+ const tierTip = t("ranked_after_completing_mandatory_tasks_quest");
6010
+ const pointsTip = t(
6011
+ "pointsname_collected_tasks_completed_during_quest",
6012
+ { pointsName: resolvedPointsName }
6013
+ );
5783
6014
  const columns = useMemo(
5784
6015
  () => [
5785
6016
  {
5786
6017
  key: "rank",
5787
6018
  title: /* @__PURE__ */ jsxs("span", { className: "taskon-quest-leaderboard-header", children: [
5788
- /* @__PURE__ */ jsx("span", { children: "Position" }),
6019
+ /* @__PURE__ */ jsx("span", { children: t("position") }),
5789
6020
  /* @__PURE__ */ jsx(TipPopover, { content: positionTip, side: "top" })
5790
6021
  ] }),
5791
6022
  width: 100,
@@ -5794,15 +6025,15 @@ function LeaderboardModal({
5794
6025
  {
5795
6026
  key: "tier",
5796
6027
  title: /* @__PURE__ */ jsxs("span", { className: "taskon-quest-leaderboard-header", children: [
5797
- /* @__PURE__ */ jsx("span", { children: "Tier" }),
6028
+ /* @__PURE__ */ jsx("span", { children: t("tier") }),
5798
6029
  /* @__PURE__ */ jsx(TipPopover, { content: tierTip, side: "top" })
5799
6030
  ] }),
5800
6031
  width: 80,
5801
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-tier", children: row.tier !== void 0 && row.tier > 0 ? row.tier : "--" })
6032
+ render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-tier", children: row.tier !== void 0 && row.tier > 0 ? row.tier : t("na") })
5802
6033
  },
5803
6034
  {
5804
6035
  key: "user",
5805
- title: "User",
6036
+ title: t("user"),
5806
6037
  minWidth: 120,
5807
6038
  render: (_, row) => /* @__PURE__ */ jsx(
5808
6039
  UserCell,
@@ -5815,21 +6046,21 @@ function LeaderboardModal({
5815
6046
  {
5816
6047
  key: "points",
5817
6048
  title: /* @__PURE__ */ jsxs("span", { className: "taskon-quest-leaderboard-header", children: [
5818
- /* @__PURE__ */ jsx("span", { children: pointsName }),
6049
+ /* @__PURE__ */ jsx("span", { children: resolvedPointsName }),
5819
6050
  /* @__PURE__ */ jsx(TipPopover, { content: pointsTip, side: "top" })
5820
6051
  ] }),
5821
6052
  width: 100,
5822
- render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-points", children: row.points > 0 ? row.points.toLocaleString() : "--" })
6053
+ render: (_, row) => /* @__PURE__ */ jsx("span", { className: "taskon-quest-leaderboard-points", children: row.points > 0 ? row.points.toLocaleString() : t("na") })
5823
6054
  },
5824
6055
  {
5825
6056
  key: "rewards",
5826
- title: "Rewards",
6057
+ title: t("rewards"),
5827
6058
  width: 150,
5828
6059
  align: "right",
5829
6060
  render: (_, row) => /* @__PURE__ */ jsx(RewardCell, { row })
5830
6061
  }
5831
6062
  ],
5832
- [pointsName, positionTip, pointsTip, tierTip, userId]
6063
+ [positionTip, pointsTip, resolvedPointsName, t, tierTip, userId]
5833
6064
  );
5834
6065
  const rowConfig = useMemo(
5835
6066
  () => ({
@@ -5858,20 +6089,20 @@ function LeaderboardModal({
5858
6089
  onOpenChange: (open) => {
5859
6090
  if (!open) onClose();
5860
6091
  },
5861
- title: "Leaderboard",
6092
+ title: t("leaderboard"),
5862
6093
  showCloseButton: true,
5863
6094
  className,
5864
- contentClassName: "taskon-quest-leaderboard-modal",
5865
6095
  maxWidth: 600,
5866
6096
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-leaderboard-content", children: [
5867
- /* @__PURE__ */ jsx("h2", { className: "taskon-quest-leaderboard-title", children: "Leaderboard" }),
6097
+ /* @__PURE__ */ jsx("h2", { className: "taskon-quest-leaderboard-title", children: t("leaderboard") }),
5868
6098
  data && /* @__PURE__ */ jsxs("p", { className: "taskon-quest-leaderboard-subtitle", children: [
5869
6099
  data.total_user.toLocaleString(),
5870
- " participants"
6100
+ " ",
6101
+ t("participants_2")
5871
6102
  ] }),
5872
6103
  error && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-leaderboard-error", children: [
5873
6104
  /* @__PURE__ */ jsx("p", { children: error }),
5874
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: fetchData, children: "Retry" })
6105
+ /* @__PURE__ */ jsx(Button, { variant: "primary", size: "small", onClick: fetchData, children: t("retry") })
5875
6106
  ] }),
5876
6107
  !error && /* @__PURE__ */ jsx(
5877
6108
  Table,
@@ -5880,10 +6111,10 @@ function LeaderboardModal({
5880
6111
  data: tableData,
5881
6112
  rowConfig,
5882
6113
  loading,
5883
- loadingText: "Loading...",
6114
+ loadingText: t("loading"),
5884
6115
  empty: {
5885
- title: "No Data",
5886
- description: "No participants yet"
6116
+ title: t("no_data"),
6117
+ description: t("no_participants")
5887
6118
  },
5888
6119
  striped: true,
5889
6120
  className: "taskon-quest-leaderboard-table"
@@ -5939,14 +6170,19 @@ function RewardCard$1({
5939
6170
  chains
5940
6171
  }) {
5941
6172
  var _a, _b, _c;
6173
+ const { t } = useQuestLocale();
5942
6174
  const [isDescOpen, setIsDescOpen] = useState(false);
5943
6175
  const isPointRanking = howToSelectWinner === "PointRanking";
5944
6176
  const ranking = (_a = rewardLayer.winner_layer) == null ? void 0 : _a.winner_rank_range;
5945
6177
  const rankingLabel = useMemo(() => {
5946
6178
  if (!ranking) return "";
5947
- return formatRankingLabel(ranking);
5948
- }, [ranking]);
5949
- const tierLabel = getTierLabel(layerIndex, isCurrentLayer);
6179
+ return formatRankingLabel(ranking, t);
6180
+ }, [ranking, t]);
6181
+ const tierLabel = getTierLabel(
6182
+ layerIndex,
6183
+ isCurrentLayer,
6184
+ t
6185
+ );
5950
6186
  const showEstimatedRewards = useMemo(() => {
5951
6187
  return rewardInfo.reward_distribute_type === QuestRewardsDistributeType.PointProportionally && totalPoints !== -1;
5952
6188
  }, [rewardInfo.reward_distribute_type, totalPoints]);
@@ -6037,7 +6273,7 @@ function RewardCard$1({
6037
6273
  className: "taskon-quest-rewards-whitelist-desc-trigger",
6038
6274
  onClick: () => setIsDescOpen(!isDescOpen),
6039
6275
  type: "button",
6040
- children: /* @__PURE__ */ jsx(BaseRow, { label: "Whitelist Description", children: /* @__PURE__ */ jsx(
6276
+ children: /* @__PURE__ */ jsx(BaseRow, { label: t("whitelist_description"), children: /* @__PURE__ */ jsx(
6041
6277
  UnfoldIcon,
6042
6278
  {
6043
6279
  className: `taskon-quest-rewards-whitelist-desc-icon ${isDescOpen ? "taskon-quest-rewards-whitelist-desc-icon--open" : ""}`
@@ -6077,12 +6313,13 @@ function WinnerGroup({
6077
6313
  groupIndex,
6078
6314
  chains
6079
6315
  }) {
6316
+ const { t } = useQuestLocale();
6080
6317
  const howToSelectWinner = useMemo(() => {
6081
6318
  return getHowToSelectWinner$1(group);
6082
6319
  }, [group]);
6083
6320
  const winnerSelectionLabel = useMemo(() => {
6084
- return getWinnerSelectionLabel$1(howToSelectWinner);
6085
- }, [howToSelectWinner]);
6321
+ return t(getWinnerSelectionLabel$1(howToSelectWinner));
6322
+ }, [howToSelectWinner, t]);
6086
6323
  const getTotalPoints = (layerIndex) => {
6087
6324
  if (group.automatically_winner_draw_type !== QuestAutomaticallyWinnerDrawType.PointRank) {
6088
6325
  return (userStatus == null ? void 0 : userStatus.open_to_all_total_points) || 0;
@@ -6128,12 +6365,14 @@ function QuestRewards({
6128
6365
  winnerRewards,
6129
6366
  campaignStatus,
6130
6367
  userStatus,
6131
- pointName = "Points",
6368
+ pointName,
6132
6369
  isEnded,
6133
6370
  isOngoingOrEnded = false,
6134
6371
  chains
6135
6372
  }) {
6136
6373
  var _a;
6374
+ const { t } = useQuestLocale();
6375
+ const resolvedPointName = pointName || t("points");
6137
6376
  const [isLeaderboardOpen, setIsLeaderboardOpen] = useState(false);
6138
6377
  if (!winnerRewards || winnerRewards.length === 0) {
6139
6378
  return null;
@@ -6150,7 +6389,7 @@ function QuestRewards({
6150
6389
  };
6151
6390
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards", children: [
6152
6391
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-container", children: [
6153
- showUserRanking && /* @__PURE__ */ jsx(RankingPoint, { userStatus, pointsName: pointName }),
6392
+ showUserRanking && /* @__PURE__ */ jsx(RankingPoint, { userStatus, pointsName: resolvedPointName }),
6154
6393
  showViewLeaderboard && /* @__PURE__ */ jsxs(
6155
6394
  "button",
6156
6395
  {
@@ -6158,7 +6397,7 @@ function QuestRewards({
6158
6397
  className: "taskon-quest-rewards-view-leaderboard",
6159
6398
  onClick: handleOpenLeaderboard,
6160
6399
  children: [
6161
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-view-leaderboard-text", children: "View Leaderboard" }),
6400
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-view-leaderboard-text", children: t("view_leaderboard") }),
6162
6401
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-rewards-view-leaderboard-arrow", children: "→" })
6163
6402
  ]
6164
6403
  }
@@ -6168,7 +6407,7 @@ function QuestRewards({
6168
6407
  {
6169
6408
  group,
6170
6409
  currentWinners,
6171
- pointName,
6410
+ pointName: resolvedPointName,
6172
6411
  isEnded,
6173
6412
  userStatus,
6174
6413
  groupIndex,
@@ -6183,7 +6422,7 @@ function QuestRewards({
6183
6422
  isOpen: isLeaderboardOpen,
6184
6423
  onClose: handleCloseLeaderboard,
6185
6424
  campaignId,
6186
- pointsName: pointName
6425
+ pointsName: resolvedPointName
6187
6426
  }
6188
6427
  )
6189
6428
  ] });
@@ -6207,6 +6446,32 @@ function formatLongStr(str, ellipsis = "...", prefixLen = 6, suffixLen = 4) {
6207
6446
  if (str.length <= prefixLen + suffixLen) return str;
6208
6447
  return `${str.slice(0, prefixLen)}${ellipsis}${str.slice(-suffixLen)}`;
6209
6448
  }
6449
+ function getOpenseaUrl(chainInfo) {
6450
+ if (!chainInfo) return "";
6451
+ const { name, nft_contract } = chainInfo;
6452
+ const chainName = name.toLowerCase();
6453
+ if (chainName === "core") return "";
6454
+ const openseaPrefix = "https://opensea.io/assets/";
6455
+ if (chainName === "polygon") {
6456
+ return `${openseaPrefix}matic/${nft_contract}`;
6457
+ }
6458
+ return `${openseaPrefix}${name}/${nft_contract}`;
6459
+ }
6460
+ function getIsOldCapNft(tokenId) {
6461
+ if (!tokenId) return false;
6462
+ try {
6463
+ return BigInt(tokenId) <= 2147483647n;
6464
+ } catch {
6465
+ return false;
6466
+ }
6467
+ }
6468
+ function getElementUrl(chainInfo, tokenId) {
6469
+ if (!chainInfo || !tokenId) return "";
6470
+ const chainName = chainInfo.name.toLowerCase();
6471
+ if (chainName === "core") return "";
6472
+ const nftContract = getIsOldCapNft(tokenId) ? chainInfo.old_nft_contract : chainInfo.nft_contract;
6473
+ return `https://element.market/assets/${chainInfo.name}/${nftContract}/${tokenId}`;
6474
+ }
6210
6475
  function getTxExplorerUrl(chainInfo, txHash) {
6211
6476
  if (!chainInfo || !txHash) return "";
6212
6477
  const explorerBase = chainInfo.explorer || `https://etherscan.io`;
@@ -6237,26 +6502,29 @@ function getHowToSelectWinner(winnerReward) {
6237
6502
  function getWinnerSelectionLabel(howToSelectWinner) {
6238
6503
  switch (howToSelectWinner) {
6239
6504
  case 1:
6240
- return { label: "Lucky Draw", desc: "Winners are randomly selected" };
6505
+ return { label: "lucky_draw", desc: "winners_randomly_selected" };
6241
6506
  case 0:
6242
6507
  return {
6243
- label: "FCFS",
6244
- desc: "First to complete gets the reward"
6508
+ label: "fcfs",
6509
+ desc: "first_complete_gets_reward"
6245
6510
  };
6246
6511
  case 4:
6247
6512
  return {
6248
- label: "Open to All",
6249
- desc: "All qualified users receive reward"
6513
+ label: "open",
6514
+ desc: "qualified_users_receive_reward"
6250
6515
  };
6251
6516
  case 3:
6252
- return { label: "Ranking", desc: "Top ranked users win" };
6517
+ return { label: "ranking_2", desc: "top_ranked_users_win" };
6253
6518
  case 2:
6254
6519
  return {
6255
- label: "Manually Upload",
6256
- desc: "Project owner selects winners"
6520
+ label: "manually_upload",
6521
+ desc: "project_owner_selects_winners"
6257
6522
  };
6258
6523
  default:
6259
- return { label: "", desc: "" };
6524
+ return {
6525
+ label: "fcfs",
6526
+ desc: "first_complete_gets_reward"
6527
+ };
6260
6528
  }
6261
6529
  }
6262
6530
  function getEarnedWinnerSelectionList(winnerRewards, userStatus, campaignStatus) {
@@ -6402,52 +6670,52 @@ function getStatusCardConfig(status, params) {
6402
6670
  case "winner":
6403
6671
  return {
6404
6672
  badgeType: "winner",
6405
- title: "Congratulations!"
6673
+ title: "congratulations"
6406
6674
  };
6407
6675
  case "blind-box-failed":
6408
6676
  case "qualifier-failed":
6409
6677
  return {
6410
6678
  badgeType: "qualifier",
6411
- title: "Oops! Better Luck Next Time!",
6412
- description: "You have won multiple rewards!"
6679
+ title: "oops_better_luck_next_time",
6680
+ description: "won_multiple_rewards"
6413
6681
  // Will be overridden if has rewards
6414
6682
  };
6415
6683
  case "qualifier-wait":
6416
6684
  if (params == null ? void 0 : params.hasLegacyManual) {
6417
6685
  return {
6418
6686
  badgeType: "qualifier",
6419
- title: "Successfully Entered!",
6420
- description: "Waiting for project owner to upload the winner list. Stay tuned to see if you win!"
6687
+ title: "successfully_entered",
6688
+ description: "waiting_project_owner_upload_winner_list_stay_tuned_see_2"
6421
6689
  };
6422
6690
  }
6423
6691
  if (params == null ? void 0 : params.hasPointRanking) {
6424
6692
  return {
6425
6693
  badgeType: "qualifier",
6426
- title: "Successfully Entered!",
6427
- description: "Waiting for final ranking. Stay tuned to see if you win!"
6694
+ title: "successfully_entered",
6695
+ description: "waiting_final_ranking_stay_tuned_see_win_2"
6428
6696
  };
6429
6697
  }
6430
6698
  return {
6431
6699
  badgeType: "qualifier",
6432
- title: "Waiting for drawing winners",
6433
- description: "Please keep participating in tasks (e.g. keep following on X) to stay eligible for winner draws!"
6700
+ title: "waiting_drawing_winners",
6701
+ description: "please_keep_participating_tasks_e_g_keep_following_x"
6434
6702
  };
6435
6703
  case "submitter-failed":
6436
6704
  return {
6437
6705
  badgeType: "submitter",
6438
- title: "Oops!",
6439
- description: "Not all tasks are successfully verified, better luck next time!"
6706
+ title: "oops",
6707
+ description: "tasks_successfully_verified_better_luck_next_time"
6440
6708
  };
6441
6709
  case "submitter-wait":
6442
6710
  return {
6443
6711
  badgeType: "submitter",
6444
- title: "Waiting For Task Verification",
6445
- description: "Stay tuned! Only verified users are eligible to compete for rewards."
6712
+ title: "waiting_task_verification",
6713
+ description: "stay_tuned_verified_users_eligible_compete_rewards"
6446
6714
  };
6447
6715
  case "too-late":
6448
6716
  return {
6449
- title: "Oops!",
6450
- description: "Sorry you are late."
6717
+ title: "oops",
6718
+ description: "sorry_late"
6451
6719
  };
6452
6720
  case "can-complete":
6453
6721
  return null;
@@ -6484,8 +6752,12 @@ function RewardToken({
6484
6752
  layer,
6485
6753
  reward,
6486
6754
  campaign,
6487
- chains
6755
+ chains,
6756
+ rewardDisplayMode = "popup",
6757
+ rewardRedirectUrl
6488
6758
  }) {
6759
+ const { t } = useQuestLocale();
6760
+ const [popupOpen, setPopupOpen] = useState(false);
6489
6761
  const params = reward.reward_value;
6490
6762
  const chainInfo = useMemo(() => {
6491
6763
  if (!chains || !params.chain) return null;
@@ -6508,59 +6780,128 @@ function RewardToken({
6508
6780
  }, [params.amount]);
6509
6781
  const typeText = useMemo(() => {
6510
6782
  if (params.is_usdt_equal_amount) {
6511
- return `USD in ${params.token_name}`;
6783
+ return t("usd_token_name", { token_name: params.token_name });
6512
6784
  }
6513
6785
  return params.token_name;
6514
- }, [params.is_usdt_equal_amount, params.token_name]);
6786
+ }, [params.is_usdt_equal_amount, params.token_name, t]);
6515
6787
  const showAmountNotRevealed = !params.amount;
6516
6788
  const showWithdraw = isDeposited && params.amount;
6517
- return /* @__PURE__ */ jsxs(RewardCard, { children: [
6518
- /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6519
- /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-info", children: [
6520
- (chainInfo == null ? void 0 : chainInfo.icon) && /* @__PURE__ */ jsx(
6521
- "img",
6522
- {
6523
- src: chainInfo.icon,
6524
- alt: "",
6525
- className: "taskon-quest-footer-earned-single-icon"
6526
- }
6527
- ),
6528
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: formattedAmount })
6789
+ const handleWithdraw = useCallback(() => {
6790
+ if (rewardDisplayMode === "redirect" && rewardRedirectUrl) {
6791
+ window.open(rewardRedirectUrl, "_blank", "noopener,noreferrer");
6792
+ } else {
6793
+ setPopupOpen(true);
6794
+ }
6795
+ }, [rewardDisplayMode, rewardRedirectUrl]);
6796
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6797
+ /* @__PURE__ */ jsxs(RewardCard, { children: [
6798
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6799
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-info", children: [
6800
+ (chainInfo == null ? void 0 : chainInfo.icon) && /* @__PURE__ */ jsx(
6801
+ "img",
6802
+ {
6803
+ src: chainInfo.icon,
6804
+ alt: "",
6805
+ className: "taskon-quest-footer-earned-single-icon"
6806
+ }
6807
+ ),
6808
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: formattedAmount })
6809
+ ] }),
6810
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: typeText }),
6811
+ showWithdraw && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleWithdraw, children: t("withdraw") })
6529
6812
  ] }),
6530
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: typeText }),
6531
- showWithdraw && /* @__PURE__ */ jsx(ClaimButton, { disabled: true, children: "Withdraw" })
6813
+ showAmountNotRevealed && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: t("reward_amount_revealed_once_quest_ends") })
6532
6814
  ] }),
6533
- showAmountNotRevealed && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: "Reward amount will be revealed once quest ends." })
6815
+ /* @__PURE__ */ jsx(
6816
+ RewardModuleDialog,
6817
+ {
6818
+ open: popupOpen,
6819
+ onOpenChange: setPopupOpen,
6820
+ type: "token"
6821
+ }
6822
+ )
6534
6823
  ] });
6535
6824
  }
6825
+ const ArrowIcon = () => /* @__PURE__ */ jsx(
6826
+ "svg",
6827
+ {
6828
+ className: "taskon-quest-footer-action-arrow",
6829
+ width: "6",
6830
+ height: "10",
6831
+ viewBox: "0 0 6 10",
6832
+ fill: "none",
6833
+ xmlns: "http://www.w3.org/2000/svg",
6834
+ children: /* @__PURE__ */ jsx(
6835
+ "path",
6836
+ {
6837
+ d: "M1 1L5 5L1 9",
6838
+ stroke: "currentColor",
6839
+ strokeWidth: "1.5",
6840
+ strokeLinecap: "round",
6841
+ strokeLinejoin: "round"
6842
+ }
6843
+ )
6844
+ }
6845
+ );
6846
+ function ActionButton({
6847
+ onClick,
6848
+ disabled = false,
6849
+ children,
6850
+ href
6851
+ }) {
6852
+ const className = `taskon-quest-footer-action-btn ${disabled ? "taskon-quest-footer-action-btn--disabled" : ""}`;
6853
+ if (href && !disabled) {
6854
+ return /* @__PURE__ */ jsxs(
6855
+ "a",
6856
+ {
6857
+ href,
6858
+ target: "_blank",
6859
+ rel: "noopener noreferrer",
6860
+ className,
6861
+ children: [
6862
+ /* @__PURE__ */ jsx("span", { children }),
6863
+ /* @__PURE__ */ jsx(ArrowIcon, {})
6864
+ ]
6865
+ }
6866
+ );
6867
+ }
6868
+ return /* @__PURE__ */ jsxs(
6869
+ "div",
6870
+ {
6871
+ className,
6872
+ onClick: disabled ? void 0 : onClick,
6873
+ role: onClick && !disabled ? "button" : void 0,
6874
+ tabIndex: onClick && !disabled ? 0 : void 0,
6875
+ children: [
6876
+ /* @__PURE__ */ jsx("span", { children }),
6877
+ !disabled && /* @__PURE__ */ jsx(ArrowIcon, {})
6878
+ ]
6879
+ }
6880
+ );
6881
+ }
6536
6882
  function RewardNft({
6537
6883
  layer,
6538
6884
  reward,
6539
- campaign,
6540
6885
  chains,
6541
6886
  onRefresh,
6542
6887
  onClaimNft
6543
6888
  }) {
6889
+ const { t } = useQuestLocale();
6544
6890
  const [loading, setLoading] = useState(false);
6545
6891
  const params = reward.reward_value;
6546
6892
  const chainInfo = useMemo(() => {
6547
6893
  if (!chains || !params.chain) return null;
6548
- return chains[params.chain] || null;
6894
+ return chains[params.chain] || chains[params.chain.toLowerCase()] || null;
6549
6895
  }, [chains, params.chain]);
6550
- const rewardInfo = useMemo(() => {
6551
- const winnerReward = campaign.winner_rewards[layer.winner_index];
6552
- if (!winnerReward) return null;
6553
- const layerReward = winnerReward.winner_layer_rewards[layer.layer_no];
6554
- if (!layerReward) return null;
6555
- return layerReward.rewards.find((item) => item.reward_id === reward.reward_id) || null;
6556
- }, [campaign, layer, reward.reward_id]);
6557
- const isDeposited = useMemo(() => {
6558
- const distributedByType = rewardInfo == null ? void 0 : rewardInfo.reward_distributed_by_type;
6559
- return distributedByType === RewardDistributedByType.Taskon;
6560
- }, [rewardInfo]);
6896
+ const openseaLink = useMemo(() => {
6897
+ if (!params.token_id) {
6898
+ return "";
6899
+ }
6900
+ return getOpenseaUrl(chainInfo);
6901
+ }, [chainInfo, params.token_id]);
6561
6902
  const handleClaim = useCallback(async () => {
6562
6903
  if (!onClaimNft) {
6563
- console.warn("onClaimNft callback not provided");
6904
+ console.warn("NFT claim handler not provided");
6564
6905
  return;
6565
6906
  }
6566
6907
  setLoading(true);
@@ -6573,8 +6914,6 @@ function RewardNft({
6573
6914
  setLoading(false);
6574
6915
  }
6575
6916
  }, [onClaimNft, reward, layer, onRefresh]);
6576
- const buttonText = params.tx_hash ? "Retry" : "Claim";
6577
- const showButton = params.claimable || isDeposited && params.tx_hash;
6578
6917
  return /* @__PURE__ */ jsxs(RewardCard, { children: [
6579
6918
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6580
6919
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-info", children: [
@@ -6589,10 +6928,10 @@ function RewardNft({
6589
6928
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "NFT" })
6590
6929
  ] }),
6591
6930
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: params.collection_name }),
6592
- showButton && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: buttonText })
6931
+ params.claimable && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: t("claim") })
6593
6932
  ] }),
6594
- params.tx_hash && chainInfo && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-reward-tx", children: [
6595
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-reward-tx-label", children: "Txn Hash:" }),
6933
+ openseaLink ? /* @__PURE__ */ jsx(ActionButton, { href: openseaLink, children: t("check_collection_opensea") }) : params.tx_hash && chainInfo && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-reward-tx", children: [
6934
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-reward-tx-label", children: t("txn_hash") }),
6596
6935
  /* @__PURE__ */ jsx(
6597
6936
  "a",
6598
6937
  {
@@ -6613,18 +6952,25 @@ function RewardMintedNft({
6613
6952
  onRefresh,
6614
6953
  onClaimNft
6615
6954
  }) {
6955
+ const { t } = useQuestLocale();
6616
6956
  const [loading, setLoading] = useState(false);
6617
6957
  const params = reward.reward_value;
6618
6958
  const chainInfo = useMemo(() => {
6619
6959
  if (!chains || !params.chain) return null;
6620
- return chains[params.chain] || null;
6960
+ return chains[params.chain] || chains[params.chain.toLowerCase()] || null;
6621
6961
  }, [chains, params.chain]);
6962
+ const openseaLink = useMemo(() => {
6963
+ if (!params.token_id) {
6964
+ return "";
6965
+ }
6966
+ return getOpenseaUrl(chainInfo);
6967
+ }, [chainInfo, params.token_id]);
6622
6968
  const isGasStationDropping = useMemo(() => {
6623
6969
  return !!(params.gs_req_id && !params.tx_hash);
6624
6970
  }, [params.gs_req_id, params.tx_hash]);
6625
6971
  const handleClaim = useCallback(async () => {
6626
6972
  if (!onClaimNft) {
6627
- console.warn("onClaimNft callback not provided");
6973
+ console.warn("NFT claim handler not provided");
6628
6974
  return;
6629
6975
  }
6630
6976
  setLoading(true);
@@ -6637,8 +6983,6 @@ function RewardMintedNft({
6637
6983
  setLoading(false);
6638
6984
  }
6639
6985
  }, [onClaimNft, reward, layer, onRefresh]);
6640
- const buttonText = params.tx_hash ? "Retry" : "Claim";
6641
- const showButton = params.claimable;
6642
6986
  return /* @__PURE__ */ jsxs(RewardCard, { children: [
6643
6987
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6644
6988
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-info", children: [
@@ -6653,10 +6997,10 @@ function RewardMintedNft({
6653
6997
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "NFT" })
6654
6998
  ] }),
6655
6999
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: params.collection_name }),
6656
- showButton && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: buttonText })
7000
+ params.claimable && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: t("claim") })
6657
7001
  ] }),
6658
- params.tx_hash && chainInfo && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-reward-tx", children: [
6659
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-reward-tx-label", children: "Txn Hash:" }),
7002
+ openseaLink ? /* @__PURE__ */ jsx(ActionButton, { href: openseaLink, children: t("check_collection_opensea") }) : params.tx_hash && chainInfo && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-reward-tx", children: [
7003
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-reward-tx-label", children: t("txn_hash") }),
6660
7004
  /* @__PURE__ */ jsx(
6661
7005
  "a",
6662
7006
  {
@@ -6668,7 +7012,7 @@ function RewardMintedNft({
6668
7012
  }
6669
7013
  )
6670
7014
  ] }),
6671
- isGasStationDropping && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: "NFT will be airdropped soon..." })
7015
+ isGasStationDropping && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: t("nft_airdropped_soon") })
6672
7016
  ] });
6673
7017
  }
6674
7018
  function RewardCap({
@@ -6678,18 +7022,22 @@ function RewardCap({
6678
7022
  onRefresh,
6679
7023
  onClaimNft
6680
7024
  }) {
7025
+ const { t } = useQuestLocale();
6681
7026
  const [loading, setLoading] = useState(false);
6682
7027
  const params = reward.reward_value;
6683
7028
  const chainInfo = useMemo(() => {
6684
7029
  if (!chains || !params.chain) return null;
6685
- return chains[params.chain] || null;
7030
+ return chains[params.chain] || chains[params.chain.toLowerCase()] || null;
6686
7031
  }, [chains, params.chain]);
7032
+ const elementLink = useMemo(() => {
7033
+ return getElementUrl(chainInfo, params.token_id);
7034
+ }, [chainInfo, params.token_id]);
6687
7035
  const isGasStationDropping = useMemo(() => {
6688
7036
  return !!(params.gs_req_id && !params.tx_hash);
6689
7037
  }, [params.gs_req_id, params.tx_hash]);
6690
7038
  const handleClaim = useCallback(async () => {
6691
7039
  if (!onClaimNft) {
6692
- console.warn("onClaimNft callback not provided");
7040
+ console.warn("NFT claim handler not provided");
6693
7041
  return;
6694
7042
  }
6695
7043
  setLoading(true);
@@ -6713,17 +7061,19 @@ function RewardCap({
6713
7061
  className: "taskon-quest-footer-earned-single-icon"
6714
7062
  }
6715
7063
  ),
6716
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "Cap" })
7064
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "CAP" })
6717
7065
  ] }),
6718
- params.claimable && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: "Claim" })
7066
+ params.claimable && /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: t("claim") })
6719
7067
  ] }),
6720
- isGasStationDropping && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: "Cap will be airdropped soon..." })
7068
+ elementLink && /* @__PURE__ */ jsx(ActionButton, { href: elementLink, children: t("check_cap_element") }),
7069
+ isGasStationDropping && /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-reward-dropping", children: t("cap_airdropped_soon") })
6721
7070
  ] });
6722
7071
  }
6723
7072
  function RewardWhitelist({
6724
7073
  reward,
6725
7074
  chains
6726
7075
  }) {
7076
+ const { t } = useQuestLocale();
6727
7077
  const params = reward.reward_value;
6728
7078
  const chainInfo = useMemo(() => {
6729
7079
  if (!chains || !params.chain) return null;
@@ -6738,82 +7088,48 @@ function RewardWhitelist({
6738
7088
  className: "taskon-quest-footer-earned-single-icon"
6739
7089
  }
6740
7090
  ),
6741
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "Whitelist" })
7091
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: t("whitelist") })
6742
7092
  ] }) }) });
6743
7093
  }
6744
- const ArrowIcon = () => /* @__PURE__ */ jsx(
6745
- "svg",
6746
- {
6747
- className: "taskon-quest-footer-action-arrow",
6748
- width: "6",
6749
- height: "10",
6750
- viewBox: "0 0 6 10",
6751
- fill: "none",
6752
- xmlns: "http://www.w3.org/2000/svg",
6753
- children: /* @__PURE__ */ jsx(
6754
- "path",
6755
- {
6756
- d: "M1 1L5 5L1 9",
6757
- stroke: "currentColor",
6758
- strokeWidth: "1.5",
6759
- strokeLinecap: "round",
6760
- strokeLinejoin: "round"
6761
- }
6762
- )
6763
- }
6764
- );
6765
- function ActionButton({
6766
- onClick,
6767
- disabled = false,
6768
- children,
6769
- href
6770
- }) {
6771
- const className = `taskon-quest-footer-action-btn ${disabled ? "taskon-quest-footer-action-btn--disabled" : ""}`;
6772
- if (href && !disabled) {
6773
- return /* @__PURE__ */ jsxs(
6774
- "a",
6775
- {
6776
- href,
6777
- target: "_blank",
6778
- rel: "noopener noreferrer",
6779
- className,
6780
- children: [
6781
- /* @__PURE__ */ jsx("span", { children }),
6782
- /* @__PURE__ */ jsx(ArrowIcon, {})
6783
- ]
6784
- }
6785
- );
6786
- }
6787
- return /* @__PURE__ */ jsxs(
6788
- "div",
6789
- {
6790
- className,
6791
- onClick: disabled ? void 0 : onClick,
6792
- role: onClick && !disabled ? "button" : void 0,
6793
- tabIndex: onClick && !disabled ? 0 : void 0,
6794
- children: [
6795
- /* @__PURE__ */ jsx("span", { children }),
6796
- !disabled && /* @__PURE__ */ jsx(ArrowIcon, {})
6797
- ]
6798
- }
6799
- );
6800
- }
6801
7094
  function RewardPoint({
6802
- reward
7095
+ reward,
7096
+ rewardDisplayMode = "popup",
7097
+ rewardRedirectUrl
6803
7098
  }) {
7099
+ const { t } = useQuestLocale();
7100
+ const [popupOpen, setPopupOpen] = useState(false);
6804
7101
  const params = reward.reward_value;
6805
7102
  const pointName = useMemo(() => {
6806
7103
  if (reward.reward_type === RewardType.GTCPoints) {
6807
- return params.points_name || "Points";
7104
+ return params.points_name || t("points");
6808
7105
  }
6809
- return "Points";
6810
- }, [reward.reward_type, params.points_name]);
6811
- return /* @__PURE__ */ jsxs(RewardCard, { children: [
6812
- /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6813
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-single-info", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: params.amount }) }),
6814
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: pointName })
7106
+ return t("points");
7107
+ }, [reward.reward_type, params.points_name, t]);
7108
+ const handlePointsHistory = useCallback(() => {
7109
+ if (rewardDisplayMode === "redirect" && rewardRedirectUrl) {
7110
+ window.open(rewardRedirectUrl, "_blank", "noopener,noreferrer");
7111
+ } else {
7112
+ setPopupOpen(true);
7113
+ }
7114
+ }, [rewardDisplayMode, rewardRedirectUrl]);
7115
+ const actionButtonProps = rewardDisplayMode === "redirect" && rewardRedirectUrl ? { href: rewardRedirectUrl } : { onClick: handlePointsHistory };
7116
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7117
+ /* @__PURE__ */ jsxs(RewardCard, { children: [
7118
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
7119
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-single-info", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: params.amount }) }),
7120
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: pointName })
7121
+ ] }),
7122
+ /* @__PURE__ */ jsx(ActionButton, { ...actionButtonProps, children: t("points_history") })
6815
7123
  ] }),
6816
- /* @__PURE__ */ jsx(ActionButton, { children: "Points History" })
7124
+ /* @__PURE__ */ jsx(
7125
+ RewardModuleDialog,
7126
+ {
7127
+ open: popupOpen,
7128
+ onOpenChange: setPopupOpen,
7129
+ type: "points",
7130
+ pointsInfo: params
7131
+ }
7132
+ )
6817
7133
  ] });
6818
7134
  }
6819
7135
  function RewardDiscordRole({
@@ -6822,6 +7138,7 @@ function RewardDiscordRole({
6822
7138
  onRefresh,
6823
7139
  onClaimDiscordRole
6824
7140
  }) {
7141
+ const { t } = useQuestLocale();
6825
7142
  const [loading, setLoading] = useState(false);
6826
7143
  const params = reward.reward_value;
6827
7144
  const isClaimable = useMemo(() => {
@@ -6843,9 +7160,9 @@ function RewardDiscordRole({
6843
7160
  }
6844
7161
  }, [onClaimDiscordRole, reward, layer, onRefresh]);
6845
7162
  return /* @__PURE__ */ jsx(RewardCard, { children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-single-row", children: [
6846
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-single-info", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: "Discord Role" }) }),
7163
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-single-info", children: /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-type", children: t("discord_role") }) }),
6847
7164
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-earned-single-name", children: params.role_name }),
6848
- isClaimable ? /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: "Claim" }) : /* @__PURE__ */ jsx(ClaimButton, { disabled: true, children: "Claimed" })
7165
+ isClaimable ? /* @__PURE__ */ jsx(ClaimButton, { onClick: handleClaim, loading, children: t("claim") }) : /* @__PURE__ */ jsx(ClaimButton, { disabled: true, children: t("claimed") })
6849
7166
  ] }) });
6850
7167
  }
6851
7168
  const REWARD_COMPONENT_MAP = {
@@ -6869,24 +7186,24 @@ function RewardItem(props) {
6869
7186
  }
6870
7187
  const OOPS_ICON = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='8' cy='8' r='8' fill='%23FF6B6B'/%3E%3Cpath d='M8 4v5' stroke='white' stroke-width='1.5' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.5' r='0.75' fill='white'/%3E%3C/svg%3E";
6871
7188
  const WAIT_ICON = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='34' height='34' viewBox='0 0 34 34' fill='none'%3E%3Ccircle cx='17' cy='17' r='16' stroke='%23CBFF01' stroke-width='2'/%3E%3Cpath d='M17 9v8l5 3' stroke='%23CBFF01' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E";
6872
- function getFailedLabel(status) {
7189
+ function getFailedLabel(status, t) {
6873
7190
  if (status === "join-earlier") {
6874
- return "Join the quest earlier next time!";
7191
+ return t("join_quest_earlier_next_time");
6875
7192
  }
6876
7193
  if (status === "better-luck") {
6877
- return "Oops, Better Luck Next Time!";
7194
+ return t("oops_better_luck_next_time_2");
6878
7195
  }
6879
7196
  return "";
6880
7197
  }
6881
- function getWaitLabel(status) {
7198
+ function getWaitLabel(status, t) {
6882
7199
  if (status === "wait-draw") {
6883
- return "Waiting for drawing winners, Stay tuned to see if you win!";
7200
+ return t("waiting_drawing_winners_stay_tuned_see_win");
6884
7201
  }
6885
7202
  if (status === "wait-upload") {
6886
- return "Waiting for project owner to upload the winner list, Stay tuned to see if you win!";
7203
+ return t("waiting_project_owner_upload_winner_list_stay_tuned_see");
6887
7204
  }
6888
7205
  if (status === "wait-ranking") {
6889
- return "Waiting For Final Ranking, Stay tuned to see if you win!";
7206
+ return t("waiting_final_ranking_stay_tuned_see_win");
6890
7207
  }
6891
7208
  return "";
6892
7209
  }
@@ -6898,14 +7215,18 @@ function SelectionItem({
6898
7215
  isJoined,
6899
7216
  onRefresh,
6900
7217
  onClaimNft,
6901
- onClaimDiscordRole
7218
+ onClaimDiscordRole,
7219
+ rewardDisplayMode,
7220
+ rewardRedirectUrl
6902
7221
  }) {
7222
+ const { t } = useQuestLocale();
6903
7223
  const { howToSelectWinner, status, rewards } = selection;
6904
7224
  const label = getWinnerSelectionLabel(howToSelectWinner);
6905
- const failedLabel = getFailedLabel(status);
6906
- const waitLabel = getWaitLabel(status);
7225
+ const translate = t;
7226
+ const failedLabel = getFailedLabel(status, translate);
7227
+ const waitLabel = getWaitLabel(status, translate);
6907
7228
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-selection-item", children: [
6908
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-selection-label", children: label.label }),
7229
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-selection-label", children: t(label.label) }),
6909
7230
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-selection-rewards", children: [
6910
7231
  status === "winner" && rewards.map((layer) => /* @__PURE__ */ jsx(React__default.Fragment, { children: layer.reward.map((reward) => /* @__PURE__ */ jsx(
6911
7232
  RewardItem,
@@ -6918,7 +7239,9 @@ function SelectionItem({
6918
7239
  isJoined,
6919
7240
  onRefresh,
6920
7241
  onClaimNft,
6921
- onClaimDiscordRole
7242
+ onClaimDiscordRole,
7243
+ rewardDisplayMode,
7244
+ rewardRedirectUrl
6922
7245
  },
6923
7246
  reward.reward_id
6924
7247
  )) }, `layer-${layer.winner_index}-${layer.layer_no}`)),
@@ -6958,8 +7281,11 @@ function DetailPanelDialog({
6958
7281
  isJoined,
6959
7282
  onRefresh,
6960
7283
  onClaimNft,
6961
- onClaimDiscordRole
7284
+ onClaimDiscordRole,
7285
+ rewardDisplayMode,
7286
+ rewardRedirectUrl
6962
7287
  }) {
7288
+ const { t } = useQuestLocale();
6963
7289
  const winnerSelectionList = useMemo(() => {
6964
7290
  return getEarnedWinnerSelectionList(
6965
7291
  campaign.winner_rewards,
@@ -6971,7 +7297,7 @@ function DetailPanelDialog({
6971
7297
  const qualifierRewards = campaign.qualifier_rewards;
6972
7298
  if (!qualifierRewards) return null;
6973
7299
  const reward = qualifierRewards.find(
6974
- (item) => item.reward_type === "Points" || item.reward_type === "GTCPoints"
7300
+ (item) => item.reward_type === "points" || item.reward_type === "GTCPoints"
6975
7301
  );
6976
7302
  if (!reward) return null;
6977
7303
  return reward.reward_params;
@@ -6981,12 +7307,12 @@ function DetailPanelDialog({
6981
7307
  {
6982
7308
  open,
6983
7309
  onOpenChange,
6984
- title: "Multiple Rewards Detail",
7310
+ title: t("multiple_rewards_detail"),
6985
7311
  showCloseButton: true,
6986
7312
  maxWidth: 480,
6987
7313
  contentClassName: "taskon-quest-footer-detail-dialog",
6988
7314
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-detail-panel", children: [
6989
- /* @__PURE__ */ jsx("h2", { className: "taskon-quest-footer-detail-title", children: "Multiple Rewards Detail" }),
7315
+ /* @__PURE__ */ jsx("h2", { className: "taskon-quest-footer-detail-title", children: t("multiple_rewards_detail") }),
6990
7316
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-content", children: winnerSelectionList.map((item, index) => /* @__PURE__ */ jsx(
6991
7317
  SelectionItem,
6992
7318
  {
@@ -6997,18 +7323,18 @@ function DetailPanelDialog({
6997
7323
  isJoined,
6998
7324
  onRefresh,
6999
7325
  onClaimNft,
7000
- onClaimDiscordRole
7326
+ onClaimDiscordRole,
7327
+ rewardDisplayMode,
7328
+ rewardRedirectUrl
7001
7329
  },
7002
7330
  index
7003
7331
  )) }),
7004
7332
  qualifierPointParams && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-detail-bonus", children: [
7005
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-bonus-label", children: "Bonus" }),
7006
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-bonus-right", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-detail-bonus-item", children: [
7007
- qualifierPointParams.amount,
7008
- " Qualifier",
7009
- " ",
7010
- qualifierPointParams.points_name || "Points"
7011
- ] }) })
7333
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-bonus-label", children: t("bonus") }),
7334
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-bonus-right", children: /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-detail-bonus-item", children: t("amount_qualifier_pointsname", {
7335
+ amount: qualifierPointParams.amount,
7336
+ pointsName: qualifierPointParams.points_name || t("points")
7337
+ }) }) })
7012
7338
  ] })
7013
7339
  ] })
7014
7340
  }
@@ -7024,8 +7350,11 @@ function EarnedRewards({
7024
7350
  isJoined,
7025
7351
  onRefresh,
7026
7352
  onClaimNft,
7027
- onClaimDiscordRole
7353
+ onClaimDiscordRole,
7354
+ rewardDisplayMode = "popup",
7355
+ rewardRedirectUrl
7028
7356
  }) {
7357
+ const { t } = useQuestLocale();
7029
7358
  const [dialogOpen, setDialogOpen] = useState(false);
7030
7359
  const rewardCount = useMemo(() => {
7031
7360
  return earnedRewards.reduce(
@@ -7054,8 +7383,8 @@ function EarnedRewards({
7054
7383
  hasMultiReward ? (
7055
7384
  // Multiple rewards: show text + button
7056
7385
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer-earned-multi", children: [
7057
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-multi-text", children: "You have won multiple rewards!" }),
7058
- /* @__PURE__ */ jsx(ClaimButton, { onClick: handleOpenDialog, children: "Check & Claim" })
7386
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-earned-multi-text", children: t("won_multiple_rewards") }),
7387
+ /* @__PURE__ */ jsx(ClaimButton, { onClick: handleOpenDialog, children: t("check_claim") })
7059
7388
  ] })
7060
7389
  ) : (
7061
7390
  // Single reward: show detailed card
@@ -7070,7 +7399,9 @@ function EarnedRewards({
7070
7399
  isJoined,
7071
7400
  onRefresh,
7072
7401
  onClaimNft,
7073
- onClaimDiscordRole
7402
+ onClaimDiscordRole,
7403
+ rewardDisplayMode,
7404
+ rewardRedirectUrl
7074
7405
  }
7075
7406
  ) })
7076
7407
  ),
@@ -7087,13 +7418,21 @@ function EarnedRewards({
7087
7418
  isJoined,
7088
7419
  onRefresh,
7089
7420
  onClaimNft,
7090
- onClaimDiscordRole
7421
+ onClaimDiscordRole,
7422
+ rewardDisplayMode,
7423
+ rewardRedirectUrl
7091
7424
  }
7092
7425
  )
7093
7426
  ] });
7094
7427
  }
7095
7428
  function StatusBadge({ type }) {
7096
- const badgeText = type.toUpperCase();
7429
+ const { t } = useQuestLocale();
7430
+ const badgeTextMap = {
7431
+ winner: t("winners"),
7432
+ qualifier: t("qualifiers"),
7433
+ submitter: t("submitters")
7434
+ };
7435
+ const badgeText = badgeTextMap[type];
7097
7436
  return /* @__PURE__ */ jsx("div", { className: `taskon-quest-footer-badge taskon-quest-footer-badge--${type}`, children: badgeText });
7098
7437
  }
7099
7438
  function StatusCard(props) {
@@ -7110,7 +7449,9 @@ function StatusCard(props) {
7110
7449
  isJoined,
7111
7450
  onRefresh,
7112
7451
  onClaimNft,
7113
- onClaimDiscordRole
7452
+ onClaimDiscordRole,
7453
+ rewardDisplayMode,
7454
+ rewardRedirectUrl
7114
7455
  } = props;
7115
7456
  const displayableRewardCount = earnedRewards ? earnedRewards.reduce(
7116
7457
  (acc, curr) => acc + curr.reward.filter((r) => r.reward_type !== RewardType.Exp).length,
@@ -7136,11 +7477,29 @@ function StatusCard(props) {
7136
7477
  isJoined,
7137
7478
  onRefresh,
7138
7479
  onClaimNft,
7139
- onClaimDiscordRole
7480
+ onClaimDiscordRole,
7481
+ rewardDisplayMode,
7482
+ rewardRedirectUrl
7140
7483
  }
7141
7484
  ) : /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-card-message", children: description }) })
7142
7485
  ] });
7143
7486
  }
7487
+ function normalizeCompleteSubmitError(error, t) {
7488
+ if (error instanceof ApiError) {
7489
+ if (error.code === ErrorCode.RUSER_REPEAT_SUBMIT) {
7490
+ return new ApiError(
7491
+ error.code,
7492
+ t("oops_seems_like_already_finished_quest_2"),
7493
+ error.data
7494
+ );
7495
+ }
7496
+ return error;
7497
+ }
7498
+ if (error instanceof Error) {
7499
+ return error;
7500
+ }
7501
+ return new Error(t("failed_complete_quest"));
7502
+ }
7144
7503
  function CompleteButton({
7145
7504
  campaignId,
7146
7505
  hasPointProportionally: hasPointProportionally2 = false,
@@ -7152,44 +7511,50 @@ function CompleteButton({
7152
7511
  className,
7153
7512
  onBeforeComplete
7154
7513
  }) {
7514
+ const { t } = useQuestLocale();
7155
7515
  const [isLoading, setIsLoading] = useState(false);
7156
7516
  const { client } = useTaskOnContext();
7157
7517
  const api = useMemo(() => {
7158
7518
  if (!client) return null;
7159
7519
  return createQuestApi(client);
7160
7520
  }, [client]);
7161
- const buttonText = hasPointProportionally2 ? "Complete to qualify for rewards!" : "Complete";
7521
+ const buttonText = hasPointProportionally2 ? t("complete_qualify_rewards") : t("complete");
7162
7522
  const handleComplete = useCallback(async () => {
7163
7523
  if (!api || isLoading || disabled) {
7164
7524
  return;
7165
7525
  }
7166
- if (onBeforeComplete) {
7167
- try {
7168
- const canContinue = await onBeforeComplete();
7169
- if (!canContinue) {
7526
+ setIsLoading(true);
7527
+ try {
7528
+ if (onBeforeComplete) {
7529
+ try {
7530
+ const canContinue = await onBeforeComplete();
7531
+ if (!canContinue) {
7532
+ return;
7533
+ }
7534
+ } catch (error) {
7535
+ console.error("[CompleteButton] onBeforeComplete error:", error);
7170
7536
  return;
7171
7537
  }
7172
- } catch (error) {
7173
- console.error("[CompleteButton] onBeforeComplete error:", error);
7538
+ }
7539
+ if (requiresRecaptcha && !captchaToken) {
7540
+ onError == null ? void 0 : onError(new Error(t("recaptcha_verification_required")));
7174
7541
  return;
7175
7542
  }
7176
- }
7177
- if (requiresRecaptcha && !captchaToken) {
7178
- onError == null ? void 0 : onError(new Error("reCAPTCHA verification required"));
7179
- return;
7180
- }
7181
- setIsLoading(true);
7182
- try {
7183
- await api.submitCampaign({
7184
- campaign_id: campaignId,
7185
- // Widget version: always false (no auto-join checkbox)
7186
- auto_follow_community: false,
7187
- captcha_token: captchaToken
7188
- });
7189
- onComplete == null ? void 0 : onComplete();
7190
- } catch (error) {
7191
- const errorMessage = error instanceof Error ? error.message : "Failed to complete quest";
7192
- onError == null ? void 0 : onError(new Error(errorMessage));
7543
+ try {
7544
+ await api.submitCampaign({
7545
+ campaign_id: campaignId,
7546
+ // Widget version: always false (no auto-join checkbox)
7547
+ auto_follow_community: false,
7548
+ captcha_token: captchaToken
7549
+ });
7550
+ onComplete == null ? void 0 : onComplete();
7551
+ } catch (error) {
7552
+ const normalizedError = normalizeCompleteSubmitError(
7553
+ error,
7554
+ t
7555
+ );
7556
+ onError == null ? void 0 : onError(normalizedError);
7557
+ }
7193
7558
  } finally {
7194
7559
  setIsLoading(false);
7195
7560
  }
@@ -7202,7 +7567,8 @@ function CompleteButton({
7202
7567
  onBeforeComplete,
7203
7568
  onComplete,
7204
7569
  onError,
7205
- requiresRecaptcha
7570
+ requiresRecaptcha,
7571
+ t
7206
7572
  ]);
7207
7573
  return /* @__PURE__ */ jsx(
7208
7574
  "button",
@@ -7213,12 +7579,13 @@ function CompleteButton({
7213
7579
  disabled: disabled || isLoading || !api,
7214
7580
  children: isLoading ? /* @__PURE__ */ jsxs("span", { className: "taskon-quest-footer-complete-btn-loading", children: [
7215
7581
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-footer-complete-btn-spinner" }),
7216
- "Completing..."
7582
+ t("completing")
7217
7583
  ] }) : buttonText
7218
7584
  }
7219
7585
  );
7220
7586
  }
7221
7587
  function OperateFooter(props) {
7588
+ const { t } = useQuestLocale();
7222
7589
  const {
7223
7590
  campaign,
7224
7591
  userStatus,
@@ -7234,8 +7601,12 @@ function OperateFooter(props) {
7234
7601
  onConnectWallet,
7235
7602
  onClaimNft,
7236
7603
  onClaimDiscordRole,
7237
- onBeforeComplete
7604
+ onBeforeComplete,
7605
+ rewardDisplayMode,
7606
+ rewardRedirectUrl
7238
7607
  } = props;
7608
+ const { toast } = useToast();
7609
+ const [isRepeatSubmitDialogVisible, setIsRepeatSubmitDialogVisible] = useState(false);
7239
7610
  const hasRanking = useMemo(() => {
7240
7611
  return hasPointRanking(campaign.winner_rewards);
7241
7612
  }, [campaign.winner_rewards]);
@@ -7275,14 +7646,34 @@ function OperateFooter(props) {
7275
7646
  hasPointRanking: hasRanking
7276
7647
  });
7277
7648
  }, [participationStatus, hasLegacyManual, hasRanking]);
7649
+ const localizedCardConfig = useMemo(() => {
7650
+ if (!cardConfig) {
7651
+ return null;
7652
+ }
7653
+ return {
7654
+ ...cardConfig,
7655
+ title: t(cardConfig.title),
7656
+ description: cardConfig.description ? t(cardConfig.description) : void 0
7657
+ };
7658
+ }, [cardConfig, t]);
7278
7659
  const renderConnectWallet = () => /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer-connect", children: /* @__PURE__ */ jsx(
7279
7660
  "button",
7280
7661
  {
7281
7662
  className: "taskon-quest-footer-connect-btn",
7282
7663
  onClick: onConnectWallet,
7283
- children: "Connect Wallet to Participate"
7664
+ children: t("start_to_earn")
7284
7665
  }
7285
7666
  ) });
7667
+ const handleCompleteError = useCallback(
7668
+ (error) => {
7669
+ if (error instanceof ApiError && error.code === ErrorCode.RUSER_REPEAT_SUBMIT) {
7670
+ setIsRepeatSubmitDialogVisible(true);
7671
+ return;
7672
+ }
7673
+ toast.error(error.message);
7674
+ },
7675
+ [toast]
7676
+ );
7286
7677
  const renderCompleteButton = () => /* @__PURE__ */ jsx(
7287
7678
  CompleteButton,
7288
7679
  {
@@ -7292,19 +7683,17 @@ function OperateFooter(props) {
7292
7683
  disabled: !isActive,
7293
7684
  onBeforeComplete,
7294
7685
  onComplete,
7295
- onError: (error) => {
7296
- console.error("Complete quest error:", error.message);
7297
- }
7686
+ onError: handleCompleteError
7298
7687
  }
7299
7688
  );
7300
7689
  const renderStatusCard = () => {
7301
- if (!cardConfig) return null;
7690
+ if (!localizedCardConfig) return null;
7302
7691
  return /* @__PURE__ */ jsx(
7303
7692
  StatusCard,
7304
7693
  {
7305
- title: cardConfig.title,
7306
- badgeType: cardConfig.badgeType,
7307
- description: cardConfig.description,
7694
+ title: localizedCardConfig.title,
7695
+ badgeType: localizedCardConfig.badgeType,
7696
+ description: localizedCardConfig.description,
7308
7697
  campaign,
7309
7698
  userStatus: userStatus || void 0,
7310
7699
  campaignStatus: campaignStatus || void 0,
@@ -7314,34 +7703,56 @@ function OperateFooter(props) {
7314
7703
  isJoined,
7315
7704
  onRefresh,
7316
7705
  onClaimNft,
7317
- onClaimDiscordRole
7706
+ onClaimDiscordRole,
7707
+ rewardDisplayMode,
7708
+ rewardRedirectUrl
7318
7709
  }
7319
7710
  );
7320
7711
  };
7712
+ const renderRepeatSubmitNoticeDialog = () => /* @__PURE__ */ jsx(
7713
+ ConfirmNoticeDialog,
7714
+ {
7715
+ open: isRepeatSubmitDialogVisible,
7716
+ onOpenChange: setIsRepeatSubmitDialogVisible,
7717
+ type: "warn",
7718
+ title: t("oops_seems_like_already_finished_quest"),
7719
+ desc: t(
7720
+ "ensure_fair_experience_submissions_identical_wallet_addresses_x_discord"
7721
+ ),
7722
+ confirmButton: t("confirm"),
7723
+ onConfirm: () => setIsRepeatSubmitDialogVisible(false),
7724
+ accessibilityTitle: t("oops_seems_like_already_finished_quest"),
7725
+ accessibilityDescription: t(
7726
+ "ensure_fair_experience_submissions_identical_wallet_addresses_x_discord"
7727
+ )
7728
+ }
7729
+ );
7730
+ let footerContent = null;
7321
7731
  if (participationStatus === "not-logged-in") {
7322
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer", id: "detail-operate-footer", children: renderConnectWallet() });
7732
+ footerContent = renderConnectWallet();
7733
+ } else if (participationStatus === "can-complete") {
7734
+ footerContent = renderCompleteButton();
7735
+ } else if (participationStatus !== "none" && localizedCardConfig) {
7736
+ footerContent = renderStatusCard();
7323
7737
  }
7324
- if (participationStatus === "none") {
7738
+ if (!footerContent && !isRepeatSubmitDialogVisible) {
7325
7739
  return null;
7326
7740
  }
7327
- if (participationStatus === "can-complete") {
7328
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer", id: "detail-operate-footer", children: renderCompleteButton() });
7329
- }
7330
- if (cardConfig) {
7331
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest-footer", id: "detail-operate-footer", children: renderStatusCard() });
7332
- }
7333
- return null;
7741
+ return /* @__PURE__ */ jsxs("div", { className: "taskon-quest-footer", id: "detail-operate-footer", children: [
7742
+ footerContent,
7743
+ renderRepeatSubmitNoticeDialog()
7744
+ ] });
7334
7745
  }
7335
- function getDialogTitle(errorType) {
7746
+ function getDialogTitle(errorType, t) {
7336
7747
  switch (errorType) {
7337
7748
  case "mandatory":
7338
- return "Tasks Incomplete";
7749
+ return t("tasks_incomplete");
7339
7750
  case "optional_count":
7340
- return "More Tasks Required";
7751
+ return t("tasks_required");
7341
7752
  case "optional_points":
7342
- return "More Points Required";
7753
+ return t("points_required");
7343
7754
  default:
7344
- return "Validation Failed";
7755
+ return t("validation_failed");
7345
7756
  }
7346
7757
  }
7347
7758
  function getDialogIcon(errorType) {
@@ -7355,17 +7766,17 @@ function getDialogIcon(errorType) {
7355
7766
  fill: "none",
7356
7767
  xmlns: "http://www.w3.org/2000/svg",
7357
7768
  children: [
7358
- /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "22", stroke: "#FF9500", strokeWidth: "4" }),
7769
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "22", stroke: "currentColor", strokeWidth: "4" }),
7359
7770
  /* @__PURE__ */ jsx(
7360
7771
  "path",
7361
7772
  {
7362
7773
  d: "M24 14V28",
7363
- stroke: "#FF9500",
7774
+ stroke: "currentColor",
7364
7775
  strokeWidth: "4",
7365
7776
  strokeLinecap: "round"
7366
7777
  }
7367
7778
  ),
7368
- /* @__PURE__ */ jsx("circle", { cx: "24", cy: "35", r: "2.5", fill: "#FF9500" })
7779
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "35", r: "2.5", fill: "currentColor" })
7369
7780
  ]
7370
7781
  }
7371
7782
  );
@@ -7375,6 +7786,7 @@ function TaskValidationDialog({
7375
7786
  error,
7376
7787
  onClose
7377
7788
  }) {
7789
+ const { t } = useQuestLocale();
7378
7790
  return /* @__PURE__ */ jsx(
7379
7791
  Dialog,
7380
7792
  {
@@ -7384,32 +7796,29 @@ function TaskValidationDialog({
7384
7796
  onClose();
7385
7797
  }
7386
7798
  },
7387
- title: getDialogTitle(error == null ? void 0 : error.type),
7799
+ title: getDialogTitle(
7800
+ error == null ? void 0 : error.type,
7801
+ t
7802
+ ),
7388
7803
  showCloseButton: true,
7389
7804
  maxWidth: 400,
7390
7805
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-task-validation-dialog", children: [
7391
7806
  /* @__PURE__ */ jsx("div", { className: "taskon-task-validation-dialog-icon-wrap", children: getDialogIcon(error == null ? void 0 : error.type) }),
7392
- /* @__PURE__ */ jsx("p", { className: "taskon-task-validation-dialog-message", children: (error == null ? void 0 : error.message) || "Please complete all required tasks before continuing." }),
7393
- (error == null ? void 0 : error.type) === "optional_count" && error.required !== void 0 && error.current !== void 0 && /* @__PURE__ */ jsxs("p", { className: "taskon-task-validation-dialog-progress", children: [
7394
- "Completed: ",
7395
- error.current,
7396
- " / ",
7397
- error.required,
7398
- " optional tasks"
7399
- ] }),
7400
- (error == null ? void 0 : error.type) === "optional_points" && error.required !== void 0 && error.current !== void 0 && /* @__PURE__ */ jsxs("p", { className: "taskon-task-validation-dialog-progress", children: [
7401
- "Earned: ",
7402
- error.current,
7403
- " / ",
7404
- error.required,
7405
- " points"
7406
- ] }),
7807
+ /* @__PURE__ */ jsx("p", { className: "taskon-task-validation-dialog-message", children: (error == null ? void 0 : error.message) || t("please_complete_required_tasks_before_continuing") }),
7808
+ (error == null ? void 0 : error.type) === "optional_count" && error.required !== void 0 && error.current !== void 0 && /* @__PURE__ */ jsx("p", { className: "taskon-task-validation-dialog-progress", children: t("completed_current_required_optional_tasks", {
7809
+ current: error.current,
7810
+ required: error.required
7811
+ }) }),
7812
+ (error == null ? void 0 : error.type) === "optional_points" && error.required !== void 0 && error.current !== void 0 && /* @__PURE__ */ jsx("p", { className: "taskon-task-validation-dialog-progress", children: t("earned_current_required_points", {
7813
+ current: error.current,
7814
+ required: error.required
7815
+ }) }),
7407
7816
  /* @__PURE__ */ jsx(
7408
7817
  "button",
7409
7818
  {
7410
7819
  className: "taskon-task-validation-dialog-btn",
7411
7820
  onClick: onClose,
7412
- children: "OK"
7821
+ children: t("ok")
7413
7822
  }
7414
7823
  )
7415
7824
  ] })
@@ -7417,7 +7826,7 @@ function TaskValidationDialog({
7417
7826
  );
7418
7827
  }
7419
7828
  const CHAIN_TYPE_LABELS = {
7420
- evm: "EVM Chain",
7829
+ evm: "evm_chain",
7421
7830
  btc: "Bitcoin",
7422
7831
  starknet: "Starknet",
7423
7832
  solana: "Solana",
@@ -7429,6 +7838,7 @@ const CHAIN_TYPE_LABELS = {
7429
7838
  ton: "TON"
7430
7839
  };
7431
7840
  function BindItem({ chainType, isBinding, isBound, onBind }) {
7841
+ const { t } = useQuestLocale();
7432
7842
  const label = CHAIN_TYPE_LABELS[chainType.toLowerCase()] || chainType;
7433
7843
  return /* @__PURE__ */ jsxs("div", { className: `taskon-reward-bind-item ${isBound ? "taskon-reward-bind-item--bound" : ""}`, children: [
7434
7844
  /* @__PURE__ */ jsx("span", { className: "taskon-reward-bind-item-label", children: label }),
@@ -7443,7 +7853,7 @@ function BindItem({ chainType, isBinding, isBound, onBind }) {
7443
7853
  strokeLinejoin: "round"
7444
7854
  }
7445
7855
  ) }),
7446
- "Bound"
7856
+ t("bound")
7447
7857
  ] }) : /* @__PURE__ */ jsx(
7448
7858
  "button",
7449
7859
  {
@@ -7463,8 +7873,8 @@ function BindItem({ chainType, isBinding, isBound, onBind }) {
7463
7873
  strokeDasharray: "31.4 31.4"
7464
7874
  }
7465
7875
  ) }),
7466
- "Binding..."
7467
- ] }) : "Bind"
7876
+ t("binding")
7877
+ ] }) : t("bind")
7468
7878
  }
7469
7879
  )
7470
7880
  ] });
@@ -7478,6 +7888,7 @@ function RewardBindDialog({
7478
7888
  onAllBind,
7479
7889
  onBindChain
7480
7890
  }) {
7891
+ const { t } = useQuestLocale();
7481
7892
  const [notBoundChains, setNotBoundChains] = useState(chainTypes);
7482
7893
  const [bindingType, setBindingType] = useState(null);
7483
7894
  React__default.useEffect(() => {
@@ -7496,7 +7907,7 @@ function RewardBindDialog({
7496
7907
  try {
7497
7908
  const success = await onBindChain(chainType);
7498
7909
  if (success) {
7499
- setNotBoundChains((prev) => prev.filter((t) => t !== chainType));
7910
+ setNotBoundChains((prev) => prev.filter((t2) => t2 !== chainType));
7500
7911
  }
7501
7912
  } finally {
7502
7913
  setBindingType(null);
@@ -7509,7 +7920,7 @@ function RewardBindDialog({
7509
7920
  onClose();
7510
7921
  }
7511
7922
  }, [skippable, onSkip, onClose]);
7512
- const tipText = skippable ? "Please link the following wallet addresses to receive rewards. You can skip this step and link later before the campaign ends." : "Please link the following wallet addresses to receive rewards. This is required for FCFS rewards.";
7923
+ const tipText = skippable ? t("please_link_following_wallet_addresses_receive_rewards_skip_step") : t("please_link_following_wallet_addresses_receive_rewards_required_fcfs");
7513
7924
  return /* @__PURE__ */ jsx(
7514
7925
  Dialog,
7515
7926
  {
@@ -7519,7 +7930,7 @@ function RewardBindDialog({
7519
7930
  handleClose();
7520
7931
  }
7521
7932
  },
7522
- title: "Link Wallet Address",
7933
+ title: t("link_wallet_address"),
7523
7934
  showCloseButton: true,
7524
7935
  maxWidth: 480,
7525
7936
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-reward-bind-dialog", children: [
@@ -7539,7 +7950,7 @@ function RewardBindDialog({
7539
7950
  {
7540
7951
  className: "taskon-reward-bind-skip-btn",
7541
7952
  onClick: onSkip,
7542
- children: "Complete the Campaign"
7953
+ children: t("complete_campaign_2")
7543
7954
  }
7544
7955
  )
7545
7956
  ] })
@@ -7557,12 +7968,12 @@ function DiscordIcon() {
7557
7968
  fill: "none",
7558
7969
  xmlns: "http://www.w3.org/2000/svg",
7559
7970
  children: [
7560
- /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "24", fill: "#5865F2" }),
7971
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "24", fill: "var(--taskon-color-link)" }),
7561
7972
  /* @__PURE__ */ jsx(
7562
7973
  "path",
7563
7974
  {
7564
7975
  d: "M32.6 17.3C31.1 16.6 29.5 16.1 27.8 15.8C27.6 16.2 27.3 16.7 27.1 17.1C25.3 16.8 23.5 16.8 21.7 17.1C21.5 16.7 21.2 16.2 21 15.8C19.3 16.1 17.7 16.6 16.2 17.3C13.2 21.8 12.4 26.2 12.8 30.5C14.8 32 16.7 32.8 18.6 33.4C19.1 32.7 19.5 31.9 19.9 31.1C19.1 30.8 18.4 30.4 17.7 29.9C17.9 29.8 18.1 29.6 18.2 29.5C22 31.3 26.2 31.3 29.9 29.5C30.1 29.7 30.3 29.8 30.4 29.9C29.7 30.4 29 30.8 28.2 31.1C28.6 31.9 29 32.7 29.5 33.4C31.4 32.8 33.3 32 35.3 30.5C35.8 25.5 34.5 21.2 32.6 17.3ZM19.4 28.1C18.4 28.1 17.6 27.2 17.6 26.1C17.6 25 18.4 24.1 19.4 24.1C20.4 24.1 21.2 25 21.2 26.1C21.2 27.2 20.4 28.1 19.4 28.1ZM28.6 28.1C27.6 28.1 26.8 27.2 26.8 26.1C26.8 25 27.6 24.1 28.6 24.1C29.6 24.1 30.4 25 30.4 26.1C30.4 27.2 29.6 28.1 28.6 28.1Z",
7565
- fill: "white"
7976
+ fill: "var(--taskon-color-text)"
7566
7977
  }
7567
7978
  )
7568
7979
  ]
@@ -7575,6 +7986,7 @@ function DiscordBindDialog({
7575
7986
  onLinkDiscord,
7576
7987
  onContinue
7577
7988
  }) {
7989
+ const { t } = useQuestLocale();
7578
7990
  return /* @__PURE__ */ jsx(
7579
7991
  Dialog,
7580
7992
  {
@@ -7584,19 +7996,23 @@ function DiscordBindDialog({
7584
7996
  onClose();
7585
7997
  }
7586
7998
  },
7587
- title: "Discord Account Not Linked",
7999
+ title: t("discord_account_linked"),
7588
8000
  showCloseButton: true,
7589
8001
  maxWidth: 440,
7590
8002
  children: /* @__PURE__ */ jsxs("div", { className: "taskon-discord-bind-dialog", children: [
7591
8003
  /* @__PURE__ */ jsx("div", { className: "taskon-discord-bind-dialog-icon-wrap", children: /* @__PURE__ */ jsx(DiscordIcon, {}) }),
7592
- /* @__PURE__ */ jsx("p", { className: "taskon-discord-bind-dialog-desc", children: "To receive the Discord Role reward, you need to link your Discord account. You can still complete the campaign without linking, but you won't be able to claim the Discord Role reward." }),
8004
+ /* @__PURE__ */ jsxs("p", { className: "taskon-discord-bind-dialog-desc", children: [
8005
+ t("receive_discord_role_reward_need_link_discord_account"),
8006
+ " ",
8007
+ t("complete_campaign_without_linking_won_t_able_claim_discord")
8008
+ ] }),
7593
8009
  /* @__PURE__ */ jsxs("div", { className: "taskon-discord-bind-dialog-buttons", children: [
7594
8010
  /* @__PURE__ */ jsx(
7595
8011
  "button",
7596
8012
  {
7597
8013
  className: "taskon-discord-bind-dialog-btn taskon-discord-bind-dialog-btn--secondary",
7598
8014
  onClick: onLinkDiscord,
7599
- children: "Link Discord Account"
8015
+ children: t("link_discord_account")
7600
8016
  }
7601
8017
  ),
7602
8018
  /* @__PURE__ */ jsx(
@@ -7604,7 +8020,7 @@ function DiscordBindDialog({
7604
8020
  {
7605
8021
  className: "taskon-discord-bind-dialog-btn taskon-discord-bind-dialog-btn--primary",
7606
8022
  onClick: onContinue,
7607
- children: "Complete Campaign"
8023
+ children: t("complete_campaign")
7608
8024
  }
7609
8025
  )
7610
8026
  ] })
@@ -7612,6 +8028,46 @@ function DiscordBindDialog({
7612
8028
  }
7613
8029
  );
7614
8030
  }
8031
+ function QuestLoadingSkeleton() {
8032
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest-loading", "aria-busy": "true", "aria-label": "Loading quest", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-layout taskon-quest-skeleton-layout", children: [
8033
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-content taskon-quest-skeleton-content", children: [
8034
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-skeleton-group", children: [
8035
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-title" }),
8036
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-meta" }),
8037
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-banner" }),
8038
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-description" }),
8039
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-description taskon-quest-skeleton-description--short" })
8040
+ ] }),
8041
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-content-divider taskon-quest-skeleton-content-divider" }),
8042
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-skeleton-group taskon-quest-skeleton-group--tasks", children: [
8043
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-section-title" }),
8044
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-progress" }),
8045
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-task" }),
8046
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-task" }),
8047
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-task" }),
8048
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-complete-button" })
8049
+ ] })
8050
+ ] }),
8051
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-divider taskon-quest-skeleton-divider" }),
8052
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-sidebar taskon-quest-skeleton-sidebar", children: [
8053
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-skeleton-panel", children: [
8054
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-title" }),
8055
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line" }),
8056
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line taskon-quest-skeleton-panel-line--short" })
8057
+ ] }),
8058
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-skeleton-panel", children: [
8059
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-title" }),
8060
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line" }),
8061
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line" }),
8062
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line taskon-quest-skeleton-panel-line--short" })
8063
+ ] }),
8064
+ /* @__PURE__ */ jsxs("div", { className: "taskon-quest-skeleton-panel", children: [
8065
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-title" }),
8066
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-skeleton-block taskon-quest-skeleton-panel-line" })
8067
+ ] })
8068
+ ] })
8069
+ ] }) });
8070
+ }
7615
8071
  function ChevronRightIcon() {
7616
8072
  return /* @__PURE__ */ jsx(
7617
8073
  "svg",
@@ -7638,11 +8094,13 @@ function ChevronRightIcon() {
7638
8094
  function WinnersRow({
7639
8095
  campaignId,
7640
8096
  winnerRewards,
7641
- pointsName = "Points",
8097
+ pointsName,
7642
8098
  onVisibleChange,
7643
8099
  className
7644
8100
  }) {
8101
+ const { t } = useQuestLocale();
7645
8102
  const { client } = useTaskOnContext();
8103
+ const resolvedPointsName = pointsName || t("points");
7646
8104
  const api = useMemo(() => {
7647
8105
  if (!client) return null;
7648
8106
  return createQuestApi(client);
@@ -7678,9 +8136,9 @@ function WinnersRow({
7678
8136
  type: "button",
7679
8137
  className: `taskon-quest-winners-row ${className || ""}`,
7680
8138
  onClick: () => setIsModalOpen(true),
7681
- "aria-label": "View winners list",
8139
+ "aria-label": t("view_winners_list"),
7682
8140
  children: [
7683
- /* @__PURE__ */ jsx("span", { className: "taskon-quest-winners-row-label", children: "Winners" }),
8141
+ /* @__PURE__ */ jsx("span", { className: "taskon-quest-winners-row-label", children: t("winners") }),
7684
8142
  /* @__PURE__ */ jsx("span", { className: "taskon-quest-winners-row-count", children: total.toLocaleString() }),
7685
8143
  /* @__PURE__ */ jsx(ChevronRightIcon, {})
7686
8144
  ]
@@ -7693,7 +8151,7 @@ function WinnersRow({
7693
8151
  onClose: () => setIsModalOpen(false),
7694
8152
  campaignId,
7695
8153
  winnerRewards,
7696
- pointsName
8154
+ pointsName: resolvedPointsName
7697
8155
  }
7698
8156
  )
7699
8157
  ] });
@@ -7747,23 +8205,10 @@ function ArrowUpRightIcon() {
7747
8205
  }
7748
8206
  function formatDateShort(timestamp) {
7749
8207
  const date = new Date(timestamp);
7750
- const months = [
7751
- "Jan",
7752
- "Feb",
7753
- "Mar",
7754
- "Apr",
7755
- "May",
7756
- "Jun",
7757
- "Jul",
7758
- "Aug",
7759
- "Sep",
7760
- "Oct",
7761
- "Nov",
7762
- "Dec"
7763
- ];
7764
- const month = months[date.getMonth()];
7765
- const day = String(date.getDate()).padStart(2, "0");
7766
- return `${month} ${day}`;
8208
+ return new Intl.DateTimeFormat("en-US", {
8209
+ month: "short",
8210
+ day: "2-digit"
8211
+ }).format(date);
7767
8212
  }
7768
8213
  function WinnersStatus({
7769
8214
  campaign,
@@ -7774,6 +8219,7 @@ function WinnersStatus({
7774
8219
  className = ""
7775
8220
  }) {
7776
8221
  var _a, _b, _c;
8222
+ const { t } = useQuestLocale();
7777
8223
  const [hasWinners, setHasWinners] = useState(false);
7778
8224
  const endTime = campaign.end_time;
7779
8225
  const isWaitingReviewPow = useMemo(() => {
@@ -7806,9 +8252,9 @@ function WinnersStatus({
7806
8252
  if (discordLink) return discordLink;
7807
8253
  return void 0;
7808
8254
  }, [discordLink]);
7809
- const handleWinnersVisibleChange = (visible) => {
8255
+ const handleWinnersVisibleChange = useCallback((visible) => {
7810
8256
  setHasWinners(visible);
7811
- };
8257
+ }, []);
7812
8258
  return /* @__PURE__ */ jsxs("div", { className: `taskon-winners ${className}`, children: [
7813
8259
  isWaitingReviewPow && (powReviewLink ? /* @__PURE__ */ jsxs(
7814
8260
  "a",
@@ -7819,29 +8265,35 @@ function WinnersStatus({
7819
8265
  className: "taskon-winners-alert",
7820
8266
  children: [
7821
8267
  /* @__PURE__ */ jsx(TimerIcon, {}),
7822
- /* @__PURE__ */ jsxs("span", { className: "taskon-winners-alert-text", children: [
7823
- "Waiting for",
7824
- " ",
7825
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-community", children: campaign.community_name }),
7826
- " ",
7827
- "Reviewed All Tasks"
7828
- ] }),
8268
+ /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-text", children: /* @__PURE__ */ jsx(
8269
+ I18nT,
8270
+ {
8271
+ t,
8272
+ i18nKey: "waiting_community_reviewed_tasks",
8273
+ components: {
8274
+ community: /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-community", children: campaign.community_name })
8275
+ }
8276
+ }
8277
+ ) }),
7829
8278
  /* @__PURE__ */ jsx(ArrowUpRightIcon, {})
7830
8279
  ]
7831
8280
  }
7832
8281
  ) : /* @__PURE__ */ jsxs("div", { className: "taskon-winners-alert", children: [
7833
8282
  /* @__PURE__ */ jsx(TimerIcon, {}),
7834
- /* @__PURE__ */ jsxs("span", { className: "taskon-winners-alert-text", children: [
7835
- "Waiting for",
7836
- " ",
7837
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-community", children: campaign.community_name }),
7838
- " ",
7839
- "Reviewed All Tasks"
7840
- ] })
8283
+ /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-text", children: /* @__PURE__ */ jsx(
8284
+ I18nT,
8285
+ {
8286
+ t,
8287
+ i18nKey: "waiting_community_reviewed_tasks",
8288
+ components: {
8289
+ community: /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-community", children: campaign.community_name })
8290
+ }
8291
+ }
8292
+ ) })
7841
8293
  ] })),
7842
8294
  !isWaitingReviewPow && isDrawingWinner && /* @__PURE__ */ jsxs("div", { className: "taskon-winners-alert", children: [
7843
8295
  /* @__PURE__ */ jsx(TimerIcon, {}),
7844
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-text", children: "System is Drawing Winners..." })
8296
+ /* @__PURE__ */ jsx("span", { className: "taskon-winners-alert-text", children: t("system_drawing_winners") })
7845
8297
  ] }),
7846
8298
  /* @__PURE__ */ jsxs(
7847
8299
  "div",
@@ -7850,22 +8302,26 @@ function WinnersStatus({
7850
8302
  style: { display: isShowContent ? "block" : "none" },
7851
8303
  children: [
7852
8304
  isWaitingReviewPow && /* @__PURE__ */ jsxs("div", { className: "taskon-winners-pow-info", children: [
7853
- "*This quest includes Proof of Work (POW) tasks, which",
7854
- " ",
7855
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-pow-info-community", children: campaign.community_name }),
7856
- " ",
7857
- "will review. Winners will be selected",
7858
- " ",
7859
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-pow-info-only", children: "ONLY" }),
7860
- " after all tasks have been reviewed."
8305
+ "*",
8306
+ /* @__PURE__ */ jsx(
8307
+ I18nT,
8308
+ {
8309
+ t,
8310
+ i18nKey: "quest_includes_proof_work_pow_tasks_which_community_review",
8311
+ components: {
8312
+ community: /* @__PURE__ */ jsx("span", { className: "taskon-winners-pow-info-community", children: campaign.community_name }),
8313
+ only: /* @__PURE__ */ jsx("span", { className: "taskon-winners-pow-info-only", children: t("only") })
8314
+ }
8315
+ }
8316
+ )
7861
8317
  ] }),
7862
8318
  /* @__PURE__ */ jsxs("div", { className: "taskon-winners-card", children: [
7863
8319
  isWaitingReviewPow && /* @__PURE__ */ jsxs("div", { className: "taskon-winners-card-row", children: [
7864
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-label", children: "System will automatically select winners in" }),
8320
+ /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-label", children: t("system_automatically_select_winners") }),
7865
8321
  /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-value", children: reviewDeadlineText })
7866
8322
  ] }),
7867
8323
  isDrawingWinner && /* @__PURE__ */ jsxs("div", { className: "taskon-winners-card-row", children: [
7868
- /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-label", children: "All winners are to be announced by" }),
8324
+ /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-label", children: t("winners_announced") }),
7869
8325
  /* @__PURE__ */ jsx("span", { className: "taskon-winners-card-value--primary", children: drawWinnersDeadlineText })
7870
8326
  ] }),
7871
8327
  /* @__PURE__ */ jsx(
@@ -7884,19 +8340,62 @@ function WinnersStatus({
7884
8340
  ] });
7885
8341
  }
7886
8342
  function mergeQuestConfig(props, cloud) {
7887
- var _a, _b, _c, _d;
7888
8343
  return {
7889
8344
  // campaignId: props > cloud > 0 (will be validated by caller)
7890
8345
  campaignId: props.campaignId ?? (cloud == null ? void 0 : cloud.campaignId) ?? 0,
7891
- // Display options: props > cloud > true (default show all)
7892
- showTitle: props.showTitle ?? ((_a = cloud == null ? void 0 : cloud.displayOptions) == null ? void 0 : _a.showTitle) ?? true,
7893
- showDescription: props.showDescription ?? ((_b = cloud == null ? void 0 : cloud.displayOptions) == null ? void 0 : _b.showDescription) ?? true,
7894
- showBanner: props.showBanner ?? ((_c = cloud == null ? void 0 : cloud.displayOptions) == null ? void 0 : _c.showBanner) ?? true,
7895
- // Share text: props > cloud custom text (if enabled) > undefined
7896
- shareText: props.shareText ?? (((_d = cloud == null ? void 0 : cloud.otherOptions) == null ? void 0 : _d.enableCustomTwitterShareText) ? cloud.otherOptions.customTwitterShareText : void 0)
8346
+ // Display options: props > cloud (flat fields) > true (default show all)
8347
+ showTitle: props.showTitle ?? (cloud == null ? void 0 : cloud.showTitle) ?? true,
8348
+ showDescription: props.showDescription ?? (cloud == null ? void 0 : cloud.showDescription) ?? true,
8349
+ showBanner: props.showBanner ?? (cloud == null ? void 0 : cloud.showBanner) ?? true,
8350
+ showParticipants: props.showParticipants ?? (cloud == null ? void 0 : cloud.showParticipants) ?? true,
8351
+ // Share: whether to show share button
8352
+ // props > cloud > true
8353
+ showShare: props.showShare ?? (cloud == null ? void 0 : cloud.showShare) ?? true,
8354
+ // Share: props shareText > cloud shareText (when showShare) > undefined
8355
+ shareText: props.shareText ?? ((cloud == null ? void 0 : cloud.showShare) ? cloud.shareText : void 0),
8356
+ // Share URL: props > cloud shareUrl > undefined (fallback to window.location.href at runtime)
8357
+ shareUrl: props.shareUrl ?? ((cloud == null ? void 0 : cloud.shareUrl) || void 0),
8358
+ // Auto append link: props > cloud > true
8359
+ shareAutoAppendLink: props.shareAutoAppendLink ?? (cloud == null ? void 0 : cloud.shareAutoAppendLink) ?? true,
8360
+ // Reward display mode: props > cloud > 'popup'
8361
+ rewardDisplayMode: props.rewardDisplayMode ?? (cloud == null ? void 0 : cloud.rewardDisplayMode) ?? "popup",
8362
+ rewardRedirectUrl: props.rewardRedirectUrl ?? (cloud == null ? void 0 : cloud.rewardRedirectUrl) ?? ""
8363
+ };
8364
+ }
8365
+ function createQuestNftClaimMessages(t) {
8366
+ return {
8367
+ claimDialog: {
8368
+ claimNft: t("claim_nft"),
8369
+ claimingNft: t("claiming_nft"),
8370
+ claimConnectingWallet: t("connecting_wallet"),
8371
+ claimSwitchingNetwork: t("switching_network"),
8372
+ claimGettingSignature: t("getting_signature"),
8373
+ claimConfirmInWallet: t("please_confirm_wallet"),
8374
+ claimTransactionPending: t("transaction_pending"),
8375
+ claimSuccess: t("claim_successful"),
8376
+ claimFailed: t("claim_failed"),
8377
+ claimCanceled: t("transaction_rejected_user"),
8378
+ viewOnExplorer: t("view_explorer"),
8379
+ retry: t("retry"),
8380
+ close: t("close")
8381
+ },
8382
+ pendingDialog: {
8383
+ pendingTransaction: t("pending_transaction"),
8384
+ claimPendingTitle: t(
8385
+ "already_claimed_nft_please_wait_transaction_confirmed"
8386
+ ),
8387
+ claimPendingCheckExplorer: t("check_transaction_explorer"),
8388
+ claimPendingHashLabel: t("transaction_hash"),
8389
+ claimPendingClaimAgainWarn: t(
8390
+ "claim_again_send_new_transaction_recommended_when_sure_there"
8391
+ ),
8392
+ claimPendingReceiveAddressNoChange: t("receive_address_t_changed"),
8393
+ claimAgain: t("claim_again"),
8394
+ continueWaiting: t("continue_waiting")
8395
+ }
7897
8396
  };
7898
8397
  }
7899
- function getQuestStatusDisplay(campaignStatus, startTime, endTime, isEnd) {
8398
+ function getQuestStatusDisplay(campaignStatus, startTime, endTime, isEnd, labels) {
7900
8399
  const now = Date.now();
7901
8400
  const startMs = startTime;
7902
8401
  const endMs = endTime;
@@ -7907,13 +8406,13 @@ function getQuestStatusDisplay(campaignStatus, startTime, endTime, isEnd) {
7907
8406
  let label;
7908
8407
  if (!isStarted) {
7909
8408
  status = "upcoming";
7910
- label = "Upcoming";
8409
+ label = labels.upcoming;
7911
8410
  } else if (isEnded) {
7912
8411
  status = "ended";
7913
- label = "Ended";
8412
+ label = labels.ended;
7914
8413
  } else {
7915
8414
  status = "ongoing";
7916
- label = "Ongoing";
8415
+ label = labels.ongoing;
7917
8416
  }
7918
8417
  return {
7919
8418
  status,
@@ -7932,22 +8431,39 @@ function getHasRanking(winnerRewards) {
7932
8431
  );
7933
8432
  }
7934
8433
  function QuestWidget(props) {
7935
- const { widgetId } = props;
8434
+ const { widgetId, themeMode } = props;
8435
+ const { t } = useQuestLocale();
7936
8436
  const { functionConfig, cloudTheme, isConfigLoading, configError } = useResolvedWidgetConfig(widgetId);
7937
8437
  const mergedConfig = useMemo(() => {
7938
8438
  return mergeQuestConfig(
7939
8439
  props,
7940
8440
  functionConfig ?? null
7941
8441
  );
7942
- }, [props.campaignId, props.showTitle, props.showDescription, props.showBanner, props.shareText, functionConfig]);
8442
+ }, [
8443
+ props.campaignId,
8444
+ props.showTitle,
8445
+ props.showDescription,
8446
+ props.showBanner,
8447
+ props.showParticipants,
8448
+ props.showShare,
8449
+ props.shareText,
8450
+ props.shareUrl,
8451
+ props.shareAutoAppendLink,
8452
+ props.rewardDisplayMode,
8453
+ props.rewardRedirectUrl,
8454
+ functionConfig
8455
+ ]);
7943
8456
  return /* @__PURE__ */ jsx(
7944
8457
  WidgetShell,
7945
8458
  {
7946
8459
  widgetId,
7947
8460
  isConfigLoading,
7948
8461
  cloudTheme,
8462
+ themeMode,
7949
8463
  className: "taskon-quest",
7950
- errorMessage: configError ?? (!mergedConfig.campaignId ? "Campaign ID is required. Please provide campaignId via props or widgetId." : void 0),
8464
+ errorMessage: configError ?? (!mergedConfig.campaignId ? t(
8465
+ "campaign_id_required_please_provide_campaignid_via_props_widgetid"
8466
+ ) : void 0),
7951
8467
  children: /* @__PURE__ */ jsx(
7952
8468
  QuestWidgetInner,
7953
8469
  {
@@ -7956,7 +8472,13 @@ function QuestWidget(props) {
7956
8472
  showBanner: mergedConfig.showBanner,
7957
8473
  showTitle: mergedConfig.showTitle,
7958
8474
  showDescription: mergedConfig.showDescription,
7959
- shareText: mergedConfig.shareText
8475
+ showParticipants: mergedConfig.showParticipants,
8476
+ shareText: mergedConfig.shareText,
8477
+ shareUrl: mergedConfig.shareUrl,
8478
+ showShare: mergedConfig.showShare,
8479
+ shareAutoAppendLink: mergedConfig.shareAutoAppendLink,
8480
+ rewardDisplayMode: mergedConfig.rewardDisplayMode,
8481
+ rewardRedirectUrl: mergedConfig.rewardRedirectUrl
7960
8482
  }
7961
8483
  )
7962
8484
  }
@@ -7964,6 +8486,7 @@ function QuestWidget(props) {
7964
8486
  }
7965
8487
  function QuestWidgetInner(props) {
7966
8488
  var _a, _b, _c, _d, _e;
8489
+ const { t } = useQuestLocale();
7967
8490
  const {
7968
8491
  campaignId,
7969
8492
  channel,
@@ -7974,19 +8497,35 @@ function QuestWidgetInner(props) {
7974
8497
  showBanner = true,
7975
8498
  showTitle = true,
7976
8499
  showDescription = true,
8500
+ showParticipants = true,
7977
8501
  onLoaded,
7978
8502
  onTaskCompleted,
7979
8503
  onSubmitSuccess,
7980
8504
  onError,
7981
8505
  onConnectWallet,
7982
- onClaimNft,
7983
8506
  onClaimDiscordRole,
7984
8507
  // onBindChainRequired 和 onBindSnsRequired 已弃用,绑定现在由 Widget 内部处理
7985
8508
  shareUrl,
7986
- shareText
8509
+ shareText,
8510
+ showShare,
8511
+ shareAutoAppendLink,
8512
+ rewardDisplayMode,
8513
+ rewardRedirectUrl
7987
8514
  } = props;
7988
- const { client, chains, isLoggedIn, userInfo, requestLogin, communityInfo } = useTaskOnContext();
8515
+ const {
8516
+ client,
8517
+ chains,
8518
+ isLoggedIn,
8519
+ userInfo,
8520
+ userToken,
8521
+ requestLogin,
8522
+ communityInfo
8523
+ } = useTaskOnContext();
7989
8524
  const { toast } = useToast();
8525
+ const questNftClaimMessages = useMemo(
8526
+ () => createQuestNftClaimMessages(t),
8527
+ [t]
8528
+ );
7990
8529
  const chainMap = useMemo(() => {
7991
8530
  if (!chains || chains.length === 0) return {};
7992
8531
  return Object.fromEntries(
@@ -8005,9 +8544,7 @@ function QuestWidgetInner(props) {
8005
8544
  const { bindAndWait: bindChainAndWait } = useBindWallet({
8006
8545
  onFailed: (error2) => {
8007
8546
  toast.error(error2);
8008
- },
8009
- // 当没有 adapter 时触发外部弹窗(如果配置了的话)
8010
- onNeedWalletDialog: onConnectWallet
8547
+ }
8011
8548
  });
8012
8549
  const {
8013
8550
  data: campaign,
@@ -8033,7 +8570,8 @@ function QuestWidgetInner(props) {
8033
8570
  campaignId,
8034
8571
  channel,
8035
8572
  kolHandle,
8036
- enabled: !isPreview
8573
+ enabled: !isPreview,
8574
+ authToken: userToken
8037
8575
  });
8038
8576
  const {
8039
8577
  data: questStatus,
@@ -8047,6 +8585,31 @@ function QuestWidgetInner(props) {
8047
8585
  kolHandle,
8048
8586
  enabled: !isPreview
8049
8587
  });
8588
+ const {
8589
+ claimNftReward,
8590
+ isSupportedNftRewardType,
8591
+ dialogs: nftClaimDialogs
8592
+ } = useNftClaimFlow({
8593
+ campaignId,
8594
+ targetType: (campaign == null ? void 0 : campaign.campaign_type) === CampaignType.Event ? "event" : "campaign",
8595
+ messages: questNftClaimMessages,
8596
+ onClaimSuccess: async () => {
8597
+ refetchUserStatus();
8598
+ refetchStatus();
8599
+ },
8600
+ onClaimError: (error2) => {
8601
+ toast.error(error2.message || t("failed_claim_nft"));
8602
+ }
8603
+ });
8604
+ const handleQuestClaimNft = useCallback(
8605
+ async (reward, layer) => {
8606
+ if (!isSupportedNftRewardType(reward.reward_type)) {
8607
+ return;
8608
+ }
8609
+ await claimNftReward(reward, layer);
8610
+ },
8611
+ [isSupportedNftRewardType, claimNftReward]
8612
+ );
8050
8613
  const {
8051
8614
  mandatoryTasks,
8052
8615
  optionalTasks,
@@ -8077,9 +8640,14 @@ function QuestWidgetInner(props) {
8077
8640
  campaign.campaign_status,
8078
8641
  campaign.start_time,
8079
8642
  campaign.end_time,
8080
- campaign.is_end
8643
+ campaign.is_end,
8644
+ {
8645
+ upcoming: t("upcoming"),
8646
+ ended: t("ended"),
8647
+ ongoing: t("ongoing")
8648
+ }
8081
8649
  );
8082
- }, [campaign]);
8650
+ }, [campaign, t]);
8083
8651
  const isTaskDisabled = useMemo(() => {
8084
8652
  if (!statusDisplay) return true;
8085
8653
  return !statusDisplay.isActive;
@@ -8102,6 +8670,17 @@ function QuestWidgetInner(props) {
8102
8670
  const [blindBoxEmptyReward, setBlindBoxEmptyReward] = useState();
8103
8671
  const [blindBoxTokenPrice, setBlindBoxTokenPrice] = useState();
8104
8672
  const [isClaimingBlindBox, setIsClaimingBlindBox] = useState(false);
8673
+ const [hasCompletedBlindBoxClaim, setHasCompletedBlindBoxClaim] = useState(false);
8674
+ const closeBlindBoxModal = useCallback(() => {
8675
+ setBlindBoxDialogVisible(false);
8676
+ setBlindBoxRewardVisible(false);
8677
+ }, []);
8678
+ const handleBlindBoxDialogOpenChange = useCallback((open) => {
8679
+ setBlindBoxDialogVisible(open);
8680
+ if (!open) {
8681
+ setBlindBoxRewardVisible(false);
8682
+ }
8683
+ }, []);
8105
8684
  const buildBlindBoxRewardValue = useCallback(
8106
8685
  (amount) => {
8107
8686
  if (!blindBoxTokenReward) {
@@ -8136,15 +8715,17 @@ function QuestWidgetInner(props) {
8136
8715
  [blindBoxTokenReward]
8137
8716
  );
8138
8717
  const handleOpenBlindBox = useCallback(() => {
8139
- setBlindBoxRewardVisible(false);
8140
8718
  setBlindBoxDialogVisible(true);
8719
+ setBlindBoxRewardVisible(false);
8141
8720
  }, []);
8142
8721
  const handleBlindBoxOpened = useCallback(async () => {
8143
8722
  var _a2;
8144
8723
  if (isClaimingBlindBox || !api) return;
8145
8724
  setIsClaimingBlindBox(true);
8146
8725
  try {
8147
- const result = await api.claimBlindBoxRewards({ campaign_id: campaignId });
8726
+ const result = await api.claimBlindBoxRewards({
8727
+ campaign_id: campaignId
8728
+ });
8148
8729
  const amount = (result ?? "").toString().trim();
8149
8730
  const normalized = amount !== "" ? amount : "0";
8150
8731
  if (normalized !== "0") {
@@ -8158,22 +8739,40 @@ function QuestWidgetInner(props) {
8158
8739
  }
8159
8740
  refetchUserStatus();
8160
8741
  refetchStatus();
8161
- setBlindBoxDialogVisible(false);
8742
+ setHasCompletedBlindBoxClaim(true);
8162
8743
  setBlindBoxRewardVisible(true);
8163
8744
  } catch (error2) {
8164
8745
  console.error("Claim blind box error:", error2);
8165
- const errorMessage = error2 instanceof Error ? error2.message : "Network error, please try again";
8746
+ const errorMessage = error2 instanceof Error ? error2.message : t("network_error_please_try_again");
8166
8747
  toast.error(errorMessage);
8167
8748
  (_a2 = blindBoxDialogRef.current) == null ? void 0 : _a2.resetToUnopened();
8168
8749
  } finally {
8169
8750
  setIsClaimingBlindBox(false);
8170
8751
  }
8171
- }, [isClaimingBlindBox, api, campaignId, buildBlindBoxRewardValue, refetchUserStatus, refetchStatus, toast]);
8752
+ }, [
8753
+ isClaimingBlindBox,
8754
+ api,
8755
+ campaignId,
8756
+ buildBlindBoxRewardValue,
8757
+ refetchUserStatus,
8758
+ refetchStatus,
8759
+ t,
8760
+ toast
8761
+ ]);
8172
8762
  useEffect(() => {
8173
- if (userBlindBoxStatus === "wait-claim" && !isBlindBoxDialogVisible && !isBlindBoxRewardVisible) {
8763
+ if (userBlindBoxStatus === "wait-claim" && !isBlindBoxDialogVisible && !isBlindBoxRewardVisible && !hasCompletedBlindBoxClaim) {
8174
8764
  handleOpenBlindBox();
8175
8765
  }
8176
- }, [userBlindBoxStatus, isBlindBoxDialogVisible, isBlindBoxRewardVisible, handleOpenBlindBox]);
8766
+ }, [
8767
+ userBlindBoxStatus,
8768
+ isBlindBoxDialogVisible,
8769
+ isBlindBoxRewardVisible,
8770
+ hasCompletedBlindBoxClaim,
8771
+ handleOpenBlindBox
8772
+ ]);
8773
+ useEffect(() => {
8774
+ setHasCompletedBlindBoxClaim(false);
8775
+ }, [campaignId]);
8177
8776
  const isLoading = isDetailLoading || isUserStatusLoading || isStatusLoading;
8178
8777
  const error = detailError || userStatusError || statusError;
8179
8778
  useEffect(() => {
@@ -8194,7 +8793,7 @@ function QuestWidgetInner(props) {
8194
8793
  const handleTaskCompleted = (taskId, result) => {
8195
8794
  var _a2;
8196
8795
  const successTaskIds = (result == null ? void 0 : result.success_tasks) ?? [taskId];
8197
- const task = (_a2 = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _a2.find((t) => t.id === taskId);
8796
+ const task = (_a2 = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _a2.find((t2) => t2.id === taskId);
8198
8797
  const isSwapDex = (task == null ? void 0 : task.template_id) === "SwapDexContractInteractive";
8199
8798
  const isSuccess = successTaskIds.includes(taskId);
8200
8799
  if (isSuccess) {
@@ -8207,6 +8806,22 @@ function QuestWidgetInner(props) {
8207
8806
  refetchUserStatus();
8208
8807
  }
8209
8808
  };
8809
+ const handleTaskVerifyAttempted = useCallback(
8810
+ (taskId, success) => {
8811
+ var _a2;
8812
+ if (success || isPreview) {
8813
+ return;
8814
+ }
8815
+ const targetTask = (_a2 = campaign == null ? void 0 : campaign.tasks) == null ? void 0 : _a2.find((task) => task.id === taskId);
8816
+ if (!targetTask) {
8817
+ return;
8818
+ }
8819
+ if (targetTask.template_id === "SwapDexContractInteractive") {
8820
+ refetchUserStatus();
8821
+ }
8822
+ },
8823
+ [campaign == null ? void 0 : campaign.tasks, isPreview, refetchUserStatus]
8824
+ );
8210
8825
  const handleSubmitSuccess = () => {
8211
8826
  refetchDetail();
8212
8827
  refetchUserStatus();
@@ -8223,7 +8838,6 @@ function QuestWidgetInner(props) {
8223
8838
  // 绑定弹窗相关
8224
8839
  eligsBindInfo,
8225
8840
  closeEligsBindDialog,
8226
- skipEligsBind,
8227
8841
  onAllEligsBind
8228
8842
  } = useEligibilityRefresh({
8229
8843
  api,
@@ -8242,6 +8856,42 @@ function QuestWidgetInner(props) {
8242
8856
  await refetchUserStatus();
8243
8857
  }
8244
8858
  });
8859
+ const [completeEligibilityFailedInfo, setCompleteEligibilityFailedInfo] = useState(null);
8860
+ const [isRefreshingCompleteEligs, setIsRefreshingCompleteEligs] = useState(false);
8861
+ const closeCompleteEligibilityFailedDialog = useCallback(() => {
8862
+ setCompleteEligibilityFailedInfo(null);
8863
+ }, []);
8864
+ const refreshCompleteEligibilityInDialog = useCallback(async () => {
8865
+ if (!api || !campaign) {
8866
+ return;
8867
+ }
8868
+ setIsRefreshingCompleteEligs(true);
8869
+ try {
8870
+ const result = await api.checkUserCampaignEligibility({
8871
+ campaign_id: campaign.id
8872
+ });
8873
+ if (result.result) {
8874
+ setCompleteEligibilityFailedInfo(null);
8875
+ await refetchUserStatus();
8876
+ return;
8877
+ }
8878
+ setCompleteEligibilityFailedInfo((previousInfo) => {
8879
+ if (!previousInfo) {
8880
+ return {
8881
+ eligs: campaign.eligs,
8882
+ eligibilityExpress: campaign.eligibility_express || "and",
8883
+ details: result.details
8884
+ };
8885
+ }
8886
+ return {
8887
+ ...previousInfo,
8888
+ details: result.details
8889
+ };
8890
+ });
8891
+ } finally {
8892
+ setIsRefreshingCompleteEligs(false);
8893
+ }
8894
+ }, [api, campaign, refetchUserStatus]);
8245
8895
  const {
8246
8896
  validateBeforeComplete,
8247
8897
  // Task validation error dialog
@@ -8277,9 +8927,10 @@ function QuestWidgetInner(props) {
8277
8927
  onBindSns: async (snsType) => {
8278
8928
  return await bindSnsAndWait(snsType);
8279
8929
  },
8280
- // When eligibility check fails, show the existing EligsNotPassDialog
8281
- onEligibilityFailed: () => {
8282
- return false;
8930
+ // Complete eligibility 检查失败:
8931
+ // 弹出 EligsNotPassDialog 并阻断 complete,行为对齐 Vue。
8932
+ onEligibilityFailed: (info) => {
8933
+ setCompleteEligibilityFailedInfo(info);
8283
8934
  }
8284
8935
  });
8285
8936
  const hasEligibility = (campaign == null ? void 0 : campaign.eligs) && campaign.eligs.length > 0;
@@ -8289,10 +8940,7 @@ function QuestWidgetInner(props) {
8289
8940
  return userStatus.campaign_eligible !== UserEligibleStatus.Eligible;
8290
8941
  }, [statusDisplay == null ? void 0 : statusDisplay.isActive, userStatus]);
8291
8942
  if (isLoading && !campaign) {
8292
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-loading", children: [
8293
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-loading-spinner" }),
8294
- /* @__PURE__ */ jsx("span", { children: "Loading quest..." })
8295
- ] }) });
8943
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest", children: /* @__PURE__ */ jsx(QuestLoadingSkeleton, {}) });
8296
8944
  }
8297
8945
  if (error && !campaign) {
8298
8946
  return /* @__PURE__ */ jsx("div", { className: "taskon-quest", children: /* @__PURE__ */ jsxs("div", { className: "taskon-quest-error", children: [
@@ -8307,13 +8955,13 @@ function QuestWidgetInner(props) {
8307
8955
  refetchUserStatus();
8308
8956
  refetchStatus();
8309
8957
  },
8310
- children: "Retry"
8958
+ children: t("retry")
8311
8959
  }
8312
8960
  )
8313
8961
  ] }) });
8314
8962
  }
8315
8963
  if (!campaign) {
8316
- return /* @__PURE__ */ jsx("div", { className: "taskon-quest", children: /* @__PURE__ */ jsx("div", { className: "taskon-quest-empty", children: "Quest not found" }) });
8964
+ return /* @__PURE__ */ jsx("div", { className: "taskon-quest", children: /* @__PURE__ */ jsx("div", { className: "taskon-quest-empty", children: t("quest_found") }) });
8317
8965
  }
8318
8966
  return /* @__PURE__ */ jsxs("div", { className: "taskon-quest", children: [
8319
8967
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-layout", children: [
@@ -8332,6 +8980,8 @@ function QuestWidgetInner(props) {
8332
8980
  showDescription,
8333
8981
  shareUrl,
8334
8982
  shareText,
8983
+ showShare,
8984
+ shareAutoAppendLink,
8335
8985
  communityName: campaign.community_name,
8336
8986
  communityAvatar: campaign.community_avatar,
8337
8987
  winnerRewardsSimple: campaign.winner_rewards_simple
@@ -8339,13 +8989,14 @@ function QuestWidgetInner(props) {
8339
8989
  ),
8340
8990
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-content-divider" }),
8341
8991
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-tasks", children: [
8342
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-tasks-header", children: /* @__PURE__ */ jsx("h2", { className: "taskon-quest-tasks-title", children: "Task" }) }),
8992
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-tasks-header", children: /* @__PURE__ */ jsx("h2", { className: "taskon-quest-tasks-title", children: t("task") }) }),
8343
8993
  mandatoryTasks.length > 0 && optionalTasks.length === 0 && /* @__PURE__ */ jsx(
8344
8994
  CompletedCount,
8345
8995
  {
8346
8996
  className: "taskon-quest-tasks-progress",
8347
8997
  current: mandatoryCompleted + optionalCompleted,
8348
- total: mandatoryTotal + optionalTotal
8998
+ total: mandatoryTotal + optionalTotal,
8999
+ completedLabel: t("completed")
8349
9000
  }
8350
9001
  ),
8351
9002
  /* @__PURE__ */ jsx(
@@ -8356,6 +9007,7 @@ function QuestWidgetInner(props) {
8356
9007
  optionalTasks: optionalTaskData,
8357
9008
  userTaskStatus: userTaskStatusMap,
8358
9009
  onTaskCompleted: handleTaskCompleted,
9010
+ onVerifyAttempted: handleTaskVerifyAttempted,
8359
9011
  onBeforeVerify: checkBeforeSubmitTask,
8360
9012
  disabled: isTaskDisabled,
8361
9013
  isStarted: statusDisplay == null ? void 0 : statusDisplay.isStarted,
@@ -8365,7 +9017,10 @@ function QuestWidgetInner(props) {
8365
9017
  ownerName: campaign == null ? void 0 : campaign.community_name,
8366
9018
  isEnded: statusDisplay == null ? void 0 : statusDisplay.isEnded,
8367
9019
  minOptionalTasks: campaign == null ? void 0 : campaign.min_finished_optional_task_num,
8368
- minOptionalPoints: campaign == null ? void 0 : campaign.min_finished_optional_task_points
9020
+ minOptionalPoints: campaign == null ? void 0 : campaign.min_finished_optional_task_points,
9021
+ onCooldownComplete: () => {
9022
+ refetchUserStatus();
9023
+ }
8369
9024
  }
8370
9025
  ),
8371
9026
  /* @__PURE__ */ jsx(
@@ -8384,9 +9039,11 @@ function QuestWidgetInner(props) {
8384
9039
  refetchStatus();
8385
9040
  },
8386
9041
  onConnectWallet,
8387
- onClaimNft,
9042
+ onClaimNft: handleQuestClaimNft,
8388
9043
  onClaimDiscordRole,
8389
- onBeforeComplete: validateBeforeComplete
9044
+ onBeforeComplete: validateBeforeComplete,
9045
+ rewardDisplayMode,
9046
+ rewardRedirectUrl
8390
9047
  }
8391
9048
  )
8392
9049
  ] })
@@ -8394,7 +9051,7 @@ function QuestWidgetInner(props) {
8394
9051
  /* @__PURE__ */ jsx("div", { className: "taskon-quest-divider" }),
8395
9052
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-sidebar", children: [
8396
9053
  (statusDisplay == null ? void 0 : statusDisplay.isEnded) && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-winners-section", children: [
8397
- /* @__PURE__ */ jsx("h3", { className: "taskon-quest-winners-section-title", children: "Winners" }),
9054
+ /* @__PURE__ */ jsx("h3", { className: "taskon-quest-winners-section-title", children: t("winners") }),
8398
9055
  /* @__PURE__ */ jsx(
8399
9056
  WinnersStatus,
8400
9057
  {
@@ -8407,7 +9064,7 @@ function QuestWidgetInner(props) {
8407
9064
  )
8408
9065
  ] }),
8409
9066
  /* @__PURE__ */ jsxs("div", { className: "taskon-quest-rewards-section", children: [
8410
- /* @__PURE__ */ jsx("h3", { className: "taskon-quest-rewards-section-title", children: "Quest Rewards" }),
9067
+ /* @__PURE__ */ jsx("h3", { className: "taskon-quest-rewards-section-title", children: t("quest_rewards") }),
8411
9068
  /* @__PURE__ */ jsx(
8412
9069
  QuestRewards,
8413
9070
  {
@@ -8431,7 +9088,7 @@ function QuestWidgetInner(props) {
8431
9088
  )
8432
9089
  ] }),
8433
9090
  hasEligibility && /* @__PURE__ */ jsxs("div", { className: "taskon-quest-eligs-section", children: [
8434
- /* @__PURE__ */ jsx("div", { className: "taskon-quest-eligs-section-header", children: /* @__PURE__ */ jsx("h3", { className: "taskon-quest-eligs-section-title", children: "Quest Eligibility" }) }),
9091
+ /* @__PURE__ */ jsx("div", { className: "taskon-quest-eligs-section-header", children: /* @__PURE__ */ jsx("h3", { className: "taskon-quest-eligs-section-title", children: t("quest_eligibility") }) }),
8435
9092
  /* @__PURE__ */ jsx(
8436
9093
  EligibilityInfo,
8437
9094
  {
@@ -8448,7 +9105,7 @@ function QuestWidgetInner(props) {
8448
9105
  }
8449
9106
  )
8450
9107
  ] }),
8451
- questStatus && /* @__PURE__ */ jsx(
9108
+ questStatus && showParticipants && /* @__PURE__ */ jsx(
8452
9109
  ParticipantsInfo,
8453
9110
  {
8454
9111
  participantCount: questStatus.statistics.participant_number
@@ -8460,38 +9117,27 @@ function QuestWidgetInner(props) {
8460
9117
  Dialog,
8461
9118
  {
8462
9119
  open: isBlindBoxDialogVisible,
8463
- onOpenChange: setBlindBoxDialogVisible,
8464
- title: "Open Blind Box",
8465
- showCloseButton: false,
8466
- closeOnOverlayClick: false,
8467
- closeOnEscapeKey: false,
8468
- contentClassName: "taskon-quest-blindbox-dialog-wrapper",
8469
- children: /* @__PURE__ */ jsx(
8470
- BlindBoxDialog,
8471
- {
8472
- ref: blindBoxDialogRef,
8473
- onClose: () => setBlindBoxDialogVisible(false),
8474
- onOpened: handleBlindBoxOpened
8475
- }
8476
- )
8477
- }
8478
- ),
8479
- /* @__PURE__ */ jsx(
8480
- Dialog,
8481
- {
8482
- open: isBlindBoxRewardVisible,
8483
- onOpenChange: setBlindBoxRewardVisible,
8484
- title: "Blind Box Reward",
8485
- showCloseButton: true,
8486
- contentClassName: "taskon-quest-blindbox-reward-wrapper",
8487
- children: /* @__PURE__ */ jsx(
9120
+ onOpenChange: handleBlindBoxDialogOpenChange,
9121
+ title: isBlindBoxRewardVisible ? t("blind_box_reward") : t("open_blind_box"),
9122
+ showCloseButton: isBlindBoxRewardVisible,
9123
+ closeOnOverlayClick: isBlindBoxRewardVisible,
9124
+ closeOnEscapeKey: isBlindBoxRewardVisible,
9125
+ contentClassName: `taskon-quest-blindbox-dialog-wrapper${isBlindBoxRewardVisible ? " taskon-quest-blindbox-dialog-wrapper--result" : ""}`,
9126
+ children: isBlindBoxRewardVisible ? /* @__PURE__ */ jsx(
8488
9127
  BlindBoxRewardDialog,
8489
9128
  {
8490
9129
  rewards: blindBoxWinnerRewards,
8491
9130
  emptyReward: blindBoxEmptyReward,
8492
9131
  tokenPrice: blindBoxTokenPrice,
8493
9132
  loading: isClaimingBlindBox,
8494
- onClose: () => setBlindBoxRewardVisible(false)
9133
+ onClose: closeBlindBoxModal
9134
+ }
9135
+ ) : /* @__PURE__ */ jsx(
9136
+ BlindBoxDialog,
9137
+ {
9138
+ ref: blindBoxDialogRef,
9139
+ onClose: closeBlindBoxModal,
9140
+ onOpened: handleBlindBoxOpened
8495
9141
  }
8496
9142
  )
8497
9143
  }
@@ -8511,6 +9157,21 @@ function QuestWidgetInner(props) {
8511
9157
  isRefreshing: isRefreshingEligs
8512
9158
  }
8513
9159
  ),
9160
+ completeEligibilityFailedInfo && campaign && /* @__PURE__ */ jsx(
9161
+ EligsNotPassDialog,
9162
+ {
9163
+ open: !!completeEligibilityFailedInfo,
9164
+ onClose: closeCompleteEligibilityFailedDialog,
9165
+ eligs: completeEligibilityFailedInfo.eligs,
9166
+ eligibilityExpress: completeEligibilityFailedInfo.eligibilityExpress,
9167
+ details: completeEligibilityFailedInfo.details,
9168
+ campaignId,
9169
+ communityKey: campaign.community_key,
9170
+ communityName: campaign.community_name,
9171
+ onRefresh: refreshCompleteEligibilityInDialog,
9172
+ isRefreshing: isRefreshingCompleteEligs
9173
+ }
9174
+ ),
8514
9175
  eligsBindInfo && campaign && /* @__PURE__ */ jsx(
8515
9176
  EligsBindDialog,
8516
9177
  {
@@ -8518,9 +9179,7 @@ function QuestWidgetInner(props) {
8518
9179
  chainTypes: eligsBindInfo.chainTypes,
8519
9180
  snsTypes: eligsBindInfo.snsTypes,
8520
9181
  campaign,
8521
- skippable: eligsBindInfo.skippable,
8522
9182
  onClose: closeEligsBindDialog,
8523
- onSkip: skipEligsBind,
8524
9183
  onAllBind: onAllEligsBind,
8525
9184
  onBindChain: bindChainAndWait,
8526
9185
  onBindSns: bindSnsAndWait
@@ -8562,20 +9221,15 @@ function QuestWidgetInner(props) {
8562
9221
  chainTypes: completeEligsBindInfo.chainTypes,
8563
9222
  snsTypes: completeEligsBindInfo.snsTypes,
8564
9223
  campaign,
8565
- skippable: completeEligsBindInfo.skippable,
8566
9224
  onClose: closeCompleteEligsBindDialog,
8567
- onSkip: () => {
8568
- },
8569
9225
  onAllBind: onAllCompleteEligsBind,
8570
9226
  onBindChain: bindChainAndWait,
8571
9227
  onBindSns: bindSnsAndWait
8572
9228
  }
8573
- )
9229
+ ),
9230
+ nftClaimDialogs
8574
9231
  ] });
8575
9232
  }
8576
9233
  export {
8577
- QuestWidget as Q,
8578
- useQuestUserStatus as a,
8579
- useQuestStatus as b,
8580
- useQuestDetail as u
9234
+ QuestWidget as Q
8581
9235
  };