2021-10-17 10:36:14 +02:00
import * as ACTIONS from 'constants/action_types' ;
2022-06-01 10:58:09 +02:00
import * as MODALS from 'constants/modal_types' ;
import * as ERRORS from 'constants/errors' ;
2021-10-17 10:36:14 +02:00
import Lbry from 'lbry' ;
2021-10-28 22:25:34 +02:00
import { Lbryio } from 'lbryinc' ;
2022-06-01 10:58:09 +02:00
import { doOpenModal } from 'redux/actions/app' ;
2021-10-17 10:36:14 +02:00
import { doToast } from 'redux/actions/notifications' ;
import {
selectBalance ,
selectPendingSupportTransactions ,
selectTxoPageParams ,
selectPendingOtherTransactions ,
selectPendingConsolidateTxid ,
selectPendingMassClaimTxid ,
} from 'redux/selectors/wallet' ;
2022-05-05 10:41:47 +02:00
import { resolveApiMessage } from 'util/api-message' ;
2021-10-17 10:36:14 +02:00
import { creditsToString } from 'util/format-credits' ;
import { selectMyClaimsRaw , selectClaimsById } from 'redux/selectors/claims' ;
import { doFetchChannelListMine , doFetchClaimListMine , doClaimSearch } from 'redux/actions/claims' ;
const FIFTEEN _SECONDS = 15000 ;
let walletBalancePromise = null ;
export function doUpdateBalance ( ) {
return ( dispatch , getState ) => {
const {
wallet : { totalBalance : totalInStore } ,
} = getState ( ) ;
if ( walletBalancePromise === null ) {
walletBalancePromise = Lbry . wallet _balance ( )
. then ( ( response ) => {
walletBalancePromise = null ;
const { available , reserved , reserved _subtotals , total } = response ;
const { claims , supports , tips } = reserved _subtotals ;
const totalFloat = parseFloat ( total ) ;
if ( totalInStore !== totalFloat ) {
dispatch ( {
type : ACTIONS . UPDATE _BALANCE ,
data : {
totalBalance : totalFloat ,
balance : parseFloat ( available ) ,
reservedBalance : parseFloat ( reserved ) ,
claimsBalance : parseFloat ( claims ) ,
supportsBalance : parseFloat ( supports ) ,
tipsBalance : parseFloat ( tips ) ,
} ,
} ) ;
}
} )
. catch ( ( ) => {
walletBalancePromise = null ;
} ) ;
}
return walletBalancePromise ;
} ;
}
export function doBalanceSubscribe ( ) {
return ( dispatch ) => {
dispatch ( doUpdateBalance ( ) ) ;
setInterval ( ( ) => dispatch ( doUpdateBalance ( ) ) , 10000 ) ;
} ;
}
export function doFetchTransactions ( page = 1 , pageSize = 999999 ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . FETCH _TRANSACTIONS _STARTED ,
} ) ;
Lbry . transaction _list ( { page , page _size : pageSize } ) . then ( ( result ) => {
dispatch ( {
type : ACTIONS . FETCH _TRANSACTIONS _COMPLETED ,
data : {
transactions : result . items ,
} ,
} ) ;
} ) ;
} ;
}
export function doFetchTxoPage ( ) {
return ( dispatch , getState ) => {
const fetchId = Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) ;
dispatch ( {
type : ACTIONS . FETCH _TXO _PAGE _STARTED ,
data : fetchId ,
} ) ;
const state = getState ( ) ;
const queryParams = selectTxoPageParams ( state ) ;
Lbry . txo _list ( queryParams )
. then ( ( res ) => {
const items = res . items || [ ] ;
const claimsById = selectClaimsById ( state ) ;
const channelIds = items . reduce ( ( acc , cur ) => {
if ( cur . type === 'support' && cur . signing _channel && ! claimsById [ cur . signing _channel . channel _id ] ) {
acc . push ( cur . signing _channel . channel _id ) ;
}
return acc ;
} , [ ] ) ;
if ( channelIds . length ) {
const searchParams = {
page _size : 9999 ,
page : 1 ,
no _totals : true ,
claim _ids : channelIds ,
} ;
// make sure redux has these channels resolved
dispatch ( doClaimSearch ( searchParams ) ) ;
}
return res ;
} )
. then ( ( res ) => {
dispatch ( {
type : ACTIONS . FETCH _TXO _PAGE _COMPLETED ,
data : {
result : res ,
fetchId : fetchId ,
} ,
} ) ;
} )
. catch ( ( e ) => {
dispatch ( {
type : ACTIONS . FETCH _TXO _PAGE _COMPLETED ,
data : {
error : e . message ,
fetchId : fetchId ,
} ,
} ) ;
} ) ;
} ;
}
export function doUpdateTxoPageParams ( params ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . UPDATE _TXO _FETCH _PARAMS ,
data : params ,
} ) ;
dispatch ( doFetchTxoPage ( ) ) ;
} ;
}
export function doFetchSupports ( page = 1 , pageSize = 99999 ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . FETCH _SUPPORTS _STARTED ,
} ) ;
Lbry . support _list ( { page , page _size : pageSize } ) . then ( ( result ) => {
dispatch ( {
type : ACTIONS . FETCH _SUPPORTS _COMPLETED ,
data : {
supports : result . items ,
} ,
} ) ;
} ) ;
} ;
}
export function doFetchUtxoCounts ( ) {
return async ( dispatch ) => {
dispatch ( {
type : ACTIONS . FETCH _UTXO _COUNT _STARTED ,
} ) ;
let resultSets = await Promise . all ( [
Lbry . txo _list ( { type : 'other' , is _not _spent : true , page : 1 , page _size : 1 } ) ,
Lbry . txo _list ( { type : 'support' , is _not _spent : true , page : 1 , page _size : 1 } ) ,
] ) ;
const counts = { } ;
const paymentCount = resultSets [ 0 ] [ 'total_items' ] ;
const supportCount = resultSets [ 1 ] [ 'total_items' ] ;
counts [ 'other' ] = typeof paymentCount === 'number' ? paymentCount : 0 ;
counts [ 'support' ] = typeof supportCount === 'number' ? supportCount : 0 ;
dispatch ( {
type : ACTIONS . FETCH _UTXO _COUNT _COMPLETED ,
data : counts ,
debug : { resultSets } ,
} ) ;
} ;
}
export function doUtxoConsolidate ( ) {
return async ( dispatch ) => {
dispatch ( {
type : ACTIONS . DO _UTXO _CONSOLIDATE _STARTED ,
} ) ;
const results = await Lbry . txo _spend ( { type : 'other' } ) ;
const result = results [ 0 ] ;
dispatch ( {
type : ACTIONS . PENDING _CONSOLIDATED _TXOS _UPDATED ,
data : { txids : [ result . txid ] } ,
} ) ;
dispatch ( {
type : ACTIONS . DO _UTXO _CONSOLIDATE _COMPLETED ,
data : { txid : result . txid } ,
} ) ;
dispatch ( doCheckPendingTxs ( ) ) ;
} ;
}
export function doTipClaimMass ( ) {
return async ( dispatch ) => {
dispatch ( {
type : ACTIONS . TIP _CLAIM _MASS _STARTED ,
} ) ;
const results = await Lbry . txo _spend ( { type : 'support' , is _not _my _input : true } ) ;
const result = results [ 0 ] ;
dispatch ( {
type : ACTIONS . PENDING _CONSOLIDATED _TXOS _UPDATED ,
data : { txids : [ result . txid ] } ,
} ) ;
dispatch ( {
type : ACTIONS . TIP _CLAIM _MASS _COMPLETED ,
data : { txid : result . txid } ,
} ) ;
dispatch ( doCheckPendingTxs ( ) ) ;
} ;
}
export function doGetNewAddress ( ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . GET _NEW _ADDRESS _STARTED ,
} ) ;
Lbry . address _unused ( ) . then ( ( address ) => {
dispatch ( {
type : ACTIONS . GET _NEW _ADDRESS _COMPLETED ,
data : { address } ,
} ) ;
} ) ;
} ;
}
export function doCheckAddressIsMine ( address ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . CHECK _ADDRESS _IS _MINE _STARTED ,
} ) ;
Lbry . address _is _mine ( { address } ) . then ( ( isMine ) => {
if ( ! isMine ) dispatch ( doGetNewAddress ( ) ) ;
dispatch ( {
type : ACTIONS . CHECK _ADDRESS _IS _MINE _COMPLETED ,
} ) ;
} ) ;
} ;
}
export function doSendDraftTransaction ( address , amount ) {
return ( dispatch , getState ) => {
const state = getState ( ) ;
const balance = selectBalance ( state ) ;
if ( balance - amount <= 0 ) {
dispatch (
doToast ( {
title : _ _ ( 'Insufficient credits' ) ,
message : _ _ ( 'Insufficient credits' ) ,
} )
) ;
return ;
}
dispatch ( {
type : ACTIONS . SEND _TRANSACTION _STARTED ,
} ) ;
const successCallback = ( response ) => {
if ( response . txid ) {
dispatch ( {
type : ACTIONS . SEND _TRANSACTION _COMPLETED ,
} ) ;
dispatch (
doToast ( {
2022-06-02 09:29:37 +02:00
message : _ _ ( 'Credits successfully sent.' ) ,
linkText : ` ${ amount } LBC ` ,
2021-10-17 10:36:14 +02:00
linkTarget : '/wallet' ,
} )
) ;
} else {
dispatch ( {
type : ACTIONS . SEND _TRANSACTION _FAILED ,
data : { error : response } ,
} ) ;
dispatch (
doToast ( {
message : _ _ ( 'Transaction failed' ) ,
isError : true ,
} )
) ;
}
} ;
const errorCallback = ( error ) => {
dispatch ( {
type : ACTIONS . SEND _TRANSACTION _FAILED ,
data : { error : error . message } ,
} ) ;
dispatch (
doToast ( {
message : _ _ ( 'Transaction failed' ) ,
2022-05-05 10:41:47 +02:00
subMessage : resolveApiMessage ( error ? . message ) ,
2021-10-17 10:36:14 +02:00
isError : true ,
} )
) ;
} ;
Lbry . wallet _send ( {
addresses : [ address ] ,
amount : creditsToString ( amount ) ,
} ) . then ( successCallback , errorCallback ) ;
} ;
}
export function doSetDraftTransactionAmount ( amount ) {
return {
type : ACTIONS . SET _DRAFT _TRANSACTION _AMOUNT ,
data : { amount } ,
} ;
}
export function doSetDraftTransactionAddress ( address ) {
return {
type : ACTIONS . SET _DRAFT _TRANSACTION _ADDRESS ,
data : { address } ,
} ;
}
2022-06-01 10:58:09 +02:00
export function doSendTip ( params , isSupport , successCallback , errorCallback , shouldNotify = true , purpose = '' ) {
2021-10-17 10:36:14 +02:00
return ( dispatch , getState ) => {
const state = getState ( ) ;
const balance = selectBalance ( state ) ;
const myClaims = selectMyClaimsRaw ( state ) ;
2021-10-21 17:17:17 +02:00
const supportOwnClaim = myClaims ? myClaims . find ( ( claim ) => claim . claim _id === params . claim _id ) : false ;
2021-10-17 10:36:14 +02:00
2021-10-21 17:17:17 +02:00
const shouldSupport = isSupport || supportOwnClaim ;
2021-10-17 10:36:14 +02:00
if ( balance - params . amount <= 0 ) {
dispatch (
doToast ( {
message : _ _ ( 'Insufficient credits' ) ,
isError : true ,
} )
) ;
return ;
}
const success = ( response ) => {
if ( shouldNotify ) {
dispatch (
doToast ( {
2022-06-02 09:29:37 +02:00
message : shouldSupport ? _ _ ( 'Boost transaction successful.' ) : _ _ ( 'Tip successfully sent.' ) ,
subMessage : _ _ ( "I'm sure they appreciate it!" ) ,
linkText : ` ${ params . amount } LBC ` ,
2021-10-17 10:36:14 +02:00
linkTarget : '/wallet' ,
} )
) ;
}
dispatch ( {
type : ACTIONS . SUPPORT _TRANSACTION _COMPLETED ,
2021-10-21 17:17:17 +02:00
data : {
amount : params . amount ,
type : shouldSupport ? ( supportOwnClaim ? 'support_own' : 'support_others' ) : 'tip' ,
} ,
2021-10-17 10:36:14 +02:00
} ) ;
if ( successCallback ) {
successCallback ( response ) ;
}
} ;
const error = ( err ) => {
2022-03-18 09:42:52 +01:00
const baseMsg = isSupport ? _ _ ( 'Boost transaction failed.' ) : _ _ ( 'Tip transaction failed.' ) ;
const errMsg = typeof err === 'object' ? err . message : err ;
2022-06-01 10:58:09 +02:00
if ( errMsg . endsWith ( ERRORS . SDK _FETCH _TIMEOUT ) ) {
let msg ;
switch ( purpose ) {
case 'comment' :
msg = _ _ (
'The transaction timed out, but may have been completed. Please wait a few minutes, then check your wallet transactions before attempting to retry. Note that due to current limitations, we are unable to re-link the tip sent to a new comment.'
) ;
break ;
default :
msg = _ _ (
'The transaction timed out, but may have been completed. Please wait a few minutes, then check your wallet transactions before attempting to retry.'
) ;
break ;
}
2022-03-18 09:42:52 +01:00
2022-06-01 10:58:09 +02:00
dispatch (
doOpenModal ( MODALS . CONFIRM , {
title : baseMsg ,
body : msg ,
onConfirm : ( closeModal ) => closeModal ( ) ,
hideCancel : true ,
} )
) ;
}
2021-10-17 10:36:14 +02:00
dispatch ( {
type : ACTIONS . SUPPORT _TRANSACTION _FAILED ,
data : {
error : err ,
2021-10-21 17:17:17 +02:00
type : shouldSupport ? ( supportOwnClaim ? 'support_own' : 'support_others' ) : 'tip' ,
2021-10-17 10:36:14 +02:00
} ,
} ) ;
if ( errorCallback ) {
2022-06-01 10:04:05 +02:00
errorCallback ( err ) ;
2021-10-17 10:36:14 +02:00
}
} ;
dispatch ( {
type : ACTIONS . SUPPORT _TRANSACTION _STARTED ,
} ) ;
Lbry . support _create ( {
... params ,
tip : ! shouldSupport ,
blocking : true ,
amount : creditsToString ( params . amount ) ,
} ) . then ( success , error ) ;
} ;
}
export function doClearSupport ( ) {
return {
type : ACTIONS . CLEAR _SUPPORT _TRANSACTION ,
} ;
}
export function doWalletEncrypt ( newPassword ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _ENCRYPT _START ,
} ) ;
Lbry . wallet _encrypt ( { new _password : newPassword } ) . then ( ( result ) => {
if ( result === true ) {
dispatch ( {
type : ACTIONS . WALLET _ENCRYPT _COMPLETED ,
result ,
} ) ;
} else {
dispatch ( {
type : ACTIONS . WALLET _ENCRYPT _FAILED ,
result ,
} ) ;
}
} ) ;
} ;
}
export function doWalletUnlock ( password ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _UNLOCK _START ,
} ) ;
Lbry . wallet _unlock ( { password } ) . then ( ( result ) => {
if ( result === true ) {
dispatch ( {
type : ACTIONS . WALLET _UNLOCK _COMPLETED ,
result ,
} ) ;
} else {
dispatch ( {
type : ACTIONS . WALLET _UNLOCK _FAILED ,
result ,
} ) ;
}
} ) ;
} ;
}
export function doWalletLock ( ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _LOCK _START ,
} ) ;
Lbry . wallet _lock ( ) . then ( ( result ) => {
if ( result === true ) {
dispatch ( {
type : ACTIONS . WALLET _LOCK _COMPLETED ,
result ,
} ) ;
} else {
dispatch ( {
type : ACTIONS . WALLET _LOCK _FAILED ,
result ,
} ) ;
}
} ) ;
} ;
}
// Collect all tips for a claim
export function doSupportAbandonForClaim ( claimId , claimType , keep , preview ) {
return ( dispatch ) => {
if ( preview ) {
dispatch ( {
type : ACTIONS . ABANDON _CLAIM _SUPPORT _PREVIEW ,
} ) ;
} else {
dispatch ( {
type : ACTIONS . ABANDON _CLAIM _SUPPORT _STARTED ,
} ) ;
}
const params = { claim _id : claimId } ;
if ( preview ) params [ 'preview' ] = true ;
if ( keep ) params [ 'keep' ] = keep ;
return Lbry . support _abandon ( params )
. then ( ( res ) => {
if ( ! preview ) {
dispatch ( {
type : ACTIONS . ABANDON _CLAIM _SUPPORT _COMPLETED ,
data : { claimId , txid : res . txid , effective : res . outputs [ 0 ] . amount , type : claimType } ,
} ) ;
dispatch ( doCheckPendingTxs ( ) ) ;
}
return res ;
} )
. catch ( ( e ) => {
dispatch ( {
type : ACTIONS . ABANDON _CLAIM _SUPPORT _FAILED ,
data : e . message ,
} ) ;
} ) ;
} ;
}
export function doWalletReconnect ( ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _RESTART ,
} ) ;
let failed = false ;
// this basically returns null when it's done. :(
// might be good to dispatch ACTIONS.WALLET_RESTARTED
const walletTimeout = setTimeout ( ( ) => {
failed = true ;
dispatch ( {
type : ACTIONS . WALLET _RESTART _COMPLETED ,
} ) ;
dispatch (
doToast ( {
message : _ _ ( 'Your servers were not available. Check your url and port, or switch back to defaults.' ) ,
isError : true ,
} )
) ;
} , FIFTEEN _SECONDS ) ;
Lbry . wallet _reconnect ( ) . then ( ( ) => {
clearTimeout ( walletTimeout ) ;
if ( ! failed ) dispatch ( { type : ACTIONS . WALLET _RESTART _COMPLETED } ) ;
} ) ;
} ;
}
export function doWalletDecrypt ( ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _DECRYPT _START ,
} ) ;
Lbry . wallet _decrypt ( ) . then ( ( result ) => {
if ( result === true ) {
dispatch ( {
type : ACTIONS . WALLET _DECRYPT _COMPLETED ,
result ,
} ) ;
} else {
dispatch ( {
type : ACTIONS . WALLET _DECRYPT _FAILED ,
result ,
} ) ;
}
} ) ;
} ;
}
export function doWalletStatus ( ) {
return ( dispatch ) => {
dispatch ( {
type : ACTIONS . WALLET _STATUS _START ,
} ) ;
Lbry . wallet _status ( ) . then ( ( status ) => {
if ( status ) {
dispatch ( {
type : ACTIONS . WALLET _STATUS _COMPLETED ,
result : status . is _encrypted ,
} ) ;
}
} ) ;
} ;
}
export function doSetTransactionListFilter ( filterOption ) {
return {
type : ACTIONS . SET _TRANSACTION _LIST _FILTER ,
data : filterOption ,
} ;
}
export function doUpdateBlockHeight ( ) {
return ( dispatch ) =>
Lbry . status ( ) . then ( ( status ) => {
if ( status . wallet ) {
dispatch ( {
type : ACTIONS . UPDATE _CURRENT _HEIGHT ,
data : status . wallet . blocks ,
} ) ;
}
} ) ;
}
// Calls transaction_show on txes until any pending txes are confirmed
export const doCheckPendingTxs = ( ) => ( dispatch , getState ) => {
const state = getState ( ) ;
const pendingTxsById = selectPendingSupportTransactions ( state ) ; // {}
const pendingOtherTxes = selectPendingOtherTransactions ( state ) ;
if ( ! Object . keys ( pendingTxsById ) . length && ! pendingOtherTxes . length ) {
return ;
}
let txCheckInterval ;
const checkTxList = ( ) => {
const state = getState ( ) ;
const pendingSupportTxs = selectPendingSupportTransactions ( state ) ; // {}
const pendingConsolidateTxes = selectPendingOtherTransactions ( state ) ;
const pendingConsTxid = selectPendingConsolidateTxid ( state ) ;
const pendingMassCLaimTxid = selectPendingMassClaimTxid ( state ) ;
const promises = [ ] ;
const newPendingTxes = { } ;
const noLongerPendingConsolidate = [ ] ;
const types = new Set ( [ ] ) ;
// { claimId: {txid: 123, amount 12.3}, }
const entries = Object . entries ( pendingSupportTxs ) ;
entries . forEach ( ( [ claim , data ] ) => {
promises . push ( Lbry . transaction _show ( { txid : data . txid } ) ) ;
types . add ( data . type ) ;
} ) ;
if ( pendingConsolidateTxes . length ) {
pendingConsolidateTxes . forEach ( ( txid ) => promises . push ( Lbry . transaction _show ( { txid } ) ) ) ;
}
Promise . all ( promises ) . then ( ( txShows ) => {
let changed = false ;
txShows . forEach ( ( result ) => {
if ( pendingConsolidateTxes . includes ( result . txid ) ) {
if ( result . height > 0 ) {
noLongerPendingConsolidate . push ( result . txid ) ;
}
} else {
if ( result . height <= 0 ) {
const match = entries . find ( ( entry ) => entry [ 1 ] . txid === result . txid ) ;
newPendingTxes [ match [ 0 ] ] = match [ 1 ] ;
} else {
changed = true ;
}
}
} ) ;
if ( changed ) {
dispatch ( {
type : ACTIONS . PENDING _SUPPORTS _UPDATED ,
data : newPendingTxes ,
} ) ;
if ( types . has ( 'channel' ) ) {
dispatch ( doFetchChannelListMine ( ) ) ;
}
if ( types . has ( 'stream' ) ) {
dispatch ( doFetchClaimListMine ( ) ) ;
}
}
if ( noLongerPendingConsolidate . length ) {
if ( noLongerPendingConsolidate . includes ( pendingConsTxid ) ) {
dispatch (
doToast ( {
message : _ _ ( 'Your wallet is finished consolidating' ) ,
} )
) ;
}
if ( noLongerPendingConsolidate . includes ( pendingMassCLaimTxid ) ) {
dispatch (
doToast ( {
message : _ _ ( 'Your tips have been collected' ) ,
} )
) ;
}
dispatch ( {
type : ACTIONS . PENDING _CONSOLIDATED _TXOS _UPDATED ,
data : { txids : noLongerPendingConsolidate , remove : true } ,
} ) ;
}
if ( ! Object . keys ( pendingTxsById ) . length && ! pendingOtherTxes . length ) {
clearInterval ( txCheckInterval ) ;
}
} ) ;
} ;
txCheckInterval = setInterval ( ( ) => {
checkTxList ( ) ;
} , 30000 ) ;
} ;
2021-10-28 22:25:34 +02:00
2022-03-28 23:40:56 +02:00
export const doSendCashTip = (
tipParams ,
anonymous ,
userParams ,
claimId ,
stripeEnvironment ,
preferredCurrency ,
2022-03-30 07:42:20 +02:00
successCallback
) => ( dispatch ) => {
2021-10-28 22:25:34 +02:00
Lbryio . call (
'customer' ,
'tip' ,
{
// round to fix issues with floating point numbers
amount : Math . round ( 100 * tipParams . tipAmount ) , // convert from dollars to cents
creator _channel _name : tipParams . tipChannelName , // creator_channel_name
creator _channel _claim _id : tipParams . channelClaimId ,
tipper _channel _name : anonymous ? '' : userParams . activeChannelName ,
tipper _channel _claim _id : anonymous ? '' : userParams . activeChannelId ,
2022-03-28 23:40:56 +02:00
currency : preferredCurrency || 'USD' ,
2021-10-28 22:25:34 +02:00
anonymous : anonymous ,
source _claim _id : claimId ,
environment : stripeEnvironment ,
} ,
'post'
)
. then ( ( customerTipResponse ) => {
2022-03-30 12:17:39 +02:00
const fiatSymbol = preferredCurrency === 'USD' ? '$' : '€' ;
2022-03-28 23:40:56 +02:00
2021-10-28 22:25:34 +02:00
dispatch (
doToast ( {
2022-06-02 09:29:37 +02:00
message : _ _ ( 'Tip successfully sent.' ) ,
subMessage : _ _ ( "I'm sure they appreciate it!" ) ,
linkText : ` ${ fiatSymbol } ${ tipParams . tipAmount } ⇒ ${ tipParams . tipChannelName } ` ,
linkTarget : '/wallet' ,
2021-10-28 22:25:34 +02:00
} )
) ;
if ( successCallback ) successCallback ( customerTipResponse ) ;
} )
. catch ( ( error ) => {
// show error message from Stripe if one exists (being passed from backend by Beamer's API currently)
dispatch (
doToast ( {
message : error . message || _ _ ( 'Sorry, there was an error in processing your payment!' ) ,
isError : true ,
} )
) ;
} ) ;
} ;