add user + rewards redux code from lbryinc

This commit is contained in:
Sean Yesmunt 2020-06-15 16:33:03 -04:00
parent 7138fe54bc
commit 2066205b8f
92 changed files with 1967 additions and 331 deletions

View file

@ -24,6 +24,7 @@ module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/ui/modal\1'
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/ui/app\1' module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/ui/app\1'
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/ui/native\1' module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/ui/native\1'
module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/ui/analytics\1' module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/ui/analytics\1'
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/ui/rewards\1'
module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1' module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1'
module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1' module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1'
module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1' module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1'

View file

@ -1,16 +1,10 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { hot } from 'react-hot-loader/root'; import { hot } from 'react-hot-loader/root';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { selectGetSyncErrorMessage, selectUploadCount } from 'lbryinc';
selectUser, import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
selectAccessToken, import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
doFetchAccessToken, import { selectUnclaimedRewards } from 'redux/selectors/rewards';
selectGetSyncErrorMessage,
selectUploadCount,
selectUnclaimedRewards,
doUserSetReferrer,
selectUserVerifiedEmail,
} from 'lbryinc';
import { doFetchChannelListMine } from 'lbry-redux'; import { doFetchChannelListMine } from 'lbry-redux';
import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';

View file

@ -14,7 +14,7 @@ import FileRenderFloating from 'component/fileRenderFloating';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import usePrevious from 'effects/use-previous'; import usePrevious from 'effects/use-previous';
import Nag from 'component/common/nag'; import Nag from 'component/common/nag';
import { rewards as REWARDS } from 'lbryinc'; import REWARDS from 'rewards';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import FileDrop from 'component/fileDrop'; import FileDrop from 'component/fileDrop';
// @if TARGET='web' // @if TARGET='web'

View file

