diff --git a/browser/brave_profile_prefs.cc b/browser/brave_profile_prefs.cc index 7430fd73f05c2..3adcc95f7e9f4 100644 --- a/browser/brave_profile_prefs.cc +++ b/browser/brave_profile_prefs.cc @@ -160,6 +160,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref(kNewTabPageShowClock, true); registry->RegisterBooleanPref(kNewTabPageShowTopSites, true); registry->RegisterBooleanPref(kNewTabPageShowStats, true); + registry->RegisterBooleanPref(kNewTabPageShowRewards, true); // Brave Wallet registry->RegisterStringPref(kBraveWalletAES256GCMSivNonce, ""); diff --git a/browser/extensions/api/brave_rewards_api.cc b/browser/extensions/api/brave_rewards_api.cc index d5c30fb534cf3..7b946da4e0c72 100644 --- a/browser/extensions/api/brave_rewards_api.cc +++ b/browser/extensions/api/brave_rewards_api.cc @@ -968,5 +968,121 @@ BraveRewardsOnlyAnonWalletFunction::Run() { return RespondNow(OneArgument(std::make_unique(only))); } +BraveRewardsGetAdsEnabledFunction:: +~BraveRewardsGetAdsEnabledFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetAdsEnabledFunction::Run() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + AdsService* ads_service_ = + AdsServiceFactory::GetForProfile(profile); + + if (!ads_service_) { + return RespondNow(Error("Ads service is not initialized")); + } + + const bool enabled = ads_service_->IsEnabled(); + return RespondNow( + OneArgument(std::make_unique(enabled))); +} + +BraveRewardsGetAdsEstimatedEarningsFunction:: +~BraveRewardsGetAdsEstimatedEarningsFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetAdsEstimatedEarningsFunction::Run() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + RewardsService* rewards_service = + RewardsServiceFactory::GetForProfile(profile); + + if (!rewards_service) { + return RespondNow(Error("Rewards service is not initialized")); + } + + rewards_service->GetTransactionHistory(base::Bind( + &BraveRewardsGetAdsEstimatedEarningsFunction::OnAdsEstimatedEarnings, + this)); + return RespondLater(); +} + +void BraveRewardsGetAdsEstimatedEarningsFunction::OnAdsEstimatedEarnings( + const double estimated_pending_rewards, + const uint64_t next_payment_date_in_seconds, + const uint64_t ad_notifications_received_this_month) { + Respond(OneArgument( + std::make_unique(estimated_pending_rewards))); +} + +BraveRewardsGetBalanceReportsFunction:: +~BraveRewardsGetBalanceReportsFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetBalanceReportsFunction::Run() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + auto* rewards_service_ = RewardsServiceFactory::GetForProfile(profile); + + if (!rewards_service_) { + return RespondNow(Error("Rewards service is not not initialized")); + } + + rewards_service_->GetAllBalanceReports(base::Bind( + &BraveRewardsGetBalanceReportsFunction::OnGetBalanceReports, + this)); + + return RespondLater(); +} + +void BraveRewardsGetBalanceReportsFunction::OnGetBalanceReports( + const std::map& reports) { + std::unique_ptr data( + new base::DictionaryValue()); + + if (!reports.empty()) { + for (auto const& report : reports) { + const ::brave_rewards::BalanceReport old_report = report.second; + auto new_report = std::make_unique(); + new_report->SetString("grant", old_report.grants); + new_report->SetString("deposit", old_report.deposits); + new_report->SetString("ads", old_report.earning_from_ads); + new_report->SetString("contribute", old_report.auto_contribute); + new_report->SetString("donation", old_report.recurring_donation); + new_report->SetString("tips", old_report.one_time_donation); + new_report->SetString("total", old_report.total); + data->SetDictionary(report.first, std::move(new_report)); + } + } + + Respond(OneArgument(std::move(data))); +} + +BraveRewardsGetWalletExistsFunction:: +~BraveRewardsGetWalletExistsFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetWalletExistsFunction::Run() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + RewardsService* rewards_service = + RewardsServiceFactory::GetForProfile(profile); + + if (!rewards_service) { + return RespondNow(Error("Rewards service is not initialized")); + } + + rewards_service->IsWalletCreated(base::Bind( + &BraveRewardsGetWalletExistsFunction::OnGetWalletExists, + this)); + return RespondLater(); +} + +void BraveRewardsGetWalletExistsFunction::OnGetWalletExists( + const bool exists) { + Respond(OneArgument(std::make_unique(exists))); +} + } // namespace api } // namespace extensions diff --git a/browser/extensions/api/brave_rewards_api.h b/browser/extensions/api/brave_rewards_api.h index bd215c146d6bb..783d6f9d67b91 100644 --- a/browser/extensions/api/brave_rewards_api.h +++ b/browser/extensions/api/brave_rewards_api.h @@ -6,6 +6,7 @@ #ifndef BRAVE_BROWSER_EXTENSIONS_API_BRAVE_REWARDS_API_H_ #define BRAVE_BROWSER_EXTENSIONS_API_BRAVE_REWARDS_API_H_ +#include #include #include @@ -14,6 +15,7 @@ #include "brave/components/brave_rewards/browser/content_site.h" #include "brave/components/brave_rewards/browser/external_wallet.h" #include "brave/components/brave_rewards/browser/publisher_banner.h" +#include "brave/components/brave_rewards/browser/balance_report.h" #include "extensions/browser/extension_function.h" namespace extensions { @@ -371,6 +373,63 @@ class BraveRewardsOnlyAnonWalletFunction : public ExtensionFunction { ResponseAction Run() override; }; +class BraveRewardsGetAdsEnabledFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getAdsEnabled", UNKNOWN) + + protected: + ~BraveRewardsGetAdsEnabledFunction() override; + + ResponseAction Run() override; +}; + +class BraveRewardsGetAdsEstimatedEarningsFunction + : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getAdsEstimatedEarnings", UNKNOWN) + + protected: + ~BraveRewardsGetAdsEstimatedEarningsFunction() override; + + ResponseAction Run() override; + + private: + void OnAdsEstimatedEarnings( + const double estimated_pending_rewards, + const uint64_t next_payment_date_in_seconds, + const uint64_t ad_notifications_received_this_month); +}; + +class BraveRewardsGetBalanceReportsFunction + : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getBalanceReports", UNKNOWN) + + protected: + ~BraveRewardsGetBalanceReportsFunction() override; + + ResponseAction Run() override; + + private: + void OnGetBalanceReports( + const std::map& reports); +}; + +class BraveRewardsGetWalletExistsFunction + : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getWalletExists", UNKNOWN) + + protected: + ~BraveRewardsGetWalletExistsFunction() override; + + ResponseAction Run() override; + + private: + void OnGetWalletExists(const bool exists); +}; + } // namespace api } // namespace extensions diff --git a/browser/ui/webui/brave_new_tab_message_handler.cc b/browser/ui/webui/brave_new_tab_message_handler.cc index 544fa6ad74a52..48a69db91e4a4 100644 --- a/browser/ui/webui/brave_new_tab_message_handler.cc +++ b/browser/ui/webui/brave_new_tab_message_handler.cc @@ -55,6 +55,9 @@ base::DictionaryValue GetPreferencesDictionary(PrefService* prefs) { pref_data.SetBoolean( "showStats", prefs->GetBoolean(kNewTabPageShowStats)); + pref_data.SetBoolean( + "showRewards", + prefs->GetBoolean(kNewTabPageShowRewards)); return pref_data; } @@ -168,6 +171,9 @@ void BraveNewTabMessageHandler::OnJavascriptAllowed() { pref_change_registrar_.Add(kNewTabPageShowTopSites, base::Bind(&BraveNewTabMessageHandler::OnPreferencesChanged, base::Unretained(this))); + pref_change_registrar_.Add(kNewTabPageShowRewards, + base::Bind(&BraveNewTabMessageHandler::OnPreferencesChanged, + base::Unretained(this))); } void BraveNewTabMessageHandler::OnJavascriptDisallowed() { @@ -229,6 +235,8 @@ void BraveNewTabMessageHandler::HandleSaveNewTabPagePref( settingsKey = kNewTabPageShowTopSites; } else if (settingsKeyInput == "showStats") { settingsKey = kNewTabPageShowStats; + } else if (settingsKeyInput == "showRewards") { + settingsKey = kNewTabPageShowRewards; } else { LOG(ERROR) << "Invalid setting key"; return; diff --git a/browser/ui/webui/brave_rewards_page_ui.cc b/browser/ui/webui/brave_rewards_page_ui.cc index d4fcd313d38f1..36d6823d769cc 100644 --- a/browser/ui/webui/brave_rewards_page_ui.cc +++ b/browser/ui/webui/brave_rewards_page_ui.cc @@ -238,6 +238,10 @@ class RewardsDOMHandler : public WebUIMessageHandler, int32_t result, const std::string& wallet_type) override; + void OnAdsEnabled( + brave_rewards::RewardsService* rewards_service, + bool ads_enabled) override; + // RewardsNotificationsServiceObserver implementation void OnNotificationAdded( brave_rewards::RewardsNotificationService* rewards_notification_service, @@ -1646,6 +1650,17 @@ void RewardsDOMHandler::OnDisconnectWallet( data); } +void RewardsDOMHandler::OnAdsEnabled( + brave_rewards::RewardsService* rewards_service, + bool ads_enabled) { + if (!web_ui()->CanCallJavascript()) { + return; + } + + base::ListValue* emptyArgs = nullptr; + GetAdsData(emptyArgs); +} + void RewardsDOMHandler::OnlyAnonWallet(const base::ListValue* args) { if (!rewards_service_) { return; diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index 662db126ab0a4..b4e130801f210 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -155,6 +155,7 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "showBraveStats", IDS_BRAVE_NEW_TAB_SHOW_BRAVE_STATS }, { "showClock", IDS_BRAVE_NEW_TAB_SHOW_CLOCK }, { "showTopSites", IDS_BRAVE_NEW_TAB_SHOW_TOP_SITES }, + { "showRewards", IDS_BRAVE_NEW_TAB_SHOW_REWARDS }, // Private Tab - General { "learnMore", IDS_BRAVE_PRIVATE_NEW_TAB_LEARN_MORE }, @@ -189,7 +190,31 @@ void CustomizeWebUIHTMLSource(const std::string &name, // Private Tab - Private Window - Tor Box { "boxTorText2", IDS_BRAVE_PRIVATE_NEW_TAB_BOX_TOR_TEXT_2 }, - { "boxTorButton", IDS_BRAVE_PRIVATE_NEW_TAB_BOX_TOR_BUTTON } + { "boxTorButton", IDS_BRAVE_PRIVATE_NEW_TAB_BOX_TOR_BUTTON }, + + // Rewards widget + { "rewardsWidgetAnd", IDS_BRAVE_UI_AND }, + { "rewardsWidgetBat", IDS_BRAVE_UI_BAT_REWARDS_TEXT }, + { "rewardsWidgetBatPoints", IDS_BRAVE_UI_BAT_POINTS_TEXT }, + { "rewardsWidgetBraveRewards", IDS_BRAVE_UI_BRAVE_REWARDS }, + { "rewardsWidgetPrivacyPolicy", IDS_BRAVE_UI_PRIVACY_POLICY }, + { "rewardsWidgetTermsOfService", IDS_BRAVE_UI_TERMS_OF_SERVICE }, + { "rewardsWidgetTurnOnAds", IDS_BRAVE_UI_TURN_ON_ADS }, + { "rewardsWidgetClaimMyRewards", IDS_REWARDS_WIDGET_CLAIM_MY_REWARDS }, + { "rewardsWidgetWalletFailedButton", IDS_BRAVE_UI_WALLET_FAILED_BUTTON }, + { "rewardsWidgetAboutRewards", IDS_REWARDS_WIDGET_ABOUT_REWARDS }, + { "rewardsWidgetServiceText", IDS_REWARDS_WIDGET_SERVICE_TEXT }, + { "rewardsWidgetEstimatedEarnings", IDS_REWARDS_WIDGET_ESTIMATED_EARNINGS }, // NOLINT + { "rewardsWidgetMonthlyTips", IDS_REWARDS_WIDGET_MONTHLY_TIPS }, + { "rewardsWidgetTurningOn", IDS_REWARDS_WIDGET_TURNING_ON }, + { "rewardsWidgetTurnOnRewards", IDS_REWARDS_WIDGET_TURN_ON_REWARDS }, // NOLINT + { "rewardsWidgetReEnableTitle", IDS_REWARDS_WIDGET_REENABLE_TITLE }, // NOLINT + { "rewardsWidgetEnableTitle", IDS_REWARDS_WIDGET_ENABLE_TITLE }, + { "rewardsWidgetReEnableSubTitle", IDS_REWARDS_WIDGET_REENABLE_SUBTITLE }, // NOLINT + { "rewardsWidgetEnableSubTitle", IDS_REWARDS_WIDGET_ENABLE_SUBTITLE }, // NOLINT + { "rewardsWidgetNotificationTitle", IDS_REWARDS_WIDGET_NOTIFICATION_TITLE }, // NOLINT + { "rewardsWidgetNotificationTextAds", IDS_REWARDS_WIDGET_NOTIFICATION_TEXT_ADS }, // NOLINT + { "rewardsWidgetNotificationTextUGP", IDS_REWARDS_WIDGET_NOTIFICATION_TEXT_UGP } // NOLINT } }, { std::string("welcome"), { diff --git a/common/extensions/api/_api_features.json b/common/extensions/api/_api_features.json index ab2e1c70fb1af..07b1028c9e331 100644 --- a/common/extensions/api/_api_features.json +++ b/common/extensions/api/_api_features.json @@ -77,14 +77,23 @@ "contexts": ["blessed_extension"], "whitelist": ["3D9518A72EB02667A773B69DBA9E72E0F4A37423", "780BF954C0F7C586EA9662D4F967771F49CC2114", "FF32507DC3DB5DFFD1D6733187C84D4B74713D63"] }, - "braveRewards": { - "channel": "stable", - "dependencies": [], - "contexts": ["blessed_extension"], - "whitelist": [ - "46E9817CBF915C0D1F6BCCF916C42CC666FF1D64" - ] - }, + "braveRewards": [ + { + "channel": "stable", + "dependencies": [], + "contexts": ["blessed_extension"], + "whitelist": [ + "46E9817CBF915C0D1F6BCCF916C42CC666FF1D64" + ] + }, + { + "channel": "stable", + "contexts": ["webui"], + "matches": [ + "chrome://newtab/*" + ] + } + ], "rewardsNotifications": { "channel": "stable", "dependencies": [], diff --git a/common/extensions/api/brave_rewards.json b/common/extensions/api/brave_rewards.json index 04b6f53c6dd0b..1df69a288cb64 100644 --- a/common/extensions/api/brave_rewards.json +++ b/common/extensions/api/brave_rewards.json @@ -230,6 +230,17 @@ } ] }, + { + "name": "onAdsEnabled", + "type": "function", + "description": "", + "parameters": [ + { + "name": "enabled", + "type": "boolean" + } + ] + }, { "name": "onEnabledMain", "type": "function", @@ -628,6 +639,57 @@ } ] }, + { + "name": "getAdsEnabled", + "type": "function", + "description": "Gets whether ads is enabled", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "enabled", + "type": "boolean" + } + ] + } + ] + }, + { + "name": "getAdsEstimatedEarnings", + "type": "function", + "description": "Gets estimated ads earnings for the current month", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "amount", + "type": "number" + } + ] + } + ] + }, + { + "name": "getBalanceReports", + "type": "function", + "description": "Gets balance reports and contribution totals", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "data", + "type": "any" + } + ] + } + ] + }, { "name": "getRewardsMainEnabled", "type": "function", @@ -645,6 +707,23 @@ } ] }, + { + "name": "getWalletExists", + "type": "function", + "description": "Gets whether a Rewards wallet already exists", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "exists", + "type": "boolean" + } + ] + } + ] + }, { "name": "getACEnabled", "type": "function", diff --git a/common/pref_names.cc b/common/pref_names.cc index 758112bed9279..ac01e1e732548 100644 --- a/common/pref_names.cc +++ b/common/pref_names.cc @@ -63,6 +63,7 @@ const char kNewTabPageShowBackgroundImage[] = const char kNewTabPageShowClock[] = "brave.new_tab_page.show_clock"; const char kNewTabPageShowTopSites[] = "brave.new_tab_page.show_top_sites"; const char kNewTabPageShowStats[] = "brave.new_tab_page.show_stats"; +const char kNewTabPageShowRewards[] = "brave.new_tab_page.show_rewards"; const char kBraveEnabledMediaRouter[] = "brave.enable_media_router"; const char kBraveWalletAES256GCMSivNonce[] = "brave.wallet.aes_256_gcm_siv_nonce"; diff --git a/common/pref_names.h b/common/pref_names.h index 6f709804ce799..49d5bd9769512 100644 --- a/common/pref_names.h +++ b/common/pref_names.h @@ -54,6 +54,7 @@ extern const char kNewTabPageShowBackgroundImage[]; extern const char kNewTabPageShowClock[]; extern const char kNewTabPageShowTopSites[]; extern const char kNewTabPageShowStats[]; +extern const char kNewTabPageShowRewards[]; extern const char kBraveEnabledMediaRouter[]; extern const char kBraveWalletAES256GCMSivNonce[]; extern const char kBraveWalletEncryptedSeed[]; diff --git a/components/brave_ads/browser/ads_service_impl.cc b/components/brave_ads/browser/ads_service_impl.cc index 1a509a828e502..e6eebd4860b33 100644 --- a/components/brave_ads/browser/ads_service_impl.cc +++ b/components/brave_ads/browser/ads_service_impl.cc @@ -411,6 +411,7 @@ bool AdsServiceImpl::IsSupportedRegion() const { void AdsServiceImpl::SetEnabled( const bool is_enabled) { SetBooleanPref(prefs::kEnabled, is_enabled); + rewards_service_->TriggerOnAdsEnabled(is_enabled); } void AdsServiceImpl::SetAdsPerHour( diff --git a/components/brave_ads/browser/ads_service_impl_unittest.cc b/components/brave_ads/browser/ads_service_impl_unittest.cc index fea5f5ccdb8ff..2fc1bdf2a8a14 100644 --- a/components/brave_ads/browser/ads_service_impl_unittest.cc +++ b/components/brave_ads/browser/ads_service_impl_unittest.cc @@ -144,6 +144,7 @@ class MockRewardsService : public RewardsService { brave_rewards::SaveRecurringTipCallback)); MOCK_METHOD2(RefreshPublisher, void(const std::string&, brave_rewards::RefreshPublisherCallback)); + MOCK_METHOD1(TriggerOnAdsEnabled, void(bool)); MOCK_METHOD0(GetAllNotifications, const brave_rewards::RewardsNotificationService::RewardsNotificationsMap&()); MOCK_METHOD3(SaveInlineMediaInfo, diff --git a/components/brave_new_tab_ui/actions/new_tab_actions.ts b/components/brave_new_tab_ui/actions/new_tab_actions.ts index b13c08d3e948c..6bb64447e030e 100644 --- a/components/brave_new_tab_ui/actions/new_tab_actions.ts +++ b/components/brave_new_tab_ui/actions/new_tab_actions.ts @@ -9,7 +9,7 @@ import { types } from '../constants/new_tab_types' import { Preferences } from '../api/preferences' import { Stats } from '../api/stats' import { PrivateTabData } from '../api/privateTabData' -import { InitialData } from '../api/initialData' +import { InitialData, InitialRewardsData, PreInitialRewardsData } from '../api/initialData' export const bookmarkAdded = (url: string) => action(types.BOOKMARK_ADDED, { url @@ -74,3 +74,50 @@ export const preferencesUpdated = (preferences: Preferences) => export const setInitialData = (initialData: InitialData) => action(types.NEW_TAB_SET_INITIAL_DATA, initialData) + +export const createWallet = () => action(types.CREATE_WALLET, {}) + +export const onEnabledMain = (enabledMain: boolean) => action(types.ON_ENABLED_MAIN, { + enabledMain +}) + +export const onAdsEnabled = (enabled: boolean) => action(types.ON_ADS_ENABLED, { + enabled +}) + +export const onRewardsSettingSave = (key: string, value: any) => action(types.ON_REWARDS_SETTING_SAVE, { + key, + value +}) + +export const onWalletInitialized = (result: NewTab.RewardsResult) => action(types.ON_WALLET_INITIALIZED, { + result +}) + +export const onAdsEstimatedEarnings = (amount: number) => action(types.ON_ADS_ESTIMATED_EARNINGS, { + amount +}) + +export const onBalanceReports = (reports: Record) => action(types.ON_BALANCE_REPORTS, { + reports +}) + +export const onGrant = (properties: NewTab.GrantResponse) => action(types.ON_GRANT, { + properties +}) + +export const dismissNotification = (id: string) => action(types.DISMISS_NOTIFICATION, { + id +}) + +export const onBalance = (balance: NewTab.RewardsBalance) => action(types.ON_BALANCE, { + balance +}) + +export const onWalletExists = (exists: boolean) => action(types.ON_WALLET_EXISTS, { + exists +}) + +export const setInitialRewardsData = (initialRewardsData: InitialRewardsData) => action(types.SET_INITIAL_REWARDS_DATA, initialRewardsData) + +export const setPreInitialRewardsData = (preInitialRewardsData: PreInitialRewardsData) => action(types.SET_PRE_INITIAL_REWARDS_DATA, preInitialRewardsData) diff --git a/components/brave_new_tab_ui/api/initialData.ts b/components/brave_new_tab_ui/api/initialData.ts index 4bb0bc46e1689..a4e442c89d15d 100644 --- a/components/brave_new_tab_ui/api/initialData.ts +++ b/components/brave_new_tab_ui/api/initialData.ts @@ -15,8 +15,20 @@ export type InitialData = { topSites: topSitesAPI.TopSitesData } +export type PreInitialRewardsData = { + enabledAds: boolean + enabledMain: boolean +} + +export type InitialRewardsData = { + onlyAnonWallet: boolean + adsEstimatedEarnings: boolean + reports: Record + balance: NewTab.RewardsBalance +} + // Gets all data required for the first render of the page -export default async function getInitialData (): Promise { +export async function getInitialData (): Promise { try { console.timeStamp('Getting initial data...') const [preferences, stats, privateTabData, topSites] = await Promise.all([ @@ -37,3 +49,61 @@ export default async function getInitialData (): Promise { throw Error('Error getting initial data') } } + +export async function getRewardsPreInitialData (): Promise { + try { + const [ + enabledAds, + enabledMain + ] = await Promise.all([ + new Promise(resolve => chrome.braveRewards.getAdsEnabled((enabledAds: boolean) => { + resolve(enabledAds) + })), + new Promise(resolve => chrome.braveRewards.getRewardsMainEnabled((enabledMain: boolean) => { + resolve(enabledMain) + })) + ]) + return { + enabledAds, + enabledMain + } as PreInitialRewardsData + } catch (err) { + throw Error(err) + } +} + +export async function getRewardsInitialData (): Promise { + try { + const [ + onlyAnonWallet, + adsEstimatedEarnings, + reports, + balance + ] = await Promise.all([ + new Promise(resolve => chrome.braveRewards.onlyAnonWallet((onlyAnonWallet: boolean) => { + resolve(!!onlyAnonWallet) + })), + new Promise(resolve => chrome.braveRewards.getAdsEstimatedEarnings((adsEstimatedEarnings: number) => { + resolve(adsEstimatedEarnings) + })), + new Promise(resolve => chrome.braveRewards.getBalanceReports((reports: Record) => { + resolve(reports) + })), + new Promise(resolve => chrome.braveRewards.fetchBalance((balance: NewTab.RewardsBalance) => { + resolve(balance) + })), + new Promise(resolve => { + chrome.braveRewards.getGrants() + resolve(true) + }) + ]) + return { + onlyAnonWallet, + adsEstimatedEarnings, + reports, + balance + } as InitialRewardsData + } catch (err) { + throw Error(err) + } +} diff --git a/components/brave_new_tab_ui/api/preferences.ts b/components/brave_new_tab_ui/api/preferences.ts index cd600a6ec1537..e62b49a8cbc8b 100644 --- a/components/brave_new_tab_ui/api/preferences.ts +++ b/components/brave_new_tab_ui/api/preferences.ts @@ -15,6 +15,7 @@ export type Preferences = { showStats: boolean showClock: boolean showTopSites: boolean + showRewards: boolean } type PreferencesUpdatedHandler = (prefData: Preferences) => void @@ -43,6 +44,10 @@ export function saveShowStats (value: boolean): void { sendSavePref('showStats', value) } +export function saveShowRewards (value: boolean): void { + sendSavePref('showRewards', value) +} + export function addChangeListener (listener: PreferencesUpdatedHandler): void { window.cr.addWebUIListener('preferences-changed', listener) } diff --git a/components/brave_new_tab_ui/apiEventsToStore.ts b/components/brave_new_tab_ui/apiEventsToStore.ts index 6338caf31203e..88b31d1249aea 100644 --- a/components/brave_new_tab_ui/apiEventsToStore.ts +++ b/components/brave_new_tab_ui/apiEventsToStore.ts @@ -7,7 +7,7 @@ import getActions from './api/getActions' import * as preferencesAPI from './api/preferences' import * as statsAPI from './api/stats' import * as privateTabDataAPI from './api/privateTabData' -import getInitialData from './api/initialData' +import { getInitialData, getRewardsInitialData, getRewardsPreInitialData } from './api/initialData' async function updatePreferences (prefData: preferencesAPI.Preferences) { getActions().preferencesUpdated(prefData) @@ -21,19 +21,75 @@ async function updatePrivateTabData (data: privateTabDataAPI.PrivateTabData) { getActions().privateTabDataUpdated(data) } +function onRewardsToggled (prefData: preferencesAPI.Preferences): void { + if (prefData.showRewards) { + rewardsInitData() + } +} + // Not marked as async so we don't return a promise // and confuse callers -export default function wireApiEventsToStore () { +export function wireApiEventsToStore () { // Get initial data and dispatch to store getInitialData() .then((initialData) => { + if (initialData.preferences.showRewards) { + rewardsInitData() + window.setInterval(() => { + fetchCreatedWalletData() + }, 30000) + } getActions().setInitialData(initialData) // Listen for API changes and dispatch to store statsAPI.addChangeListener(updateStats) preferencesAPI.addChangeListener(updatePreferences) + preferencesAPI.addChangeListener(onRewardsToggled) privateTabDataAPI.addChangeListener(updatePrivateTabData) }) .catch(e => { console.error('New Tab Page fatal error:', e) }) } + +export function rewardsInitData () { + getRewardsPreInitialData() + .then((preInitialRewardsData) => { + getActions().setPreInitialRewardsData(preInitialRewardsData) + chrome.braveRewards.getWalletExists((exists: boolean) => { + if (!exists) { + return + } + fetchCreatedWalletData() + getActions().onWalletExists(exists) + }) + }) + .catch(e => { + console.error('Error fetching pre-initial rewards data: ', e) + }) +} + +function fetchCreatedWalletData () { + getRewardsInitialData() + .then((initialRewardsData) => { + getActions().setInitialRewardsData(initialRewardsData) + }) + .catch(e => { + console.error('Error fetching initial rewards data: ', e) + }) +} + +chrome.braveRewards.onWalletInitialized.addListener((result: any | NewTab.RewardsResult) => { + getActions().onWalletInitialized(result) +}) + +chrome.braveRewards.onEnabledMain.addListener((enabledMain: boolean) => { + getActions().onEnabledMain(enabledMain) +}) + +chrome.braveRewards.onAdsEnabled.addListener((enabled: boolean) => { + getActions().onAdsEnabled(enabled) +}) + +chrome.braveRewards.onGrant.addListener((properties: NewTab.GrantResponse) => { + getActions().onGrant(properties) +}) diff --git a/components/brave_new_tab_ui/brave_new_tab.tsx b/components/brave_new_tab_ui/brave_new_tab.tsx index a4aca28665b68..cd9cc8285992e 100644 --- a/components/brave_new_tab_ui/brave_new_tab.tsx +++ b/components/brave_new_tab_ui/brave_new_tab.tsx @@ -9,7 +9,7 @@ import { Provider } from 'react-redux' import Theme from 'brave-ui/theme/brave-default' import DarkTheme from 'brave-ui/theme/brave-dark' import BraveCoreThemeProvider from '../common/BraveCoreThemeProvider' -import wireAPIEventsToStore from './apiEventsToStore' +import { wireApiEventsToStore } from './apiEventsToStore' // Components import App from './containers/app' @@ -49,7 +49,7 @@ function initialize () { console.timeStamp('JS start') // Get store data going -wireAPIEventsToStore() +wireApiEventsToStore() // Perform DOM-dependent initialization when ready document.addEventListener('DOMContentLoaded', initialize) diff --git a/components/brave_new_tab_ui/components/default/grid/index.ts b/components/brave_new_tab_ui/components/default/grid/index.ts index 12a7c3e69706a..03c09b2c3eb7f 100644 --- a/components/brave_new_tab_ui/components/default/grid/index.ts +++ b/components/brave_new_tab_ui/components/default/grid/index.ts @@ -13,25 +13,31 @@ export const Header = styled<{}, 'header'>('header')` grid-template-areas: "stats . clock" ". . clock" - "topsites topsites topsites" + "topsites . rewards" + ". . ." "notification notification notification"; > *:nth-child(1) { grid-area: stats; margin: 0 46px 0 46px; } + > *:nth-child(2) { grid-area: clock; margin: 0 46px 0 46px; } > *:nth-child(3) { + grid-area: rewards; + } + + > *:nth-child(4) { grid-area: topsites; margin: 0 46px 0 46px; justify-self: start; } - > *:nth-child(4) { + > *:nth-child(5) { grid-area: notification; justify-self: center; } @@ -42,6 +48,7 @@ export const Header = styled<{}, 'header'>('header')` "clock clock clock" "stats stats stats" "topsites topsites topsites" + "rewards rewards rewards" "notification notification notification"; @@ -59,6 +66,11 @@ export const Header = styled<{}, 'header'>('header')` margin: auto; justify-content: center; } + + > *:nth-child(4) { + margin: auto; + justify-content: center; + } } ` export const Main = styled<{}, 'main'>('main')` diff --git a/components/brave_new_tab_ui/components/default/index.ts b/components/brave_new_tab_ui/components/default/index.ts index a60a46772ffbf..82223b3527366 100644 --- a/components/brave_new_tab_ui/components/default/index.ts +++ b/components/brave_new_tab_ui/components/default/index.ts @@ -9,6 +9,7 @@ import { SettingsMenu, SettingsRow, SettingsText, SettingsTitle, SettingsWrapper import { ListWidget, Tile, TileActionsContainer, TileAction, TileFavicon } from './topSites' import { SiteRemovalNotification, SiteRemovalText, SiteRemovalAction } from './notification' import { ClockWidget } from './clock' +import { RewardsWidget } from './rewards' import createWidget from './widget' export * from './page' @@ -33,5 +34,6 @@ export { SettingsText, SettingsTitle, SettingsWrapper, + RewardsWidget, createWidget } diff --git a/components/brave_new_tab_ui/components/default/rewards/index.tsx b/components/brave_new_tab_ui/components/default/rewards/index.tsx new file mode 100644 index 0000000000000..f86a07ad44e57 --- /dev/null +++ b/components/brave_new_tab_ui/components/default/rewards/index.tsx @@ -0,0 +1,269 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import createWidget from '../widget/index' +import { convertBalance } from '../../../../brave_rewards/resources/page/utils' +import { getLocale } from '../../../../common/locale' + +import { + WidgetWrapper, + BatIcon, + RewardsTitle, + Footer, + ServiceText, + ServiceLink, + LearnMoreText, + PreOptInInfo, + Title, + SubTitle, + PreOptInAction, + TurnOnButton, + AmountItem, + AmountInformation, + AmountDescription, + Amount, + ConvertedAmount, + LearnMoreLink, + TurnOnAdsButton +} from './style' +import Notification from './notification' +import { BatColorIcon } from 'brave-ui/components/icons' + +export interface RewardsProps { + enabledAds: boolean + enabledMain: boolean + balance: NewTab.RewardsBalance + grants: NewTab.GrantRecord[] + totalContribution: string + walletCreated: boolean + walletCreating: boolean + walletCreateFailed: boolean + walletCorrupted: boolean + adsEstimatedEarnings: number + onlyAnonWallet?: boolean + onCreateWallet: () => void + onEnableAds: () => void + onEnableRewards: () => void + onDismissNotification: (id: string) => void +} + +const enum AmountItemType { + ADS = 0, + TIPS = 1 +} + +class Rewards extends React.PureComponent { + + getButtonText = (isAds: boolean = false) => { + if (isAds) { + return getLocale('rewardsWidgetTurnOnAds') + } + + const { + walletCreating, + walletCreateFailed, + walletCorrupted + } = this.props + + if (walletCreateFailed || walletCorrupted) { + return getLocale('rewardsWidgetWalletFailedButton') + } + + if (walletCreating) { + return getLocale('rewardsWidgetTurningOn') + } + + return getLocale('rewardsWidgetTurnOnRewards') + } + + optInAction = (hasEnabled: boolean) => { + if (hasEnabled) { + this.props.onEnableRewards() + } else { + this.props.onCreateWallet() + } + } + + renderPreOptIn = () => { + const { + enabledMain, + walletCreated + } = this.props + + if (enabledMain && walletCreated) { + return null + } + + const hasEnabled = !enabledMain && walletCreated + + return ( + <> + + + { + hasEnabled + ? getLocale('rewardsWidgetReEnableTitle') + : getLocale('rewardsWidgetEnableTitle') + } + + + { + hasEnabled + ? getLocale('rewardsWidgetReEnableSubTitle') + : getLocale('rewardsWidgetEnableSubTitle') + } + + + + + {this.getButtonText()} + + + + ) + } + + renderAmountItem = (type: AmountItemType) => { + const { + balance, + enabledAds, + onEnableAds, + adsEstimatedEarnings, + onlyAnonWallet, + totalContribution + } = this.props + + const rates = balance.rates || {} + const showEnableAds = type === AmountItemType.ADS && !enabledAds + const amount = type === AmountItemType.TIPS + ? totalContribution + : adsEstimatedEarnings.toFixed(1) + const converted = convertBalance(amount, rates) + const batFormatString = onlyAnonWallet ? getLocale('rewardsWidgetBatPoints') : getLocale('rewardsWidgetBat') + + return ( + + { + showEnableAds + ? + {this.getButtonText(true)} + + : null + } + { + !showEnableAds + ? + {amount} + + {`${batFormatString} ${converted} USD`} + + + : null + } + + { + type === AmountItemType.ADS + ? getLocale('rewardsWidgetEstimatedEarnings') + : getLocale('rewardsWidgetMonthlyTips') + } + + + ) + } + + renderRewardsInfo = () => { + const { + enabledMain, + walletCreated + } = this.props + + if (!enabledMain || !walletCreated) { + return null + } + + return ( +
+ {this.renderAmountItem(AmountItemType.ADS)} + {this.renderAmountItem(AmountItemType.TIPS)} +
+ ) + } + + renderLearnMore = () => { + return ( + + + {getLocale('learnMore')} + + {getLocale('rewardsWidgetAboutRewards')} + + ) + } + + renderPrivacyPolicy = () => { + return ( + <> + + {getLocale('rewardsWidgetServiceText')} {getLocale('rewardsWidgetTermsOfService')} {getLocale('rewardsWidgetAnd')} {getLocale('rewardsWidgetPrivacyPolicy')}. + + + ) + } + + renderNotifications = () => { + const { grants, onDismissNotification } = this.props + + return ( + <> + {grants.map((grant: NewTab.GrantRecord, index) => { + return ( + + ) + })} + + ) + } + + render () { + const { + enabledMain, + walletCreated + } = this.props + + return ( + + + + + + {getLocale('rewardsWidgetBraveRewards')} + + {this.renderPreOptIn()} + {this.renderRewardsInfo()} +
+ { + enabledMain && walletCreated + ? this.renderLearnMore() + : this.renderPrivacyPolicy() + } +
+ { + enabledMain + ? this.renderNotifications() + : null + } +
+ ) + } +} + +export const RewardsWidget = createWidget(Rewards) diff --git a/components/brave_new_tab_ui/components/default/rewards/notification.tsx b/components/brave_new_tab_ui/components/default/rewards/notification.tsx new file mode 100644 index 0000000000000..975afaa9699b6 --- /dev/null +++ b/components/brave_new_tab_ui/components/default/rewards/notification.tsx @@ -0,0 +1,58 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +import { + Title, + SubTitle, + CloseIcon, + Content, + NotificationWrapper, + NotificationButton +} from './style' +import { CloseStrokeIcon } from 'brave-ui/components/icons' +import { getLocale } from '../../../../common/locale' + +interface NotificationProps { + grant: NewTab.GrantRecord + onDismissNotification: (id: string) => void +} + +export default class RewardsNotification extends React.PureComponent { + + dismissNotification = () => { + this.props.onDismissNotification(this.props.grant.promotionId) + } + + onNotificationAction = () => { + this.dismissNotification() + chrome.braveRewards.openBrowserActionUI(`brave_rewards_panel.html#grant_${this.props.grant.promotionId}`) + } + + render () { + return ( + + + + + + + {getLocale('rewardsWidgetNotificationTitle')} + + + { + this.props.grant.type === 'ads' + ? getLocale('rewardsWidgetNotificationTextAds') + : getLocale('rewardsWidgetNotificationTextUGP') + } + + + {getLocale('rewardsWidgetClaimMyRewards')} + + + + ) + } +} diff --git a/components/brave_new_tab_ui/components/default/rewards/style.ts b/components/brave_new_tab_ui/components/default/rewards/style.ts new file mode 100644 index 0000000000000..c96a0efa1de0f --- /dev/null +++ b/components/brave_new_tab_ui/components/default/rewards/style.ts @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import styled from 'styled-components' +import palette from 'brave-ui/theme/colors' + +export const WidgetWrapper = styled<{}, 'div'>('div')` + color: white; + padding: 10px 15px; + border-radius: 6px; + position: relative; + font-family: Muli, sans-serif; + overflow-x: hidden; + background-image: linear-gradient(140deg, #392DD1 0%, #8E2995 100%); +` + +export const Footer = styled<{}, 'div'>('div')` + max-width: 275px; + margin-top: 10px; +` + +export const BatIcon = styled<{}, 'div'>('div')` + width: 30px; + height: 30px; + display: inline-block; +` + +export const RewardsTitle = styled<{}, 'span'>('span')` + top: -9px; + left: 8px; + font-size: 14px; + font-weight: 500; + position: relative; + font-family: Poppins, sans-serif; +` + +export const ServiceText = styled<{}, 'span'>('span')` + color: #fff; + font-size: 10px; + letter-spacing: 0; + line-height: 18px; +` + +export const ServiceLink = styled<{}, 'a'>('a')` + color: ${palette.blue500}; + font-weight: 600; + text-decoration: none; +` + +export const LearnMoreLink = styled(ServiceLink)` + margin-right: 5px; +` + +export const LearnMoreText = styled<{}, 'div'>('div')` + font-size: 14px; + margin-top: 50px; +` + +export const PreOptInInfo = styled<{}, 'div'>('div')` + margin-top: 20px; +` + +export const Title = styled<{}, 'span'>('span')` + font-size: 19px; + display: block; + font-family: Poppins, sans-serif; +` + +export const SubTitle = styled<{}, 'span'>('span')` + font-size: 14px; + display: block; + margin-top: 10px; + max-width: 250px; +` + +export const PreOptInAction = styled<{}, 'div'>('div')` + margin-top: 30px; + text-align: center +` + +export const TurnOnButton = styled<{}, 'button'>('button')` + border-radius: 20px; + background: white; + color: ${palette.blurple500}; + font-weight: bold; + font-size: 14px; + padding: 7px 60px; + margin: 0 auto; + cursor: pointer; +` + +export const TurnOnAdsButton = styled(TurnOnButton)` + width: 100%; + margin-bottom: 5px; + display: block; +` + +export const AmountItem = styled<{}, 'div'>('div')` + margin-top: 10px; +` + +export const AmountInformation = styled<{}, 'div'>('div')` + margin-bottom: 5px; +` + +export const Amount = styled<{}, 'span'>('span')` + font-size: 32px; + margin-right: 10px; + font-family: Poppins, sans-serif; +` + +export const ConvertedAmount = styled<{}, 'span'>('span')` + font-size: 14px; +` + +export const AmountDescription = styled<{}, 'span'>('span')` + font-size: 14px; + color: rgb(128, 158, 255); +` + +export const NotificationWrapper = styled(WidgetWrapper)` + position: absolute; + bottom: 0; + left: 0; + width: 100%; + box-shadow: 5px 10px 8px 10px #000; +` + +export const NotificationButton = styled(TurnOnButton)` + background: ${palette.green500}; + color: #fff; + border: none; + font-weight: bold; + padding-top: 10px; + padding-bottom: 10px; + margin-top: 50px; + font-size: 12px; +` + +export const Content = styled<{}, 'div'>('div')` + margin-top: 30px; +` + +export const CloseIcon = styled<{}, 'div'>('div')` + color: #fff; + width: 20px; + height: 20px; + float: right; + cursor: pointer; +` diff --git a/components/brave_new_tab_ui/constants/new_tab_types.ts b/components/brave_new_tab_ui/constants/new_tab_types.ts index 34d73066b6170..aec0519ba47b9 100644 --- a/components/brave_new_tab_ui/constants/new_tab_types.ts +++ b/components/brave_new_tab_ui/constants/new_tab_types.ts @@ -19,5 +19,19 @@ export const enum types { NEW_TAB_STATS_UPDATED = '@@newtab/NEW_TAB_STATS_UPDATED', NEW_TAB_PRIVATE_TAB_DATA_UPDATED = '@@newtab/NEW_TAB_PRIVATE_TAB_DATA_UPDATED', NEW_TAB_PREFERENCES_UPDATED = '@@newtab/NEW_TAB_PREFERENCES_UPDATED', - NEW_TAB_SET_INITIAL_DATA = '@@newtab/NEW_TAB_SET_INITIAL_DATA' + NEW_TAB_SET_INITIAL_DATA = '@@newtab/NEW_TAB_SET_INITIAL_DATA', + // Rewards Widget + CREATE_WALLET = '@@newtab/CREATE_WALLET', + DISMISS_NOTIFICATION = '@@newtab/DISMISS_NOTIFICATION', + ON_ADS_ENABLED = '@@newtab/ON_ADS_ENABLED', + ON_ADS_ESTIMATED_EARNINGS = '@@newtab/ON_ADS_ESTIMATED_EARNINGS', + ON_ENABLED_MAIN = '@@newtab/ON_ENABLED_MAIN', + ON_REWARDS_SETTING_SAVE = '@@newtab_panel/ON_SETTING_SAVE', + ON_WALLET_INITIALIZED = '@@newtab/ON_WALLET_INITIALIZED', + ON_BALANCE_REPORTS = '@@newtab/ON_BALANCE_REPORTS', + ON_GRANT = '@@newtab/ON_GRANT', + ON_BALANCE = '@@newtab/ON_BALANCE', + ON_WALLET_EXISTS = '@@newtab/ON_WALLET_EXISTS', + SET_INITIAL_REWARDS_DATA = '@@newtab/SET_INITIAL_REWARDS_DATA', + SET_PRE_INITIAL_REWARDS_DATA = '@@newtab/SET_PRE_INITIAL_REWARDS_DATA' } diff --git a/components/brave_new_tab_ui/containers/app.tsx b/components/brave_new_tab_ui/containers/app.tsx index a9255855f2df4..dd00465968a60 100644 --- a/components/brave_new_tab_ui/containers/app.tsx +++ b/components/brave_new_tab_ui/containers/app.tsx @@ -39,6 +39,7 @@ class DefaultPage extends React.Component { saveShowClock={PreferencesAPI.saveShowClock} saveShowStats={PreferencesAPI.saveShowStats} saveShowTopSites={PreferencesAPI.saveShowTopSites} + saveShowRewards={PreferencesAPI.saveShowRewards} /> ) } diff --git a/components/brave_new_tab_ui/containers/newTab/footerInfo.tsx b/components/brave_new_tab_ui/containers/newTab/footerInfo.tsx index a620804ae6d80..3d45d9ef60272 100644 --- a/components/brave_new_tab_ui/containers/newTab/footerInfo.tsx +++ b/components/brave_new_tab_ui/containers/newTab/footerInfo.tsx @@ -25,10 +25,12 @@ interface Props { toggleShowClock: () => void toggleShowStats: () => void toggleShowTopSites: () => void + toggleShowRewards: () => void showBackgroundImage: boolean showClock: boolean showStats: boolean showTopSites: boolean + showRewards: boolean } export default class FooterInfo extends React.PureComponent { @@ -48,7 +50,9 @@ export default class FooterInfo extends React.PureComponent { showBackgroundImage, showClock, showStats, - showTopSites + showTopSites, + toggleShowRewards, + showRewards } = this.props return ( @@ -76,6 +80,8 @@ export default class FooterInfo extends React.PureComponent { showClock={showClock} showStats={showStats} showTopSites={showTopSites} + toggleShowRewards={toggleShowRewards} + showRewards={showRewards} /> diff --git a/components/brave_new_tab_ui/containers/newTab/index.tsx b/components/brave_new_tab_ui/containers/newTab/index.tsx index 4f78d19f94e25..f8b2cd478b750 100644 --- a/components/brave_new_tab_ui/containers/newTab/index.tsx +++ b/components/brave_new_tab_ui/containers/newTab/index.tsx @@ -13,7 +13,8 @@ import { Footer, App, PosterBackground, - Gradient + Gradient, + RewardsWidget as Rewards } from '../../components/default' // Components @@ -29,15 +30,18 @@ interface Props { saveShowClock: (value: boolean) => void saveShowTopSites: (value: boolean) => void saveShowStats: (value: boolean) => void + saveShowRewards: (value: boolean) => void } interface State { + onlyAnonWallet: boolean showSettingsMenu: boolean backgroundHasLoaded: boolean } class NewTabPage extends React.Component { state = { + onlyAnonWallet: false, showSettingsMenu: false, backgroundHasLoaded: false } @@ -128,6 +132,28 @@ class NewTabPage extends React.Component { ) } + toggleShowRewards = () => { + this.props.saveShowRewards( + !this.props.newTabData.showRewards + ) + } + + enableAds = () => { + chrome.braveRewards.saveAdsSetting('adsEnabled', 'true') + } + + enableRewards = () => { + this.props.actions.onRewardsSettingSave('enabledMain', '1') + } + + createWallet = () => { + this.props.actions.createWallet() + } + + dismissNotification = (id: string) => { + this.props.actions.dismissNotification(id) + } + closeSettings = () => { this.setState({ showSettingsMenu: false }) } @@ -139,6 +165,7 @@ class NewTabPage extends React.Component { render () { const { newTabData, actions } = this.props const { showSettingsMenu } = this.state + const { rewardsState } = newTabData if (!newTabData) { return null @@ -174,6 +201,17 @@ class NewTabPage extends React.Component { hideWidget={this.toggleShowClock} menuPosition={'left'} /> + {this.props.newTabData.gridSites.length ? { showClock={newTabData.showClock} showStats={newTabData.showStats} showTopSites={newTabData.showTopSites} + showRewards={newTabData.showRewards} + toggleShowRewards={this.toggleShowRewards} /> diff --git a/components/brave_new_tab_ui/containers/newTab/settings.tsx b/components/brave_new_tab_ui/containers/newTab/settings.tsx index 812a5902e3467..f5298420ded4d 100644 --- a/components/brave_new_tab_ui/containers/newTab/settings.tsx +++ b/components/brave_new_tab_ui/containers/newTab/settings.tsx @@ -20,10 +20,12 @@ export interface Props { toggleShowClock: () => void toggleShowStats: () => void toggleShowTopSites: () => void + toggleShowRewards: () => void showBackgroundImage: boolean showStats: boolean showClock: boolean showTopSites: boolean + showRewards: boolean } export default class Settings extends React.PureComponent { @@ -61,10 +63,12 @@ export default class Settings extends React.PureComponent { toggleShowClock, toggleShowStats, toggleShowTopSites, + toggleShowRewards, showBackgroundImage, showStats, showClock, showTopSites, + showRewards, onClick } = this.props return ( @@ -105,6 +109,14 @@ export default class Settings extends React.PureComponent { size='small' /> + + {getLocale('showRewards')} + + } diff --git a/components/brave_new_tab_ui/reducers/new_tab_reducer.tsx b/components/brave_new_tab_ui/reducers/new_tab_reducer.tsx index f28bcdbc7fb4f..0fdead5bc76cc 100644 --- a/components/brave_new_tab_ui/reducers/new_tab_reducer.tsx +++ b/components/brave_new_tab_ui/reducers/new_tab_reducer.tsx @@ -13,10 +13,11 @@ import { PrivateTabData } from '../api/privateTabData' // API import * as backgroundAPI from '../api/background' import * as gridAPI from '../api/topSites/grid' -import { InitialData } from '../api/initialData' +import { InitialData, InitialRewardsData, PreInitialRewardsData } from '../api/initialData' import * as bookmarksAPI from '../api/topSites/bookmarks' import * as dndAPI from '../api/topSites/dnd' import * as storage from '../storage' +import { getTotalContributions } from '../rewards-utils' const initialState = storage.load() @@ -246,6 +247,158 @@ export const newTabReducer: Reducer = (state: NewTab.S } break + case types.CREATE_WALLET: + chrome.braveRewards.createWallet() + state = { ...state } + state.rewardsState.walletCreating = true + break + + case types.ON_ENABLED_MAIN: + state = { ...state } + state.rewardsState.enabledMain = payload.enabledMain + break + + case types.ON_WALLET_INITIALIZED: { + const result: NewTab.RewardsResult = payload.result + state = { ...state } + + switch (result) { + case NewTab.RewardsResult.WALLET_CORRUPT: + state.rewardsState.walletCorrupted = true + break + case NewTab.RewardsResult.WALLET_CREATED: + state.rewardsState.walletCreated = true + state.rewardsState.walletCreateFailed = false + state.rewardsState.walletCreating = false + state.rewardsState.walletCorrupted = false + chrome.braveRewards.saveAdsSetting('adsEnabled', 'true') + break + case NewTab.RewardsResult.LEDGER_OK: + state.rewardsState.walletCreateFailed = true + state.rewardsState.walletCreating = false + state.rewardsState.walletCreated = false + state.rewardsState.walletCorrupted = false + break + } + break + } + + case types.ON_REWARDS_SETTING_SAVE: + const key = action.payload.key + const value = action.payload.value + + if (key) { + state = { ...state } + state.rewardsState[key] = !!value + chrome.braveRewards.saveSetting(key, value) + } + break + + case types.ON_ADS_ENABLED: + state = { ...state } + state.rewardsState.enabledAds = payload.enabled + break + + case types.ON_ADS_ESTIMATED_EARNINGS: + state = { ...state } + state.rewardsState.adsEstimatedEarnings = payload.amount + break + + case types.ON_BALANCE_REPORTS: + state = { ...state } + const reports = payload.reports || {} + state.rewardsState.totalContribution = getTotalContributions(reports) + break + + case types.DISMISS_NOTIFICATION: + state = { ...state } + + const dismissedNotifications = state.rewardsState.dismissedNotifications + dismissedNotifications.push(payload.id) + state.rewardsState.dismissedNotifications = dismissedNotifications + + state.rewardsState.grants = state.rewardsState.grants.filter((grant) => { + return grant.promotionId !== payload.id + }) + break + + case types.ON_GRANT: + if (action.payload.properties.status === 1) { + break + } + + const promotionId = payload.properties.promotionId + if (!promotionId) { + break + } + + state = { ...state } + + if (!state.rewardsState.dismissedNotifications) { + state.rewardsState.dismissedNotifications = [] + } + + if (state.rewardsState.dismissedNotifications.indexOf(promotionId) > -1) { + break + } + + const hasGrant = state.rewardsState.grants.find((grant: NewTab.GrantRecord) => { + return grant.promotionId === promotionId + }) + if (hasGrant) { + break + } + + const updatedGrants = state.rewardsState.grants + updatedGrants.push({ + promotionId: promotionId, + type: payload.properties.type + }) + + state.rewardsState.grants = updatedGrants + break + + case types.ON_BALANCE: + state = { ...state } + state.rewardsState.balance = payload.balance + break + + case types.ON_WALLET_EXISTS: + if (!payload.exists || state.rewardsState.walletCreated) { + break + } + state.rewardsState.walletCreated = true + break + + case types.SET_PRE_INITIAL_REWARDS_DATA: + const preInitialRewardsDataPayload = payload as PreInitialRewardsData + state = { + ...state, + rewardsState: { + ...state.rewardsState, + enabledAds: preInitialRewardsDataPayload.enabledAds, + enabledMain: preInitialRewardsDataPayload.enabledMain + } + } + break + + case types.SET_INITIAL_REWARDS_DATA: + const initialRewardsDataPayload = payload as InitialRewardsData + const newRewardsState = { + onlyAnonWallet: initialRewardsDataPayload.onlyAnonWallet, + balance: initialRewardsDataPayload.balance, + totalContribution: getTotalContributions(initialRewardsDataPayload.reports) + } + + state = { + ...state, + rewardsState: { + ...state.rewardsState, + ...newRewardsState + } + } + break + default: break } diff --git a/components/brave_new_tab_ui/rewards-utils.ts b/components/brave_new_tab_ui/rewards-utils.ts new file mode 100644 index 0000000000000..109e57323c368 --- /dev/null +++ b/components/brave_new_tab_ui/rewards-utils.ts @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { tipsTotal } from '../brave_rewards/resources/page/utils' + +export const getTotalContributions = (reports: Record) => { + const currentTime = new Date() + const year = currentTime.getFullYear() + const month = (currentTime.getMonth() + 1) + const report: NewTab.RewardsReport = reports[`${year}_${month}`] + + if (!report) { + return '0.0' + } + + return tipsTotal(report) +} diff --git a/components/brave_new_tab_ui/storage.ts b/components/brave_new_tab_ui/storage.ts index 1d1abb9a609fa..c24a8002d5a1a 100644 --- a/components/brave_new_tab_ui/storage.ts +++ b/components/brave_new_tab_ui/storage.ts @@ -14,6 +14,7 @@ const defaultState: NewTab.State = { showStats: false, showClock: false, showTopSites: false, + showRewards: false, topSites: [], ignoredTopSites: [], pinnedTopSites: [], @@ -29,6 +30,24 @@ const defaultState: NewTab.State = { javascriptBlockedStat: 0, httpsUpgradesStat: 0, fingerprintingBlockedStat: 0 + }, + rewardsState: { + adsEstimatedEarnings: 0, + balance: { + total: 0, + rates: {}, + wallets: {} + }, + dismissedNotifications: [], + enabledAds: false, + enabledMain: false, + grants: [], + onlyAnonWallet: false, + totalContribution: '0.0', + walletCreated: false, + walletCreating: false, + walletCreateFailed: false, + walletCorrupted: false } } @@ -46,7 +65,8 @@ const getPersistentData = (state: NewTab.State): NewTab.PersistentState => { pinnedTopSites: state.pinnedTopSites, gridSites: state.gridSites, showEmptyPage: state.showEmptyPage, - bookmarks: state.bookmarks + bookmarks: state.bookmarks, + rewardsState: state.rewardsState } return peristantState diff --git a/components/brave_new_tab_ui/stories/default/footerInfo.tsx b/components/brave_new_tab_ui/stories/default/footerInfo.tsx index 7fac03da21de9..823813fd2c952 100644 --- a/components/brave_new_tab_ui/stories/default/footerInfo.tsx +++ b/components/brave_new_tab_ui/stories/default/footerInfo.tsx @@ -25,10 +25,12 @@ interface Props { toggleShowClock: () => void toggleShowStats: () => void toggleShowTopSites: () => void + toggleShowRewards: () => void showBackgroundImage: boolean showClock: boolean showStats: boolean showTopSites: boolean + showRewards: boolean } export default class FooterInfo extends React.PureComponent { @@ -45,10 +47,12 @@ export default class FooterInfo extends React.PureComponent { toggleShowClock, toggleShowStats, toggleShowTopSites, + toggleShowRewards, showBackgroundImage, showClock, showStats, - showTopSites + showTopSites, + showRewards } = this.props return ( @@ -72,10 +76,12 @@ export default class FooterInfo extends React.PureComponent { toggleShowClock={toggleShowClock} toggleShowStats={toggleShowStats} toggleShowTopSites={toggleShowTopSites} + toggleShowRewards={toggleShowRewards} showBackgroundImage={showBackgroundImage} showClock={showClock} showStats={showStats} showTopSites={showTopSites} + showRewards={showRewards} /> diff --git a/components/brave_new_tab_ui/stories/default/index.tsx b/components/brave_new_tab_ui/stories/default/index.tsx index 8443bf58be187..9aa1e1783bb64 100644 --- a/components/brave_new_tab_ui/stories/default/index.tsx +++ b/components/brave_new_tab_ui/stories/default/index.tsx @@ -5,7 +5,7 @@ import * as React from 'react' // Feature-specific components -import { Page, Header, Footer, App, PosterBackground, Gradient, ClockWidget as Clock } from '../../components/default' +import { Page, Header, Footer, App, PosterBackground, Gradient, ClockWidget as Clock, RewardsWidget as Rewards } from '../../components/default' import TopSitesList from './topSites/topSitesList' import Stats from './stats' @@ -23,6 +23,17 @@ interface State { showStats: boolean showClock: boolean showTopSites: boolean + showRewards: boolean + adsEstimatedEarnings: number + balance: NewTab.RewardsBalance + grants: NewTab.GrantRecord[] + enabledAds: boolean + enabledMain: boolean + totalContribution: string + walletCreated: boolean + walletCreating: boolean + walletCreateFailed: boolean + walletCorrupted: boolean } interface Props { @@ -37,10 +48,29 @@ export default class NewTabPage extends React.PureComponent { showBackgroundImage: true, showStats: true, showClock: true, - showTopSites: true + showTopSites: true, + showRewards: true, + adsEstimatedEarnings: 5, + enabledAds: false, + enabledMain: false, + grants: [], + balance: { + total: 0, + rates: {}, + wallets: {} + }, + totalContribution: '0.0', + walletCreated: false, + walletCreating: false, + walletCreateFailed: false, + walletCorrupted: false } } + doNothing = (s: string) => { + /* no-op */ + } + toggleShowBackgroundImage = () => { this.setState({ showBackgroundImage: !this.state.showBackgroundImage }) } @@ -57,6 +87,10 @@ export default class NewTabPage extends React.PureComponent { this.setState({ showTopSites: !this.state.showTopSites }) } + toggleShowRewards = () => { + this.setState({ showRewards: !this.state.showRewards }) + } + closeSettings = () => { this.setState({ showSettingsMenu: false }) } @@ -65,9 +99,39 @@ export default class NewTabPage extends React.PureComponent { this.setState({ showSettingsMenu: !this.state.showSettingsMenu }) } + enableAds = () => { + this.setState({ enabledAds: true }) + } + + enableRewards = () => { + this.setState({ enabledMain: true }) + } + + createWallet = () => { + this.setState({ walletCreating: true }) + setTimeout(() => { + this.setState({ walletCreated: true }) + this.enableAds() + this.enableRewards() + }, 1000) + } + render () { - const { showSettingsMenu, showBackgroundImage, showClock, showStats, showTopSites } = this.state + const { showSettingsMenu, showBackgroundImage, showClock, showStats, showTopSites, showRewards } = this.state + const { + enabledAds, + enabledMain, + adsEstimatedEarnings, + walletCorrupted, + walletCreateFailed, + walletCreated, + walletCreating, + grants, + balance, + totalContribution + } = this.state const { textDirection } = this.props + return ( @@ -94,6 +158,26 @@ export default class NewTabPage extends React.PureComponent { menuPosition={'right'} hideWidget={this.toggleShowTopSites} /> +
@@ -108,10 +192,12 @@ export default class NewTabPage extends React.PureComponent { toggleShowClock={this.toggleShowClock} toggleShowStats={this.toggleShowStats} toggleShowTopSites={this.toggleShowTopSites} + toggleShowRewards={this.toggleShowRewards} showBackgroundImage={showBackgroundImage} showClock={showClock} showStats={showStats} showTopSites={showTopSites} + showRewards={showRewards} />
diff --git a/components/brave_new_tab_ui/stories/default/settings.tsx b/components/brave_new_tab_ui/stories/default/settings.tsx index a785a902f2817..71dbb404b1152 100644 --- a/components/brave_new_tab_ui/stories/default/settings.tsx +++ b/components/brave_new_tab_ui/stories/default/settings.tsx @@ -20,10 +20,12 @@ interface Props { toggleShowClock: () => void toggleShowStats: () => void toggleShowTopSites: () => void + toggleShowRewards: () => void showBackgroundImage: boolean showStats: boolean showClock: boolean showTopSites: boolean + showRewards: boolean } export default class Settings extends React.PureComponent { @@ -61,10 +63,12 @@ export default class Settings extends React.PureComponent { toggleShowClock, toggleShowStats, toggleShowTopSites, + toggleShowRewards, showBackgroundImage, showStats, showClock, showTopSites, + showRewards, onClick } = this.props return ( @@ -105,6 +109,14 @@ export default class Settings extends React.PureComponent { size='small' /> + + {getLocale('showRewards')} + + } diff --git a/components/brave_new_tab_ui/stories/fakeLocale.ts b/components/brave_new_tab_ui/stories/fakeLocale.ts index d38beffeaa437..49206e2f7d5a6 100644 --- a/components/brave_new_tab_ui/stories/fakeLocale.ts +++ b/components/brave_new_tab_ui/stories/fakeLocale.ts @@ -20,7 +20,8 @@ const locale: any = { showBackgroundImg: 'Show background image', showBraveStats: 'Show Brave Stats', showClock: 'Show Clock', - showTopSites: 'Show Top Sites' + showTopSites: 'Show Top Sites', + showRewards: 'Show Rewards' } export default locale diff --git a/components/brave_rewards/browser/extension_rewards_service_observer.cc b/components/brave_rewards/browser/extension_rewards_service_observer.cc index fa543e6f6aee1..f62378a9e351b 100644 --- a/components/brave_rewards/browser/extension_rewards_service_observer.cc +++ b/components/brave_rewards/browser/extension_rewards_service_observer.cc @@ -222,6 +222,24 @@ void ExtensionRewardsServiceObserver::OnGrantFinish( event_router->BroadcastEvent(std::move(event)); } +void ExtensionRewardsServiceObserver::OnAdsEnabled( + RewardsService* rewards_service, + bool ads_enabled) { + auto* event_router = extensions::EventRouter::Get(profile_); + if (!event_router) { + return; + } + + std::unique_ptr args( + extensions::api::brave_rewards::OnAdsEnabled::Create( + ads_enabled).release()); + std::unique_ptr event(new extensions::Event( + extensions::events::BRAVE_START, + extensions::api::brave_rewards::OnAdsEnabled::kEventName, + std::move(args))); + event_router->BroadcastEvent(std::move(event)); +} + void ExtensionRewardsServiceObserver::OnRewardsMainEnabled( RewardsService* rewards_service, bool rewards_main_enabled) { diff --git a/components/brave_rewards/browser/extension_rewards_service_observer.h b/components/brave_rewards/browser/extension_rewards_service_observer.h index 1e9e51ced7ac7..70193b5f4991a 100644 --- a/components/brave_rewards/browser/extension_rewards_service_observer.h +++ b/components/brave_rewards/browser/extension_rewards_service_observer.h @@ -83,6 +83,9 @@ class ExtensionRewardsServiceObserver : public RewardsServiceObserver, void OnPendingContributionSaved(RewardsService* rewards_service, int result) override; + void OnAdsEnabled(RewardsService* rewards_service, + bool ads_enabled) override; + private: Profile* profile_; diff --git a/components/brave_rewards/browser/rewards_service.h b/components/brave_rewards/browser/rewards_service.h index 87aaaa249cfac..7b3111befb4c7 100644 --- a/components/brave_rewards/browser/rewards_service.h +++ b/components/brave_rewards/browser/rewards_service.h @@ -214,6 +214,7 @@ class RewardsService : public KeyedService { RewardsServicePrivateObserver* observer) = 0; virtual void GetTransactionHistory( GetTransactionHistoryCallback callback) = 0; + virtual void TriggerOnAdsEnabled(bool ads_enabled) = 0; virtual void RefreshPublisher( const std::string& publisher_key, diff --git a/components/brave_rewards/browser/rewards_service_browsertest.cc b/components/brave_rewards/browser/rewards_service_browsertest.cc index e1830d9b87e6e..2bef25a4118c7 100644 --- a/components/brave_rewards/browser/rewards_service_browsertest.cc +++ b/components/brave_rewards/browser/rewards_service_browsertest.cc @@ -846,6 +846,11 @@ class BraveRewardsBrowserTest return rewards_url; } + GURL new_tab_url() { + GURL new_tab_url("brave://newtab"); + return new_tab_url; + } + GURL uphold_auth_url() { GURL url("chrome://rewards/uphold/authorization?" "code=0c42b34121f624593ee3b04cbe4cc6ddcd72d&state=123456789"); @@ -856,9 +861,10 @@ class BraveRewardsBrowserTest return browser()->tab_strip_model()->GetActiveWebContents(); } - void EnableRewards() { + void EnableRewards(bool use_new_tab = false) { // Load rewards page - ui_test_utils::NavigateToURL(browser(), rewards_url()); + GURL page_url = use_new_tab ? new_tab_url() : rewards_url(); + ui_test_utils::NavigateToURL(browser(), page_url); WaitForLoadStop(contents()); // Opt in and create wallet to enable rewards ASSERT_TRUE(ExecJs(contents(), @@ -2959,6 +2965,12 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, EXPECT_FALSE(is_showing_notification); } +IN_PROC_BROWSER_TEST_F( + BraveRewardsBrowserTest, + NewTabPageWidgetEnableRewards) { + EnableRewards(true); +} + struct BraveAdsUpgradePathParamInfo { // |preferences| should be set to the name of the preferences filename located // at "src/brave/test/data/rewards-data/migration" diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index 876de7014011c..b4983074bd517 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -2080,6 +2080,12 @@ void RewardsServiceImpl::SetAutoContribute(bool enabled) { } } +void RewardsServiceImpl::TriggerOnAdsEnabled( + bool ads_enabled) { + for (auto& observer : observers_) + observer.OnAdsEnabled(this, ads_enabled); +} + void RewardsServiceImpl::TriggerOnRewardsMainEnabled( bool rewards_main_enabled) { for (auto& observer : observers_) diff --git a/components/brave_rewards/browser/rewards_service_impl.h b/components/brave_rewards/browser/rewards_service_impl.h index 8486773f90529..b505def750e06 100644 --- a/components/brave_rewards/browser/rewards_service_impl.h +++ b/components/brave_rewards/browser/rewards_service_impl.h @@ -216,6 +216,7 @@ class RewardsServiceImpl : public RewardsService, void RefreshPublisher( const std::string& publisher_key, RefreshPublisherCallback callback) override; + void TriggerOnAdsEnabled(bool ads_enabled) override; void OnSaveRecurringTipUI( SaveRecurringTipCallback callback, diff --git a/components/brave_rewards/browser/rewards_service_impl_unittest.cc b/components/brave_rewards/browser/rewards_service_impl_unittest.cc index 1e327565efd12..88c6994eac9eb 100644 --- a/components/brave_rewards/browser/rewards_service_impl_unittest.cc +++ b/components/brave_rewards/browser/rewards_service_impl_unittest.cc @@ -51,6 +51,7 @@ class MockRewardsServiceObserver : public RewardsServiceObserver { void(RewardsService*, const brave_rewards::PublisherBanner)); MOCK_METHOD4(OnPanelPublisherInfo, void(RewardsService*, int, ledger::PublisherInfoPtr, uint64_t)); + MOCK_METHOD2(OnAdsEnabled, void(RewardsService*, bool)); }; class RewardsServiceTest : public testing::Test { diff --git a/components/brave_rewards/browser/rewards_service_observer.h b/components/brave_rewards/browser/rewards_service_observer.h index 88f79ac82806c..9c76308679bc7 100644 --- a/components/brave_rewards/browser/rewards_service_observer.h +++ b/components/brave_rewards/browser/rewards_service_observer.h @@ -61,6 +61,9 @@ class RewardsServiceObserver : public base::CheckedObserver { const std::string& viewing_id, const std::string& probi, const int32_t type) {} + virtual void OnAdsEnabled( + brave_rewards::RewardsService* rewards_service, + bool ads_enabled) {} virtual void OnRewardsMainEnabled( brave_rewards::RewardsService* rewards_service, bool rewards_main_enabled) {} 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 9f0b7b3affe97..a421fe3159b82 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx +++ b/components/brave_rewards/resources/extension/brave_rewards/components/app.tsx @@ -66,6 +66,8 @@ export class RewardsPanel extends React.Component { const { externalWallet } = this.props.rewardsPanelData utils.getExternalWallet(this.actions, externalWallet) } + + this.handleGrantNotification() } componentDidUpdate (prevProps: Props, prevState: State) { @@ -80,6 +82,20 @@ export class RewardsPanel extends React.Component { } } + handleGrantNotification = () => { + const hash = window && window.location && window.location.hash + + if (!hash) { + return + } + + if (!hash.startsWith('#grant_')) { + return + } + + this.actions.getGrantCaptcha(hash.split('#grant_')[1]) + } + goToUphold = () => { const { externalWallet } = this.props.rewardsPanelData diff --git a/components/definitions/chromel.d.ts b/components/definitions/chromel.d.ts index 8d3ed845ba205..1013f54f8f202 100644 --- a/components/definitions/chromel.d.ts +++ b/components/definitions/chromel.d.ts @@ -94,10 +94,17 @@ declare namespace chrome.braveRewards { const solveGrantCaptcha: (solution: string, promotionId: string) => {} const getPendingContributionsTotal: (callback: (amount: number) => void) => {} const getNonVerifiedSettings: (callback: (nonVerified: boolean) => void) => {} + const onAdsEnabled: { + addListener: (callback: (enabled: boolean) => void) => void + } const onEnabledMain: { addListener: (callback: (enabledMain: boolean) => void) => void } + const getAdsEnabled: (callback: (enabled: boolean) => void) => {} + const getBalanceReports: (callback: (reports: Record) => void) => {} + const getAdsEstimatedEarnings: (callback: (amount: number) => void) => {} const getRewardsMainEnabled: (callback: (enabled: boolean) => void) => {} + const getWalletExists: (callback: (exists: boolean) => void) => {} const saveAdsSetting: (key: string, value: string) => {} const onPendingContributionSaved: { addListener: (callback: (result: number) => void) => void @@ -137,6 +144,8 @@ declare namespace chrome.braveRewards { } const onlyAnonWallet: (callback: (only: boolean) => void) => {} + + const openBrowserActionUI: (path?: string) => {} } declare namespace chrome.rewardsNotifications { diff --git a/components/definitions/newTab.d.ts b/components/definitions/newTab.d.ts index 54b6079fc071b..3380caea75e36 100644 --- a/components/definitions/newTab.d.ts +++ b/components/definitions/newTab.d.ts @@ -46,6 +46,7 @@ declare namespace NewTab { gridSites: Site[] showEmptyPage: boolean bookmarks: Record + rewardsState: RewardsWidgetState } export interface EphemeralState { @@ -62,9 +63,72 @@ declare namespace NewTab { showStats: boolean showClock: boolean showTopSites: boolean + showRewards: boolean stats: Stats } + export interface RewardsWidgetState { + adsEstimatedEarnings: number + balance: RewardsBalance + dismissedNotifications: string[] + enabledAds: boolean + enabledMain: boolean + grants: GrantRecord[] + onlyAnonWallet: boolean + totalContribution: string + walletCreated: boolean + walletCreating: boolean + walletCreateFailed: boolean + walletCorrupted: boolean + } + + export const enum RewardsResult { + LEDGER_OK = 0, + LEDGER_ERROR = 1, + NO_PUBLISHER_STATE = 2, + NO_LEDGER_STATE = 3, + INVALID_PUBLISHER_STATE = 4, + INVALID_LEDGER_STATE = 5, + CAPTCHA_FAILED = 6, + NO_PUBLISHER_LIST = 7, + TOO_MANY_RESULTS = 8, + NOT_FOUND = 9, + REGISTRATION_VERIFICATION_FAILED = 10, + BAD_REGISTRATION_RESPONSE = 11, + WALLET_CREATED = 12, + GRANT_NOT_FOUND = 13, + WALLET_CORRUPT = 17 + } + + export interface RewardsReport { + ads: string + closing: string + contribute: string + deposit: string + donation: string + grant: string + tips: string + opening: string + total: string + } + + export interface GrantResponse { + promotionId?: string + status?: number + type?: string + } + + export interface GrantRecord { + type: string + promotionId: string + } + + export interface RewardsBalance { + total: number + rates: Record + wallets: Record + } + // In-memory state is a superset of PersistentState export type State = PersistentState & EphemeralState } diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index b5f7df14d0c6f..6a33016fda0cb 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -142,6 +142,7 @@ Show Brave Stats Show Clock Show Top Sites + Show Rewards Learn more @@ -537,7 +538,7 @@ tokens Total Transactions - Turn on Ads + Turn on Brave Ads This enables both ads and automatic contributions. You can turn them on or off separately at any time. Activate Rewards Tweet @@ -616,6 +617,22 @@ Uphold may require you to verify your identity based on services requested. Brave Software Inc. does not process, store, or access any of the personal information that you provide to Uphold when you establish an account with them. + + about Brave Rewards + By clicking 'Turn on Rewards', you indicate that you have read and agree to the + Estimated earnings so far this month + Tips and contributions this month + Claim my Rewards + Turning on... + Turn on Rewards + Feeling Generous? + Ready to start earning? + Try Brave Rewards again and pay it forward as you earn! + Turn on Brave Rewards and get paid to view privacy respecting ads. + Way to Go! + Your rewards from Ads are here + You have a UGP grant from Brave. + Done