diff --git a/.flowconfig b/.flowconfig index c2bb89028..ffc632dcf 100644 --- a/.flowconfig +++ b/.flowconfig @@ -17,10 +17,10 @@ module.name_mapper='^types\(.*\)$' -> '/src/renderer/types\1' module.name_mapper='^component\(.*\)$' -> '/src/renderer/component\1' module.name_mapper='^page\(.*\)$' -> '/src/renderer/page\1' module.name_mapper='^lbry\(.*\)$' -> '/src/renderer/lbry\1' -module.name_mapper='^rewards\(.*\)$' -> '/src/renderer/rewards\1' module.name_mapper='^modal\(.*\)$' -> '/src/renderer/modal\1' module.name_mapper='^app\(.*\)$' -> '/src/renderer/app\1' module.name_mapper='^native\(.*\)$' -> '/src/renderer/native\1' module.name_mapper='^analytics\(.*\)$' -> '/src/renderer/analytics\1' + [strict] diff --git a/package.json b/package.json index 00a4053ac..17b825523 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "hast-util-sanitize": "^1.1.2", "keytar": "^4.2.1", "lbry-redux": "lbryio/lbry-redux#d1cee82af119c0c5f98ec27f94b2e7f61e34b54c", + "lbryinc": "lbryio/lbryinc#c09aa2645ecccb33c83e9a9545ff119232910f6f", "localforage": "^1.7.1", "mammoth": "^1.4.6", "mime": "^2.3.1", diff --git a/src/renderer/analytics.js b/src/renderer/analytics.js index 7ab84e448..68454249c 100644 --- a/src/renderer/analytics.js +++ b/src/renderer/analytics.js @@ -1,6 +1,6 @@ // @flow import mixpanel from 'mixpanel-browser'; -import Lbryio from 'lbryio'; +import { Lbryio } from 'lbryinc'; import isDev from 'electron-is-dev'; if (isDev) { diff --git a/src/renderer/app.js b/src/renderer/app.js index 9933b47eb..6d93deb25 100644 --- a/src/renderer/app.js +++ b/src/renderer/app.js @@ -38,4 +38,7 @@ global.__ = i18n.__; global.__n = i18n.__n; global.app = app; +// Lbryinc needs access to the redux store for dispatching auth-releated actions +global.store = app.store; + export default app; diff --git a/src/renderer/component/app/index.js b/src/renderer/component/app/index.js index d78487976..e68f66443 100644 --- a/src/renderer/component/app/index.js +++ b/src/renderer/component/app/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { selectPageTitle, selectHistoryIndex, selectActiveHistoryEntry } from 'lbry-redux'; import { doRecordScroll } from 'redux/actions/navigation'; -import { selectUser } from 'redux/selectors/user'; +import { selectUser } from 'lbryinc'; import { doAlertError } from 'redux/actions/app'; import App from './view'; @@ -17,4 +17,7 @@ const perform = dispatch => ({ recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)), }); -export default connect(select, perform)(App); +export default connect( + select, + perform +)(App); diff --git a/src/renderer/component/cardVerify/index.js b/src/renderer/component/cardVerify/index.js index 390622f3d..5a770a0e1 100644 --- a/src/renderer/component/cardVerify/index.js +++ b/src/renderer/component/cardVerify/index.js @@ -1,12 +1,14 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { selectUserEmail } from 'redux/selectors/user'; +import { selectUserEmail } from 'lbryinc'; import CardVerify from './view'; const select = state => ({ email: selectUserEmail(state), }); -const perform = dispatch => ({}); +const perform = () => ({}); -export default connect(select, perform)(CardVerify); +export default connect( + select, + perform +)(CardVerify); diff --git a/src/renderer/component/fileViewer/index.js b/src/renderer/component/fileViewer/index.js index 3dca7eb02..56e7fb69b 100644 --- a/src/renderer/component/fileViewer/index.js +++ b/src/renderer/component/fileViewer/index.js @@ -3,6 +3,7 @@ import * as settings from 'constants/settings'; import { doChangeVolume } from 'redux/actions/app'; import { selectVolume } from 'redux/selectors/app'; import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content'; +import { doClaimEligiblePurchaseRewards } from 'lbryinc'; import { makeSelectMetadataForUri, makeSelectContentTypeForUri, @@ -13,7 +14,6 @@ import { makeSelectDownloadingForUri, selectSearchBarFocused, } from 'lbry-redux'; -import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards'; import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings'; import { selectPlayingUri, makeSelectContentPositionForUri } from 'redux/selectors/content'; import { selectFileInfoErrors } from 'redux/selectors/file_info'; diff --git a/src/renderer/component/inviteList/index.js b/src/renderer/component/inviteList/index.js index 7dca63af5..d8df4a4b3 100644 --- a/src/renderer/component/inviteList/index.js +++ b/src/renderer/component/inviteList/index.js @@ -1,6 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { selectUserInvitees, selectUserInviteStatusIsPending } from 'redux/selectors/user'; +import { selectUserInvitees, selectUserInviteStatusIsPending } from 'lbryinc'; import InviteList from './view'; const select = state => ({ @@ -8,6 +7,9 @@ const select = state => ({ isPending: selectUserInviteStatusIsPending(state), }); -const perform = dispatch => ({}); +const perform = () => ({}); -export default connect(select, perform)(InviteList); +export default connect( + select, + perform +)(InviteList); diff --git a/src/renderer/component/inviteList/view.jsx b/src/renderer/component/inviteList/view.jsx index 7874e9251..8d98f94d9 100644 --- a/src/renderer/component/inviteList/view.jsx +++ b/src/renderer/component/inviteList/view.jsx @@ -1,10 +1,20 @@ +// @flow import React from 'react'; import Icon from 'component/common/icon'; import RewardLink from 'component/rewardLink'; -import rewards from 'rewards.js'; +import { rewards } from 'lbryinc'; import * as icons from 'constants/icons'; -class InviteList extends React.PureComponent { +type Props = { + invitees: ?Array<{ + email: string, + invite_accepted: boolean, + invite_reward_claimed: boolean, + invite_reward_claimable: boolean, + }>, +}; + +class InviteList extends React.PureComponent { render() { const { invitees } = this.props; @@ -31,8 +41,8 @@ class InviteList extends React.PureComponent { - {invitees.map((invitee, index) => ( - + {invitees.map(invitee => ( + {invitee.email} {invitee.invite_accepted ? ( diff --git a/src/renderer/component/inviteNew/index.js b/src/renderer/component/inviteNew/index.js index bfb65ab39..f8f527b93 100644 --- a/src/renderer/component/inviteNew/index.js +++ b/src/renderer/component/inviteNew/index.js @@ -3,8 +3,8 @@ import { selectUserInvitesRemaining, selectUserInviteNewIsPending, selectUserInviteNewErrorMessage, -} from 'redux/selectors/user'; -import { doUserInviteNew } from 'redux/actions/user'; + doUserInviteNew, +} from 'lbryinc'; import InviteNew from './view'; const select = state => ({ @@ -17,4 +17,7 @@ const perform = dispatch => ({ inviteNew: email => dispatch(doUserInviteNew(email)), }); -export default connect(select, perform)(InviteNew); +export default connect( + select, + perform +)(InviteNew); diff --git a/src/renderer/component/rewardLink/index.js b/src/renderer/component/rewardLink/index.js index f7e3561ef..37006bfec 100644 --- a/src/renderer/component/rewardLink/index.js +++ b/src/renderer/component/rewardLink/index.js @@ -3,9 +3,10 @@ import { makeSelectClaimRewardError, makeSelectRewardByType, makeSelectIsRewardClaimPending, -} from 'redux/selectors/rewards'; + doClaimRewardType, + doClaimRewardClearError, +} from 'lbryinc'; import { doNavigate } from 'redux/actions/navigation'; -import { doClaimRewardType, doClaimRewardClearError } from 'redux/actions/rewards'; import RewardLink from './view'; const makeSelect = () => { @@ -28,4 +29,7 @@ const perform = dispatch => ({ navigate: path => dispatch(doNavigate(path)), }); -export default connect(makeSelect, perform)(RewardLink); +export default connect( + makeSelect, + perform +)(RewardLink); diff --git a/src/renderer/component/rewardListClaimed/index.js b/src/renderer/component/rewardListClaimed/index.js index 212341cda..1bab4ea82 100644 --- a/src/renderer/component/rewardListClaimed/index.js +++ b/src/renderer/component/rewardListClaimed/index.js @@ -1,10 +1,12 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { selectClaimedRewards } from 'redux/selectors/rewards'; +import { selectClaimedRewards } from 'lbryinc'; import RewardListClaimed from './view'; const select = state => ({ rewards: selectClaimedRewards(state), }); -export default connect(select, null)(RewardListClaimed); +export default connect( + select, + null +)(RewardListClaimed); diff --git a/src/renderer/component/rewardSummary/index.js b/src/renderer/component/rewardSummary/index.js index 331825385..8aaea1384 100644 --- a/src/renderer/component/rewardSummary/index.js +++ b/src/renderer/component/rewardSummary/index.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; -import { selectUnclaimedRewardValue, selectFetchingRewards } from 'redux/selectors/rewards'; -import { doRewardList } from 'redux/actions/rewards'; +import { selectUnclaimedRewardValue, selectFetchingRewards, doRewardList } from 'lbryinc'; import { doFetchRewardedContent } from 'redux/actions/content'; import RewardSummary from './view'; diff --git a/src/renderer/component/rewardTile/view.jsx b/src/renderer/component/rewardTile/view.jsx index 743d5161e..9bfcfc507 100644 --- a/src/renderer/component/rewardTile/view.jsx +++ b/src/renderer/component/rewardTile/view.jsx @@ -3,7 +3,7 @@ import React from 'react'; import Icon from 'component/common/icon'; import RewardLink from 'component/rewardLink'; import Button from 'component/button'; -import rewards from 'rewards'; +import { rewards } from 'lbryinc'; import * as icons from 'constants/icons'; type Props = { diff --git a/src/renderer/component/transactionList/index.js b/src/renderer/component/transactionList/index.js index f87371f4d..fde907969 100644 --- a/src/renderer/component/transactionList/index.js +++ b/src/renderer/component/transactionList/index.js @@ -1,8 +1,7 @@ import { connect } from 'react-redux'; -import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards'; +import { selectClaimedRewardsByTransactionId } from 'lbryinc'; import { doNavigate } from 'redux/actions/navigation'; -import { doNotify } from 'lbry-redux'; -import { selectAllMyClaimsByOutpoint } from 'lbry-redux'; +import { selectAllMyClaimsByOutpoint, doNotify } from 'lbry-redux'; import TransactionList from './view'; const select = state => ({ @@ -15,4 +14,7 @@ const perform = dispatch => ({ openModal: (modal, props) => dispatch(doNotify(modal, props)), }); -export default connect(select, perform)(TransactionList); +export default connect( + select, + perform +)(TransactionList); diff --git a/src/renderer/component/userEmailNew/index.js b/src/renderer/component/userEmailNew/index.js index 0228a4aaa..b15793b6b 100644 --- a/src/renderer/component/userEmailNew/index.js +++ b/src/renderer/component/userEmailNew/index.js @@ -1,7 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doUserEmailNew, doUserInviteNew } from 'redux/actions/user'; -import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user'; +import { selectEmailNewIsPending, selectEmailNewErrorMessage, doUserEmailNew } from 'lbryinc'; import UserEmailNew from './view'; const select = state => ({ @@ -13,4 +11,7 @@ const perform = dispatch => ({ addUserEmail: email => dispatch(doUserEmailNew(email)), }); -export default connect(select, perform)(UserEmailNew); +export default connect( + select, + perform +)(UserEmailNew); diff --git a/src/renderer/component/userEmailVerify/index.js b/src/renderer/component/userEmailVerify/index.js index 886a0318a..6ac91cd13 100644 --- a/src/renderer/component/userEmailVerify/index.js +++ b/src/renderer/component/userEmailVerify/index.js @@ -1,14 +1,12 @@ import { connect } from 'react-redux'; -import { - doUserEmailVerify, - doUserEmailVerifyFailure, - doUserResendVerificationEmail, -} from 'redux/actions/user'; import { selectEmailVerifyIsPending, selectEmailToVerify, selectEmailVerifyErrorMessage, -} from 'redux/selectors/user'; + doUserEmailVerify, + doUserEmailVerifyFailure, + doUserResendVerificationEmail, +} from 'lbryinc'; import UserEmailVerify from './view'; const select = state => ({ @@ -23,4 +21,7 @@ const perform = dispatch => ({ resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)), }); -export default connect(select, perform)(UserEmailVerify); +export default connect( + select, + perform +)(UserEmailVerify); diff --git a/src/renderer/component/userPhoneNew/index.js b/src/renderer/component/userPhoneNew/index.js index 3033a3c2c..12b2fdf2d 100644 --- a/src/renderer/component/userPhoneNew/index.js +++ b/src/renderer/component/userPhoneNew/index.js @@ -1,7 +1,5 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doUserPhoneNew } from 'redux/actions/user'; -import { selectPhoneNewErrorMessage } from 'redux/selectors/user'; +import { selectPhoneNewErrorMessage, doUserPhoneNew } from 'lbryinc'; import UserPhoneNew from './view'; const select = state => ({ @@ -9,7 +7,10 @@ const select = state => ({ }); const perform = dispatch => ({ - addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)), + addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)), }); -export default connect(select, perform)(UserPhoneNew); +export default connect( + select, + perform +)(UserPhoneNew); diff --git a/src/renderer/component/userPhoneVerify/index.js b/src/renderer/component/userPhoneVerify/index.js index fea5e2893..a916182f2 100644 --- a/src/renderer/component/userPhoneVerify/index.js +++ b/src/renderer/component/userPhoneVerify/index.js @@ -1,11 +1,11 @@ -import React from 'react'; import { connect } from 'react-redux'; -import { doUserPhoneVerify, doUserPhoneReset } from 'redux/actions/user'; import { + doUserPhoneVerify, + doUserPhoneReset, selectPhoneToVerify, selectPhoneVerifyErrorMessage, selectUserCountryCode, -} from 'redux/selectors/user'; +} from 'lbryinc'; import UserPhoneVerify from './view'; const select = state => ({ @@ -19,4 +19,7 @@ const perform = dispatch => ({ verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), }); -export default connect(select, perform)(UserPhoneVerify); +export default connect( + select, + perform +)(UserPhoneVerify); diff --git a/src/renderer/component/userVerify/index.js b/src/renderer/component/userVerify/index.js index b139c96c1..8998450b9 100644 --- a/src/renderer/component/userVerify/index.js +++ b/src/renderer/component/userVerify/index.js @@ -1,13 +1,13 @@ import { connect } from 'react-redux'; import { doNotify, MODALS } from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; -import { doUserIdentityVerify } from 'redux/actions/user'; -import rewards from 'rewards'; -import { makeSelectRewardByType } from 'redux/selectors/rewards'; import { + doUserIdentityVerify, + rewards, + makeSelectRewardByType, selectIdentityVerifyIsPending, selectIdentityVerifyErrorMessage, -} from 'redux/selectors/user'; +} from 'lbryinc'; import UserVerify from './view'; const select = state => { @@ -26,4 +26,7 @@ const perform = dispatch => ({ verifyPhone: () => dispatch(doNotify({ id: MODALS.PHONE_COLLECTION })), }); -export default connect(select, perform)(UserVerify); +export default connect( + select, + perform +)(UserVerify); diff --git a/src/renderer/component/userVerify/view.jsx b/src/renderer/component/userVerify/view.jsx index 70c9afd7e..da09e15c3 100644 --- a/src/renderer/component/userVerify/view.jsx +++ b/src/renderer/component/userVerify/view.jsx @@ -2,7 +2,7 @@ import * as React from 'react'; import Button from 'component/button'; import CardVerify from 'component/cardVerify'; -import lbryio from 'lbryio'; +import Lbryio from 'lbryinc'; import * as icons from 'constants/icons'; type Props = { @@ -51,7 +51,7 @@ class UserVerify extends React.PureComponent { label={__('Perform Card Verification')} disabled={isPending} token={this.onToken} - stripeKey={lbryio.getStripeToken()} + stripeKey={Lbryio.getStripeToken()} />
diff --git a/src/renderer/index.js b/src/renderer/index.js index d4b979091..9647865f3 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -11,9 +11,10 @@ import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/ac import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings'; -import { doUserEmailVerify, doAuthenticate } from 'redux/actions/user'; +import { doUserEmailVerify, doAuthenticate, Lbryio } from 'lbryinc'; import 'scss/all.scss'; import store from 'store'; +import pjson from 'package.json'; import app from './app'; import analytics from './analytics'; import doLogWarningConsoleMessage from './logWarningConsoleMessage'; @@ -23,6 +24,40 @@ const APPPAGEURL = 'lbry://?'; autoUpdater.logger = remote.require('electron-log'); +// We need to override Lbryio for getting/setting the authToken +// We interect with ipcRenderer to get the auth key from a users keyring +Lbryio.setOverride('setAuthToken', status => { + Lbryio.call( + 'user', + 'new', + { + auth_token: '', + language: 'en', + app_id: status.installation_id, + }, + 'post' + ).then(response => { + if (!response.auth_token) { + throw new Error(__('auth_token is missing from response')); + } + + ipcRenderer.send('set-auth-token', response.auth_token); + }); +}); + +Lbryio.setOverride( + 'getAuthToken', + () => + new Promise(resolve => { + ipcRenderer.once('auth-token-response', (event, token) => { + Lbryio.authToken = token; + resolve(token); + }); + + ipcRenderer.send('get-auth-token'); + }) +); + ipcRenderer.on('open-uri-requested', (event, uri, newSession) => { if (uri && uri.startsWith('lbry://')) { if (uri.startsWith('lbry://?verify=')) { @@ -156,7 +191,7 @@ const init = () => { ReactDOM.render( app.store.dispatch(doAuthenticate())} + authenticate={() => app.store.dispatch(doAuthenticate(pjson.version))} onReadyToLaunch={onDaemonReady} /> , diff --git a/src/renderer/lbryio.js b/src/renderer/lbryio.js index a80ab27f1..e69de29bb 100644 --- a/src/renderer/lbryio.js +++ b/src/renderer/lbryio.js @@ -1,155 +0,0 @@ -import { ipcRenderer } from 'electron'; -import { Lbry } from 'lbry-redux'; -import querystring from 'querystring'; - -const Lbryio = { - enabled: true, - authenticationPromise: null, -}; - -const CONNECTION_STRING = process.env.LBRY_APP_API_URL - ? process.env.LBRY_APP_API_URL.replace(/\/*$/, '/') // exactly one slash at the end - : 'https://api.lbry.io/'; - -Lbryio.call = (resource, action, params = {}, method = 'get') => { - if (!Lbryio.enabled) { - console.log(__('Internal API disabled')); - return Promise.reject(new Error(__('LBRY internal API is disabled'))); - } - - if (!(method === 'get' || method === 'post')) { - return Promise.reject(new Error(__('Invalid method'))); - } - - function checkAndParse(response) { - if (response.status >= 200 && response.status < 300) { - return response.json(); - } - return response.json().then(json => { - let error; - if (json.error) { - error = new Error(json.error); - } else { - error = new Error('Unknown API error signature'); - } - error.response = response; // This is primarily a hack used in actions/user.js - return Promise.reject(error); - }); - } - - function makeRequest(url, options) { - return fetch(url, options).then(checkAndParse); - } - - return Lbryio.getAuthToken().then(token => { - const fullParams = { auth_token: token, ...params }; - const qs = querystring.stringify(fullParams); - let url = `${CONNECTION_STRING}${resource}/${action}?${qs}`; - - let options = { - method: 'GET', - }; - - if (method === 'post') { - options = { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: qs, - }; - url = `${CONNECTION_STRING}${resource}/${action}`; - } - - return makeRequest(url, options).then(response => response.data); - }); -}; - -Lbryio.authToken = null; - -Lbryio.getAuthToken = () => - new Promise(resolve => { - if (Lbryio.authToken) { - resolve(Lbryio.authToken); - } else { - ipcRenderer.once('auth-token-response', (event, token) => { - Lbryio.authToken = token; - return resolve(token); - }); - ipcRenderer.send('get-auth-token'); - } - }); - -Lbryio.setAuthToken = token => { - Lbryio.authToken = token ? token.toString().trim() : null; - ipcRenderer.send('set-auth-token', token); -}; - -Lbryio.getCurrentUser = () => Lbryio.call('user', 'me'); - -Lbryio.authenticate = () => { - if (!Lbryio.enabled) { - return new Promise(resolve => { - resolve({ - id: 1, - language: 'en', - primary_email: 'disabled@lbry.io', - has_verified_email: true, - is_identity_verified: true, - is_reward_approved: false, - }); - }); - } - - if (Lbryio.authenticationPromise === null) { - Lbryio.authenticationPromise = new Promise((resolve, reject) => { - Lbryio.getAuthToken() - .then(token => { - if (!token || token.length > 60) { - return false; - } - - // check that token works - return Lbryio.getCurrentUser() - .then(() => true) - .catch(() => false); - }) - .then(isTokenValid => { - if (isTokenValid) { - return reject; - } - - return Lbry.status() - .then(status => - Lbryio.call( - 'user', - 'new', - { - auth_token: '', - language: 'en', - app_id: status.installation_id, - }, - 'post' - ) - ) - .then(response => { - if (!response.auth_token) { - throw new Error(__('auth_token is missing from response')); - } - return Lbryio.setAuthToken(response.auth_token); - }); - }) - .then(Lbryio.getCurrentUser) - .then(resolve, reject); - }); - } - - return Lbryio.authenticationPromise; -}; - -Lbryio.getStripeToken = () => - CONNECTION_STRING.startsWith('http://localhost:') - ? 'pk_test_NoL1JWL7i1ipfhVId5KfDZgo' - : 'pk_live_e8M4dRNnCCbmpZzduEUZBgJO'; - -export default Lbryio; diff --git a/src/renderer/modal/modalCreditIntro/index.js b/src/renderer/modal/modalCreditIntro/index.js index da724d2fa..b2d17af94 100644 --- a/src/renderer/modal/modalCreditIntro/index.js +++ b/src/renderer/modal/modalCreditIntro/index.js @@ -1,9 +1,8 @@ import { connect } from 'react-redux'; import { doNavigate } from 'redux/actions/navigation'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectUserIsRewardApproved } from 'redux/selectors/user'; +import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc'; import { selectBalance, doHideNotification } from 'lbry-redux'; -import { selectUnclaimedRewardValue } from 'redux/selectors/rewards'; import * as settings from 'constants/settings'; import ModalCreditIntro from './view'; @@ -25,4 +24,7 @@ const perform = dispatch => () => ({ }, }); -export default connect(select, perform)(ModalCreditIntro); +export default connect( + select, + perform +)(ModalCreditIntro); diff --git a/src/renderer/modal/modalEmailCollection/index.js b/src/renderer/modal/modalEmailCollection/index.js index 311f1c274..eba4ab760 100644 --- a/src/renderer/modal/modalEmailCollection/index.js +++ b/src/renderer/modal/modalEmailCollection/index.js @@ -2,7 +2,7 @@ import * as settings from 'constants/settings'; import { connect } from 'react-redux'; import { doHideNotification } from 'lbry-redux'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectEmailToVerify, selectUser } from 'redux/selectors/user'; +import { selectEmailToVerify, selectUser } from 'lbryinc'; import ModalEmailCollection from './view'; const select = state => ({ @@ -17,4 +17,7 @@ const perform = dispatch => () => ({ }, }); -export default connect(select, perform)(ModalEmailCollection); +export default connect( + select, + perform +)(ModalEmailCollection); diff --git a/src/renderer/modal/modalFirstReward/index.js b/src/renderer/modal/modalFirstReward/index.js index c38b9d7e0..aab42baf6 100644 --- a/src/renderer/modal/modalFirstReward/index.js +++ b/src/renderer/modal/modalFirstReward/index.js @@ -1,7 +1,6 @@ -import rewards from 'rewards'; +import { rewards, makeSelectRewardByType } from 'lbryinc'; import { connect } from 'react-redux'; import { doHideNotification } from 'lbry-redux'; -import { makeSelectRewardByType } from 'redux/selectors/rewards'; import ModalFirstReward from './view'; const select = state => { @@ -16,4 +15,7 @@ const perform = dispatch => ({ closeModal: () => dispatch(doHideNotification()), }); -export default connect(select, perform)(ModalFirstReward); +export default connect( + select, + perform +)(ModalFirstReward); diff --git a/src/renderer/modal/modalPhoneCollection/index.js b/src/renderer/modal/modalPhoneCollection/index.js index 98f60212b..af7d379b4 100644 --- a/src/renderer/modal/modalPhoneCollection/index.js +++ b/src/renderer/modal/modalPhoneCollection/index.js @@ -1,9 +1,6 @@ -import React from 'react'; -import * as settings from 'constants/settings'; import { connect } from 'react-redux'; import { doHideNotification } from 'lbry-redux'; -import { doSetClientSetting } from 'redux/actions/settings'; -import { selectPhoneToVerify, selectUser } from 'redux/selectors/user'; +import { selectPhoneToVerify, selectUser } from 'lbryinc'; import { doNavigate } from 'redux/actions/navigation'; import ModalPhoneCollection from './view'; @@ -19,4 +16,7 @@ const perform = dispatch => () => ({ }, }); -export default connect(select, perform)(ModalPhoneCollection); +export default connect( + select, + perform +)(ModalPhoneCollection); diff --git a/src/renderer/modal/modalRouter/index.js b/src/renderer/modal/modalRouter/index.js index 6e794d9b5..f88bce9dd 100644 --- a/src/renderer/modal/modalRouter/index.js +++ b/src/renderer/modal/modalRouter/index.js @@ -9,7 +9,7 @@ import { selectNotificationProps, } from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; -import { selectUser, selectUserIsVerificationCandidate } from 'redux/selectors/user'; +import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc'; import ModalRouter from './view'; @@ -32,4 +32,7 @@ const perform = dispatch => ({ openModal: notification => dispatch(doNotify(notification)), }); -export default connect(select, perform)(ModalRouter); +export default connect( + select, + perform +)(ModalRouter); diff --git a/src/renderer/page/auth/index.js b/src/renderer/page/auth/index.js index 7964ef405..4fbef0886 100644 --- a/src/renderer/page/auth/index.js +++ b/src/renderer/page/auth/index.js @@ -8,7 +8,7 @@ import { selectUser, selectUserIsPending, selectIdentityVerifyIsPending, -} from 'redux/selectors/user'; +} from 'lbryinc'; import AuthPage from './view'; const select = state => ({ @@ -26,4 +26,7 @@ const perform = dispatch => ({ navigate: path => dispatch(doNavigate(path)), }); -export default connect(select, perform)(AuthPage); +export default connect( + select, + perform +)(AuthPage); diff --git a/src/renderer/page/auth/view.jsx b/src/renderer/page/auth/view.jsx index f7e045241..50a7c20ad 100644 --- a/src/renderer/page/auth/view.jsx +++ b/src/renderer/page/auth/view.jsx @@ -21,7 +21,7 @@ type Props = { navigate: (string, ?{}) => void, }; -export class AuthPage extends React.PureComponent { +class AuthPage extends React.PureComponent { componentWillMount() { this.navigateIfAuthenticated(this.props); } diff --git a/src/renderer/page/help/index.js b/src/renderer/page/help/index.js index cfabb784b..d00bda044 100644 --- a/src/renderer/page/help/index.js +++ b/src/renderer/page/help/index.js @@ -1,8 +1,7 @@ import { connect } from 'react-redux'; import { doAuthNavigate } from 'redux/actions/navigation'; -import { doFetchAccessToken } from 'redux/actions/user'; +import { doFetchAccessToken, selectAccessToken, selectUser } from 'lbryinc'; import { selectDaemonSettings } from 'redux/selectors/settings'; -import { selectAccessToken, selectUser } from 'redux/selectors/user'; import HelpPage from './view'; const select = state => ({ diff --git a/src/renderer/page/invite/index.js b/src/renderer/page/invite/index.js index 65360a1f2..c69a52697 100644 --- a/src/renderer/page/invite/index.js +++ b/src/renderer/page/invite/index.js @@ -1,11 +1,10 @@ -import React from 'react'; import { connect } from 'react-redux'; -import InvitePage from './view'; -import { doFetchInviteStatus } from 'redux/actions/user'; import { + doFetchInviteStatus, selectUserInviteStatusFailed, selectUserInviteStatusIsPending, -} from 'redux/selectors/user'; +} from 'lbryinc'; +import InvitePage from './view'; const select = state => ({ isFailed: selectUserInviteStatusFailed(state), @@ -16,4 +15,7 @@ const perform = dispatch => ({ fetchInviteStatus: () => dispatch(doFetchInviteStatus()), }); -export default connect(select, perform)(InvitePage); +export default connect( + select, + perform +)(InvitePage); diff --git a/src/renderer/page/rewards/index.js b/src/renderer/page/rewards/index.js index 3a8bfb3c4..636f57752 100644 --- a/src/renderer/page/rewards/index.js +++ b/src/renderer/page/rewards/index.js @@ -3,10 +3,10 @@ import { selectFetchingRewards, selectUnclaimedRewards, selectClaimedRewards, -} from 'redux/selectors/rewards'; -import { selectUser } from 'redux/selectors/user'; + selectUser, + doRewardList, +} from 'lbryinc'; import { doAuthNavigate, doNavigate } from 'redux/actions/navigation'; -import { doRewardList } from 'redux/actions/rewards'; import { selectDaemonSettings } from 'redux/selectors/settings'; import RewardsPage from './view'; diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index afb7bf13e..c41702b4e 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -16,7 +16,6 @@ import Native from 'native'; import { doFetchRewardedContent } from 'redux/actions/content'; import { doFetchDaemonSettings } from 'redux/actions/settings'; import { doAuthNavigate } from 'redux/actions/navigation'; -import { doAuthenticate } from 'redux/actions/user'; import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions'; import { selectIsUpgradeSkipped, @@ -28,7 +27,8 @@ import { selectRemoteVersion, selectUpgradeTimer, } from 'redux/selectors/app'; -import { lbrySettings as config } from 'package.json'; +import { doAuthenticate } from 'lbryinc'; +import { lbrySettings as config, version as appVersion } from 'package.json'; const { autoUpdater } = remote.require('electron-updater'); const { download } = remote.require('electron-dl'); @@ -333,7 +333,7 @@ export function doDaemonReady() { return (dispatch, getState) => { const state = getState(); - dispatch(doAuthenticate()); + dispatch(doAuthenticate(appVersion)); dispatch({ type: ACTIONS.DAEMON_READY }); dispatch(doFetchDaemonSettings()); dispatch(doBalanceSubscribe()); diff --git a/src/renderer/redux/actions/content.js b/src/renderer/redux/actions/content.js index e39508808..208fc3879 100644 --- a/src/renderer/redux/actions/content.js +++ b/src/renderer/redux/actions/content.js @@ -1,7 +1,6 @@ // @flow import * as NOTIFICATION_TYPES from 'constants/notification_types'; import { ipcRenderer } from 'electron'; -import Lbryio from 'lbryio'; import { doAlertError } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { @@ -32,6 +31,7 @@ import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/sel import setBadge from 'util/setBadge'; import setProgressBar from 'util/setProgressBar'; import analytics from 'analytics'; +import { Lbryio } from 'lbryinc'; const DOWNLOAD_POLL_INTERVAL = 250; diff --git a/src/renderer/redux/actions/rewards.js b/src/renderer/redux/actions/rewards.js deleted file mode 100644 index 18823dcf3..000000000 --- a/src/renderer/redux/actions/rewards.js +++ /dev/null @@ -1,117 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; -import Lbryio from 'lbryio'; -import { doNotify, MODALS } from 'lbry-redux'; -import { selectUnclaimedRewards } from 'redux/selectors/rewards'; -import { selectUserIsRewardApproved } from 'redux/selectors/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 unclaimedRewards = selectUnclaimedRewards(state); - const reward = unclaimedRewards.find(ur => ur.reward_type === rewardType); - const userIsRewardApproved = selectUserIsRewardApproved(state); - - if (!reward || reward.transaction_id) { - // already claimed or doesn't exist, do nothing - return; - } - - if (!userIsRewardApproved && rewardType !== rewards.TYPE_CONFIRM_EMAIL) { - if (!options || !options.failSilently) { - const action = doNotify({ - id: MODALS.REWARD_APPROVAL_REQUIRED, - isError: false, - }); - dispatch(action); - } - - return; - } - - dispatch({ - type: ACTIONS.CLAIM_REWARD_STARTED, - data: { reward }, - }); - - const success = successReward => { - dispatch(doRewardList()); - dispatch({ - type: ACTIONS.CLAIM_REWARD_SUCCESS, - data: { - reward: successReward, - }, - }); - if (successReward.reward_type === rewards.TYPE_NEW_USER) { - const action = doNotify({ - id: MODALS.FIRST_REWARD, - isError: false, - }); - dispatch(action); - } - }; - - const failure = error => { - dispatch({ - type: ACTIONS.CLAIM_REWARD_FAILURE, - data: { - reward, - error: !options || !options.failSilently ? error : undefined, - }, - }); - }; - - rewards.claimReward(rewardType).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_FEATURED_DOWNLOAD].forEach(type => { - dispatch(doClaimRewardType(type, { failSilently: true })); - }); - } - }; -} - -export function doClaimRewardClearError(reward) { - return dispatch => { - dispatch({ - type: ACTIONS.CLAIM_REWARD_CLEAR_ERROR, - data: { reward }, - }); - }; -} diff --git a/src/renderer/redux/actions/subscriptions.js b/src/renderer/redux/actions/subscriptions.js index 1f4f320aa..13cce467d 100644 --- a/src/renderer/redux/actions/subscriptions.js +++ b/src/renderer/redux/actions/subscriptions.js @@ -2,16 +2,14 @@ import * as ACTIONS from 'constants/action_types'; import * as NOTIFICATION_TYPES from 'constants/notification_types'; import * as SETTINGS from 'constants/settings'; -import rewards from 'rewards'; +import { Lbryio, rewards, doClaimRewardType } from 'lbryinc'; import type { Dispatch, SubscriptionNotifications } from 'redux/reducers/subscriptions'; import type { Subscription } from 'types/subscription'; import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import { Lbry, buildURI, parseURI, selectCurrentPage } from 'lbry-redux'; import { doPurchaseUri, doFetchClaimsByChannel } from 'redux/actions/content'; -import { doClaimRewardType } from 'redux/actions/rewards'; import Promise from 'bluebird'; -import Lbryio from 'lbryio'; const CHECK_SUBSCRIPTIONS_INTERVAL = 15 * 60 * 1000; const SUBSCRIPTION_DOWNLOAD_LIMIT = 1; @@ -246,7 +244,7 @@ export const doChannelSubscribe = (subscription: Subscription) => ( claim_id: claimId, }); - dispatch(doClaimRewardType(rewards.SUBSCRIPTION, { failSilently: true })); + dispatch(doClaimRewardType(rewards.TYPE_SUBSCRIPTION, { failSilently: true })); } dispatch(doCheckSubscription(subscription.uri, true)); diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js deleted file mode 100644 index 963e503c9..000000000 --- a/src/renderer/redux/actions/user.js +++ /dev/null @@ -1,360 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; -import Lbryio from 'lbryio'; -import { Lbry, doNotify, MODALS, doHideNotification } from 'lbry-redux'; -import { doClaimRewardType, doRewardList } from 'redux/actions/rewards'; -import { - selectEmailToVerify, - selectPhoneToVerify, - selectUserCountryCode, -} from 'redux/selectors/user'; -import rewards from 'rewards'; -import analytics from 'analytics'; -import pjson from 'package.json'; - -export function doFetchInviteStatus() { - return dispatch => { - dispatch({ - type: ACTIONS.USER_INVITE_STATUS_FETCH_STARTED, - }); - - Lbryio.call('user', 'invite_status') - .then(status => { - dispatch({ - type: ACTIONS.USER_INVITE_STATUS_FETCH_SUCCESS, - data: { - invitesRemaining: status.invites_remaining ? status.invites_remaining : 0, - invitees: status.invitees, - }, - }); - }) - .catch(error => { - dispatch({ - type: ACTIONS.USER_INVITE_STATUS_FETCH_FAILURE, - data: { error }, - }); - }); - }; -} - -export function doInstallNew() { - const payload = { app_version: pjson.version }; - Lbry.status().then(status => { - payload.app_id = status.installation_id; - if (status.dht) payload.node_id = status.dht.node_id; - Lbry.version().then(version => { - payload.daemon_version = version.lbrynet_version; - payload.operating_system = version.os_system; - payload.platform = version.platform; - Lbryio.call('install', 'new', payload); - }); - }); -} - -export function doAuthenticate() { - return dispatch => { - dispatch({ - type: ACTIONS.AUTHENTICATION_STARTED, - }); - Lbryio.authenticate() - .then(user => { - analytics.setUser(user); - dispatch({ - type: ACTIONS.AUTHENTICATION_SUCCESS, - data: { user }, - }); - dispatch(doRewardList()); - dispatch(doFetchInviteStatus()); - doInstallNew(); - }) - .catch(error => { - dispatch(doNotify({ id: MODALS.AUTHENTICATION_FAILURE })); - dispatch({ - type: ACTIONS.AUTHENTICATION_FAILURE, - data: { error }, - }); - }); - }; -} - -export function doUserFetch() { - return dispatch => { - dispatch({ - type: ACTIONS.USER_FETCH_STARTED, - }); - Lbryio.getCurrentUser() - .then(user => { - analytics.setUser(user); - dispatch(doRewardList()); - - dispatch({ - type: ACTIONS.USER_FETCH_SUCCESS, - data: { user }, - }); - }) - .catch(error => { - dispatch({ - type: ACTIONS.USER_FETCH_FAILURE, - data: { error }, - }); - }); - }; -} - -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(doHideNotification()); - dispatch(doClaimRewardType(rewards.TYPE_NEW_USER)); - } - }) - .catch(error => dispatch(doUserPhoneVerifyFailure(error))); - }; -} - -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) { - return Lbryio.call( - 'user_email', - 'resend_token', - { email, only_if_expired: true }, - 'post' - ).then(success, failure); - } - throw error; - }) - .then(success, failure); - }; -} - -export function doUserResendVerificationEmail(email) { - return dispatch => { - dispatch({ - type: ACTIONS.USER_EMAIL_VERIFY_RETRY, - 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', 'resend_token', { email }, 'post') - .catch(error => { - if (error.response && error.response.status === 409) { - throw error; - } - }) - .then(success, failure); - }; -} - -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 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 doFetchAccessToken() { - return dispatch => { - const success = token => - dispatch({ - type: ACTIONS.FETCH_ACCESS_TOKEN_SUCCESS, - data: { token }, - }); - Lbryio.getAuthToken().then(success); - }; -} - -export function doUserInviteNew(email) { - return dispatch => { - dispatch({ - type: ACTIONS.USER_INVITE_NEW_STARTED, - }); - - Lbryio.call('user', 'invite', { email }, 'post') - .then(() => { - dispatch({ - type: ACTIONS.USER_INVITE_NEW_SUCCESS, - data: { email }, - }); - - dispatch( - doNotify({ - displayType: ['snackbar'], - message: __('Invite sent to %s', email), - }) - ); - - dispatch(doFetchInviteStatus()); - }) - .catch(error => { - dispatch({ - type: ACTIONS.USER_INVITE_NEW_FAILURE, - data: { error }, - }); - }); - }; -} diff --git a/src/renderer/redux/reducers/rewards.js b/src/renderer/redux/reducers/rewards.js deleted file mode 100644 index 67f861e6c..000000000 --- a/src/renderer/redux/reducers/rewards.js +++ /dev/null @@ -1,98 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; -const defaultState = { - fetching: false, - claimedRewardsById: {}, // id => reward - unclaimedRewards: [], - claimPendingByType: {}, - claimErrorsByType: {}, -}; - -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); - 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.reward_type === reward.reward_type); - 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], ''); -}; - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/reducers/user.js b/src/renderer/redux/reducers/user.js deleted file mode 100644 index aade82c69..000000000 --- a/src/renderer/redux/reducers/user.js +++ /dev/null @@ -1,222 +0,0 @@ -import * as ACTIONS from 'constants/action_types'; - -const reducers = {}; - -const defaultState = { - authenticationIsPending: false, - userIsPending: false, - emailNewIsPending: false, - emailNewErrorMessage: '', - emailToVerify: '', - inviteNewErrorMessage: '', - inviteNewIsPending: false, - inviteStatusIsPending: false, - invitesRemaining: undefined, - invitees: undefined, - user: undefined, -}; - -reducers[ACTIONS.AUTHENTICATION_STARTED] = state => - Object.assign({}, state, { - authenticationIsPending: true, - userIsPending: true, - user: defaultState.user, - }); - -reducers[ACTIONS.AUTHENTICATION_SUCCESS] = (state, action) => - Object.assign({}, state, { - authenticationIsPending: false, - userIsPending: false, - 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, - user: defaultState.user, - }); - -reducers[ACTIONS.USER_FETCH_SUCCESS] = (state, action) => - Object.assign({}, state, { - userIsPending: false, - user: action.data.user, - }); - -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: '', - }); - -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, action) => - Object.assign({}, state, { - emailToVerify: action.data.email, - emailNewIsPending: false, - }); - -reducers[ACTIONS.USER_EMAIL_NEW_FAILURE] = (state, action) => - Object.assign({}, state, { - emailNewIsPending: false, - emailNewErrorMessage: action.data.error, - }); - -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_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, - }); - -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, - }); - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/src/renderer/redux/selectors/rewards.js b/src/renderer/redux/selectors/rewards.js deleted file mode 100644 index c7fd3ef3d..000000000 --- a/src/renderer/redux/selectors/rewards.js +++ /dev/null @@ -1,64 +0,0 @@ -import { createSelector } from 'reselect'; - -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); - -export const makeSelectRewardAmountByType = () => - createSelector(selectRewardByType, reward => (reward ? reward.reward_amount : 0)); diff --git a/src/renderer/redux/selectors/user.js b/src/renderer/redux/selectors/user.js deleted file mode 100644 index a1b0df18e..000000000 --- a/src/renderer/redux/selectors/user.js +++ /dev/null @@ -1,118 +0,0 @@ -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 selectUserEmail = createSelector( - selectUser, - user => (user ? user.primary_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 selectUserIsRewardApproved = createSelector( - selectUser, - user => user && user.is_reward_approved -); - -export const selectEmailNewIsPending = createSelector( - selectState, - state => state.emailNewIsPending -); - -export const selectEmailNewErrorMessage = createSelector( - selectState, - state => state.emailNewErrorMessage -); - -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 selectPhoneVerifyErrorMessage = createSelector( - selectState, - state => state.phoneVerifyErrorMessage -); - -export const selectIdentityVerifyIsPending = createSelector( - selectState, - state => state.identityVerifyIsPending -); - -export const selectIdentityVerifyErrorMessage = createSelector( - selectState, - state => state.identityVerifyErrorMessage -); - -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 -); diff --git a/src/renderer/rewards.js b/src/renderer/rewards.js deleted file mode 100644 index da3833e7b..000000000 --- a/src/renderer/rewards.js +++ /dev/null @@ -1,113 +0,0 @@ -import { Lbry, doNotify } from 'lbry-redux'; -import Lbryio from 'lbryio'; - -const rewards = {}; - -rewards.TYPE_NEW_DEVELOPER = 'new_developer'; -rewards.TYPE_NEW_USER = 'new_user'; -rewards.TYPE_CONFIRM_EMAIL = 'verified_email'; -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_FEATURED_DOWNLOAD = 'featured_download'; -rewards.TYPE_REFERRAL = 'referral'; -rewards.YOUTUBE_CREATOR = 'youtube_creator'; -rewards.SUBSCRIPTION = 'subscription'; - -rewards.claimReward = type => { - function requestReward(resolve, reject, params) { - if (!Lbryio.enabled) { - reject(new Error(__('Rewards are not enabled.'))); - return; - } - Lbryio.call('reward', 'new', params, 'post').then(reward => { - const message = - reward.reward_notification || `You have claimed a ${reward.reward_amount} LBC reward.`; - - // Display global notice - const action = doNotify({ - message, - linkText: __('Show All'), - linkTarget: '/rewards', - isError: false, - displayType: ['snackbar'], - }); - window.app.store.dispatch(action); - - // Add more events here to display other places - - resolve(reward); - }, reject); - } - - return new Promise((resolve, reject) => { - Lbry.wallet_unused_address().then(address => { - const params = { - reward_type: type, - wallet_address: address, - }; - - switch (type) { - case rewards.TYPE_FIRST_CHANNEL: - Lbry.claim_list_mine() - .then(claims => { - const claim = claims - .reverse() - .find( - foundClaim => - foundClaim.name.length && - foundClaim.name[0] === '@' && - foundClaim.txid.length && - foundClaim.category === '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.claim_list_mine() - .then(claims => { - const claim = claims - .reverse() - .find( - foundClaim => - foundClaim.name.length && - foundClaim.name[0] !== '@' && - foundClaim.txid.length && - foundClaim.category === '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); - } - }); - }); -}; - -export default rewards; diff --git a/src/renderer/store.js b/src/renderer/store.js index 37cbd6cf0..fdb1be5c9 100644 --- a/src/renderer/store.js +++ b/src/renderer/store.js @@ -12,9 +12,8 @@ import { blacklistReducer, } from 'lbry-redux'; import navigationReducer from 'redux/reducers/navigation'; -import rewardsReducer from 'redux/reducers/rewards'; import settingsReducer from 'redux/reducers/settings'; -import userReducer from 'redux/reducers/user'; +import { userReducer, rewardsReducer } from 'lbryinc'; import shapeShiftReducer from 'redux/reducers/shape_shift'; import subscriptionsReducer from 'redux/reducers/subscriptions'; import publishReducer from 'redux/reducers/publish'; diff --git a/yarn.lock b/yarn.lock index 149175414..f82b53e6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5655,6 +5655,13 @@ lazy-val@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc" +lbry-redux@lbryio/lbry-redux: + version "0.0.1" + resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/a8e81949837171e94e649fce6f7c7a8b7faadd51" + dependencies: + proxy-polyfill "0.1.6" + reselect "^3.0.0" + lbry-redux@lbryio/lbry-redux#d1cee82af119c0c5f98ec27f94b2e7f61e34b54c: version "0.0.1" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/d1cee82af119c0c5f98ec27f94b2e7f61e34b54c" @@ -5662,6 +5669,13 @@ lbry-redux@lbryio/lbry-redux#d1cee82af119c0c5f98ec27f94b2e7f61e34b54c: proxy-polyfill "0.1.6" reselect "^3.0.0" +lbryinc@lbryio/lbryinc#c09aa2645ecccb33c83e9a9545ff119232910f6f: + version "0.0.1" + resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/c09aa2645ecccb33c83e9a9545ff119232910f6f" + dependencies: + lbry-redux lbryio/lbry-redux + reselect "^3.0.0" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"