Skip to content

Commit 5a70bbb

Browse files
committed
chore(rewards): completed ondo campaign ui changes
1 parent e3355b5 commit 5a70bbb

10 files changed

Lines changed: 295 additions & 24 deletions

app/components/UI/Rewards/Views/OndoCampaignDetailsView.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,62 @@ describe('OndoCampaignDetailsView', () => {
15051505
});
15061506
});
15071507

1508+
describe('positions section visibility', () => {
1509+
it('hides the positions section when campaign is complete, even if opted in with positions', () => {
1510+
const lastMonth = new Date();
1511+
lastMonth.setMonth(lastMonth.getMonth() - 1);
1512+
const yesterday = new Date();
1513+
yesterday.setDate(yesterday.getDate() - 1);
1514+
1515+
mockUseRewardCampaigns.mockReturnValue({
1516+
...hookDefaults,
1517+
campaigns: [
1518+
createTestCampaign({
1519+
startDate: lastMonth.toISOString(),
1520+
endDate: yesterday.toISOString(),
1521+
}),
1522+
],
1523+
});
1524+
mockUseGetCampaignParticipantStatus.mockReturnValue({
1525+
status: { optedIn: true, participantCount: 1 },
1526+
isLoading: false,
1527+
hasError: false,
1528+
refetch: jest.fn(),
1529+
});
1530+
mockUseGetOndoPortfolioPosition.mockReturnValue({
1531+
portfolio: { positions: [{}], summary: {}, computedAt: '' } as never,
1532+
isLoading: false,
1533+
hasError: false,
1534+
hasFetched: true,
1535+
refetch: jest.fn(),
1536+
});
1537+
const { queryByTestId } = render(<OndoCampaignDetailsView />);
1538+
expect(queryByTestId('ondo-campaign-portfolio')).toBeNull();
1539+
});
1540+
1541+
it('shows the positions section when campaign is active, opted in with positions', () => {
1542+
mockUseRewardCampaigns.mockReturnValue({
1543+
...hookDefaults,
1544+
campaigns: [createTestCampaign()],
1545+
});
1546+
mockUseGetCampaignParticipantStatus.mockReturnValue({
1547+
status: { optedIn: true, participantCount: 1 },
1548+
isLoading: false,
1549+
hasError: false,
1550+
refetch: jest.fn(),
1551+
});
1552+
mockUseGetOndoPortfolioPosition.mockReturnValue({
1553+
portfolio: { positions: [{}], summary: {}, computedAt: '' } as never,
1554+
isLoading: false,
1555+
hasError: false,
1556+
hasFetched: true,
1557+
refetch: jest.fn(),
1558+
});
1559+
const { getByTestId } = render(<OndoCampaignDetailsView />);
1560+
expect(getByTestId('ondo-campaign-portfolio')).toBeDefined();
1561+
});
1562+
});
1563+
15081564
describe('portfolio and leaderboard navigation', () => {
15091565
const setupOptedInWithPositions = () => {
15101566
mockUseRewardCampaigns.mockReturnValue({

app/components/UI/Rewards/Views/OndoCampaignDetailsView.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ const OndoCampaignDetailsView: React.FC = () => {
277277
!hasPositions &&
278278
getCampaignStatus(campaign) === 'active',
279279
showStatsSummarySection: hasPositions,
280-
showPortfolioSection: isOptedIn && hasPositions,
280+
showPortfolioSection:
281+
isOptedIn && hasPositions && getCampaignStatus(campaign) !== 'complete',
281282
showLeaderboardSection: true,
282283
};
283284
}, [campaign, isOptedIn, hasPositions]);
@@ -523,6 +524,9 @@ const OndoCampaignDetailsView: React.FC = () => {
523524
currentUserReferralCode={referralCode}
524525
userPosition={leaderboardUserPosition}
525526
campaignId={effectiveCampaignId}
527+
isCampaignComplete={
528+
getCampaignStatus(campaign) === 'complete'
529+
}
526530
/>
527531
</Box>
528532
</>

app/components/UI/Rewards/Views/OndoCampaignStatsView.test.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,54 @@ describe('OndoCampaignStatsView', () => {
666666
expect(getByText('$12,000.00')).toBeDefined();
667667
});
668668

669+
it('hides market value label when campaign is complete', () => {
670+
mockGetCampaignStatus.mockReturnValue('complete');
671+
mockRewardsState.campaigns = [createTestCampaign()];
672+
mockUseGetOndoPortfolioPosition.mockReturnValue({
673+
...portfolioDefaults,
674+
portfolio: {
675+
positions: [],
676+
summary: {
677+
totalCurrentValue: '12000',
678+
totalBookValue: '11000',
679+
totalUsdDeposited: '11000',
680+
netDeposit: '10500',
681+
totalCashedOut: '0',
682+
portfolioPnl: '1000',
683+
portfolioPnlPercent: '0.09',
684+
},
685+
computedAt: '2024-01-01T00:00:00Z',
686+
},
687+
});
688+
const { queryByText } = render(<OndoCampaignStatsView />);
689+
expect(
690+
queryByText('rewards.ondo_campaign_stats.label_market_value'),
691+
).toBeNull();
692+
});
693+
694+
it('shows market value label when campaign is active', () => {
695+
mockUseGetOndoPortfolioPosition.mockReturnValue({
696+
...portfolioDefaults,
697+
portfolio: {
698+
positions: [],
699+
summary: {
700+
totalCurrentValue: '12000',
701+
totalBookValue: '11000',
702+
totalUsdDeposited: '11000',
703+
netDeposit: '10500',
704+
totalCashedOut: '0',
705+
portfolioPnl: '1000',
706+
portfolioPnlPercent: '0.09',
707+
},
708+
computedAt: '2024-01-01T00:00:00Z',
709+
},
710+
});
711+
const { getByText } = render(<OndoCampaignStatsView />);
712+
expect(
713+
getByText('rewards.ondo_campaign_stats.label_market_value'),
714+
).toBeDefined();
715+
});
716+
669717
it('shows pending tag when position is not qualified', () => {
670718
mockUseGetOndoLeaderboardPosition.mockReturnValue({
671719
...positionDefaults,
@@ -856,6 +904,25 @@ describe('OndoCampaignStatsView', () => {
856904
queryByText('rewards.ondo_campaign_leaderboard.ineligible'),
857905
).toBeNull();
858906
});
907+
908+
it('does not show pending tag when campaign is complete even if position is not qualified', () => {
909+
mockGetCampaignStatus.mockReturnValue('complete');
910+
mockRewardsState.campaigns = [createTestCampaign()];
911+
mockUseGetCampaignParticipantStatus.mockReturnValue({
912+
status: { optedIn: true, participantCount: 1 },
913+
isLoading: false,
914+
hasError: false,
915+
refetch: jest.fn(),
916+
});
917+
mockUseGetOndoLeaderboardPosition.mockReturnValue({
918+
...positionDefaults,
919+
position: makePendingPosition(),
920+
});
921+
const { queryByText } = render(<OndoCampaignStatsView />);
922+
expect(
923+
queryByText('rewards.ondo_campaign_leaderboard.pending'),
924+
).toBeNull();
925+
});
859926
});
860927

861928
it('uses routeCampaignName as fallback when campaign has no name', () => {

app/components/UI/Rewards/Views/OndoCampaignStatsView.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,9 @@ const OndoCampaignStatsView: React.FC = () => {
230230
rank={rankValue}
231231
tier={tierValue}
232232
isLoading={leaderboardLoading}
233-
isPending={isPending}
233+
isPending={!isCampaignComplete && isPending}
234234
isQualified={isQualified}
235-
isIneligible={isIneligible}
235+
isIneligible={!isCampaignComplete && isIneligible}
236236
/>
237237
</Box>
238238

@@ -252,14 +252,16 @@ const OndoCampaignStatsView: React.FC = () => {
252252
isLoading={portfolioLoading}
253253
valueColor={returnColor}
254254
/>
255-
<StatCell
256-
label={strings(
257-
'rewards.ondo_campaign_stats.label_market_value',
258-
)}
259-
value={marketValue}
260-
isLoading={portfolioLoading}
261-
valueColor={returnColor}
262-
/>
255+
{!isCampaignComplete && (
256+
<StatCell
257+
label={strings(
258+
'rewards.ondo_campaign_stats.label_market_value',
259+
)}
260+
value={marketValue}
261+
isLoading={portfolioLoading}
262+
valueColor={returnColor}
263+
/>
264+
)}
263265
</Box>
264266

265267
{/* Net inflow | Outflow (or Days held when no outflow) */}

app/components/UI/Rewards/Views/OndoLeaderboardView.test.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,4 +358,61 @@ describe('OndoLeaderboardView', () => {
358358
expect.objectContaining({ defaultTier: 'MID' }),
359359
);
360360
});
361+
362+
describe('isCampaignComplete behavior', () => {
363+
const completeCampaign = {
364+
...mockCampaign,
365+
startDate: '2024-01-01T00:00:00Z',
366+
endDate: '2024-01-02T00:00:00Z',
367+
};
368+
369+
const pendingPosition = {
370+
rank: 8,
371+
projectedTier: 'STARTER',
372+
qualified: false,
373+
qualifiedDays: 3,
374+
totalInTier: 100,
375+
rateOfReturn: 0.05,
376+
currentUsdValue: 5000,
377+
totalUsdDeposited: 4000,
378+
netDeposit: 3500,
379+
neighbors: [],
380+
computedAt: '2024-01-01T00:00:00Z',
381+
};
382+
383+
it('does not show Pending tag when campaign is complete and position is not qualified', () => {
384+
mockUseSelector.mockImplementation((selector: (s: unknown) => unknown) =>
385+
selector({
386+
rewards: { referralCode: null, campaigns: [completeCampaign] },
387+
}),
388+
);
389+
mockUseGetOndoLeaderboardPosition.mockReturnValue({
390+
...positionDefaults,
391+
position: pendingPosition,
392+
});
393+
const { queryByText } = render(<OndoLeaderboardView />);
394+
expect(
395+
queryByText('rewards.ondo_campaign_leaderboard.pending'),
396+
).toBeNull();
397+
});
398+
399+
it('passes isCampaignComplete=true to OndoLeaderboard when campaign is complete', () => {
400+
mockUseSelector.mockImplementation((selector: (s: unknown) => unknown) =>
401+
selector({
402+
rewards: { referralCode: null, campaigns: [completeCampaign] },
403+
}),
404+
);
405+
render(<OndoLeaderboardView />);
406+
expect(mockOndoLeaderboard).toHaveBeenCalledWith(
407+
expect.objectContaining({ isCampaignComplete: true }),
408+
);
409+
});
410+
411+
it('passes isCampaignComplete=false to OndoLeaderboard when campaign is active', () => {
412+
render(<OndoLeaderboardView />);
413+
expect(mockOndoLeaderboard).toHaveBeenCalledWith(
414+
expect.objectContaining({ isCampaignComplete: false }),
415+
);
416+
});
417+
});
361418
});

app/components/UI/Rewards/Views/OndoLeaderboardView.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { useGetCampaignParticipantStatus } from '../hooks/useGetCampaignParticip
2323
import { getCurrentPrize } from '../components/Campaigns/OndoPrizePool';
2424
import { formatPercentChange, formatUsd } from '../utils/formatUtils';
2525
import { isCampaignIneligible } from '../utils/ondoCampaignConstants';
26+
import { getCampaignStatus } from '../components/Campaigns/CampaignTile.utils';
2627
import { strings } from '../../../../../locales/i18n';
2728
import Routes from '../../../../constants/navigation/Routes';
2829
import {
@@ -73,6 +74,9 @@ const OndoLeaderboardView: React.FC = () => {
7374
const { deposits, isLoading: isDepositsLoading } =
7475
useGetOndoCampaignDeposits(campaignId);
7576

77+
const isCampaignComplete =
78+
campaign != null && getCampaignStatus(campaign) === 'complete';
79+
7680
const isPending = position != null && !position.qualified;
7781
const isQualified = position != null && position.qualified;
7882

@@ -168,9 +172,9 @@ const OndoLeaderboardView: React.FC = () => {
168172
rank={rankValue}
169173
tier={tierValue}
170174
isLoading={isPositionLoading}
171-
isPending={isPending}
175+
isPending={!isCampaignComplete && isPending}
172176
isQualified={isQualified}
173-
isIneligible={isIneligible}
177+
isIneligible={!isCampaignComplete && isIneligible}
174178
showReturn
175179
returnValue={returnValue}
176180
returnColor={returnColor}
@@ -197,6 +201,7 @@ const OndoLeaderboardView: React.FC = () => {
197201
currentUserReferralCode={referralCode}
198202
userPosition={leaderboardUserPosition}
199203
campaignId={campaignId}
204+
isCampaignComplete={isCampaignComplete}
200205
/>
201206
</Box>
202207
</ScrollView>

app/components/UI/Rewards/components/Campaigns/CampaignStatsSummary.test.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,33 @@ describe('CampaignStatsSummary', () => {
621621

622622
// ── Campaign complete state ───────────────────────────────────────
623623

624+
it('hides IneligibleTag from rank cell suffix when isCampaignComplete=true', () => {
625+
const { queryByTestId } = render(
626+
<CampaignStatsSummary {...baseProps} isIneligible isCampaignComplete />,
627+
);
628+
expect(
629+
queryByTestId(CAMPAIGN_STATS_SUMMARY_TEST_IDS.INELIGIBLE_TAG),
630+
).toBeNull();
631+
});
632+
633+
it('hides PendingTag from rank cell suffix when isCampaignComplete=true and position is pending', () => {
634+
const pendingPosition: CampaignLeaderboardPositionDto = {
635+
...MOCK_POSITION,
636+
qualified: false,
637+
qualifiedDays: 3,
638+
};
639+
const { queryByTestId } = render(
640+
<CampaignStatsSummary
641+
{...baseProps}
642+
leaderboardPosition={pendingPosition}
643+
isCampaignComplete
644+
/>,
645+
);
646+
expect(
647+
queryByTestId(CAMPAIGN_STATS_SUMMARY_TEST_IDS.PENDING_TAG),
648+
).toBeNull();
649+
});
650+
624651
it('hides qualified card when isCampaignComplete=true', () => {
625652
const { queryByText } = render(
626653
<CampaignStatsSummary
@@ -658,6 +685,24 @@ describe('CampaignStatsSummary', () => {
658685
expect(queryByText('Qualify for this rank')).toBeNull();
659686
});
660687

688+
it('hides market value cell when isCampaignComplete=true', () => {
689+
const { queryByTestId } = render(
690+
<CampaignStatsSummary {...baseProps} isCampaignComplete />,
691+
);
692+
expect(
693+
queryByTestId(CAMPAIGN_STATS_SUMMARY_TEST_IDS.MARKET_VALUE),
694+
).toBeNull();
695+
});
696+
697+
it('shows market value cell when isCampaignComplete=false', () => {
698+
const { getByTestId } = render(
699+
<CampaignStatsSummary {...baseProps} isCampaignComplete={false} />,
700+
);
701+
expect(
702+
getByTestId(CAMPAIGN_STATS_SUMMARY_TEST_IDS.MARKET_VALUE),
703+
).toBeDefined();
704+
});
705+
661706
it('shows outcome banner when isCampaignComplete=true and outcome is provided', () => {
662707
const { getByTestId } = render(
663708
<CampaignStatsSummary

app/components/UI/Rewards/components/Campaigns/CampaignStatsSummary.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,11 @@ const CampaignStatsSummary: React.FC<CampaignStatsSummaryProps> = ({
193193
isLoading={leaderboardLoading}
194194
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.RANK}
195195
suffix={
196-
isIneligible ? (
196+
!isCampaignComplete && isIneligible ? (
197197
<IneligibleTag
198198
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.INELIGIBLE_TAG}
199199
/>
200-
) : isPending ? (
200+
) : !isCampaignComplete && isPending ? (
201201
<PendingTag
202202
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.PENDING_TAG}
203203
/>
@@ -228,13 +228,15 @@ const CampaignStatsSummary: React.FC<CampaignStatsSummaryProps> = ({
228228
valueColor={returnColor}
229229
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.RETURN}
230230
/>
231-
<StatCell
232-
label={strings('rewards.ondo_campaign_stats.label_market_value')}
233-
value={marketValue}
234-
isLoading={portfolioLoading}
235-
valueColor={returnColor}
236-
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.MARKET_VALUE}
237-
/>
231+
{!isCampaignComplete && (
232+
<StatCell
233+
label={strings('rewards.ondo_campaign_stats.label_market_value')}
234+
value={marketValue}
235+
isLoading={portfolioLoading}
236+
valueColor={returnColor}
237+
testID={CAMPAIGN_STATS_SUMMARY_TEST_IDS.MARKET_VALUE}
238+
/>
239+
)}
238240
</Box>
239241

240242
{/* Outcome banner (campaign ended) */}

0 commit comments

Comments
 (0)