@taskon/widget-react 0.0.1-beta.1

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 (48) hide show
  1. package/README.md +1065 -0
  2. package/dist/CommunityTaskList.css +4893 -0
  3. package/dist/EligibilityInfo.css +2337 -0
  4. package/dist/LeaderboardWidget.css +815 -0
  5. package/dist/PageBuilder.css +54 -0
  6. package/dist/Quest.css +4214 -0
  7. package/dist/TaskOnProvider.css +163 -0
  8. package/dist/TipPopover.css +210 -0
  9. package/dist/UserCenterWidget.css +297 -0
  10. package/dist/UserCenterWidget2.css +3519 -0
  11. package/dist/WidgetShell.css +182 -0
  12. package/dist/chunks/CommunityTaskList-DoPGZsw1.js +6813 -0
  13. package/dist/chunks/EligibilityInfo-C7GZ2G5u.js +22228 -0
  14. package/dist/chunks/LeaderboardWidget-CmYfDeHV.js +1068 -0
  15. package/dist/chunks/PageBuilder-Tmhf2GTS.js +150 -0
  16. package/dist/chunks/Quest-DKFZ-pPU.js +8839 -0
  17. package/dist/chunks/TaskOnProvider-BD6Vp2x8.js +1435 -0
  18. package/dist/chunks/ThemeProvider-wnSXrNQb.js +1118 -0
  19. package/dist/chunks/TipPopover-BrW8jo71.js +2926 -0
  20. package/dist/chunks/UserCenterWidget-BE329iS7.js +3546 -0
  21. package/dist/chunks/UserCenterWidget-BVw_IEEd.js +3989 -0
  22. package/dist/chunks/WidgetShell-D_5OjvNZ.js +1517 -0
  23. package/dist/chunks/common-ja-DWhTaFHb.js +23 -0
  24. package/dist/chunks/common-ko-80ezXsMG.js +23 -0
  25. package/dist/chunks/dynamic-import-helper-DxEFwm31.js +537 -0
  26. package/dist/chunks/index-CwMvO_wZ.js +777 -0
  27. package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +119 -0
  28. package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +119 -0
  29. package/dist/chunks/useToast-B-wyO5zL.js +93 -0
  30. package/dist/chunks/useWidgetLocale-JDelxtt8.js +74 -0
  31. package/dist/chunks/usercenter-ja-uu-XfVF9.js +332 -0
  32. package/dist/chunks/usercenter-ko-DYgUOVzd.js +332 -0
  33. package/dist/community-task.d.ts +451 -0
  34. package/dist/community-task.js +9 -0
  35. package/dist/core.d.ts +803 -0
  36. package/dist/core.js +22 -0
  37. package/dist/dynamic-import-helper.css +389 -0
  38. package/dist/index.d.ts +1660 -0
  39. package/dist/index.js +41 -0
  40. package/dist/leaderboard.d.ts +547 -0
  41. package/dist/leaderboard.js +18 -0
  42. package/dist/page-builder.d.ts +20 -0
  43. package/dist/page-builder.js +4 -0
  44. package/dist/quest.d.ts +400 -0
  45. package/dist/quest.js +8 -0
  46. package/dist/user-center.d.ts +1780 -0
  47. package/dist/user-center.js +713 -0
  48. package/package.json +105 -0
