[WIP] Comments #131
11 changed files with 380 additions and 6169 deletions
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"linters": {
|
||||
"src/**/*.{js,json}": ["prettier --write", "git add"],
|
||||
"src/**/*.js": ["eslint --fix", "git add"]
|
||||
"src/**/*.{js,json}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
],
|
||||
"src/**/*.js": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,15 @@ npm link lbry-redux
|
|||
### Build
|
||||
Run `$ yarn build`. If the symlink does not work, just build the file and move the `bundle.js` file in to the `node_modules/` folder.
|
||||
|
||||
#### Local Development with `lbry-desktop`
|
||||
If you're working with the desktop app and you've followed the steps above, then you'll want to
|
||||
run `$ yarn dev` (or equivalently `$ webpack --watch`). This will allow any changes made to the code
|
||||
to be automatically reflected in `dist/bundle.js`.
|
||||
|
||||
Once you've made your changes, running `(lbry-desktop)$ yarn dev` should have it automatically
|
||||
reloading changes. If this doesn't happen, just rebuild `lbry-redux` and
|
||||
[relink it to `lbry-desktop`](.README.md:11)
|
||||
|
||||
## Contributing
|
||||
We :heart: contributions from everyone! We welcome [bug reports](https://github.com/lbryio/lbry-redux/issues/), [bug fixes](https://github.com/lbryio/lbry-redux/pulls) and feedback on the module is always appreciated.
|
||||
|
||||
|
|
24
dist/bundle.es.js
vendored
24
dist/bundle.es.js
vendored
|
@ -653,6 +653,9 @@ const Lbry = {
|
|||
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
|
||||
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),
|
||||
|
||||
comment_list: (params = {}) => daemonCallWithResult('comment_list', params),
|
||||
comment_create: (params = {}) => daemonCallWithResult('comment_create', params),
|
||||
|
||||
// Connect to the sdk
|
||||
connect: () => {
|
||||
if (Lbry.connectPromise === null) {
|
||||
|
@ -1430,9 +1433,14 @@ const selectTransactionItems = reselect.createSelector(selectTransactionsById, b
|
|||
append.push(...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: ABANDON })));
|
||||
|
||||
if (!append.length) {
|
||||
append.push(Object.assign({}, tx, {
|
||||
type: tx.value < 0 ? SPEND : RECEIVE
|
||||
}));
|
||||
append.push(...tx.claim_info.map(item => Object.assign({}, tx, item, {
|
||||
type: item.claim_name[0] === '@' ? CHANNEL : PUBLISH
|
||||
})));
|
||||
append.push(...tx.support_info.map(item => Object.assign({}, tx, item, {
|
||||
type: !item.is_tip ? SUPPORT : TIP
|
||||
})));
|
||||
append.push(...tx.update_info.map(item => Object.assign({}, tx, item, { type: UPDATE })));
|
||||
append.push(...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: ABANDON })));
|
||||
}
|
||||
|
||||
items.push(...append.map(item => {
|
||||
|
@ -2229,14 +2237,18 @@ const selectSearchDownloadUris = query => reselect.createSelector(selectFileInfo
|
|||
});
|
||||
|
||||
return downloadResultsFromQuery.length ? downloadResultsFromQuery.map(fileInfo => {
|
||||
const { channel_name: channelName, claim_id: claimId, claim_name: claimName } = fileInfo;
|
||||
const {
|
||||
channel_name: channelName,
|
||||
claim_id: claimId,
|
||||
claim_name: claimName
|
||||
} = fileInfo;
|
||||
|
||||
const uriParams = {};
|
||||
|
||||
if (channelName) {
|
||||
const claim = claimsById[claimId];
|
||||
if (claim && claim.value) {
|
||||
uriParams.claimId = claim.value.publisherSignature.certificateId;
|
||||
if (claim) {
|
||||
uriParams.claimId = claim.channel_id;
|
||||
} else {
|
||||
uriParams.claimId = claimId;
|
||||
}
|
||||
|
|
5929
dist/bundle.js
vendored
5929
dist/bundle.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -90,6 +90,9 @@ const Lbry: LbryTypes = {
|
|||
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
|
||||
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),
|
||||
|
||||
comment_list: (params = {}) => daemonCallWithResult('comment_list', params),
|
||||
comment_create: (params = {}) => daemonCallWithResult('comment_create', params),
|
||||
|
||||
// Connect to the sdk
|
||||
connect: () => {
|
||||
if (Lbry.connectPromise === null) {
|
||||
|
|
|
@ -4,11 +4,15 @@ import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
|||
export const selectState = (state: any) => state.content || {};
|
||||
|
||||
export const makeSelectContentPositionForUri = (uri: string) =>
|
||||
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
|
||||
if (!claim) {
|
||||
return null;
|
||||
createSelector(
|
||||
selectState,
|
||||
makeSelectClaimForUri(uri),
|
||||
(state, claim) => {
|
||||
if (!claim) {
|
||||
return null;
|
||||
}
|
||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
||||
const id = claim.claim_id;
|
||||
return state.positions[id] ? state.positions[id][outpoint] : null;
|
||||
}
|
||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
||||
const id = claim.claim_id;
|
||||
return state.positions[id] ? state.positions[id][outpoint] : null;
|
||||
});
|
||||
);
|
||||
|
|
|
@ -26,11 +26,15 @@ export const selectIsFetchingFileListDownloadedOrPublished = createSelector(
|
|||
);
|
||||
|
||||
export const makeSelectFileInfoForUri = uri =>
|
||||
createSelector(selectClaimsByUri, selectFileInfosByOutpoint, (claims, byOutpoint) => {
|
||||
const claim = claims[uri];
|
||||
const outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
||||
return outpoint ? byOutpoint[outpoint] : undefined;
|
||||
});
|
||||
createSelector(
|
||||
selectClaimsByUri,
|
||||
selectFileInfosByOutpoint,
|
||||
(claims, byOutpoint) => {
|
||||
const claim = claims[uri];
|
||||
const outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
||||
return outpoint ? byOutpoint[outpoint] : undefined;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectDownloadingByOutpoint = createSelector(
|
||||
selectState,
|
||||
|
@ -47,10 +51,16 @@ export const makeSelectDownloadingForUri = uri =>
|
|||
}
|
||||
);
|
||||
|
||||
export const selectUrisLoading = createSelector(selectState, state => state.urisLoading || {});
|
||||
export const selectUrisLoading = createSelector(
|
||||
selectState,
|
||||
state => state.urisLoading || {}
|
||||
);
|
||||
|
||||
export const makeSelectLoadingForUri = uri =>
|
||||
createSelector(selectUrisLoading, byUri => byUri && byUri[uri]);
|
||||
createSelector(
|
||||
selectUrisLoading,
|
||||
byUri => byUri && byUri[uri]
|
||||
);
|
||||
|
||||
export const selectFileInfosDownloaded = createSelector(
|
||||
selectFileInfosByOutpoint,
|
||||
|
@ -93,93 +103,103 @@ export const selectDownloadingFileInfos = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
export const selectTotalDownloadProgress = createSelector(selectDownloadingFileInfos, fileInfos => {
|
||||
const progress = [];
|
||||
export const selectTotalDownloadProgress = createSelector(
|
||||
selectDownloadingFileInfos,
|
||||
fileInfos => {
|
||||
const progress = [];
|
||||
|
||||
fileInfos.forEach(fileInfo => {
|
||||
progress.push((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
||||
});
|
||||
fileInfos.forEach(fileInfo => {
|
||||
progress.push((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
||||
});
|
||||
|
||||
const totalProgress = progress.reduce((a, b) => a + b, 0);
|
||||
const totalProgress = progress.reduce((a, b) => a + b, 0);
|
||||
|
||||
if (fileInfos.length > 0) return totalProgress / fileInfos.length / 100.0;
|
||||
return -1;
|
||||
});
|
||||
if (fileInfos.length > 0) return totalProgress / fileInfos.length / 100.0;
|
||||
return -1;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectSearchDownloadUris = query =>
|
||||
createSelector(selectFileInfosDownloaded, selectClaimsById, (fileInfos, claimsById) => {
|
||||
if (!query || !fileInfos.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const queryParts = query.toLowerCase().split(' ');
|
||||
const searchQueryDictionary = {};
|
||||
queryParts.forEach(subQuery => {
|
||||
searchQueryDictionary[subQuery] = subQuery;
|
||||
});
|
||||
|
||||
const arrayContainsQueryPart = array => {
|
||||
for (let i = 0; i < array.length; i += 1) {
|
||||
const subQuery = array[i];
|
||||
if (searchQueryDictionary[subQuery]) {
|
||||
return true;
|
||||
}
|
||||
createSelector(
|
||||
selectFileInfosDownloaded,
|
||||
selectClaimsById,
|
||||
(fileInfos, claimsById) => {
|
||||
if (!query || !fileInfos.length) {
|
||||
return null;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const downloadResultsFromQuery = [];
|
||||
fileInfos.forEach(fileInfo => {
|
||||
const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo;
|
||||
const { author, description, title } = metadata;
|
||||
const queryParts = query.toLowerCase().split(' ');
|
||||
const searchQueryDictionary = {};
|
||||
queryParts.forEach(subQuery => {
|
||||
searchQueryDictionary[subQuery] = subQuery;
|
||||
});
|
||||
|
||||
if (channelName) {
|
||||
const lowerCaseChannel = channelName.toLowerCase();
|
||||
const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @
|
||||
if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) {
|
||||
const arrayContainsQueryPart = array => {
|
||||
for (let i = 0; i < array.length; i += 1) {
|
||||
const subQuery = array[i];
|
||||
if (searchQueryDictionary[subQuery]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const downloadResultsFromQuery = [];
|
||||
fileInfos.forEach(fileInfo => {
|
||||
const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo;
|
||||
const { author, description, title } = metadata;
|
||||
|
||||
if (channelName) {
|
||||
const lowerCaseChannel = channelName.toLowerCase();
|
||||
const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @
|
||||
if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const nameParts = claimName.toLowerCase().split('-');
|
||||
if (arrayContainsQueryPart(nameParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const nameParts = claimName.toLowerCase().split('-');
|
||||
if (arrayContainsQueryPart(nameParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
const titleParts = title.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(titleParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (author) {
|
||||
const authorParts = author.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(authorParts)) {
|
||||
const titleParts = title.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(titleParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (description) {
|
||||
const descriptionParts = description.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(descriptionParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
if (author) {
|
||||
const authorParts = author.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(authorParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return downloadResultsFromQuery.length
|
||||
? downloadResultsFromQuery.map(fileInfo => {
|
||||
const { channel_name: channelName, claim_id: claimId, claim_name: claimName } = fileInfo;
|
||||
if (description) {
|
||||
const descriptionParts = description.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(descriptionParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return downloadResultsFromQuery.length
|
||||
? downloadResultsFromQuery.map(fileInfo => {
|
||||
const {
|
||||
channel_name: channelName,
|
||||
claim_id: claimId,
|
||||
claim_name: claimName,
|
||||
} = fileInfo;
|
||||
|
||||
const uriParams = {};
|
||||
|
||||
if (channelName) {
|
||||
const claim = claimsById[claimId];
|
||||
if (claim && claim.value) {
|
||||
uriParams.claimId = claim.value.publisherSignature.certificateId;
|
||||
if (claim) {
|
||||
uriParams.claimId = claim.channel_id;
|
||||
} else {
|
||||
uriParams.claimId = claimId;
|
||||
}
|
||||
|
@ -193,8 +213,9 @@ export const selectSearchDownloadUris = query =>
|
|||
const uri = buildURI(uriParams);
|
||||
return uri;
|
||||
})
|
||||
: null;
|
||||
});
|
||||
: null;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectFileListPublishedSort = createSelector(
|
||||
selectState,
|
||||
|
|
|
@ -3,38 +3,63 @@ import { parseQueryParams } from 'util/query_params';
|
|||
|
||||
export const selectState = state => state.navigation || {};
|
||||
|
||||
export const selectCurrentPath = createSelector(selectState, state => state.currentPath);
|
||||
export const selectCurrentPath = createSelector(
|
||||
selectState,
|
||||
state => state.currentPath
|
||||
);
|
||||
|
||||
export const computePageFromPath = path => (path ? path.replace(/^\//, '').split('?')[0] : '');
|
||||
|
||||
export const selectCurrentPage = createSelector(selectCurrentPath, path =>
|
||||
computePageFromPath(path)
|
||||
export const selectCurrentPage = createSelector(
|
||||
selectCurrentPath,
|
||||
path => computePageFromPath(path)
|
||||
);
|
||||
|
||||
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
|
||||
if (path === undefined) return {};
|
||||
if (!path.match(/\?/)) return {};
|
||||
export const selectCurrentParams = createSelector(
|
||||
selectCurrentPath,
|
||||
path => {
|
||||
if (path === undefined) return {};
|
||||
if (!path.match(/\?/)) return {};
|
||||
|
||||
return parseQueryParams(path.split('?')[1]);
|
||||
});
|
||||
return parseQueryParams(path.split('?')[1]);
|
||||
}
|
||||
);
|
||||
|
||||
export const makeSelectCurrentParam = param =>
|
||||
createSelector(selectCurrentParams, params => (params ? params[param] : undefined));
|
||||
createSelector(
|
||||
selectCurrentParams,
|
||||
params => (params ? params[param] : undefined)
|
||||
);
|
||||
|
||||
export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth);
|
||||
export const selectPathAfterAuth = createSelector(
|
||||
selectState,
|
||||
state => state.pathAfterAuth
|
||||
);
|
||||
|
||||
export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0);
|
||||
export const selectIsBackDisabled = createSelector(
|
||||
selectState,
|
||||
state => state.index === 0
|
||||
);
|
||||
|
||||
export const selectIsForwardDisabled = createSelector(
|
||||
selectState,
|
||||
state => state.index === state.stack.length - 1
|
||||
);
|
||||
|
||||
export const selectIsHome = createSelector(selectCurrentPage, page => page === 'discover');
|
||||
export const selectIsHome = createSelector(
|
||||
selectCurrentPage,
|
||||
page => page === 'discover'
|
||||
);
|
||||
|
||||
export const selectHistoryIndex = createSelector(selectState, state => state.index);
|
||||
export const selectHistoryIndex = createSelector(
|
||||
selectState,
|
||||
state => state.index
|
||||
);
|
||||
|
||||
export const selectHistoryStack = createSelector(selectState, state => state.stack);
|
||||
export const selectHistoryStack = createSelector(
|
||||
selectState,
|
||||
state => state.stack
|
||||
);
|
||||
|
||||
// returns current page attributes (scrollY, path)
|
||||
export const selectActiveHistoryEntry = createSelector(
|
||||
|
@ -42,9 +67,12 @@ export const selectActiveHistoryEntry = createSelector(
|
|||
state => state.stack[state.index]
|
||||
);
|
||||
|
||||
export const selectPageTitle = createSelector(selectCurrentPage, page => {
|
||||
switch (page) {
|
||||
default:
|
||||
return '';
|
||||
export const selectPageTitle = createSelector(
|
||||
selectCurrentPage,
|
||||
page => {
|
||||
switch (page) {
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
|
|
@ -1,26 +1,32 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
export const selectState = (state) => state.notifications || {};
|
||||
export const selectState = state => state.notifications || {};
|
||||
|
||||
export const selectToast = createSelector(selectState, (state) => {
|
||||
if (state.toasts.length) {
|
||||
const { id, params } = state.toasts[0];
|
||||
return {
|
||||
id,
|
||||
...params,
|
||||
};
|
||||
export const selectToast = createSelector(
|
||||
selectState,
|
||||
state => {
|
||||
if (state.toasts.length) {
|
||||
const { id, params } = state.toasts[0];
|
||||
return {
|
||||
id,
|
||||
...params,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return null;
|
||||
});
|
||||
export const selectError = createSelector(
|
||||
selectState,
|
||||
state => {
|
||||
if (state.errors.length) {
|
||||
const { error } = state.errors[0];
|
||||
return {
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export const selectError = createSelector(selectState, (state) => {
|
||||
if (state.errors.length) {
|
||||
const { error } = state.errors[0];
|
||||
return {
|
||||
error,
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
);
|
||||
|
|
|
@ -65,112 +65,147 @@ export const selectWalletLockSucceeded = createSelector(
|
|||
state => state.walletLockSucceded
|
||||
);
|
||||
|
||||
export const selectWalletLockResult = createSelector(selectState, state => state.walletLockResult);
|
||||
export const selectWalletLockResult = createSelector(
|
||||
selectState,
|
||||
state => state.walletLockResult
|
||||
);
|
||||
|
||||
export const selectBalance = createSelector(selectState, state => state.balance);
|
||||
export const selectBalance = createSelector(
|
||||
selectState,
|
||||
state => state.balance
|
||||
);
|
||||
|
||||
export const selectTotalBalance = createSelector(selectState, state => state.totalBalance);
|
||||
export const selectTotalBalance = createSelector(
|
||||
selectState,
|
||||
state => state.totalBalance
|
||||
);
|
||||
|
||||
export const selectTransactionsById = createSelector(selectState, state => state.transactions);
|
||||
export const selectTransactionsById = createSelector(
|
||||
selectState,
|
||||
state => state.transactions
|
||||
);
|
||||
|
||||
export const selectTransactionItems = createSelector(selectTransactionsById, byId => {
|
||||
const items = [];
|
||||
export const selectTransactionItems = createSelector(
|
||||
selectTransactionsById,
|
||||
byId => {
|
||||
const items = [];
|
||||
|
||||
Object.keys(byId).forEach(txid => {
|
||||
const tx = byId[txid];
|
||||
Object.keys(byId).forEach(txid => {
|
||||
const tx = byId[txid];
|
||||
|
||||
// ignore dust/fees
|
||||
// it is fee only txn if all infos are also empty
|
||||
if (
|
||||
Math.abs(tx.value) === Math.abs(tx.fee) &&
|
||||
tx.claim_info.length === 0 &&
|
||||
tx.support_info.length === 0 &&
|
||||
tx.update_info.length === 0 &&
|
||||
tx.abandon_info.length === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// ignore dust/fees
|
||||
// it is fee only txn if all infos are also empty
|
||||
if (
|
||||
Math.abs(tx.value) === Math.abs(tx.fee) &&
|
||||
tx.claim_info.length === 0 &&
|
||||
tx.support_info.length === 0 &&
|
||||
tx.update_info.length === 0 &&
|
||||
tx.abandon_info.length === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const append = [];
|
||||
const append = [];
|
||||
|
||||
append.push(
|
||||
...tx.claim_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: item.claim_name[0] === '@' ? TRANSACTIONS.CHANNEL : TRANSACTIONS.PUBLISH,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.support_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: !item.is_tip ? TRANSACTIONS.SUPPORT : TRANSACTIONS.TIP,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.update_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.UPDATE }))
|
||||
);
|
||||
append.push(
|
||||
...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.ABANDON }))
|
||||
);
|
||||
|
||||
if (!append.length) {
|
||||
append.push(
|
||||
Object.assign({}, tx, {
|
||||
type: tx.value < 0 ? TRANSACTIONS.SPEND : TRANSACTIONS.RECEIVE,
|
||||
...tx.claim_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: item.claim_name[0] === '@' ? TRANSACTIONS.CHANNEL : TRANSACTIONS.PUBLISH,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.support_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: !item.is_tip ? TRANSACTIONS.SUPPORT : TRANSACTIONS.TIP,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.update_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.UPDATE }))
|
||||
);
|
||||
append.push(
|
||||
...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.ABANDON }))
|
||||
);
|
||||
|
||||
if (!append.length) {
|
||||
append.push(
|
||||
...tx.claim_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: item.claim_name[0] === '@' ? TRANSACTIONS.CHANNEL : TRANSACTIONS.PUBLISH,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.support_info.map(item =>
|
||||
Object.assign({}, tx, item, {
|
||||
type: !item.is_tip ? TRANSACTIONS.SUPPORT : TRANSACTIONS.TIP,
|
||||
})
|
||||
)
|
||||
);
|
||||
append.push(
|
||||
...tx.update_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.UPDATE }))
|
||||
);
|
||||
append.push(
|
||||
...tx.abandon_info.map(item =>
|
||||
Object.assign({}, tx, item, { type: TRANSACTIONS.ABANDON })
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
items.push(
|
||||
...append.map(item => {
|
||||
// value on transaction, amount on outpoint
|
||||
// amount is always positive, but should match sign of value
|
||||
const balanceDelta = parseFloat(item.balance_delta);
|
||||
const value = parseFloat(item.value);
|
||||
const amount = balanceDelta || value;
|
||||
const fee = parseFloat(tx.fee);
|
||||
|
||||
return {
|
||||
txid,
|
||||
timestamp: tx.timestamp,
|
||||
date: tx.timestamp ? new Date(Number(tx.timestamp) * 1000) : null,
|
||||
amount,
|
||||
fee,
|
||||
claim_id: item.claim_id,
|
||||
claim_name: item.claim_name,
|
||||
type: item.type || TRANSACTIONS.SPEND,
|
||||
nout: item.nout,
|
||||
confirmations: tx.confirmations,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
items.push(
|
||||
...append.map(item => {
|
||||
// value on transaction, amount on outpoint
|
||||
// amount is always positive, but should match sign of value
|
||||
const balanceDelta = parseFloat(item.balance_delta);
|
||||
const value = parseFloat(item.value);
|
||||
const amount = balanceDelta || value;
|
||||
const fee = parseFloat(tx.fee);
|
||||
return items.sort((tx1, tx2) => {
|
||||
if (!tx1.timestamp && !tx2.timestamp) {
|
||||
return 0;
|
||||
} else if (!tx1.timestamp && tx2.timestamp) {
|
||||
return -1;
|
||||
} else if (tx1.timestamp && !tx2.timestamp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return {
|
||||
txid,
|
||||
timestamp: tx.timestamp,
|
||||
date: tx.timestamp ? new Date(Number(tx.timestamp) * 1000) : null,
|
||||
amount,
|
||||
fee,
|
||||
claim_id: item.claim_id,
|
||||
claim_name: item.claim_name,
|
||||
type: item.type || TRANSACTIONS.SPEND,
|
||||
nout: item.nout,
|
||||
confirmations: tx.confirmations,
|
||||
};
|
||||
})
|
||||
);
|
||||
});
|
||||
return tx2.timestamp - tx1.timestamp;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return items.sort((tx1, tx2) => {
|
||||
if (!tx1.timestamp && !tx2.timestamp) {
|
||||
return 0;
|
||||
} else if (!tx1.timestamp && tx2.timestamp) {
|
||||
return -1;
|
||||
} else if (tx1.timestamp && !tx2.timestamp) {
|
||||
return 1;
|
||||
}
|
||||
export const selectRecentTransactions = createSelector(
|
||||
selectTransactionItems,
|
||||
transactions => {
|
||||
const threshold = new Date();
|
||||
threshold.setDate(threshold.getDate() - 7);
|
||||
return transactions.filter(transaction => {
|
||||
if (!transaction.date) {
|
||||
return true; // pending transaction
|
||||
}
|
||||
|
||||
return tx2.timestamp - tx1.timestamp;
|
||||
});
|
||||
});
|
||||
|
||||
export const selectRecentTransactions = createSelector(selectTransactionItems, transactions => {
|
||||
const threshold = new Date();
|
||||
threshold.setDate(threshold.getDate() - 7);
|
||||
return transactions.filter(transaction => {
|
||||
if (!transaction.date) {
|
||||
return true; // pending transaction
|
||||
}
|
||||
|
||||
return transaction.date > threshold;
|
||||
});
|
||||
});
|
||||
return transaction.date > threshold;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export const selectHasTransactions = createSelector(
|
||||
selectTransactionItems,
|
||||
|
@ -182,9 +217,15 @@ export const selectIsFetchingTransactions = createSelector(
|
|||
state => state.fetchingTransactions
|
||||
);
|
||||
|
||||
export const selectIsSendingSupport = createSelector(selectState, state => state.sendingSupport);
|
||||
export const selectIsSendingSupport = createSelector(
|
||||
selectState,
|
||||
state => state.sendingSupport
|
||||
);
|
||||
|
||||
export const selectReceiveAddress = createSelector(selectState, state => state.receiveAddress);
|
||||
export const selectReceiveAddress = createSelector(
|
||||
selectState,
|
||||
state => state.receiveAddress
|
||||
);
|
||||
|
||||
export const selectGettingNewAddress = createSelector(
|
||||
selectState,
|
||||
|
@ -211,30 +252,40 @@ export const selectDraftTransactionError = createSelector(
|
|||
draft => draft.error
|
||||
);
|
||||
|
||||
export const selectBlocks = createSelector(selectState, state => state.blocks);
|
||||
export const selectBlocks = createSelector(
|
||||
selectState,
|
||||
state => state.blocks
|
||||
);
|
||||
|
||||
export const selectCurrentHeight = createSelector(selectState, state => state.latestBlock);
|
||||
export const selectCurrentHeight = createSelector(
|
||||
selectState,
|
||||
state => state.latestBlock
|
||||
);
|
||||
|
||||
export const makeSelectBlockDate = block =>
|
||||
createSelector(selectBlocks, selectCurrentHeight, (blocks, latestBlock) => {
|
||||
// If we have the block data, look at the actual date,
|
||||
// If not, try to simulate it based on 2.5 minute blocks
|
||||
// Adding this on 11/7/2018 because caling block_show for every claim is causing
|
||||
// performance issues.
|
||||
if (blocks && blocks[block]) {
|
||||
return new Date(blocks[block].time * 1000);
|
||||
}
|
||||
createSelector(
|
||||
selectBlocks,
|
||||
selectCurrentHeight,
|
||||
(blocks, latestBlock) => {
|
||||
// If we have the block data, look at the actual date,
|
||||
// If not, try to simulate it based on 2.5 minute blocks
|
||||
// Adding this on 11/7/2018 because caling block_show for every claim is causing
|
||||
// performance issues.
|
||||
if (blocks && blocks[block]) {
|
||||
return new Date(blocks[block].time * 1000);
|
||||
}
|
||||
|
||||
// Pending claim
|
||||
if (block < 1) {
|
||||
return null;
|
||||
}
|
||||
// Pending claim
|
||||
if (block < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const difference = latestBlock - block;
|
||||
const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms
|
||||
const publishDate = Date.now() - msSincePublish;
|
||||
return new Date(publishDate);
|
||||
});
|
||||
const difference = latestBlock - block;
|
||||
const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms
|
||||
const publishDate = Date.now() - msSincePublish;
|
||||
return new Date(publishDate);
|
||||
}
|
||||
);
|
||||
|
||||
export const selectTransactionListFilter = createSelector(
|
||||
selectState,
|
||||
|
|
|
@ -13,7 +13,7 @@ export function formatFullPrice(amount, precision = 1) {
|
|||
|
||||
if (fraction) {
|
||||
const decimals = fraction.split('');
|
||||
const first = decimals.filter((number) => number !== '0')[0];
|
||||
const first = decimals.filter(number => number !== '0')[0];
|
||||
const index = decimals.indexOf(first);
|
||||
|
||||
// Set format fraction
|
||||
|
|
Loading…
Reference in a new issue