Skip to content

Commit d75e449

Browse files
VGR-GITclaude
andcommitted
refactor(rewards): make outcome toast hook zero-arg, self-contain campaign lookup, guard on opted-in
Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d43259d commit d75e449

3 files changed

Lines changed: 38 additions & 32 deletions

File tree

app/components/UI/Rewards/RewardsNavigator.tsx

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,12 @@ import CampaignTourStepView from './Views/CampaignTourStepView';
1919
import { useDispatch, useSelector } from 'react-redux';
2020
import { selectRewardsSubscriptionId } from '../../../selectors/rewards';
2121
import {
22-
selectCampaigns,
2322
selectIsRewardsVersionBlocked,
2423
selectPendingDeeplink,
2524
} from '../../../reducers/rewards/selectors';
2625
import { setPendingDeeplink } from '../../../reducers/rewards';
2726
import { useCandidateSubscriptionId } from './hooks/useCandidateSubscriptionId';
2827
import { useOndoCampaignEndedOutcomeToast } from './hooks/useOndoCampaignEndedOutcomeToast';
29-
import { getCampaignStatus } from './components/Campaigns/CampaignTile.utils';
30-
import { CampaignType } from '../../../core/Engine/controllers/rewards-controller/types';
3128
import { useNavigation } from '@react-navigation/native';
3229
import { useTheme } from '../../../util/theme';
3330
import useRewardsVersionGuard from './hooks/useRewardsVersionGuard';
@@ -40,15 +37,6 @@ const RewardsNavigator: React.FC = () => {
4037
const subscriptionId = useSelector(selectRewardsSubscriptionId);
4138
const isVersionBlocked = useSelector(selectIsRewardsVersionBlocked);
4239
const pendingDeeplink = useSelector(selectPendingDeeplink);
43-
const campaigns = useSelector(selectCampaigns);
44-
const completeOndoCampaign =
45-
subscriptionId && campaigns
46-
? (campaigns.find(
47-
(c) =>
48-
c.type === CampaignType.ONDO_HOLDING &&
49-
getCampaignStatus(c) === 'complete',
50-
) ?? null)
51-
: null;
5240
const dispatch = useDispatch();
5341
const navigation = useNavigation();
5442
const { colors } = useTheme();
@@ -68,10 +56,7 @@ const RewardsNavigator: React.FC = () => {
6856
// Set candidate subscription ID in Redux state when component mounts and account changes
6957
useCandidateSubscriptionId();
7058

71-
useOndoCampaignEndedOutcomeToast(
72-
completeOndoCampaign?.id ?? undefined,
73-
completeOndoCampaign,
74-
);
59+
useOndoCampaignEndedOutcomeToast();
7560

7661
// Determine initial route - always start with onboarding intro step initially
7762
const getInitialRoute = () => {

app/components/UI/Rewards/hooks/useOndoCampaignEndedOutcomeToast.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,49 @@ import { IconName } from '../../../../component-library/components/Icons/Icon';
1111
import { useAppThemeFromContext } from '../../../../util/theme';
1212
import { strings } from '../../../../../locales/i18n';
1313
import Routes from '../../../../constants/navigation/Routes';
14-
import {
15-
CampaignType,
16-
CampaignDto,
17-
} from '../../../../core/Engine/controllers/rewards-controller/types';
14+
import { CampaignType } from '../../../../core/Engine/controllers/rewards-controller/types';
1815
import { getCampaignStatus } from '../components/Campaigns/CampaignTile.utils';
1916
import { selectRewardsSubscriptionId } from '../../../../selectors/rewards';
20-
import { selectIsCampaignOutcomeToastDismissed } from '../../../../reducers/rewards/selectors';
17+
import {
18+
selectCampaigns,
19+
selectCampaignParticipantStatusById,
20+
selectIsCampaignOutcomeToastDismissed,
21+
} from '../../../../reducers/rewards/selectors';
2122
import { dismissCampaignOutcomeToast } from '../../../../reducers/rewards';
2223
import useRewardsToast from './useRewardsToast';
2324
import { useOndoCampaignParticipantOutcome } from './useOndoCampaignParticipantOutcome';
2425

25-
export function useOndoCampaignEndedOutcomeToast(
26-
campaignId: string | undefined,
27-
campaign: CampaignDto | null,
28-
): void {
26+
export function useOndoCampaignEndedOutcomeToast(): void {
2927
const dispatch = useDispatch();
3028
const navigation = useNavigation();
3129
const theme = useAppThemeFromContext();
3230
const { toastRef } = useContext(ToastContext);
3331
const { showToast } = useRewardsToast();
3432

3533
const subscriptionId = useSelector(selectRewardsSubscriptionId);
34+
const campaigns = useSelector(selectCampaigns);
35+
36+
const campaign =
37+
subscriptionId && campaigns
38+
? (campaigns
39+
.filter(
40+
(c) =>
41+
c.type === CampaignType.ONDO_HOLDING &&
42+
getCampaignStatus(c) === 'complete',
43+
)
44+
.sort(
45+
(a, b) =>
46+
new Date(b.endDate).getTime() - new Date(a.endDate).getTime(),
47+
)[0] ?? null)
48+
: null;
49+
50+
const campaignId = campaign?.id;
51+
const isOptedIn =
52+
useSelector(selectCampaignParticipantStatusById(campaignId))?.optedIn ===
53+
true;
3654

3755
const isEligible =
38-
campaign?.type === CampaignType.ONDO_HOLDING &&
39-
getCampaignStatus(campaign) === 'complete' &&
40-
Boolean(subscriptionId) &&
41-
Boolean(campaignId);
56+
Boolean(subscriptionId) && Boolean(campaignId) && isOptedIn;
4257

4358
const { outcome } = useOndoCampaignParticipantOutcome(
4459
isEligible ? campaignId : undefined,

app/components/UI/Rewards/hooks/useOndoCampaignParticipantOutcome.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { useCallback, useEffect, useState } from 'react';
22
import { useDispatch, useSelector } from 'react-redux';
33
import Engine from '../../../../core/Engine';
44
import { selectRewardsSubscriptionId } from '../../../../selectors/rewards';
5-
import { selectOndoCampaignParticipantOutcomeById } from '../../../../reducers/rewards/selectors';
5+
import {
6+
selectOndoCampaignParticipantOutcomeById,
7+
selectCampaignParticipantStatusById,
8+
} from '../../../../reducers/rewards/selectors';
69
import { setOndoCampaignParticipantOutcome } from '../../../../reducers/rewards';
710
import type { OndoGmCampaignParticipantOutcomeDto } from '../../../../core/Engine/controllers/rewards-controller/types';
811

@@ -17,6 +20,9 @@ export function useOndoCampaignParticipantOutcome(
1720
): UseOndoCampaignParticipantOutcomeResult {
1821
const dispatch = useDispatch();
1922
const subscriptionId = useSelector(selectRewardsSubscriptionId);
23+
const isOptedIn =
24+
useSelector(selectCampaignParticipantStatusById(campaignId))?.optedIn ===
25+
true;
2026
const outcome = useSelector(
2127
selectOndoCampaignParticipantOutcomeById(
2228
subscriptionId ?? undefined,
@@ -27,7 +33,7 @@ export function useOndoCampaignParticipantOutcome(
2733
const [hasError, setHasError] = useState(false);
2834

2935
const fetchOutcome = useCallback(async (): Promise<void> => {
30-
if (!subscriptionId || !campaignId) {
36+
if (!subscriptionId || !campaignId || !isOptedIn) {
3137
setIsLoading(false);
3238
setHasError(false);
3339
return;
@@ -54,7 +60,7 @@ export function useOndoCampaignParticipantOutcome(
5460
} finally {
5561
setIsLoading(false);
5662
}
57-
}, [dispatch, campaignId, subscriptionId]);
63+
}, [dispatch, campaignId, subscriptionId, isOptedIn]);
5864

5965
useEffect(() => {
6066
fetchOutcome();

0 commit comments

Comments
 (0)