@@ -0,0 +1,1068 @@
1
+ import { B as Button, T as Table, P as Pagination, _ as __variableDynamicImportRuntimeHelper, u as usePagination } from "./dynamic-import-helper-DxEFwm31.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback, useEffect, useMemo } from "react";
4
+ import { createLeaderboardApi, LeaderboardContentType, formatRankRange, RewardsDistributeType, formatRewardText, calculatePrizePool, RewardType, LeaderboardTableColumn, isAllTimeResponse, isCampaignResponse } from "@taskon/core";
5
+ import { b as useTaskOnContext } from "./ThemeProvider-wnSXrNQb.js";
6
+ import { D as Dialog, u as useResolvedWidgetConfig, W as WidgetShell } from "./WidgetShell-D_5OjvNZ.js";
7
+ import { u as useWidgetLocale } from "./useWidgetLocale-JDelxtt8.js";
8
+ import '../LeaderboardWidget.css';function useLeaderboard(options) {
9
+ const { client } = useTaskOnContext();
10
+ const [data, setData] = useState(null);
11
+ const [loading2, setLoading] = useState(false);
12
+ const [error2, setError] = useState(null);
13
+ const { tabConfig, page: page2, pageSize } = options;
14
+ const fetchData = useCallback(async () => {
15
+ if (!client) return;
16
+ setLoading(true);
17
+ setError(null);
18
+ try {
19
+ const api = createLeaderboardApi(client);
20
+ const pageParams = { page_no: page2, size: pageSize };
21
+ let result;
22
+ if (tabConfig.type === LeaderboardContentType.AllTime) {
23
+ result = await api.getAllTimeLeaderboard({
24
+ page: pageParams,
25
+ points_id: tabConfig.relatedId
26
+ });
27
+ } else {
28
+ const isIncentive = tabConfig.type === LeaderboardContentType.LeaderboardSprint;
29
+ result = await api.getCampaignLeaderboard({
30
+ campaign_id: tabConfig.relatedId,
31
+ page: pageParams,
32
+ incentive_campaign: isIncentive
33
+ });
34
+ }
35
+ setData(result);
36
+ } catch (err) {
37
+ setError(err instanceof Error ? err : new Error("Unknown error"));
38
+ } finally {
39
+ setLoading(false);
40
+ }
41
+ }, [client, tabConfig, page2, pageSize]);
42
+ useEffect(() => {
43
+ fetchData();
44
+ }, [fetchData]);
45
+ const { total, totalPages } = useMemo(() => {
46
+ if (!data) return { total: 0, totalPages: 0 };
47
+ const totalCount = data.total;
48
+ return {
49
+ total: totalCount,
50
+ totalPages: Math.ceil(totalCount / pageSize)
51
+ };
52
+ }, [data, pageSize]);
53
+ return {
54
+ data,
55
+ loading: loading2,
56
+ error: error2,
57
+ total,
58
+ totalPages,
59
+ refresh: fetchData
60
+ };
61
+ }
62
+ function useCampaignReward(campaignId) {
63
+ const { client } = useTaskOnContext();
64
+ const [campaignInfo, setCampaignInfo] = useState(null);
65
+ const [loading2, setLoading] = useState(false);
66
+ const [error2, setError] = useState(null);
67
+ const fetchCampaignInfo = async () => {
68
+ if (!campaignId || !client) return;
69
+ setLoading(true);
70
+ setError(null);
71
+ try {
72
+ const api = createLeaderboardApi(client);
73
+ const info = await api.getCampaignInfo(campaignId);
74
+ setCampaignInfo(info);
75
+ } catch (err) {
76
+ setError(err instanceof Error ? err : new Error("Unknown error"));
77
+ } finally {
78
+ setLoading(false);
79
+ }
80
+ };
81
+ useEffect(() => {
82
+ fetchCampaignInfo();
83
+ }, [campaignId, client]);
84
+ const rewardSummary = useMemo(() => {
85
+ if (!campaignInfo) return null;
86
+ let totalWinners2 = 0;
87
+ const tiers = [];
88
+ campaignInfo.winner_rewards.forEach((wr) => {
89
+ wr.winner_layer_rewards.forEach((wlr, index) => {
90
+ var _a;
91
+ totalWinners2 += wlr.max_winners;
92
+ const { text: rankRangeText, from: rankFrom, to: rankTo } = formatRankRange(wlr, index);
93
+ const distributeType = ((_a = wlr.rewards[0]) == null ? void 0 : _a.reward_distribute_type) || RewardsDistributeType.Equally;
94
+ const simpleReward = campaignInfo.winner_rewards_simple[index];
95
+ tiers.push({
96
+ tierNo: index + 1,
97
+ rankRangeText,
98
+ rankFrom,
99
+ rankTo,
100
+ winnerCount: wlr.max_winners,
101
+ rewardText: formatRewardText(simpleReward, distributeType),
102
+ rewardAmount: (simpleReward == null ? void 0 : simpleReward.reward_amount) || "",
103
+ rewardSymbol: (simpleReward == null ? void 0 : simpleReward.reward_symbol) || "",
104
+ rewardIcon: (simpleReward == null ? void 0 : simpleReward.reward_icon) || "",
105
+ chainLabel: (simpleReward == null ? void 0 : simpleReward.chain_label) || "",
106
+ distributeType
107
+ });
108
+ });
109
+ });
110
+ const prizePool2 = calculatePrizePool(campaignInfo.winner_rewards_simple);
111
+ return {
112
+ prizePool: prizePool2,
113
+ totalWinners: totalWinners2,
114
+ tiers,
115
+ startTime: campaignInfo.start_time,
116
+ endTime: campaignInfo.end_time,
117
+ pointsName: "",
118
+ // TODO: 根据 incentive_rank_by_points_id 获取积分名称
119
+ isEnded: campaignInfo.is_end
120
+ };
121
+ }, [campaignInfo]);
122
+ return {
123
+ campaignInfo,
124
+ rewardSummary,
125
+ loading: loading2,
126
+ error: error2,
127
+ refresh: fetchCampaignInfo
128
+ };
129
+ }
130
+ function HexagonBadge({
131
+ rank,
132
+ colorClass
133
+ }) {
134
+ return /* @__PURE__ */ jsxs("div", { className: `taskon-leaderboard-rank taskon-leaderboard-rank--badge taskon-leaderboard-rank--${colorClass}`, children: [
135
+ /* @__PURE__ */ jsx(
136
+ "svg",
137
+ {
138
+ width: "27",
139
+ height: "27",
140
+ viewBox: "0 0 27 27",
141
+ fill: "none",
142
+ xmlns: "http://www.w3.org/2000/svg",
143
+ className: "taskon-leaderboard-rank__hexagon",
144
+ children: /* @__PURE__ */ jsx(
145
+ "path",
146
+ {
147
+ d: "M13.5 1L25 7.5V19.5L13.5 26L2 19.5V7.5L13.5 1Z",
148
+ className: "taskon-leaderboard-rank__hexagon-path"
149
+ }
150
+ )
151
+ }
152
+ ),
153
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-rank__number-overlay", children: rank })
154
+ ] });
155
+ }
156
+ function RankBadge({ rank, isAllTime = false, className = "" }) {
157
+ if (rank < 0) {
158
+ return /* @__PURE__ */ jsx("span", { className: `taskon-leaderboard-rank taskon-leaderboard-rank--na ${className}`, children: "N/A" });
159
+ }
160
+ if (rank === 0) {
161
+ return /* @__PURE__ */ jsx("span", { className: `taskon-leaderboard-rank taskon-leaderboard-rank--unranked ${className}`, children: "--" });
162
+ }
163
+ if (rank === 1) {
164
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(HexagonBadge, { rank: 1, colorClass: "gold" }) });
165
+ }
166
+ if (rank === 2) {
167
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(HexagonBadge, { rank: 2, colorClass: "silver" }) });
168
+ }
169
+ if (rank === 3) {
170
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(HexagonBadge, { rank: 3, colorClass: "bronze" }) });
171
+ }
172
+ return /* @__PURE__ */ jsx("span", { className: `taskon-leaderboard-rank taskon-leaderboard-rank--number ${className}`, children: rank });
173
+ }
174
+ function UserCell({
175
+ userId,
176
+ userName,
177
+ avatar,
178
+ isCurrentUser = false,
179
+ youLabel = "YOU",
180
+ onUserClick,
181
+ className = ""
182
+ }) {
183
+ const handleClick = () => {
184
+ if (onUserClick) {
185
+ onUserClick(userId, userName);
186
+ }
187
+ };
188
+ const isClickable = !!onUserClick && !isCurrentUser;
189
+ if (isCurrentUser) {
190
+ return /* @__PURE__ */ jsx("div", { className: `taskon-leaderboard-user taskon-leaderboard-user--current ${className}`, children: /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-user__you-badge", children: youLabel }) });
191
+ }
192
+ return /* @__PURE__ */ jsx(
193
+ "div",
194
+ {
195
+ className: `taskon-leaderboard-user ${isClickable ? "taskon-leaderboard-user--clickable" : ""} ${className}`,
196
+ onClick: isClickable ? handleClick : void 0,
197
+ role: isClickable ? "button" : void 0,
198
+ tabIndex: isClickable ? 0 : void 0,
199
+ onKeyDown: isClickable ? (e) => {
200
+ if (e.key === "Enter" || e.key === " ") {
201
+ handleClick();
202
+ }
203
+ } : void 0,
204
+ children: /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-user__name", children: userName })
205
+ }
206
+ );
207
+ }
208
+ function getRewardTypeLabel(rewardType, rewardPointsName, messages) {
209
+ if (!rewardType) return null;
210
+ if (rewardType === RewardType.BMintedNft || rewardType === RewardType.Cap || rewardType === RewardType.Nft) {
211
+ return "NFT:";
212
+ }
213
+ if (rewardType === RewardType.DiscordRole) {
214
+ return "Discord Role:";
215
+ }
216
+ if (rewardType === RewardType.Exp) {
217
+ return "EXP:";
218
+ }
219
+ if (rewardType === RewardType.GTCPoints || rewardType === RewardType.Points) {
220
+ return `${rewardPointsName || messages.columnPoints}:`;
221
+ }
222
+ if (rewardType === RewardType.Token) {
223
+ return "Token:";
224
+ }
225
+ if (rewardType === RewardType.Whitelist) {
226
+ return null;
227
+ }
228
+ return null;
229
+ }
230
+ function getRewardValueLabel(rewardType, rewardAmount, rewardSymbol, chainLabel, isUsdtEqual, messages) {
231
+ if (!rewardType) {
232
+ return {
233
+ value: rewardAmount ? `${rewardAmount} ${rewardSymbol || ""}` : messages.noData,
234
+ showChain: !!chainLabel
235
+ };
236
+ }
237
+ if (rewardType === RewardType.Nft || rewardType === RewardType.BMintedNft || rewardType === RewardType.DiscordRole || rewardType === RewardType.Exp) {
238
+ return { value: rewardSymbol || "", showChain: false };
239
+ }
240
+ if (rewardType === RewardType.Cap) {
241
+ return { value: "CAP", showChain: false };
242
+ }
243
+ if (rewardType === RewardType.GTCPoints || rewardType === RewardType.Points) {
244
+ return { value: rewardAmount || "", showChain: false };
245
+ }
246
+ if (rewardType === RewardType.Token) {
247
+ if (isUsdtEqual) {
248
+ return { value: `${rewardAmount} USD in ${rewardSymbol}`, showChain: false };
249
+ }
250
+ return { value: `${rewardAmount} ${rewardSymbol}`, showChain: !!chainLabel };
251
+ }
252
+ if (rewardType === RewardType.Whitelist) {
253
+ return { value: messages.whitelist || "Whitelist", showChain: false };
254
+ }
255
+ return {
256
+ value: rewardAmount ? `${rewardAmount} ${rewardSymbol || ""}` : messages.noData,
257
+ showChain: !!chainLabel
258
+ };
259
+ }
260
+ function RewardCell({
261
+ rewardAmount,
262
+ rewardSymbol,
263
+ chainLabel,
264
+ rewardType,
265
+ rewardPointsName,
266
+ isUsdtEqual,
267
+ messages,
268
+ isPotential = false,
269
+ className = ""
270
+ }) {
271
+ if (!rewardAmount && !rewardType) {
272
+ return /* @__PURE__ */ jsx("span", { className, children: messages.noData });
273
+ }
274
+ const typeLabel = getRewardTypeLabel(rewardType, rewardPointsName, messages);
275
+ const { value, showChain } = getRewardValueLabel(
276
+ rewardType,
277
+ rewardAmount,
278
+ rewardSymbol,
279
+ chainLabel,
280
+ isUsdtEqual,
281
+ messages
282
+ );
283
+ const potentialClass = isPotential ? "taskon-leaderboard-table__reward--potential" : "";
284
+ return /* @__PURE__ */ jsxs("span", { className: `taskon-leaderboard-table__reward ${potentialClass} ${className}`, children: [
285
+ typeLabel && /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-table__reward-type", children: typeLabel }),
286
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-table__reward-value", children: value }),
287
+ showChain && chainLabel && /* @__PURE__ */ jsxs("span", { className: "taskon-leaderboard-table__reward-chain", children: [
288
+ "(",
289
+ chainLabel,
290
+ ")"
291
+ ] })
292
+ ] });
293
+ }
294
+ function LeaderboardTabs({
295
+ tabs,
296
+ activeTabId,
297
+ onTabChange,
298
+ className = ""
299
+ }) {
300
+ if (tabs.length <= 1) {
301
+ return null;
302
+ }
303
+ return /* @__PURE__ */ jsx("div", { className: `taskon-leaderboard-tabs ${className}`, role: "tablist", children: tabs.map((tab) => {
304
+ const isActive = tab.id === activeTabId;
305
+ return /* @__PURE__ */ jsx(
306
+ "button",
307
+ {
308
+ role: "tab",
309
+ "aria-selected": isActive,
310
+ "aria-controls": `leaderboard-panel-${tab.id}`,
311
+ className: `taskon-leaderboard-tabs__tab ${isActive ? "taskon-leaderboard-tabs__tab--active" : ""}`,
312
+ onClick: () => onTabChange(tab.id),
313
+ children: tab.title
314
+ },
315
+ tab.id
316
+ );
317
+ }) });
318
+ }
319
+ function formatTimeRange(startTime, endTime) {
320
+ if (!startTime || !endTime) return "";
321
+ const start = new Date(startTime);
322
+ const end = new Date(endTime);
323
+ const offset = -start.getTimezoneOffset();
324
+ const offsetHours = Math.floor(Math.abs(offset) / 60);
325
+ const offsetSign = offset >= 0 ? "+" : "-";
326
+ const timezone = `UTC${offsetSign}${offsetHours}`;
327
+ const startYear = start.getFullYear();
328
+ const startMonth = String(start.getMonth() + 1).padStart(2, "0");
329
+ const startDay = String(start.getDate()).padStart(2, "0");
330
+ const startHours = String(start.getHours()).padStart(2, "0");
331
+ const startMinutes = String(start.getMinutes()).padStart(2, "0");
332
+ const endYear = end.getFullYear();
333
+ const endMonth = String(end.getMonth() + 1).padStart(2, "0");
334
+ const endDay = String(end.getDate()).padStart(2, "0");
335
+ const endHours = String(end.getHours()).padStart(2, "0");
336
+ const endMinutes = String(end.getMinutes()).padStart(2, "0");
337
+ return `(${timezone}) ${startYear}-${startMonth}-${startDay} ${startHours}:${startMinutes} ~ ${endYear}-${endMonth}-${endDay} ${endHours}:${endMinutes}`;
338
+ }
339
+ function getEventStatus(startTime, endTime, messages) {
340
+ if (!startTime || !endTime) return null;
341
+ const now = Date.now();
342
+ if (now < startTime) {
343
+ return { label: messages.statusUpcoming, status: "upcoming" };
344
+ }
345
+ if (now > endTime) {
346
+ return { label: messages.statusEnded, status: "ended" };
347
+ }
348
+ return { label: messages.statusOngoing, status: "ongoing" };
349
+ }
350
+ function LeaderboardHeader({
351
+ tabConfig,
352
+ showTitle,
353
+ rewardSummary,
354
+ participantsCount,
355
+ messages,
356
+ onOpenRewardRules,
357
+ className = ""
358
+ }) {
359
+ const isSprint = tabConfig.type === LeaderboardContentType.LeaderboardSprint;
360
+ const eventStatus = getEventStatus(tabConfig.startTime, tabConfig.endTime, messages);
361
+ const hasTimeRange = tabConfig.startTime && tabConfig.endTime;
362
+ const hasParticipants = typeof participantsCount === "number";
363
+ const hasContent = eventStatus || hasTimeRange || hasParticipants;
364
+ if (!hasContent && !showTitle && !isSprint) {
365
+ return null;
366
+ }
367
+ return /* @__PURE__ */ jsxs("div", { className: `taskon-leaderboard-header ${className}`, children: [
368
+ (eventStatus || hasTimeRange || hasParticipants) && /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-header__info", children: [
369
+ eventStatus && /* @__PURE__ */ jsx(
370
+ "span",
371
+ {
372
+ className: `taskon-leaderboard-header__status taskon-leaderboard-header__status--${eventStatus.status}`,
373
+ children: eventStatus.label
374
+ }
375
+ ),
376
+ hasTimeRange && /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__time", children: formatTimeRange(tabConfig.startTime, tabConfig.endTime) }),
377
+ hasParticipants && (eventStatus || hasTimeRange) && /* @__PURE__ */ jsx("div", { className: "taskon-leaderboard-header__separator" }),
378
+ hasParticipants && /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-header__participants", children: [
379
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__participants-label", children: messages.participants || "Participants" }),
380
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__participants-value", children: participantsCount.toLocaleString() })
381
+ ] })
382
+ ] }),
383
+ isSprint && rewardSummary && /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-header__reward-info", children: [
384
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-header__reward-item", children: [
385
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__reward-label", children: messages.prizePool }),
386
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__reward-value", children: rewardSummary.prizePool || "-" })
387
+ ] }),
388
+ /* @__PURE__ */ jsx("div", { className: "taskon-leaderboard-header__reward-separator" }),
389
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-header__reward-item", children: [
390
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__reward-label", children: messages.totalWinners }),
391
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-header__reward-value", children: rewardSummary.totalWinners })
392
+ ] }),
393
+ onOpenRewardRules && /* @__PURE__ */ jsx(
394
+ Button,
395
+ {
396
+ variant: "ghost",
397
+ size: "small",
398
+ onClick: onOpenRewardRules,
399
+ className: "taskon-leaderboard-header__reward-rules-btn",
400
+ children: messages.rewardRules
401
+ }
402
+ )
403
+ ] })
404
+ ] });
405
+ }
406
+ function getColumnTitle(column, messages, pointsName) {
407
+ switch (column) {
408
+ case LeaderboardTableColumn.Rank:
409
+ return messages.columnRank;
410
+ case LeaderboardTableColumn.User:
411
+ return messages.columnUser;
412
+ case LeaderboardTableColumn.Tasks:
413
+ return messages.columnTasks;
414
+ case LeaderboardTableColumn.InvitedUsers:
415
+ return messages.columnInvitedUsers;
416
+ case LeaderboardTableColumn.CurrentTier:
417
+ return messages.columnCurrentTier;
418
+ case LeaderboardTableColumn.Points:
419
+ return pointsName || messages.columnPoints;
420
+ case LeaderboardTableColumn.Rewards:
421
+ return messages.columnRewards;
422
+ default:
423
+ return "";
424
+ }
425
+ }
426
+ function getRewardForRank(rank, rewardTiers) {
427
+ if (!rewardTiers || rank <= 0) return void 0;
428
+ return rewardTiers.find((tier) => {
429
+ return rank >= tier.rankFrom && rank <= tier.rankTo;
430
+ });
431
+ }
432
+ function convertAllTimeData(data) {
433
+ return data.map((item) => ({
434
+ id: item.user_id,
435
+ rank: item.rank,
436
+ displayRank: item.rank,
437
+ userId: item.user_id,
438
+ userName: item.user,
439
+ avatar: item.avatar,
440
+ tasks: item.task,
441
+ invitedUsers: item.invited_users,
442
+ points: item.point.amount,
443
+ isAllTime: true
444
+ }));
445
+ }
446
+ function convertCampaignData(data) {
447
+ return data.map((item) => {
448
+ var _a;
449
+ return {
450
+ id: item.user_info.user_id,
451
+ rank: item.rank,
452
+ displayRank: item.rank >= 0 ? item.rank + 1 : item.rank,
453
+ // Campaign 的 rank 从 0 开始
454
+ userId: item.user_info.user_id,
455
+ userName: item.user_info.user_name,
456
+ avatar: item.user_info.user_avatar,
457
+ tasks: item.task_count,
458
+ currentTier: item.winner_layer !== void 0 && item.winner_layer >= 0 ? item.winner_layer + 1 : void 0,
459
+ points: item.point.amount,
460
+ rewardAmount: item.reward_amount,
461
+ rewardSymbol: item.reward_symbol,
462
+ chainLabel: item.chain_label,
463
+ rewardType: item.reward_type,
464
+ rewardPointsName: (_a = item.point) == null ? void 0 : _a.points_name,
465
+ isUsdtEqual: item.is_usdt_equal,
466
+ isAllTime: false
467
+ };
468
+ });
469
+ }
470
+ function LeaderboardTable({
471
+ tabConfig,
472
+ allTimeData,
473
+ campaignData,
474
+ currentUserId,
475
+ messages,
476
+ onUserClick,
477
+ rewardTiers,
478
+ loading: loading2 = false,
479
+ className = ""
480
+ }) {
481
+ const isAllTime = tabConfig.type === LeaderboardContentType.AllTime;
482
+ const tableData = useMemo(() => {
483
+ if (isAllTime && allTimeData) {
484
+ return convertAllTimeData(allTimeData);
485
+ }
486
+ if (!isAllTime && campaignData) {
487
+ return convertCampaignData(campaignData);
488
+ }
489
+ return [];
490
+ }, [isAllTime, allTimeData, campaignData]);
491
+ const columns = useMemo(() => {
492
+ return tabConfig.columns.map((column) => {
493
+ const baseColumn = {
494
+ key: column,
495
+ title: getColumnTitle(column, messages, tabConfig.pointsName)
496
+ };
497
+ switch (column) {
498
+ case LeaderboardTableColumn.Rank:
499
+ return {
500
+ ...baseColumn,
501
+ width: 120,
502
+ render: (_, row) => /* @__PURE__ */ jsx(RankBadge, { rank: row.displayRank, isAllTime: row.isAllTime })
503
+ };
504
+ case LeaderboardTableColumn.User:
505
+ return {
506
+ ...baseColumn,
507
+ minWidth: 164,
508
+ render: (_, row) => /* @__PURE__ */ jsx(
509
+ UserCell,
510
+ {
511
+ userId: row.userId,
512
+ userName: row.userName,
513
+ avatar: row.avatar,
514
+ isCurrentUser: currentUserId === row.userId,
515
+ youLabel: messages.you,
516
+ onUserClick
517
+ }
518
+ )
519
+ };
520
+ case LeaderboardTableColumn.Tasks:
521
+ return {
522
+ ...baseColumn,
523
+ width: 142,
524
+ render: (_, row) => row.tasks ?? messages.noData
525
+ };
526
+ case LeaderboardTableColumn.InvitedUsers:
527
+ return {
528
+ ...baseColumn,
529
+ width: 142,
530
+ render: (_, row) => row.invitedUsers ?? messages.noData
531
+ };
532
+ case LeaderboardTableColumn.CurrentTier:
533
+ return {
534
+ ...baseColumn,
535
+ width: 142,
536
+ render: (_, row) => row.currentTier ?? messages.noData
537
+ };
538
+ case LeaderboardTableColumn.Points:
539
+ return {
540
+ ...baseColumn,
541
+ width: 142,
542
+ render: (_, row) => row.points && row.points > 0 ? row.points.toLocaleString() : messages.noData
543
+ };
544
+ case LeaderboardTableColumn.Rewards:
545
+ return {
546
+ ...baseColumn,
547
+ width: 103,
548
+ align: "right",
549
+ render: (_, row) => {
550
+ if (row.rewardAmount || row.rewardType) {
551
+ return /* @__PURE__ */ jsx(
552
+ RewardCell,
553
+ {
554
+ rewardAmount: row.rewardAmount,
555
+ rewardSymbol: row.rewardSymbol,
556
+ chainLabel: row.chainLabel,
557
+ rewardType: row.rewardType,
558
+ rewardPointsName: row.rewardPointsName,
559
+ isUsdtEqual: row.isUsdtEqual,
560
+ messages
561
+ }
562
+ );
563
+ }
564
+ const reward = getRewardForRank(row.displayRank, rewardTiers);
565
+ if (reward) {
566
+ return /* @__PURE__ */ jsx(
567
+ RewardCell,
568
+ {
569
+ rewardAmount: reward.rewardAmount,
570
+ rewardSymbol: reward.rewardSymbol,
571
+ chainLabel: reward.chainLabel,
572
+ messages,
573
+ isPotential: true
574
+ }
575
+ );
576
+ }
577
+ return messages.noData;
578
+ }
579
+ };
580
+ default:
581
+ return {
582
+ ...baseColumn,
583
+ render: () => messages.noData
584
+ };
585
+ }
586
+ });
587
+ }, [tabConfig.columns, tabConfig.pointsName, messages, currentUserId, onUserClick, rewardTiers]);
588
+ const rowConfig = useMemo(
589
+ () => ({
590
+ getRowKey: (row) => row.id,
591
+ isHighlighted: (row) => currentUserId === row.userId
592
+ }),
593
+ [currentUserId]
594
+ );
595
+ const emptyConfig = useMemo(
596
+ () => ({
597
+ title: messages.emptyTitle,
598
+ description: messages.emptyDesc
599
+ }),
600
+ [messages.emptyTitle, messages.emptyDesc]
601
+ );
602
+ return /* @__PURE__ */ jsx(
603
+ Table,
604
+ {
605
+ columns,
606
+ data: tableData,
607
+ rowConfig,
608
+ loading: loading2,
609
+ loadingText: messages.loading,
610
+ empty: emptyConfig,
611
+ striped: true,
612
+ className
613
+ }
614
+ );
615
+ }
616
+ function LeaderboardPagination({
617
+ page: page2,
618
+ totalPages,
619
+ total,
620
+ hasPrevious,
621
+ hasNext,
622
+ onPrevious,
623
+ onNext,
624
+ messages,
625
+ className = ""
626
+ }) {
627
+ if (totalPages <= 1 || total === 0) {
628
+ return null;
629
+ }
630
+ return /* @__PURE__ */ jsx(
631
+ Pagination,
632
+ {
633
+ page: page2,
634
+ totalPages,
635
+ hasPrevious,
636
+ hasNext,
637
+ onPrevious,
638
+ onNext,
639
+ className: `taskon-leaderboard-pagination ${className}`,
640
+ showArrows: true,
641
+ showButtonText: false
642
+ }
643
+ );
644
+ }
645
+ function formatDate(timestamp) {
646
+ if (!timestamp) return "";
647
+ const date = new Date(timestamp);
648
+ return date.toLocaleDateString("en-US", {
649
+ year: "numeric",
650
+ month: "short",
651
+ day: "numeric",
652
+ hour: "2-digit",
653
+ minute: "2-digit"
654
+ });
655
+ }
656
+ function getDistributeText(distributeType, messages) {
657
+ switch (distributeType) {
658
+ case RewardsDistributeType.Equally:
659
+ return "Each receives";
660
+ case RewardsDistributeType.Random:
661
+ return "Randomly split";
662
+ default:
663
+ return "";
664
+ }
665
+ }
666
+ function TierRow({
667
+ tier,
668
+ messages
669
+ }) {
670
+ const distributeText = getDistributeText(tier.distributeType);
671
+ return /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__tier", children: [
672
+ /* @__PURE__ */ jsxs("span", { className: "taskon-leaderboard-modal__tier-rank", children: [
673
+ "Top ",
674
+ tier.rankRangeText
675
+ ] }),
676
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__tier-reward", children: [
677
+ distributeText && /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-modal__tier-distribute", children: distributeText }),
678
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__tier-token", children: [
679
+ tier.rewardIcon && /* @__PURE__ */ jsx(
680
+ "img",
681
+ {
682
+ src: tier.rewardIcon,
683
+ alt: tier.rewardSymbol,
684
+ className: "taskon-leaderboard-modal__tier-token-icon"
685
+ }
686
+ ),
687
+ /* @__PURE__ */ jsxs("span", { className: "taskon-leaderboard-modal__tier-amount", children: [
688
+ /* @__PURE__ */ jsxs("span", { className: "taskon-leaderboard-modal__tier-amount-value", children: [
689
+ tier.rewardAmount,
690
+ " "
691
+ ] }),
692
+ /* @__PURE__ */ jsx("span", { className: "taskon-leaderboard-modal__tier-amount-symbol", children: tier.rewardSymbol })
693
+ ] })
694
+ ] })
695
+ ] })
696
+ ] });
697
+ }
698
+ function RewardRulesModal({
699
+ isOpen,
700
+ onClose,
701
+ rewardSummary,
702
+ messages,
703
+ className = ""
704
+ }) {
705
+ if (!rewardSummary) {
706
+ return null;
707
+ }
708
+ const description = messages.rewardRulesDesc.replace(
709
+ "{pointsName}",
710
+ rewardSummary.pointsName || "points"
711
+ );
712
+ return /* @__PURE__ */ jsx(
713
+ Dialog,
714
+ {
715
+ open: isOpen,
716
+ onOpenChange: (open) => {
717
+ if (!open) onClose();
718
+ },
719
+ title: messages.rewardRulesTitle,
720
+ showCloseButton: true,
721
+ className,
722
+ contentClassName: "taskon-leaderboard-modal",
723
+ maxWidth: 480,
724
+ children: /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__content", children: [
725
+ /* @__PURE__ */ jsx("h2", { className: "taskon-leaderboard-modal__title", children: messages.rewardRulesTitle }),
726
+ /* @__PURE__ */ jsx("p", { className: "taskon-leaderboard-modal__desc", children: description }),
727
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__section", children: [
728
+ /* @__PURE__ */ jsx("h3", { className: "taskon-leaderboard-modal__section-title", children: messages.eventPeriod }),
729
+ /* @__PURE__ */ jsxs("p", { className: "taskon-leaderboard-modal__period", children: [
730
+ formatDate(rewardSummary.startTime),
731
+ " -",
732
+ " ",
733
+ formatDate(rewardSummary.endTime)
734
+ ] })
735
+ ] }),
736
+ /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard-modal__section", children: [
737
+ /* @__PURE__ */ jsx("h3", { className: "taskon-leaderboard-modal__section-title", children: messages.rewardDetails }),
738
+ /* @__PURE__ */ jsx("div", { className: "taskon-leaderboard-modal__tiers", children: rewardSummary.tiers.map((tier) => /* @__PURE__ */ jsx(TierRow, { tier, messages }, tier.tierNo)) })
739
+ ] })
740
+ ] })
741
+ }
742
+ );
743
+ }
744
+ function mergeLeaderboardConfig(props, cloud) {
745
+ return {
746
+ config: props.config ?? cloud ?? null
747
+ };
748
+ }
749
+ const tabAllTime = "All Time";
750
+ const tabQuest = "Quest";
751
+ const tabEvent = "Event";
752
+ const tabSprint = "Sprint";
753
+ const columnRank = "Rank";
754
+ const columnPosition = "Position";
755
+ const columnUser = "User";
756
+ const columnTasks = "Tasks";
757
+ const columnInvitedUsers = "Invited Users";
758
+ const columnCurrentTier = "Current Tier";
759
+ const columnPoints = "Points";
760
+ const columnRewards = "Reward";
761
+ const statusOngoing = "Ongoing";
762
+ const statusEnded = "Ended";
763
+ const statusUpcoming = "Upcoming";
764
+ const participants = "Participants";
765
+ const prizePool = "Prize Pool";
766
+ const totalWinners = "Total Winners";
767
+ const rewardRules = "Reward Rules";
768
+ const rewardRulesTitle = "Reward Rules";
769
+ const rewardRulesDesc = "Rewards will be given based on leaderboard rankings, determined by users' {pointsName} earned during the event.";
770
+ const eventPeriod = "Event Period";
771
+ const rewardDetails = "Reward Details";
772
+ const eachReceives = "Each receives {amount}";
773
+ const randomlySplit = "Randomly split {amount}";
774
+ const emptyTitle = "No Rankings Yet";
775
+ const emptyDesc = "Be the first to join and claim the top spot!";
776
+ const page = "Page";
777
+ const of = "of";
778
+ const previous = "Previous";
779
+ const next = "Next";
780
+ const loading = "Loading...";
781
+ const error = "Failed to load leaderboard";
782
+ const retry = "Retry";
783
+ const you = "You";
784
+ const unranked = "Unranked";
785
+ const na = "N/A";
786
+ const noData = "-";
787
+ const whitelist = "Whitelist";
788
+ const enMessages = {
789
+ tabAllTime,
790
+ tabQuest,
791
+ tabEvent,
792
+ tabSprint,
793
+ columnRank,
794
+ columnPosition,
795
+ columnUser,
796
+ columnTasks,
797
+ columnInvitedUsers,
798
+ columnCurrentTier,
799
+ columnPoints,
800
+ columnRewards,
801
+ statusOngoing,
802
+ statusEnded,
803
+ statusUpcoming,
804
+ participants,
805
+ prizePool,
806
+ totalWinners,
807
+ rewardRules,
808
+ rewardRulesTitle,
809
+ rewardRulesDesc,
810
+ eventPeriod,
811
+ rewardDetails,
812
+ eachReceives,
813
+ randomlySplit,
814
+ emptyTitle,
815
+ emptyDesc,
816
+ page,
817
+ of,
818
+ previous,
819
+ next,
820
+ loading,
821
+ error,
822
+ retry,
823
+ you,
824
+ unranked,
825
+ na,
826
+ noData,
827
+ whitelist
828
+ };
829
+ const en = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
830
+ __proto__: null,
831
+ columnCurrentTier,
832
+ columnInvitedUsers,
833
+ columnPoints,
834
+ columnPosition,
835
+ columnRank,
836
+ columnRewards,
837
+ columnTasks,
838
+ columnUser,
839
+ default: enMessages,
840
+ eachReceives,
841
+ emptyDesc,
842
+ emptyTitle,
843
+ error,
844
+ eventPeriod,
845
+ loading,
846
+ na,
847
+ next,
848
+ noData,
849
+ of,
850
+ page,
851
+ participants,
852
+ previous,
853
+ prizePool,
854
+ randomlySplit,
855
+ retry,
856
+ rewardDetails,
857
+ rewardRules,
858
+ rewardRulesDesc,
859
+ rewardRulesTitle,
860
+ statusEnded,
861
+ statusOngoing,
862
+ statusUpcoming,
863
+ tabAllTime,
864
+ tabEvent,
865
+ tabQuest,
866
+ tabSprint,
867
+ totalWinners,
868
+ unranked,
869
+ whitelist,
870
+ you
871
+ }, Symbol.toStringTag, { value: "Module" }));
872
+ function LeaderboardWidget(props) {
873
+ const { widgetId } = props;
874
+ const { functionConfig, cloudTheme, isConfigLoading, configError } = useResolvedWidgetConfig(widgetId);
875
+ const mergedConfig = useMemo(() => {
876
+ return mergeLeaderboardConfig(
877
+ props,
878
+ functionConfig ?? null
879
+ );
880
+ }, [props.config, functionConfig]);
881
+ return /* @__PURE__ */ jsx(
882
+ WidgetShell,
883
+ {
884
+ widgetId,
885
+ isConfigLoading,
886
+ cloudTheme,
887
+ className: "taskon-leaderboard",
888
+ errorMessage: configError ?? (!mergedConfig.config ? "Leaderboard config is required. Please provide config via props or widgetId." : void 0),
889
+ children: /* @__PURE__ */ jsx(
890
+ LeaderboardWidgetInner,
891
+ {
892
+ ...props,
893
+ config: mergedConfig.config
894
+ }
895
+ )
896
+ }
897
+ );
898
+ }
899
+ function LeaderboardWidgetInner({
900
+ config,
901
+ defaultTabId,
902
+ onTabChange,
903
+ onUserClick,
904
+ className = "",
905
+ style
906
+ }) {
907
+ var _a;
908
+ const { userId } = useTaskOnContext();
909
+ const { messages } = useWidgetLocale({
910
+ widgetId: "LeaderboardWidget",
911
+ defaultMessages: enMessages,
912
+ loadMessages: (locale) => __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./locales/en.json": () => Promise.resolve().then(() => en), "./locales/ja.json": () => import("./leaderboardwidget-ja-Bj6gz6y1.js"), "./locales/ko.json": () => import("./leaderboardwidget-ko-f1cLO9ic.js") }), `./locales/${locale}.json`, 3)
913
+ });
914
+ const [activeTabId, setActiveTabId] = useState(
915
+ defaultTabId || ((_a = config.leaderboards[0]) == null ? void 0 : _a.id) || ""
916
+ );
917
+ const [isRewardModalOpen, setIsRewardModalOpen] = useState(false);
918
+ const currentTab = useMemo(() => {
919
+ return config.leaderboards.find((tab) => tab.id === activeTabId);
920
+ }, [config.leaderboards, activeTabId]);
921
+ const {
922
+ page: page2,
923
+ goToPrevious,
924
+ goToNext,
925
+ reset: resetPagination
926
+ } = usePagination({
927
+ total: 0,
928
+ // 初始值,hasPrevious/hasNext 将根据实际 total 重新计算
929
+ pageSize: config.displayOptions.rows
930
+ });
931
+ const {
932
+ data: leaderboardData,
933
+ loading: leaderboardLoading,
934
+ error: leaderboardError,
935
+ total,
936
+ refresh: refreshLeaderboard
937
+ } = useLeaderboard({
938
+ tabConfig: currentTab,
939
+ page: page2,
940
+ pageSize: config.displayOptions.rows
941
+ });
942
+ const actualTotalPages = Math.max(1, Math.ceil(total / config.displayOptions.rows));
943
+ const hasPrevious = page2 > 0;
944
+ const hasNext = page2 < actualTotalPages - 1;
945
+ const isSprint = (currentTab == null ? void 0 : currentTab.type) === LeaderboardContentType.LeaderboardSprint;
946
+ const { rewardSummary, loading: rewardLoading } = useCampaignReward(
947
+ isSprint ? currentTab == null ? void 0 : currentTab.relatedId : void 0
948
+ );
949
+ const handleTabChange = useCallback(
950
+ (tabId) => {
951
+ setActiveTabId(tabId);
952
+ resetPagination();
953
+ onTabChange == null ? void 0 : onTabChange(tabId);
954
+ },
955
+ [onTabChange, resetPagination]
956
+ );
957
+ const handleOpenRewardRules = useCallback(() => {
958
+ setIsRewardModalOpen(true);
959
+ }, []);
960
+ const handleCloseRewardRules = useCallback(() => {
961
+ setIsRewardModalOpen(false);
962
+ }, []);
963
+ const allTimeData = useMemo(() => {
964
+ if (leaderboardData && isAllTimeResponse(leaderboardData)) {
965
+ return leaderboardData.list;
966
+ }
967
+ return void 0;
968
+ }, [leaderboardData]);
969
+ const campaignData = useMemo(() => {
970
+ if (leaderboardData && isCampaignResponse(leaderboardData)) {
971
+ return leaderboardData.data;
972
+ }
973
+ return void 0;
974
+ }, [leaderboardData]);
975
+ const participantsCount = useMemo(() => {
976
+ if (leaderboardData && isCampaignResponse(leaderboardData)) {
977
+ return leaderboardData.total_user;
978
+ }
979
+ return void 0;
980
+ }, [leaderboardData]);
981
+ if (leaderboardError) {
982
+ return /* @__PURE__ */ jsx("div", { className: `taskon-leaderboard taskon-leaderboard--error ${className}`, style, children: /* @__PURE__ */ jsxs("div", { className: "taskon-leaderboard__error", children: [
983
+ /* @__PURE__ */ jsx("p", { className: "taskon-leaderboard__error-text", children: messages.error }),
984
+ /* @__PURE__ */ jsx(
985
+ Button,
986
+ {
987
+ variant: "primary",
988
+ size: "medium",
989
+ onClick: refreshLeaderboard,
990
+ className: "taskon-leaderboard__retry-btn",
991
+ children: messages.retry
992
+ }
993
+ )
994
+ ] }) });
995
+ }
996
+ if (!currentTab) {
997
+ return null;
998
+ }
999
+ return /* @__PURE__ */ jsxs("div", { className: `taskon-leaderboard ${className}`, style, children: [
1000
+ /* @__PURE__ */ jsx(
1001
+ LeaderboardTabs,
1002
+ {
1003
+ tabs: config.leaderboards,
1004
+ activeTabId,
1005
+ onTabChange: handleTabChange
1006
+ }
1007
+ ),
1008
+ /* @__PURE__ */ jsx(
1009
+ LeaderboardHeader,
1010
+ {
1011
+ tabConfig: currentTab,
1012
+ showTitle: config.displayOptions.showTitle,
1013
+ rewardSummary,
1014
+ participantsCount,
1015
+ messages,
1016
+ onOpenRewardRules: isSprint ? handleOpenRewardRules : void 0
1017
+ }
1018
+ ),
1019
+ /* @__PURE__ */ jsx(
1020
+ LeaderboardTable,
1021
+ {
1022
+ tabConfig: currentTab,
1023
+ allTimeData,
1024
+ campaignData,
1025
+ currentUserId: userId,
1026
+ messages,
1027
+ onUserClick,
1028
+ rewardTiers: rewardSummary == null ? void 0 : rewardSummary.tiers,
1029
+ loading: leaderboardLoading || rewardLoading,
1030
+ className: "taskon-leaderboard-table"
1031
+ }
1032
+ ),
1033
+ /* @__PURE__ */ jsx(
1034
+ LeaderboardPagination,
1035
+ {
1036
+ page: page2,
1037
+ totalPages: actualTotalPages,
1038
+ total,
1039
+ hasPrevious,
1040
+ hasNext,
1041
+ onPrevious: goToPrevious,
1042
+ onNext: goToNext,
1043
+ messages
1044
+ }
1045
+ ),
1046
+ isSprint && /* @__PURE__ */ jsx(
1047
+ RewardRulesModal,
1048
+ {
1049
+ isOpen: isRewardModalOpen,
1050
+ onClose: handleCloseRewardRules,
1051
+ rewardSummary,
1052
+ messages
1053
+ }
1054
+ )
1055
+ ] });
1056
+ }
1057
+ export {
1058
+ LeaderboardWidget as L,
1059
+ RankBadge as R,
1060
+ UserCell as U,
1061
+ useCampaignReward as a,
1062
+ LeaderboardTabs as b,
1063
+ LeaderboardHeader as c,
1064
+ LeaderboardTable as d,
1065
+ LeaderboardPagination as e,
1066
+ RewardRulesModal as f,
1067
+ useLeaderboard as u
1068
+ };