diff --git a/.flowconfig b/.flowconfig index de74dca5966..6731231c0b3 100644 --- a/.flowconfig +++ b/.flowconfig @@ -24,6 +24,7 @@ module.name_mapper='^app\(.*\)$' -> '/src/ui/app\1' module.name_mapper='^native\(.*\)$' -> '/src/ui/native\1' module.name_mapper='^analytics\(.*\)$' -> '/src/ui/analytics\1' module.name_mapper='^i18n\(.*\)$' -> '/src/ui/i18n\1' +module.name_mapper='^effects\(.*\)$' -> '/src/ui/effects\1' module.name_mapper='^config\(.*\)$' -> '/config\1' diff --git a/flow-typed/18nj.js b/flow-typed/18nj.js new file mode 100644 index 00000000000..de97c0c8671 --- /dev/null +++ b/flow-typed/18nj.js @@ -0,0 +1,2 @@ +// @flow +declare function __(a: string, b?: {}): string; diff --git a/package.json b/package.json index 5f8dc9f54ae..b76bbc83f80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lbry", - "version": "0.35.7", + "version": "0.36.0-rc.1", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "keywords": [ "lbry" @@ -129,7 +129,7 @@ "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-redux": "lbryio/lbry-redux#04ae0913a444abac200731c7ed53796d763a0bbb", - "lbryinc": "lbryio/lbryinc#d99232ebc754a49649a2ff4132478415faef08e2", + "lbryinc": "lbryio/lbryinc#a44576194e1f5f60e37d328ddfdca40bd6165c2d", "lint-staged": "^7.0.2", "localforage": "^1.7.1", "lodash-es": "^4.17.14", @@ -151,6 +151,7 @@ "raw-loader": "^2.0.0", "rc-progress": "^2.0.6", "react": "^16.8.2", + "react-confetti": "^4.0.1", "react-dom": "^16.8.2", "react-draggable": "^3.3.0", "react-ga": "^2.5.7", diff --git a/src/ui/component/app/index.js b/src/ui/component/app/index.js index ec011bb9e53..a7e13ac1362 100644 --- a/src/ui/component/app/index.js +++ b/src/ui/component/app/index.js @@ -1,7 +1,7 @@ import * as SETTINGS from 'constants/settings'; import { hot } from 'react-hot-loader/root'; import { connect } from 'react-redux'; -import { selectUser, doRewardList, doFetchRewardedContent, doFetchAccessToken, selectAccessToken } from 'lbryinc'; +import { selectUser, doRewardList, doFetchRewardedContent, doFetchAccessToken } from 'lbryinc'; import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux'; import { makeSelectClientSetting, selectThemePath } from 'redux/selectors/settings'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; @@ -12,7 +12,6 @@ const select = state => ({ user: selectUser(state), theme: selectThemePath(state), language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), - accessToken: selectAccessToken(state), autoUpdateDownloaded: selectAutoUpdateDownloaded(state), isUpgradeAvailable: selectIsUpgradeAvailable(state), }); @@ -22,9 +21,9 @@ const perform = dispatch => ({ fetchRewardedContent: () => dispatch(doFetchRewardedContent()), fetchTransactions: () => dispatch(doFetchTransactions()), fetchAccessToken: () => dispatch(doFetchAccessToken()), - requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()), - onSignedIn: () => dispatch(doSignIn()), + signIn: () => dispatch(doSignIn()), + requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), }); export default hot( diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx index f17ee1a669d..37c02008bfc 100644 --- a/src/ui/component/app/view.jsx +++ b/src/ui/component/app/view.jsx @@ -11,7 +11,7 @@ import useKonamiListener from 'util/enhanced-layout'; import Yrbl from 'component/yrbl'; import FileViewer from 'component/fileViewer'; import { withRouter } from 'react-router'; -import usePrevious from 'util/use-previous'; +import usePrevious from 'effects/use-previous'; import Button from 'component/button'; export const MAIN_WRAPPER_CLASS = 'main-wrapper'; @@ -27,11 +27,13 @@ type Props = { fetchRewardedContent: () => void, fetchTransactions: () => void, fetchAccessToken: () => void, - autoUpdateDownloaded: boolean, - isUpgradeAvailable: boolean, + fetchChannelListMine: () => void, + signIn: () => void, requestDownloadUpgrade: () => void, fetchChannelListMine: () => void, onSignedIn: () => void, + isUpgradeAvailable: boolean, + autoUpdateDownloaded: boolean, }; function App(props: Props) { @@ -42,11 +44,11 @@ function App(props: Props) { fetchTransactions, user, fetchAccessToken, - requestDownloadUpgrade, + fetchChannelListMine, + signIn, autoUpdateDownloaded, isUpgradeAvailable, - fetchChannelListMine, - onSignedIn, + requestDownloadUpgrade, } = props; const appRef = useRef(); const isEnhancedLayout = useKonamiListener(); @@ -94,7 +96,7 @@ function App(props: Props) { if (previousHasVerifiedEmail === false && hasVerifiedEmail) { analytics.emailVerifiedEvent(); } - }, [previousHasVerifiedEmail, hasVerifiedEmail, onSignedIn]); + }, [previousHasVerifiedEmail, hasVerifiedEmail, signIn]); useEffect(() => { if (previousRewardApproved === false && isRewardApproved) { @@ -105,9 +107,9 @@ function App(props: Props) { // Keep this at the end to ensure initial setup effects are run first useEffect(() => { if (!previousHasVerifiedEmail && hasVerifiedEmail) { - onSignedIn(); + signIn(); } - }, [previousHasVerifiedEmail, hasVerifiedEmail, onSignedIn]); + }, [previousHasVerifiedEmail, hasVerifiedEmail, signIn]); if (!user) { return null; diff --git a/src/ui/component/blockButton/view.jsx b/src/ui/component/blockButton/view.jsx index ea1228c4730..62e75e1eab8 100644 --- a/src/ui/component/blockButton/view.jsx +++ b/src/ui/component/blockButton/view.jsx @@ -3,7 +3,7 @@ import * as ICONS from 'constants/icons'; import * as PAGES from 'constants/pages'; import React, { useRef } from 'react'; import Button from 'component/button'; -import useHover from 'util/use-hover'; +import useHover from 'effects/use-hover'; type Props = { permanentUrl: ?string, diff --git a/src/ui/component/channelContent/view.jsx b/src/ui/component/channelContent/view.jsx index dfd03a35bf3..2aec0ddf9c3 100644 --- a/src/ui/component/channelContent/view.jsx +++ b/src/ui/component/channelContent/view.jsx @@ -64,7 +64,7 @@ function ChannelContent(props: Props) { )} - {!channelIsMine && } + {!channelIsMine && } {hasContent && !channelIsBlocked && !channelIsBlackListed && ( claim && claim.canonical_url)} /> diff --git a/src/ui/component/channelEdit/view.jsx b/src/ui/component/channelEdit/view.jsx index 725e2389d77..bb0ec1418e3 100644 --- a/src/ui/component/channelEdit/view.jsx +++ b/src/ui/component/channelEdit/view.jsx @@ -182,7 +182,7 @@ function ChannelForm(props: Props) { onChange={text => setParams({ ...params, description: text })} /> void, + actions: boolean | Node | string | number, + properties: boolean | Node | string | number, + onClick?: any => any, }; const ClaimPreview = forwardRef((props: Props, ref: any) => { @@ -70,12 +74,14 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { channelIsBlocked, isSubscribed, beginPublish, + actions, + properties, + onClick, } = props; const shouldFetch = claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta)); const abandoned = !isResolvingUri && !claim; const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0; const showPublishLink = abandoned && placeholder === 'publish'; - const includeChannelTooltip = type !== 'inline' && type !== 'tooltip'; const hideActions = type === 'small' || type === 'tooltip'; let name; @@ -90,6 +96,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { } const isChannel = isValid ? parseURI(uri).isChannel : false; + const includeChannelTooltip = type !== 'inline' && type !== 'tooltip' && !isChannel; const signingChannel = claim && claim.signing_channel; let shouldHide = placeholder !== 'loading' && ((abandoned && !showPublishLink) || (!claimIsMine && obscureNsfw && nsfw)); @@ -129,8 +136,10 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { } } - function onClick(e) { - if ((isChannel || title) && !pending) { + function handleOnClick(e) { + if (onClick) { + onClick(e); + } else if ((isChannel || title) && !pending) { history.push(formatLbryUriForWeb(uri)); } } @@ -161,7 +170,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => {
  • ((props: Props, ref: any) => {
    {claim ? : {__('Nothing here')}}
    - {!hideActions && ( + {!hideActions && actions !== undefined ? ( + actions + ) : (
    - {isChannel && !channelIsBlocked && ( + {isChannel && !channelIsBlocked && !claimIsMine && ( )} - {isChannel && !isSubscribed && } + {isChannel && !isSubscribed && !claimIsMine && ( + + )} {!isChannel && claim && }
    )} @@ -219,7 +232,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { )} - + {properties !== undefined ? properties : }
  • diff --git a/src/ui/component/commentCreate/view.jsx b/src/ui/component/commentCreate/view.jsx index acdfe185e2b..2fc32a58460 100644 --- a/src/ui/component/commentCreate/view.jsx +++ b/src/ui/component/commentCreate/view.jsx @@ -5,7 +5,7 @@ import { FormField, Form } from 'component/common/form'; import Button from 'component/button'; import ChannelSection from 'component/selectChannel'; import UnsupportedOnWeb from 'component/common/unsupported-on-web'; -import usePersistedState from 'util/use-persisted-state'; +import usePersistedState from 'effects/use-persisted-state'; type Props = { uri: string, diff --git a/src/ui/component/common/card.jsx b/src/ui/component/common/card.jsx index 586a8746d9f..c10dd747076 100644 --- a/src/ui/component/common/card.jsx +++ b/src/ui/component/common/card.jsx @@ -5,7 +5,7 @@ import classnames from 'classnames'; import Icon from 'component/common/icon'; type Props = { - title: string | Node, + title?: string | Node, subtitle?: string | Node, body?: string | Node, actions?: string | Node, @@ -16,15 +16,17 @@ export default function Card(props: Props) { const { title, subtitle, body, actions, icon } = props; return (
    -
    -
    - {icon && } -
    -

    {title}

    -

    {subtitle}

    + {title && ( +
    +
    + {icon && } +
    +

    {title}

    +

    {subtitle}

    +
    -
    + )} {body &&
    {body}
    } {actions && ( diff --git a/src/ui/component/common/form-components/form-field.jsx b/src/ui/component/common/form-components/form-field.jsx index cc70debf304..9e88871137d 100644 --- a/src/ui/component/common/form-components/form-field.jsx +++ b/src/ui/component/common/form-components/form-field.jsx @@ -104,9 +104,11 @@ export class FormField extends React.PureComponent { input = ( - - - + + + ); diff --git a/src/ui/component/common/icon-custom.jsx b/src/ui/component/common/icon-custom.jsx index 64f90b02193..8b04ec24f30 100644 --- a/src/ui/component/common/icon-custom.jsx +++ b/src/ui/component/common/icon-custom.jsx @@ -303,6 +303,13 @@ export const icons = { ), + [ICONS.SIGN_IN]: buildIcon( + + + + + + ), [ICONS.SIGN_OUT]: buildIcon( diff --git a/src/ui/component/errorBoundary/view.jsx b/src/ui/component/errorBoundary/view.jsx index ef73ff085a1..d48766ed3e9 100644 --- a/src/ui/component/errorBoundary/view.jsx +++ b/src/ui/component/errorBoundary/view.jsx @@ -75,16 +75,14 @@ class ErrorBoundary extends React.Component { title={__('Aw shucks!')} subtitle={ -

    - {__("There was an error. It's been reported and will be fixed")}. {__('Try')}{' '} -

    diff --git a/src/ui/component/inviteNew/view.jsx b/src/ui/component/inviteNew/view.jsx index 93a677168fe..d35dc161610 100644 --- a/src/ui/component/inviteNew/view.jsx +++ b/src/ui/component/inviteNew/view.jsx @@ -77,7 +77,7 @@ class InviteNew extends React.PureComponent { - {!hideSection && ( -
    - updatePublishForm({ language: event.target.value })} - > - - - - - - - - - - - - - - - - - - - - - - - - - - + + {!hideSection && ( +
    + updatePublishForm({ language: event.target.value })} + > + + + + + + + + + + + + + + + + + + + + + + + + + + - - updatePublishForm({ - licenseType: newLicenseType, - licenseUrl: newLicenseUrl, - }) - } - handleLicenseDescriptionChange={event => - updatePublishForm({ - otherLicenseDescription: event.target.value, - }) - } - handleLicenseUrlChange={event => updatePublishForm({ licenseUrl: event.target.value })} - /> -
    - )} + + updatePublishForm({ + licenseType: newLicenseType, + licenseUrl: newLicenseUrl, + }) + } + handleLicenseDescriptionChange={event => + updatePublishForm({ + otherLicenseDescription: event.target.value, + }) + } + handleLicenseUrlChange={event => updatePublishForm({ licenseUrl: event.target.value })} + /> +
    + )} -
    -
    -
    +
    +
    + + } + /> ); } diff --git a/src/ui/component/publishFile/view.jsx b/src/ui/component/publishFile/view.jsx index ba3ce716c0d..0973b5a2e79 100644 --- a/src/ui/component/publishFile/view.jsx +++ b/src/ui/component/publishFile/view.jsx @@ -1,9 +1,10 @@ // @flow +import * as ICONS from 'constants/icons'; import React from 'react'; import { regexInvalidURI } from 'lbry-redux'; -import classnames from 'classnames'; import FileSelector from 'component/common/file-selector'; import Button from 'component/button'; +import Card from 'component/common/card'; type Props = { name: ?string, @@ -11,10 +12,11 @@ type Props = { isStillEditing: boolean, balance: number, updatePublishForm: ({}) => void, + disabled: boolean, }; function PublishFile(props: Props) { - const { name, balance, filePath, isStillEditing, updatePublishForm } = props; + const { name, balance, filePath, isStillEditing, updatePublishForm, disabled } = props; function handleFileChange(filePath: string, fileName: string) { const publishFormParams: { filePath: string, name?: string } = { filePath }; @@ -28,29 +30,28 @@ function PublishFile(props: Props) { } return ( -
    -

    {isStillEditing ? __('Edit') : __('Publish')}

    - {isStillEditing &&

    {__('You are currently editing a claim.')}

    } - -
    - - {!isStillEditing && ( -

    - {__('For video content, use MP4s in H264/AAC format for best compatibility.')}{' '} -

    -
    + + + {!isStillEditing && ( +

    + {__('For video content, use MP4s in H264/AAC format for best compatibility.')}{' '} +