diff --git a/browser/extensions/api/brave_rewards_api.cc b/browser/extensions/api/brave_rewards_api.cc index ab0394302495..33b2a4f52552 100644 --- a/browser/extensions/api/brave_rewards_api.cc +++ b/browser/extensions/api/brave_rewards_api.cc @@ -1014,6 +1014,7 @@ void BraveRewardsGetExternalWalletFunction::OnExternalWalet( data->SetStringKey("withdrawUrl", wallet->withdraw_url); data->SetStringKey("userName", wallet->user_name); data->SetStringKey("accountUrl", wallet->account_url); + data->SetStringKey("loginUrl", wallet->login_url); } Respond(TwoArguments( diff --git a/browser/ui/webui/brave_rewards_page_ui.cc b/browser/ui/webui/brave_rewards_page_ui.cc index 65233d493f7b..22955516c2cb 100644 --- a/browser/ui/webui/brave_rewards_page_ui.cc +++ b/browser/ui/webui/brave_rewards_page_ui.cc @@ -1647,6 +1647,7 @@ void RewardsDOMHandler::OnGetExternalWallet( wallet_dict.SetStringKey("withdrawUrl", wallet->withdraw_url); wallet_dict.SetStringKey("userName", wallet->user_name); wallet_dict.SetStringKey("accountUrl", wallet->account_url); + wallet_dict.SetStringKey("loginUrl", wallet->login_url); } data.SetKey("wallet", std::move(wallet_dict)); diff --git a/browser/ui/webui/brave_tip_ui.cc b/browser/ui/webui/brave_tip_ui.cc index bb3678b9783c..8c5c258e5347 100644 --- a/browser/ui/webui/brave_tip_ui.cc +++ b/browser/ui/webui/brave_tip_ui.cc @@ -463,6 +463,7 @@ void RewardsTipDOMHandler::OnExternalWallet( data.SetString("withdrawUrl", wallet->withdraw_url); data.SetString("userName", wallet->user_name); data.SetString("accountUrl", wallet->account_url); + data.SetString("loginUrl", wallet->login_url); data.SetInteger("status", static_cast(wallet->status)); } diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index 73305ae70ee0..db6469a2959f 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -411,6 +411,8 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "redirectModalError", IDS_BRAVE_REWARDS_LOCAL_REDIRECT_MODAL_ERROR }, { "redirectModalClose", IDS_BRAVE_REWARDS_LOCAL_REDIRECT_MODAL_CLOSE }, { "redirectModalErrorWallet", IDS_BRAVE_REWARDS_LOCAL_REDIRECT_MODAL_ERROR_WALLET }, // NOLINT + { "redirectModalBatLimitTitle", IDS_BRAVE_REWARDS_LOCAL_REDIRECT_MODAL_BAT_LIMIT_TITLE }, // NOLINT + { "redirectModalBatLimitText", IDS_BRAVE_REWARDS_LOCAL_REDIRECT_MODAL_BAT_LIMIT_TEXT }, // NOLINT { "click", IDS_BRAVE_REWARDS_LOCAL_ADS_CONFIRMATION_TYPE_CLICK }, { "dismiss", IDS_BRAVE_REWARDS_LOCAL_ADS_CONFIRMATION_TYPE_DISMISS }, @@ -510,6 +512,9 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "import", IDS_BRAVE_UI_IMPORT }, { "includeInAuto", IDS_BRAVE_UI_INCLUDE_IN_AUTO }, { "learnMore", IDS_BRAVE_UI_LEARN_MORE }, + { "login", IDS_BRAVE_UI_LOGIN }, + { "loginMessageTitle", IDS_BRAVE_UI_LOGIN_MESSAGE_TITLE }, + { "loginMessageText", IDS_BRAVE_UI_LOGIN_MESSAGE_TEXT }, { "makeMonthly", IDS_BRAVE_UI_MAKE_MONTHLY }, { "manageWallet", IDS_BRAVE_UI_MANAGE_WALLET }, { "markAsInappropriate", IDS_BRAVE_UI_ADS_MARK_AS_INAPPROPRIATE }, diff --git a/common/extensions/api/brave_rewards.json b/common/extensions/api/brave_rewards.json index cd1b4649edba..fb8741227769 100644 --- a/common/extensions/api/brave_rewards.json +++ b/common/extensions/api/brave_rewards.json @@ -1049,6 +1049,9 @@ }, "accountUrl": { "type": "any" + }, + "loginUrl": { + "type": "string" } } } diff --git a/components/brave_rewards/browser/external_wallet.cc b/components/brave_rewards/browser/external_wallet.cc index 5bf56bb0b979..0ada1ad3c08a 100644 --- a/components/brave_rewards/browser/external_wallet.cc +++ b/components/brave_rewards/browser/external_wallet.cc @@ -25,6 +25,7 @@ namespace brave_rewards { withdraw_url = properties.withdraw_url; user_name = properties.user_name; account_url = properties.account_url; + login_url = properties.login_url; } std::string ExternalWallet::toJson() { @@ -41,6 +42,7 @@ namespace brave_rewards { dict.SetStringKey("withdraw_url", withdraw_url); dict.SetStringKey("user_name", user_name); dict.SetStringKey("account_url", account_url); + dict.SetStringKey("login_url", login_url); base::JSONWriter::Write(dict, &json_wallet); return json_wallet; } diff --git a/components/brave_rewards/browser/external_wallet.h b/components/brave_rewards/browser/external_wallet.h index db7cbbaa12ca..c7e9517acc7b 100644 --- a/components/brave_rewards/browser/external_wallet.h +++ b/components/brave_rewards/browser/external_wallet.h @@ -25,6 +25,7 @@ struct ExternalWallet { std::string withdraw_url; std::string user_name; std::string account_url; + std::string login_url; }; } // namespace brave_rewards diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index 114ff3a5a3fa..c2c74619d418 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -3151,6 +3151,7 @@ void RewardsServiceImpl::SaveExternalWallet(const std::string& wallet_type, new_wallet.SetStringKey("add_url", wallet->add_url); new_wallet.SetStringKey("withdraw_url", wallet->withdraw_url); new_wallet.SetStringKey("account_url", wallet->account_url); + new_wallet.SetStringKey("login_url", wallet->login_url); new_wallets.SetKey(wallet_type, std::move(new_wallet)); @@ -3219,6 +3220,11 @@ RewardsServiceImpl::GetExternalWallets() { wallet->account_url = *account_url; } + auto* login_url = it.second.FindStringKey("login_url"); + if (login_url) { + wallet->login_url = *login_url; + } + wallets.insert(std::make_pair(it.first, std::move(wallet))); } @@ -3243,6 +3249,7 @@ void RewardsServiceImpl::OnGetExternalWallet( external->withdraw_url = wallet->withdraw_url; external->user_name = wallet->user_name; external->account_url = wallet->account_url; + external->login_url = wallet->login_url; } std::move(callback).Run(static_cast(result), std::move(external)); diff --git a/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.cc b/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.cc index bdb65f88a37b..53664a8b9f9e 100644 --- a/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.cc +++ b/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.cc @@ -67,6 +67,23 @@ void RewardsBrowserTestPromotion::OnPromotionFinished( } } +void RewardsBrowserTestPromotion::WaitForUnblindedTokensReady() { + if (unblinded_tokens_) { + return; + } + + wait_for_unblinded_tokens_loop_.reset(new base::RunLoop); + wait_for_unblinded_tokens_loop_->Run(); +} + +void RewardsBrowserTestPromotion::OnUnblindedTokensReady( + brave_rewards::RewardsService* rewards_service) { + unblinded_tokens_ = true; + if (wait_for_unblinded_tokens_loop_) { + wait_for_unblinded_tokens_loop_->Quit(); + } +} + brave_rewards::Promotion RewardsBrowserTestPromotion::GetPromotion() { return promotion_; } @@ -90,6 +107,7 @@ double RewardsBrowserTestPromotion::ClaimPromotionViaCode() { solution, base::DoNothing()); WaitForPromotionFinished(); + WaitForUnblindedTokensReady(); return 30; } diff --git a/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.h b/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.h index 2ede26157604..e9d290374d59 100644 --- a/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.h +++ b/components/brave_rewards/browser/test/common/rewards_browsertest_promotion.h @@ -32,6 +32,8 @@ class RewardsBrowserTestPromotion void WaitForPromotionFinished(); + void WaitForUnblindedTokensReady(); + brave_rewards::Promotion GetPromotion(); std::string GetPromotionId(); @@ -49,10 +51,15 @@ class RewardsBrowserTestPromotion const uint32_t result, brave_rewards::Promotion promotion) override; + void OnUnblindedTokensReady( + brave_rewards::RewardsService* rewards_service) override; + std::unique_ptr wait_for_initialization_loop_; bool initialized_ = false; std::unique_ptr wait_for_finished_loop_; bool finished_ = false; + std::unique_ptr wait_for_unblinded_tokens_loop_; + bool unblinded_tokens_ = false; brave_rewards::Promotion promotion_; Browser* browser_; // NOT OWNED diff --git a/components/brave_rewards/browser/test/rewards_browsertest.cc b/components/brave_rewards/browser/test/rewards_browsertest.cc index 1a8aa1758be5..4c14fc36780c 100644 --- a/components/brave_rewards/browser/test/rewards_browsertest.cc +++ b/components/brave_rewards/browser/test/rewards_browsertest.cc @@ -240,6 +240,8 @@ IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(RewardsBrowserTest, NotVerifiedWallet) { rewards_browsertest_helper::EnableRewards(browser()); + contribution_->AddBalance(promotion_->ClaimPromotionViaCode()); + contribution_->IsBalanceCorrect(); // Click on verify button rewards_browsertest_util::WaitForElementThenClick( @@ -452,4 +454,32 @@ IN_PROC_BROWSER_TEST_F(RewardsBrowserTest, ResetRewardsWithBAT) { "Your 30 BATs and other Rewards"); } +IN_PROC_BROWSER_TEST_F(RewardsBrowserTest, UpholdLimitNoBAT) { + rewards_browsertest_helper::EnableRewards(browser()); + + rewards_browsertest_util::WaitForElementThenClick( + contents(), + "#verify-wallet-button"); + + rewards_browsertest_util::WaitForElementThenClick( + contents(), + "#cancel-login-button"); + + rewards_browsertest_util::WaitForElementThenClick( + contents(), + "#verify-wallet-button"); + + rewards_browsertest_util::WaitForElementThenClick( + contents(), + "#login-button"); + + // Check if we are redirected to uphold + { + const GURL current_url = contents()->GetURL(); + + auto found = current_url.spec().find("intention=login"); + ASSERT_TRUE(found != std::string::npos); + } +} + } // namespace rewards_browsertest diff --git a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json index 205870a59bc0..bef657c01316 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json +++ b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json @@ -598,5 +598,21 @@ "example": "John" } } + }, + "cancel": { + "message": "Cancel", + "description": "Text for cancel button" + }, + "login": { + "message": "Login", + "description": "Text for login button" + }, + "loginMessageTitle": { + "message": "Verifying wallet allows you to manage your funds more efficiently.", + "description": "Text for login button" + }, + "loginMessageText": { + "message": "You need to have minimum 25 BAT to create an Uphold account. Please try again later.
If you already have a verified Uphold account, continue to login.", + "description": "Text for login button" } } diff --git a/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts b/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts index 03e332551c7e..fbc72b7fb791 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/background/api/locale_api.ts @@ -143,7 +143,11 @@ export const getUIMessages = (): Record => { 'walletVerificationListHeader', 'walletVerificationTitle1', 'walletVerified', - 'yourBalance' + 'yourBalance', + 'cancel', + 'login', + 'loginMessageTitle', + 'loginMessageText' ] let translations = {} diff --git a/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx b/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx index 5f5a058ddd23..7ac7e58c1f85 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx +++ b/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx @@ -241,7 +241,7 @@ export class RewardsPanel extends React.Component { } openRewardsAddFunds = () => { - const { externalWallet } = this.props.rewardsPanelData + const { externalWallet, balance } = this.props.rewardsPanelData if (!externalWallet) { return @@ -254,10 +254,7 @@ export class RewardsPanel extends React.Component { return } - if (externalWallet.verifyUrl) { - utils.handleUpholdLink(externalWallet.verifyUrl, externalWallet) - return - } + utils.handleUpholdLink(balance, externalWallet) } openTOS () { @@ -331,7 +328,7 @@ export class RewardsPanel extends React.Component { let onVerifyClick = undefined if (!this.state.onlyAnonWallet) { walletStatus = utils.getWalletStatus(externalWallet) - onVerifyClick = utils.onVerifyClick.bind(this, this.actions) + onVerifyClick = utils.handleUpholdLink.bind(this, balance, externalWallet) } return ( diff --git a/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx b/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx index 27b8962f5979..60720169b0f9 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx +++ b/components/brave_rewards/resources/extension/brave_rewards/components/panel.tsx @@ -253,7 +253,7 @@ export class Panel extends React.Component { } onAddFunds = (notificationId?: string) => { - const { externalWallet } = this.props.rewardsPanelData + const { externalWallet, balance } = this.props.rewardsPanelData if (notificationId) { this.actions.deleteNotification(notificationId) @@ -270,10 +270,7 @@ export class Panel extends React.Component { return } - if (externalWallet.verifyUrl) { - utils.handleUpholdLink(externalWallet.verifyUrl, externalWallet) - return - } + utils.handleUpholdLink(balance, externalWallet) } showTipSiteDetail = (monthly: boolean) => { @@ -720,7 +717,7 @@ export class Panel extends React.Component { let onVerifyClick = undefined if (!this.props.onlyAnonWallet) { walletStatus = utils.getWalletStatus(externalWallet) - onVerifyClick = utils.onVerifyClick.bind(this, this.actions) + onVerifyClick = utils.handleUpholdLink.bind(this, balance, externalWallet) } return ( @@ -745,6 +742,7 @@ export class Panel extends React.Component { goToUphold={this.goToUphold} greetings={utils.getGreetings(externalWallet)} onlyAnonWallet={this.props.onlyAnonWallet} + showLoginMessage={balance.total < 25} {...notification} > { +export const handleUpholdLink = (balance: RewardsExtension.Balance, externalWallet?: RewardsExtension.ExternalWallet) => { + if (!externalWallet) { + return + } + + let link = externalWallet.verifyUrl + if (!externalWallet || (externalWallet && externalWallet.status === 0)) { link = 'brave://rewards/#verify' } + if (balance.total < 25) { + link = externalWallet.loginUrl + } + chrome.tabs.create({ url: link }) } -export const getExternalWallet = (actions: any, externalWallet?: RewardsExtension.ExternalWallet, open: boolean = false) => { +export const getExternalWallet = (actions: any, externalWallet?: RewardsExtension.ExternalWallet) => { chrome.braveRewards.getExternalWallet('uphold', (result: number, wallet: RewardsExtension.ExternalWallet) => { // EXPIRED TOKEN if (result === 24) { - getExternalWallet(actions, externalWallet, open) + getExternalWallet(actions, externalWallet) return } actions.onExternalWallet(wallet) - - if (open && wallet.verifyUrl) { - handleUpholdLink(wallet.verifyUrl) - } }) } -export const onVerifyClick = (actions: any, externalWallet?: RewardsExtension.ExternalWallet) => { - if (!externalWallet || externalWallet.verifyUrl) { - getExternalWallet(actions, externalWallet, true) - return - } - - handleUpholdLink(externalWallet.verifyUrl) -} - export const getClaimedPromotions = (promotions: RewardsExtension.Promotion[]) => { return promotions.filter((promotion: RewardsExtension.Promotion) => { return promotion.status === 4 // PromotionStatus::FINISHED diff --git a/components/brave_rewards/resources/page/components/pageWallet.tsx b/components/brave_rewards/resources/page/components/pageWallet.tsx index 9e5585e588d9..e5d55cc22adb 100644 --- a/components/brave_rewards/resources/page/components/pageWallet.tsx +++ b/components/brave_rewards/resources/page/components/pageWallet.tsx @@ -360,15 +360,24 @@ class PageWallet extends React.Component { this.actions.removeAllPendingContribution() } - handleUpholdLink = (link: string) => { - const { ui, externalWallet } = this.props.rewardsData - if (!ui.onBoardingDisplayed && - (!externalWallet || (externalWallet && externalWallet.status === 0))) { + handleUpholdLink = () => { + const { ui, externalWallet, balance } = this.props.rewardsData + + if (!externalWallet) { + return + } + + if (balance.total < 25) { + window.open(externalWallet.loginUrl, '_self') + return + } + + if (!ui.onBoardingDisplayed && externalWallet.status === 0) { this.toggleVerifyModal() return } - window.open(link, '_self') + window.open(externalWallet.verifyUrl, '_self') } onVerifyClick = (hideVerify: boolean) => { @@ -383,7 +392,7 @@ class PageWallet extends React.Component { this.actions.onOnBoardingDisplayed() } - this.handleUpholdLink(externalWallet.verifyUrl) + this.handleUpholdLink() } getWalletStatus = (): WalletState | undefined => { @@ -436,7 +445,7 @@ class PageWallet extends React.Component { } if (externalWallet.verifyUrl) { - this.handleUpholdLink(externalWallet.verifyUrl) + this.handleUpholdLink() return } } @@ -793,6 +802,7 @@ class PageWallet extends React.Component { goToUphold={this.goToUphold} greetings={this.getGreetings()} onlyAnonWallet={onlyAnonWallet} + showLoginMessage={balance.total < 25} > { enabledMain diff --git a/components/brave_rewards/resources/page/components/settingsPage.tsx b/components/brave_rewards/resources/page/components/settingsPage.tsx index 76c0c9a38d67..5ea93e5b1a7d 100644 --- a/components/brave_rewards/resources/page/components/settingsPage.tsx +++ b/components/brave_rewards/resources/page/components/settingsPage.tsx @@ -240,6 +240,18 @@ class SettingsPage extends React.Component { ) } + if (ui.modalRedirect === 'batLimit') { + return ( + + ) + } + if (ui.modalRedirect === 'error') { return ( = (state: Rewards.State break } + // NOT_FOUND + if (data.result === 9) { + ui.modalRedirect = 'batLimit' + break + } + if (data.result !== 0) { ui.modalRedirect = 'error' break diff --git a/components/brave_rewards/resources/ui/components/walletWrapper/index.tsx b/components/brave_rewards/resources/ui/components/walletWrapper/index.tsx index 2a7c3ae37afb..4a86227b72e1 100644 --- a/components/brave_rewards/resources/ui/components/walletWrapper/index.tsx +++ b/components/brave_rewards/resources/ui/components/walletWrapper/index.tsx @@ -41,7 +41,10 @@ import { StyledVerifiedButtonIcon, StyledVerifiedButtonText, StyledDialogList, - StyledLink + StyledLink, + LoginMessage, + LoginMessageButtons, + LoginMessageText } from './style' import { getLocale } from 'brave-ui/helpers' import { GrantCaptcha, GrantComplete, GrantError, GrantWrapper, WalletPopup } from '../' @@ -151,6 +154,7 @@ export interface Props { goToUphold?: () => void greetings?: string onlyAnonWallet?: boolean + showLoginMessage?: boolean } export type Step = '' | 'captcha' | 'complete' @@ -158,6 +162,7 @@ export type Step = '' | 'captcha' | 'complete' interface State { grantDetails: boolean, verificationDetails: boolean + showLoginMessage: boolean } export default class WalletWrapper extends React.PureComponent { @@ -165,7 +170,8 @@ export default class WalletWrapper extends React.PureComponent { super(props) this.state = { grantDetails: false, - verificationDetails: false + verificationDetails: false, + showLoginMessage: false } } @@ -317,12 +323,27 @@ export default class WalletWrapper extends React.PureComponent { ) } + walletButtonClicked = () => { + if (!this.props.onVerifyClick) { + return + } + + if (!this.props.showLoginMessage) { + this.props.onVerifyClick() + return + } + + this.setState({ + showLoginMessage: true + }) + } + generateWalletButton = (walletState: WalletState) => { const buttonProps: Partial = { size: 'small', level: 'primary', brand: 'rewards', - onClick: this.props.onVerifyClick + onClick: this.walletButtonClicked } switch (walletState) { @@ -531,6 +552,12 @@ export default class WalletWrapper extends React.PureComponent { ) } + toggleLoginMessage = () => { + this.setState({ + showLoginMessage: false + }) + } + render () { const { id, @@ -695,6 +722,32 @@ export default class WalletWrapper extends React.PureComponent { : this.generateNotification(notification) } + { + this.state.showLoginMessage + ? + + {getLocale('loginMessageTitle')} +

+ + +