diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 701db2ed766..11e59c96c67 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -6431,6 +6431,9 @@
"message": "Get $1 points/$2.",
"description": "The $1 is the number of points, $2 is the plan interval (month or year)"
},
+ "shieldTxDetails3DescriptionLinkReward": {
+ "message": "Link Rewards"
+ },
"shieldTxDetails3DescriptionSignUp": {
"message": "Sign up"
},
diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json
index 701db2ed766..11e59c96c67 100644
--- a/app/_locales/en_GB/messages.json
+++ b/app/_locales/en_GB/messages.json
@@ -6431,6 +6431,9 @@
"message": "Get $1 points/$2.",
"description": "The $1 is the number of points, $2 is the plan interval (month or year)"
},
+ "shieldTxDetails3DescriptionLinkReward": {
+ "message": "Link Rewards"
+ },
"shieldTxDetails3DescriptionSignUp": {
"message": "Sign up"
},
diff --git a/ui/hooks/rewards/useOptIn.ts b/ui/hooks/rewards/useOptIn.ts
index fda2fe60199..784f6f3d0ee 100644
--- a/ui/hooks/rewards/useOptIn.ts
+++ b/ui/hooks/rewards/useOptIn.ts
@@ -1,6 +1,7 @@
import { useCallback, useState, useContext, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { AccountGroupId, AccountWalletId } from '@metamask/account-api';
+import log from 'loglevel';
import {
getMultichainAccountsByWalletId,
getWalletIdAndNameByAccountAddress,
@@ -173,8 +174,9 @@ export const useOptIn = (options?: UseOptInOptions): UseOptinResult => {
options.rewardPoints,
),
);
- } catch {
+ } catch (error) {
// Silently fail - reward linking should not block opt-in
+ log.warn('Failed to link reward to shield subscription', error);
}
}
}
diff --git a/ui/pages/settings/transaction-shield-tab/transaction-shield.tsx b/ui/pages/settings/transaction-shield-tab/transaction-shield.tsx
index a53a3f2921a..10fc8c099af 100644
--- a/ui/pages/settings/transaction-shield-tab/transaction-shield.tsx
+++ b/ui/pages/settings/transaction-shield-tab/transaction-shield.tsx
@@ -4,6 +4,7 @@ import {
Product,
PRODUCT_TYPES,
RECURRING_INTERVALS,
+ Subscription,
SUBSCRIPTION_STATUSES,
} from '@metamask/subscription-controller';
import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
@@ -17,6 +18,7 @@ import {
IconSize,
} from '@metamask/design-system-react';
import { useDispatch, useSelector } from 'react-redux';
+import log from 'loglevel';
import {
BannerAlert,
BannerAlertSeverity,
@@ -83,6 +85,7 @@ import { useHandlePayment } from '../../../hooks/subscription/useHandlePayment';
import { MetaMaskReduxDispatch } from '../../../store/store';
import { setOnboardingModalOpen } from '../../../ducks/rewards';
import { getIntlLocale } from '../../../ducks/locale/locale';
+import { linkRewardToShieldSubscription } from '../../../store/actions';
import CancelMembershipModal from './cancel-membership-modal';
import { isCardPaymentMethod, isCryptoPaymentMethod } from './types';
import ShieldBannerAnimation from './shield-banner-animation';
@@ -126,8 +129,9 @@ const TransactionShield = () => {
lastSubscription,
);
// show current active shield subscription or last subscription if no active subscription
- const displayedShieldSubscription =
- currentShieldSubscription ?? lastShieldSubscription;
+ const displayedShieldSubscription:
+ | (Subscription & { rewardAccountId?: string }) // TODO: fix this type once we have controller released.
+ | undefined = currentShieldSubscription ?? lastShieldSubscription;
const [timeoutCancelled, setTimeoutCancelled] = useState(false);
useEffect(() => {
@@ -280,6 +284,20 @@ const TransactionShield = () => {
padding: 4,
};
+ const handleLinkRewardToShieldSubscription = useCallback(
+ async (subscriptionId: string, rewardPoints: number) => {
+ // link to shield only coz already opted in to rewards
+ try {
+ await dispatch(
+ linkRewardToShieldSubscription(subscriptionId, rewardPoints),
+ );
+ } catch (error) {
+ log.warn('Failed to link reward to shield subscription', error);
+ }
+ },
+ [dispatch],
+ );
+
const buttonRow = (label: string, onClick: () => void, id?: string) => {
return (
{
)}
+ {hasOptedIntoRewards &&
+ displayedShieldSubscription?.id &&
+ claimedRewardsPoints &&
+ !displayedShieldSubscription?.rewardAccountId && (
+
+
+
+ )}
)}