@ -1,7 +1,7 @@
import Button from './view'; import Button from './view';
import React, { forwardRef } from 'react'; import React, { forwardRef } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
pathname: state.router.location.pathname, pathname: state.router.location.pathname,

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUserEmail } from 'lbryinc'; import { selectUserEmail } from 'redux/selectors/user';
import CardVerify from './view'; import CardVerify from './view';
const select = state => ({ const select = state => ({
@ -8,7 +8,4 @@ const select = state => ({
const perform = () => ({}); const perform = () => ({});
export default connect( export default connect(select, perform)(CardVerify);
select,
perform
)(CardVerify);

View file

@ -9,7 +9,7 @@ import {
makeSelectClaimForUri, makeSelectClaimForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import ChannelPage from './view'; import ChannelPage from './view';
const select = (state, props) => { const select = (state, props) => {

View file

@ -12,7 +12,7 @@ import {
doPrepareEdit, doPrepareEdit,
} from 'lbry-redux'; } from 'lbry-redux';
import { doPublishDesktop } from 'redux/actions/publish'; import { doPublishDesktop } from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
import ChannelForm from './view'; import ChannelForm from './view';
const select = state => ({ const select = state => ({

View file

@ -1,9 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri, makeSelectTitleForUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux'; import { doResolveUri, makeSelectTitleForUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux';
import { selectBlackListedOutpoints } from 'lbryinc'; import { selectBlackListedOutpoints } from 'lbryinc';
import ClaimLink from './view'; import ClaimLink from './view';
const select = (state, props) => { const select = (state, props) => {
@ -20,7 +17,4 @@ const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
}); });
export default connect( export default connect(select, perform)(ClaimLink);
select,
perform
)(ClaimLink);

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { doCommentCreate, makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux'; import { doCommentCreate, makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { CommentCreate } from './view'; import { CommentCreate } from './view';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
const select = (state, props) => ({ const select = (state, props) => ({
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,

View file

@ -2,7 +2,7 @@ import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectEmailToVerify, selectUser } from 'lbryinc'; import { selectEmailToVerify, selectUser } from 'redux/selectors/user';
import FirstRunEmailCollection from './view'; import FirstRunEmailCollection from './view';
const select = state => ({ const select = state => ({
@ -17,7 +17,4 @@ const perform = dispatch => () => ({
}, },
}); });
export default connect( export default connect(select, perform)(FirstRunEmailCollection);
select,
perform
)(FirstRunEmailCollection);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimForUri, makeSelectMetadataForUri, makeSelectTagsForUri } from 'lbry-redux'; import { makeSelectClaimForUri, makeSelectMetadataForUri, makeSelectTagsForUri } from 'lbry-redux';
import { selectUser } from 'lbryinc'; import { selectUser } from 'redux/selectors/user';
import FileDescription from './view'; import FileDescription from './view';
const select = (state, props) => ({ const select = (state, props) => ({

View file

@ -5,7 +5,7 @@ import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
makeSelectFileInfoForUri, makeSelectFileInfoForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectUser } from 'lbryinc'; import { selectUser } from 'redux/selectors/user';
import { doOpenFileInFolder } from 'redux/actions/file'; import { doOpenFileInFolder } from 'redux/actions/file';
import FileDetails from './view'; import FileDetails from './view';
@ -21,7 +21,4 @@ const perform = dispatch => ({
openFolder: path => dispatch(doOpenFileInFolder(path)), openFolder: path => dispatch(doOpenFileInFolder(path)),
}); });
export default connect( export default connect(select, perform)(FileDetails);
select,
perform
)(FileDetails);

View file

@ -8,7 +8,8 @@ import {
makeSelectStreamingUrlForUri, makeSelectStreamingUrlForUri,
makeSelectClaimWasPurchased, makeSelectClaimWasPurchased,
} from 'lbry-redux'; } from 'lbry-redux';
import { makeSelectCostInfoForUri, selectUserVerifiedEmail } from 'lbryinc'; import { makeSelectCostInfoForUri } from 'lbryinc';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { import {

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectFileInfoForUri, makeSelectStreamingUrlForUri } from 'lbry-redux'; import { makeSelectFileInfoForUri, makeSelectStreamingUrlForUri } from 'lbry-redux';
import { doClaimEligiblePurchaseRewards } from 'lbryinc'; import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
import { makeSelectFileRenderModeForUri, makeSelectIsPlaying } from 'redux/selectors/content'; import { makeSelectFileRenderModeForUri, makeSelectIsPlaying } from 'redux/selectors/content';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { doAnalyticsView } from 'redux/actions/app'; import { doAnalyticsView } from 'redux/actions/app';

View file

@ -7,7 +7,7 @@ import {
makeSelectPendingAmountByUri, makeSelectPendingAmountByUri,
makeSelectClaimIsMine, makeSelectClaimIsMine,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectUser } from 'lbryinc'; import { selectUser } from 'redux/selectors/user';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import FileValues from './view'; import FileValues from './view';

View file

@ -2,14 +2,9 @@ import * as SETTINGS from 'constants/settings';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance, formatCredits } from 'lbry-redux'; import { selectBalance, formatCredits } from 'lbry-redux';
import { import { selectGetSyncErrorMessage } from 'lbryinc';
selectUserVerifiedEmail, import { selectUserVerifiedEmail, selectUserEmail, selectEmailToVerify } from 'redux/selectors/user';
selectGetSyncErrorMessage, import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
selectUserEmail,
doClearEmailEntry,
doClearPasswordEntry,
selectEmailToVerify,
} from 'lbryinc';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { doSignOut, doOpenModal } from 'redux/actions/app'; import { doSignOut, doOpenModal } from 'redux/actions/app';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectReferralReward, selectUserInvitees, selectUserInviteStatusIsPending } from 'lbryinc'; import { selectReferralReward } from 'redux/selectors/rewards';
import { selectUserInvitees, selectUserInviteStatusIsPending } from 'redux/selectors/user';
import InviteList from './view'; import InviteList from './view';
const select = state => ({ const select = state => ({
@ -10,7 +11,4 @@ const select = state => ({
const perform = () => ({}); const perform = () => ({});
export default connect( export default connect(select, perform)(InviteList);
select,
perform
)(InviteList);

View file

@ -5,8 +5,8 @@ import {
selectUserInviteNewErrorMessage, selectUserInviteNewErrorMessage,
selectUserInviteReferralLink, selectUserInviteReferralLink,
selectUserInviteReferralCode, selectUserInviteReferralCode,
doUserInviteNew, } from 'redux/selectors/user';
} from 'lbryinc'; import { doUserInviteNew } from 'redux/actions/user';
import { selectMyChannelClaims, selectFetchingMyChannels, doFetchChannelListMine } from 'lbry-redux'; import { selectMyChannelClaims, selectFetchingMyChannels, doFetchChannelListMine } from 'lbry-redux';
import InviteNew from './view'; import InviteNew from './view';
@ -25,7 +25,4 @@ const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
}); });
export default connect( export default connect(select, perform)(InviteNew);
select,
perform
)(InviteNew);

View file

@ -1,17 +1,13 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { withRouter } from 'react-router';
selectUser, import REWARDS from 'rewards';
doClaimRewardType, import { selectUser, selectSetReferrerPending, selectSetReferrerError } from 'redux/selectors/user';
doUserSetReferrer, import { doClaimRewardType } from 'redux/actions/rewards';
selectSetReferrerPending, import { selectUnclaimedRewards } from 'redux/selectors/rewards';
selectSetReferrerError, import { doUserSetReferrer } from 'redux/actions/user';
rewards as REWARDS,
selectUnclaimedRewards,
} from 'lbryinc';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
import { doChannelSubscribe } from 'redux/actions/subscriptions'; import { doChannelSubscribe } from 'redux/actions/subscriptions';
import Invited from './view'; import Invited from './view';
import { withRouter } from 'react-router';
const select = (state, props) => { const select = (state, props) => {
return { return {
@ -31,9 +27,4 @@ const perform = dispatch => ({
channelSubscribe: uri => dispatch(doChannelSubscribe(uri)), channelSubscribe: uri => dispatch(doChannelSubscribe(uri)),
}); });
export default withRouter( export default withRouter(connect(select, perform)(Invited));
connect(
select,
perform
)(Invited)
);

View file

@ -5,7 +5,8 @@ import Button from 'component/button';
import ClaimPreview from 'component/claimPreview'; import ClaimPreview from 'component/claimPreview';
import Card from 'component/common/card'; import Card from 'component/common/card';
import { buildURI, parseURI } from 'lbry-redux'; import { buildURI, parseURI } from 'lbry-redux';
import { rewards as REWARDS, ERRORS } from 'lbryinc'; import { ERRORS } from 'lbryinc';
import REWARDS from 'rewards';
import { formatLbryUrlForWeb } from 'util/url'; import { formatLbryUrlForWeb } from 'util/url';
import ChannelContent from 'component/channelContent'; import ChannelContent from 'component/channelContent';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';

View file

@ -1,5 +1,4 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
doResolveUri, doResolveUri,
makeSelectClaimIsMine, makeSelectClaimIsMine,
@ -9,9 +8,7 @@ import {
makeSelectIsUriResolving, makeSelectIsUriResolving,
makeSelectMetadataItemForUri, makeSelectMetadataItemForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectBlackListedOutpoints } from 'lbryinc'; import { selectBlackListedOutpoints } from 'lbryinc';
import PreviewLink from './view'; import PreviewLink from './view';
const select = (state, props) => { const select = (state, props) => {
@ -31,7 +28,4 @@ const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
}); });
export default connect( export default connect(select, perform)(PreviewLink);
select,
perform
)(PreviewLink);

View file

@ -3,7 +3,7 @@ import { doSetDaemonSetting } from 'redux/actions/settings';
import { doSetWelcomeVersion, doToggle3PAnalytics, doSignOut } from 'redux/actions/app'; import { doSetWelcomeVersion, doToggle3PAnalytics, doSignOut } from 'redux/actions/app';
import { DAEMON_SETTINGS } from 'lbry-redux'; import { DAEMON_SETTINGS } from 'lbry-redux';
import { WELCOME_VERSION } from 'config.js'; import { WELCOME_VERSION } from 'config.js';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import PrivacyAgreement from './view'; import PrivacyAgreement from './view';
const select = state => ({ const select = state => ({
@ -17,7 +17,4 @@ const perform = dispatch => ({
signOut: () => dispatch(doSignOut()), signOut: () => dispatch(doSignOut()),
}); });
export default connect( export default connect(select, perform)(PrivacyAgreement);
select,
perform
)(PrivacyAgreement);

View file

@ -13,7 +13,7 @@ import {
doCheckPublishNameAvailability, doCheckPublishNameAvailability,
} from 'lbry-redux'; } from 'lbry-redux';
import { doPublishDesktop } from 'redux/actions/publish'; import { doPublishDesktop } from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({

View file

@ -6,7 +6,7 @@ import {
makeSelectRecommendedContentForUri, makeSelectRecommendedContentForUri,
selectIsSearching, selectIsSearching,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import RecommendedVideos from './view'; import RecommendedVideos from './view';
const select = (state, props) => ({ const select = (state, props) => ({

View file

@ -1,12 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
import RewardAuthIntro from './view'; import RewardAuthIntro from './view';
const select = state => ({ const select = state => ({
totalRewardValue: selectUnclaimedRewardValue(state), totalRewardValue: selectUnclaimedRewardValue(state),
}); });
export default connect( export default connect(select, null)(RewardAuthIntro);
select,
null
)(RewardAuthIntro);

View file

@ -1,5 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectRewardByClaimCode, makeSelectIsRewardClaimPending, doClaimRewardType } from 'lbryinc'; import { makeSelectRewardByClaimCode, makeSelectIsRewardClaimPending } from 'redux/selectors/rewards';
import { doClaimRewardType } from 'redux/actions/rewards';
import RewardLink from './view'; import RewardLink from './view';
const select = (state, props) => ({ const select = (state, props) => ({

View file

@ -1,12 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimedRewards } from 'lbryinc'; import { selectClaimedRewards } from 'redux/selectors/rewards';
import RewardListClaimed from './view'; import RewardListClaimed from './view';
const select = state => ({ const select = state => ({
rewards: selectClaimedRewards(state), rewards: selectClaimedRewards(state),
}); });
export default connect( export default connect(select, null)(RewardListClaimed);
select,
null
)(RewardListClaimed);

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUnclaimedRewardValue, selectFetchingRewards } from 'lbryinc'; import { selectUnclaimedRewardValue, selectFetchingRewards } from 'redux/selectors/rewards';
import RewardSummary from './view'; import RewardSummary from './view';
const select = state => ({ const select = state => ({
@ -7,7 +7,4 @@ const select = state => ({
fetching: selectFetchingRewards(state), fetching: selectFetchingRewards(state),
}); });
export default connect( export default connect(select, null)(RewardSummary);
select,
null
)(RewardSummary);

View file

@ -1,8 +1,8 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectUser } from 'redux/selectors/user';
import RewardTile from './view'; import RewardTile from './view';
import { selectUser } from 'lbryinc';
const select = state => ({ const select = state => ({
user: selectUser(state), user: selectUser(state),
@ -12,7 +12,4 @@ const perform = dispatch => ({
openSetReferrerModal: () => dispatch(doOpenModal(MODALS.SET_REFERRER)), openSetReferrerModal: () => dispatch(doOpenModal(MODALS.SET_REFERRER)),
}); });
export default connect( export default connect(select, perform)(RewardTile);
select,
perform
)(RewardTile);

View file

@ -5,7 +5,7 @@ import Icon from 'component/common/icon';
import RewardLink from 'component/rewardLink'; import RewardLink from 'component/rewardLink';
import Button from 'component/button'; import Button from 'component/button';
import Card from 'component/common/card'; import Card from 'component/common/card';
import { rewards } from 'lbryinc'; import rewards from 'rewards';
type Props = { type Props = {
openRewardCodeModal: () => void, openRewardCodeModal: () => void,

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUnclaimedRewardValue, selectFetchingRewards, doRewardList, selectClaimedRewards } from 'lbryinc'; import { selectUnclaimedRewardValue, selectFetchingRewards, selectClaimedRewards } from 'redux/selectors/rewards';
import { doRewardList } from 'redux/actions/rewards';
import RewardSummary from './view'; import RewardSummary from './view';
const select = state => ({ const select = state => ({
@ -12,7 +13,4 @@ const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()), fetchRewards: () => dispatch(doRewardList()),
}); });
export default connect( export default connect(select, perform)(RewardSummary);
select,
perform
)(RewardSummary);

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectScrollStartingPosition, selectWelcomeVersion } from 'redux/selectors/app'; import { selectScrollStartingPosition, selectWelcomeVersion } from 'redux/selectors/app';
import Router from './view'; import Router from './view';
import { normalizeURI, makeSelectTitleForUri } from 'lbry-redux'; import { normalizeURI, makeSelectTitleForUri } from 'lbry-redux';

View file

@ -7,7 +7,7 @@ import {
doFetchChannelListMine, doFetchChannelListMine,
doCreateChannel, doCreateChannel,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
const select = state => ({ const select = state => ({
channels: selectMyChannelClaims(state), channels: selectMyChannelClaims(state),
@ -21,7 +21,4 @@ const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
}); });
export default connect( export default connect(select, perform)(SelectChannel);
select,
perform
)(SelectChannel);

View file

@ -1,11 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { selectUser, selectPasswordSetSuccess, selectPasswordSetError } from 'redux/selectors/user';
selectUser, import { doUserPasswordSet, doClearPasswordEntry } from 'redux/actions/user';
selectPasswordSetSuccess,
selectPasswordSetError,
doUserPasswordSet,
doClearPasswordEntry,
} from 'lbryinc';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import UserSignIn from './view'; import UserSignIn from './view';

View file

@ -2,7 +2,8 @@ import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { selectFollowedTags, selectPurchaseUriSuccess, doClearPurchasedUriSuccess } from 'lbry-redux'; import { selectFollowedTags, selectPurchaseUriSuccess, doClearPurchasedUriSuccess } from 'lbry-redux';
import { selectUploadCount, selectUserVerifiedEmail } from 'lbryinc'; import { selectUploadCount } from 'lbryinc';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSignOut } from 'redux/actions/app'; import { doSignOut } from 'redux/actions/app';
import SideNavigation from './view'; import SideNavigation from './view';

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimForUri, makeSelectTitleForUri } from 'lbry-redux'; import { makeSelectClaimForUri, makeSelectTitleForUri } from 'lbry-redux';
import SocialShare from './view'; import SocialShare from './view';
import { selectUserInviteReferralCode, selectUser } from 'lbryinc'; import { selectUserInviteReferralCode, selectUser } from 'redux/selectors/user';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
const select = (state, props) => ({ const select = (state, props) => ({

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doGetSync, selectGetSyncIsPending, selectUserEmail, selectSyncApplyPasswordError } from 'lbryinc'; import { doGetSync, selectGetSyncIsPending, selectSyncApplyPasswordError } from 'lbryinc';
import { selectUserEmail } from 'redux/selectors/user';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { doSignOut, doHandleSyncComplete } from 'redux/actions/app'; import { doSignOut, doHandleSyncComplete } from 'redux/actions/app';
import SyncPassword from './view'; import SyncPassword from './view';

View file

@ -1,6 +1,7 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUserVerifiedEmail, selectGetSyncErrorMessage } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectGetSyncErrorMessage } from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import SyncToggle from './view'; import SyncToggle from './view';
@ -15,7 +16,4 @@ const perform = dispatch => ({
setSyncEnabled: value => dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, value)), setSyncEnabled: value => dispatch(doSetClientSetting(SETTINGS.ENABLE_SYNC, value)),
}); });
export default connect( export default connect(select, perform)(SyncToggle);
select,
perform
)(SyncToggle);

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimedRewardsByTransactionId } from 'lbryinc'; import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectIsFetchingTxos } from 'lbry-redux'; import { selectIsFetchingTxos } from 'lbry-redux';
import TransactionListTable from './view'; import TransactionListTable from './view';

View file

@ -1,12 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { doUserResendVerificationEmail, doUserCheckEmailVerified, doFetchAccessToken } from 'redux/actions/user';
selectEmailToVerify, import { selectEmailToVerify, selectUser, selectAccessToken } from 'redux/selectors/user';
doUserResendVerificationEmail,
doUserCheckEmailVerified,
selectUser,
doFetchAccessToken,
selectAccessToken,
} from 'lbryinc';
import UserEmailVerify from './view'; import UserEmailVerify from './view';
const select = state => ({ const select = state => ({

View file

@ -1,13 +1,12 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doClearEmailEntry, doUserSignUp } from 'redux/actions/user';
import { import {
selectEmailNewIsPending, selectEmailNewIsPending,
selectEmailNewErrorMessage, selectEmailNewErrorMessage,
selectEmailAlreadyExists, selectEmailAlreadyExists,
doUserSignUp,
doClearEmailEntry,
selectUser, selectUser,
} from 'lbryinc'; } from 'redux/selectors/user';
import { DAEMON_SETTINGS } from 'lbry-redux'; import { DAEMON_SETTINGS } from 'lbry-redux';
import { doSetClientSetting, doSetDaemonSetting } from 'redux/actions/settings'; import { doSetClientSetting, doSetDaemonSetting } from 'redux/actions/settings';
import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings';

View file

@ -2,12 +2,11 @@ import { connect } from 'react-redux';
import { import {
selectEmailNewErrorMessage, selectEmailNewErrorMessage,
selectEmailToVerify, selectEmailToVerify,
doUserCheckIfEmailExists,
doClearEmailEntry,
selectEmailDoesNotExist, selectEmailDoesNotExist,
selectEmailAlreadyExists, selectEmailAlreadyExists,
selectUser, selectUser,
} from 'lbryinc'; } from 'redux/selectors/user';
import { doUserCheckIfEmailExists, doClearEmailEntry } from 'redux/actions/user';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import UserEmailReturning from './view'; import UserEmailReturning from './view';

View file

@ -1,12 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doUserResendVerificationEmail, doUserCheckEmailVerified } from 'redux/actions/user';
import { import {
selectEmailAlreadyExists,
selectEmailToVerify, selectEmailToVerify,
doUserResendVerificationEmail, selectEmailAlreadyExists,
doUserCheckEmailVerified,
selectUser, selectUser,
selectResendingVerificationEmail, selectResendingVerificationEmail,
} from 'lbryinc'; } from 'redux/selectors/user';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import UserEmailVerify from './view'; import UserEmailVerify from './view';

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUser, selectEmailToVerify } from 'lbryinc'; import { selectUser, selectEmailToVerify } from 'redux/selectors/user';
import { doCreateChannel, selectCreatingChannel, selectMyChannelClaims, selectCreateChannelError } from 'lbry-redux'; import { doCreateChannel, selectCreatingChannel, selectMyChannelClaims, selectCreateChannelError } from 'lbry-redux';
import UserFirstChannel from './view'; import UserFirstChannel from './view';
@ -15,7 +15,4 @@ const perform = dispatch => ({
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)), createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
}); });
export default connect( export default connect(select, perform)(UserFirstChannel);
select,
perform
)(UserFirstChannel);

View file

@ -1,13 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
doUserPasswordReset,
selectPasswordResetSuccess, selectPasswordResetSuccess,
selectPasswordResetIsPending, selectPasswordResetIsPending,
selectPasswordResetError, selectPasswordResetError,
doClearPasswordEntry,
doClearEmailEntry,
selectEmailToVerify, selectEmailToVerify,
} from 'lbryinc'; } from 'redux/selectors/user';
import { doUserPasswordReset, doClearPasswordEntry, doClearEmailEntry } from 'redux/actions/user';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import UserSignIn from './view'; import UserSignIn from './view';

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doClearEmailEntry, doUserFetch } from 'lbryinc'; import { doClearEmailEntry, doUserFetch } from 'redux/actions/user';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import UserSignIn from './view'; import UserSignIn from './view';

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectPhoneNewErrorMessage, doUserPhoneNew } from 'lbryinc'; import { selectPhoneNewErrorMessage } from 'redux/selectors/user';
import { doUserPhoneNew } from 'redux/actions/user';
import UserPhoneNew from './view'; import UserPhoneNew from './view';
const select = state => ({ const select = state => ({
@ -10,7 +11,4 @@ const perform = dispatch => ({
addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)), addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)),
}); });
export default connect( export default connect(select, perform)(UserPhoneNew);
select,
perform
)(UserPhoneNew);

View file

@ -1,11 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { doUserPhoneVerify, doUserPhoneReset } from 'redux/actions/user';
doUserPhoneVerify, import { selectPhoneToVerify, selectPhoneVerifyErrorMessage, selectUserCountryCode } from 'redux/selectors/user';
doUserPhoneReset,
selectPhoneToVerify,
selectPhoneVerifyErrorMessage,
selectUserCountryCode,
} from 'lbryinc';
import UserPhoneVerify from './view'; import UserPhoneVerify from './view';
const select = state => ({ const select = state => ({
@ -19,7 +14,4 @@ const perform = dispatch => ({
verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), verifyUserPhone: code => dispatch(doUserPhoneVerify(code)),
}); });
export default connect( export default connect(select, perform)(UserPhoneVerify);
select,
perform
)(UserPhoneVerify);

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUser, selectUserIsPending, selectEmailToVerify, selectPasswordExists, doUserSignIn } from 'lbryinc'; import { selectUser, selectUserIsPending, selectEmailToVerify, selectPasswordExists } from 'redux/selectors/user';
import { doUserSignIn } from 'redux/actions/user';
import UserSignIn from './view'; import UserSignIn from './view';
const select = state => ({ const select = state => ({

View file

@ -1,12 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { selectUser, selectUserIsPending, selectEmailToVerify, selectEmailNewErrorMessage } from 'redux/selectors/user';
selectUser, import { doUserSignIn, doClearEmailEntry } from 'redux/actions/user';
selectUserIsPending,
selectEmailToVerify,
selectEmailNewErrorMessage,
doUserSignIn,
doClearEmailEntry,
} from 'lbryinc';
import UserSignIn from './view'; import UserSignIn from './view';
const select = state => ({ const select = state => ({

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doSignOut } from 'redux/actions/app'; import { doSignOut } from 'redux/actions/app';
import { doClearEmailEntry, doClearPasswordEntry } from 'lbryinc'; import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
import UserSignOutButton from './view'; import UserSignOutButton from './view';
const select = state => ({}); const select = state => ({});

View file

@ -1,20 +1,17 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import REWARD_TYPES from 'rewards';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectGetSyncIsPending, selectGetSyncErrorMessage, selectSyncHash } from 'lbryinc';
import { doClaimRewardType } from 'redux/actions/rewards';
import { selectClaimedRewards, makeSelectIsRewardClaimPending } from 'redux/selectors/rewards';
import { doUserFetch } from 'redux/actions/user';
import { import {
selectUserIsPending,
selectYoutubeChannels,
selectEmailToVerify, selectEmailToVerify,
selectUser, selectUser,
selectAccessToken, selectAccessToken,
makeSelectIsRewardClaimPending, } from 'redux/selectors/user';
selectClaimedRewards,
rewards as REWARD_TYPES,
doClaimRewardType,
doUserFetch,
selectUserIsPending,
selectYoutubeChannels,
selectGetSyncIsPending,
selectGetSyncErrorMessage,
selectSyncHash,
} from 'lbryinc';
import { selectMyChannelClaims, selectBalance, selectFetchingMyChannels, selectCreatingChannel } from 'lbry-redux'; import { selectMyChannelClaims, selectBalance, selectFetchingMyChannels, selectCreatingChannel } from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import UserSignIn from './view'; import UserSignIn from './view';

View file

@ -8,7 +8,8 @@ import UserFirstChannel from 'component/userFirstChannel';
import UserChannelFollowIntro from 'component/userChannelFollowIntro'; import UserChannelFollowIntro from 'component/userChannelFollowIntro';
import UserTagFollowIntro from 'component/userTagFollowIntro'; import UserTagFollowIntro from 'component/userTagFollowIntro';
import { DEFAULT_BID_FOR_FIRST_CHANNEL } from 'component/userFirstChannel/view'; import { DEFAULT_BID_FOR_FIRST_CHANNEL } from 'component/userFirstChannel/view';
import { rewards as REWARDS, YOUTUBE_STATUSES } from 'lbryinc'; import { YOUTUBE_STATUSES } from 'lbryinc';
import REWARDS from 'rewards';
import UserVerify from 'component/userVerify'; import UserVerify from 'component/userVerify';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import YoutubeTransferStatus from 'component/youtubeTransferStatus'; import YoutubeTransferStatus from 'component/youtubeTransferStatus';

View file

@ -1,14 +1,10 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { import { doUserIdentityVerify, doUserFetch } from 'redux/actions/user';
doUserIdentityVerify, import { makeSelectRewardByType } from 'redux/selectors/rewards';
doUserFetch, import rewards from 'rewards';
rewards, import { selectIdentityVerifyIsPending, selectIdentityVerifyErrorMessage } from 'redux/selectors/user';
makeSelectRewardByType,
selectIdentityVerifyIsPending,
selectIdentityVerifyErrorMessage,
} from 'lbryinc';
import UserVerify from './view'; import UserVerify from './view';
const select = state => { const select = state => {
@ -27,7 +23,4 @@ const perform = dispatch => ({
fetchUser: () => dispatch(doUserFetch()), fetchUser: () => dispatch(doUserFetch()),
}); });
export default connect( export default connect(select, perform)(UserVerify);
select,
perform
)(UserVerify);

View file

@ -6,7 +6,7 @@ import { savePosition, clearPosition } from 'redux/actions/content';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
import VideoViewer from './view'; import VideoViewer from './view';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { doClaimEligiblePurchaseRewards } from 'lbryinc'; import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';

View file

@ -1,7 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance, selectClaimsBalance, selectSupportsBalance, selectTipsBalance } from 'lbry-redux'; import { selectBalance, selectClaimsBalance, selectSupportsBalance, selectTipsBalance } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectClaimedRewards, selectSyncHash } from 'lbryinc'; import { selectSyncHash } from 'lbryinc';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import WalletBalance from './view'; import WalletBalance from './view';
const select = state => ({ const select = state => ({

View file

@ -1,13 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doClaimYoutubeChannels, doUserFetch, doCheckYoutubeTransfer } from 'redux/actions/user';
import { import {
selectYoutubeChannels, selectYoutubeChannels,
selectYouTubeImportVideosComplete,
selectYouTubeImportPending, selectYouTubeImportPending,
selectUserIsPending, selectUserIsPending,
doClaimYoutubeChannels, } from 'redux/selectors/user';
doUserFetch,
selectYouTubeImportVideosComplete,
doCheckYoutubeTransfer,
} from 'lbryinc';
import YoutubeChannelList from './view'; import YoutubeChannelList from './view';
const select = state => ({ const select = state => ({
@ -23,7 +21,4 @@ const perform = dispatch => ({
checkYoutubeTransfer: () => dispatch(doCheckYoutubeTransfer()), checkYoutubeTransfer: () => dispatch(doCheckYoutubeTransfer()),
}); });
export default connect( export default connect(select, perform)(YoutubeChannelList);
select,
perform
)(YoutubeChannelList);

View file

@ -129,11 +129,24 @@ export const USER_EMAIL_DECLINE = 'USER_EMAIL_DECLINE';
export const USER_EMAIL_NEW_STARTED = 'USER_EMAIL_NEW_STARTED'; export const USER_EMAIL_NEW_STARTED = 'USER_EMAIL_NEW_STARTED';
export const USER_EMAIL_NEW_SUCCESS = 'USER_EMAIL_NEW_SUCCESS'; export const USER_EMAIL_NEW_SUCCESS = 'USER_EMAIL_NEW_SUCCESS';
export const USER_EMAIL_NEW_EXISTS = 'USER_EMAIL_NEW_EXISTS'; export const USER_EMAIL_NEW_EXISTS = 'USER_EMAIL_NEW_EXISTS';
export const USER_EMAIL_NEW_DOES_NOT_EXIST = 'USER_EMAIL_NEW_DOES_NOT_EXIST';
export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE'; export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE';
export const USER_EMAIL_NEW_CLEAR_ENTRY = 'USER_EMAIL_NEW_CLEAR_ENTRY';
export const USER_EMAIL_VERIFY_SET = 'USER_EMAIL_VERIFY_SET';
export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED'; export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED';
export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS'; export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS';
export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE'; export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE';
export const USER_EMAIL_VERIFY_RETRY = 'USER_EMAIL_VERIFY_RETRY'; export const USER_EMAIL_VERIFY_RETRY_STARTED = 'USER_EMAIL_VERIFY_RETRY_STARTED';
export const USER_EMAIL_VERIFY_RETRY_FAILURE = 'USER_EMAIL_VERIFY_RETRY_FAILURE';
export const USER_EMAIL_VERIFY_RETRY_SUCCESS = 'USER_EMAIL_VERIFY_RETRY_SUCCESS';
export const USER_PASSWORD_EXISTS = 'USER_PASSWORD_EXISTS';
export const USER_PASSWORD_RESET_STARTED = 'USER_PASSWORD_RESET_STARTED';
export const USER_PASSWORD_RESET_SUCCESS = 'USER_PASSWORD_RESET_SUCCESS';
export const USER_PASSWORD_RESET_FAILURE = 'USER_PASSWORD_RESET_FAILURE';
export const USER_PASSWORD_SET_STARTED = 'USER_PASSWORD_SET_STARTED';
export const USER_PASSWORD_SET_SUCCESS = 'USER_PASSWORD_SET_SUCCESS';
export const USER_PASSWORD_SET_FAILURE = 'USER_PASSWORD_SET_FAILURE';
export const USER_PASSWORD_SET_CLEAR = 'USER_PASSWORD_SET_CLEAR';
export const USER_PHONE_RESET = 'USER_PHONE_RESET'; export const USER_PHONE_RESET = 'USER_PHONE_RESET';
export const USER_PHONE_NEW_STARTED = 'USER_PHONE_NEW_STARTED'; export const USER_PHONE_NEW_STARTED = 'USER_PHONE_NEW_STARTED';
export const USER_PHONE_NEW_SUCCESS = 'USER_PHONE_NEW_SUCCESS'; export const USER_PHONE_NEW_SUCCESS = 'USER_PHONE_NEW_SUCCESS';
@ -154,6 +167,13 @@ export const USER_INVITE_NEW_STARTED = 'USER_INVITE_NEW_STARTED';
export const USER_INVITE_NEW_SUCCESS = 'USER_INVITE_NEW_SUCCESS'; export const USER_INVITE_NEW_SUCCESS = 'USER_INVITE_NEW_SUCCESS';
export const USER_INVITE_NEW_FAILURE = 'USER_INVITE_NEW_FAILURE'; export const USER_INVITE_NEW_FAILURE = 'USER_INVITE_NEW_FAILURE';
export const FETCH_ACCESS_TOKEN_SUCCESS = 'FETCH_ACCESS_TOKEN_SUCCESS'; export const FETCH_ACCESS_TOKEN_SUCCESS = 'FETCH_ACCESS_TOKEN_SUCCESS';
export const USER_YOUTUBE_IMPORT_STARTED = 'USER_YOUTUBE_IMPORT_STARTED';
export const USER_YOUTUBE_IMPORT_FAILURE = 'USER_YOUTUBE_IMPORT_FAILURE';
export const USER_YOUTUBE_IMPORT_SUCCESS = 'USER_YOUTUBE_IMPORT_SUCCESS';
export const USER_SET_REFERRER_STARTED = 'USER_SET_REFERRER_STARTED';
export const USER_SET_REFERRER_SUCCESS = 'USER_SET_REFERRER_SUCCESS';
export const USER_SET_REFERRER_FAILURE = 'USER_SET_REFERRER_FAILURE';
export const USER_SET_REFERRER_RESET = 'USER_SET_REFERRER_RESET';
// Rewards // Rewards
export const FETCH_REWARDS_STARTED = 'FETCH_REWARDS_STARTED'; export const FETCH_REWARDS_STARTED = 'FETCH_REWARDS_STARTED';

View file

@ -16,7 +16,8 @@ import { Provider } from 'react-redux';
import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal, doToggle3PAnalytics } from 'redux/actions/app'; import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal, doToggle3PAnalytics } from 'redux/actions/app';
import { Lbry, isURIValid, setSearchApi, apiCall } from 'lbry-redux'; import { Lbry, isURIValid, setSearchApi, apiCall } from 'lbry-redux';
import { doSetLanguage, doFetchLanguage, doUpdateIsNightAsync } from 'redux/actions/settings'; import { doSetLanguage, doFetchLanguage, doUpdateIsNightAsync } from 'redux/actions/settings';
import { Lbryio, rewards, doBlackListedOutpointsSubscribe, doFilteredOutpointsSubscribe } from 'lbryinc'; import { Lbryio, doBlackListedOutpointsSubscribe, doFilteredOutpointsSubscribe } from 'lbryinc';
import rewards from 'rewards';
import { store, persistor, history } from 'store'; import { store, persistor, history } from 'store';
import app from './app'; import app from './app';
import doLogWarningConsoleMessage from './logWarningConsoleMessage'; import doLogWarningConsoleMessage from './logWarningConsoleMessage';
@ -55,7 +56,7 @@ if (process.env.NODE_ENV === 'production') {
} }
if (process.env.SDK_API_URL) { if (process.env.SDK_API_URL) {
console.warn('SDK_API_URL env var is deprecated. Use SDK_API_HOST instead'); console.warn('SDK_API_URL env var is deprecated. Use SDK_API_HOST instead'); // @eslint-disable-line
} }
let sdkAPIHost = process.env.SDK_API_HOST || process.env.SDK_API_URL; let sdkAPIHost = process.env.SDK_API_HOST || process.env.SDK_API_URL;

View file

@ -1,4 +1,5 @@
import { rewards, makeSelectRewardByType } from 'lbryinc'; import { makeSelectRewardByType } from 'redux/selectors/rewards';
import rewards from 'rewards';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import ModalFirstReward from './view'; import ModalFirstReward from './view';
@ -15,7 +16,4 @@ const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
}); });
export default connect( export default connect(select, perform)(ModalFirstReward);
select,
perform
)(ModalFirstReward);

View file

@ -1,21 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { selectAccessToken, selectUser } from 'lbryinc'; import { selectAccessToken, selectUser } from 'redux/selectors/user';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import ModalFirstSubscription from './view'; import ModalFirstSubscription from './view';
const select = state => ({ const select = state => ({
accessToken: selectAccessToken(state), accessToken: selectAccessToken(state),
user: selectUser(state), user: selectUser(state),
}) });
const perform = dispatch => () => ({ const perform = dispatch => () => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
}); });
export default withRouter(connect( export default withRouter(connect(select, perform)(ModalFirstSubscription));
select,
perform
)(ModalFirstSubscription));

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { selectPhoneToVerify, selectUser } from 'lbryinc'; import { selectPhoneToVerify, selectUser } from 'redux/selectors/user';
import ModalPhoneCollection from './view'; import ModalPhoneCollection from './view';
const select = state => ({ const select = state => ({
@ -12,7 +12,4 @@ const perform = dispatch => () => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
}); });
export default connect( export default connect(select, perform)(ModalPhoneCollection);
select,
perform
)(ModalPhoneCollection);

View file

@ -1,26 +1,21 @@
import REWARDS from 'rewards';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { import { doClaimRewardType } from 'redux/actions/rewards';
makeSelectClaimRewardError, import { makeSelectClaimRewardError, makeSelectIsRewardClaimPending } from 'redux/selectors/rewards';
doClaimRewardType,
makeSelectIsRewardClaimPending,
rewards as REWARD_TYPES,
} from 'lbryinc';
import ModalRewardCode from './view'; import ModalRewardCode from './view';
const select = state => ({ const select = state => ({
rewardIsPending: makeSelectIsRewardClaimPending()(state, { rewardIsPending: makeSelectIsRewardClaimPending()(state, {
reward_type: REWARD_TYPES.TYPE_REWARD_CODE, reward_type: REWARDS.TYPE_REWARD_CODE,
}), }),
error: makeSelectClaimRewardError()(state, { reward_type: REWARD_TYPES.TYPE_REWARD_CODE }), error: makeSelectClaimRewardError()(state, { reward_type: REWARDS.TYPE_REWARD_CODE }),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
submitRewardCode: code => dispatch(doClaimRewardType(REWARD_TYPES.TYPE_REWARD_CODE, { params: { code } })), submitRewardCode: code => dispatch(doClaimRewardType(REWARDS.TYPE_REWARD_CODE, { params: { code } })),
}); });
export default connect( export default connect(select, perform)(ModalRewardCode);
select,
perform
)(ModalRewardCode);

View file

@ -1,6 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { doUserSetReferrer, selectSetReferrerError, selectSetReferrerPending, doUserSetReferrerReset } from 'lbryinc'; import { selectSetReferrerError, selectSetReferrerPending } from 'redux/selectors/user';
import { doUserSetReferrer, doUserSetReferrerReset } from 'redux/actions/user';
import ModalSetReferrer from './view'; import ModalSetReferrer from './view';
const select = state => ({ const select = state => ({
@ -14,7 +15,4 @@ const perform = dispatch => ({
resetReferrerError: () => dispatch(doUserSetReferrerReset()), resetReferrerError: () => dispatch(doUserSetReferrerReset()),
}); });
export default connect( export default connect(select, perform)(ModalSetReferrer);
select,
perform
)(ModalSetReferrer);

View file

@ -1,6 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectGettingNewAddress, selectReceiveAddress, doGetNewAddress } from 'lbry-redux'; import { selectGettingNewAddress, selectReceiveAddress, doGetNewAddress } from 'lbry-redux';
import { selectUserEmail, selectUser, doUserSetCountry } from 'lbryinc'; import { selectUserEmail, selectUser } from 'redux/selectors/user';
import { doUserSetCountry } from 'redux/actions/user';
import BuyPage from './view'; import BuyPage from './view';
const select = state => ({ const select = state => ({

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectMyChannelClaims, doFetchChannelListMine, selectFetchingMyChannels } from 'lbry-redux'; import { selectMyChannelClaims, doFetchChannelListMine, selectFetchingMyChannels } from 'lbry-redux';
import { selectYoutubeChannels } from 'lbryinc'; import { selectYoutubeChannels } from 'redux/selectors/user';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import ChannelsPage from './view'; import ChannelsPage from './view';
@ -15,7 +15,4 @@ const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
}); });
export default connect( export default connect(select, perform)(ChannelsPage);
select,
perform
)(ChannelsPage);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectClaimForUri, selectFollowedTags, doResolveUri } from 'lbry-redux'; import { makeSelectClaimForUri, selectFollowedTags, doResolveUri } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { doToggleTagFollowDesktop } from 'redux/actions/tags';
import * as CS from 'constants/claim_search'; import * as CS from 'constants/claim_search';
import Tags from './view'; import Tags from './view';

View file

@ -1,6 +1,7 @@
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doFetchAccessToken, selectAccessToken, selectUser } from 'lbryinc'; import { doFetchAccessToken } from 'redux/actions/user';
import { selectAccessToken, selectUser } from 'redux/selectors/user';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings } from 'redux/selectors/settings';
import HelpPage from './view'; import HelpPage from './view';
@ -15,7 +16,4 @@ const perform = (dispatch, ownProps) => ({
fetchAccessToken: () => dispatch(doFetchAccessToken()), fetchAccessToken: () => dispatch(doFetchAccessToken()),
}); });
export default connect( export default connect(select, perform)(HelpPage);
select,
perform
)(HelpPage);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import DiscoverPage from './view'; import DiscoverPage from './view';
@ -12,7 +12,4 @@ const select = state => ({
const perform = {}; const perform = {};
export default connect( export default connect(select, perform)(DiscoverPage);
select,
perform
)(DiscoverPage);

View file

@ -1,11 +1,11 @@
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
doFetchInviteStatus,
selectUserInviteStatusFailed, selectUserInviteStatusFailed,
selectUserInviteStatusIsPending, selectUserInviteStatusIsPending,
selectUserVerifiedEmail, selectUserVerifiedEmail,
} from 'lbryinc'; } from 'redux/selectors/user';
import { doFetchInviteStatus } from 'redux/actions/user';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import InvitePage from './view'; import InvitePage from './view';
@ -22,7 +22,4 @@ const perform = dispatch => ({
acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)), acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)),
}); });
export default connect( export default connect(select, perform)(InvitePage);
select,
perform
)(InvitePage);

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = state => ({
@ -8,7 +8,4 @@ const select = state => ({
totalRewardValue: selectUnclaimedRewardValue(state), totalRewardValue: selectUnclaimedRewardValue(state),
}); });
export default connect( export default connect(select, null)(PublishPage);
select,
null
)(PublishPage);

