[WIP] Comments #131
11 changed files with 380 additions and 6169 deletions
|
@ -1,6 +1,12 @@
|
||||||
{
|
{
|
||||||
"linters": {
|
"linters": {
|
||||||
"src/**/*.{js,json}": ["prettier --write", "git add"],
|
"src/**/*.{js,json}": [
|
||||||
"src/**/*.js": ["eslint --fix", "git add"]
|
"prettier --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"src/**/*.js": [
|
||||||
|
"eslint --fix",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,15 @@ npm link lbry-redux
|
||||||
### Build
|
### 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.
|
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
|
## 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.
|
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_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
|
||||||
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', 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 to the sdk
|
||||||
connect: () => {
|
connect: () => {
|
||||||
if (Lbry.connectPromise === null) {
|
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 })));
|
append.push(...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: ABANDON })));
|
||||||
|
|
||||||
if (!append.length) {
|
if (!append.length) {
|
||||||
append.push(Object.assign({}, tx, {
|
append.push(...tx.claim_info.map(item => Object.assign({}, tx, item, {
|
||||||
type: tx.value < 0 ? SPEND : RECEIVE
|
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 => {
|
items.push(...append.map(item => {
|
||||||
|
@ -2229,14 +2237,18 @@ const selectSearchDownloadUris = query => reselect.createSelector(selectFileInfo
|
||||||
});
|
});
|
||||||
|
|
||||||
return downloadResultsFromQuery.length ? downloadResultsFromQuery.map(fileInfo => {
|
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 = {};
|
const uriParams = {};
|
||||||
|
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
const claim = claimsById[claimId];
|
const claim = claimsById[claimId];
|
||||||
if (claim && claim.value) {
|
if (claim) {
|
||||||
uriParams.claimId = claim.value.publisherSignature.certificateId;
|
uriParams.claimId = claim.channel_id;
|
||||||
} else {
|
} else {
|
||||||
uriParams.claimId = claimId;
|
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_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
|
||||||
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', 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 to the sdk
|
||||||
connect: () => {
|
connect: () => {
|
||||||
if (Lbry.connectPromise === null) {
|
if (Lbry.connectPromise === null) {
|
||||||
|
|
|
@ -4,11 +4,15 @@ import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||||
export const selectState = (state: any) => state.content || {};
|
export const selectState = (state: any) => state.content || {};
|
||||||
|
|
||||||
export const makeSelectContentPositionForUri = (uri: string) =>
|
export const makeSelectContentPositionForUri = (uri: string) =>
|
||||||
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
|
createSelector(
|
||||||
if (!claim) {
|
selectState,
|
||||||
return null;
|
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 =>
|
export const makeSelectFileInfoForUri = uri =>
|
||||||
createSelector(selectClaimsByUri, selectFileInfosByOutpoint, (claims, byOutpoint) => {
|
createSelector(
|
||||||
const claim = claims[uri];
|
selectClaimsByUri,
|
||||||
const outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
selectFileInfosByOutpoint,
|
||||||
return outpoint ? byOutpoint[outpoint] : undefined;
|
(claims, byOutpoint) => {
|
||||||
});
|
const claim = claims[uri];
|
||||||
|
const outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
||||||
|
return outpoint ? byOutpoint[outpoint] : undefined;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const selectDownloadingByOutpoint = createSelector(
|
export const selectDownloadingByOutpoint = createSelector(
|
||||||
selectState,
|
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 =>
|
export const makeSelectLoadingForUri = uri =>
|
||||||
createSelector(selectUrisLoading, byUri => byUri && byUri[uri]);
|
createSelector(
|
||||||
|
selectUrisLoading,
|
||||||
|
byUri => byUri && byUri[uri]
|
||||||
|
);
|
||||||
|
|
||||||
export const selectFileInfosDownloaded = createSelector(
|
export const selectFileInfosDownloaded = createSelector(
|
||||||
selectFileInfosByOutpoint,
|
selectFileInfosByOutpoint,
|
||||||
|
@ -93,93 +103,103 @@ export const selectDownloadingFileInfos = createSelector(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectTotalDownloadProgress = createSelector(selectDownloadingFileInfos, fileInfos => {
|
export const selectTotalDownloadProgress = createSelector(
|
||||||
const progress = [];
|
selectDownloadingFileInfos,
|
||||||
|
fileInfos => {
|
||||||
|
const progress = [];
|
||||||
|
|
||||||
fileInfos.forEach(fileInfo => {
|
fileInfos.forEach(fileInfo => {
|
||||||
progress.push((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
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;
|
if (fileInfos.length > 0) return totalProgress / fileInfos.length / 100.0;
|
||||||
return -1;
|
return -1;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const selectSearchDownloadUris = query =>
|
export const selectSearchDownloadUris = query =>
|
||||||
createSelector(selectFileInfosDownloaded, selectClaimsById, (fileInfos, claimsById) => {
|
createSelector(
|
||||||
if (!query || !fileInfos.length) {
|
selectFileInfosDownloaded,
|
||||||
return null;
|
selectClaimsById,
|
||||||
}
|
(fileInfos, claimsById) => {
|
||||||
|
if (!query || !fileInfos.length) {
|
||||||
const queryParts = query.toLowerCase().split(' ');
|
return null;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadResultsFromQuery = [];
|
const queryParts = query.toLowerCase().split(' ');
|
||||||
fileInfos.forEach(fileInfo => {
|
const searchQueryDictionary = {};
|
||||||
const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo;
|
queryParts.forEach(subQuery => {
|
||||||
const { author, description, title } = metadata;
|
searchQueryDictionary[subQuery] = subQuery;
|
||||||
|
});
|
||||||
|
|
||||||
if (channelName) {
|
const arrayContainsQueryPart = array => {
|
||||||
const lowerCaseChannel = channelName.toLowerCase();
|
for (let i = 0; i < array.length; i += 1) {
|
||||||
const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @
|
const subQuery = array[i];
|
||||||
if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) {
|
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);
|
downloadResultsFromQuery.push(fileInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const nameParts = claimName.toLowerCase().split('-');
|
const titleParts = title.toLowerCase().split(' ');
|
||||||
if (arrayContainsQueryPart(nameParts)) {
|
if (arrayContainsQueryPart(titleParts)) {
|
||||||
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)) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
downloadResultsFromQuery.push(fileInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (description) {
|
if (author) {
|
||||||
const descriptionParts = description.toLowerCase().split(' ');
|
const authorParts = author.toLowerCase().split(' ');
|
||||||
if (arrayContainsQueryPart(descriptionParts)) {
|
if (arrayContainsQueryPart(authorParts)) {
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
downloadResultsFromQuery.push(fileInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return downloadResultsFromQuery.length
|
if (description) {
|
||||||
? downloadResultsFromQuery.map(fileInfo => {
|
const descriptionParts = description.toLowerCase().split(' ');
|
||||||
const { channel_name: channelName, claim_id: claimId, claim_name: claimName } = fileInfo;
|
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 = {};
|
const uriParams = {};
|
||||||
|
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
const claim = claimsById[claimId];
|
const claim = claimsById[claimId];
|
||||||
if (claim && claim.value) {
|
if (claim) {
|
||||||
uriParams.claimId = claim.value.publisherSignature.certificateId;
|
uriParams.claimId = claim.channel_id;
|
||||||
} else {
|
} else {
|
||||||
uriParams.claimId = claimId;
|
uriParams.claimId = claimId;
|
||||||
}
|
}
|
||||||
|
@ -193,8 +213,9 @@ export const selectSearchDownloadUris = query =>
|
||||||
const uri = buildURI(uriParams);
|
const uri = buildURI(uriParams);
|
||||||
return uri;
|
return uri;
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const selectFileListPublishedSort = createSelector(
|
export const selectFileListPublishedSort = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
|
|
|
@ -3,38 +3,63 @@ import { parseQueryParams } from 'util/query_params';
|
||||||
|
|
||||||
export const selectState = state => state.navigation || {};
|
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 computePageFromPath = path => (path ? path.replace(/^\//, '').split('?')[0] : '');
|
||||||
|
|
||||||
export const selectCurrentPage = createSelector(selectCurrentPath, path =>
|
export const selectCurrentPage = createSelector(
|
||||||
computePageFromPath(path)
|
selectCurrentPath,
|
||||||
|
path => computePageFromPath(path)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
|
export const selectCurrentParams = createSelector(
|
||||||
if (path === undefined) return {};
|
selectCurrentPath,
|
||||||
if (!path.match(/\?/)) return {};
|
path => {
|
||||||
|
if (path === undefined) return {};
|
||||||
|
if (!path.match(/\?/)) return {};
|
||||||
|
|
||||||
return parseQueryParams(path.split('?')[1]);
|
return parseQueryParams(path.split('?')[1]);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const makeSelectCurrentParam = param =>
|
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(
|
export const selectIsForwardDisabled = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.index === state.stack.length - 1
|
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)
|
// returns current page attributes (scrollY, path)
|
||||||
export const selectActiveHistoryEntry = createSelector(
|
export const selectActiveHistoryEntry = createSelector(
|
||||||
|
@ -42,9 +67,12 @@ export const selectActiveHistoryEntry = createSelector(
|
||||||
state => state.stack[state.index]
|
state => state.stack[state.index]
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectPageTitle = createSelector(selectCurrentPage, page => {
|
export const selectPageTitle = createSelector(
|
||||||
switch (page) {
|
selectCurrentPage,
|
||||||
default:
|
page => {
|
||||||
return '';
|
switch (page) {
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
export const selectState = (state) => state.notifications || {};
|
export const selectState = state => state.notifications || {};
|
||||||
|
|
||||||
export const selectToast = createSelector(selectState, (state) => {
|
export const selectToast = createSelector(
|
||||||
if (state.toasts.length) {
|
selectState,
|
||||||
const { id, params } = state.toasts[0];
|
state => {
|
||||||
return {
|
if (state.toasts.length) {
|
||||||
id,
|
const { id, params } = state.toasts[0];
|
||||||
...params,
|
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) => {
|
return null;
|
||||||
if (state.errors.length) {
|
|
||||||
const { error } = state.errors[0];
|
|
||||||
return {
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
|
@ -65,112 +65,147 @@ export const selectWalletLockSucceeded = createSelector(
|
||||||
state => state.walletLockSucceded
|
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 => {
|
export const selectTransactionItems = createSelector(
|
||||||
const items = [];
|
selectTransactionsById,
|
||||||
|
byId => {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
Object.keys(byId).forEach(txid => {
|
Object.keys(byId).forEach(txid => {
|
||||||
const tx = byId[txid];
|
const tx = byId[txid];
|
||||||
|
|
||||||
// ignore dust/fees
|
// ignore dust/fees
|
||||||
// it is fee only txn if all infos are also empty
|
// it is fee only txn if all infos are also empty
|
||||||
if (
|
if (
|
||||||
Math.abs(tx.value) === Math.abs(tx.fee) &&
|
Math.abs(tx.value) === Math.abs(tx.fee) &&
|
||||||
tx.claim_info.length === 0 &&
|
tx.claim_info.length === 0 &&
|
||||||
tx.support_info.length === 0 &&
|
tx.support_info.length === 0 &&
|
||||||
tx.update_info.length === 0 &&
|
tx.update_info.length === 0 &&
|
||||||
tx.abandon_info.length === 0
|
tx.abandon_info.length === 0
|
||||||
) {
|
) {
|
||||||
return;
|
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(
|
append.push(
|
||||||
Object.assign({}, tx, {
|
...tx.claim_info.map(item =>
|
||||||
type: tx.value < 0 ? TRANSACTIONS.SPEND : TRANSACTIONS.RECEIVE,
|
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(
|
return items.sort((tx1, tx2) => {
|
||||||
...append.map(item => {
|
if (!tx1.timestamp && !tx2.timestamp) {
|
||||||
// value on transaction, amount on outpoint
|
return 0;
|
||||||
// amount is always positive, but should match sign of value
|
} else if (!tx1.timestamp && tx2.timestamp) {
|
||||||
const balanceDelta = parseFloat(item.balance_delta);
|
return -1;
|
||||||
const value = parseFloat(item.value);
|
} else if (tx1.timestamp && !tx2.timestamp) {
|
||||||
const amount = balanceDelta || value;
|
return 1;
|
||||||
const fee = parseFloat(tx.fee);
|
}
|
||||||
|
|
||||||
return {
|
return tx2.timestamp - tx1.timestamp;
|
||||||
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 items.sort((tx1, tx2) => {
|
export const selectRecentTransactions = createSelector(
|
||||||
if (!tx1.timestamp && !tx2.timestamp) {
|
selectTransactionItems,
|
||||||
return 0;
|
transactions => {
|
||||||
} else if (!tx1.timestamp && tx2.timestamp) {
|
const threshold = new Date();
|
||||||
return -1;
|
threshold.setDate(threshold.getDate() - 7);
|
||||||
} else if (tx1.timestamp && !tx2.timestamp) {
|
return transactions.filter(transaction => {
|
||||||
return 1;
|
if (!transaction.date) {
|
||||||
}
|
return true; // pending transaction
|
||||||
|
}
|
||||||
|
|
||||||
return tx2.timestamp - tx1.timestamp;
|
return transaction.date > threshold;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectHasTransactions = createSelector(
|
export const selectHasTransactions = createSelector(
|
||||||
selectTransactionItems,
|
selectTransactionItems,
|
||||||
|
@ -182,9 +217,15 @@ export const selectIsFetchingTransactions = createSelector(
|
||||||
state => state.fetchingTransactions
|
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(
|
export const selectGettingNewAddress = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
|
@ -211,30 +252,40 @@ export const selectDraftTransactionError = createSelector(
|
||||||
draft => draft.error
|
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 =>
|
export const makeSelectBlockDate = block =>
|
||||||
createSelector(selectBlocks, selectCurrentHeight, (blocks, latestBlock) => {
|
createSelector(
|
||||||
// If we have the block data, look at the actual date,
|
selectBlocks,
|
||||||
// If not, try to simulate it based on 2.5 minute blocks
|
selectCurrentHeight,
|
||||||
// Adding this on 11/7/2018 because caling block_show for every claim is causing
|
(blocks, latestBlock) => {
|
||||||
// performance issues.
|
// If we have the block data, look at the actual date,
|
||||||
if (blocks && blocks[block]) {
|
// If not, try to simulate it based on 2.5 minute blocks
|
||||||
return new Date(blocks[block].time * 1000);
|
// 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
|
// Pending claim
|
||||||
if (block < 1) {
|
if (block < 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const difference = latestBlock - block;
|
const difference = latestBlock - block;
|
||||||
const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms
|
const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms
|
||||||
const publishDate = Date.now() - msSincePublish;
|
const publishDate = Date.now() - msSincePublish;
|
||||||
return new Date(publishDate);
|
return new Date(publishDate);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const selectTransactionListFilter = createSelector(
|
export const selectTransactionListFilter = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function formatFullPrice(amount, precision = 1) {
|
||||||
|
|
||||||
if (fraction) {
|
if (fraction) {
|
||||||
const decimals = fraction.split('');
|
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);
|
const index = decimals.indexOf(first);
|
||||||
|
|
||||||
// Set format fraction
|
// Set format fraction
|
||||||
|
|
Loading…
Add table
Reference in a new issue