From 74c4e1efa3b23c014f672ce406da3956beefb528 Mon Sep 17 00:00:00 2001 From: hackrush Date: Tue, 24 Oct 2017 18:40:27 +0530 Subject: [PATCH 1/9] Revoke claims from Txn list --- ui/js/actions/content.js | 31 +++++++++++++++++ ui/js/actions/file_info.js | 14 +++++++- ui/js/component/transactionList/index.js | 10 +++++- .../internal/TransactionListItem.jsx | 20 ++++++++++- ui/js/component/transactionList/view.jsx | 25 ++++++++++++++ ui/js/reducers/claims.js | 34 ++++++++++++++----- ui/js/selectors/claims.js | 5 +++ ui/scss/component/_table.scss | 11 +++--- 8 files changed, 134 insertions(+), 16 deletions(-) diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index b9891751a..defa06a3d 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -505,3 +505,34 @@ export function doPublish(params) { }); }; } + +export function doAbandonClaim(claimId, txid, nout) { + return function(dispatch, getState) { + const state = getState(); + + dispatch({ + type: types.ABANDON_CLAIM_STARTED, + data: { + claimId: claimId, + txid: txid, + nout: nout, + }, + }); + + const success = dispatch({ + type: types.ABANDON_CLAIM_SUCCEEDED, + data: { + claimId: claimId, + txid: txid, + nout: nout, + }, + }); + + lbry + .claim_abandon({ + txid: txid, + nout: nout, + }) + .then(success); + }; +} diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index 49c949e5c..825dfa07c 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -102,10 +102,15 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) { const fileInfo = byOutpoint[outpoint]; if (fileInfo) { + txid = fileInfo.outpoint.slice(0, -2); + nout = fileInfo.outpoint.slice(-1); + dispatch({ type: types.ABANDON_CLAIM_STARTED, data: { claimId: fileInfo.claim_id, + txid: txid, + nout: nout, }, }); @@ -113,9 +118,16 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) { type: types.ABANDON_CLAIM_SUCCEEDED, data: { claimId: fileInfo.claim_id, + txid: txid, + nout: nout, }, }); - lbry.claim_abandon({ claim_id: fileInfo.claim_id }).then(success); + lbry + .claim_abandon({ + txid: txid, + nout: nout, + }) + .then(success); } } diff --git a/ui/js/component/transactionList/index.js b/ui/js/component/transactionList/index.js index 5a6c10b6b..39d5cde5e 100644 --- a/ui/js/component/transactionList/index.js +++ b/ui/js/component/transactionList/index.js @@ -1,15 +1,23 @@ import React from "react"; import { connect } from "react-redux"; import { doNavigate } from "actions/navigation"; +import { doAbandonClaim, doResolveUri } from "actions/content"; import { selectClaimedRewardsByTransactionId } from "selectors/rewards"; +import { selectAllMyClaimsByTxidNout } from "selectors/claims"; +import { selectResolvingUris } from "selectors/content"; import TransactionList from "./view"; const select = state => ({ rewards: selectClaimedRewardsByTransactionId(state), + myClaims: selectAllMyClaimsByTxidNout(state), + resolvingUris: selectResolvingUris(state), }); const perform = dispatch => ({ navigate: (path, params) => dispatch(doNavigate(path, params)), + resolveUri: uri => dispatch(doResolveUri(uri)), + abandonClaim: (claimId, txid, nout) => + dispatch(doAbandonClaim(claimId, txid, nout)), }); -export default connect(null, perform)(TransactionList); +export default connect(select, perform)(TransactionList); diff --git a/ui/js/component/transactionList/internal/TransactionListItem.jsx b/ui/js/component/transactionList/internal/TransactionListItem.jsx index fd4429bd3..93e9e56d2 100644 --- a/ui/js/component/transactionList/internal/TransactionListItem.jsx +++ b/ui/js/component/transactionList/internal/TransactionListItem.jsx @@ -6,8 +6,12 @@ import Link from "component/link"; import lbryuri from "lbryuri"; class TransactionListItem extends React.PureComponent { + abandonClaim(abandonData) { + this.props.revokeClaim(abandonData); + } + render() { - const { reward, transaction } = this.props; + const { reward, transaction, isRevokeable } = this.props; const { amount, claim_id: claimId, @@ -16,8 +20,16 @@ class TransactionListItem extends React.PureComponent { fee, txid, type, + nout, } = transaction; + const abandonData = { + name: name, + claimId: claimId, + txid: txid, + nout: nout, + }; + const dateFormat = { month: "short", day: "numeric", @@ -80,6 +92,12 @@ class TransactionListItem extends React.PureComponent { + + {isRevokeable && + this.abandonClaim(abandonData)}> + {__("Revoke")} + } + ); } diff --git a/ui/js/component/transactionList/view.jsx b/ui/js/component/transactionList/view.jsx index beb2f8514..48f476eb6 100644 --- a/ui/js/component/transactionList/view.jsx +++ b/ui/js/component/transactionList/view.jsx @@ -1,6 +1,7 @@ import React from "react"; import TransactionListItem from "./internal/TransactionListItem"; import FormField from "component/formField"; +import lbryuri from "lbryuri"; class TransactionList extends React.PureComponent { constructor(props) { @@ -23,6 +24,27 @@ class TransactionList extends React.PureComponent { return !filter || filter == transaction.type; } + isRevokeable(txid, nout) { + // a claim/support/update is revokable if it + // is in my claim list(claim_list_mine) + return this.props.myClaims.has(`${txid}:${nout}`); + } + + revokeClaim(abandonData) { + const { + name: name, + claimId: claimId, + txid: txid, + nout: nout, + } = abandonData; + + const uri = lbryuri.build({ name, claimId }); + this.props.resolveUri(uri); + if (!this.props.resolvingUris.includes(uri)) { + this.props.abandonClaim(claimId, txid, nout); + } + } + render() { const { emptyMessage, rewards, transactions } = this.props; @@ -62,6 +84,7 @@ class TransactionList extends React.PureComponent { {__("Type")} {__("Details")} {__("Transaction")} + {__("Action")} @@ -70,6 +93,8 @@ class TransactionList extends React.PureComponent { key={`${t.txid}:${t.nout}`} transaction={t} reward={rewards && rewards[t.txid]} + isRevokeable={this.isRevokeable(t.txid, t.nout)} + revokeClaim={this.revokeClaim.bind(this)} /> )} diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index a3e4ae2b4..2f0a8658f 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -45,6 +45,9 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { const byId = Object.assign({}, state.byId); const pendingById = Object.assign({}, state.pendingById); const abandoningById = Object.assign({}, state.abandoningById); + const allMyClaimsByTxidNout = new Set( + claims.map(claim => `${claim.txid}:${claim.nout}`) + ); const myClaims = new Set( claims .map(claim => claim.claim_id) @@ -78,6 +81,7 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { return Object.assign({}, state, { isFetchingClaimListMine: false, myClaims: myClaims, + allMyClaimsByTxidNout: allMyClaimsByTxidNout, byId, pendingById, }); @@ -157,21 +161,35 @@ reducers[types.ABANDON_CLAIM_STARTED] = function(state, action) { }; reducers[types.ABANDON_CLAIM_SUCCEEDED] = function(state, action) { - const { claimId } = action.data; + const { claimId, txid, nout } = action.data; const myClaims = new Set(state.myClaims); const byId = Object.assign({}, state.byId); const claimsByUri = Object.assign({}, state.claimsByUri); + const supports = byId[claimId].supports; const uris = []; - Object.keys(claimsByUri).forEach(uri => { - if (claimsByUri[uri] === claimId) { - delete claimsByUri[uri]; - } - }); + // This logic is needed when a claim has supports + // and it is the support that is being abandoned + // so we need to remove the support from the state + // but this is not working, even after calling resolve on the uri. + if (supports && supports.length > 0) { + indexToDelete = supports.findIndex(support => { + return support.txid === txid && support.nout === nout; + }); - delete byId[claimId]; - myClaims.delete(claimId); + supports.splice[(indexToDelete, 1)]; + } + if (!supports || supports.length == 0) { + Object.keys(claimsByUri).forEach(uri => { + if (claimsByUri[uri] === claimId) { + delete claimsByUri[uri]; + } + }); + + delete byId[claimId]; + myClaims.delete(claimId); + } return Object.assign({}, state, { myClaims, byId, diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index c90b78843..608ceae67 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -157,6 +157,11 @@ export const selectMyClaimsWithoutChannels = createSelector( myClaims => myClaims.filter(claim => !claim.name.match(/^@/)) ); +export const selectAllMyClaimsByTxidNout = createSelector( + _selectState, + state => state.allMyClaimsByTxidNout || {} +); + export const selectMyClaimsOutpoints = createSelector( selectMyClaims, myClaims => { diff --git a/ui/scss/component/_table.scss b/ui/scss/component/_table.scss index 06f33aaf0..e17e90253 100644 --- a/ui/scss/component/_table.scss +++ b/ui/scss/component/_table.scss @@ -62,9 +62,10 @@ table.table-stretch { } table.table-transactions { - td:nth-of-type(1) { width: 15%; } - td:nth-of-type(2) { width: 15%; } - td:nth-of-type(3) { width: 15%; } - td:nth-of-type(4) { width: 40%; } - td:nth-of-type(5) { width: 15%; } + td:nth-of-type(1) { width: 13%; } + td:nth-of-type(2) { width: 13%; } + td:nth-of-type(3) { width: 13%; } + td:nth-of-type(4) { width: 35%; } + td:nth-of-type(5) { width: 13%; } + td:nth-of-type(6) { width: 13%; } } From f73cace72d4c7b5fd0bdff5b8c048442f43eb38b Mon Sep 17 00:00:00 2001 From: hackrush Date: Sat, 28 Oct 2017 01:12:54 +0530 Subject: [PATCH 2/9] Ask for confirmation before revoking --- ui/js/actions/content.js | 4 ++- ui/js/component/transactionList/index.js | 7 +++-- ui/js/component/transactionList/view.jsx | 5 ++-- ui/js/constants/modal_types.js | 1 + ui/js/modal/modalRevokeClaim/index.js | 13 +++++++++ ui/js/modal/modalRevokeClaim/view.jsx | 34 ++++++++++++++++++++++++ ui/js/modal/modalRouter/view.jsx | 3 +++ ui/js/reducers/claims.js | 4 +-- 8 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 ui/js/modal/modalRevokeClaim/index.js create mode 100644 ui/js/modal/modalRevokeClaim/view.jsx diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index defa06a3d..3bc8b730b 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -11,7 +11,7 @@ import { } from "selectors/file_info"; import { selectResolvingUris } from "selectors/content"; import { makeSelectCostInfoForUri } from "selectors/cost_info"; -import { doAlertError, doOpenModal } from "actions/app"; +import { doAlertError, doOpenModal, doCloseModal } from "actions/app"; import { doClaimEligiblePurchaseRewards } from "actions/rewards"; import { selectBadgeNumber } from "selectors/app"; import { selectTotalDownloadProgress } from "selectors/file_info"; @@ -510,6 +510,8 @@ export function doAbandonClaim(claimId, txid, nout) { return function(dispatch, getState) { const state = getState(); + dispatch(doCloseModal()); + dispatch({ type: types.ABANDON_CLAIM_STARTED, data: { diff --git a/ui/js/component/transactionList/index.js b/ui/js/component/transactionList/index.js index 39d5cde5e..61015823d 100644 --- a/ui/js/component/transactionList/index.js +++ b/ui/js/component/transactionList/index.js @@ -1,7 +1,8 @@ import React from "react"; import { connect } from "react-redux"; import { doNavigate } from "actions/navigation"; -import { doAbandonClaim, doResolveUri } from "actions/content"; +import { doOpenModal } from "actions/app"; +import { doResolveUri } from "actions/content"; import { selectClaimedRewardsByTransactionId } from "selectors/rewards"; import { selectAllMyClaimsByTxidNout } from "selectors/claims"; import { selectResolvingUris } from "selectors/content"; @@ -10,14 +11,12 @@ import TransactionList from "./view"; const select = state => ({ rewards: selectClaimedRewardsByTransactionId(state), myClaims: selectAllMyClaimsByTxidNout(state), - resolvingUris: selectResolvingUris(state), }); const perform = dispatch => ({ navigate: (path, params) => dispatch(doNavigate(path, params)), resolveUri: uri => dispatch(doResolveUri(uri)), - abandonClaim: (claimId, txid, nout) => - dispatch(doAbandonClaim(claimId, txid, nout)), + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), }); export default connect(select, perform)(TransactionList); diff --git a/ui/js/component/transactionList/view.jsx b/ui/js/component/transactionList/view.jsx index 48f476eb6..8d787de4f 100644 --- a/ui/js/component/transactionList/view.jsx +++ b/ui/js/component/transactionList/view.jsx @@ -2,6 +2,7 @@ import React from "react"; import TransactionListItem from "./internal/TransactionListItem"; import FormField from "component/formField"; import lbryuri from "lbryuri"; +import * as modals from "constants/modal_types"; class TransactionList extends React.PureComponent { constructor(props) { @@ -40,9 +41,7 @@ class TransactionList extends React.PureComponent { const uri = lbryuri.build({ name, claimId }); this.props.resolveUri(uri); - if (!this.props.resolvingUris.includes(uri)) { - this.props.abandonClaim(claimId, txid, nout); - } + this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, { claimId, txid, nout }); } render() { diff --git a/ui/js/constants/modal_types.js b/ui/js/constants/modal_types.js index 9e82be50a..d68349d44 100644 --- a/ui/js/constants/modal_types.js +++ b/ui/js/constants/modal_types.js @@ -13,3 +13,4 @@ export const INSUFFICIENT_BALANCE = "insufficient_balance"; export const REWARD_APPROVAL_REQUIRED = "reward_approval_required"; export const AFFIRM_PURCHASE = "affirm_purchase"; export const CREDIT_INTRO = "credit_intro"; +export const CONFIRM_CLAIM_REVOKE = "confirmClaimRevoke"; diff --git a/ui/js/modal/modalRevokeClaim/index.js b/ui/js/modal/modalRevokeClaim/index.js new file mode 100644 index 000000000..20ecc9371 --- /dev/null +++ b/ui/js/modal/modalRevokeClaim/index.js @@ -0,0 +1,13 @@ +import React from "react"; +import { connect } from "react-redux"; +import { doCloseModal } from "actions/app"; +import { doAbandonClaim } from "actions/content"; +import ModalRevokeClaim from "./view"; + +const perform = dispatch => ({ + closeModal: () => dispatch(doCloseModal()), + abandonClaim: (claimId, txid, nout) => + dispatch(doAbandonClaim(claimId, txid, nout)), +}); + +export default connect(null, perform)(ModalRevokeClaim); diff --git a/ui/js/modal/modalRevokeClaim/view.jsx b/ui/js/modal/modalRevokeClaim/view.jsx new file mode 100644 index 000000000..f7bbae9b3 --- /dev/null +++ b/ui/js/modal/modalRevokeClaim/view.jsx @@ -0,0 +1,34 @@ +import React from "react"; +import { Modal } from "modal/modal"; + +class ModalRevokeClaim extends React.PureComponent { + constructor(props) { + super(props); + } + + s() { + console.log("gotcha"); + } + + render() { + const { claimId, txid, nout, abandonClaim, closeModal } = this.props; + + return ( + abandonClaim(claimId, txid, nout)} + onAborted={closeModal} + > +

+ {__("Are you sure you want to revoke the claim?")} +

+
+ ); + } +} + +export default ModalRevokeClaim; diff --git a/ui/js/modal/modalRouter/view.jsx b/ui/js/modal/modalRouter/view.jsx index 8d2bf912e..d7beb7d3d 100644 --- a/ui/js/modal/modalRouter/view.jsx +++ b/ui/js/modal/modalRouter/view.jsx @@ -13,6 +13,7 @@ import ModalTransactionFailed from "modal/modalTransactionFailed"; import ModalInsufficientBalance from "modal/modalInsufficientBalance"; import ModalFileTimeout from "modal/modalFileTimeout"; import ModalAffirmPurchase from "modal/modalAffirmPurchase"; +import ModalRevokeClaim from "modal/modalRevokeClaim"; import * as modals from "constants/modal_types"; class ModalRouter extends React.PureComponent { @@ -132,6 +133,8 @@ class ModalRouter extends React.PureComponent { return ; case modals.AFFIRM_PURCHASE: return ; + case modals.CONFIRM_CLAIM_REVOKE: + return ; default: return null; } diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index 2f0a8658f..f4a80131c 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -173,11 +173,11 @@ reducers[types.ABANDON_CLAIM_SUCCEEDED] = function(state, action) { // so we need to remove the support from the state // but this is not working, even after calling resolve on the uri. if (supports && supports.length > 0) { - indexToDelete = supports.findIndex(support => { + const indexToDelete = supports.findIndex(support => { return support.txid === txid && support.nout === nout; }); - supports.splice[(indexToDelete, 1)]; + supports.splice(indexToDelete, 1); } if (!supports || supports.length == 0) { From 28241aaa3ae855edf532e81f2ae79e2094ddb75a Mon Sep 17 00:00:00 2001 From: hackrush Date: Sat, 28 Oct 2017 11:09:17 +0530 Subject: [PATCH 3/9] Updated Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a64cc392f..b07652053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Web UI version numbers should always match the corresponding version of LBRY App ## [Unreleased] ### Added - * + * Now you can revoke your claims from the txns list itself.(#581) * ### Changed From 88b3e5a08bc5375c48f5f3eec385eb2961c5e89a Mon Sep 17 00:00:00 2001 From: hackrush Date: Mon, 30 Oct 2017 21:55:56 +0530 Subject: [PATCH 4/9] Feedback fixes --- ui/js/actions/content.js | 34 ++++++----- ui/js/component/transactionList/index.js | 3 - .../internal/TransactionListItem.jsx | 61 ++++++++++++++----- ui/js/component/transactionList/view.jsx | 12 +--- ui/js/modal/modalRevokeClaim/index.js | 4 +- ui/js/modal/modalRevokeClaim/view.jsx | 14 +++-- ui/js/reducers/claims.js | 31 +++------- ui/scss/component/_table.scss | 11 ++-- 8 files changed, 90 insertions(+), 80 deletions(-) diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 3bc8b730b..f47fbc9e0 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -506,35 +506,41 @@ export function doPublish(params) { }; } -export function doAbandonClaim(claimId, txid, nout) { +export function doAbandonClaim(claimId, name, txid, nout) { return function(dispatch, getState) { const state = getState(); - dispatch(doCloseModal()); - dispatch({ type: types.ABANDON_CLAIM_STARTED, data: { claimId: claimId, - txid: txid, - nout: nout, }, }); - const success = dispatch({ - type: types.ABANDON_CLAIM_SUCCEEDED, - data: { - claimId: claimId, - txid: txid, - nout: nout, - }, - }); + const errorCallback = error => { + dispatch(doOpenModal(modals.TRANSACTION_FAILED)); + }; + + const successCallback = results => { + if (results.txid) { + dispatch({ + type: types.ABANDON_CLAIM_SUCCEEDED, + data: { + claimId: claimId, + }, + }); + dispatch(doResolveUri(lbryuri.build({ name, claimId }))); + dispatch(doFetchClaimListMine()); + } else { + dispatch(doOpenModal(modals.TRANSACTION_FAILED)); + } + }; lbry .claim_abandon({ txid: txid, nout: nout, }) - .then(success); + .then(successCallback, errorCallback); }; } diff --git a/ui/js/component/transactionList/index.js b/ui/js/component/transactionList/index.js index 61015823d..bab6a64a7 100644 --- a/ui/js/component/transactionList/index.js +++ b/ui/js/component/transactionList/index.js @@ -2,10 +2,8 @@ import React from "react"; import { connect } from "react-redux"; import { doNavigate } from "actions/navigation"; import { doOpenModal } from "actions/app"; -import { doResolveUri } from "actions/content"; import { selectClaimedRewardsByTransactionId } from "selectors/rewards"; import { selectAllMyClaimsByTxidNout } from "selectors/claims"; -import { selectResolvingUris } from "selectors/content"; import TransactionList from "./view"; const select = state => ({ @@ -15,7 +13,6 @@ const select = state => ({ const perform = dispatch => ({ navigate: (path, params) => dispatch(doNavigate(path, params)), - resolveUri: uri => dispatch(doResolveUri(uri)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)), }); diff --git a/ui/js/component/transactionList/internal/TransactionListItem.jsx b/ui/js/component/transactionList/internal/TransactionListItem.jsx index 93e9e56d2..673dc46bc 100644 --- a/ui/js/component/transactionList/internal/TransactionListItem.jsx +++ b/ui/js/component/transactionList/internal/TransactionListItem.jsx @@ -6,10 +6,53 @@ import Link from "component/link"; import lbryuri from "lbryuri"; class TransactionListItem extends React.PureComponent { - abandonClaim(abandonData) { + abandonClaim() { + const { + claim_id: claimId, + claim_name: name, + txid, + type, + nout, + } = this.props.transaction; + let msg; + + if (type == "tip") { + msg = "This will reduce the committed credits to the URL"; + } else { + msg = "This will reclaim you lbc, back to your account"; + } + + const abandonData = { + name: name, + claimId: claimId, + txid: txid, + nout: nout, + msg: msg, + }; + this.props.revokeClaim(abandonData); } + getLink(type) { + if (type == "tip") { + return ( + + ); + } else { + return ( + + ); + } + } + render() { const { reward, transaction, isRevokeable } = this.props; const { @@ -23,13 +66,6 @@ class TransactionListItem extends React.PureComponent { nout, } = transaction; - const abandonData = { - name: name, - claimId: claimId, - txid: txid, - nout: nout, - }; - const dateFormat = { month: "short", day: "numeric", @@ -72,7 +108,8 @@ class TransactionListItem extends React.PureComponent { />} - {type} + {type}{" "} + {isRevokeable && this.getLink(type)} {reward && @@ -92,12 +129,6 @@ class TransactionListItem extends React.PureComponent { - - {isRevokeable && - this.abandonClaim(abandonData)}> - {__("Revoke")} - } - ); } diff --git a/ui/js/component/transactionList/view.jsx b/ui/js/component/transactionList/view.jsx index 8d787de4f..975fa4df3 100644 --- a/ui/js/component/transactionList/view.jsx +++ b/ui/js/component/transactionList/view.jsx @@ -32,16 +32,7 @@ class TransactionList extends React.PureComponent { } revokeClaim(abandonData) { - const { - name: name, - claimId: claimId, - txid: txid, - nout: nout, - } = abandonData; - - const uri = lbryuri.build({ name, claimId }); - this.props.resolveUri(uri); - this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, { claimId, txid, nout }); + this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, abandonData); } render() { @@ -83,7 +74,6 @@ class TransactionList extends React.PureComponent { {__("Type")} {__("Details")} {__("Transaction")} - {__("Action")} diff --git a/ui/js/modal/modalRevokeClaim/index.js b/ui/js/modal/modalRevokeClaim/index.js index 20ecc9371..2216dff54 100644 --- a/ui/js/modal/modalRevokeClaim/index.js +++ b/ui/js/modal/modalRevokeClaim/index.js @@ -6,8 +6,8 @@ import ModalRevokeClaim from "./view"; const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), - abandonClaim: (claimId, txid, nout) => - dispatch(doAbandonClaim(claimId, txid, nout)), + abandonClaim: (claimId, name, txid, nout) => + dispatch(doAbandonClaim(claimId, name, txid, nout)), }); export default connect(null, perform)(ModalRevokeClaim); diff --git a/ui/js/modal/modalRevokeClaim/view.jsx b/ui/js/modal/modalRevokeClaim/view.jsx index f7bbae9b3..8078864da 100644 --- a/ui/js/modal/modalRevokeClaim/view.jsx +++ b/ui/js/modal/modalRevokeClaim/view.jsx @@ -6,12 +6,15 @@ class ModalRevokeClaim extends React.PureComponent { super(props); } - s() { - console.log("gotcha"); + revokeClaim() { + const { name, claimId, txid, nout } = this.props; + + this.props.closeModal(); + this.props.abandonClaim(claimId, name, txid, nout); } render() { - const { claimId, txid, nout, abandonClaim, closeModal } = this.props; + const { msg, closeModal } = this.props; return ( abandonClaim(claimId, txid, nout)} + onConfirmed={this.revokeClaim.bind(this)} onAborted={closeModal} >

- {__("Are you sure you want to revoke the claim?")} + {msg}

); diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index f4a80131c..67f4dcec7 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -161,35 +161,20 @@ reducers[types.ABANDON_CLAIM_STARTED] = function(state, action) { }; reducers[types.ABANDON_CLAIM_SUCCEEDED] = function(state, action) { - const { claimId, txid, nout } = action.data; + const { claimId } = action.data; const myClaims = new Set(state.myClaims); const byId = Object.assign({}, state.byId); const claimsByUri = Object.assign({}, state.claimsByUri); - const supports = byId[claimId].supports; - const uris = []; - // This logic is needed when a claim has supports - // and it is the support that is being abandoned - // so we need to remove the support from the state - // but this is not working, even after calling resolve on the uri. - if (supports && supports.length > 0) { - const indexToDelete = supports.findIndex(support => { - return support.txid === txid && support.nout === nout; - }); + Object.keys(claimsByUri).forEach(uri => { + if (claimsByUri[uri] === claimId) { + delete claimsByUri[uri]; + } + }); - supports.splice(indexToDelete, 1); - } + delete byId[claimId]; + myClaims.delete(claimId); - if (!supports || supports.length == 0) { - Object.keys(claimsByUri).forEach(uri => { - if (claimsByUri[uri] === claimId) { - delete claimsByUri[uri]; - } - }); - - delete byId[claimId]; - myClaims.delete(claimId); - } return Object.assign({}, state, { myClaims, byId, diff --git a/ui/scss/component/_table.scss b/ui/scss/component/_table.scss index e17e90253..06f33aaf0 100644 --- a/ui/scss/component/_table.scss +++ b/ui/scss/component/_table.scss @@ -62,10 +62,9 @@ table.table-stretch { } table.table-transactions { - td:nth-of-type(1) { width: 13%; } - td:nth-of-type(2) { width: 13%; } - td:nth-of-type(3) { width: 13%; } - td:nth-of-type(4) { width: 35%; } - td:nth-of-type(5) { width: 13%; } - td:nth-of-type(6) { width: 13%; } + td:nth-of-type(1) { width: 15%; } + td:nth-of-type(2) { width: 15%; } + td:nth-of-type(3) { width: 15%; } + td:nth-of-type(4) { width: 40%; } + td:nth-of-type(5) { width: 15%; } } From a2791ec57ac34a86e5c750f9addfbc60b705fde2 Mon Sep 17 00:00:00 2001 From: hackrush Date: Tue, 31 Oct 2017 19:32:08 +0530 Subject: [PATCH 5/9] Fixed redundant storing of states --- ui/js/reducers/claims.js | 11 +---------- ui/js/selectors/claims.js | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index 67f4dcec7..169792e1e 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -45,14 +45,6 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { const byId = Object.assign({}, state.byId); const pendingById = Object.assign({}, state.pendingById); const abandoningById = Object.assign({}, state.abandoningById); - const allMyClaimsByTxidNout = new Set( - claims.map(claim => `${claim.txid}:${claim.nout}`) - ); - const myClaims = new Set( - claims - .map(claim => claim.claim_id) - .filter(claimId => Object.keys(abandoningById).indexOf(claimId) === -1) - ); claims .filter(claim => claim.category && claim.category.match(/claim/)) @@ -80,8 +72,7 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) { return Object.assign({}, state, { isFetchingClaimListMine: false, - myClaims: myClaims, - allMyClaimsByTxidNout: allMyClaimsByTxidNout, + myClaims: claims, byId, pendingById, }); diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index 608ceae67..faaa4f5ce 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -121,15 +121,26 @@ export const selectIsFetchingClaimListMine = createSelector( state => !!state.isFetchingClaimListMine ); -export const selectMyClaimsRaw = createSelector( +export const cantFigureOutVarName = createSelector( _selectState, - state => new Set(state.myClaims) + state => state.myClaims ); export const selectAbandoningIds = createSelector(_selectState, state => Object.keys(state.abandoningById || {}) ); +export const selectMyClaimsRaw = createSelector( + cantFigureOutVarName, + selectAbandoningIds, + (claims, abandoningIds) => + new Set( + claims + .map(claim => claim.claim_id) + .filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1) + ) +); + export const selectPendingClaims = createSelector(_selectState, state => Object.values(state.pendingById || {}) ); @@ -158,8 +169,8 @@ export const selectMyClaimsWithoutChannels = createSelector( ); export const selectAllMyClaimsByTxidNout = createSelector( - _selectState, - state => state.allMyClaimsByTxidNout || {} + cantFigureOutVarName, + claims => new Set(claims.map(claim => `${claim.txid}:${claim.nout}`)) ); export const selectMyClaimsOutpoints = createSelector( From 588972d017f765a422e9151c9b15c953df8e1a9a Mon Sep 17 00:00:00 2001 From: hackrush Date: Thu, 2 Nov 2017 01:53:30 +0530 Subject: [PATCH 6/9] Clean Up --- ui/js/actions/content.js | 10 ++- ui/js/actions/file_info.js | 26 +------- ui/js/component/transactionList/index.js | 4 +- .../internal/TransactionListItem.jsx | 32 ++-------- ui/js/component/transactionList/view.jsx | 4 +- ui/js/constants/transaction_types.js | 1 + ui/js/modal/modalRevokeClaim/index.js | 10 ++- ui/js/modal/modalRevokeClaim/view.jsx | 64 +++++++++++++++++-- ui/js/selectors/claims.js | 14 ++-- 9 files changed, 91 insertions(+), 74 deletions(-) create mode 100644 ui/js/constants/transaction_types.js diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index f47fbc9e0..d5281a0f9 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -4,14 +4,14 @@ import lbry from "lbry"; import lbryio from "lbryio"; import lbryuri from "lbryuri"; import { makeSelectClientSetting } from "selectors/settings"; -import { selectBalance } from "selectors/wallet"; +import { selectBalance, selectTransactionItems } from "selectors/wallet"; import { makeSelectFileInfoForUri, selectDownloadingByOutpoint, } from "selectors/file_info"; import { selectResolvingUris } from "selectors/content"; import { makeSelectCostInfoForUri } from "selectors/cost_info"; -import { doAlertError, doOpenModal, doCloseModal } from "actions/app"; +import { doAlertError, doOpenModal } from "actions/app"; import { doClaimEligiblePurchaseRewards } from "actions/rewards"; import { selectBadgeNumber } from "selectors/app"; import { selectTotalDownloadProgress } from "selectors/file_info"; @@ -506,9 +506,13 @@ export function doPublish(params) { }; } -export function doAbandonClaim(claimId, name, txid, nout) { +export function doAbandonClaim(txid, nout) { return function(dispatch, getState) { const state = getState(); + const transactionItems = selectTransactionItems(state); + const { claim_id: claimId, claim_name: name } = transactionItems.find( + claim => claim.txid == txid && claim.nout == nout + ); dispatch({ type: types.ABANDON_CLAIM_STARTED, diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index 825dfa07c..ef9a742d5 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -1,6 +1,6 @@ import * as types from "constants/action_types"; import lbry from "lbry"; -import { doFetchClaimListMine } from "actions/content"; +import { doFetchClaimListMine, doAbandonClaim } from "actions/content"; import { selectClaimsByUri, selectIsFetchingClaimListMine, @@ -105,29 +105,7 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) { txid = fileInfo.outpoint.slice(0, -2); nout = fileInfo.outpoint.slice(-1); - dispatch({ - type: types.ABANDON_CLAIM_STARTED, - data: { - claimId: fileInfo.claim_id, - txid: txid, - nout: nout, - }, - }); - - const success = dispatch({ - type: types.ABANDON_CLAIM_SUCCEEDED, - data: { - claimId: fileInfo.claim_id, - txid: txid, - nout: nout, - }, - }); - lbry - .claim_abandon({ - txid: txid, - nout: nout, - }) - .then(success); + dispatch(doAbandonClaim(txid, nout)); } } diff --git a/ui/js/component/transactionList/index.js b/ui/js/component/transactionList/index.js index bab6a64a7..48ea3bc05 100644 --- a/ui/js/component/transactionList/index.js +++ b/ui/js/component/transactionList/index.js @@ -3,12 +3,12 @@ import { connect } from "react-redux"; import { doNavigate } from "actions/navigation"; import { doOpenModal } from "actions/app"; import { selectClaimedRewardsByTransactionId } from "selectors/rewards"; -import { selectAllMyClaimsByTxidNout } from "selectors/claims"; +import { selectAllMyClaimsByOutpoint } from "selectors/claims"; import TransactionList from "./view"; const select = state => ({ rewards: selectClaimedRewardsByTransactionId(state), - myClaims: selectAllMyClaimsByTxidNout(state), + myClaims: selectAllMyClaimsByOutpoint(state), }); const perform = dispatch => ({ diff --git a/ui/js/component/transactionList/internal/TransactionListItem.jsx b/ui/js/component/transactionList/internal/TransactionListItem.jsx index 229dc8fd6..9acf92fde 100644 --- a/ui/js/component/transactionList/internal/TransactionListItem.jsx +++ b/ui/js/component/transactionList/internal/TransactionListItem.jsx @@ -4,42 +4,22 @@ import { CreditAmount } from "component/common"; import DateTime from "component/dateTime"; import Link from "component/link"; import lbryuri from "lbryuri"; +import * as txnTypes from "constants/transaction_types"; class TransactionListItem extends React.PureComponent { abandonClaim() { - const { - claim_id: claimId, - claim_name: name, - txid, - type, - nout, - } = this.props.transaction; - let msg; + const { txid, nout } = this.props.transaction; - if (type == "tip") { - msg = "This will reduce the committed credits to the URL"; - } else { - msg = "This will reclaim you lbc, back to your account"; - } - - const abandonData = { - name: name, - claimId: claimId, - txid: txid, - nout: nout, - msg: msg, - }; - - this.props.revokeClaim(abandonData); + this.props.revokeClaim(txid, nout); } getLink(type) { - if (type == "tip") { + if (type == txnTypes.TIP) { return ( ); } else { @@ -47,7 +27,7 @@ class TransactionListItem extends React.PureComponent { ); } diff --git a/ui/js/component/transactionList/view.jsx b/ui/js/component/transactionList/view.jsx index a24f9f205..0fcb4d5f5 100644 --- a/ui/js/component/transactionList/view.jsx +++ b/ui/js/component/transactionList/view.jsx @@ -30,8 +30,8 @@ class TransactionList extends React.PureComponent { return this.props.myClaims.has(`${txid}:${nout}`); } - revokeClaim(abandonData) { - this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, abandonData); + revokeClaim(txid, nout) { + this.props.openModal(modals.CONFIRM_CLAIM_REVOKE, { txid, nout }); } render() { diff --git a/ui/js/constants/transaction_types.js b/ui/js/constants/transaction_types.js new file mode 100644 index 000000000..89530f9f0 --- /dev/null +++ b/ui/js/constants/transaction_types.js @@ -0,0 +1 @@ +export const TIP = "tip"; diff --git a/ui/js/modal/modalRevokeClaim/index.js b/ui/js/modal/modalRevokeClaim/index.js index 2216dff54..766095b64 100644 --- a/ui/js/modal/modalRevokeClaim/index.js +++ b/ui/js/modal/modalRevokeClaim/index.js @@ -2,12 +2,16 @@ import React from "react"; import { connect } from "react-redux"; import { doCloseModal } from "actions/app"; import { doAbandonClaim } from "actions/content"; +import { selectTransactionItems } from "selectors/wallet"; import ModalRevokeClaim from "./view"; +const select = state => ({ + transactionItems: selectTransactionItems(state), +}); + const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), - abandonClaim: (claimId, name, txid, nout) => - dispatch(doAbandonClaim(claimId, name, txid, nout)), + abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)), }); -export default connect(null, perform)(ModalRevokeClaim); +export default connect(select, perform)(ModalRevokeClaim); diff --git a/ui/js/modal/modalRevokeClaim/view.jsx b/ui/js/modal/modalRevokeClaim/view.jsx index 8078864da..06f1362f8 100644 --- a/ui/js/modal/modalRevokeClaim/view.jsx +++ b/ui/js/modal/modalRevokeClaim/view.jsx @@ -1,5 +1,6 @@ import React from "react"; import { Modal } from "modal/modal"; +import * as txnTypes from "constants/transaction_types"; class ModalRevokeClaim extends React.PureComponent { constructor(props) { @@ -7,27 +8,76 @@ class ModalRevokeClaim extends React.PureComponent { } revokeClaim() { - const { name, claimId, txid, nout } = this.props; + const { txid, nout } = this.props; this.props.closeModal(); - this.props.abandonClaim(claimId, name, txid, nout); + this.props.abandonClaim(txid, nout); + } + + getButtonLabel(type) { + if (type == txnTypes.TIP) { + return "Confirm Tip Unlock"; + } else { + return "Confirm Claim Revoke"; + } + } + + getMsgBody(type) { + if (type == txnTypes.TIP) { + return ( +
+

{__("Confirm Tip Unlock")}

+

+ {__("Are you sure you want to unlock these credits?")} +
+
+ {__( + "These credits are permanently yours and can be\ + unlocked at any time. Unlocking them allows you to\ + spend them, but can hurt the performance of your\ + content in lookups and search results. It is\ + recommended you leave tips locked until you\ + need or want to spend them." + )} +

+
+ ); + } else { + return ( +
+

{__("Confirm Claim Revoke")}

+

+ {__("Are you sure want to revoke this claim?")} +
+
+ {__( + "This will prevent others from resolving and\ + accessing the content you published. It will return\ + the LBC to your spendable balance, less a small\ + transaction fee." + )} +

+
+ ); + } } render() { - const { msg, closeModal } = this.props; + const { transactionItems, txid, nout, closeModal } = this.props; + const { type } = transactionItems.find( + claim => claim.txid == txid && claim.nout == nout + ); return ( -

- {msg} -

+ {this.getMsgBody(type)}
); } diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index faaa4f5ce..f3e6071a5 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -52,7 +52,7 @@ export const makeSelectClaimIsMine = rawUri => { const uri = lbryuri.normalize(rawUri); return createSelector( selectClaimsByUri, - selectMyClaimsRaw, + selectMyActiveClaims, (claims, myClaims) => claims && claims[uri] && @@ -121,7 +121,7 @@ export const selectIsFetchingClaimListMine = createSelector( state => !!state.isFetchingClaimListMine ); -export const cantFigureOutVarName = createSelector( +export const selectMyClaimsRaw = createSelector( _selectState, state => state.myClaims ); @@ -130,8 +130,8 @@ export const selectAbandoningIds = createSelector(_selectState, state => Object.keys(state.abandoningById || {}) ); -export const selectMyClaimsRaw = createSelector( - cantFigureOutVarName, +export const selectMyActiveClaims = createSelector( + selectMyClaimsRaw, selectAbandoningIds, (claims, abandoningIds) => new Set( @@ -146,7 +146,7 @@ export const selectPendingClaims = createSelector(_selectState, state => ); export const selectMyClaims = createSelector( - selectMyClaimsRaw, + selectMyActiveClaims, selectClaimsById, selectAbandoningIds, selectPendingClaims, @@ -168,8 +168,8 @@ export const selectMyClaimsWithoutChannels = createSelector( myClaims => myClaims.filter(claim => !claim.name.match(/^@/)) ); -export const selectAllMyClaimsByTxidNout = createSelector( - cantFigureOutVarName, +export const selectAllMyClaimsByOutpoint = createSelector( + selectMyClaimsRaw, claims => new Set(claims.map(claim => `${claim.txid}:${claim.nout}`)) ); From e956017bc1efa0f26c03326fc6134947467af11c Mon Sep 17 00:00:00 2001 From: hackrush Date: Thu, 2 Nov 2017 02:28:19 +0530 Subject: [PATCH 7/9] Possible fix for regression in previous commit --- ui/js/reducers/claims.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index 169792e1e..270790d8f 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -153,7 +153,6 @@ reducers[types.ABANDON_CLAIM_STARTED] = function(state, action) { reducers[types.ABANDON_CLAIM_SUCCEEDED] = function(state, action) { const { claimId } = action.data; - const myClaims = new Set(state.myClaims); const byId = Object.assign({}, state.byId); const claimsByUri = Object.assign({}, state.claimsByUri); @@ -164,10 +163,8 @@ reducers[types.ABANDON_CLAIM_SUCCEEDED] = function(state, action) { }); delete byId[claimId]; - myClaims.delete(claimId); return Object.assign({}, state, { - myClaims, byId, claimsByUri, }); From 5da244e3e2a4b4d462c30c9289865182fa8b9aec Mon Sep 17 00:00:00 2001 From: hackrush Date: Mon, 6 Nov 2017 20:20:43 +0530 Subject: [PATCH 8/9] Regression Fixes --- ui/js/selectors/claims.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index f3e6071a5..c29522dcf 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -135,9 +135,10 @@ export const selectMyActiveClaims = createSelector( selectAbandoningIds, (claims, abandoningIds) => new Set( - claims - .map(claim => claim.claim_id) - .filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1) + claims && + claims + .map(claim => claim.claim_id) + .filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1) ) ); From d9f65aaff3782e8350159f39742ec6f979dba6ce Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Wed, 8 Nov 2017 18:14:32 -0500 Subject: [PATCH 9/9] add help link for transaction types --- .../transactionList/internal/TransactionListItem.jsx | 2 +- ui/js/component/transactionList/view.jsx | 7 +++++++ ui/js/constants/icons.js | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ui/js/component/transactionList/internal/TransactionListItem.jsx b/ui/js/component/transactionList/internal/TransactionListItem.jsx index 9acf92fde..35cd33247 100644 --- a/ui/js/component/transactionList/internal/TransactionListItem.jsx +++ b/ui/js/component/transactionList/internal/TransactionListItem.jsx @@ -71,7 +71,7 @@ class TransactionListItem extends React.PureComponent { : - {__("(Transaction pending)")} + {__("Pending")} } diff --git a/ui/js/component/transactionList/view.jsx b/ui/js/component/transactionList/view.jsx index 0fcb4d5f5..f736320bf 100644 --- a/ui/js/component/transactionList/view.jsx +++ b/ui/js/component/transactionList/view.jsx @@ -1,6 +1,8 @@ import React from "react"; import TransactionListItem from "./internal/TransactionListItem"; import FormField from "component/formField"; +import Link from "component/link"; +import * as icons from "constants/icons"; import * as modals from "constants/modal_types"; class TransactionList extends React.PureComponent { @@ -59,6 +61,11 @@ class TransactionList extends React.PureComponent { + {" "} + } {!transactionList.length &&
diff --git a/ui/js/constants/icons.js b/ui/js/constants/icons.js index ce2f54e22..d28d7591e 100644 --- a/ui/js/constants/icons.js +++ b/ui/js/constants/icons.js @@ -2,3 +2,4 @@ export const FEATURED = "rocket"; export const LOCAL = "folder"; export const FILE = "file"; export const HISTORY = "history"; +export const HELP_CIRCLE = "question-circle";