Skip to content

Commit b9ef2df

Browse files
cuzz-venusclaude
andcommitted
feat: show user rank card in last cycle summary modal
Replace the top total-rewards card with a user rank card that surfaces the user's last-cycle rank, Prime score and one of three outcome messages (qualified / missed top rank / not ranked), derived from the rank. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ac5d3b9 commit b9ef2df

11 files changed

Lines changed: 102 additions & 25 deletions

File tree

apps/evm/src/constants/prime.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import BigNumber from 'bignumber.js';
22
import { ChainId } from 'types';
33

4+
// Maximum rank that qualifies for Prime during a cycle
5+
export const PRIME_RANK_LIMIT = 500;
6+
47
const bscTestnetPrimeMarketsAddresses = {
58
vBTCB: '0xb6e9322C49FD75a367Fcb17B0Fcd62C5070EbCBe',
69
vUSDT: '0xb7526572FFE56AB9D7489838Bf2E18e3323b441A',

apps/evm/src/libs/translations/translations/en.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "You qualified for Prime in this cycle. Take positions in Prime markets to earn additional rewards.",
12661266
"notEligibleMessage": "You did not qualify for Prime during the last cycle. Stake XVS to compete for Prime in the next cycle.",
1267+
"primeScoreLabel": "Prime score",
1268+
"rankLabel": "Your rank",
1269+
"rankMissed": "Almost there! You weren't in last cycle's top 500. Boost your stake to qualify this cycle.",
1270+
"rankNoStake": "You didn't stake XVS last cycle. Stake now to qualify for Prime and earn extra rewards.",
1271+
"rankQualified": "Congrats! You're in the Top 500 during last cycle and qualified for Prime Rewards.",
12671272
"title": "Last Cycle Prime Summary",
1268-
"totalRewardsTitle": "Total Prime rewards distributed during the last cycle",
12691273
"userRewardsTitle": "Your Prime rewards last cycle"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/ja.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "今サイクルで Prime の対象になりました。Prime マーケットでポジションを取ると追加報酬を獲得できます。",
12661266
"notEligibleMessage": "前サイクルでは Prime の対象ではありませんでした。XVS をステークして次のサイクルで Prime を目指しましょう。",
1267+
"primeScoreLabel": "Prime スコア",
1268+
"rankLabel": "あなたのランク",
1269+
"rankMissed": "あと一歩です!前サイクルでは上位 500 に入りませんでした。ステーク量を増やして今サイクルでの対象を目指しましょう。",
1270+
"rankNoStake": "前サイクルでは XVS をステークしていませんでした。今すぐステークして Prime の対象になり、追加報酬を獲得しましょう。",
1271+
"rankQualified": "おめでとうございます!前サイクルで上位 500 に入り、Prime 報酬の対象になりました。",
12671272
"title": "前サイクルの Prime サマリー",
1268-
"totalRewardsTitle": "前サイクルに分配された Prime 報酬の合計",
12691273
"userRewardsTitle": "前サイクルのあなたの Prime 報酬"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/th.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "คุณมีสิทธิ์รับ Prime ในรอบนี้ เปิดสถานะในตลาด Prime เพื่อรับรางวัลเพิ่มเติม",
12661266
"notEligibleMessage": "คุณไม่มีสิทธิ์รับ Prime ในรอบที่แล้ว Stake XVS เพื่อแข่งขันรับ Prime ในรอบถัดไป",
1267+
"primeScoreLabel": "คะแนน Prime",
1268+
"rankLabel": "อันดับของคุณ",
1269+
"rankMissed": "ใกล้แล้ว! คุณไม่ได้อยู่ใน Top 500 ของรอบที่แล้ว เพิ่ม stake ของคุณเพื่อให้มีสิทธิ์ในรอบนี้",
1270+
"rankNoStake": "คุณไม่ได้ stake XVS ในรอบที่แล้ว Stake ตอนนี้เพื่อมีสิทธิ์รับ Prime และรับรางวัลเพิ่มเติม",
1271+
"rankQualified": "ยินดีด้วย! คุณอยู่ใน Top 500 ในรอบที่แล้วและมีสิทธิ์รับรางวัล Prime",
12671272
"title": "สรุป Prime รอบที่แล้ว",
1268-
"totalRewardsTitle": "รางวัล Prime ทั้งหมดที่แจกจ่ายในรอบที่แล้ว",
12691273
"userRewardsTitle": "รางวัล Prime ของคุณในรอบที่แล้ว"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/tr.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "Bu döngüde Prime için uygun oldun. Ek ödül kazanmak için Prime piyasalarında pozisyon al.",
12661266
"notEligibleMessage": "Son döngüde Prime için uygun değildin. Bir sonraki döngüde Prime için yarışmak üzere XVS stake et.",
1267+
"primeScoreLabel": "Prime puanı",
1268+
"rankLabel": "Sıralaman",
1269+
"rankMissed": "Az kaldı! Son döngüde ilk 500 içinde değildin. Bu döngüde uygun olmak için stake'ini artır.",
1270+
"rankNoStake": "Son döngüde XVS stake etmedin. Prime için uygun olmak ve ek ödül kazanmak için şimdi stake et.",
1271+
"rankQualified": "Tebrikler! Son döngüde ilk 500 içindeydin ve Prime ödülleri için uygun oldun.",
12671272
"title": "Son Döngü Prime Özeti",
1268-
"totalRewardsTitle": "Son döngüde dağıtılan toplam Prime ödülleri",
12691273
"userRewardsTitle": "Son döngüdeki Prime ödülleriniz"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/vi.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "Bạn đủ điều kiện nhận Prime trong chu kỳ này. Hãy mở vị thế trong các thị trường Prime để nhận thêm phần thưởng.",
12661266
"notEligibleMessage": "Bạn không đủ điều kiện nhận Prime trong chu kỳ trước. Stake XVS để cạnh tranh Prime trong chu kỳ tiếp theo.",
1267+
"primeScoreLabel": "Điểm Prime",
1268+
"rankLabel": "Hạng của bạn",
1269+
"rankMissed": "Sắp được rồi! Bạn không nằm trong Top 500 của chu kỳ trước. Hãy tăng mức stake để đủ điều kiện trong chu kỳ này.",
1270+
"rankNoStake": "Bạn chưa stake XVS ở chu kỳ trước. Hãy stake ngay để đủ điều kiện nhận Prime và kiếm thêm phần thưởng.",
1271+
"rankQualified": "Chúc mừng! Bạn nằm trong Top 500 ở chu kỳ trước và đủ điều kiện nhận phần thưởng Prime.",
12671272
"title": "Tóm tắt Prime chu kỳ trước",
1268-
"totalRewardsTitle": "Tổng phần thưởng Prime đã phân phối trong chu kỳ trước",
12691273
"userRewardsTitle": "Phần thưởng Prime của bạn trong chu kỳ trước"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/zh-Hans.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "你在本周期已具备 Prime 资格。在 Prime 市场建仓以赚取额外奖励。",
12661266
"notEligibleMessage": "你在上一周期未具备 Prime 资格。质押 XVS 以在下一周期竞争 Prime。",
1267+
"primeScoreLabel": "Prime 分数",
1268+
"rankLabel": "你的排名",
1269+
"rankMissed": "就差一点!你未进入上一周期前 500。提升质押以在本周期获得资格。",
1270+
"rankNoStake": "你在上一周期未质押 XVS。立即质押以获得 Prime 资格并赚取额外奖励。",
1271+
"rankQualified": "恭喜!你在上一周期位列前 500,已获得 Prime 奖励资格。",
12671272
"title": "上一周期 Prime 汇总",
1268-
"totalRewardsTitle": "上一周期分发的 Prime 总奖励",
12691273
"userRewardsTitle": "你上一周期的 Prime 奖励"
12701274
},
12711275
"rankTable": {

apps/evm/src/libs/translations/translations/zh-Hant.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,12 @@
12641264
"lastCycleSummary": {
12651265
"eligibleMessage": "你在本週期已具備 Prime 資格。在 Prime 市場建倉以賺取額外獎勵。",
12661266
"notEligibleMessage": "你在上一週期未具備 Prime 資格。質押 XVS 以在下一週期競爭 Prime。",
1267+
"primeScoreLabel": "Prime 分數",
1268+
"rankLabel": "你的排名",
1269+
"rankMissed": "就差一點!你未進入上一週期前 500。提升質押以在本週期獲得資格。",
1270+
"rankNoStake": "你在上一週期未質押 XVS。立即質押以獲得 Prime 資格並賺取額外獎勵。",
1271+
"rankQualified": "恭喜!你在上一週期位列前 500,已獲得 Prime 獎勵資格。",
12671272
"title": "上一週期 Prime 彙總",
1268-
"totalRewardsTitle": "上一週期分發的 Prime 總獎勵",
12691273
"userRewardsTitle": "你上一週期的 Prime 獎勵"
12701274
},
12711275
"rankTable": {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { cn } from '@venusprotocol/ui';
2+
import type BigNumber from 'bignumber.js';
3+
4+
import { PRIME_RANK_LIMIT } from 'constants/prime';
5+
import { useTranslation } from 'libs/translations';
6+
import { shortenValueWithSuffix } from 'utilities';
7+
8+
export interface UserRankCardProps {
9+
rank?: number;
10+
primeScore?: BigNumber;
11+
className?: string;
12+
}
13+
14+
export const UserRankCard: React.FC<UserRankCardProps> = ({ rank, primeScore, className }) => {
15+
const { t } = useTranslation();
16+
17+
const isRanked = rank !== undefined;
18+
const isInTopRank = isRanked && rank <= PRIME_RANK_LIMIT;
19+
const rankLabel = isRanked ? `#${rank}` : '#-';
20+
const primeScoreLabel =
21+
isRanked && primeScore ? shortenValueWithSuffix({ value: primeScore }) : '-';
22+
23+
let message = t('primeLeaderboard.lastCycleSummary.rankNoStake');
24+
let messageClassName = 'text-yellow';
25+
26+
if (isInTopRank) {
27+
message = t('primeLeaderboard.lastCycleSummary.rankQualified');
28+
messageClassName = 'text-white';
29+
} else if (isRanked) {
30+
message = t('primeLeaderboard.lastCycleSummary.rankMissed');
31+
}
32+
33+
return (
34+
<div className={cn('flex flex-col gap-4 rounded-lg bg-background-active p-4', className)}>
35+
<div className="flex items-start justify-between">
36+
<div className="flex flex-col">
37+
<span className="text-b1r text-light-grey">
38+
{t('primeLeaderboard.lastCycleSummary.rankLabel')}
39+
</span>
40+
41+
<span className="text-h5 text-white">{rankLabel}</span>
42+
</div>
43+
44+
<div className="flex flex-col items-end">
45+
<span className="text-b1r text-light-grey">
46+
{t('primeLeaderboard.lastCycleSummary.primeScoreLabel')}
47+
</span>
48+
49+
<span className="text-h5 text-white">{primeScoreLabel}</span>
50+
</div>
51+
</div>
52+
53+
<p className={cn('text-b1r', messageClassName)}>{message}</p>
54+
</div>
55+
);
56+
};

apps/evm/src/pages/PrimeLeaderboard/LastCycleSummaryModal/__tests__/index.spec.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ import { renderComponent } from 'testUtils/render';
55
import { LastCycleSummaryModal } from '..';
66

77
describe('pages/PrimeLeaderboard/LastCycleSummaryModal', () => {
8-
it('renders the last cycle total and user Prime rewards', async () => {
8+
it('renders the last cycle user rank and rewards', async () => {
99
renderComponent(<LastCycleSummaryModal isOpen handleClose={() => {}} />);
1010

1111
expect(await screen.findByText('Last Cycle Prime Summary')).toBeInTheDocument();
12-
expect(
13-
screen.getByText('Total Prime rewards distributed during the last cycle'),
14-
).toBeInTheDocument();
12+
expect(screen.getByText('Your rank')).toBeInTheDocument();
1513
expect(screen.getByText('Your Prime rewards last cycle')).toBeInTheDocument();
1614
});
1715
});

0 commit comments

Comments
 (0)