View file

@ -1,12 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { selectUser } from 'redux/selectors/user';
selectFetchingRewards, import { selectFetchingRewards, selectUnclaimedRewards, selectClaimedRewards } from 'redux/selectors/rewards';
selectUnclaimedRewards, import { doUserFetch } from 'redux/actions/user';
selectClaimedRewards, import { doRewardList } from 'redux/actions/rewards';
selectUser,
doRewardList,
doUserFetch,
} from 'lbryinc';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings } from 'redux/selectors/settings';
import RewardsPage from './view'; import RewardsPage from './view';
@ -23,7 +19,4 @@ const perform = dispatch => ({
fetchUser: () => dispatch(doUserFetch()), fetchUser: () => dispatch(doUserFetch()),
}); });
export default connect( export default connect(select, perform)(RewardsPage);
select,
perform
)(RewardsPage);

View file

@ -7,7 +7,7 @@ import RewardTile from 'component/rewardTile';
import Button from 'component/button'; import Button from 'component/button';
import Page from 'component/page'; import Page from 'component/page';
import classnames from 'classnames'; import classnames from 'classnames';
import { rewards as REWARD_TYPES } from 'lbryinc'; import REWARD_TYPES from 'rewards';
import RewardAuthIntro from 'component/rewardAuthIntro'; import RewardAuthIntro from 'component/rewardAuthIntro';
import Card from 'component/common/card'; import Card from 'component/common/card';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { doSearch, selectIsSearching, makeSelectSearchUris, makeSelectQueryWithOptions, doToast } from 'lbry-redux'; import { doSearch, selectIsSearching, makeSelectSearchUris, makeSelectQueryWithOptions, doToast } from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import analytics from 'analytics'; import analytics from 'analytics';
import SearchPage from './view'; import SearchPage from './view';

