add txo list by params

fix set.slice() error

add txopage reducer

move txo constants to redux

abandon bug

abandon callback
This commit is contained in:
jessop 2020-04-10 08:16:27 -04:00
parent 677dd25643
commit 1e505184dc
11 changed files with 547 additions and 30 deletions

255
dist/bundle.es.js vendored
View file

@ -58,6 +58,10 @@ const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED';
const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED'; const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED'; const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED'; const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
const FETCH_TXO_PAGE_STARTED = 'FETCH_TXO_PAGE_STARTED';
const FETCH_TXO_PAGE_COMPLETED = 'FETCH_TXO_PAGE_COMPLETED';
const FETCH_TXO_PAGE_FAILED = 'FETCH_TXO_PAGE_FAILED';
const UPDATE_TXO_FETCH_PARAMS = 'UPDATE_TXO_FETCH_PARAMS';
const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED'; const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED';
const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED'; const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED';
const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED'; const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED';
@ -328,6 +332,10 @@ var action_types = /*#__PURE__*/Object.freeze({
GET_NEW_ADDRESS_COMPLETED: GET_NEW_ADDRESS_COMPLETED, GET_NEW_ADDRESS_COMPLETED: GET_NEW_ADDRESS_COMPLETED,
FETCH_TRANSACTIONS_STARTED: FETCH_TRANSACTIONS_STARTED, FETCH_TRANSACTIONS_STARTED: FETCH_TRANSACTIONS_STARTED,
FETCH_TRANSACTIONS_COMPLETED: FETCH_TRANSACTIONS_COMPLETED, FETCH_TRANSACTIONS_COMPLETED: FETCH_TRANSACTIONS_COMPLETED,
FETCH_TXO_PAGE_STARTED: FETCH_TXO_PAGE_STARTED,
FETCH_TXO_PAGE_COMPLETED: FETCH_TXO_PAGE_COMPLETED,
FETCH_TXO_PAGE_FAILED: FETCH_TXO_PAGE_FAILED,
UPDATE_TXO_FETCH_PARAMS: UPDATE_TXO_FETCH_PARAMS,
FETCH_SUPPORTS_STARTED: FETCH_SUPPORTS_STARTED, FETCH_SUPPORTS_STARTED: FETCH_SUPPORTS_STARTED,
FETCH_SUPPORTS_COMPLETED: FETCH_SUPPORTS_COMPLETED, FETCH_SUPPORTS_COMPLETED: FETCH_SUPPORTS_COMPLETED,
ABANDON_SUPPORT_STARTED: ABANDON_SUPPORT_STARTED, ABANDON_SUPPORT_STARTED: ABANDON_SUPPORT_STARTED,
@ -749,6 +757,71 @@ var transaction_list = /*#__PURE__*/Object.freeze({
LATEST_PAGE_SIZE: LATEST_PAGE_SIZE LATEST_PAGE_SIZE: LATEST_PAGE_SIZE
}); });
const ACTIVE = 'active'; // spent, active, all
const TYPE = 'type'; // all, payment, support, channel, stream, repost
const SUB_TYPE = 'subtype'; // other, purchase, tip
const PAGE_SIZE$2 = 'page_size';
const PAGE = 'page';
const ALL$1 = 'all';
// dropdown types
const SENT = 'sent';
const RECEIVED = 'received';
const SUPPORT$1 = 'support';
const CHANNEL$2 = 'channel';
const PUBLISH$2 = 'publish';
const REPOST = 'repost';
const DROPDOWN_TYPES = [ALL$1, SENT, RECEIVED, SUPPORT$1, CHANNEL$2, PUBLISH$2, REPOST];
// dropdown subtypes
const TIP$1 = 'tip';
const PURCHASE = 'purchase';
const PAYMENT = 'payment';
const DROPDOWN_SUBTYPES = [ALL$1, TIP$1, PURCHASE, PAYMENT];
// rpc params
const TX_TYPE = 'type'; // = other, stream, repost, channel, support, purchase
const IS_SPENT = 'is_spent';
const IS_NOT_SPENT = 'is_not_spent';
const IS_MY_INPUT = 'is_my_input';
const IS_MY_OUTPUT = 'is_my_output';
const IS_NOT_MY_INPUT = 'is_not_my_input';
const IS_NOT_MY_OUTPUT = 'is_not_my_output'; // use to further distinguish payments to self / from self.
// sdk unique types
const OTHER$1 = 'other';
const STREAM = 'stream';
const PAGE_SIZE_DEFAULT = 20;
var txo_list = /*#__PURE__*/Object.freeze({
ACTIVE: ACTIVE,
TYPE: TYPE,
SUB_TYPE: SUB_TYPE,
PAGE_SIZE: PAGE_SIZE$2,
PAGE: PAGE,
ALL: ALL$1,
SENT: SENT,
RECEIVED: RECEIVED,
SUPPORT: SUPPORT$1,
CHANNEL: CHANNEL$2,
PUBLISH: PUBLISH$2,
REPOST: REPOST,
DROPDOWN_TYPES: DROPDOWN_TYPES,
TIP: TIP$1,
PURCHASE: PURCHASE,
PAYMENT: PAYMENT,
DROPDOWN_SUBTYPES: DROPDOWN_SUBTYPES,
TX_TYPE: TX_TYPE,
IS_SPENT: IS_SPENT,
IS_NOT_SPENT: IS_NOT_SPENT,
IS_MY_INPUT: IS_MY_INPUT,
IS_MY_OUTPUT: IS_MY_OUTPUT,
IS_NOT_MY_INPUT: IS_NOT_MY_INPUT,
IS_NOT_MY_OUTPUT: IS_NOT_MY_OUTPUT,
OTHER: OTHER$1,
STREAM: STREAM,
PAGE_SIZE_DEFAULT: PAGE_SIZE_DEFAULT
});
const SPEECH_STATUS = 'https://spee.ch/api/config/site/publishing'; const SPEECH_STATUS = 'https://spee.ch/api/config/site/publishing';
const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish'; const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish';
@ -1966,6 +2039,18 @@ const selectFilteredTransactions = reselect.createSelector(selectTransactionItem
}); });
}); });
const selectTxoPageParams = reselect.createSelector(selectState$1, state => state.txoFetchParams);
const selectTxoPage = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.items || []);
const selectTxoPageNumber = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.page || 1);
const selectTxoItemCount = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.total_items || 1);
const selectFetchingTxosError = reselect.createSelector(selectState$1, state => state.fetchingTxosError);
const selectIsFetchingTxos = reselect.createSelector(selectState$1, state => state.fetchingTxos);
const makeSelectFilteredTransactionsForPage = (page = 1) => reselect.createSelector(selectFilteredTransactions, filteredTransactions => { const makeSelectFilteredTransactionsForPage = (page = 1) => reselect.createSelector(selectFilteredTransactions, filteredTransactions => {
const start = (Number(page) - 1) * Number(PAGE_SIZE$1); const start = (Number(page) - 1) * Number(PAGE_SIZE$1);
const end = Number(page) * Number(PAGE_SIZE$1); const end = Number(page) * Number(PAGE_SIZE$1);
@ -2591,6 +2676,40 @@ function doFetchTransactions(page = 1, pageSize = 99999) {
}; };
} }
function doFetchTxoPage() {
return (dispatch, getState) => {
dispatch({
type: FETCH_TXO_PAGE_STARTED
});
const state = getState();
const queryParams = selectTxoPageParams(state);
lbryProxy.txo_list(queryParams).then(res => {
dispatch({
type: FETCH_TXO_PAGE_COMPLETED,
data: res
});
}).catch(e => {
dispatch({
type: FETCH_TXO_PAGE_COMPLETED,
data: e.message
});
});
};
}
function doUpdateTxoPageParams(params) {
return dispatch => {
dispatch({
type: UPDATE_TXO_FETCH_PARAMS,
data: params
});
dispatch(doFetchTxoPage());
};
}
function doFetchSupports(page = 1, pageSize = 99999) { function doFetchSupports(page = 1, pageSize = 99999) {
return dispatch => { return dispatch => {
dispatch({ dispatch({
@ -3081,6 +3200,77 @@ function doFetchClaimListMine(page = 1, pageSize = 99999, resolve = true) {
}; };
} }
function doAbandonTxo(txo, cb) {
return dispatch => {
const isClaim = txo.type === 'claim';
const isSupport = txo.type === 'support' && txo.is_my_input === true;
const isTip = txo.type === 'support' && txo.is_my_input === false;
const data = isClaim ? { claimId: txo.claim_id } : { outpoint: `${txo.txid}:${txo.nout}` };
const startedActionType = isClaim ? ABANDON_CLAIM_STARTED : ABANDON_SUPPORT_STARTED;
const completedActionType = isClaim ? ABANDON_CLAIM_SUCCEEDED : ABANDON_SUPPORT_COMPLETED;
dispatch({
type: startedActionType,
data
});
const errorCallback = () => {
dispatch(doToast({
message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip',
isError: true
}));
};
const successCallback = () => {
dispatch({
type: completedActionType,
data
});
let abandonMessage;
if (isClaim) {
abandonMessage = 'Successfully abandoned your claim.';
} else if (isSupport) {
abandonMessage = 'Successfully abandoned your support.';
} else {
abandonMessage = 'Successfully unlocked your tip!';
}
if (cb) cb();
dispatch(doToast({
message: abandonMessage
}));
};
const abandonParams = {
blocking: true
};
if (isClaim) {
abandonParams['claim_id'] = txo.claim_id;
} else {
abandonParams['txid'] = txo.txid;
abandonParams['nout'] = txo.nout;
}
let method;
if (isSupport || isTip) {
method = 'support_abandon';
} else if (isClaim) {
const { normalized_name: claimName } = txo;
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);
};
}
function doAbandonClaim(txid, nout) { function doAbandonClaim(txid, nout) {
const outpoint = `${txid}:${nout}`; const outpoint = `${txid}:${nout}`;
@ -3134,13 +3324,7 @@ function doAbandonClaim(txid, nout) {
dispatch(doToast({ dispatch(doToast({
message: abandonMessage message: abandonMessage
})); }));
dispatch(doFetchTxoPage());
// After abandoning, fetch transactions to show the new abandon transaction
// Only fetch the latest few transactions since we don't care about old ones
// Not very robust, but better than calling the entire list for large wallets
const page = 1;
const pageSize = 10;
dispatch(doFetchTransactions(page, pageSize));
}; };
const abandonParams = { const abandonParams = {
@ -4825,7 +5009,7 @@ reducers[FETCH_CLAIM_LIST_MINE_COMPLETED] = (state, action) => {
return Object.assign({}, state, { return Object.assign({}, state, {
isFetchingClaimListMine: false, isFetchingClaimListMine: false,
myClaims: myClaimIds, myClaims: Array.from(myClaimIds),
byId, byId,
claimsByUri: byUri, claimsByUri: byUri,
pendingById pendingById
@ -4880,8 +5064,8 @@ reducers[FETCH_CHANNEL_LIST_COMPLETED] = (state, action) => {
claimsByUri: byUri, claimsByUri: byUri,
channelClaimCounts, channelClaimCounts,
fetchingMyChannels: false, fetchingMyChannels: false,
myChannelClaims, myChannelClaims: Array.from(myChannelClaims),
myClaims: myClaimIds myClaims: Array.from(myClaimIds)
}); });
}; };
@ -4960,6 +5144,7 @@ reducers[ABANDON_CLAIM_SUCCEEDED] = (state, action) => {
const { claimId } = action.data; const { claimId } = action.data;
const byId = Object.assign({}, state.byId); const byId = Object.assign({}, state.byId);
const newMyClaims = state.myClaims ? state.myClaims.slice() : []; const newMyClaims = state.myClaims ? state.myClaims.slice() : [];
const newMyChannelClaims = state.myChannelClaims ? state.myChannelClaims.slice() : [];
const claimsByUri = Object.assign({}, state.claimsByUri); const claimsByUri = Object.assign({}, state.claimsByUri);
Object.keys(claimsByUri).forEach(uri => { Object.keys(claimsByUri).forEach(uri => {
@ -4967,11 +5152,14 @@ reducers[ABANDON_CLAIM_SUCCEEDED] = (state, action) => {
delete claimsByUri[uri]; delete claimsByUri[uri];
} }
}); });
const myClaims = newMyClaims.filter(i => i.claim_id && i.claim_id !== claimId); const myClaims = newMyClaims.filter(i => i !== claimId);
const myChannelClaims = newMyChannelClaims.filter(i => i !== claimId);
delete byId[claimId]; delete byId[claimId];
return Object.assign({}, state, { return Object.assign({}, state, {
myClaims, myClaims,
myChannelClaims,
byId, byId,
claimsByUri claimsByUri
}); });
@ -4995,7 +5183,7 @@ reducers[CREATE_CHANNEL_COMPLETED] = (state, action) => {
return Object.assign({}, state, { return Object.assign({}, state, {
byId, byId,
pendingById, pendingById,
myChannelClaims, myChannelClaims: Array.from(myChannelClaims),
creatingChannel: false creatingChannel: false
}); });
}; };
@ -5907,6 +6095,7 @@ const defaultState$a = {
latestBlock: undefined, latestBlock: undefined,
transactions: {}, transactions: {},
fetchingTransactions: false, fetchingTransactions: false,
fetchingTransactionsError: undefined,
supports: {}, supports: {},
fetchingSupports: false, fetchingSupports: false,
abandoningSupportsByOutpoint: {}, abandoningSupportsByOutpoint: {},
@ -5928,6 +6117,10 @@ const defaultState$a = {
walletLockResult: null, walletLockResult: null,
transactionListFilter: 'all', transactionListFilter: 'all',
walletReconnecting: false, walletReconnecting: false,
txoFetchParams: {},
txoPage: {},
fetchingTxos: false,
fetchingTxosError: undefined,
pendingSupportTransactions: {}, pendingSupportTransactions: {},
abandonClaimSupportError: undefined abandonClaimSupportError: undefined
}; };
@ -5951,6 +6144,34 @@ const walletReducer = handleActions({
}); });
}, },
[FETCH_TXO_PAGE_STARTED]: state => {
return _extends$i({}, state, {
fetchingTxos: true,
fetchingTxosError: undefined
});
},
[FETCH_TXO_PAGE_COMPLETED]: (state, action) => {
return _extends$i({}, state, {
txoPage: action.data,
fetchingTxos: false
});
},
[FETCH_TXO_PAGE_FAILED]: (state, action) => {
return _extends$i({}, state, {
txoPage: {},
fetchingTxos: false,
fetchingTxosError: action.data
});
},
[UPDATE_TXO_FETCH_PARAMS]: (state, action) => {
return _extends$i({}, state, {
txoFetchParams: action.data
});
},
[FETCH_SUPPORTS_STARTED]: state => _extends$i({}, state, { [FETCH_SUPPORTS_STARTED]: state => _extends$i({}, state, {
fetchingSupports: true fetchingSupports: true
}), }),
@ -6344,6 +6565,7 @@ exports.SORT_OPTIONS = sort_options;
exports.SPEECH_URLS = speech_urls; exports.SPEECH_URLS = speech_urls;
exports.THUMBNAIL_STATUSES = thumbnail_upload_statuses; exports.THUMBNAIL_STATUSES = thumbnail_upload_statuses;
exports.TRANSACTIONS = transaction_types; exports.TRANSACTIONS = transaction_types;
exports.TXO_LIST = txo_list;
exports.TX_LIST = transaction_list; exports.TX_LIST = transaction_list;
exports.apiCall = apiCall; exports.apiCall = apiCall;
exports.batchActions = batchActions; exports.batchActions = batchActions;
@ -6357,6 +6579,7 @@ exports.convertToShareLink = convertToShareLink;
exports.createNormalizedClaimSearchKey = createNormalizedClaimSearchKey; exports.createNormalizedClaimSearchKey = createNormalizedClaimSearchKey;
exports.creditsToString = creditsToString; exports.creditsToString = creditsToString;
exports.doAbandonClaim = doAbandonClaim; exports.doAbandonClaim = doAbandonClaim;
exports.doAbandonTxo = doAbandonTxo;
exports.doAddTag = doAddTag; exports.doAddTag = doAddTag;
exports.doBalanceSubscribe = doBalanceSubscribe; exports.doBalanceSubscribe = doBalanceSubscribe;
exports.doBlurSearchInput = doBlurSearchInput; exports.doBlurSearchInput = doBlurSearchInput;
@ -6383,6 +6606,7 @@ exports.doFetchClaimsByChannel = doFetchClaimsByChannel;
exports.doFetchFileInfo = doFetchFileInfo; exports.doFetchFileInfo = doFetchFileInfo;
exports.doFetchFileInfosAndPublishedClaims = doFetchFileInfosAndPublishedClaims; exports.doFetchFileInfosAndPublishedClaims = doFetchFileInfosAndPublishedClaims;
exports.doFetchTransactions = doFetchTransactions; exports.doFetchTransactions = doFetchTransactions;
exports.doFetchTxoPage = doFetchTxoPage;
exports.doFileGet = doFileGet; exports.doFileGet = doFileGet;
exports.doFileList = doFileList; exports.doFileList = doFileList;
exports.doFocusSearchInput = doFocusSearchInput; exports.doFocusSearchInput = doFocusSearchInput;
@ -6416,6 +6640,7 @@ exports.doUpdateChannel = doUpdateChannel;
exports.doUpdatePublishForm = doUpdatePublishForm; exports.doUpdatePublishForm = doUpdatePublishForm;
exports.doUpdateSearchOptions = doUpdateSearchOptions; exports.doUpdateSearchOptions = doUpdateSearchOptions;
exports.doUpdateSearchQuery = doUpdateSearchQuery; exports.doUpdateSearchQuery = doUpdateSearchQuery;
exports.doUpdateTxoPageParams = doUpdateTxoPageParams;
exports.doUploadThumbnail = doUploadThumbnail; exports.doUploadThumbnail = doUploadThumbnail;
exports.doWalletDecrypt = doWalletDecrypt; exports.doWalletDecrypt = doWalletDecrypt;
exports.doWalletEncrypt = doWalletEncrypt; exports.doWalletEncrypt = doWalletEncrypt;
@ -6529,6 +6754,7 @@ exports.selectFailedPurchaseUris = selectFailedPurchaseUris;
exports.selectFetchingClaimSearch = selectFetchingClaimSearch; exports.selectFetchingClaimSearch = selectFetchingClaimSearch;
exports.selectFetchingClaimSearchByQuery = selectFetchingClaimSearchByQuery; exports.selectFetchingClaimSearchByQuery = selectFetchingClaimSearchByQuery;
exports.selectFetchingMyChannels = selectFetchingMyChannels; exports.selectFetchingMyChannels = selectFetchingMyChannels;
exports.selectFetchingTxosError = selectFetchingTxosError;
exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint;
exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileInfosDownloaded = selectFileInfosDownloaded;
exports.selectFileListDownloadedSort = selectFileListDownloadedSort; exports.selectFileListDownloadedSort = selectFileListDownloadedSort;
@ -6543,6 +6769,7 @@ exports.selectIsFetchingClaimListMine = selectIsFetchingClaimListMine;
exports.selectIsFetchingFileList = selectIsFetchingFileList; exports.selectIsFetchingFileList = selectIsFetchingFileList;
exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileListDownloadedOrPublished; exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileListDownloadedOrPublished;
exports.selectIsFetchingTransactions = selectIsFetchingTransactions; exports.selectIsFetchingTransactions = selectIsFetchingTransactions;
exports.selectIsFetchingTxos = selectIsFetchingTxos;
exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris; exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris;
exports.selectIsSearching = selectIsSearching; exports.selectIsSearching = selectIsSearching;
exports.selectIsSendingSupport = selectIsSendingSupport; exports.selectIsSendingSupport = selectIsSendingSupport;
@ -6590,6 +6817,10 @@ exports.selectTotalSupports = selectTotalSupports;
exports.selectTransactionItems = selectTransactionItems; exports.selectTransactionItems = selectTransactionItems;
exports.selectTransactionListFilter = selectTransactionListFilter; exports.selectTransactionListFilter = selectTransactionListFilter;
exports.selectTransactionsById = selectTransactionsById; exports.selectTransactionsById = selectTransactionsById;
exports.selectTxoItemCount = selectTxoItemCount;
exports.selectTxoPage = selectTxoPage;
exports.selectTxoPageNumber = selectTxoPageNumber;
exports.selectTxoPageParams = selectTxoPageParams;
exports.selectUnfollowedTags = selectUnfollowedTags; exports.selectUnfollowedTags = selectUnfollowedTags;
exports.selectUpdateChannelError = selectUpdateChannelError; exports.selectUpdateChannelError = selectUpdateChannelError;
exports.selectUpdatingChannel = selectUpdatingChannel; exports.selectUpdatingChannel = selectUpdatingChannel;

24
dist/flow-typed/Txo.js vendored Normal file
View file

@ -0,0 +1,24 @@
declare type Txo = {
amount: number,
claim_id: string,
normalized_name: string,
nout: number,
txid: string,
type: string,
value_type: string,
timestamp: number,
is_my_output: boolean,
is_my_input: boolean,
is_spent: boolean,
};
declare type TxoListParams = {
page: number,
page_size: number,
type: string,
is_my_input?: boolean,
is_my_output?: boolean,
is_not_my_input?: boolean,
is_not_my_output?: boolean,
is_spent?: boolean,
}

24
flow-typed/Txo.js vendored Normal file
View file

@ -0,0 +1,24 @@
declare type Txo = {
amount: number,
claim_id: string,
normalized_name: string,
nout: number,
txid: string,
type: string,
value_type: string,
timestamp: number,
is_my_output: boolean,
is_my_input: boolean,
is_spent: boolean,
};
declare type TxoListParams = {
page: number,
page_size: number,
type: string,
is_my_input?: boolean,
is_my_output?: boolean,
is_not_my_input?: boolean,
is_not_my_output?: boolean,
is_spent?: boolean,
}

View file

@ -35,6 +35,10 @@ export const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED';
export const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED'; export const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
export const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED'; export const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED'; export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
export const FETCH_TXO_PAGE_STARTED = 'FETCH_TXO_PAGE_STARTED';
export const FETCH_TXO_PAGE_COMPLETED = 'FETCH_TXO_PAGE_COMPLETED';
export const FETCH_TXO_PAGE_FAILED = 'FETCH_TXO_PAGE_FAILED';
export const UPDATE_TXO_FETCH_PARAMS = 'UPDATE_TXO_FETCH_PARAMS';
export const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED'; export const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED';
export const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED'; export const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED';
export const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED'; export const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED';

35
src/constants/txo_list.js Normal file
View file

@ -0,0 +1,35 @@
export const ACTIVE = 'active'; // spent, active, all
export const TYPE = 'type'; // all, payment, support, channel, stream, repost
export const SUB_TYPE = 'subtype'; // other, purchase, tip
export const PAGE_SIZE = 'page_size';
export const PAGE = 'page';
export const ALL = 'all';
// dropdown types
export const SENT = 'sent';
export const RECEIVED = 'received';
export const SUPPORT = 'support';
export const CHANNEL = 'channel';
export const PUBLISH = 'publish';
export const REPOST = 'repost';
export const DROPDOWN_TYPES = [ALL, SENT, RECEIVED, SUPPORT, CHANNEL, PUBLISH, REPOST];
// dropdown subtypes
export const TIP = 'tip';
export const PURCHASE = 'purchase';
export const PAYMENT = 'payment';
export const DROPDOWN_SUBTYPES = [ALL, TIP, PURCHASE, PAYMENT];
// rpc params
export const TX_TYPE = 'type'; // = other, stream, repost, channel, support, purchase
export const IS_SPENT = 'is_spent';
export const IS_NOT_SPENT = 'is_not_spent';
export const IS_MY_INPUT = 'is_my_input';
export const IS_MY_OUTPUT = 'is_my_output';
export const IS_NOT_MY_INPUT = 'is_not_my_input';
export const IS_NOT_MY_OUTPUT = 'is_not_my_output'; // use to further distinguish payments to self / from self.
// sdk unique types
export const OTHER = 'other';
export const STREAM = 'stream';
export const PAGE_SIZE_DEFAULT = 20;

View file

@ -7,6 +7,7 @@ import * as SORT_OPTIONS from 'constants/sort_options';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import * as TRANSACTIONS from 'constants/transaction_types'; import * as TRANSACTIONS from 'constants/transaction_types';
import * as TX_LIST from 'constants/transaction_list'; import * as TX_LIST from 'constants/transaction_list';
import * as TXO_LIST from 'constants/txo_list';
import * as SPEECH_URLS from 'constants/speech_urls'; import * as SPEECH_URLS from 'constants/speech_urls';
import * as DAEMON_SETTINGS from 'constants/daemon_settings'; import * as DAEMON_SETTINGS from 'constants/daemon_settings';
import * as SHARED_PREFERENCES from 'constants/shared_preferences'; import * as SHARED_PREFERENCES from 'constants/shared_preferences';
@ -27,6 +28,7 @@ export {
DAEMON_SETTINGS, DAEMON_SETTINGS,
TRANSACTIONS, TRANSACTIONS,
TX_LIST, TX_LIST,
TXO_LIST,
SORT_OPTIONS, SORT_OPTIONS,
PAGES, PAGES,
DEFAULT_KNOWN_TAGS, DEFAULT_KNOWN_TAGS,
@ -60,6 +62,7 @@ export {
doFetchClaimsByChannel, doFetchClaimsByChannel,
doFetchClaimListMine, doFetchClaimListMine,
doAbandonClaim, doAbandonClaim,
doAbandonTxo,
doResolveUris, doResolveUris,
doResolveUri, doResolveUri,
doFetchChannelListMine, doFetchChannelListMine,
@ -106,6 +109,8 @@ export {
doUpdateBalance, doUpdateBalance,
doBalanceSubscribe, doBalanceSubscribe,
doFetchTransactions, doFetchTransactions,
doFetchTxoPage,
doUpdateTxoPageParams,
doGetNewAddress, doGetNewAddress,
doCheckAddressIsMine, doCheckAddressIsMine,
doSendDraftTransaction, doSendDraftTransaction,
@ -327,6 +332,12 @@ export {
selectWalletUnlockResult, selectWalletUnlockResult,
selectTransactionListFilter, selectTransactionListFilter,
selectFilteredTransactions, selectFilteredTransactions,
selectTxoPageParams,
selectTxoPage,
selectTxoPageNumber,
selectTxoItemCount,
selectIsFetchingTxos,
selectFetchingTxosError,
makeSelectLatestTransactions, makeSelectLatestTransactions,
makeSelectFilteredTransactionsForPage, makeSelectFilteredTransactionsForPage,
selectFilteredTransactionCount, selectFilteredTransactionCount,

View file

@ -9,7 +9,7 @@ import {
selectClaimsByUri, selectClaimsByUri,
selectMyChannelClaims, selectMyChannelClaims,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
import { doFetchTransactions } from 'redux/actions/wallet'; import { doFetchTxoPage } from 'redux/actions/wallet';
import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
import { creditsToString } from 'util/format-credits'; import { creditsToString } from 'util/format-credits';
import { batchActions } from 'util/batch-actions'; import { batchActions } from 'util/batch-actions';
@ -120,6 +120,89 @@ export function doFetchClaimListMine(
}; };
} }
export function doAbandonTxo(txo: Txo, cb: any => void) {
return (dispatch: Dispatch) => {
const isClaim = txo.type === 'claim';
const isSupport = txo.type === 'support' && txo.is_my_input === true;
const isTip = txo.type === 'support' && txo.is_my_input === false;
const data = isClaim ? { claimId: txo.claim_id } : { outpoint: `${txo.txid}:${txo.nout}` };
const startedActionType = isClaim
? ACTIONS.ABANDON_CLAIM_STARTED
: ACTIONS.ABANDON_SUPPORT_STARTED;
const completedActionType = isClaim
? ACTIONS.ABANDON_CLAIM_SUCCEEDED
: ACTIONS.ABANDON_SUPPORT_COMPLETED;
dispatch({
type: startedActionType,
data,
});
const errorCallback = () => {
dispatch(
doToast({
message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip',
isError: true,
})
);
};
const successCallback = () => {
dispatch({
type: completedActionType,
data,
});
let abandonMessage;
if (isClaim) {
abandonMessage = 'Successfully abandoned your claim.';
} else if (isSupport) {
abandonMessage = 'Successfully abandoned your support.';
} else {
abandonMessage = 'Successfully unlocked your tip!';
}
if (cb) cb();
dispatch(
doToast({
message: abandonMessage,
})
);
};
const abandonParams: {
claim_id?: string,
txid?: string,
nout?: number,
} = {
blocking: true,
};
if (isClaim) {
abandonParams['claim_id'] = txo.claim_id;
} else {
abandonParams['txid'] = txo.txid;
abandonParams['nout'] = txo.nout;
}
let method;
if (isSupport || isTip) {
method = 'support_abandon';
} else if (isClaim) {
const { normalized_name: claimName } = txo;
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);
};
}
export function doAbandonClaim(txid: string, nout: number) { export function doAbandonClaim(txid: string, nout: number) {
const outpoint = `${txid}:${nout}`; const outpoint = `${txid}:${nout}`;
@ -183,13 +266,7 @@ export function doAbandonClaim(txid: string, nout: number) {
message: abandonMessage, message: abandonMessage,
}) })
); );
dispatch(doFetchTxoPage());
// After abandoning, fetch transactions to show the new abandon transaction
// Only fetch the latest few transactions since we don't care about old ones
// Not very robust, but better than calling the entire list for large wallets
const page = 1;
const pageSize = 10;
dispatch(doFetchTransactions(page, pageSize));
}; };
const abandonParams = { const abandonParams = {

View file

@ -1,7 +1,7 @@
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import Lbry from 'lbry'; import Lbry from 'lbry';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import { selectBalance, selectPendingSupportTransactions } from 'redux/selectors/wallet'; import { selectBalance, selectPendingSupportTransactions, selectTxoPageParams } from 'redux/selectors/wallet';
import { creditsToString } from 'util/format-credits'; import { creditsToString } from 'util/format-credits';
import { selectMyClaimsRaw } from 'redux/selectors/claims'; import { selectMyClaimsRaw } from 'redux/selectors/claims';
import { doFetchChannelListMine, doFetchClaimListMine } from 'redux/actions/claims'; import { doFetchChannelListMine, doFetchClaimListMine } from 'redux/actions/claims';
@ -72,6 +72,42 @@ export function doFetchTransactions(page = 1, pageSize = 99999) {
}; };
} }
export function doFetchTxoPage() {
return (dispatch, getState) => {
dispatch({
type: ACTIONS.FETCH_TXO_PAGE_STARTED,
});
const state = getState();
const queryParams = selectTxoPageParams(state);
Lbry.txo_list(queryParams)
.then(res => {
dispatch({
type: ACTIONS.FETCH_TXO_PAGE_COMPLETED,
data: res,
});
})
.catch(e => {
dispatch({
type: ACTIONS.FETCH_TXO_PAGE_COMPLETED,
data: e.message,
});
});
};
}
export function doUpdateTxoPageParams(params: TxoListParams) {
return dispatch => {
dispatch({
type: ACTIONS.UPDATE_TXO_FETCH_PARAMS,
data: params,
});
dispatch(doFetchTxoPage());
};
}
export function doFetchSupports(page = 1, pageSize = 99999) { export function doFetchSupports(page = 1, pageSize = 99999) {
return dispatch => { return dispatch => {
dispatch({ dispatch({
@ -432,6 +468,7 @@ export function doWalletStatus() {
}; };
} }
export function doSetTransactionListFilter(filterOption) { export function doSetTransactionListFilter(filterOption) {
return { return {
type: ACTIONS.SET_TRANSACTION_LIST_FILTER, type: ACTIONS.SET_TRANSACTION_LIST_FILTER,

View file

@ -18,8 +18,8 @@ type State = {
byId: { [string]: Claim }, byId: { [string]: Claim },
resolvingUris: Array<string>, resolvingUris: Array<string>,
pendingById: { [string]: Claim }, pendingById: { [string]: Claim },
myClaims: ?Array<Claim>, myClaims: ?Array<string>,
myChannelClaims: ?Set<string>, myChannelClaims: ?Array<string>,
abandoningById: { [string]: boolean }, abandoningById: { [string]: boolean },
fetchingChannelClaims: { [string]: number }, fetchingChannelClaims: { [string]: number },
fetchingMyChannels: boolean, fetchingMyChannels: boolean,
@ -198,7 +198,7 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any):
return Object.assign({}, state, { return Object.assign({}, state, {
isFetchingClaimListMine: false, isFetchingClaimListMine: false,
myClaims: myClaimIds, myClaims: Array.from(myClaimIds),
byId, byId,
claimsByUri: byUri, claimsByUri: byUri,
pendingById, pendingById,
@ -255,8 +255,8 @@ reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state: State, action: any): St
claimsByUri: byUri, claimsByUri: byUri,
channelClaimCounts, channelClaimCounts,
fetchingMyChannels: false, fetchingMyChannels: false,
myChannelClaims, myChannelClaims: Array.from(myChannelClaims),
myClaims: myClaimIds, myClaims: Array.from(myClaimIds),
}); });
}; };
@ -342,6 +342,7 @@ reducers[ACTIONS.ABANDON_CLAIM_SUCCEEDED] = (state: State, action: any): State =
const { claimId }: { claimId: string } = action.data; const { claimId }: { claimId: string } = action.data;
const byId = Object.assign({}, state.byId); const byId = Object.assign({}, state.byId);
const newMyClaims = state.myClaims ? state.myClaims.slice() : []; const newMyClaims = state.myClaims ? state.myClaims.slice() : [];
const newMyChannelClaims = state.myChannelClaims ? state.myChannelClaims.slice() : [];
const claimsByUri = Object.assign({}, state.claimsByUri); const claimsByUri = Object.assign({}, state.claimsByUri);
Object.keys(claimsByUri).forEach(uri => { Object.keys(claimsByUri).forEach(uri => {
@ -349,11 +350,14 @@ reducers[ACTIONS.ABANDON_CLAIM_SUCCEEDED] = (state: State, action: any): State =
delete claimsByUri[uri]; delete claimsByUri[uri];
} }
}); });
const myClaims = newMyClaims.filter(i => i.claim_id && i.claim_id !== claimId); const myClaims = newMyClaims.filter(i => i !== claimId);
const myChannelClaims = newMyChannelClaims.filter(i => i !== claimId);
delete byId[claimId]; delete byId[claimId];
return Object.assign({}, state, { return Object.assign({}, state, {
myClaims, myClaims,
myChannelClaims,
byId, byId,
claimsByUri, claimsByUri,
}); });
@ -378,7 +382,7 @@ reducers[ACTIONS.CREATE_CHANNEL_COMPLETED] = (state: State, action: any): State
return Object.assign({}, state, { return Object.assign({}, state, {
byId, byId,
pendingById, pendingById,
myChannelClaims, myChannelClaims: Array.from(myChannelClaims),
creatingChannel: false, creatingChannel: false,
}); });
}; };

View file

@ -14,8 +14,6 @@ type ActionResult = {
result: any, result: any,
}; };
type WalletState = { type WalletState = {
balance: any, balance: any,
totalBalance: any, totalBalance: any,
@ -28,6 +26,7 @@ type WalletState = {
supports: { [string]: Support }, supports: { [string]: Support },
abandoningSupportsByOutpoint: { [string]: boolean }, abandoningSupportsByOutpoint: { [string]: boolean },
fetchingTransactions: boolean, fetchingTransactions: boolean,
fetchingTransactionsError: string,
gettingNewAddress: boolean, gettingNewAddress: boolean,
draftTransaction: any, draftTransaction: any,
sendingSupport: boolean, sendingSupport: boolean,
@ -45,6 +44,10 @@ type WalletState = {
walletLockSucceded: ?boolean, walletLockSucceded: ?boolean,
walletLockResult: ?boolean, walletLockResult: ?boolean,
walletReconnecting: boolean, walletReconnecting: boolean,
txoFetchParams: {},
txoPage: any,
fetchingTxos: boolean,
fetchingTxosError?: string,
pendingSupportTransactions: {}, // { claimId: {txid: 123, amount 12.3}, } pendingSupportTransactions: {}, // { claimId: {txid: 123, amount 12.3}, }
abandonClaimSupportError?: string, abandonClaimSupportError?: string,
}; };
@ -59,6 +62,7 @@ const defaultState = {
latestBlock: undefined, latestBlock: undefined,
transactions: {}, transactions: {},
fetchingTransactions: false, fetchingTransactions: false,
fetchingTransactionsError: undefined,
supports: {}, supports: {},
fetchingSupports: false, fetchingSupports: false,
abandoningSupportsByOutpoint: {}, abandoningSupportsByOutpoint: {},
@ -80,6 +84,10 @@ const defaultState = {
walletLockResult: null, walletLockResult: null,
transactionListFilter: 'all', transactionListFilter: 'all',
walletReconnecting: false, walletReconnecting: false,
txoFetchParams: {},
txoPage: {},
fetchingTxos: false,
fetchingTxosError: undefined,
pendingSupportTransactions: {}, pendingSupportTransactions: {},
abandonClaimSupportError: undefined, abandonClaimSupportError: undefined,
}; };
@ -106,6 +114,38 @@ export const walletReducer = handleActions(
}; };
}, },
[ACTIONS.FETCH_TXO_PAGE_STARTED]: (state: WalletState) => {
return {
...state,
fetchingTxos: true,
fetchingTxosError: undefined,
};
},
[ACTIONS.FETCH_TXO_PAGE_COMPLETED]: (state: WalletState, action) => {
return {
...state,
txoPage: action.data,
fetchingTxos: false,
};
},
[ACTIONS.FETCH_TXO_PAGE_FAILED]: (state: WalletState, action) => {
return {
...state,
txoPage: {},
fetchingTxos: false,
fetchingTxosError: action.data,
};
},
[ACTIONS.UPDATE_TXO_FETCH_PARAMS]: (state: WalletState, action) => {
return {
...state,
txoFetchParams: action.data,
};
},
[ACTIONS.FETCH_SUPPORTS_STARTED]: (state: WalletState) => ({ [ACTIONS.FETCH_SUPPORTS_STARTED]: (state: WalletState) => ({
...state, ...state,
fetchingSupports: true, fetchingSupports: true,

View file

@ -321,6 +321,36 @@ export const selectFilteredTransactions = createSelector(
} }
); );
export const selectTxoPageParams = createSelector(
selectState,
state => state.txoFetchParams
);
export const selectTxoPage = createSelector(
selectState,
state => (state.txoPage && state.txoPage.items) || [],
);
export const selectTxoPageNumber = createSelector(
selectState,
state => (state.txoPage && state.txoPage.page) || 1,
);
export const selectTxoItemCount = createSelector(
selectState,
state => (state.txoPage && state.txoPage.total_items) || 1,
);
export const selectFetchingTxosError = createSelector(
selectState,
state => state.fetchingTxosError,
);
export const selectIsFetchingTxos = createSelector(
selectState,
state => state.fetchingTxos,
);
export const makeSelectFilteredTransactionsForPage = (page = 1) => export const makeSelectFilteredTransactionsForPage = (page = 1) =>
createSelector( createSelector(
selectFilteredTransactions, selectFilteredTransactions,