Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Commit

Permalink
Merge pull request #3473 from willy-b/issue-2994-rebased
Browse files Browse the repository at this point in the history
Add Payment History dialog to Payments Tab (issue #2994)
  • Loading branch information
diracdeltas authored Aug 27, 2016
2 parents d6d7627 + 547a1dc commit 93062f1
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 27 deletions.
10 changes: 9 additions & 1 deletion app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ syncEmptyText=Sync settings coming soon.
bitcoin=Bitcoin
bitcoinAdd=Use an existing Bitcoin wallet
bitcoinBuy=Buy Bitcoin
viewPaymentHistory=View Payment History
paymentHistoryTitle=Your Payment History
paymentHistoryFooterText=Your next payment submission is {{reconcileDate}}.
paymentHistoryOKText=OK
bitcoinAddress=Your Brave wallet address is:
bitcoinPaymentURL=Scan the QR code or copy this link:
bitcoinQR=Brave wallet QR code:
paymentHistoryTitle=Your Payment History
bitcoinCopyAddress=Copy Bitcoin address to clipboard
bitcoinVisitAccount=Transfer BTC
bitcoinBalance=Please transfer: 
Expand All @@ -56,8 +61,11 @@ on=on
notifications=Notifications
moneyAdd=Use your debit or credit card
add=Buy with Coinbase
addFundsTitle=Add Funds
addFundsTitle=Add Funds...
addFunds=Add funds to your Brave Payments Account
date=Date
totalAmount=Total Amount
receiptLink=Receipt Link
advanced=Advanced
rank=Rank
views=Views
Expand Down
34 changes: 24 additions & 10 deletions app/ledger.js
Original file line number Diff line number Diff line change
Expand Up @@ -695,16 +695,28 @@ var ledgerInfo = {
transactions:
[
/*
{ viewingId : undefined
, submissionStamp : undefined
, satoshis : undefined
, currency : undefined
, amount : undefined
, ballots :
{ 'publisher1' : undefined
...
{
viewingId: undefined,
surveyorId: undefined,
contribution: {
fiat: {
amount: undefined,
currency: undefined
},
rates: {
[currency]: undefined // bitcoin value in <currency>
},
satoshis: undefined,
fee: undefined
},
submissionStamp: undefined,
submissionId: undefined,
count: undefined,
satoshis: undefined,
votes: undefined,
ballots: {
[publisher]: undefined
}
}
, ...
*/
],
Expand Down Expand Up @@ -1002,7 +1014,9 @@ var getPaymentInfo = () => {
info.address = client.getWalletAddress()
if ((amount) && (currency)) {
info = underscore.extend(info, { amount: amount, currency: currency })
if ((body.rates) && (body.rates[currency])) info.btc = (amount / body.rates[currency]).toFixed(8)
if ((body.rates) && (body.rates[currency])) {
info.btc = (amount / body.rates[currency]).toFixed(8)
}
}
ledgerInfo._internal.paymentInfo = info
updateLedgerInfo()
Expand Down
133 changes: 129 additions & 4 deletions js/about/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ class SettingsList extends ImmutableComponent {
class SettingItem extends ImmutableComponent {
render () {
return <div className='settingItem'>
<span data-l10n-id={this.props.dataL10nId} />
{
this.props.dataL10nId
? <span data-l10n-id={this.props.dataL10nId} />
: null
}
{this.props.children}
</div>
}
Expand Down Expand Up @@ -323,6 +327,80 @@ class BitcoinDashboard extends ImmutableComponent {
}
}

class PaymentHistory extends ImmutableComponent {
get ledgerData () {
return this.props.ledgerData
}

render () {
const transactions = this.props.ledgerData.get('transactions')

return <div id='paymentHistory'>
<table className='sort'>
<thead>
<tr>
<th className='sort-header' data-l10n-id='date' />
<th className='sort-header' data-l10n-id='totalAmount' />
</tr>
</thead>
<tbody>
{
transactions.map(function (row) {
return <PaymentHistoryRow transaction={row} ledgerData={this.props.ledgerData} />
}.bind(this))
}
</tbody>
</table>
</div>
}
}

class PaymentHistoryRow extends ImmutableComponent {

get transaction () {
return this.props.transaction
}

get timestamp () {
return this.transaction.get('submissionStamp')
}

get formattedDate () {
return formattedDateFromTimestamp(this.timestamp)
}

get numericDateStr () {
return (new Date(this.timestamp)).toLocaleDateString().replace(/\//g, '-')
}

get ledgerData () {
return this.props.ledgerData
}

get satoshis () {
return this.transaction.getIn(['contribution', 'satoshis'])
}

get currency () {
return this.transaction.getIn(['contribution', 'fiat', 'currency'])
}

get totalAmount () {
var fiatAmount = this.transaction.getIn(['contribution', 'fiat', 'amount'])
return (fiatAmount && typeof fiatAmount === 'number' ? fiatAmount.toFixed(2) : '0.00')
}

render () {
var date = this.formattedDate
var totalAmountStr = `${this.totalAmount} ${this.currency}`

return <tr>
<td className='narrow' data-sort={this.timestamp}>{date}</td>
<td className='wide' data-sort={this.satoshis}>{totalAmountStr}</td>
</tr>
}
}

class GeneralTab extends ImmutableComponent {
enabled (keyArray) {
return keyArray.every((key) => getSetting(key, this.props.settings) === true)
Expand Down Expand Up @@ -494,7 +572,21 @@ class PaymentsTab extends ImmutableComponent {
const onButtonClick = this.props.ledgerData.get('created')
? this.props.showOverlay.bind(this, 'addFunds')
: (this.props.ledgerData.get('creating') ? () => {} : this.createWallet)
return <Button l10nId={buttonText} className='primaryButton' onClick={onButtonClick.bind(this)} disabled={this.props.ledgerData.get('creating')} />
return <Button l10nId={buttonText} className='primaryButton addFunds' onClick={onButtonClick.bind(this)} disabled={this.props.ledgerData.get('creating')} />
}

get paymentHistoryButton () {
const walletCreated = this.props.ledgerData.get('created') && !this.props.ledgerData.get('creating')
const walletTransactions = this.props.ledgerData.get('transactions')
const walletHasTransactions = walletTransactions && walletTransactions.size

if (!walletCreated || !walletHasTransactions) {
return null
}

const buttonText = 'viewPaymentHistory'
const onButtonClick = this.props.showOverlay.bind(this, 'paymentHistory')
return <Button className='paymentHistoryButton' l10nId={buttonText} onClick={onButtonClick.bind(this)} disabled={this.props.ledgerData.get('creating')} />
}

get walletStatus () {
Expand Down Expand Up @@ -535,6 +627,27 @@ class PaymentsTab extends ImmutableComponent {
hideParentOverlay={this.props.hideOverlay.bind(this, 'addFunds')} />
}

get paymentHistoryContent () {
return <PaymentHistory ledgerData={this.props.ledgerData} />
}

get paymentHistoryFooter () {
let ledgerData = this.props.ledgerData
if (!ledgerData.get('reconcileStamp')) {
return null
}
let nextReconcileDate = formattedDateFromTimestamp(ledgerData.get('reconcileStamp'))
let l10nDataArgs = {
reconcileDate: nextReconcileDate
}
return <div className='paymentHistoryFooter'>
<div className='nextPaymentSubmission'>
<span data-l10n-id='paymentHistoryFooterText' data-l10n-args={JSON.stringify(l10nDataArgs)} />
</div>
<Button l10nId='paymentHistoryOKText' className='okButton primaryButton' onClick={this.props.hideOverlay.bind(this, 'paymentHistory')} />
</div>
}

btcToCurrencyString (btc) {
const balance = Number(btc || 0)
const currency = this.props.ledgerData.get('currency')
Expand All @@ -544,8 +657,7 @@ class PaymentsTab extends ImmutableComponent {
if (balance === 0) {
return `0 ${currency}`
}
if (this.props.ledgerData.get('btc') &&
typeof this.props.ledgerData.get('amount') === 'number') {
if (this.props.ledgerData.get('btc') && typeof this.props.ledgerData.get('amount') === 'number') {
const btcValue = this.props.ledgerData.get('btc') / this.props.ledgerData.get('amount')
return `${(balance / btcValue).toFixed(2)} ${currency}`
}
Expand Down Expand Up @@ -584,6 +696,7 @@ class PaymentsTab extends ImmutableComponent {
{this.btcToCurrencyString(this.props.ledgerData.get('balance'))}
</span>
{this.walletButton}
{this.paymentHistoryButton}
</td>
<td>
<SettingsList>
Expand Down Expand Up @@ -618,6 +731,11 @@ class PaymentsTab extends ImmutableComponent {
? <ModalOverlay title={'addFunds'} content={this.overlayContent} onHide={this.props.hideOverlay.bind(this, 'addFunds')} />
: null
}
{
this.enabled && this.props.paymentHistoryOverlayVisible
? <ModalOverlay title={'paymentHistoryTitle'} customTitleClasses={'paymentHistory'} content={this.paymentHistoryContent} footer={this.paymentHistoryFooter} onHide={this.props.hideOverlay.bind(this, 'paymentHistory')} />
: null
}
<div className='titleBar'>
<div className='sectionTitleWrapper pull-left'>
<span className='sectionTitle' data-l10n-id='publisherPaymentsTitle' />
Expand Down Expand Up @@ -1005,6 +1123,7 @@ class AboutPreferences extends React.Component {
let hash = window.location.hash ? window.location.hash.slice(1) : ''
this.state = {
bitcoinOverlayVisible: false,
paymentHistoryOverlayVisible: false,
addFundsOverlayVisible: false,
preferenceTab: hash.toUpperCase() in preferenceTabs ? hash : preferenceTabs.GENERAL,
hintNumber: this.getNextHintNumber(),
Expand Down Expand Up @@ -1118,6 +1237,7 @@ class AboutPreferences extends React.Component {
braveryDefaults={braveryDefaults} ledgerData={ledgerData}
onChangeSetting={this.onChangeSetting}
bitcoinOverlayVisible={this.state.bitcoinOverlayVisible}
paymentHistoryOverlayVisible={this.state.paymentHistoryOverlayVisible}
addFundsOverlayVisible={this.state.addFundsOverlayVisible}
showOverlay={this.setOverlayVisible.bind(this, true)}
hideOverlay={this.setOverlayVisible.bind(this, false)} />
Expand All @@ -1143,4 +1263,9 @@ class AboutPreferences extends React.Component {
}
}

let formattedDateFromTimestamp = function (timestamp) {
var date = new Date(timestamp)
return date.toLocaleDateString()
}

module.exports = <AboutPreferences />
17 changes: 13 additions & 4 deletions js/components/modalOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@ class ModalOverlay extends ImmutableComponent {
close = <button type='button' className='close pull-right' onClick={this.props.onHide}><span>&times;</span></button>
title = <div className='sectionTitle' data-l10n-id={this.props.title} />
}
return <div className='dialog'>
{close}
{title}
{this.props.content}
let customTitleClassesStr = (this.props.customTitleClasses ? this.props.customTitleClasses : '')

return <div className={'dialog ' + customTitleClassesStr}>
<div className='dialog-header'>
{close}
{title}
</div>
<div className='dialog-body'>
{this.props.content}
</div>
<div className='dialog-footer'>
{this.props.footer}
</div>
</div>
}

Expand Down
Loading

0 comments on commit 93062f1

Please sign in to comment.