View file

@ -25,7 +25,7 @@ import {
} from 'redux/selectors/settings'; } from 'redux/selectors/settings';
import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount, SETTINGS } from 'lbry-redux'; import { doWalletStatus, selectWalletIsEncrypted, selectBlockedChannelsCount, SETTINGS } from 'lbry-redux';
import SettingsPage from './view'; import SettingsPage from './view';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
const select = state => ({ const select = state => ({
daemonSettings: selectDaemonSettings(state), daemonSettings: selectDaemonSettings(state),

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'lbry-redux';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import DiscoverPage from './view'; import DiscoverPage from './view';
@ -12,7 +12,4 @@ const select = state => ({
const perform = {}; const perform = {};
export default connect( export default connect(select, perform)(DiscoverPage);
select,
perform
)(DiscoverPage);

View file

@ -5,15 +5,12 @@ import {
fileInfoReducer, fileInfoReducer,
searchReducer, searchReducer,
walletReducer, walletReducer,
notificationsReducer,
tagsReducer, tagsReducer,
commentReducer, commentReducer,
blockedReducer, blockedReducer,
publishReducer, publishReducer,
} from 'lbry-redux'; } from 'lbry-redux';
import { import {
userReducer,
rewardsReducer,
costInfoReducer, costInfoReducer,
blacklistReducer, blacklistReducer,
filteredReducer, filteredReducer,
@ -26,6 +23,9 @@ import appReducer from 'redux/reducers/app';
import contentReducer from 'redux/reducers/content'; import contentReducer from 'redux/reducers/content';
import settingsReducer from 'redux/reducers/settings'; import settingsReducer from 'redux/reducers/settings';
import subscriptionsReducer from 'redux/reducers/subscriptions'; import subscriptionsReducer from 'redux/reducers/subscriptions';
import notificationsReducer from 'redux/reducers/notifications';
import rewardsReducer from 'redux/reducers/rewards';
import userReducer from 'redux/reducers/user';
export default history => export default history =>
combineReducers({ combineReducers({

View file

@ -43,7 +43,10 @@ import {
selectAllowAnalytics, selectAllowAnalytics,
} from 'redux/selectors/app'; } from 'redux/selectors/app';
// import { selectDaemonSettings } from 'redux/selectors/settings'; // import { selectDaemonSettings } from 'redux/selectors/settings';
import { doAuthenticate, doGetSync, doClaimRewardType, rewards as REWARDS } from 'lbryinc'; import { doGetSync } from 'lbryinc';
import { doClaimRewardType } from 'redux/actions/rewards';
import REWARDS from 'rewards';
import { doAuthenticate } from 'redux/actions/user';
import { lbrySettings as config, version as appVersion } from 'package.json'; import { lbrySettings as config, version as appVersion } from 'package.json';
import analytics, { SHARE_INTERNAL } from 'analytics'; import analytics, { SHARE_INTERNAL } from 'analytics';
import { doSignOutCleanup, deleteSavedPassword, getSavedPassword } from 'util/saved-passwords'; import { doSignOutCleanup, deleteSavedPassword, getSavedPassword } from 'util/saved-passwords';

178
ui/redux/actions/rewards.js Normal file
View file

@ -0,0 +1,178 @@
import { Lbryio } from 'lbryinc';
import { ACTIONS, doToast, doUpdateBalance } from 'lbry-redux';
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { selectUserIsRewardApproved } from 'redux/selectors/user';
import { doFetchInviteStatus } from 'redux/actions/user';
import rewards from 'rewards';
export function doRewardList() {
return dispatch => {
dispatch({
type: ACTIONS.FETCH_REWARDS_STARTED,
});
Lbryio.call('reward', 'list', { multiple_rewards_per_type: true })
.then(userRewards => {
dispatch({
type: ACTIONS.FETCH_REWARDS_COMPLETED,
data: { userRewards },
});
})
.catch(() => {
dispatch({
type: ACTIONS.FETCH_REWARDS_COMPLETED,
data: { userRewards: [] },
});
});
};
}
export function doClaimRewardType(rewardType, options = {}) {
return (dispatch, getState) => {
const state = getState();
const userIsRewardApproved = selectUserIsRewardApproved(state);
const unclaimedRewards = selectUnclaimedRewards(state);
const reward =
rewardType === rewards.TYPE_REWARD_CODE || rewardType === rewards.TYPE_NEW_ANDROID
? { reward_type: rewards.TYPE_REWARD_CODE }
: unclaimedRewards.find(ur => ur.reward_type === rewardType);
// Try to claim the email reward right away, even if we haven't called reward_list yet
if (
rewardType !== rewards.TYPE_REWARD_CODE &&
rewardType !== rewards.TYPE_CONFIRM_EMAIL &&
rewardType !== rewards.TYPE_DAILY_VIEW &&
rewardType !== rewards.TYPE_NEW_ANDROID &&
rewardType !== rewards.TYPE_PAID_CONTENT
) {
if (!reward || reward.transaction_id) {
// already claimed or doesn't exist, do nothing
return;
}
}
if (
!userIsRewardApproved &&
rewardType !== rewards.TYPE_CONFIRM_EMAIL &&
rewardType !== rewards.TYPE_REWARD_CODE &&
rewardType !== rewards.TYPE_NEW_ANDROID
) {
if (!options || (!options.failSilently && rewards.callbacks.rewardApprovalRequested)) {
rewards.callbacks.rewardApprovalRequested();
}
return;
}
// Set `claim_code` so the api knows which reward to give if there are multiple of the same type
const params = options.params || {};
if (!params.claim_code && reward) {
params.claim_code = reward.claim_code;
}
dispatch({
type: ACTIONS.CLAIM_REWARD_STARTED,
data: { reward },
});
const success = successReward => {
// Temporary timeout to ensure the sdk has the correct balance after claiming a reward
setTimeout(() => {
dispatch(doUpdateBalance()).then(() => {
dispatch({
type: ACTIONS.CLAIM_REWARD_SUCCESS,
data: {
reward: successReward,
},
});
if (successReward.reward_type === rewards.TYPE_NEW_USER && rewards.callbacks.claimFirstRewardSuccess) {
rewards.callbacks.claimFirstRewardSuccess();
} else if (successReward.reward_type === rewards.TYPE_REFERRAL) {
dispatch(doFetchInviteStatus());
}
dispatch(doRewardList());
if (options.callback) {
options.callback();
}
});
}, 2000);
};
const failure = error => {
dispatch({
type: ACTIONS.CLAIM_REWARD_FAILURE,
data: {
reward,
error: !options || !options.failSilently ? error : undefined,
},
});
if (options.notifyError) {
dispatch(doToast({ message: error.message, isError: true }));
}
if (options.callback) {
options.callback(error);
}
};
return rewards.claimReward(rewardType, params).then(success, failure);
};
}
export function doClaimEligiblePurchaseRewards() {
return (dispatch, getState) => {
const state = getState();
const unclaimedRewards = selectUnclaimedRewards(state);
const userIsRewardApproved = selectUserIsRewardApproved(state);
if (!userIsRewardApproved || !Lbryio.enabled) {
return;
}
if (unclaimedRewards.find(ur => ur.reward_type === rewards.TYPE_FIRST_STREAM)) {
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
} else {
[rewards.TYPE_MANY_DOWNLOADS, rewards.TYPE_DAILY_VIEW].forEach(type => {
dispatch(doClaimRewardType(type, { failSilently: true }));
});
}
};
}
export function doClaimRewardClearError(reward) {
return dispatch => {
dispatch({
type: ACTIONS.CLAIM_REWARD_CLEAR_ERROR,
data: { reward },
});
};
}
export function doFetchRewardedContent() {
return dispatch => {
const success = nameToClaimId => {
dispatch({
type: ACTIONS.FETCH_REWARD_CONTENT_COMPLETED,
data: {
claimIds: Object.values(nameToClaimId),
success: true,
},
});
};
const failure = () => {
dispatch({
type: ACTIONS.FETCH_REWARD_CONTENT_COMPLETED,
data: {
claimIds: [],
success: false,
},
});
};
Lbryio.call('reward', 'list_featured').then(success, failure);
};
}

View file

@ -1,6 +1,8 @@
// @flow // @flow
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import { Lbryio, rewards, doClaimRewardType } from 'lbryinc'; import REWARDS from 'rewards';
import { Lbryio } from 'lbryinc';
import { doClaimRewardType } from 'redux/actions/rewards';
import { selectUnreadByChannel } from 'redux/selectors/subscriptions'; import { selectUnreadByChannel } from 'redux/selectors/subscriptions';
import { parseURI } from 'lbry-redux'; import { parseURI } from 'lbry-redux';
@ -144,7 +146,7 @@ export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dis
claim_id: channelClaimId, claim_id: channelClaimId,
}); });
dispatch(doClaimRewardType(rewards.TYPE_SUBSCRIPTION, { failSilently: true })); dispatch(doClaimRewardType(REWARDS.TYPE_SUBSCRIPTION, { failSilently: true }));
} }
}; };

774
ui/redux/actions/user.js Normal file
View file

@ -0,0 +1,774 @@
import { Lbry, doFetchChannelListMine, batchActions, makeSelectClaimForUri, parseURI } from 'lbry-redux';
import * as ACTIONS from 'constants/action_types';
import { doClaimRewardType, doRewardList } from 'redux/actions/rewards';
import { selectEmailToVerify, selectPhoneToVerify, selectUserCountryCode, selectUser } from 'redux/selectors/user';
import { doToast } from 'redux/actions/notifications';
import rewards from 'rewards';
import { Lbryio } from 'lbryinc';
export function doFetchInviteStatus(shouldCallRewardList = true) {
return dispatch => {
dispatch({
type: ACTIONS.USER_INVITE_STATUS_FETCH_STARTED,
});
Promise.all([Lbryio.call('user', 'invite_status'), Lbryio.call('user_referral_code', 'list')])
.then(([status, code]) => {
if (shouldCallRewardList) {
dispatch(doRewardList());
}
dispatch({
type: ACTIONS.USER_INVITE_STATUS_FETCH_SUCCESS,
data: {
invitesRemaining: status.invites_remaining ? status.invites_remaining : 0,
invitees: status.invitees,
referralLink: `${Lbryio.CONNECTION_STRING}user/refer?r=${code}`,
referralCode: code,
},
});
})
.catch(error => {
dispatch({
type: ACTIONS.USER_INVITE_STATUS_FETCH_FAILURE,
data: { error },
});
});
};
}
export function doInstallNew(appVersion, os = null, firebaseToken = null, callbackForUsersWhoAreSharingData, domain) {
const payload = { app_version: appVersion, domain };
if (firebaseToken) {
payload.firebase_token = firebaseToken;
}
Lbry.status().then(status => {
payload.app_id =
domain && domain !== 'lbry.tv'
? (domain.replace(/[.]/gi, '') + status.installation_id).slice(0, 66)
: status.installation_id;
payload.node_id = status.lbry_id;
Lbry.version().then(version => {
payload.daemon_version = version.lbrynet_version;
payload.operating_system = os || version.os_system;
payload.platform = version.platform;
Lbryio.call('install', 'new', payload);
if (callbackForUsersWhoAreSharingData) {
callbackForUsersWhoAreSharingData(status);
}
});
});
}
export function doInstallNewWithParams(
appVersion,
installationId,
nodeId,
lbrynetVersion,
os,
platform,
firebaseToken = null
) {
return () => {
const payload = { app_version: appVersion };
if (firebaseToken) {
payload.firebase_token = firebaseToken;
}
payload.app_id = installationId;
payload.node_id = nodeId;
payload.daemon_version = lbrynetVersion;
payload.operating_system = os;
payload.platform = platform;
Lbryio.call('install', 'new', payload);
};
}
// TODO: Call doInstallNew separately so we don't have to pass appVersion and os_system params?
export function doAuthenticate(
appVersion,
os = null,
firebaseToken = null,
shareUsageData = true,
callbackForUsersWhoAreSharingData,
callInstall = true,
domain = null
) {
return dispatch => {
dispatch({
type: ACTIONS.AUTHENTICATION_STARTED,
});
Lbryio.authenticate()
.then(user => {
Lbryio.getAuthToken().then(token => {
dispatch({
type: ACTIONS.AUTHENTICATION_SUCCESS,
data: { user, accessToken: token },
});
if (shareUsageData) {
dispatch(doRewardList());
dispatch(doFetchInviteStatus(false));
if (callInstall) {
doInstallNew(appVersion, os, firebaseToken, callbackForUsersWhoAreSharingData, domain);
}
}
});
})
.catch(error => {
dispatch({
type: ACTIONS.AUTHENTICATION_FAILURE,
data: { error },
});
});
};
}
export function doUserFetch() {
return dispatch =>
new Promise((resolve, reject) => {
dispatch({
type: ACTIONS.USER_FETCH_STARTED,
});
Lbryio.getCurrentUser()
.then(user => {
dispatch({
type: ACTIONS.USER_FETCH_SUCCESS,
data: { user },
});
resolve(user);
})
.catch(error => {
reject(error);
dispatch({
type: ACTIONS.USER_FETCH_FAILURE,
data: { error },
});
});
});
}
export function doUserCheckEmailVerified() {
// This will happen in the background so we don't need loading booleans
return dispatch => {
Lbryio.getCurrentUser().then(user => {
if (user.has_verified_email) {
dispatch(doRewardList());
dispatch({
type: ACTIONS.USER_FETCH_SUCCESS,
data: { user },
});
}
});
};
}
export function doUserPhoneReset() {
return {
type: ACTIONS.USER_PHONE_RESET,
};
}
export function doUserPhoneNew(phone, countryCode) {
return dispatch => {
dispatch({
type: ACTIONS.USER_PHONE_NEW_STARTED,
data: { phone, country_code: countryCode },
});
const success = () => {
dispatch({
type: ACTIONS.USER_PHONE_NEW_SUCCESS,
data: { phone },
});
};
const failure = error => {
dispatch({
type: ACTIONS.USER_PHONE_NEW_FAILURE,
data: { error },
});
};
Lbryio.call('user', 'phone_number_new', { phone_number: phone, country_code: countryCode }, 'post').then(
success,
failure
);
};
}
export function doUserPhoneVerifyFailure(error) {
return {
type: ACTIONS.USER_PHONE_VERIFY_FAILURE,
data: { error },
};
}
export function doUserPhoneVerify(verificationCode) {
return (dispatch, getState) => {
const phoneNumber = selectPhoneToVerify(getState());
const countryCode = selectUserCountryCode(getState());
dispatch({
type: ACTIONS.USER_PHONE_VERIFY_STARTED,
code: verificationCode,
});
Lbryio.call(
'user',
'phone_number_confirm',
{
verification_code: verificationCode,
phone_number: phoneNumber,
country_code: countryCode,
},
'post'
)
.then(user => {
if (user.is_identity_verified) {
dispatch({
type: ACTIONS.USER_PHONE_VERIFY_SUCCESS,
data: { user },
});
dispatch(doClaimRewardType(rewards.TYPE_NEW_USER));
}
})
.catch(error => dispatch(doUserPhoneVerifyFailure(error)));
};
}
export function doUserEmailToVerify(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_SET,
data: { email },
});
};
}
export function doUserEmailNew(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_STARTED,
email,
});
const success = () => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
};
const failure = error => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_FAILURE,
data: { error },
});
};
Lbryio.call('user_email', 'new', { email, send_verification_email: true }, 'post')
.catch(error => {
if (error.response && error.response.status === 409) {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_EXISTS,
});
return Lbryio.call('user_email', 'resend_token', { email, only_if_expired: true }, 'post').then(
success,
failure
);
}
throw error;
})
.then(success, failure);
};
}
export function doUserCheckIfEmailExists(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_STARTED,
email,
});
const triggerEmailFlow = hasPassword => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch({
type: ACTIONS.USER_EMAIL_NEW_EXISTS,
});
if (hasPassword) {
dispatch({
type: ACTIONS.USER_PASSWORD_EXISTS,
});
} else {
// If they don't have a password, they will need to use the email verification api
Lbryio.call('user_email', 'resend_token', { email, only_if_expired: true }, 'post');
}
};
const success = response => {
triggerEmailFlow(response.has_password);
};
const failure = error =>
dispatch({
type: ACTIONS.USER_EMAIL_NEW_FAILURE,
data: { error },
});
Lbryio.call('user', 'exists', { email }, 'post')
.catch(error => {
if (error.response && error.response.status === 404) {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_DOES_NOT_EXIST,
});
} else if (error.response && error.response.status === 412) {
triggerEmailFlow(false);
}
throw error;
})
.then(success, failure);
};
}
export function doUserSignIn(email, password) {
return dispatch => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_STARTED,
email,
});
const success = () => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
};
const failure = error =>
dispatch({
type: ACTIONS.USER_EMAIL_NEW_FAILURE,
data: { error },
});
Lbryio.call('user', 'signin', { email, ...(password ? { password } : {}) }, 'post')
.catch(error => {
if (error.response && error.response.status === 409) {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_EXISTS,
});
return Lbryio.call('user_email', 'resend_token', { email, only_if_expired: true }, 'post').then(
success,
failure
);
}
throw error;
})
.then(success, failure);
};
}
export function doUserSignUp(email, password) {
return dispatch =>
new Promise((resolve, reject) => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_STARTED,
email,
});
const success = () => {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
resolve();
};
const failure = error => {
if (error.response && error.response.status === 409) {
dispatch({
type: ACTIONS.USER_EMAIL_NEW_EXISTS,
});
}
dispatch({
type: ACTIONS.USER_EMAIL_NEW_FAILURE,
data: { error },
});
reject(error);
};
Lbryio.call('user', 'signup', { email, ...(password ? { password } : {}) }, 'post').then(success, failure);
});
}
export function doUserPasswordReset(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_PASSWORD_RESET_STARTED,
email,
});
const success = () => {
dispatch({
type: ACTIONS.USER_PASSWORD_RESET_SUCCESS,
});
};
const failure = error =>
dispatch({
type: ACTIONS.USER_PASSWORD_RESET_FAILURE,
data: { error },
});
Lbryio.call('user_password', 'reset', { email }, 'post').then(success, failure);
};
}
export function doUserPasswordSet(newPassword, oldPassword, authToken) {
return dispatch => {
dispatch({
type: ACTIONS.USER_PASSWORD_SET_STARTED,
});
const success = () => {
dispatch({
type: ACTIONS.USER_PASSWORD_SET_SUCCESS,
});
dispatch(doUserFetch());
};
const failure = error =>
dispatch({
type: ACTIONS.USER_PASSWORD_SET_FAILURE,
data: { error },
});
Lbryio.call(
'user_password',
'set',
{
new_password: newPassword,
...(oldPassword ? { old_password: oldPassword } : {}),
...(authToken ? { auth_token: authToken } : {}),
},
'post'
).then(success, failure);
};
}
export function doUserResendVerificationEmail(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_RETRY_STARTED,
});
const success = () => {
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_RETRY_SUCCESS,
});
};
const failure = error => {
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_RETRY_FAILURE,
data: { error },
});
};
Lbryio.call('user_email', 'resend_token', { email }, 'post')
.catch(error => {
if (error.response && error.response.status === 409) {
throw error;
}
})
.then(success, failure);
};
}
export function doClearEmailEntry() {
return {
type: ACTIONS.USER_EMAIL_NEW_CLEAR_ENTRY,
};
}
export function doClearPasswordEntry() {
return {
type: ACTIONS.USER_PASSWORD_SET_CLEAR,
};
}
export function doUserEmailVerifyFailure(error) {
return {
type: ACTIONS.USER_EMAIL_VERIFY_FAILURE,
data: { error },
};
}
export function doUserEmailVerify(verificationToken, recaptcha) {
return (dispatch, getState) => {
const email = selectEmailToVerify(getState());
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_STARTED,
code: verificationToken,
recaptcha,
});
Lbryio.call(
'user_email',
'confirm',
{
verification_token: verificationToken,
email,
recaptcha,
},
'post'
)
.then(userEmail => {
if (userEmail.is_verified) {
dispatch({
type: ACTIONS.USER_EMAIL_VERIFY_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
} else {
throw new Error('Your email is still not verified.'); // shouldn't happen
}
})
.catch(error => dispatch(doUserEmailVerifyFailure(error)));
};
}
export function doFetchAccessToken() {
return dispatch => {
const success = token =>
dispatch({
type: ACTIONS.FETCH_ACCESS_TOKEN_SUCCESS,
data: { token },
});
Lbryio.getAuthToken().then(success);
};
}
export function doUserIdentityVerify(stripeToken) {
return dispatch => {
dispatch({
type: ACTIONS.USER_IDENTITY_VERIFY_STARTED,
token: stripeToken,
});
Lbryio.call('user', 'verify_identity', { stripe_token: stripeToken }, 'post')
.then(user => {
if (user.is_identity_verified) {
dispatch({
type: ACTIONS.USER_IDENTITY_VERIFY_SUCCESS,
data: { user },
});
dispatch(doClaimRewardType(rewards.TYPE_NEW_USER));
} else {
throw new Error('Your identity is still not verified. This should not happen.'); // shouldn't happen
}
})
.catch(error => {
dispatch({
type: ACTIONS.USER_IDENTITY_VERIFY_FAILURE,
data: { error: error.toString() },
});
});
};
}
export function doUserInviteNew(email) {
return dispatch => {
dispatch({
type: ACTIONS.USER_INVITE_NEW_STARTED,
});
return Lbryio.call('user', 'invite', { email }, 'post')
.then(success => {
dispatch({
type: ACTIONS.USER_INVITE_NEW_SUCCESS,
data: { email },
});
dispatch(
doToast({
message: __(`Invite sent to ${email}`),
})
);
dispatch(doFetchInviteStatus());
return success;
})
.catch(error => {
dispatch({
type: ACTIONS.USER_INVITE_NEW_FAILURE,
data: { error },
});
});
};
}
export function doUserSetReferrerReset() {
return dispatch => {
dispatch({
type: ACTIONS.USER_SET_REFERRER_RESET,
});
};
}
export function doUserSetReferrer(referrer, shouldClaim) {
return async (dispatch, getState) => {
dispatch({
type: ACTIONS.USER_SET_REFERRER_STARTED,
});
let claim;
let referrerCode;
const { isChannel } = parseURI(referrer);
if (isChannel) {
const uri = `lbry://${referrer}`;
claim = makeSelectClaimForUri(uri)(getState());
if (!claim) {
try {
const response = await Lbry.resolve({ urls: [uri] });
claim = response && response[uri];
} catch (error) {
dispatch({
type: ACTIONS.USER_SET_REFERRER_FAILURE,
data: { error },
});
}
}
referrerCode = claim && claim.permanent_url && claim.permanent_url.replace('lbry://', '');
}
if (!referrerCode) {
referrerCode = referrer;
}
try {
await Lbryio.call('user', 'referral', { referrer: referrerCode }, 'post');
dispatch({
type: ACTIONS.USER_SET_REFERRER_SUCCESS,
});
if (shouldClaim) {
dispatch(doClaimRewardType(rewards.TYPE_REFEREE));
dispatch(doUserFetch());
} else {
dispatch(doUserFetch());
}
} catch (error) {
dispatch({
type: ACTIONS.USER_SET_REFERRER_FAILURE,
data: { error },
});
}
};
}
export function doUserSetCountry(country) {
return (dispatch, getState) => {
const state = getState();
const user = selectUser(state);
Lbryio.call('user_country', 'set', { country }).then(() => {
const newUser = { ...user, country };
dispatch({
type: ACTIONS.USER_FETCH_SUCCESS,
data: { user: newUser },
});
});
};
}
export function doClaimYoutubeChannels() {
return dispatch => {
dispatch({
type: ACTIONS.USER_YOUTUBE_IMPORT_STARTED,
});
let transferResponse;
return Lbry.address_list({ page: 1, page_size: 99999 })
.then(addressList => addressList.items[0])
.then(address =>
Lbryio.call('yt', 'transfer', {
address: address.address,
public_key: address.pubkey,
}).then(response => {
if (response && response.length) {
transferResponse = response;
return Promise.all(
response.map(channelMeta => {
if (channelMeta && channelMeta.channel && channelMeta.channel.channel_certificate) {
return Lbry.channel_import({
channel_data: channelMeta.channel.channel_certificate,
});
}
return null;
})
).then(() => {
const actions = [
{
type: ACTIONS.USER_YOUTUBE_IMPORT_SUCCESS,
data: transferResponse,
},
];
actions.push(doUserFetch());
actions.push(doFetchChannelListMine());
dispatch(batchActions(...actions));
});
}
})
)
.catch(error => {
dispatch({
type: ACTIONS.USER_YOUTUBE_IMPORT_FAILURE,
data: String(error),
});
});
};
}
export function doCheckYoutubeTransfer() {
return dispatch => {
dispatch({
type: ACTIONS.USER_YOUTUBE_IMPORT_STARTED,
});
return Lbryio.call('yt', 'transfer')
.then(response => {
if (response && response.length) {
dispatch({
type: ACTIONS.USER_YOUTUBE_IMPORT_SUCCESS,
data: response,
});
} else {
throw new Error();
}
})
.catch(error => {
dispatch({
type: ACTIONS.USER_YOUTUBE_IMPORT_FAILURE,
data: String(error),
});
});
};
}

