@quantabit/referral-sdk 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +22 -0
- package/dist/index.cjs +815 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +789 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/styles.css.map +1 -0
- package/package.json +70 -0
- package/types/index.d.ts +10 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var sdkConfig = require('@quantabit/sdk-config');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Referral SDK - API 客户端
|
|
8
|
+
* 邀请推荐系统后端接口封装
|
|
9
|
+
*
|
|
10
|
+
* 使用 BaseApiClient 基类简化代码
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 邀请推荐 API 客户端
|
|
16
|
+
*/
|
|
17
|
+
class ReferralApiClient extends sdkConfig.BaseApiClient {
|
|
18
|
+
constructor(config = {}) {
|
|
19
|
+
super('/referral', config);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ============ 邀请码 ============
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 获取我的邀请码
|
|
26
|
+
*/
|
|
27
|
+
async getMyReferralCode() {
|
|
28
|
+
return this.get('/my/code');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 生成新邀请码
|
|
33
|
+
* @param {Object} options - 生成选项
|
|
34
|
+
*/
|
|
35
|
+
async generateCode(options = {}) {
|
|
36
|
+
return this.post('/code/generate', options);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 获取邀请链接
|
|
41
|
+
* @param {string} channel - 渠道
|
|
42
|
+
*/
|
|
43
|
+
async getInviteLink(channel = 'default') {
|
|
44
|
+
return this.get('/my/link', {
|
|
45
|
+
channel
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 生成带参数的邀请链接
|
|
51
|
+
* @param {Object} params - 链接参数
|
|
52
|
+
*/
|
|
53
|
+
async generateInviteLink(params = {}) {
|
|
54
|
+
return this.post('/link/generate', params);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============ 邀请绑定 ============
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 绑定邀请关系
|
|
61
|
+
* @param {string} referralCode - 邀请码
|
|
62
|
+
*/
|
|
63
|
+
async bindReferral(referralCode) {
|
|
64
|
+
return this.post('/bind', {
|
|
65
|
+
code: referralCode
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 验证邀请码
|
|
71
|
+
* @param {string} code - 邀请码
|
|
72
|
+
*/
|
|
73
|
+
async validateCode(code) {
|
|
74
|
+
return this.get('/validate', {
|
|
75
|
+
code
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 获取我的邀请人信息
|
|
81
|
+
*/
|
|
82
|
+
async getMyInviter() {
|
|
83
|
+
return this.get('/my/inviter');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ============ 邀请记录 ============
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 获取我的邀请列表
|
|
90
|
+
* @param {Object} params - 查询参数
|
|
91
|
+
*/
|
|
92
|
+
async getMyInvites(params = {}) {
|
|
93
|
+
return this.get('/my/invites', params);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 获取邀请统计
|
|
98
|
+
*/
|
|
99
|
+
async getInviteStats() {
|
|
100
|
+
return this.get('/my/stats');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 获取邀请排行榜
|
|
105
|
+
* @param {Object} params - 查询参数
|
|
106
|
+
*/
|
|
107
|
+
async getLeaderboard(params = {}) {
|
|
108
|
+
return this.get('/leaderboard', params);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 获取我的排名
|
|
113
|
+
*/
|
|
114
|
+
async getMyRank() {
|
|
115
|
+
return this.get('/my/rank');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ============ 邀请奖励 ============
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 获取邀请奖励规则
|
|
122
|
+
*/
|
|
123
|
+
async getRewardRules() {
|
|
124
|
+
return this.get('/rewards/rules');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 获取我的邀请奖励
|
|
129
|
+
* @param {Object} params - 查询参数
|
|
130
|
+
*/
|
|
131
|
+
async getMyRewards(params = {}) {
|
|
132
|
+
return this.get('/my/rewards', params);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 获取待领取奖励
|
|
137
|
+
*/
|
|
138
|
+
async getPendingRewards() {
|
|
139
|
+
return this.get('/my/rewards/pending');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 领取奖励
|
|
144
|
+
* @param {string} rewardId - 奖励 ID
|
|
145
|
+
*/
|
|
146
|
+
async claimReward(rewardId) {
|
|
147
|
+
return this.post(`/rewards/${rewardId}/claim`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 一键领取所有奖励
|
|
152
|
+
*/
|
|
153
|
+
async claimAllRewards() {
|
|
154
|
+
return this.post('/rewards/claim-all');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ============ 邀请活动 ============
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 获取进行中的邀请活动
|
|
161
|
+
*/
|
|
162
|
+
async getActiveEvents() {
|
|
163
|
+
return this.get('/events/active');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 获取活动详情
|
|
168
|
+
* @param {string} eventId - 活动 ID
|
|
169
|
+
*/
|
|
170
|
+
async getEvent(eventId) {
|
|
171
|
+
return this.get(`/events/${eventId}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 参与邀请活动
|
|
176
|
+
* @param {string} eventId - 活动 ID
|
|
177
|
+
*/
|
|
178
|
+
async joinEvent(eventId) {
|
|
179
|
+
return this.post(`/events/${eventId}/join`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 获取活动进度
|
|
184
|
+
* @param {string} eventId - 活动 ID
|
|
185
|
+
*/
|
|
186
|
+
async getEventProgress(eventId) {
|
|
187
|
+
return this.get(`/events/${eventId}/my/progress`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ============ 兼容方法 ============
|
|
191
|
+
|
|
192
|
+
async getReferralInfo() {
|
|
193
|
+
try {
|
|
194
|
+
const codeData = await this.getMyReferralCode();
|
|
195
|
+
const statsData = await this.getInviteStats();
|
|
196
|
+
return {
|
|
197
|
+
...codeData,
|
|
198
|
+
...statsData
|
|
199
|
+
};
|
|
200
|
+
} catch {
|
|
201
|
+
return {
|
|
202
|
+
code: ''
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async getMyReferrals(params = {}) {
|
|
207
|
+
return this.getMyInvites(params);
|
|
208
|
+
}
|
|
209
|
+
async getReferralStats() {
|
|
210
|
+
return this.getInviteStats();
|
|
211
|
+
}
|
|
212
|
+
async getRewardConfig() {
|
|
213
|
+
return this.getRewardRules();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 创建默认实例
|
|
218
|
+
const referralApi = new ReferralApiClient();
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Referral SDK - 类型定义
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
const ReferralStatus = {};
|
|
225
|
+
|
|
226
|
+
const SUPPORTED_LANGUAGES = ['en', 'zh', 'ja', 'ko'];
|
|
227
|
+
const messages = {
|
|
228
|
+
en: {
|
|
229
|
+
'ref.invite': 'Invite Friends',
|
|
230
|
+
'ref.rewards': 'Rewards',
|
|
231
|
+
'ref.copied': 'Copied!'
|
|
232
|
+
},
|
|
233
|
+
zh: {
|
|
234
|
+
'ref.invite': '邀请好友',
|
|
235
|
+
'ref.rewards': '奖励',
|
|
236
|
+
'ref.copied': '已复制!'
|
|
237
|
+
},
|
|
238
|
+
ja: {
|
|
239
|
+
'ref.invite': '友達を招待',
|
|
240
|
+
'ref.rewards': '報酬',
|
|
241
|
+
'ref.copied': 'コピーしました!'
|
|
242
|
+
},
|
|
243
|
+
ko: {
|
|
244
|
+
'ref.invite': '친구 초대',
|
|
245
|
+
'ref.rewards': '보상',
|
|
246
|
+
'ref.copied': '복사되었습니다!'
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
let currentLang = 'en';
|
|
250
|
+
function setLanguage(l) {
|
|
251
|
+
if (SUPPORTED_LANGUAGES.includes(l)) currentLang = l;
|
|
252
|
+
}
|
|
253
|
+
function getLanguage() {
|
|
254
|
+
return currentLang;
|
|
255
|
+
}
|
|
256
|
+
function t(k) {
|
|
257
|
+
return messages[currentLang]?.[k] || messages.en?.[k] || k;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Referral SDK - React Hooks
|
|
262
|
+
* 邀请系统相关的状态管理
|
|
263
|
+
*/
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 获取邀请信息
|
|
268
|
+
*/
|
|
269
|
+
function useReferralInfo() {
|
|
270
|
+
const [info, setInfo] = React.useState(null);
|
|
271
|
+
const [loading, setLoading] = React.useState(true);
|
|
272
|
+
const [error, setError] = React.useState(null);
|
|
273
|
+
const fetchInfo = React.useCallback(async () => {
|
|
274
|
+
try {
|
|
275
|
+
setLoading(true);
|
|
276
|
+
const response = await referralApi.getReferralInfo();
|
|
277
|
+
setInfo(response);
|
|
278
|
+
setError(null);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
setError(err.message);
|
|
281
|
+
} finally {
|
|
282
|
+
setLoading(false);
|
|
283
|
+
}
|
|
284
|
+
}, []);
|
|
285
|
+
React.useEffect(() => {
|
|
286
|
+
fetchInfo();
|
|
287
|
+
}, [fetchInfo]);
|
|
288
|
+
const referralLink = React.useMemo(() => {
|
|
289
|
+
if (!info?.code) return '';
|
|
290
|
+
return `${window.location.origin}/invite/${info.code}`;
|
|
291
|
+
}, [info]);
|
|
292
|
+
return {
|
|
293
|
+
info,
|
|
294
|
+
referralLink,
|
|
295
|
+
loading,
|
|
296
|
+
error,
|
|
297
|
+
refresh: fetchInfo
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 我的邀请列表
|
|
303
|
+
*/
|
|
304
|
+
function useMyReferrals(options = {}) {
|
|
305
|
+
const [referrals, setReferrals] = React.useState([]);
|
|
306
|
+
const [loading, setLoading] = React.useState(true);
|
|
307
|
+
const [error, setError] = React.useState(null);
|
|
308
|
+
const [pagination, setPagination] = React.useState({
|
|
309
|
+
page: 1,
|
|
310
|
+
total: 0,
|
|
311
|
+
hasMore: true
|
|
312
|
+
});
|
|
313
|
+
const {
|
|
314
|
+
status,
|
|
315
|
+
limit = 20
|
|
316
|
+
} = options;
|
|
317
|
+
const fetchReferrals = React.useCallback(async (page = 1) => {
|
|
318
|
+
try {
|
|
319
|
+
setLoading(true);
|
|
320
|
+
const response = await referralApi.getMyReferrals({
|
|
321
|
+
status,
|
|
322
|
+
page,
|
|
323
|
+
limit
|
|
324
|
+
});
|
|
325
|
+
if (page === 1) {
|
|
326
|
+
setReferrals(response.data || []);
|
|
327
|
+
} else {
|
|
328
|
+
setReferrals(prev => [...prev, ...(response.data || [])]);
|
|
329
|
+
}
|
|
330
|
+
setPagination({
|
|
331
|
+
page,
|
|
332
|
+
total: response.total || 0,
|
|
333
|
+
hasMore: response.hasMore || false
|
|
334
|
+
});
|
|
335
|
+
setError(null);
|
|
336
|
+
} catch (err) {
|
|
337
|
+
setError(err.message);
|
|
338
|
+
} finally {
|
|
339
|
+
setLoading(false);
|
|
340
|
+
}
|
|
341
|
+
}, [status, limit]);
|
|
342
|
+
React.useEffect(() => {
|
|
343
|
+
fetchReferrals(1);
|
|
344
|
+
}, [fetchReferrals]);
|
|
345
|
+
const loadMore = React.useCallback(() => {
|
|
346
|
+
if (!loading && pagination.hasMore) {
|
|
347
|
+
fetchReferrals(pagination.page + 1);
|
|
348
|
+
}
|
|
349
|
+
}, [loading, pagination, fetchReferrals]);
|
|
350
|
+
|
|
351
|
+
// 按状态分组
|
|
352
|
+
const grouped = React.useMemo(() => {
|
|
353
|
+
const groups = {
|
|
354
|
+
pending: [],
|
|
355
|
+
confirmed: [],
|
|
356
|
+
rewarded: []
|
|
357
|
+
};
|
|
358
|
+
referrals.forEach(r => {
|
|
359
|
+
if (groups[r.status]) groups[r.status].push(r);
|
|
360
|
+
});
|
|
361
|
+
return groups;
|
|
362
|
+
}, [referrals]);
|
|
363
|
+
return {
|
|
364
|
+
referrals,
|
|
365
|
+
grouped,
|
|
366
|
+
loading,
|
|
367
|
+
error,
|
|
368
|
+
pagination,
|
|
369
|
+
loadMore,
|
|
370
|
+
refresh: () => fetchReferrals(1)
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* 邀请统计
|
|
376
|
+
*/
|
|
377
|
+
function useReferralStats() {
|
|
378
|
+
const [stats, setStats] = React.useState(null);
|
|
379
|
+
const [loading, setLoading] = React.useState(true);
|
|
380
|
+
const fetchStats = React.useCallback(async () => {
|
|
381
|
+
try {
|
|
382
|
+
setLoading(true);
|
|
383
|
+
const response = await referralApi.getReferralStats();
|
|
384
|
+
setStats(response);
|
|
385
|
+
} catch (err) {
|
|
386
|
+
console.error('Get referral stats error:', err);
|
|
387
|
+
} finally {
|
|
388
|
+
setLoading(false);
|
|
389
|
+
}
|
|
390
|
+
}, []);
|
|
391
|
+
React.useEffect(() => {
|
|
392
|
+
fetchStats();
|
|
393
|
+
}, [fetchStats]);
|
|
394
|
+
return {
|
|
395
|
+
stats,
|
|
396
|
+
loading,
|
|
397
|
+
refresh: fetchStats
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* 邀请排行榜
|
|
403
|
+
*/
|
|
404
|
+
function useReferralLeaderboard(period = 'all') {
|
|
405
|
+
const [leaderboard, setLeaderboard] = React.useState([]);
|
|
406
|
+
const [myRank, setMyRank] = React.useState(null);
|
|
407
|
+
const [loading, setLoading] = React.useState(true);
|
|
408
|
+
const fetchLeaderboard = React.useCallback(async () => {
|
|
409
|
+
try {
|
|
410
|
+
setLoading(true);
|
|
411
|
+
const response = await referralApi.getLeaderboard({
|
|
412
|
+
period
|
|
413
|
+
});
|
|
414
|
+
setLeaderboard(response.data || []);
|
|
415
|
+
setMyRank(response.myRank || null);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
console.error('Get leaderboard error:', err);
|
|
418
|
+
} finally {
|
|
419
|
+
setLoading(false);
|
|
420
|
+
}
|
|
421
|
+
}, [period]);
|
|
422
|
+
React.useEffect(() => {
|
|
423
|
+
fetchLeaderboard();
|
|
424
|
+
}, [fetchLeaderboard]);
|
|
425
|
+
return {
|
|
426
|
+
leaderboard,
|
|
427
|
+
myRank,
|
|
428
|
+
loading,
|
|
429
|
+
refresh: fetchLeaderboard
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* 复制功能
|
|
435
|
+
*/
|
|
436
|
+
function useCopyToClipboard() {
|
|
437
|
+
const [copied, setCopied] = React.useState(false);
|
|
438
|
+
const copy = React.useCallback(async text => {
|
|
439
|
+
try {
|
|
440
|
+
await navigator.clipboard.writeText(text);
|
|
441
|
+
setCopied(true);
|
|
442
|
+
setTimeout(() => setCopied(false), 2000);
|
|
443
|
+
return true;
|
|
444
|
+
} catch (err) {
|
|
445
|
+
console.error('Copy error:', err);
|
|
446
|
+
// 降级方案
|
|
447
|
+
const textarea = document.createElement('textarea');
|
|
448
|
+
textarea.value = text;
|
|
449
|
+
document.body.appendChild(textarea);
|
|
450
|
+
textarea.select();
|
|
451
|
+
document.execCommand('copy');
|
|
452
|
+
document.body.removeChild(textarea);
|
|
453
|
+
setCopied(true);
|
|
454
|
+
setTimeout(() => setCopied(false), 2000);
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
}, []);
|
|
458
|
+
return {
|
|
459
|
+
copy,
|
|
460
|
+
copied
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* 分享功能
|
|
466
|
+
*/
|
|
467
|
+
function useShare() {
|
|
468
|
+
const [sharing, setSharing] = React.useState(false);
|
|
469
|
+
const share = React.useCallback(async data => {
|
|
470
|
+
setSharing(true);
|
|
471
|
+
try {
|
|
472
|
+
if (navigator.share) {
|
|
473
|
+
await navigator.share({
|
|
474
|
+
title: data.title,
|
|
475
|
+
text: data.text,
|
|
476
|
+
url: data.url
|
|
477
|
+
});
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
} catch (err) {
|
|
482
|
+
if (err.name !== 'AbortError') {
|
|
483
|
+
console.error('Share error:', err);
|
|
484
|
+
}
|
|
485
|
+
return false;
|
|
486
|
+
} finally {
|
|
487
|
+
setSharing(false);
|
|
488
|
+
}
|
|
489
|
+
}, []);
|
|
490
|
+
const canShare = typeof navigator !== 'undefined' && !!navigator.share;
|
|
491
|
+
return {
|
|
492
|
+
share,
|
|
493
|
+
sharing,
|
|
494
|
+
canShare
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* 邀请奖励配置
|
|
500
|
+
*/
|
|
501
|
+
function useReferralRewards() {
|
|
502
|
+
const [rewards, setRewards] = React.useState(null);
|
|
503
|
+
const [loading, setLoading] = React.useState(true);
|
|
504
|
+
const fetchRewards = React.useCallback(async () => {
|
|
505
|
+
try {
|
|
506
|
+
setLoading(true);
|
|
507
|
+
const response = await referralApi.getRewardConfig();
|
|
508
|
+
setRewards(response);
|
|
509
|
+
} catch (err) {
|
|
510
|
+
console.error('Get reward config error:', err);
|
|
511
|
+
} finally {
|
|
512
|
+
setLoading(false);
|
|
513
|
+
}
|
|
514
|
+
}, []);
|
|
515
|
+
React.useEffect(() => {
|
|
516
|
+
fetchRewards();
|
|
517
|
+
}, [fetchRewards]);
|
|
518
|
+
return {
|
|
519
|
+
rewards,
|
|
520
|
+
loading,
|
|
521
|
+
refresh: fetchRewards
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Referral SDK - React 组件
|
|
527
|
+
* 邀请系统可视化组件
|
|
528
|
+
*/
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* 邀请链接卡片
|
|
533
|
+
*/
|
|
534
|
+
function ReferralLinkCard() {
|
|
535
|
+
const {
|
|
536
|
+
info,
|
|
537
|
+
referralLink,
|
|
538
|
+
loading
|
|
539
|
+
} = useReferralInfo();
|
|
540
|
+
const {
|
|
541
|
+
copy,
|
|
542
|
+
copied
|
|
543
|
+
} = useCopyToClipboard();
|
|
544
|
+
const {
|
|
545
|
+
share,
|
|
546
|
+
canShare
|
|
547
|
+
} = useShare();
|
|
548
|
+
const handleShare = React.useCallback(() => {
|
|
549
|
+
share({
|
|
550
|
+
title: t('inviteFriends'),
|
|
551
|
+
text: t('earnRewards'),
|
|
552
|
+
url: referralLink
|
|
553
|
+
});
|
|
554
|
+
}, [share, referralLink]);
|
|
555
|
+
if (loading) {
|
|
556
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
557
|
+
className: "eco-referral-card eco-referral-loading"
|
|
558
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
559
|
+
className: "eco-referral-spinner"
|
|
560
|
+
}));
|
|
561
|
+
}
|
|
562
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
563
|
+
className: "eco-referral-card"
|
|
564
|
+
}, /*#__PURE__*/React.createElement("h3", null, t('inviteFriends')), /*#__PURE__*/React.createElement("div", {
|
|
565
|
+
className: "eco-referral-code"
|
|
566
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
567
|
+
className: "eco-referral-code-label"
|
|
568
|
+
}, t('referralCode')), /*#__PURE__*/React.createElement("div", {
|
|
569
|
+
className: "eco-referral-code-value"
|
|
570
|
+
}, /*#__PURE__*/React.createElement("span", null, info?.code), /*#__PURE__*/React.createElement("button", {
|
|
571
|
+
onClick: () => copy(info?.code)
|
|
572
|
+
}, copied ? t('copied') : t('copy')))), /*#__PURE__*/React.createElement("div", {
|
|
573
|
+
className: "eco-referral-link"
|
|
574
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
575
|
+
className: "eco-referral-link-label"
|
|
576
|
+
}, t('referralLink')), /*#__PURE__*/React.createElement("div", {
|
|
577
|
+
className: "eco-referral-link-value"
|
|
578
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
579
|
+
type: "text",
|
|
580
|
+
value: referralLink,
|
|
581
|
+
readOnly: true
|
|
582
|
+
}), /*#__PURE__*/React.createElement("button", {
|
|
583
|
+
onClick: () => copy(referralLink)
|
|
584
|
+
}, copied ? t('copied') : t('copyLink')))), canShare && /*#__PURE__*/React.createElement("button", {
|
|
585
|
+
className: "eco-referral-share-btn",
|
|
586
|
+
onClick: handleShare
|
|
587
|
+
}, t('share')));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* 邀请统计卡片
|
|
592
|
+
*/
|
|
593
|
+
function ReferralStatsCard() {
|
|
594
|
+
const {
|
|
595
|
+
stats,
|
|
596
|
+
loading
|
|
597
|
+
} = useReferralStats();
|
|
598
|
+
if (loading) {
|
|
599
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
600
|
+
className: "eco-referral-stats eco-referral-loading"
|
|
601
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
602
|
+
className: "eco-referral-spinner"
|
|
603
|
+
}));
|
|
604
|
+
}
|
|
605
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
606
|
+
className: "eco-referral-stats"
|
|
607
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
608
|
+
className: "eco-referral-stat"
|
|
609
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
610
|
+
className: "eco-referral-stat-value"
|
|
611
|
+
}, stats?.totalInvited || 0), /*#__PURE__*/React.createElement("span", {
|
|
612
|
+
className: "eco-referral-stat-label"
|
|
613
|
+
}, t('totalInvited'))), /*#__PURE__*/React.createElement("div", {
|
|
614
|
+
className: "eco-referral-stat"
|
|
615
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
616
|
+
className: "eco-referral-stat-value"
|
|
617
|
+
}, stats?.pendingRewards || 0), /*#__PURE__*/React.createElement("span", {
|
|
618
|
+
className: "eco-referral-stat-label"
|
|
619
|
+
}, t('pendingRewards'))), /*#__PURE__*/React.createElement("div", {
|
|
620
|
+
className: "eco-referral-stat"
|
|
621
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
622
|
+
className: "eco-referral-stat-value"
|
|
623
|
+
}, stats?.earnedRewards || 0), /*#__PURE__*/React.createElement("span", {
|
|
624
|
+
className: "eco-referral-stat-label"
|
|
625
|
+
}, t('earnedRewards'))));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* 邀请记录列表
|
|
630
|
+
*/
|
|
631
|
+
function ReferralList() {
|
|
632
|
+
const {
|
|
633
|
+
referrals,
|
|
634
|
+
loading,
|
|
635
|
+
pagination,
|
|
636
|
+
loadMore
|
|
637
|
+
} = useMyReferrals();
|
|
638
|
+
if (loading && referrals.length === 0) {
|
|
639
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
640
|
+
className: "eco-referral-list eco-referral-loading"
|
|
641
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
642
|
+
className: "eco-referral-spinner"
|
|
643
|
+
}));
|
|
644
|
+
}
|
|
645
|
+
if (referrals.length === 0) {
|
|
646
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
647
|
+
className: "eco-referral-list eco-referral-empty"
|
|
648
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
649
|
+
className: "eco-referral-empty-icon"
|
|
650
|
+
}, "\uD83D\uDC65"), /*#__PURE__*/React.createElement("span", null, t('noReferrals')));
|
|
651
|
+
}
|
|
652
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
653
|
+
className: "eco-referral-list"
|
|
654
|
+
}, /*#__PURE__*/React.createElement("h4", null, t('myReferrals')), referrals.map(item => /*#__PURE__*/React.createElement("div", {
|
|
655
|
+
key: item.id,
|
|
656
|
+
className: "eco-referral-item"
|
|
657
|
+
}, /*#__PURE__*/React.createElement("img", {
|
|
658
|
+
className: "eco-referral-avatar",
|
|
659
|
+
src: item.user?.avatar || '/default-avatar.png',
|
|
660
|
+
alt: item.user?.name
|
|
661
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
662
|
+
className: "eco-referral-item-info"
|
|
663
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
664
|
+
className: "eco-referral-item-name"
|
|
665
|
+
}, item.user?.name), /*#__PURE__*/React.createElement("span", {
|
|
666
|
+
className: "eco-referral-item-time"
|
|
667
|
+
}, new Date(item.createdAt).toLocaleDateString())), /*#__PURE__*/React.createElement("span", {
|
|
668
|
+
className: `eco-referral-status eco-referral-status-${item.status}`
|
|
669
|
+
}, t(item.status)))), pagination.hasMore && /*#__PURE__*/React.createElement("button", {
|
|
670
|
+
className: "eco-referral-load-more",
|
|
671
|
+
onClick: loadMore,
|
|
672
|
+
disabled: loading
|
|
673
|
+
}, loading ? '...' : t('loading')));
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* 邀请排行榜
|
|
678
|
+
*/
|
|
679
|
+
function ReferralLeaderboard() {
|
|
680
|
+
const [period, setPeriod] = React.useState('all');
|
|
681
|
+
const {
|
|
682
|
+
leaderboard,
|
|
683
|
+
myRank,
|
|
684
|
+
loading
|
|
685
|
+
} = useReferralLeaderboard(period);
|
|
686
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
687
|
+
className: "eco-referral-leaderboard"
|
|
688
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
689
|
+
className: "eco-referral-leaderboard-header"
|
|
690
|
+
}, /*#__PURE__*/React.createElement("h4", null, t('leaderboard')), /*#__PURE__*/React.createElement("select", {
|
|
691
|
+
value: period,
|
|
692
|
+
onChange: e => setPeriod(e.target.value)
|
|
693
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
694
|
+
value: "daily"
|
|
695
|
+
}, "\u4ECA\u65E5"), /*#__PURE__*/React.createElement("option", {
|
|
696
|
+
value: "weekly"
|
|
697
|
+
}, "\u672C\u5468"), /*#__PURE__*/React.createElement("option", {
|
|
698
|
+
value: "monthly"
|
|
699
|
+
}, "\u672C\u6708"), /*#__PURE__*/React.createElement("option", {
|
|
700
|
+
value: "all"
|
|
701
|
+
}, "\u5168\u90E8"))), loading ? /*#__PURE__*/React.createElement("div", {
|
|
702
|
+
className: "eco-referral-loading"
|
|
703
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
704
|
+
className: "eco-referral-spinner"
|
|
705
|
+
})) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
706
|
+
className: "eco-referral-leaderboard-list"
|
|
707
|
+
}, leaderboard.map((item, qbit) => /*#__PURE__*/React.createElement("div", {
|
|
708
|
+
key: item.userId,
|
|
709
|
+
className: "eco-referral-rank-item"
|
|
710
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
711
|
+
className: `eco-referral-rank eco-referral-rank-${qbit + 1}`
|
|
712
|
+
}, qbit + 1), /*#__PURE__*/React.createElement("img", {
|
|
713
|
+
className: "eco-referral-rank-avatar",
|
|
714
|
+
src: item.avatar || '/default-avatar.png',
|
|
715
|
+
alt: item.name
|
|
716
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
717
|
+
className: "eco-referral-rank-name"
|
|
718
|
+
}, item.name), /*#__PURE__*/React.createElement("span", {
|
|
719
|
+
className: "eco-referral-rank-count"
|
|
720
|
+
}, item.count)))), myRank && /*#__PURE__*/React.createElement("div", {
|
|
721
|
+
className: "eco-referral-my-rank"
|
|
722
|
+
}, /*#__PURE__*/React.createElement("span", null, t('rank'), ": #", myRank.rank), /*#__PURE__*/React.createElement("span", null, t('inviteCount'), ": ", myRank.count))));
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* 邀请规则
|
|
727
|
+
*/
|
|
728
|
+
function ReferralRules() {
|
|
729
|
+
const {
|
|
730
|
+
rewards
|
|
731
|
+
} = useReferralRewards();
|
|
732
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
733
|
+
className: "eco-referral-rules"
|
|
734
|
+
}, /*#__PURE__*/React.createElement("h4", null, t('howItWorks')), /*#__PURE__*/React.createElement("div", {
|
|
735
|
+
className: "eco-referral-steps"
|
|
736
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
737
|
+
className: "eco-referral-step"
|
|
738
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
739
|
+
className: "eco-referral-step-num"
|
|
740
|
+
}, "1"), /*#__PURE__*/React.createElement("span", {
|
|
741
|
+
className: "eco-referral-step-text"
|
|
742
|
+
}, t('step1'))), /*#__PURE__*/React.createElement("div", {
|
|
743
|
+
className: "eco-referral-step"
|
|
744
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
745
|
+
className: "eco-referral-step-num"
|
|
746
|
+
}, "2"), /*#__PURE__*/React.createElement("span", {
|
|
747
|
+
className: "eco-referral-step-text"
|
|
748
|
+
}, t('step2'))), /*#__PURE__*/React.createElement("div", {
|
|
749
|
+
className: "eco-referral-step"
|
|
750
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
751
|
+
className: "eco-referral-step-num"
|
|
752
|
+
}, "3"), /*#__PURE__*/React.createElement("span", {
|
|
753
|
+
className: "eco-referral-step-text"
|
|
754
|
+
}, t('step3')))), rewards && /*#__PURE__*/React.createElement("div", {
|
|
755
|
+
className: "eco-referral-rewards"
|
|
756
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
757
|
+
className: "eco-referral-reward"
|
|
758
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
759
|
+
className: "eco-referral-reward-label"
|
|
760
|
+
}, t('inviteReward')), /*#__PURE__*/React.createElement("span", {
|
|
761
|
+
className: "eco-referral-reward-value"
|
|
762
|
+
}, rewards.inviterReward, " \u79EF\u5206")), /*#__PURE__*/React.createElement("div", {
|
|
763
|
+
className: "eco-referral-reward"
|
|
764
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
765
|
+
className: "eco-referral-reward-label"
|
|
766
|
+
}, t('inviteeReward')), /*#__PURE__*/React.createElement("span", {
|
|
767
|
+
className: "eco-referral-reward-value"
|
|
768
|
+
}, rewards.inviteeReward, " \u79EF\u5206"))));
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* 邀请页面
|
|
773
|
+
*/
|
|
774
|
+
function ReferralPage() {
|
|
775
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
776
|
+
className: "eco-referral-page"
|
|
777
|
+
}, /*#__PURE__*/React.createElement(ReferralLinkCard, null), /*#__PURE__*/React.createElement(ReferralStatsCard, null), /*#__PURE__*/React.createElement(ReferralRules, null), /*#__PURE__*/React.createElement(ReferralList, null), /*#__PURE__*/React.createElement(ReferralLeaderboard, null));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* @quantabit/referral-sdk
|
|
782
|
+
* Referral System SDK - Full Version
|
|
783
|
+
*/
|
|
784
|
+
|
|
785
|
+
const getReferralInfo = (...args) => referralApi.getReferralInfo(...args);
|
|
786
|
+
const getMyReferrals = (...args) => referralApi.getMyReferrals(...args);
|
|
787
|
+
const getReferralStats = (...args) => referralApi.getReferralStats(...args);
|
|
788
|
+
const getLeaderboard = (...args) => referralApi.getLeaderboard(...args);
|
|
789
|
+
|
|
790
|
+
exports.ReferralApiClient = ReferralApiClient;
|
|
791
|
+
exports.ReferralLeaderboard = ReferralLeaderboard;
|
|
792
|
+
exports.ReferralLinkCard = ReferralLinkCard;
|
|
793
|
+
exports.ReferralList = ReferralList;
|
|
794
|
+
exports.ReferralPage = ReferralPage;
|
|
795
|
+
exports.ReferralRules = ReferralRules;
|
|
796
|
+
exports.ReferralStatsCard = ReferralStatsCard;
|
|
797
|
+
exports.ReferralStatus = ReferralStatus;
|
|
798
|
+
exports.SUPPORTED_LANGUAGES = SUPPORTED_LANGUAGES;
|
|
799
|
+
exports.getLanguage = getLanguage;
|
|
800
|
+
exports.getLeaderboard = getLeaderboard;
|
|
801
|
+
exports.getMyReferrals = getMyReferrals;
|
|
802
|
+
exports.getReferralInfo = getReferralInfo;
|
|
803
|
+
exports.getReferralStats = getReferralStats;
|
|
804
|
+
exports.messages = messages;
|
|
805
|
+
exports.referralApi = referralApi;
|
|
806
|
+
exports.setLanguage = setLanguage;
|
|
807
|
+
exports.t = t;
|
|
808
|
+
exports.useCopyToClipboard = useCopyToClipboard;
|
|
809
|
+
exports.useMyReferrals = useMyReferrals;
|
|
810
|
+
exports.useReferralInfo = useReferralInfo;
|
|
811
|
+
exports.useReferralLeaderboard = useReferralLeaderboard;
|
|
812
|
+
exports.useReferralRewards = useReferralRewards;
|
|
813
|
+
exports.useReferralStats = useReferralStats;
|
|
814
|
+
exports.useShare = useShare;
|
|
815
|
+
//# sourceMappingURL=index.cjs.map
|