Revoke claims from Txn list

This commit is contained in:
hackrush 2017-10-24 18:40:27 +05:30
parent c8cc05b685
commit 74c4e1efa3
8 changed files with 134 additions and 16 deletions

View file

@ -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);
};
}

View file

@ -102,10 +102,15 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
const fileInfo = byOutpoint[outpoint]; const fileInfo = byOutpoint[outpoint];
if (fileInfo) { if (fileInfo) {
txid = fileInfo.outpoint.slice(0, -2);
nout = fileInfo.outpoint.slice(-1);
dispatch({ dispatch({
type: types.ABANDON_CLAIM_STARTED, type: types.ABANDON_CLAIM_STARTED,
data: { data: {
claimId: fileInfo.claim_id, claimId: fileInfo.claim_id,
txid: txid,
nout: nout,
}, },
}); });
@ -113,9 +118,16 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
type: types.ABANDON_CLAIM_SUCCEEDED, type: types.ABANDON_CLAIM_SUCCEEDED,
data: { data: {
claimId: fileInfo.claim_id, 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);
} }
} }

View file

@ -1,15 +1,23 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doNavigate } from "actions/navigation"; import { doNavigate } from "actions/navigation";
import { doAbandonClaim, doResolveUri } from "actions/content";
import { selectClaimedRewardsByTransactionId } from "selectors/rewards"; import { selectClaimedRewardsByTransactionId } from "selectors/rewards";
import { selectAllMyClaimsByTxidNout } from "selectors/claims";
import { selectResolvingUris } from "selectors/content";
import TransactionList from "./view"; import TransactionList from "./view";
const select = state => ({ const select = state => ({
rewards: selectClaimedRewardsByTransactionId(state), rewards: selectClaimedRewardsByTransactionId(state),
myClaims: selectAllMyClaimsByTxidNout(state),
resolvingUris: selectResolvingUris(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)), 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);

View file

@ -6,8 +6,12 @@ import Link from "component/link";
import lbryuri from "lbryuri"; import lbryuri from "lbryuri";
class TransactionListItem extends React.PureComponent { class TransactionListItem extends React.PureComponent {
abandonClaim(abandonData) {
this.props.revokeClaim(abandonData);
}
render() { render() {
const { reward, transaction } = this.props; const { reward, transaction, isRevokeable } = this.props;
const { const {
amount, amount,
claim_id: claimId, claim_id: claimId,
@ -16,8 +20,16 @@ class TransactionListItem extends React.PureComponent {
fee, fee,
txid, txid,
type, type,
nout,
} = transaction; } = transaction;
const abandonData = {
name: name,
claimId: claimId,
txid: txid,
nout: nout,
};
const dateFormat = { const dateFormat = {
month: "short", month: "short",
day: "numeric", day: "numeric",
@ -80,6 +92,12 @@ class TransactionListItem extends React.PureComponent {
<td> <td>
<LinkTransaction id={txid} /> <LinkTransaction id={txid} />
</td> </td>
<td>
{isRevokeable &&
<Link onClick={() => this.abandonClaim(abandonData)}>
{__("Revoke")}
</Link>}
</td>
</tr> </tr>
); );
} }

View file

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import TransactionListItem from "./internal/TransactionListItem"; import TransactionListItem from "./internal/TransactionListItem";
import FormField from "component/formField"; import FormField from "component/formField";
import lbryuri from "lbryuri";
class TransactionList extends React.PureComponent { class TransactionList extends React.PureComponent {
constructor(props) { constructor(props) {
@ -23,6 +24,27 @@ class TransactionList extends React.PureComponent {
return !filter || filter == transaction.type; 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() { render() {
const { emptyMessage, rewards, transactions } = this.props; const { emptyMessage, rewards, transactions } = this.props;
@ -62,6 +84,7 @@ class TransactionList extends React.PureComponent {
<th>{__("Type")} </th> <th>{__("Type")} </th>
<th>{__("Details")} </th> <th>{__("Details")} </th>
<th>{__("Transaction")}</th> <th>{__("Transaction")}</th>
<th>{__("Action")}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -70,6 +93,8 @@ class TransactionList extends React.PureComponent {
key={`${t.txid}:${t.nout}`} key={`${t.txid}:${t.nout}`}
transaction={t} transaction={t}
reward={rewards && rewards[t.txid]} reward={rewards && rewards[t.txid]}
isRevokeable={this.isRevokeable(t.txid, t.nout)}
revokeClaim={this.revokeClaim.bind(this)}
/> />
)} )}
</tbody> </tbody>

View file

@ -45,6 +45,9 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) {
const byId = Object.assign({}, state.byId); const byId = Object.assign({}, state.byId);
const pendingById = Object.assign({}, state.pendingById); const pendingById = Object.assign({}, state.pendingById);
const abandoningById = Object.assign({}, state.abandoningById); const abandoningById = Object.assign({}, state.abandoningById);
const allMyClaimsByTxidNout = new Set(
claims.map(claim => `${claim.txid}:${claim.nout}`)
);
const myClaims = new Set( const myClaims = new Set(
claims claims
.map(claim => claim.claim_id) .map(claim => claim.claim_id)
@ -78,6 +81,7 @@ reducers[types.FETCH_CLAIM_LIST_MINE_COMPLETED] = function(state, action) {
return Object.assign({}, state, { return Object.assign({}, state, {
isFetchingClaimListMine: false, isFetchingClaimListMine: false,
myClaims: myClaims, myClaims: myClaims,
allMyClaimsByTxidNout: allMyClaimsByTxidNout,
byId, byId,
pendingById, pendingById,
}); });
@ -157,21 +161,35 @@ reducers[types.ABANDON_CLAIM_STARTED] = function(state, action) {
}; };
reducers[types.ABANDON_CLAIM_SUCCEEDED] = 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 myClaims = new Set(state.myClaims);
const byId = Object.assign({}, state.byId); const byId = Object.assign({}, state.byId);
const claimsByUri = Object.assign({}, state.claimsByUri); const claimsByUri = Object.assign({}, state.claimsByUri);
const supports = byId[claimId].supports;
const uris = []; const uris = [];
Object.keys(claimsByUri).forEach(uri => { // This logic is needed when a claim has supports
if (claimsByUri[uri] === claimId) { // and it is the support that is being abandoned
delete claimsByUri[uri]; // 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]; supports.splice[(indexToDelete, 1)];
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, { return Object.assign({}, state, {
myClaims, myClaims,
byId, byId,

View file

@ -157,6 +157,11 @@ export const selectMyClaimsWithoutChannels = createSelector(
myClaims => myClaims.filter(claim => !claim.name.match(/^@/)) myClaims => myClaims.filter(claim => !claim.name.match(/^@/))
); );
export const selectAllMyClaimsByTxidNout = createSelector(
_selectState,
state => state.allMyClaimsByTxidNout || {}
);
export const selectMyClaimsOutpoints = createSelector( export const selectMyClaimsOutpoints = createSelector(
selectMyClaims, selectMyClaims,
myClaims => { myClaims => {

View file

@ -62,9 +62,10 @@ table.table-stretch {
} }
table.table-transactions { table.table-transactions {
td:nth-of-type(1) { width: 15%; } td:nth-of-type(1) { width: 13%; }
td:nth-of-type(2) { width: 15%; } td:nth-of-type(2) { width: 13%; }
td:nth-of-type(3) { width: 15%; } td:nth-of-type(3) { width: 13%; }
td:nth-of-type(4) { width: 40%; } td:nth-of-type(4) { width: 35%; }
td:nth-of-type(5) { width: 15%; } td:nth-of-type(5) { width: 13%; }
td:nth-of-type(6) { width: 13%; }
} }