View file

@ -8,7 +8,7 @@ const defaultState: NotificationState = {
errors: [], errors: [],
}; };
const notificationsReducer = handleActions( export default handleActions(
{ {
// Toasts // Toasts
[ACTIONS.CREATE_TOAST]: (state: NotificationState, action: DoToast) => { [ACTIONS.CREATE_TOAST]: (state: NotificationState, action: DoToast) => {
@ -90,5 +90,3 @@ const notificationsReducer = handleActions(
}, },
defaultState defaultState
); );
export { notificationsReducer };

View file

@ -0,0 +1,112 @@
import { ACTIONS } from 'lbry-redux';
const reducers = {};
const defaultState = {
fetching: false,
claimedRewardsById: {}, // id => reward
unclaimedRewards: [],
claimPendingByType: {},
claimErrorsByType: {},
rewardedContentClaimIds: [],
};
reducers[ACTIONS.FETCH_REWARDS_STARTED] = state =>
Object.assign({}, state, {
fetching: true,
});
reducers[ACTIONS.FETCH_REWARDS_COMPLETED] = (state, action) => {
const { userRewards } = action.data;
const unclaimedRewards = [];
const claimedRewards = {};
userRewards.forEach(reward => {
if (reward.transaction_id) {
claimedRewards[reward.id] = reward;
} else {
unclaimedRewards.push(reward);
}
});
return Object.assign({}, state, {
claimedRewardsById: claimedRewards,
unclaimedRewards,
fetching: false,
});
};
function setClaimRewardState(state, reward, isClaiming, errorMessage = '') {
const newClaimPendingByType = Object.assign({}, state.claimPendingByType);
const newClaimErrorsByType = Object.assign({}, state.claimErrorsByType);
// Currently, for multiple rewards of the same type, they will both show "claiming" when one is beacuse we track this by `reward_type`
// To fix this we will need to use `claim_code` instead, and change all selectors to match
if (reward) {
if (isClaiming) {
newClaimPendingByType[reward.reward_type] = isClaiming;
} else {
delete newClaimPendingByType[reward.reward_type];
}
if (errorMessage) {
newClaimErrorsByType[reward.reward_type] = errorMessage;
} else {
delete newClaimErrorsByType[reward.reward_type];
}
}
return Object.assign({}, state, {
claimPendingByType: newClaimPendingByType,
claimErrorsByType: newClaimErrorsByType,
});
}
reducers[ACTIONS.CLAIM_REWARD_STARTED] = (state, action) => {
const { reward } = action.data;
return setClaimRewardState(state, reward, true, '');
};
reducers[ACTIONS.CLAIM_REWARD_SUCCESS] = (state, action) => {
const { reward } = action.data;
const { unclaimedRewards } = state;
const index = unclaimedRewards.findIndex(ur => ur.claim_code === reward.claim_code);
unclaimedRewards.splice(index, 1);
const { claimedRewardsById } = state;
claimedRewardsById[reward.id] = reward;
const newState = {
...state,
unclaimedRewards: [...unclaimedRewards],
claimedRewardsById: { ...claimedRewardsById },
};
return setClaimRewardState(newState, reward, false, '');
};
reducers[ACTIONS.CLAIM_REWARD_FAILURE] = (state, action) => {
const { reward, error } = action.data;
return setClaimRewardState(state, reward, false, error ? error.message : '');
};
reducers[ACTIONS.CLAIM_REWARD_CLEAR_ERROR] = (state, action) => {
const { reward } = action.data;
return setClaimRewardState(state, reward, state.claimPendingByType[reward.reward_type], '');
};
reducers[ACTIONS.FETCH_REWARD_CONTENT_COMPLETED] = (state, action) => {
const { claimIds } = action.data;
return Object.assign({}, state, {
rewardedContentClaimIds: claimIds,
});
};
export default function rewardsReducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}

379
ui/redux/reducers/user.js Normal file
View file

@ -0,0 +1,379 @@
import * as ACTIONS from 'constants/action_types';
const reducers = {};
const defaultState = {
authenticationIsPending: false,
userIsPending: false,
emailNewIsPending: false,
emailNewErrorMessage: '',
emailToVerify: '',
emailAlreadyExists: false,
emailDoesNotExist: false,
resendingVerificationEmail: false,
passwordResetPending: false,
passwordResetSuccess: false,
passwordResetError: undefined,
passwordSetPending: false,
passwordSetSuccess: false,
passwordSetError: undefined,
inviteNewErrorMessage: '',
inviteNewIsPending: false,
inviteStatusIsPending: false,
invitesRemaining: undefined,
invitees: undefined,
referralLink: undefined,
referralCode: undefined,
user: undefined,
accessToken: undefined,
youtubeChannelImportPending: false,
youtubeChannelImportErrorMessage: '',
referrerSetIsPending: false,
referrerSetError: '',
};
reducers[ACTIONS.AUTHENTICATION_STARTED] = state =>
Object.assign({}, state, {
authenticationIsPending: true,
userIsPending: true,
accessToken: defaultState.accessToken,
});
reducers[ACTIONS.AUTHENTICATION_SUCCESS] = (state, action) =>
Object.assign({}, state, {
authenticationIsPending: false,
userIsPending: false,
accessToken: action.data.accessToken,
user: action.data.user,
});
reducers[ACTIONS.AUTHENTICATION_FAILURE] = state =>
Object.assign({}, state, {
authenticationIsPending: false,
userIsPending: false,
user: null,
});
reducers[ACTIONS.USER_FETCH_STARTED] = state =>
Object.assign({}, state, {
userIsPending: true,
});
reducers[ACTIONS.USER_FETCH_SUCCESS] = (state, action) =>
Object.assign({}, state, {
userIsPending: false,
user: action.data.user,
emailToVerify: action.data.user.has_verified_email ? null : state.emailToVerify,
});
reducers[ACTIONS.USER_FETCH_FAILURE] = state =>
Object.assign({}, state, {
userIsPending: true,
user: null,
});
reducers[ACTIONS.USER_PHONE_NEW_STARTED] = (state, action) => {
const user = Object.assign({}, state.user);
user.country_code = action.data.country_code;
return Object.assign({}, state, {
phoneNewIsPending: true,
phoneNewErrorMessage: '',
user,
});
};
reducers[ACTIONS.USER_PHONE_NEW_SUCCESS] = (state, action) =>
Object.assign({}, state, {
phoneToVerify: action.data.phone,
phoneNewIsPending: false,
});
reducers[ACTIONS.USER_PHONE_RESET] = state =>
Object.assign({}, state, {
phoneToVerify: null,
});
reducers[ACTIONS.USER_PHONE_NEW_FAILURE] = (state, action) =>
Object.assign({}, state, {
phoneNewIsPending: false,
phoneNewErrorMessage: action.data.error,
});
reducers[ACTIONS.USER_PHONE_VERIFY_STARTED] = state =>
Object.assign({}, state, {
phoneVerifyIsPending: true,
phoneVerifyErrorMessage: '',
});
reducers[ACTIONS.USER_PHONE_VERIFY_SUCCESS] = (state, action) =>
Object.assign({}, state, {
phoneToVerify: '',
phoneVerifyIsPending: false,
user: action.data.user,
});
reducers[ACTIONS.USER_PHONE_VERIFY_FAILURE] = (state, action) =>
Object.assign({}, state, {
phoneVerifyIsPending: false,
phoneVerifyErrorMessage: action.data.error,
});
reducers[ACTIONS.USER_EMAIL_NEW_STARTED] = state =>
Object.assign({}, state, {
emailNewIsPending: true,
emailNewErrorMessage: '',
emailAlreadyExists: false,
emailDoesNotExist: false,
});
reducers[ACTIONS.USER_EMAIL_NEW_SUCCESS] = (state, action) => {
const user = Object.assign({}, state.user);
user.primary_email = action.data.email;
return Object.assign({}, state, {
emailToVerify: action.data.email,
emailNewIsPending: false,
user,
});
};
reducers[ACTIONS.USER_EMAIL_NEW_EXISTS] = state =>
Object.assign({}, state, {
emailAlreadyExists: true,
});
reducers[ACTIONS.USER_EMAIL_NEW_DOES_NOT_EXIST] = state =>
Object.assign({}, state, {
emailDoesNotExist: true,
});
reducers[ACTIONS.USER_EMAIL_NEW_FAILURE] = (state, action) =>
Object.assign({}, state, {
emailNewIsPending: false,
emailNewErrorMessage: action.data.error,
});
reducers[ACTIONS.USER_EMAIL_NEW_CLEAR_ENTRY] = state => {
const newUser = { ...state.user };
delete newUser.primary_email;
return Object.assign({}, state, {
emailNewErrorMessage: null,
emailAlreadyExists: false,
emailDoesNotExist: false,
passwordExistsForUser: false,
emailToVerify: null,
user: newUser,
});
};
reducers[ACTIONS.USER_PASSWORD_SET_CLEAR] = state =>
Object.assign({}, state, {
passwordResetSuccess: false,
passwordResetPending: false,
passwordResetError: null,
});
reducers[ACTIONS.USER_EMAIL_VERIFY_STARTED] = state =>
Object.assign({}, state, {
emailVerifyIsPending: true,
emailVerifyErrorMessage: '',
});
reducers[ACTIONS.USER_EMAIL_VERIFY_SUCCESS] = (state, action) => {
const user = Object.assign({}, state.user);
user.primary_email = action.data.email;
return Object.assign({}, state, {
emailToVerify: '',
emailVerifyIsPending: false,
user,
});
};
reducers[ACTIONS.USER_EMAIL_VERIFY_FAILURE] = (state, action) =>
Object.assign({}, state, {
emailVerifyIsPending: false,
emailVerifyErrorMessage: action.data.error,
});
reducers[ACTIONS.USER_EMAIL_VERIFY_SET] = (state, action) =>
Object.assign({}, state, {
emailToVerify: action.data.email,
});
reducers[ACTIONS.USER_IDENTITY_VERIFY_STARTED] = state =>
Object.assign({}, state, {
identityVerifyIsPending: true,
identityVerifyErrorMessage: '',
});
reducers[ACTIONS.USER_IDENTITY_VERIFY_SUCCESS] = (state, action) =>
Object.assign({}, state, {
identityVerifyIsPending: false,
identityVerifyErrorMessage: '',
user: action.data.user,
});
reducers[ACTIONS.USER_IDENTITY_VERIFY_FAILURE] = (state, action) =>
Object.assign({}, state, {
identityVerifyIsPending: false,
identityVerifyErrorMessage: action.data.error,
});
reducers[ACTIONS.FETCH_ACCESS_TOKEN_SUCCESS] = (state, action) => {
const { token } = action.data;
return Object.assign({}, state, {
accessToken: token,
});
};
reducers[ACTIONS.USER_INVITE_STATUS_FETCH_STARTED] = state =>
Object.assign({}, state, {
inviteStatusIsPending: true,
});
reducers[ACTIONS.USER_INVITE_STATUS_FETCH_SUCCESS] = (state, action) =>
Object.assign({}, state, {
inviteStatusIsPending: false,
invitesRemaining: action.data.invitesRemaining,
invitees: action.data.invitees,
referralLink: action.data.referralLink,
referralCode: action.data.referralCode,
});
reducers[ACTIONS.USER_INVITE_NEW_STARTED] = state =>
Object.assign({}, state, {
inviteNewIsPending: true,
inviteNewErrorMessage: '',
});
reducers[ACTIONS.USER_INVITE_NEW_SUCCESS] = state =>
Object.assign({}, state, {
inviteNewIsPending: false,
inviteNewErrorMessage: '',
});
reducers[ACTIONS.USER_INVITE_NEW_FAILURE] = (state, action) =>
Object.assign({}, state, {
inviteNewIsPending: false,
inviteNewErrorMessage: action.data.error.message,
});
reducers[ACTIONS.USER_INVITE_STATUS_FETCH_FAILURE] = state =>
Object.assign({}, state, {
inviteStatusIsPending: false,
invitesRemaining: null,
invitees: null,
});
reducers[ACTIONS.USER_YOUTUBE_IMPORT_STARTED] = state =>
Object.assign({}, state, {
youtubeChannelImportPending: true,
youtubeChannelImportErrorMessage: '',
});
reducers[ACTIONS.USER_YOUTUBE_IMPORT_SUCCESS] = (state, action) => {
const total = action.data.reduce((acc, value) => acc + value.total_published_videos, 0);
const complete = action.data.reduce((acc, value) => acc + value.total_transferred, 0);
return Object.assign({}, state, {
youtubeChannelImportPending: false,
youtubeChannelImportErrorMessage: '',
youtubeChannelImportTotal: total,
youtubeChannelImportComplete: complete,
});
};
reducers[ACTIONS.USER_YOUTUBE_IMPORT_FAILURE] = (state, action) =>
Object.assign({}, state, {
youtubeChannelImportPending: false,
youtubeChannelImportErrorMessage: action.data,
});
reducers[ACTIONS.USER_EMAIL_VERIFY_RETRY_STARTED] = state =>
Object.assign({}, state, {
resendingVerificationEmail: true,
});
reducers[ACTIONS.USER_EMAIL_VERIFY_RETRY_SUCCESS] = state =>
Object.assign({}, state, {
resendingVerificationEmail: false,
});
reducers[ACTIONS.USER_EMAIL_VERIFY_RETRY_FAILURE] = state =>
Object.assign({}, state, {
resendingVerificationEmail: false,
});
reducers[ACTIONS.USER_SET_REFERRER_STARTED] = state =>
Object.assign({}, state, {
referrerSetIsPending: true,
referrerSetError: defaultState.referrerSetError,
});
reducers[ACTIONS.USER_SET_REFERRER_SUCCESS] = state =>
Object.assign({}, state, {
referrerSetIsPending: false,
referrerSetError: defaultState.referrerSetError,
});
reducers[ACTIONS.USER_SET_REFERRER_FAILURE] = (state, action) =>
Object.assign({}, state, {
referrerSetIsPending: false,
referrerSetError: action.data.error.message,
});
reducers[ACTIONS.USER_SET_REFERRER_RESET] = state =>
Object.assign({}, state, {
referrerSetIsPending: false,
referrerSetError: defaultState.referrerSetError,
});
reducers[ACTIONS.USER_PASSWORD_EXISTS] = state =>
Object.assign({}, state, {
passwordExistsForUser: true,
});
reducers[ACTIONS.USER_PASSWORD_RESET_STARTED] = state =>
Object.assign({}, state, {
passwordResetPending: true,
passwordResetSuccess: defaultState.passwordResetSuccess,
passwordResetError: null,
});
reducers[ACTIONS.USER_PASSWORD_RESET_SUCCESS] = state =>
Object.assign({}, state, {
passwordResetPending: false,
passwordResetSuccess: true,
});
reducers[ACTIONS.USER_PASSWORD_RESET_FAILURE] = (state, action) =>
Object.assign({}, state, {
passwordResetPending: false,
passwordResetError: action.data.error,
});
reducers[ACTIONS.USER_PASSWORD_SET_STARTED] = state =>
Object.assign({}, state, {
passwordSetPending: true,
passwordSetSuccess: defaultState.passwordSetSuccess,
});
reducers[ACTIONS.USER_PASSWORD_SET_SUCCESS] = state =>
Object.assign({}, state, {
passwordSetPending: false,
passwordSetSuccess: true,
});
reducers[ACTIONS.USER_PASSWORD_SET_FAILURE] = (state, action) =>
Object.assign({}, state, {
passwordSetPending: false,
passwordSetError: action.data.error,
});
export default function userReducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}

View file

@ -0,0 +1,59 @@
import { createSelector } from 'reselect';
import REWARDS from 'rewards';
const selectState = state => state.rewards || {};
export const selectUnclaimedRewardsByType = createSelector(selectState, state => state.unclaimedRewardsByType);
export const selectClaimedRewardsById = createSelector(selectState, state => state.claimedRewardsById);
export const selectClaimedRewards = createSelector(selectClaimedRewardsById, byId => Object.values(byId) || []);
export const selectClaimedRewardsByTransactionId = createSelector(selectClaimedRewards, rewards =>
rewards.reduce((mapParam, reward) => {
const map = mapParam;
map[reward.transaction_id] = reward;
return map;
}, {})
);
export const selectUnclaimedRewards = createSelector(selectState, state => state.unclaimedRewards);
export const selectFetchingRewards = createSelector(selectState, state => !!state.fetching);
export const selectUnclaimedRewardValue = createSelector(selectUnclaimedRewards, rewards =>
rewards.reduce((sum, reward) => sum + reward.reward_amount, 0)
);
export const selectClaimsPendingByType = createSelector(selectState, state => state.claimPendingByType);
const selectIsClaimRewardPending = (state, props) => selectClaimsPendingByType(state, props)[props.reward_type];
export const makeSelectIsRewardClaimPending = () =>
createSelector(selectIsClaimRewardPending, isClaiming => isClaiming);
export const selectClaimErrorsByType = createSelector(selectState, state => state.claimErrorsByType);
const selectClaimRewardError = (state, props) => selectClaimErrorsByType(state, props)[props.reward_type];
export const makeSelectClaimRewardError = () => createSelector(selectClaimRewardError, errorMessage => errorMessage);
const selectRewardByType = (state, rewardType) =>
selectUnclaimedRewards(state).find(reward => reward.reward_type === rewardType);
export const makeSelectRewardByType = () => createSelector(selectRewardByType, reward => reward);
const selectRewardByClaimCode = (state, claimCode) =>
selectUnclaimedRewards(state).find(reward => reward.claim_code === claimCode);
export const makeSelectRewardByClaimCode = () => createSelector(selectRewardByClaimCode, reward => reward);
export const makeSelectRewardAmountByType = () =>
createSelector(selectRewardByType, reward => (reward ? reward.reward_amount : 0));
export const selectRewardContentClaimIds = createSelector(selectState, state => state.rewardedContentClaimIds);
export const selectReferralReward = createSelector(
selectUnclaimedRewards,
unclaimedRewards => unclaimedRewards.filter(reward => reward.reward_type === REWARDS.TYPE_REFERRAL)[0]
);

129
ui/redux/selectors/user.js Normal file
View file

@ -0,0 +1,129 @@
import { createSelector } from 'reselect';
export const selectState = state => state.user || {};
export const selectAuthenticationIsPending = createSelector(selectState, state => state.authenticationIsPending);
export const selectUserIsPending = createSelector(selectState, state => state.userIsPending);
export const selectUser = createSelector(selectState, state => state.user);
export const selectEmailAlreadyExists = createSelector(selectState, state => state.emailAlreadyExists);
export const selectEmailDoesNotExist = createSelector(selectState, state => state.emailDoesNotExist);
export const selectResendingVerificationEmail = createSelector(selectState, state => state.resendingVerificationEmail);
export const selectUserEmail = createSelector(selectUser, user =>
user ? user.primary_email || user.latest_claimed_email : null
);
export const selectUserPhone = createSelector(selectUser, user => (user ? user.phone_number : null));
export const selectUserCountryCode = createSelector(selectUser, user => (user ? user.country_code : null));
export const selectEmailToVerify = createSelector(
selectState,
selectUserEmail,
(state, userEmail) => state.emailToVerify || userEmail
);
export const selectPhoneToVerify = createSelector(
selectState,
selectUserPhone,
(state, userPhone) => state.phoneToVerify || userPhone
);
export const selectYoutubeChannels = createSelector(selectUser, user => (user ? user.youtube_channels : null));
export const selectUserIsRewardApproved = createSelector(selectUser, user => user && user.is_reward_approved);
export const selectEmailNewIsPending = createSelector(selectState, state => state.emailNewIsPending);
export const selectEmailNewErrorMessage = createSelector(selectState, state => {
const error = state.emailNewErrorMessage;
return typeof error === 'object' && error !== null ? error.message : error;
});
export const selectPasswordExists = createSelector(selectState, state => state.passwordExistsForUser);
export const selectPasswordResetIsPending = createSelector(selectState, state => state.passwordResetPending);
export const selectPasswordResetSuccess = createSelector(selectState, state => state.passwordResetSuccess);
export const selectPasswordResetError = createSelector(selectState, state => {
const error = state.passwordResetError;
return typeof error === 'object' && error !== null ? error.message : error;
});
export const selectPasswordSetIsPending = createSelector(selectState, state => state.passwordSetPending);
export const selectPasswordSetSuccess = createSelector(selectState, state => state.passwordSetSuccess);
export const selectPasswordSetError = createSelector(selectState, state => {
const error = state.passwordSetError;
return typeof error === 'object' && error !== null ? error.message : error;
});
export const selectPhoneNewErrorMessage = createSelector(selectState, state => state.phoneNewErrorMessage);
export const selectEmailVerifyIsPending = createSelector(selectState, state => state.emailVerifyIsPending);
export const selectEmailVerifyErrorMessage = createSelector(selectState, state => state.emailVerifyErrorMessage);
export const selectPhoneNewIsPending = createSelector(selectState, state => state.phoneNewIsPending);
export const selectPhoneVerifyIsPending = createSelector(selectState, state => state.phoneVerifyIsPending);
export const selectPhoneVerifyErrorMessage = createSelector(selectState, state => state.phoneVerifyErrorMessage);
export const selectIdentityVerifyIsPending = createSelector(selectState, state => state.identityVerifyIsPending);
export const selectIdentityVerifyErrorMessage = createSelector(selectState, state => state.identityVerifyErrorMessage);
export const selectUserVerifiedEmail = createSelector(selectUser, user => user && user.has_verified_email);
export const selectUserIsVerificationCandidate = createSelector(
selectUser,
user => user && (!user.has_verified_email || !user.is_identity_verified)
);
export const selectAccessToken = createSelector(selectState, state => state.accessToken);
export const selectUserInviteStatusIsPending = createSelector(selectState, state => state.inviteStatusIsPending);
export const selectUserInvitesRemaining = createSelector(selectState, state => state.invitesRemaining);
export const selectUserInvitees = createSelector(selectState, state => state.invitees);
export const selectUserInviteStatusFailed = createSelector(
selectUserInvitesRemaining,
() => selectUserInvitesRemaining === null
);
export const selectUserInviteNewIsPending = createSelector(selectState, state => state.inviteNewIsPending);
export const selectUserInviteNewErrorMessage = createSelector(selectState, state => state.inviteNewErrorMessage);
export const selectUserInviteReferralLink = createSelector(selectState, state => state.referralLink);
export const selectUserInviteReferralCode = createSelector(selectState, state =>
state.referralCode ? state.referralCode[0] : ''
);
export const selectYouTubeImportPending = createSelector(selectState, state => state.youtubeChannelImportPending);
export const selectYouTubeImportError = createSelector(selectState, state => state.youtubeChannelImportErrorMessage);
export const selectSetReferrerPending = createSelector(selectState, state => state.referrerSetIsPending);
export const selectSetReferrerError = createSelector(selectState, state => state.referrerSetError);
export const selectYouTubeImportVideosComplete = createSelector(selectState, state => {
const total = state.youtubeChannelImportTotal;
const complete = state.youtubeChannelImportComplete || 0;
if (total) {
return [complete, total];
}
});

127
ui/rewards.js Normal file
View file

@ -0,0 +1,127 @@
import { Lbry } from 'lbry-redux';
import { doToast } from 'redux/actions/notifications';
import { Lbryio } from 'lbryinc';
const rewards = {};
rewards.TYPE_NEW_DEVELOPER = 'new_developer';
rewards.TYPE_NEW_USER = 'new_user';
rewards.TYPE_CONFIRM_EMAIL = 'email_provided';
rewards.TYPE_FIRST_CHANNEL = 'new_channel';
rewards.TYPE_FIRST_STREAM = 'first_stream';
rewards.TYPE_MANY_DOWNLOADS = 'many_downloads';
rewards.TYPE_FIRST_PUBLISH = 'first_publish';
rewards.TYPE_REFERRAL = 'referrer';
rewards.TYPE_REFEREE = 'referee';
rewards.TYPE_REWARD_CODE = 'reward_code';
rewards.TYPE_SUBSCRIPTION = 'subscription';
rewards.YOUTUBE_CREATOR = 'youtube_creator';
rewards.TYPE_DAILY_VIEW = 'daily_view';
rewards.TYPE_NEW_ANDROID = 'new_android';
rewards.TYPE_PAID_CONTENT = 'paid_content';
rewards.claimReward = (type, rewardParams) => {
function requestReward(resolve, reject, params) {
if (!Lbryio.enabled) {
reject(new Error(__('Rewards are not enabled.')));
return;
}
Lbryio.call('reward', 'claim', params, 'post').then(reward => {
const message = reward.reward_notification || `You have claimed a ${reward.reward_amount} LBC reward.`;
// Display global notice
const action = doToast({
message,
linkText: __('Show All'),
linkTarget: '/rewards',
});
window.store.dispatch(action);
if (rewards.callbacks.claimRewardSuccess) {
rewards.callbacks.claimRewardSuccess();
}
resolve(reward);
}, reject);
}
return new Promise((resolve, reject) => {
Lbry.address_unused().then(address => {
const params = {
reward_type: type,
wallet_address: address,
...rewardParams,
};
switch (type) {
case rewards.TYPE_FIRST_CHANNEL:
Lbry.channel_list({ page: 1, page_size: 10 })
.then(claims => {
const claim =
claims.items &&
claims.items.find(
foundClaim =>
foundClaim.name.length &&
foundClaim.name[0] === '@' &&
foundClaim.txid.length &&
foundClaim.type === 'claim'
);
if (claim) {
params.transaction_id = claim.txid;
requestReward(resolve, reject, params);
} else {
reject(new Error(__('Please create a channel identity first.')));
}
})
.catch(reject);
break;
case rewards.TYPE_FIRST_PUBLISH:
Lbry.stream_list({ page: 1, page_size: 10 })
.then(claims => {
const claim =
claims.items &&
claims.items.find(
foundClaim =>
foundClaim.name.length &&
foundClaim.name[0] !== '@' &&
foundClaim.txid.length &&
foundClaim.type === 'claim'
);
if (claim) {
params.transaction_id = claim.txid;
requestReward(resolve, reject, params);
} else {
reject(
claims.length
? new Error(
__('Please publish something and wait for confirmation by the network to claim this reward.')
)
: new Error(__('Please publish something to claim this reward.'))
);
}
})
.catch(reject);
break;
case rewards.TYPE_FIRST_STREAM:
case rewards.TYPE_NEW_USER:
default:
requestReward(resolve, reject, params);
}
});
});
};
rewards.callbacks = {
// Set any callbacks that require code not found in this project
claimRewardSuccess: null,
claimFirstRewardSuccess: null,
rewardApprovalRequired: null,
};
rewards.setCallback = (name, method) => {
rewards.callbacks[name] = method;
};
export default rewards;

View file

@ -10,7 +10,8 @@ import { createMemoryHistory, createBrowserHistory } from 'history';
import { routerMiddleware } from 'connected-react-router'; import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers'; import createRootReducer from './reducers';
import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS, SETTINGS } from 'lbry-redux'; import { Lbry, buildSharedStateMiddleware, ACTIONS as LBRY_REDUX_ACTIONS, SETTINGS } from 'lbry-redux';
import { LBRYINC_ACTIONS, doGetSync, selectUserVerifiedEmail } from 'lbryinc'; import { doGetSync } from 'lbryinc';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { getSavedPassword, getAuthToken } from 'util/saved-passwords'; import { getSavedPassword, getAuthToken } from 'util/saved-passwords';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { generateInitialUrl } from 'util/url'; import { generateInitialUrl } from 'util/url';
@ -163,7 +164,7 @@ const sharedStateCb = ({ dispatch, getState }) => {
const populateAuthTokenHeader = () => { const populateAuthTokenHeader = () => {
return next => action => { return next => action => {
if ( if (
(action.type === LBRYINC_ACTIONS.USER_FETCH_SUCCESS || action.type === LBRYINC_ACTIONS.AUTHENTICATION_SUCCESS) && (action.type === ACTIONS.USER_FETCH_SUCCESS || action.type === ACTIONS.AUTHENTICATION_SUCCESS) &&
action.data.user.has_verified_email === true action.data.user.has_verified_email === true
) { ) {
const authToken = getAuthToken(); const authToken = getAuthToken();

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import fileViewerEmbeddedEnded from './view'; import fileViewerEmbeddedEnded from './view';
import { selectUserVerifiedEmail } from 'lbryinc'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
export default connect(state => ({ export default connect(state => ({
isAuthenticated: selectUserVerifiedEmail(state), isAuthenticated: selectUserVerifiedEmail(state),

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUser } from 'lbryinc'; import { selectUser } from 'redux/selectors/user';
import OpenInAppLink from './view'; import OpenInAppLink from './view';
const select = state => ({ const select = state => ({

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectUser } from 'lbryinc'; import { selectUser } from 'redux/selectors/user';
import YoutubeWelcome from './view'; import YoutubeWelcome from './view';
const select = state => ({ const select = state => ({

View file

@ -6215,9 +6215,9 @@ lbry-redux@lbryio/lbry-redux#f8ac5359d9d05fba2c3a536003a9d4c64b86c9f0:
reselect "^3.0.0" reselect "^3.0.0"
uuid "^3.3.2" uuid "^3.3.2"
lbryinc@lbryio/lbryinc#3ceb09549cb5ec22927ce3bea44ae8dbe2e4a006: lbryinc@lbryio/lbryinc#b0e6dc8318a6990d1d366e8b80c905d7ced8c476:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/3ceb09549cb5ec22927ce3bea44ae8dbe2e4a006" resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/b0e6dc8318a6990d1d366e8b80c905d7ced8c476"
dependencies: dependencies:
reselect "^3.0.0" reselect "^3.0.0"