diff --git a/package.json b/package.json index 433fa8624..45f95efed 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dev:web": "cd ./lbrytv && yarn dev", "dev:web-server": "cross-env NODE_ENV=development yarn compile:web && concurrently \"cross-env NODE_ENV=development yarn compile:web --watch\" \"cd ./lbrytv && yarn dev:server\"", "dev:internal-apis": "LBRY_API_URL='http://localhost:8080' yarn dev:electron", + "dev:iatv": "LBRY_API_URL='http://localhost:15400' SDK_API_URL='http://localhost:15100' yarn dev:web", "run:web": "cross-env NODE_ENV=production yarn compile:web && node ./dist/web/server.js", "pack": "electron-builder --dir", "dist": "electron-builder", @@ -158,8 +159,8 @@ "react-modal": "^3.1.7", "react-paginate": "^5.2.1", "react-redux": "^6.0.1", - "react-router": "^5.0.0", - "react-router-dom": "^5.0.0", + "react-router": "^5.1.0", + "react-router-dom": "^5.1.0", "react-simplemde-editor": "^4.0.0", "react-spring": "^8.0.20", "react-sticky-box": "^0.8.0", diff --git a/ui/component/app/index.js b/ui/component/app/index.js index 33cc17d4a..d9bbf88c8 100644 --- a/ui/component/app/index.js +++ b/ui/component/app/index.js @@ -1,16 +1,29 @@ import * as SETTINGS from 'constants/settings'; import { hot } from 'react-hot-loader/root'; import { connect } from 'react-redux'; -import { selectUser, doRewardList, doFetchAccessToken, selectGetSyncErrorMessage, selectUploadCount } from 'lbryinc'; +import { + selectUser, + selectAccessToken, + doRewardList, + doFetchAccessToken, + selectGetSyncErrorMessage, + selectUploadCount, +} from 'lbryinc'; import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux'; import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { doSetLanguage } from 'redux/actions/settings'; -import { doDownloadUpgradeRequested, doSignIn, doSyncWithPreferences, doGetAndPopulatePreferences } from 'redux/actions/app'; +import { + doDownloadUpgradeRequested, + doSignIn, + doSyncWithPreferences, + doGetAndPopulatePreferences, +} from 'redux/actions/app'; import App from './view'; const select = state => ({ user: selectUser(state), + accessToken: selectAccessToken(state), theme: selectThemePath(state), language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), languages: selectLoadedLanguages(state), diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index b439c8490..3cb6e833e 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -60,6 +60,7 @@ function App(props: Props) { fetchRewards, fetchTransactions, user, + accessToken, fetchAccessToken, fetchChannelListMine, signIn, @@ -186,7 +187,7 @@ function App(props: Props) { // Require an internal-api user on lbry.tv // This also prevents the site from loading in the un-authed state while we wait for internal-apis to return for the first time // It's not needed on desktop since there is no un-authed state - if (!user) { + if (!accessToken) { return null; } // @endif diff --git a/ui/component/claimPreview/index.js b/ui/component/claimPreview/index.js index 68aed8ac7..fa6fd6c18 100644 --- a/ui/component/claimPreview/index.js +++ b/ui/component/claimPreview/index.js @@ -7,6 +7,7 @@ import { makeSelectClaimIsMine, makeSelectClaimIsPending, makeSelectThumbnailForUri, + makeSelectCoverForUri, makeSelectTitleForUri, makeSelectClaimIsNsfw, selectBlockedChannels, @@ -32,6 +33,7 @@ const select = (state, props) => ({ claimIsMine: props.uri && makeSelectClaimIsMine(props.uri)(state), isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state), thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state), + cover: props.uri && makeSelectCoverForUri(props.uri)(state), title: props.uri && makeSelectTitleForUri(props.uri)(state), mediaType: makeSelectMediaTypeForUri(props.uri)(state), nsfw: props.uri && makeSelectClaimIsNsfw(props.uri)(state), diff --git a/ui/component/invited/index.js b/ui/component/invited/index.js new file mode 100644 index 000000000..636396c4b --- /dev/null +++ b/ui/component/invited/index.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux'; +import { + selectUser, + doClaimRewardType, + doUserFetch, + doUserSetReferrer, + selectSetReferrerPending, + selectSetReferrerError, + rewards as REWARDS, +} from 'lbryinc'; +import Invited from './view'; + +const select = state => ({ + user: selectUser(state), + setReferrerPending: selectSetReferrerPending(state), + setReferrerError: selectSetReferrerError(state), +}); + +const perform = dispatch => ({ + claimReward: () => dispatch(doClaimRewardType(REWARDS.TYPE_REFEREE)), + fetchUser: () => dispatch(doUserFetch()), + setReferrer: referrer => dispatch(doUserSetReferrer(referrer)), +}); + +export default connect( + select, + perform +)(Invited); diff --git a/ui/component/invited/view.jsx b/ui/component/invited/view.jsx new file mode 100644 index 000000000..5476b8390 --- /dev/null +++ b/ui/component/invited/view.jsx @@ -0,0 +1,115 @@ +// @flow +import * as PAGES from 'constants/pages'; +import React, { useEffect } from 'react'; +import { useParams } from 'react-router'; +import Button from 'component/button'; +import ClaimPreview from 'component/claimPreview'; +import Card from 'component/common/card'; +import { parseURI } from 'lbry-redux'; + +type Props = { + user: any, + fetchUser: () => void, + claimReward: () => void, + setReferrer: string => void, + setReferrerPending: boolean, + setReferrerError: string, +}; + +function Invited(props: Props) { + const { user, fetchUser, claimReward, setReferrer, setReferrerPending, setReferrerError } = props; + + // useParams requires react-router-dom ^v5.1.0 + const { referrer } = useParams(); + const refUri = 'lbry://' + referrer.replace(':', '#'); + const referrerIsChannel = parseURI(refUri).isChannel; + // const hasReferrer = user && user['invited_by_id'] ? true : false; + const rewardsApproved = user && user.is_reward_approved; + const hasVerifiedEmail = user && user.has_verified_email; + + useEffect(() => { + fetchUser(); + }, []); + + useEffect(() => { + if (setReferrerPending && hasVerifiedEmail) { + claimReward(); + } + }, [setReferrerPending, hasVerifiedEmail]); + + //follow + + // !signed in or approved + useEffect(() => { + if (referrer) { + setReferrer(referrer.replace(':', '#')); + } + }, [referrer, hasVerifiedEmail]); + + if (setReferrerError) { + return ( + +

{__('Not a valid referral')}

+

{setReferrerError}

+ +
+
+ + } + /> + ); + } + + if (!rewardsApproved) { + return ( + + {referrerIsChannel && ( +
+ +
+ )} +
+
+ + } + /> + ); + } + + return ( + + {referrerIsChannel && ( +
+ +
+ )} +
+
+ + } + /> + ); +} + +export default Invited; diff --git a/ui/component/rewardTile/index.js b/ui/component/rewardTile/index.js index 08ad8e3f2..fc8915f4a 100644 --- a/ui/component/rewardTile/index.js +++ b/ui/component/rewardTile/index.js @@ -5,6 +5,7 @@ import RewardTile from './view'; const perform = dispatch => ({ openRewardCodeModal: () => dispatch(doOpenModal(MODALS.REWARD_GENERATED_CODE)), + openSetReferrerModal: () => dispatch(doOpenModal(MODALS.SET_REFERRER)), }); export default connect( diff --git a/ui/component/rewardTile/view.jsx b/ui/component/rewardTile/view.jsx index 90446082b..d8cee78e3 100644 --- a/ui/component/rewardTile/view.jsx +++ b/ui/component/rewardTile/view.jsx @@ -37,6 +37,9 @@ const RewardTile = (props: Props) => { {reward.reward_type === rewards.TYPE_REFERRAL && (