From b70ea1fc7086e5968224786bfb5004ac3b1cd017 Mon Sep 17 00:00:00 2001 From: Taki Koutsomitis Date: Tue, 24 Mar 2026 09:58:39 -0400 Subject: [PATCH] Add staking opt in --- .../ResearchCoin/UserBalanceSection.tsx | 45 ++++++++++++++++--- services/user.service.ts | 10 +++++ types/user.ts | 4 ++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/components/ResearchCoin/UserBalanceSection.tsx b/components/ResearchCoin/UserBalanceSection.tsx index 06e46e60d..bd2000ded 100644 --- a/components/ResearchCoin/UserBalanceSection.tsx +++ b/components/ResearchCoin/UserBalanceSection.tsx @@ -5,11 +5,14 @@ import { useState } from 'react'; import { DepositModal } from '../modals/ResearchCoin/DepositModal'; import { WithdrawModal } from '../modals/ResearchCoin/WithdrawModal'; import { useCurrencyPreference } from '@/contexts/CurrencyPreferenceContext'; +import { useUser } from '@/contexts/UserContext'; import { Tooltip } from '@/components/ui/Tooltip'; import { FundingCreditsTooltip } from '@/components/ui/FundingCreditsTooltip'; +import { Switch } from '@/components/ui/Switch'; import { formatCombinedBalance, formatCombinedBalanceSecondary } from '@/utils/number'; import { Button } from '@/components/ui/Button'; import { ResearchCoinIcon } from '@/components/ui/icons/ResearchCoinIcon'; +import { UserService } from '@/services/user.service'; interface UserBalanceSectionProps { balance: { @@ -52,9 +55,24 @@ export function UserBalanceSection({ }: UserBalanceSectionProps) { const [isDepositModalOpen, setIsDepositModalOpen] = useState(false); const [isWithdrawModalOpen, setIsWithdrawModalOpen] = useState(false); + const [isUpdatingStaking, setIsUpdatingStaking] = useState(false); + const { user, refreshUser } = useUser(); const { showUSD } = useCurrencyPreference(); + const handleStakingToggle = async (checked: boolean) => { + if (!user || isUpdatingStaking) return; + setIsUpdatingStaking(true); + try { + await UserService.updateStakingOptIn(checked); + await refreshUser({ silent: true }); + } catch (error) { + console.error('Failed to update staking preference:', error); + } finally { + setIsUpdatingStaking(false); + } + }; + const isBalanceReady = !isFetchingExchangeRate; return ( @@ -100,12 +118,27 @@ export function UserBalanceSection({
ResearchCoin
-
-
- {showUSD ? balance?.formattedUsd || '$0.00' : balance?.formatted || '0 RSC'} -
-
- {showUSD ? balance?.formatted || '0 RSC' : balance?.formattedUsd || '$0.00'} +
+ +
+ Stake + +
+
+
+
+ {showUSD ? balance?.formattedUsd || '$0.00' : balance?.formatted || '0 RSC'} +
+
+ {showUSD ? balance?.formatted || '0 RSC' : balance?.formattedUsd || '$0.00'} +
diff --git a/services/user.service.ts b/services/user.service.ts index e6332045b..5e8ad2c1b 100644 --- a/services/user.service.ts +++ b/services/user.service.ts @@ -75,6 +75,16 @@ export class UserService { } } + /** + * Update the user's RSC staking opt-in preference + */ + static async updateStakingOptIn(isOptedIn: boolean): Promise { + const response = await ApiClient.patch(`/api/user/set_staking_opted_in/`, { + is_staking_opted_in: isOptedIn, + }); + return transformUser(response); + } + /** * Check user permissions using the gatekeeper system * @param application The application name to check permissions for diff --git a/types/user.ts b/types/user.ts index d52888685..65a8c7f8d 100644 --- a/types/user.ts +++ b/types/user.ts @@ -23,6 +23,7 @@ export interface User { isModerator?: boolean; referralCode?: string; authProvider?: 'google' | 'credentials'; + isStakingOptedIn?: boolean; } export type TransformedUser = User & BaseTransformed; @@ -47,6 +48,7 @@ const baseTransformUser = (raw: any): User => { moderator: false, isModerator: false, authProvider: undefined, + isStakingOptedIn: false, }; } @@ -84,6 +86,7 @@ const baseTransformUser = (raw: any): User => { ? 'google' : 'credentials' : undefined, + isStakingOptedIn: raw.is_staking_opted_in ?? false, }; }; @@ -107,6 +110,7 @@ export const transformUser = (raw: any): TransformedUser => { raw: null, isModerator: false, authProvider: undefined, + isStakingOptedIn: false, }; }