Merge pull request #14063 from brave/emerick-rewards-payout-status

Add support for payout status
This commit is contained in:
Emerick Rogul
2022-07-11 18:51:21 -04:00
committed by GitHub
43 changed files with 295 additions and 103 deletions
+8 -3
View File
@@ -578,12 +578,11 @@ BraveRewardsGetRewardsParametersFunction::Run() {
}
rewards_service->GetRewardsParameters(base::BindOnce(
&BraveRewardsGetRewardsParametersFunction::OnGet,
this));
&BraveRewardsGetRewardsParametersFunction::OnGetRewardsParameters, this));
return RespondLater();
}
void BraveRewardsGetRewardsParametersFunction::OnGet(
void BraveRewardsGetRewardsParametersFunction::OnGetRewardsParameters(
ledger::type::RewardsParametersPtr parameters) {
base::DictionaryValue data;
@@ -604,6 +603,12 @@ void BraveRewardsGetRewardsParametersFunction::OnGet(
}
data.SetList("autoContributeChoices", std::move(ac_choices));
auto payout_status = std::make_unique<base::DictionaryValue>();
for (const auto& [key, value] : parameters->payout_status) {
payout_status->SetString(key, value);
}
data.Set("payoutStatus", std::move(payout_status));
Respond(OneArgument(std::move(data)));
}
+1 -1
View File
@@ -180,7 +180,7 @@ class BraveRewardsGetRewardsParametersFunction : public ExtensionFunction {
ResponseAction Run() override;
private:
void OnGet(ledger::type::RewardsParametersPtr parameters);
void OnGetRewardsParameters(ledger::type::RewardsParametersPtr parameters);
};
class BraveRewardsGetBalanceReportFunction : public ExtensionFunction {
+13 -6
View File
@@ -667,14 +667,21 @@ void RewardsDOMHandler::OnGetRewardsParameters(
base::DictionaryValue data;
if (parameters) {
auto choices = std::make_unique<base::ListValue>();
for (double const& choice : parameters->auto_contribute_choices) {
choices->Append(choice);
base::ListValue auto_contribute_choices;
for (double const& item : parameters->auto_contribute_choices) {
auto_contribute_choices.Append(item);
}
data.SetDouble("rate", parameters->rate);
data.SetDouble("autoContributeChoice", parameters->auto_contribute_choice);
data.SetList("autoContributeChoices", std::move(choices));
base::DictionaryValue payout_status;
for (const auto& [key, value] : parameters->payout_status) {
payout_status.SetStringKey(key, value);
}
data.SetDoubleKey("rate", parameters->rate);
data.SetDoubleKey("autoContributeChoice",
parameters->auto_contribute_choice);
data.SetKey("autoContributeChoices", std::move(auto_contribute_choices));
data.SetKey("payoutStatus", std::move(payout_status));
}
CallJavascriptFunction("brave_rewards.rewardsParameters", data);
}
+6
View File
@@ -459,10 +459,16 @@ void TipMessageHandler::GetRewardsParametersCallback(
ac_choices.Append(item);
}
base::Value payout_status(base::Value::Type::DICTIONARY);
for (const auto& item : parameters->payout_status) {
payout_status.SetStringKey(item.first, item.second);
}
data.SetDoubleKey("rate", parameters->rate);
data.SetKey("tipChoices", std::move(tip_choices));
data.SetKey("monthlyTipChoices", std::move(monthly_choices));
data.SetKey("autoContributeChoices", std::move(ac_choices));
data.SetKey("payoutStatus", std::move(payout_status));
}
FireWebUIListener("rewardsParametersUpdated", data);
+7 -1
View File
@@ -705,7 +705,7 @@
{
"name": "getRewardsParameters",
"type": "function",
"description": "Get default values that we get from the server",
"description": "Get default Rewards parameters",
"parameters": [
{
"type": "function",
@@ -734,6 +734,12 @@
"type": "number",
"minimum": 0
}
},
"payoutStatus": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
@@ -1,6 +1,6 @@
/* 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/. */
* 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'
@@ -9,6 +9,7 @@ import createWidget from '../widget/index'
import { StyledTitleTab } from '../widgetTitleTab'
import { LocaleContext } from '../../../../brave_rewards/resources/shared/lib/locale_context'
import { getProviderPayoutStatus } from '../../../../brave_rewards/resources/shared/lib/provider_payout_status'
import { WithThemeVariables } from '../../../../brave_rewards/resources/shared/components/with_theme_variables'
import { GrantInfo } from '../../../../brave_rewards/resources/shared/lib/grant_info'
import { OnboardingCompletedStore } from '../../../../brave_rewards/resources/shared/lib/onboarding_completed_store'
@@ -92,6 +93,12 @@ export const RewardsWidget = createWidget((props: RewardsProps) => {
const adsInfo = props.adsAccountStatement || null
const grantInfo = getVisibleGrant(props.promotions || [])
const externalWallet = externalWalletFromExtensionData(props.externalWallet)
const walletProvider = externalWallet ? externalWallet.provider : null
const providerPayoutStatus = props.parameters.payoutStatus
? getProviderPayoutStatus(props.parameters.payoutStatus, walletProvider)
: 'off'
const onClaimGrant = () => {
if (grantInfo) {
chrome.braveRewards.showGrantCaptcha(grantInfo.id)
@@ -107,8 +114,9 @@ export const RewardsWidget = createWidget((props: RewardsProps) => {
rewardsBalance={props.balance.total}
exchangeCurrency='USD'
exchangeRate={props.parameters.rate}
providerPayoutStatus={providerPayoutStatus}
grantInfo={grantInfo}
externalWallet={externalWalletFromExtensionData(props.externalWallet)}
externalWallet={externalWallet}
nextPaymentDate={adsInfo ? adsInfo.nextPaymentDate : 0}
earningsThisMonth={adsInfo ? adsInfo.earningsThisMonth : 0}
earningsLastMonth={adsInfo ? adsInfo.earningsLastMonth : 0}
@@ -81,7 +81,8 @@ export const defaultState: NewTab.State = {
totalContribution: 0.0,
parameters: {
rate: 0,
monthlyTipChoices: []
monthlyTipChoices: [],
payoutStatus: {}
}
},
currentStackWidget: '',
@@ -80,6 +80,7 @@ void RewardsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
"");
registry->RegisterStringPref(prefs::kParametersTipChoices, "");
registry->RegisterStringPref(prefs::kParametersMonthlyTipChoices, "");
registry->RegisterStringPref(prefs::kParametersPayoutStatus, "");
registry->RegisterBooleanPref(prefs::kFetchOldBalance, true);
registry->RegisterBooleanPref(prefs::kEmptyBalanceChecked, false);
registry->RegisterStringPref(prefs::kWalletBrave, "");
@@ -64,6 +64,7 @@ const char kParametersTipChoices[] =
"brave.rewards.parameters.tip.choices";
const char kParametersMonthlyTipChoices[] =
"brave.rewards.parameters.tip.monthly_choices";
const char kParametersPayoutStatus[] = "brave.rewards.parameters.payout_status";
const char kFetchOldBalance[] =
"brave.rewards.fetch_old_balance";
const char kEmptyBalanceChecked[] =
@@ -54,6 +54,7 @@ extern const char kParametersAutoContributeChoice[];
extern const char kParametersAutoContributeChoices[];
extern const char kParametersTipChoices[];
extern const char kParametersMonthlyTipChoices[];
extern const char kParametersPayoutStatus[];
extern const char kFetchOldBalance[];
extern const char kEmptyBalanceChecked[];
extern const char kWalletBrave[];
@@ -23,6 +23,8 @@ import {
StyledNeedsBrowserUpdateContentBody
} from './style'
import { externalWalletProviderFromString } from '../../shared/lib/external_wallet'
import { getProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { PaymentStatusView } from '../../shared/components/payment_status_view'
// Utils
@@ -221,6 +223,7 @@ class AdsBox extends React.Component<Props, {}> {
const {
adsData,
balanceReport,
externalWallet,
safetyNetFailed,
parameters
} = this.props.rewardsData
@@ -269,6 +272,13 @@ class AdsBox extends React.Component<Props, {}> {
const tokenString = getLocale('tokens')
const walletStatus = externalWallet ? externalWallet.status : null
const walletProvider = externalWallet
? externalWalletProviderFromString(externalWallet.type) : null
const providerPayoutStatus = getProviderPayoutStatus(
parameters.payoutStatus,
walletProvider && walletStatus ? walletProvider : null)
return (
<BoxMobile
title={getLocale('adsTitle')}
@@ -282,6 +292,7 @@ class AdsBox extends React.Component<Props, {}> {
earningsLastMonth={earningsLastMonth}
earningsReceived={adEarningsReceived}
nextPaymentDate={nextPaymentDate}
providerPayoutStatus={providerPayoutStatus}
/>
</StyledArrivingSoon>
<List title={<StyledListContent>{getLocale('adsCurrentEarnings')}</StyledListContent>}>
@@ -13,6 +13,7 @@ import {
} from '../../ui/components'
import { PendingContributionsModal } from './pending_contributions_modal'
import { WalletCard, ExternalWalletAction } from '../../shared/components/wallet_card'
import { getProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { ExternalWallet, ExternalWalletProvider, ExternalWalletStatus } from '../../shared/lib/external_wallet'
import { Provider } from '../../ui/components/profile'
import { DetailRow as PendingDetailRow, PendingType } from '../../ui/components/tablePending'
@@ -760,6 +761,10 @@ class PageWallet extends React.Component<Props, State> {
}
}
const providerPayoutStatus = getProviderPayoutStatus(
parameters.payoutStatus,
walletProvider && walletStatus ? walletProvider : null)
const summaryData = {
adEarnings: balanceReport && balanceReport.ads || 0,
autoContributions: balanceReport && balanceReport.contribute || 0,
@@ -773,6 +778,7 @@ class PageWallet extends React.Component<Props, State> {
<WalletCard
balance={total}
externalWallet={externalWalletInfo}
providerPayoutStatus={providerPayoutStatus}
earningsThisMonth={adsData.adsEarningsThisMonth || 0}
earningsLastMonth={adsData.adsEarningsLastMonth || 0}
nextPaymentDate={0}
@@ -8,7 +8,7 @@ import { debounce } from '../../../common/debounce'
const keyName = 'rewards-data'
export const defaultState: Rewards.State = {
version: 1,
version: 2,
createdTimestamp: null,
enabledAds: true,
enabledAdsMigrated: false,
@@ -77,7 +77,8 @@ export const defaultState: Rewards.State = {
parameters: {
autoContributeChoice: 0,
autoContributeChoices: [],
rate: 0
rate: 0,
payoutStatus: {}
},
initializing: true,
paymentId: '',
@@ -7,7 +7,8 @@ export const defaultState: RewardsExtension.State = {
parameters: {
monthlyTipChoices: [],
rate: 0,
autoContributeChoices: [5, 10, 15, 20]
autoContributeChoices: [5, 10, 15, 20],
payoutStatus: {}
},
balanceReport: {
ads: 0.0,
@@ -20,6 +20,8 @@ import {
import { Grid, Column, Select, ControlWrapper } from 'brave-ui/components'
import { AlertCircleIcon } from 'brave-ui/components/icons'
import { externalWalletProviderFromString } from '../../shared/lib/external_wallet'
import { getProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { PaymentStatusView } from '../../shared/components/payment_status_view'
import * as style from './style'
@@ -415,6 +417,7 @@ class AdsBox extends React.Component<Props, State> {
adsData,
adsHistory,
balanceReport,
externalWallet,
parameters
} = this.props.rewardsData
@@ -442,6 +445,13 @@ class AdsBox extends React.Component<Props, State> {
const rows = this.getGroupedAdsHistory(historyEntries, savedOnly)
const tokenString = getLocale('tokens')
const walletStatus = externalWallet ? externalWallet.status : null
const walletProvider = externalWallet
? externalWalletProviderFromString(externalWallet.type) : null
const providerPayoutStatus = getProviderPayoutStatus(
parameters.payoutStatus,
walletProvider && walletStatus ? walletProvider : null)
return (
<>
<Box
@@ -468,6 +478,7 @@ class AdsBox extends React.Component<Props, State> {
earningsLastMonth={earningsLastMonth}
earningsReceived={adEarningsReceived}
nextPaymentDate={nextPaymentDate}
providerPayoutStatus={providerPayoutStatus}
/>
</style.PaymentStatus>
<List title={getLocale('adsCurrentEarnings')}>
@@ -496,7 +507,7 @@ class AdsBox extends React.Component<Props, State> {
</List>
{
<ShowAdsHistory
onAdsHistoryOpen={this.onAdsHistoryToggle}
onAdsHistoryOpen={this.onAdsHistoryToggle}
/>
}
</Box>
@@ -13,6 +13,7 @@ import {
ModalQRCode
} from '../../ui/components'
import { WalletCard, ExternalWalletAction } from '../../shared/components/wallet_card'
import { getProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { ExternalWallet, ExternalWalletProvider, ExternalWalletStatus } from '../../shared/lib/external_wallet'
import { Provider } from '../../ui/components/profile'
import { DetailRow as PendingDetailRow, PendingType } from '../../ui/components/tablePending'
@@ -760,6 +761,10 @@ class PageWallet extends React.Component<Props, State> {
}
}
const providerPayoutStatus = getProviderPayoutStatus(
parameters.payoutStatus,
walletProvider && walletStatus ? walletProvider : null)
const summaryData = {
adEarnings: balanceReport && balanceReport.ads || 0,
autoContributions: balanceReport && balanceReport.contribute || 0,
@@ -773,6 +778,7 @@ class PageWallet extends React.Component<Props, State> {
<WalletCard
balance={total}
externalWallet={externalWalletInfo}
providerPayoutStatus={providerPayoutStatus}
earningsThisMonth={adsData.adsEarningsThisMonth || 0}
earningsLastMonth={adsData.adsEarningsLastMonth || 0}
nextPaymentDate={0}
@@ -8,7 +8,7 @@ import { debounce } from '../../../common/debounce'
const keyName = 'rewards-data'
export const defaultState: Rewards.State = {
version: 1,
version: 2,
createdTimestamp: null,
enabledAds: false,
enabledAdsMigrated: false,
@@ -76,7 +76,8 @@ export const defaultState: Rewards.State = {
parameters: {
autoContributeChoice: 0,
autoContributeChoices: [],
rate: 0
rate: 0,
payoutStatus: {}
},
initializing: true,
paymentId: '',
@@ -5,6 +5,7 @@
import * as React from 'react'
import { HostContext, useHostListener } from '../lib/host_context'
import { getProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { WalletCard } from '../../shared/components/wallet_card'
import { NavBar } from './navbar'
import { PanelOverlays } from './panel_overlays'
@@ -23,6 +24,8 @@ export function Panel () {
React.useState(host.state.exchangeInfo)
const [earningsInfo, setEarningsInfo] =
React.useState(host.state.earningsInfo)
const [payoutStatus, setPayoutStatus] =
React.useState(host.state.payoutStatus)
const [summaryData, setSummaryData] = React.useState(host.state.summaryData)
const [publisherInfo, setPublisherInfo] =
React.useState(host.state.publisherInfo)
@@ -36,16 +39,22 @@ export function Panel () {
setExternalWallet(state.externalWallet)
setExchangeInfo(state.exchangeInfo)
setEarningsInfo(state.earningsInfo)
setPayoutStatus(state.payoutStatus)
setSummaryData(state.summaryData)
setPublisherInfo(state.publisherInfo)
})
const walletProvider = externalWallet ? externalWallet.provider : null
const providerPayoutStatus = getProviderPayoutStatus(
payoutStatus, walletProvider)
return (
<div>
<div className='rewards-panel' data-test-id='rewards-panel'>
<WalletCard
balance={balance}
externalWallet={externalWallet}
providerPayoutStatus={providerPayoutStatus}
earningsThisMonth={earningsInfo.earningsThisMonth}
earningsLastMonth={earningsInfo.earningsLastMonth}
nextPaymentDate={earningsInfo.nextPaymentDate}
@@ -4,6 +4,7 @@
import { Notification } from '../../shared/components/notifications'
import { GrantInfo } from '../../shared/lib/grant_info'
import { ProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { RewardsSummaryData } from '../../shared/components/wallet_card'
import { mapNotification } from './notification_adapter'
@@ -63,6 +64,7 @@ export function getEarningsInfo () {
export function getRewardsParameters () {
interface Result {
exchangeInfo: ExchangeInfo
payoutStatus: Record<string, ProviderPayoutStatus>
options: Options
}
@@ -75,7 +77,8 @@ export function getRewardsParameters () {
exchangeInfo: {
currency: 'USD',
rate: parameters.rate
}
},
payoutStatus: parameters.payoutStatus
})
})
})
@@ -347,8 +347,8 @@ export function createHost (): Host {
stateManager.update({ balance })
}),
apiAdapter.getRewardsParameters().then((params) => {
const { options, exchangeInfo } = params
stateManager.update({ options, exchangeInfo })
const { options, exchangeInfo, payoutStatus } = params
stateManager.update({ options, exchangeInfo, payoutStatus })
}),
apiAdapter.getSettings().then((settings) => {
stateManager.update({ settings })
@@ -29,6 +29,7 @@ export function getInitialState (): HostState {
earningsThisMonth: 0,
earningsLastMonth: 0
},
payoutStatus: {},
publisherInfo: null,
publisherRefreshing: false,
externalWalletProviders: [],
@@ -4,6 +4,7 @@
import { ExternalWallet, ExternalWalletProvider } from '../../shared/lib/external_wallet'
import { GrantInfo } from '../../shared/lib/grant_info'
import { ProviderPayoutStatus } from '../../shared/lib/provider_payout_status'
import { PublisherPlatform } from '../../shared/lib/publisher_platform'
import { ExternalWalletAction, RewardsSummaryData } from '../../shared/components/wallet_card'
import { Notification, NotificationAction } from '../../shared/components/notifications'
@@ -78,6 +79,7 @@ export interface HostState {
adaptiveCaptchaInfo: AdaptiveCaptchaInfo | null
exchangeInfo: ExchangeInfo
earningsInfo: EarningsInfo
payoutStatus: Record<string, ProviderPayoutStatus>
publisherInfo: PublisherInfo | null
publisherRefreshing: boolean
externalWalletProviders: ExternalWalletProvider[]
@@ -74,6 +74,9 @@ function createHost (): Host {
earningsLastMonth: 2.4,
nextPaymentDate: Date.now() + 1000 * 60 * 60 * 24 * 3
},
payoutStatus: {
uphold: 'complete'
},
publisherInfo: {
id: 'brave.com',
name: 'brave.com',
@@ -7,6 +7,7 @@ import * as React from 'react'
import { LocaleContext, formatMessage } from '../../lib/locale_context'
import { GrantInfo } from '../../lib/grant_info'
import { ExternalWallet, getExternalWalletProviderName } from '../../lib/external_wallet'
import { ProviderPayoutStatus } from '../../lib/provider_payout_status'
import { ArrowCircleIcon } from '../icons/arrow_circle_icon'
import { BatIcon } from '../icons/bat_icon'
import { SettingsIcon } from '../icons/settings_icon'
@@ -68,6 +69,7 @@ interface Props {
rewardsBalance: number
exchangeRate: number
exchangeCurrency: string
providerPayoutStatus: ProviderPayoutStatus
nextPaymentDate: number
earningsThisMonth: number
earningsLastMonth: number
@@ -135,6 +137,7 @@ export function RewardsCard (props: Props) {
earningsLastMonth={props.earningsLastMonth}
earningsReceived={props.earningsReceived}
nextPaymentDate={props.nextPaymentDate}
providerPayoutStatus={props.providerPayoutStatus}
/>
</style.pendingRewards>
</style.balance>
@@ -174,6 +177,7 @@ export function RewardsCard (props: Props) {
earningsLastMonth={props.earningsLastMonth}
earningsReceived={props.earningsReceived}
nextPaymentDate={props.nextPaymentDate}
providerPayoutStatus={props.providerPayoutStatus}
/>
</style.pendingRewards>
</style.balance>
@@ -45,6 +45,7 @@ export function Card () {
rewardsBalance={91.5812}
exchangeCurrency='USD'
exchangeRate={0.82}
providerPayoutStatus={'complete'}
grantInfo={showGrant ? {
id: '',
amount: 0.15,
@@ -2,10 +2,7 @@
* 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 {
getDaysUntilRewardsPayment,
shouldShowRewardsPaymentCompleted
} from './payment_status_view'
import { getDaysUntilRewardsPayment } from './payment_status_view'
function ms (timeString: string) {
return new Date(timeString).getTime()
@@ -16,28 +13,6 @@ function mockNow (timeString: string) {
}
describe('pending_rewards', () => {
describe('shouldShowRewardsPaymentCompleted', () => {
it('returns false if the next payment date is in the past', () => {
mockNow('2021-01-20')
expect(shouldShowRewardsPaymentCompleted(ms('2021-01-19')))
.toStrictEqual(false)
})
it('returns true if we are 2 days past the previous payment date', () => {
mockNow('2021-01-09')
expect(shouldShowRewardsPaymentCompleted(ms('2021-02-07')))
.toStrictEqual(true)
expect(shouldShowRewardsPaymentCompleted(ms('2021-03-07')))
.toStrictEqual(true)
})
it('returns false if we are 4 days past the previous payment date', () => {
mockNow('2021-01-11')
expect(shouldShowRewardsPaymentCompleted(ms('2021-02-07')))
.toStrictEqual(false)
})
})
describe('getDaysUntilRewardsPayment', () => {
it('returns empty if month does not match', () => {
mockNow('2021-01-20')
@@ -1,10 +1,11 @@
/* 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/. */
* 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 { LocaleContext, formatMessage } from '../lib/locale_context'
import { ProviderPayoutStatus } from '../lib/provider_payout_status'
import { NewTabLink } from './new_tab_link'
import { TokenAmount } from './token_amount'
@@ -24,24 +25,6 @@ const monthNameFormatter = new Intl.DateTimeFormat(undefined, {
month: 'long'
})
const completedMessageDaysVisible = 3
export function shouldShowRewardsPaymentCompleted (
nextPaymentDate: number | Date
) {
if (typeof nextPaymentDate === 'number') {
nextPaymentDate = new Date(nextPaymentDate)
}
const now = Date.now()
if (nextPaymentDate.getTime() < now) {
return false
}
const days = new Date(now).getDate() - nextPaymentDate.getDate()
return days >= 0 && days <= completedMessageDaysVisible
}
export function getDaysUntilRewardsPayment (nextPaymentDate: number | Date) {
if (typeof nextPaymentDate === 'number') {
nextPaymentDate = new Date(nextPaymentDate)
@@ -95,6 +78,7 @@ interface Props {
earningsLastMonth: number
earningsReceived: boolean
nextPaymentDate: number
providerPayoutStatus: ProviderPayoutStatus
}
export function PaymentStatusView (props: Props) {
@@ -122,11 +106,7 @@ export function PaymentStatusView (props: Props) {
)
}
if (!shouldShowRewardsPaymentCompleted(props.nextPaymentDate)) {
return null
}
if (props.earningsReceived) {
if (props.earningsReceived && props.providerPayoutStatus === 'complete') {
return (
<div className='rewards-payment-completed'>
<div><PaymentCompleteIcon /></div>
@@ -141,30 +121,32 @@ export function PaymentStatusView (props: Props) {
)
}
return (
<div className='rewards-payment-processing'>
<div>
{
formatMessage(getString('rewardsPaymentProcessing'), [
<RewardAmount key='amount' amount={props.earningsLastMonth} />,
getPaymentMonth()
])
}&nbsp;
<span className='rewards-payment-check-status'>
<NewTabLink key='status' href={urls.payoutStatusURL}>
{getString('rewardsPaymentCheckStatus')}
</NewTabLink>
</span>
if (!props.earningsReceived && props.providerPayoutStatus === 'processing') {
return (
<div className='rewards-payment-processing'>
<div>
{
formatMessage(getString('rewardsPaymentProcessing'), [
<RewardAmount key='amount' amount={props.earningsLastMonth} />,
getPaymentMonth()
])
}&nbsp;
<span className='rewards-payment-check-status'>
<NewTabLink key='status' href={urls.payoutStatusURL}>
{getString('rewardsPaymentCheckStatus')}
</NewTabLink>
</span>
</div>
</div>
</div>
)
)
}
return null
}
export function shouldRenderPendingRewards (
earningsLastMonth: number,
nextPaymentDate: number
) {
return earningsLastMonth > 0 && (
getDaysUntilRewardsPayment(nextPaymentDate) ||
shouldShowRewardsPaymentCompleted(nextPaymentDate))
return earningsLastMonth > 0 && getDaysUntilRewardsPayment(nextPaymentDate)
}
@@ -1,10 +1,11 @@
/* 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/. */
* 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 { PaymentStatusView } from '../payment_status_view'
import { ProviderPayoutStatus } from '../../lib/provider_payout_status'
import * as style from './pending_rewards_view.style'
@@ -12,6 +13,7 @@ interface Props {
earningsLastMonth: number
earningsReceived: boolean
nextPaymentDate: number
providerPayoutStatus: ProviderPayoutStatus
}
export function PendingRewardsView (props: Props) {
@@ -21,6 +23,7 @@ export function PendingRewardsView (props: Props) {
earningsLastMonth={props.earningsLastMonth}
earningsReceived={props.earningsReceived}
nextPaymentDate={props.nextPaymentDate}
providerPayoutStatus={props.providerPayoutStatus}
/>
</style.root>
)
@@ -5,6 +5,7 @@
import * as React from 'react'
import { LocaleContext } from '../../lib/locale_context'
import { ProviderPayoutStatus } from '../../lib/provider_payout_status'
import { PendingRewardsView } from './pending_rewards_view'
import { TokenAmount } from '../token_amount'
import { ExchangeAmount } from '../exchange_amount'
@@ -26,6 +27,7 @@ export interface RewardsSummaryData {
interface Props {
data: RewardsSummaryData
providerPayoutStatus: ProviderPayoutStatus
autoContributeEnabled: boolean
hideAdEarnings: boolean
earningsLastMonth: number
@@ -121,6 +123,7 @@ export function RewardsSummary (props: Props) {
earningsLastMonth={props.earningsLastMonth}
earningsReceived={props.data.adEarnings > 0}
nextPaymentDate={props.nextPaymentDate}
providerPayoutStatus={props.providerPayoutStatus}
/>
</style.body>
</style.root>
@@ -61,6 +61,7 @@ export function Wallet () {
<WalletCard
balance={0}
externalWallet={externalWallet}
providerPayoutStatus={'complete'}
earningsThisMonth={0}
earningsLastMonth={1}
nextPaymentDate={nextPaymentDate.getTime()}
@@ -6,6 +6,7 @@ import * as React from 'react'
import { LocaleContext, formatMessage } from '../../lib/locale_context'
import { ExternalWallet, getExternalWalletProviderName } from '../../lib/external_wallet'
import { ProviderPayoutStatus } from '../../lib/provider_payout_status'
import { TokenAmount } from '../token_amount'
import { ExchangeAmount } from '../exchange_amount'
@@ -27,6 +28,7 @@ const rangeFormatter = new Intl.DateTimeFormat(undefined, {
interface Props {
balance: number
externalWallet: ExternalWallet | null
providerPayoutStatus: ProviderPayoutStatus
earningsThisMonth: number
earningsLastMonth: number
nextPaymentDate: number
@@ -155,6 +157,7 @@ export function WalletCard (props: Props) {
? <style.summaryBox>
<RewardsSummary
data={props.summaryData}
providerPayoutStatus={props.providerPayoutStatus}
autoContributeEnabled={props.autoContributeEnabled}
hideAdEarnings={Boolean(props.externalWallet)}
earningsLastMonth={props.earningsLastMonth}
@@ -169,6 +172,7 @@ export function WalletCard (props: Props) {
earningsLastMonth={props.earningsLastMonth}
earningsReceived={props.summaryData.adEarnings > 0}
nextPaymentDate={props.nextPaymentDate}
providerPayoutStatus={props.providerPayoutStatus}
/>
</style.pendingBox>
}
@@ -0,0 +1,15 @@
/* 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 { ExternalWalletProvider } from '../../shared/lib/external_wallet'
export type ProviderPayoutStatus = 'off' | 'processing' | 'complete'
export function getProviderPayoutStatus (
payoutStatus: Record<string, ProviderPayoutStatus>,
walletProvider: ExternalWalletProvider | null
): ProviderPayoutStatus {
const key = walletProvider || 'unverified'
return payoutStatus[key] || 'off'
}
+3
View File
@@ -279,9 +279,12 @@ declare namespace NewTab {
earningsLastMonth: number
}
export type ProviderPayoutStatus = 'off' | 'processing' | 'complete'
export interface RewardsParameters {
rate: number
monthlyTipChoices: number[]
payoutStatus?: Record<string, ProviderPayoutStatus>
}
export interface DefaultSuperReferralTopSite {
+3
View File
@@ -95,10 +95,13 @@ declare namespace Rewards {
}
}
export type ProviderPayoutStatus = 'off' | 'processing' | 'complete'
export interface RewardsParameters {
rate: number
autoContributeChoice: number
autoContributeChoices: number[]
payoutStatus: Record<string, ProviderPayoutStatus>
}
export interface ComponentProps {
+3
View File
@@ -119,10 +119,13 @@ declare namespace RewardsExtension {
hint: string
}
export type ProviderPayoutStatus = 'off' | 'processing' | 'complete'
export interface RewardsParameters {
rate: number
monthlyTipChoices: number[]
autoContributeChoices: number[]
payoutStatus: Record<string, ProviderPayoutStatus>
}
export interface BalanceReport {
+7 -1
View File
@@ -13,5 +13,11 @@
"defaultMonthlyChoices": [
1, 10, 100
]
},
"payoutStatus": {
"bitflyer": "off",
"gemini": "off",
"uphold": "off",
"unverified": "off"
}
}
}
@@ -119,6 +119,7 @@ struct RewardsParameters {
array<double> auto_contribute_choices;
array<double> tip_choices;
array<double> monthly_tip_choices;
map<string, string> payout_status;
};
struct Balance {
@@ -2,6 +2,7 @@
* 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/. */
#include "bat/ledger/internal/endpoint/api/get_parameters/get_parameters.h"
#include <utility>
@@ -129,6 +130,18 @@ type::Result GetParameters::ParseBody(
parameters->monthly_tip_choices.push_back(choice.GetDouble());
}
const auto* payout_status_dict = value->GetDict().FindDict("payoutStatus");
if (!payout_status_dict) {
BLOG(0, "Missing payout status");
return type::Result::LEDGER_ERROR;
}
for (auto&& [key, value] : *payout_status_dict) {
if (value.is_string()) {
parameters->payout_status.emplace(key, value.GetString());
}
}
return type::Result::LEDGER_OK;
}
@@ -3,8 +3,8 @@
* 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/. */
#ifndef BRAVELEDGER_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
#define BRAVELEDGER_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
#ifndef BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
#define BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
#include <string>
@@ -46,6 +46,12 @@
// 10,
// 100
// ]
// },
// "payoutStatus": {
// "unverified": "off",
// "uphold": "off",
// "gemini": "off",
// "bitflyer": "complete"
// }
// }
@@ -86,4 +92,4 @@ class GetParameters {
} // namespace endpoint
} // namespace ledger
#endif // BRAVELEDGER_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
#endif // BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINT_API_GET_PARAMETERS_GET_PARAMETERS_H_
@@ -19,6 +19,7 @@
using ::testing::_;
using ::testing::Invoke;
using ::testing::NiceMock;
namespace ledger {
namespace endpoint {
@@ -34,9 +35,10 @@ class GetParametersTest : public testing::Test {
std::unique_ptr<GetParameters> parameters_;
GetParametersTest() {
mock_ledger_client_ = std::make_unique<ledger::MockLedgerClient>();
mock_ledger_impl_ =
std::make_unique<ledger::MockLedgerImpl>(mock_ledger_client_.get());
mock_ledger_client_ =
std::make_unique<NiceMock<ledger::MockLedgerClient>>();
mock_ledger_impl_ = std::make_unique<NiceMock<ledger::MockLedgerImpl>>(
mock_ledger_client_.get());
parameters_ = std::make_unique<GetParameters>(mock_ledger_impl_.get());
}
};
@@ -71,6 +73,12 @@ TEST_F(GetParametersTest, ServerOK) {
10,
15
]
},
"payoutStatus": {
"unverified": "off",
"uphold": "off",
"gemini": "off",
"bitflyer": "complete"
}
})";
callback(response);
@@ -85,6 +93,10 @@ TEST_F(GetParametersTest, ServerOK) {
expected_parameters.auto_contribute_choices = {5, 10, 15};
expected_parameters.tip_choices = {1, 10, 100};
expected_parameters.monthly_tip_choices = {5, 10, 15};
expected_parameters.payout_status = {{"unverified", "off"},
{"uphold", "off"},
{"gemini", "off"},
{"bitflyer", "complete"}};
EXPECT_EQ(result, type::Result::LEDGER_OK);
EXPECT_TRUE(expected_parameters.Equals(parameters));
});
@@ -184,6 +196,12 @@ TEST_F(GetParametersTest, WrongListValues) {
"10",
"100"
]
},
"payoutStatus": {
"unverified": "off",
"uphold": "off",
"gemini": "off",
"bitflyer": "complete"
}
})";
callback(response);
@@ -196,6 +214,10 @@ TEST_F(GetParametersTest, WrongListValues) {
EXPECT_EQ(result, type::Result::LEDGER_OK);
expected_parameters.rate = 0.2476573499489187;
expected_parameters.auto_contribute_choice = 20;
expected_parameters.payout_status = {{"unverified", "off"},
{"uphold", "off"},
{"gemini", "off"},
{"bitflyer", "complete"}};
EXPECT_TRUE(expected_parameters.Equals(parameters));
});
}
@@ -230,6 +252,12 @@ TEST_F(GetParametersTest, DoubleListValues) {
10.5,
15.0
]
},
"payoutStatus": {
"unverified": "off",
"uphold": "off",
"gemini": "off",
"bitflyer": "complete"
}
})";
callback(response);
@@ -244,6 +272,10 @@ TEST_F(GetParametersTest, DoubleListValues) {
expected_parameters.auto_contribute_choices = {5, 10.5, 15};
expected_parameters.tip_choices = {1, 10.5, 100};
expected_parameters.monthly_tip_choices = {5, 10.5, 15};
expected_parameters.payout_status = {{"unverified", "off"},
{"uphold", "off"},
{"gemini", "off"},
{"bitflyer", "complete"}};
EXPECT_EQ(result, type::Result::LEDGER_OK);
EXPECT_TRUE(expected_parameters.Equals(parameters));
});
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <algorithm>
#include <utility>
#include "base/base64.h"
#include "base/json/json_reader.h"
@@ -53,6 +54,39 @@ std::vector<double> StringToVectorDouble(const std::string& items_string) {
return items;
}
std::string PayoutStatusToString(
const base::flat_map<std::string, std::string>& payout_status) {
base::Value::Dict dict;
for (const auto& status : payout_status) {
dict.Set(status.first, status.second);
}
std::string payout_status_string;
base::JSONWriter::Write(dict, &payout_status_string);
return payout_status_string;
}
base::flat_map<std::string, std::string> StringToPayoutStatus(
const std::string& payout_status_string) {
base::DictionaryValue* dictionary_value = nullptr;
auto dict = base::JSONReader::Read(payout_status_string);
if (!dict || !dict->GetAsDictionary(&dictionary_value)) {
return {};
}
DCHECK(dictionary_value);
base::flat_map<std::string, std::string> payout_status;
for (const auto [key, value] : dictionary_value->GetDict()) {
if (!value.is_string()) {
continue;
}
payout_status.emplace(key, value.GetString());
}
return payout_status;
}
std::string ConvertInlineTipPlatformToKey(
const ledger::type::InlineTipsPlatforms platform) {
switch (platform) {
@@ -263,6 +297,8 @@ void State::SetRewardsParameters(const type::RewardsParameters& parameters) {
ledger_->ledger_client()->SetStringState(
kParametersMonthlyTipChoices,
VectorDoubleToString(parameters.monthly_tip_choices));
ledger_->ledger_client()->SetStringState(
kParametersPayoutStatus, PayoutStatusToString(parameters.payout_status));
}
type::RewardsParametersPtr State::GetRewardsParameters() {
@@ -272,6 +308,7 @@ type::RewardsParametersPtr State::GetRewardsParameters() {
parameters->auto_contribute_choices = GetAutoContributeChoices();
parameters->tip_choices = GetTipChoices();
parameters->monthly_tip_choices = GetMonthlyTipChoices();
parameters->payout_status = GetPayoutStatus();
return parameters;
}
@@ -318,6 +355,11 @@ std::vector<double> State::GetMonthlyTipChoices() {
kParametersMonthlyTipChoices));
}
base::flat_map<std::string, std::string> State::GetPayoutStatus() {
return StringToPayoutStatus(
ledger_->ledger_client()->GetStringState(kParametersPayoutStatus));
}
void State::SetFetchOldBalanceEnabled(bool enabled) {
ledger_->database()->SaveEventLog(kFetchOldBalance, std::to_string(enabled));
ledger_->ledger_client()->SetBooleanState(kFetchOldBalance, enabled);
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace ledger {
@@ -89,6 +90,8 @@ class State {
std::vector<double> GetMonthlyTipChoices();
base::flat_map<std::string, std::string> GetPayoutStatus();
void SetFetchOldBalanceEnabled(bool enabled);
bool GetFetchOldBalanceEnabled();
@@ -38,6 +38,7 @@ const char kParametersAutoContributeChoices[] = "parameters.ac.choices";
const char kParametersTipChoices[] = "parameters.tip.choices";
const char kParametersMonthlyTipChoices[] =
"parameters.tip.monthly_choices";
const char kParametersPayoutStatus[] = "parameters.payout_status";
const char kFetchOldBalance[] = "fetch_old_balance";
const char kEmptyBalanceChecked[] = "empty_balance_checked";
const char kExternalWalletType[] = "external_wallet_type";