store user supports

This commit is contained in:
Sean Yesmunt 2019-05-10 01:02:03 -04:00
parent 8adcd00e65
commit c8126ab217
12 changed files with 574 additions and 391 deletions

438
dist/bundle.es.js vendored
View file

@ -43,6 +43,10 @@ const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED';
const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED';
const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED';
const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED';
const ABANDON_SUPPORT_COMPLETED = 'ABANDON_SUPPORT_COMPLETED';
const UPDATE_BALANCE = 'UPDATE_BALANCE';
const UPDATE_TOTAL_BALANCE = 'UPDATE_TOTAL_BALANCE';
const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';
@ -254,6 +258,10 @@ var action_types = /*#__PURE__*/Object.freeze({
GET_NEW_ADDRESS_COMPLETED: GET_NEW_ADDRESS_COMPLETED,
FETCH_TRANSACTIONS_STARTED: FETCH_TRANSACTIONS_STARTED,
FETCH_TRANSACTIONS_COMPLETED: FETCH_TRANSACTIONS_COMPLETED,
FETCH_SUPPORTS_STARTED: FETCH_SUPPORTS_STARTED,
FETCH_SUPPORTS_COMPLETED: FETCH_SUPPORTS_COMPLETED,
ABANDON_SUPPORT_STARTED: ABANDON_SUPPORT_STARTED,
ABANDON_SUPPORT_COMPLETED: ABANDON_SUPPORT_COMPLETED,
UPDATE_BALANCE: UPDATE_BALANCE,
UPDATE_TOTAL_BALANCE: UPDATE_TOTAL_BALANCE,
CHECK_ADDRESS_IS_MINE_STARTED: CHECK_ADDRESS_IS_MINE_STARTED,
@ -647,6 +655,7 @@ const Lbry = {
address_unused: (params = {}) => daemonCallWithResult('address_unused', params),
transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params),
utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params),
support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params),
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),
@ -1421,7 +1430,9 @@ const selectBalance = reselect.createSelector(selectState$2, state => state.bala
const selectTotalBalance = reselect.createSelector(selectState$2, state => state.totalBalance);
const selectTransactionsById = reselect.createSelector(selectState$2, state => state.transactions);
const selectTransactionsById = reselect.createSelector(selectState$2, state => state.transactions || {});
const selectSupportsById = reselect.createSelector(selectState$2, state => state.supports || {});
const selectTransactionItems = reselect.createSelector(selectTransactionsById, byId => {
const items = [];
@ -1608,6 +1619,7 @@ function doTotalBalanceSubscribe() {
function doFetchTransactions() {
return dispatch => {
dispatch(doFetchSupports());
dispatch({
type: FETCH_TRANSACTIONS_STARTED
});
@ -1623,6 +1635,23 @@ function doFetchTransactions() {
};
}
function doFetchSupports() {
return dispatch => {
dispatch({
type: FETCH_SUPPORTS_STARTED
});
lbryProxy.support_list().then(results => {
dispatch({
type: FETCH_SUPPORTS_COMPLETED,
data: {
supports: results
}
});
});
};
}
function doGetNewAddress() {
return dispatch => {
dispatch({
@ -1966,39 +1995,43 @@ function doAbandonClaim(txid, nout) {
return (dispatch, getState) => {
const state = getState();
const myClaims = selectMyClaimsRaw(state);
const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout);
const mySupports = selectSupportsById(state);
if (!claimToAbandon) {
console.error('No associated claim with txid: ', txid);
// A user could be trying to abandon a support or one of their claims
const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout);
const supportToAbandon = mySupports[txid];
if (!claimToAbandon && !supportToAbandon) {
console.error('No associated support or claim with txid: ', txid);
return;
}
const { claim_id: claimId, name: claimName } = claimToAbandon;
const data = claimToAbandon ? { claimId: claimToAbandon.claim_id } : { txid: supportToAbandon.txid };
const isClaim = !!claimToAbandon;
const startedActionType = isClaim ? ABANDON_CLAIM_STARTED : ABANDON_SUPPORT_STARTED;
const completedActionType = isClaim ? ABANDON_CLAIM_STARTED : ABANDON_SUPPORT_COMPLETED;
dispatch({
type: ABANDON_CLAIM_STARTED,
data: {
claimId
}
type: startedActionType,
data
});
const errorCallback = () => {
dispatch(doToast({
message: 'Error abandoning claim',
message: isClaim ? 'Error abandoning your claim' : 'Error unlocking your tip',
isError: true
}));
};
const successCallback = () => {
dispatch({
type: ABANDON_CLAIM_SUCCEEDED,
data: {
claimId
}
type: completedActionType,
data
});
dispatch(doToast({
message: 'Successfully abandoned your claim'
message: isClaim ? 'Successfully abandoned your claim' : 'Successfully unlocked your tip!'
}));
// After abandoning, call claim_list to show the claim as abandoned
@ -2013,7 +2046,19 @@ function doAbandonClaim(txid, nout) {
blocking: true
};
const method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon';
let method;
if (supportToAbandon) {
method = 'support_abandon';
} else if (claimToAbandon) {
const { name: claimName } = claimToAbandon;
method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon';
}
if (!method) {
console.error('No "method" chosen for claim or support abandon');
return;
}
lbryProxy[method](abandonParams).then(successCallback, errorCallback);
};
}
@ -3094,9 +3139,8 @@ const searchReducer = handleActions({
}
}, defaultState$3);
//
var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const reducers$2 = {};
const buildDraftTransaction = () => ({
amount: undefined,
address: undefined
@ -3109,10 +3153,12 @@ const buildDraftTransaction = () => ({
const defaultState$4 = {
balance: undefined,
totalBalance: undefined,
blocks: {},
latestBlock: undefined,
transactions: {},
fetchingTransactions: false,
supports: {},
fetchingSupports: false,
abandoningSupportsById: {},
gettingNewAddress: false,
draftTransaction: buildDraftTransaction(),
sendingSupport: false,
@ -3132,217 +3178,234 @@ const defaultState$4 = {
transactionListFilter: 'all'
};
reducers$2[FETCH_TRANSACTIONS_STARTED] = state => Object.assign({}, state, {
fetchingTransactions: true
});
const walletReducer = handleActions({
[FETCH_TRANSACTIONS_STARTED]: state => _extends$7({}, state, {
fetchingTransactions: true
}),
reducers$2[FETCH_TRANSACTIONS_COMPLETED] = (state, action) => {
const byId = Object.assign({}, state.transactions);
[FETCH_TRANSACTIONS_COMPLETED]: (state, action) => {
const byId = _extends$7({}, state.transactions);
const { transactions } = action.data;
const { transactions } = action.data;
transactions.forEach(transaction => {
byId[transaction.txid] = transaction;
});
transactions.forEach(transaction => {
byId[transaction.txid] = transaction;
});
return _extends$7({}, state, {
transactions: byId,
fetchingTransactions: false
});
},
return Object.assign({}, state, {
transactions: byId,
fetchingTransactions: false
});
};
[FETCH_SUPPORTS_STARTED]: state => _extends$7({}, state, {
fetchingSupports: true
}),
reducers$2[GET_NEW_ADDRESS_STARTED] = state => Object.assign({}, state, {
gettingNewAddress: true
});
[FETCH_SUPPORTS_COMPLETED]: (state, action) => {
const byId = state.supports;
const { supports } = action.data;
reducers$2[GET_NEW_ADDRESS_COMPLETED] = (state, action) => {
const { address } = action.data;
supports.forEach(support => {
byId[support.txid] = support;
});
// Say no to localStorage!
return Object.assign({}, state, {
gettingNewAddress: false,
receiveAddress: address
});
};
return _extends$7({}, state, { supports: byId, fetchingSupports: false });
},
reducers$2[UPDATE_BALANCE] = (state, action) => Object.assign({}, state, {
balance: action.data.balance
});
[ABANDON_SUPPORT_STARTED]: (state, action) => {
const { txid } = action.data;
const abandoningById = state.abandoningSupportsById;
reducers$2[UPDATE_TOTAL_BALANCE] = (state, action) => Object.assign({}, state, {
totalBalance: action.data.totalBalance
});
abandoningById[txid] = true;
reducers$2[CHECK_ADDRESS_IS_MINE_STARTED] = state => Object.assign({}, state, {
checkingAddressOwnership: true
});
return _extends$7({}, state, {
abandoningSupportsById: abandoningById
});
},
reducers$2[CHECK_ADDRESS_IS_MINE_COMPLETED] = state => Object.assign({}, state, {
checkingAddressOwnership: false
});
[ABANDON_SUPPORT_COMPLETED]: (state, action) => {
const { txid } = action.data;
const byId = state.supports;
const abandoningById = state.abandoningSupportsById;
reducers$2[SET_DRAFT_TRANSACTION_AMOUNT] = (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = Object.assign({}, oldDraft, {
amount: parseFloat(action.data.amount)
});
delete abandoningById[txid];
delete byId[txid];
return Object.assign({}, state, {
draftTransaction: newDraft
});
};
return _extends$7({}, state, {
supports: byId,
abandoningSupportsById: abandoningById
});
},
reducers$2[SET_DRAFT_TRANSACTION_ADDRESS] = (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = Object.assign({}, oldDraft, {
address: action.data.address
});
[GET_NEW_ADDRESS_STARTED]: state => _extends$7({}, state, {
gettingNewAddress: true
}),
return Object.assign({}, state, {
draftTransaction: newDraft
});
};
[GET_NEW_ADDRESS_COMPLETED]: (state, action) => {
const { address } = action.data;
reducers$2[SEND_TRANSACTION_STARTED] = state => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: true
});
return _extends$7({}, state, { gettingNewAddress: false, receiveAddress: address });
},
return Object.assign({}, state, {
draftTransaction: newDraftTransaction
});
};
[UPDATE_BALANCE]: (state, action) => _extends$7({}, state, {
balance: action.data.balance
}),
reducers$2[SEND_TRANSACTION_COMPLETED] = state => Object.assign({}, state, {
draftTransaction: buildDraftTransaction()
});
[UPDATE_TOTAL_BALANCE]: (state, action) => _extends$7({}, state, {
totalBalance: action.data.totalBalance
}),
reducers$2[SEND_TRANSACTION_FAILED] = (state, action) => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: false,
error: action.data.error
});
[CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$7({}, state, {
checkingAddressOwnership: true
}),
return Object.assign({}, state, {
draftTransaction: newDraftTransaction
});
};
[CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$7({}, state, {
checkingAddressOwnership: false
}),
reducers$2[SUPPORT_TRANSACTION_STARTED] = state => Object.assign({}, state, {
sendingSupport: true
});
[SET_DRAFT_TRANSACTION_AMOUNT]: (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = _extends$7({}, oldDraft, { amount: parseFloat(action.data.amount) });
reducers$2[SUPPORT_TRANSACTION_COMPLETED] = state => Object.assign({}, state, {
sendingSupport: false
});
return _extends$7({}, state, { draftTransaction: newDraft });
},
reducers$2[SUPPORT_TRANSACTION_FAILED] = (state, action) => Object.assign({}, state, {
error: action.data.error,
sendingSupport: false
});
[SET_DRAFT_TRANSACTION_ADDRESS]: (state, action) => {
const oldDraft = state.draftTransaction;
const newDraft = _extends$7({}, oldDraft, { address: action.data.address });
reducers$2[WALLET_STATUS_COMPLETED] = (state, action) => Object.assign({}, state, {
walletIsEncrypted: action.result
});
return _extends$7({}, state, { draftTransaction: newDraft });
},
reducers$2[WALLET_ENCRYPT_START] = state => Object.assign({}, state, {
walletEncryptPending: true,
walletEncryptSucceded: null,
walletEncryptResult: null
});
[SEND_TRANSACTION_STARTED]: state => {
const newDraftTransaction = _extends$7({}, state.draftTransaction, { sending: true });
reducers$2[WALLET_ENCRYPT_COMPLETED] = (state, action) => Object.assign({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: true,
walletEncryptResult: action.result
});
return _extends$7({}, state, { draftTransaction: newDraftTransaction });
},
reducers$2[WALLET_ENCRYPT_FAILED] = (state, action) => Object.assign({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: false,
walletEncryptResult: action.result
});
[SEND_TRANSACTION_COMPLETED]: state => Object.assign({}, state, {
draftTransaction: buildDraftTransaction()
}),
reducers$2[WALLET_DECRYPT_START] = state => Object.assign({}, state, {
walletDecryptPending: true,
walletDecryptSucceded: null,
walletDecryptResult: null
});
[SEND_TRANSACTION_FAILED]: (state, action) => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: false,
error: action.data.error
});
reducers$2[WALLET_DECRYPT_COMPLETED] = (state, action) => Object.assign({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: true,
walletDecryptResult: action.result
});
return _extends$7({}, state, { draftTransaction: newDraftTransaction });
},
reducers$2[WALLET_DECRYPT_FAILED] = (state, action) => Object.assign({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: false,
walletDecryptResult: action.result
});
[SUPPORT_TRANSACTION_STARTED]: state => _extends$7({}, state, {
sendingSupport: true
}),
reducers$2[WALLET_UNLOCK_START] = state => Object.assign({}, state, {
walletUnlockPending: true,
walletUnlockSucceded: null,
walletUnlockResult: null
});
[SUPPORT_TRANSACTION_COMPLETED]: state => _extends$7({}, state, {
sendingSupport: false
}),
reducers$2[WALLET_UNLOCK_COMPLETED] = (state, action) => Object.assign({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: true,
walletUnlockResult: action.result
});
[SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$7({}, state, {
error: action.data.error,
sendingSupport: false
}),
reducers$2[WALLET_UNLOCK_FAILED] = (state, action) => Object.assign({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: false,
walletUnlockResult: action.result
});
[WALLET_STATUS_COMPLETED]: (state, action) => _extends$7({}, state, {
walletIsEncrypted: action.result
}),
reducers$2[WALLET_LOCK_START] = state => Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: null,
walletLockResult: null
});
[WALLET_ENCRYPT_START]: state => _extends$7({}, state, {
walletEncryptPending: true,
walletEncryptSucceded: null,
walletEncryptResult: null
}),
reducers$2[WALLET_LOCK_COMPLETED] = (state, action) => Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: true,
walletLockResult: action.result
});
[WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$7({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: true,
walletEncryptResult: action.result
}),
reducers$2[WALLET_LOCK_FAILED] = (state, action) => Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: false,
walletLockResult: action.result
});
[WALLET_ENCRYPT_FAILED]: (state, action) => _extends$7({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: false,
walletEncryptResult: action.result
}),
reducers$2[SET_TRANSACTION_LIST_FILTER] = (state, action) => Object.assign({}, state, {
transactionListFilter: action.data
});
[WALLET_DECRYPT_START]: state => _extends$7({}, state, {
walletDecryptPending: true,
walletDecryptSucceded: null,
walletDecryptResult: null
}),
reducers$2[UPDATE_CURRENT_HEIGHT] = (state, action) => Object.assign({}, state, {
latestBlock: action.data
});
[WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$7({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: true,
walletDecryptResult: action.result
}),
function walletReducer(state = defaultState$4, action) {
const handler = reducers$2[action.type];
if (handler) return handler(state, action);
return state;
}
[WALLET_DECRYPT_FAILED]: (state, action) => _extends$7({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: false,
walletDecryptResult: action.result
}),
var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
[WALLET_UNLOCK_START]: state => _extends$7({}, state, {
walletUnlockPending: true,
walletUnlockSucceded: null,
walletUnlockResult: null
}),
const reducers$3 = {};
[WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$7({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: true,
walletUnlockResult: action.result
}),
[WALLET_UNLOCK_FAILED]: (state, action) => _extends$7({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: false,
walletUnlockResult: action.result
}),
[WALLET_LOCK_START]: state => _extends$7({}, state, {
walletLockPending: false,
walletLockSucceded: null,
walletLockResult: null
}),
[WALLET_LOCK_COMPLETED]: (state, action) => _extends$7({}, state, {
walletLockPending: false,
walletLockSucceded: true,
walletLockResult: action.result
}),
[WALLET_LOCK_FAILED]: (state, action) => _extends$7({}, state, {
walletLockPending: false,
walletLockSucceded: false,
walletLockResult: action.result
}),
[SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$7({}, state, {
transactionListFilter: action.data
}),
[UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$7({}, state, {
latestBlock: action.data
})
}, defaultState$4);
var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const reducers$2 = {};
const defaultState$5 = {
positions: {}
};
reducers$3[SET_CONTENT_POSITION] = (state, action) => {
reducers$2[SET_CONTENT_POSITION] = (state, action) => {
const { claimId, outpoint, position } = action.data;
return _extends$7({}, state, {
positions: _extends$7({}, state.positions, {
[claimId]: _extends$7({}, state.positions[claimId], {
return _extends$8({}, state, {
positions: _extends$8({}, state.positions, {
[claimId]: _extends$8({}, state.positions[claimId], {
[outpoint]: position
})
})
@ -3350,7 +3413,7 @@ reducers$3[SET_CONTENT_POSITION] = (state, action) => {
};
function contentReducer(state = defaultState$5, action) {
const handler = reducers$3[action.type];
const handler = reducers$2[action.type];
if (handler) return handler(state, action);
return state;
}
@ -3366,14 +3429,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta
return state.positions[id] ? state.positions[id][outpoint] : null;
});
var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const selectState$5 = state => state.notifications || {};
const selectToast = reselect.createSelector(selectState$5, state => {
if (state.toasts.length) {
const { id, params } = state.toasts[0];
return _extends$8({
return _extends$9({
id
}, params);
}
@ -3537,6 +3600,7 @@ exports.selectSearchState = selectState;
exports.selectSearchSuggestions = selectSearchSuggestions;
exports.selectSearchUrisByQuery = selectSearchUrisByQuery;
exports.selectSearchValue = selectSearchValue;
exports.selectSupportsById = selectSupportsById;
exports.selectToast = selectToast;
exports.selectTotalBalance = selectTotalBalance;
exports.selectTotalDownloadProgress = selectTotalDownloadProgress;

View file

@ -130,6 +130,8 @@ declare type SyncApplyResponse = {
data: string,
};
declare type SupportAbandonResponse = GenericTxResponse;
//
// Types used in the generic Lbry object that is exported
//
@ -175,6 +177,7 @@ declare type LbryTypes = {
address_is_mine: (params: {}) => Promise<boolean>,
address_unused: (params: {}) => Promise<string>, // New address
transaction_list: (params: {}) => Promise<TxListResponse>,
support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
// Sync
sync_hash: (params: {}) => Promise<string>,

View file

@ -9,3 +9,19 @@ declare type Transaction = {
type: string,
date: Date,
};
declare type Support = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: string,
is_change: string,
is_mine: string,
name: string,
nout: string,
permanent_url: string,
timestamp: number,
txid: string,
type: string,
};

3
flow-typed/Lbry.js vendored
View file

@ -130,6 +130,8 @@ declare type SyncApplyResponse = {
data: string,
};
declare type SupportAbandonResponse = GenericTxResponse;
//
// Types used in the generic Lbry object that is exported
//
@ -175,6 +177,7 @@ declare type LbryTypes = {
address_is_mine: (params: {}) => Promise<boolean>,
address_unused: (params: {}) => Promise<string>, // New address
transaction_list: (params: {}) => Promise<TxListResponse>,
support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
// Sync
sync_hash: (params: {}) => Promise<string>,

View file

@ -9,3 +9,19 @@ declare type Transaction = {
type: string,
date: Date,
};
declare type Support = {
address: string,
amount: string,
claim_id: string,
confirmations: number,
height: string,
is_change: string,
is_mine: string,
name: string,
nout: string,
permanent_url: string,
timestamp: number,
txid: string,
type: string,
};

View file

@ -33,6 +33,10 @@ export const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED';
export const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
export const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
export const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED';
export const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED';
export const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED';
export const ABANDON_SUPPORT_COMPLETED = 'ABANDON_SUPPORT_COMPLETED';
export const UPDATE_BALANCE = 'UPDATE_BALANCE';
export const UPDATE_TOTAL_BALANCE = 'UPDATE_TOTAL_BALANCE';
export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';

View file

@ -183,6 +183,7 @@ export {
selectBalance,
selectTotalBalance,
selectTransactionsById,
selectSupportsById,
selectTransactionItems,
selectRecentTransactions,
selectHasTransactions,

View file

@ -86,6 +86,7 @@ const Lbry: LbryTypes = {
address_unused: (params = {}) => daemonCallWithResult('address_unused', params),
transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params),
utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params),
support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params),
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),

View file

@ -5,6 +5,7 @@ import { normalizeURI, parseURI } from 'lbryURI';
import { doToast } from 'redux/actions/notifications';
import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux/selectors/claims';
import { doFetchTransactions } from 'redux/actions/wallet';
import { selectSupportsById } from 'redux/selectors/wallet';
import { creditsToString } from 'util/formatCredits';
export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean = false) {
@ -92,26 +93,38 @@ export function doAbandonClaim(txid: string, nout: number) {
return (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const myClaims: Array<ChannelClaim | StreamClaim> = selectMyClaimsRaw(state);
const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout);
const mySupports: { [string]: Support } = selectSupportsById(state);
if (!claimToAbandon) {
console.error('No associated claim with txid: ', txid);
// A user could be trying to abandon a support or one of their claims
const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout);
const supportToAbandon = mySupports[txid];
if (!claimToAbandon && !supportToAbandon) {
console.error('No associated support or claim with txid: ', txid);
return;
}
const { claim_id: claimId, name: claimName } = claimToAbandon;
const data = claimToAbandon
? { claimId: claimToAbandon.claim_id }
: { txid: supportToAbandon.txid };
const isClaim = !!claimToAbandon;
const startedActionType = isClaim
? ACTIONS.ABANDON_CLAIM_STARTED
: ACTIONS.ABANDON_SUPPORT_STARTED;
const completedActionType = isClaim
? ACTIONS.ABANDON_CLAIM_STARTED
: ACTIONS.ABANDON_SUPPORT_COMPLETED;
dispatch({
type: ACTIONS.ABANDON_CLAIM_STARTED,
data: {
claimId,
},
type: startedActionType,
data,
});
const errorCallback = () => {
dispatch(
doToast({
message: 'Error abandoning claim',
message: isClaim ? 'Error abandoning your claim' : 'Error unlocking your tip',
isError: true,
})
);
@ -119,15 +132,15 @@ export function doAbandonClaim(txid: string, nout: number) {
const successCallback = () => {
dispatch({
type: ACTIONS.ABANDON_CLAIM_SUCCEEDED,
data: {
claimId,
},
type: completedActionType,
data,
});
dispatch(
doToast({
message: 'Successfully abandoned your claim',
message: isClaim
? 'Successfully abandoned your claim'
: 'Successfully unlocked your tip!',
})
);
@ -143,7 +156,19 @@ export function doAbandonClaim(txid: string, nout: number) {
blocking: true,
};
const method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon';
let method;
if (supportToAbandon) {
method = 'support_abandon';
} else if (claimToAbandon) {
const { name: claimName } = claimToAbandon;
method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon';
}
if (!method) {
console.error('No "method" chosen for claim or support abandon');
return;
}
Lbry[method](abandonParams).then(successCallback, errorCallback);
};
}

View file

@ -63,6 +63,7 @@ export function doTotalBalanceSubscribe() {
export function doFetchTransactions() {
return dispatch => {
dispatch(doFetchSupports());
dispatch({
type: ACTIONS.FETCH_TRANSACTIONS_STARTED,
});
@ -80,6 +81,23 @@ export function doFetchTransactions() {
};
}
export function doFetchSupports() {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_SUPPORTS_STARTED,
});
Lbry.support_list().then(results => {
dispatch({
type: ACTIONS.FETCH_SUPPORTS_COMPLETED,
data: {
supports: results,
},
});
});
};
}
export function doGetNewAddress() {
return dispatch => {
dispatch({

View file

@ -1,7 +1,7 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import { handleActions } from 'util/redux-utils';
const reducers = {};
const buildDraftTransaction = () => ({
amount: undefined,
address: undefined,
@ -16,9 +16,10 @@ type ActionResult = {
type WalletState = {
balance: any,
blocks: any,
latestBlock: ?number,
transactions: any,
transactions: { [string]: Transaction },
supports: { [string]: Support },
abandoningSupportsById: { [string]: boolean },
fetchingTransactions: boolean,
gettingNewAddress: boolean,
draftTransaction: any,
@ -41,10 +42,12 @@ type WalletState = {
const defaultState = {
balance: undefined,
totalBalance: undefined,
blocks: {},
latestBlock: undefined,
transactions: {},
fetchingTransactions: false,
supports: {},
fetchingSupports: false,
abandoningSupportsById: {},
gettingNewAddress: false,
draftTransaction: buildDraftTransaction(),
sendingSupport: false,
@ -64,226 +67,250 @@ const defaultState = {
transactionListFilter: 'all',
};
reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = (state: WalletState) =>
Object.assign({}, state, {
fetchingTransactions: true,
});
export const walletReducer = handleActions(
{
[ACTIONS.FETCH_TRANSACTIONS_STARTED]: (state: WalletState) => ({
...state,
fetchingTransactions: true,
}),
reducers[ACTIONS.FETCH_TRANSACTIONS_COMPLETED] = (state: WalletState, action) => {
const byId = Object.assign({}, state.transactions);
[ACTIONS.FETCH_TRANSACTIONS_COMPLETED]: (state: WalletState, action) => {
const byId = { ...state.transactions };
const { transactions } = action.data;
const { transactions } = action.data;
transactions.forEach(transaction => {
byId[transaction.txid] = transaction;
});
transactions.forEach(transaction => {
byId[transaction.txid] = transaction;
});
return {
...state,
transactions: byId,
fetchingTransactions: false,
};
},
return Object.assign({}, state, {
transactions: byId,
fetchingTransactions: false,
});
};
[ACTIONS.FETCH_SUPPORTS_STARTED]: (state: WalletState) => ({
...state,
fetchingSupports: true,
}),
reducers[ACTIONS.GET_NEW_ADDRESS_STARTED] = (state: WalletState) =>
Object.assign({}, state, {
gettingNewAddress: true,
});
[ACTIONS.FETCH_SUPPORTS_COMPLETED]: (state: WalletState, action) => {
const byId = state.supports;
const { supports } = action.data;
reducers[ACTIONS.GET_NEW_ADDRESS_COMPLETED] = (state: WalletState, action) => {
const { address } = action.data;
supports.forEach(support => {
byId[support.txid] = support;
});
// Say no to localStorage!
return Object.assign({}, state, {
gettingNewAddress: false,
receiveAddress: address,
});
};
return { ...state, supports: byId, fetchingSupports: false };
},
reducers[ACTIONS.UPDATE_BALANCE] = (state: WalletState, action) =>
Object.assign({}, state, {
balance: action.data.balance,
});
[ACTIONS.ABANDON_SUPPORT_STARTED]: (state: WalletState, action: any): WalletState => {
const { txid }: { txid: string } = action.data;
const abandoningById = state.abandoningSupportsById;
reducers[ACTIONS.UPDATE_TOTAL_BALANCE] = (state: WalletState, action) =>
Object.assign({}, state, {
totalBalance: action.data.totalBalance,
});
abandoningById[txid] = true;
reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED] = (state: WalletState) =>
Object.assign({}, state, {
checkingAddressOwnership: true,
});
return {
...state,
abandoningSupportsById: abandoningById,
};
},
reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED] = (state: WalletState) =>
Object.assign({}, state, {
checkingAddressOwnership: false,
});
[ACTIONS.ABANDON_SUPPORT_COMPLETED]: (state: WalletState, action: any): WalletState => {
const { txid }: { txid: string } = action.data;
const byId = state.supports;
const abandoningById = state.abandoningSupportsById;
reducers[ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT] = (state: WalletState, action) => {
const oldDraft = state.draftTransaction;
const newDraft = Object.assign({}, oldDraft, {
amount: parseFloat(action.data.amount),
});
delete abandoningById[txid];
delete byId[txid];
return Object.assign({}, state, {
draftTransaction: newDraft,
});
};
return {
...state,
supports: byId,
abandoningSupportsById: abandoningById,
};
},
reducers[ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS] = (state: WalletState, action) => {
const oldDraft = state.draftTransaction;
const newDraft = Object.assign({}, oldDraft, {
address: action.data.address,
});
[ACTIONS.GET_NEW_ADDRESS_STARTED]: (state: WalletState) => ({
...state,
gettingNewAddress: true,
}),
return Object.assign({}, state, {
draftTransaction: newDraft,
});
};
[ACTIONS.GET_NEW_ADDRESS_COMPLETED]: (state: WalletState, action) => {
const { address } = action.data;
reducers[ACTIONS.SEND_TRANSACTION_STARTED] = (state: WalletState) => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: true,
});
return { ...state, gettingNewAddress: false, receiveAddress: address };
},
return Object.assign({}, state, {
draftTransaction: newDraftTransaction,
});
};
[ACTIONS.UPDATE_BALANCE]: (state: WalletState, action) => ({
...state,
balance: action.data.balance,
}),
reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = (state: WalletState) =>
Object.assign({}, state, {
draftTransaction: buildDraftTransaction(),
});
[ACTIONS.UPDATE_TOTAL_BALANCE]: (state: WalletState, action) => ({
...state,
totalBalance: action.data.totalBalance,
}),
reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state: WalletState, action) => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: false,
error: action.data.error,
});
[ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED]: (state: WalletState) => ({
...state,
checkingAddressOwnership: true,
}),
return Object.assign({}, state, {
draftTransaction: newDraftTransaction,
});
};
[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED]: (state: WalletState) => ({
...state,
checkingAddressOwnership: false,
}),
reducers[ACTIONS.SUPPORT_TRANSACTION_STARTED] = (state: WalletState) =>
Object.assign({}, state, {
sendingSupport: true,
});
[ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT]: (state: WalletState, action) => {
const oldDraft = state.draftTransaction;
const newDraft = { ...oldDraft, amount: parseFloat(action.data.amount) };
reducers[ACTIONS.SUPPORT_TRANSACTION_COMPLETED] = (state: WalletState) =>
Object.assign({}, state, {
sendingSupport: false,
});
return { ...state, draftTransaction: newDraft };
},
reducers[ACTIONS.SUPPORT_TRANSACTION_FAILED] = (state: WalletState, action) =>
Object.assign({}, state, {
error: action.data.error,
sendingSupport: false,
});
[ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS]: (state: WalletState, action) => {
const oldDraft = state.draftTransaction;
const newDraft = { ...oldDraft, address: action.data.address };
reducers[ACTIONS.WALLET_STATUS_COMPLETED] = (state: WalletState, action) =>
Object.assign({}, state, {
walletIsEncrypted: action.result,
});
return { ...state, draftTransaction: newDraft };
},
reducers[ACTIONS.WALLET_ENCRYPT_START] = (state: WalletState) =>
Object.assign({}, state, {
walletEncryptPending: true,
walletEncryptSucceded: null,
walletEncryptResult: null,
});
[ACTIONS.SEND_TRANSACTION_STARTED]: (state: WalletState) => {
const newDraftTransaction = { ...state.draftTransaction, sending: true };
reducers[ACTIONS.WALLET_ENCRYPT_COMPLETED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: true,
walletEncryptResult: action.result,
});
return { ...state, draftTransaction: newDraftTransaction };
},
reducers[ACTIONS.WALLET_ENCRYPT_FAILED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletEncryptPending: false,
walletEncryptSucceded: false,
walletEncryptResult: action.result,
});
[ACTIONS.SEND_TRANSACTION_COMPLETED]: (state: WalletState) =>
Object.assign({}, state, {
draftTransaction: buildDraftTransaction(),
}),
reducers[ACTIONS.WALLET_DECRYPT_START] = (state: WalletState) =>
Object.assign({}, state, {
walletDecryptPending: true,
walletDecryptSucceded: null,
walletDecryptResult: null,
});
[ACTIONS.SEND_TRANSACTION_FAILED]: (state: WalletState, action) => {
const newDraftTransaction = Object.assign({}, state.draftTransaction, {
sending: false,
error: action.data.error,
});
reducers[ACTIONS.WALLET_DECRYPT_COMPLETED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: true,
walletDecryptResult: action.result,
});
return { ...state, draftTransaction: newDraftTransaction };
},
reducers[ACTIONS.WALLET_DECRYPT_FAILED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletDecryptPending: false,
walletDecryptSucceded: false,
walletDecryptResult: action.result,
});
[ACTIONS.SUPPORT_TRANSACTION_STARTED]: (state: WalletState) => ({
...state,
sendingSupport: true,
}),
reducers[ACTIONS.WALLET_UNLOCK_START] = (state: WalletState) =>
Object.assign({}, state, {
walletUnlockPending: true,
walletUnlockSucceded: null,
walletUnlockResult: null,
});
[ACTIONS.SUPPORT_TRANSACTION_COMPLETED]: (state: WalletState) => ({
...state,
sendingSupport: false,
}),
reducers[ACTIONS.WALLET_UNLOCK_COMPLETED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: true,
walletUnlockResult: action.result,
});
[ACTIONS.SUPPORT_TRANSACTION_FAILED]: (state: WalletState, action) => ({
...state,
error: action.data.error,
sendingSupport: false,
}),
reducers[ACTIONS.WALLET_UNLOCK_FAILED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletUnlockPending: false,
walletUnlockSucceded: false,
walletUnlockResult: action.result,
});
[ACTIONS.WALLET_STATUS_COMPLETED]: (state: WalletState, action) => ({
...state,
walletIsEncrypted: action.result,
}),
reducers[ACTIONS.WALLET_LOCK_START] = (state: WalletState) =>
Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: null,
walletLockResult: null,
});
[ACTIONS.WALLET_ENCRYPT_START]: (state: WalletState) => ({
...state,
walletEncryptPending: true,
walletEncryptSucceded: null,
walletEncryptResult: null,
}),
reducers[ACTIONS.WALLET_LOCK_COMPLETED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: true,
walletLockResult: action.result,
});
[ACTIONS.WALLET_ENCRYPT_COMPLETED]: (state: WalletState, action: ActionResult) => ({
...state,
walletEncryptPending: false,
walletEncryptSucceded: true,
walletEncryptResult: action.result,
}),
reducers[ACTIONS.WALLET_LOCK_FAILED] = (state: WalletState, action: ActionResult) =>
Object.assign({}, state, {
walletLockPending: false,
walletLockSucceded: false,
walletLockResult: action.result,
});
[ACTIONS.WALLET_ENCRYPT_FAILED]: (state: WalletState, action: ActionResult) => ({
...state,
walletEncryptPending: false,
walletEncryptSucceded: false,
walletEncryptResult: action.result,
}),
reducers[ACTIONS.SET_TRANSACTION_LIST_FILTER] = (state: WalletState, action: { data: string }) =>
Object.assign({}, state, {
transactionListFilter: action.data,
});
[ACTIONS.WALLET_DECRYPT_START]: (state: WalletState) => ({
...state,
walletDecryptPending: true,
walletDecryptSucceded: null,
walletDecryptResult: null,
}),
reducers[ACTIONS.UPDATE_CURRENT_HEIGHT] = (state: WalletState, action: { data: number }) =>
Object.assign({}, state, {
latestBlock: action.data,
});
[ACTIONS.WALLET_DECRYPT_COMPLETED]: (state: WalletState, action: ActionResult) => ({
...state,
walletDecryptPending: false,
walletDecryptSucceded: true,
walletDecryptResult: action.result,
}),
export function walletReducer(state: WalletState = defaultState, action: ActionResult) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}
[ACTIONS.WALLET_DECRYPT_FAILED]: (state: WalletState, action: ActionResult) => ({
...state,
walletDecryptPending: false,
walletDecryptSucceded: false,
walletDecryptResult: action.result,
}),
[ACTIONS.WALLET_UNLOCK_START]: (state: WalletState) => ({
...state,
walletUnlockPending: true,
walletUnlockSucceded: null,
walletUnlockResult: null,
}),
[ACTIONS.WALLET_UNLOCK_COMPLETED]: (state: WalletState, action: ActionResult) => ({
...state,
walletUnlockPending: false,
walletUnlockSucceded: true,
walletUnlockResult: action.result,
}),
[ACTIONS.WALLET_UNLOCK_FAILED]: (state: WalletState, action: ActionResult) => ({
...state,
walletUnlockPending: false,
walletUnlockSucceded: false,
walletUnlockResult: action.result,
}),
[ACTIONS.WALLET_LOCK_START]: (state: WalletState) => ({
...state,
walletLockPending: false,
walletLockSucceded: null,
walletLockResult: null,
}),
[ACTIONS.WALLET_LOCK_COMPLETED]: (state: WalletState, action: ActionResult) => ({
...state,
walletLockPending: false,
walletLockSucceded: true,
walletLockResult: action.result,
}),
[ACTIONS.WALLET_LOCK_FAILED]: (state: WalletState, action: ActionResult) => ({
...state,
walletLockPending: false,
walletLockSucceded: false,
walletLockResult: action.result,
}),
[ACTIONS.SET_TRANSACTION_LIST_FILTER]: (state: WalletState, action: { data: string }) => ({
...state,
transactionListFilter: action.data,
}),
[ACTIONS.UPDATE_CURRENT_HEIGHT]: (state: WalletState, action: { data: number }) => ({
...state,
latestBlock: action.data,
}),
},
defaultState
);

View file

@ -82,7 +82,12 @@ export const selectTotalBalance = createSelector(
export const selectTransactionsById = createSelector(
selectState,
state => state.transactions
state => state.transactions || {}
);
export const selectSupportsById = createSelector(
selectState,
state => state.supports || {}
);
export const selectTransactionItems = createSelector(