From 919f82ba9428dc2f3ba14f889f310eda81f3dff0 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Mon, 11 May 2020 11:54:39 -0400 Subject: [PATCH] purchases page, cleanup on pages with --- package.json | 2 +- ui/component/claimList/view.jsx | 5 +- ui/component/claimListDiscover/view.jsx | 49 +++++---- ui/component/claimPreview/index.js | 2 + ui/component/claimTags/view.jsx | 2 +- ui/component/common/credit-amount.jsx | 18 +++- ui/component/common/icon-custom.jsx | 5 + ui/component/filePrice/view.jsx | 4 +- ui/component/fileProperties/index.js | 8 +- ui/component/fileProperties/view.jsx | 24 +++-- ui/component/router/view.jsx | 2 - ui/constants/claim.js | 2 +- ui/constants/icons.js | 1 + ui/constants/pages.js | 1 - ui/modal/modalAffirmPurchase/view.jsx | 40 ++++--- ui/page/channelsFollowing/view.jsx | 4 +- ui/page/fileListDownloaded/index.js | 29 +++-- ui/page/fileListDownloaded/view.jsx | 137 ++++++++++++++++-------- ui/page/fileListPublished/index.js | 4 +- ui/page/library/index.js | 16 ++- ui/page/library/view.jsx | 37 ++++++- ui/page/tagsFollowing/view.jsx | 2 +- ui/redux/selectors/content.js | 3 +- ui/scss/component/_button.scss | 18 +++- ui/scss/component/_claim-search.scss | 12 +-- ui/scss/component/_file-properties.scss | 58 +++++++++- ui/scss/component/_form-field.scss | 4 + ui/scss/component/_pagination.scss | 6 ++ ui/scss/init/_gui.scss | 3 +- ui/scss/themes/dark.scss | 3 + ui/scss/themes/light.scss | 3 + yarn.lock | 4 +- 32 files changed, 366 insertions(+), 142 deletions(-) diff --git a/package.json b/package.json index c0824c397..e7c692e3d 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "imagesloaded": "^4.1.4", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#259317250af62391718ac0cb8b8e25f172dc4223", + "lbry-redux": "lbryio/lbry-redux#cd9c15567f2934ddc82de364d88b378ff04d5571", "lbryinc": "lbryio/lbryinc#cc62a4eec10845cc0b31da7d0f27287cfa7c4866", "lint-staged": "^7.0.2", "localforage": "^1.7.1", diff --git a/ui/component/claimList/view.jsx b/ui/component/claimList/view.jsx index 57b0c5674..4503c4618 100644 --- a/ui/component/claimList/view.jsx +++ b/ui/component/claimList/view.jsx @@ -26,7 +26,6 @@ type Props = { // If using the default header, this is a unique ID needed to persist the state of the filter setting persistedStorageKey?: string, showHiddenByUser: boolean, - headerLabel?: string | Node, showUnresolvedClaims?: boolean, renderProperties: ?(Claim) => Node, includeSupportAction?: boolean, @@ -51,7 +50,6 @@ export default function ClaimList(props: Props) { page, id, showHiddenByUser, - headerLabel, showUnresolvedClaims, renderProperties, includeSupportAction, @@ -105,12 +103,10 @@ export default function ClaimList(props: Props) {
{header !== false && ( - {headerLabel && } {header && (
{header} @@ -139,6 +135,7 @@ export default function ClaimList(props: Props) {
    {sortedUris.map((uri, index) => ( diff --git a/ui/component/claimListDiscover/view.jsx b/ui/component/claimListDiscover/view.jsx index f610187de..8ac3dbeb4 100644 --- a/ui/component/claimListDiscover/view.jsx +++ b/ui/component/claimListDiscover/view.jsx @@ -13,6 +13,7 @@ import ClaimPreview from 'component/claimPreview'; import { toCapitalCase } from 'util/string'; import I18nMessage from 'component/i18nMessage'; import * as ICONS from 'constants/icons'; +import Card from 'component/common/card'; type Props = { uris: Array, @@ -595,30 +596,32 @@ function ClaimListDiscover(props: Props) { return ( - {headerLabel}} + {meta}
} + isBodyList + body={ + <> + + {loading && + new Array(pageSize || CS.PAGE_SIZE).fill(1).map((x, i) => )} + + } /> - - {loading && ( -
- {new Array(pageSize || CS.PAGE_SIZE).fill(1).map((x, i) => ( - - ))} -
- )}
); } diff --git a/ui/component/claimPreview/index.js b/ui/component/claimPreview/index.js index f2eefe804..32b8dc4b2 100644 --- a/ui/component/claimPreview/index.js +++ b/ui/component/claimPreview/index.js @@ -12,6 +12,7 @@ import { selectChannelIsBlocked, doFileGet, makeSelectReflectingClaimForUri, + makeSelectClaimWasPurchased, } from 'lbry-redux'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; import { selectShowMatureContent } from 'redux/selectors/settings'; @@ -36,6 +37,7 @@ const select = (state, props) => ({ channelIsBlocked: props.uri && selectChannelIsBlocked(props.uri)(state), isSubscribed: props.uri && makeSelectIsSubscribed(props.uri, true)(state), streamingUrl: props.uri && makeSelectStreamingUrlForUriWebProxy(props.uri)(state), + wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state), }); const perform = dispatch => ({ diff --git a/ui/component/claimTags/view.jsx b/ui/component/claimTags/view.jsx index af92dec5f..e55413e7a 100644 --- a/ui/component/claimTags/view.jsx +++ b/ui/component/claimTags/view.jsx @@ -52,7 +52,7 @@ export default function ClaimTags(props: Props) { } return ( -
+
{tagsToDisplay.map(tag => ( ))} diff --git a/ui/component/common/credit-amount.jsx b/ui/component/common/credit-amount.jsx index 4e95352d4..83b7db7ed 100644 --- a/ui/component/common/credit-amount.jsx +++ b/ui/component/common/credit-amount.jsx @@ -13,6 +13,7 @@ type Props = { showLBC?: boolean, fee?: boolean, badge?: boolean, + className?: string, }; class CreditAmount extends React.PureComponent { @@ -26,7 +27,18 @@ class CreditAmount extends React.PureComponent { }; render() { - const { amount, precision, showFullPrice, showFree, showPlus, isEstimate, fee, showLBC, badge } = this.props; + const { + amount, + precision, + showFullPrice, + showFree, + showPlus, + isEstimate, + fee, + showLBC, + badge, + className, + } = this.props; const minimumRenderableAmount = 10 ** (-1 * precision); const fullPrice = formatFullPrice(amount, 2); @@ -64,13 +76,13 @@ class CreditAmount extends React.PureComponent { return ( 0, 'badge--free': badge && isFree, })} > - {amountText} + {amountText} {isEstimate ? ( diff --git a/ui/component/common/icon-custom.jsx b/ui/component/common/icon-custom.jsx index 80f7c81fc..59fc4cac0 100644 --- a/ui/component/common/icon-custom.jsx +++ b/ui/component/common/icon-custom.jsx @@ -618,4 +618,9 @@ export const icons = { viewBox: '0 0 60 60', } ), + [ICONS.PURCHASED]: buildIcon( + + + + ), }; diff --git a/ui/component/filePrice/view.jsx b/ui/component/filePrice/view.jsx index e19b8168b..ecdb6add4 100644 --- a/ui/component/filePrice/view.jsx +++ b/ui/component/filePrice/view.jsx @@ -14,6 +14,7 @@ type Props = { inheritStyle?: boolean, showLBC?: boolean, hideFree?: boolean, // hide the file price if it's free + className?: string, }; class FilePrice extends React.PureComponent { @@ -38,7 +39,7 @@ class FilePrice extends React.PureComponent { }; render() { - const { costInfo, showFullPrice, badge, inheritStyle, showLBC, hideFree } = this.props; + const { costInfo, showFullPrice, badge, inheritStyle, showLBC, hideFree, className } = this.props; if (costInfo && (!costInfo.cost || (!costInfo.cost && hideFree))) { return null; } @@ -52,6 +53,7 @@ class FilePrice extends React.PureComponent { amount={costInfo.cost} isEstimate={!costInfo.includesData} showFullPrice={showFullPrice} + className={className} /> ) : null; } diff --git a/ui/component/fileProperties/index.js b/ui/component/fileProperties/index.js index 0d5a0c0dd..2ec0f4f8e 100644 --- a/ui/component/fileProperties/index.js +++ b/ui/component/fileProperties/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectFilePartlyDownloaded, makeSelectClaimIsMine } from 'lbry-redux'; +import { makeSelectFilePartlyDownloaded, makeSelectClaimIsMine, makeSelectClaimWasPurchased } from 'lbry-redux'; import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions'; import FileProperties from './view'; @@ -8,9 +8,7 @@ const select = (state, props) => ({ isSubscribed: makeSelectIsSubscribed(props.uri)(state), isNew: makeSelectIsNew(props.uri)(state), claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), }); -export default connect( - select, - null -)(FileProperties); +export default connect(select, null)(FileProperties); diff --git a/ui/component/fileProperties/view.jsx b/ui/component/fileProperties/view.jsx index 23892471d..3c3796645 100644 --- a/ui/component/fileProperties/view.jsx +++ b/ui/component/fileProperties/view.jsx @@ -1,5 +1,5 @@ // @flow -import * as icons from 'constants/icons'; +import * as ICONS from 'constants/icons'; import * as React from 'react'; import classnames from 'classnames'; import Icon from 'component/common/icon'; @@ -14,18 +14,28 @@ type Props = { isSubscribed: boolean, isNew: boolean, small: boolean, + claimWasPurchased: boolean, }; export default function FileProperties(props: Props) { - const { uri, downloaded, claimIsMine, isSubscribed, small = false } = props; - + const { uri, downloaded, claimIsMine, claimWasPurchased, isSubscribed, small = false } = props; return ( -
- +
- {isSubscribed && } - {!claimIsMine && downloaded && } + {isSubscribed && } + {!claimIsMine && downloaded && } + {claimWasPurchased ? ( + + + + ) : ( + + )}
); } diff --git a/ui/component/router/view.jsx b/ui/component/router/view.jsx index b00102d75..03da65f1e 100644 --- a/ui/component/router/view.jsx +++ b/ui/component/router/view.jsx @@ -14,7 +14,6 @@ import DiscoverPage from 'page/discover'; import HomePage from 'page/home'; import InvitedPage from 'page/invited'; import RewardsPage from 'page/rewards'; -import FileListDownloaded from 'page/fileListDownloaded'; import FileListPublished from 'page/fileListPublished'; import InvitePage from 'page/invite'; import SearchPage from 'page/search'; @@ -177,7 +176,6 @@ function AppRouter(props: Props) { - diff --git a/ui/constants/claim.js b/ui/constants/claim.js index 516edc8dc..d6486d553 100644 --- a/ui/constants/claim.js +++ b/ui/constants/claim.js @@ -3,7 +3,7 @@ export const MINIMUM_PUBLISH_BID = 0.00001; export const CHANNEL_ANONYMOUS = 'anonymous'; export const CHANNEL_NEW = 'new'; export const PAGE_SIZE = 20; -export const PUBLISHES_PAGE_SIZE = 10; +export const MY_CLAIMS_PAGE_SIZE = 10; export const PAGE_PARAM = 'page'; export const PAGE_SIZE_PARAM = 'page_size'; diff --git a/ui/constants/icons.js b/ui/constants/icons.js index d83f9ea57..8ab697305 100644 --- a/ui/constants/icons.js +++ b/ui/constants/icons.js @@ -99,3 +99,4 @@ export const VALIDATED = 'Check'; export const SLIDERS = 'Sliders'; export const SCIENCE = 'Science'; export const ANALYTICS = 'BarChart2'; +export const PURCHASED = 'Key'; diff --git a/ui/constants/pages.js b/ui/constants/pages.js index 7d553830c..5e646c0b8 100644 --- a/ui/constants/pages.js +++ b/ui/constants/pages.js @@ -6,7 +6,6 @@ exports.BACKUP = 'backup'; exports.CHANNEL = 'channel'; exports.DISCOVER = 'discover'; exports.HOME = 'home'; -exports.DOWNLOADED = 'downloaded'; exports.HELP = 'help'; exports.LIBRARY = 'library'; exports.INVITE = 'invite'; diff --git a/ui/modal/modalAffirmPurchase/view.jsx b/ui/modal/modalAffirmPurchase/view.jsx index cedf86d44..13507f9d7 100644 --- a/ui/modal/modalAffirmPurchase/view.jsx +++ b/ui/modal/modalAffirmPurchase/view.jsx @@ -2,6 +2,9 @@ import React from 'react'; import FilePrice from 'component/filePrice'; import { Modal } from 'modal/modal'; +import Card from 'component/common/card'; +import I18nMessage from 'component/i18nMessage'; +import Button from 'component/button'; type Props = { closeModal: () => void, @@ -30,22 +33,29 @@ class ModalAffirmPurchase extends React.PureComponent { uri, } = this.props; + const modalTitle = __('Confirm Purchase'); + return ( - -

- {__('This will purchase')} {title ? `"${title}"` : uri} {__('for')}{' '} - - - {' '} - {__('credits')}. -

+ + {title ? `"${title}"` : uri}, + amount: , + }} + > + This will purchase %claim_title% for %amount%. + + } + actions={ +
+
+ } + />
); } diff --git a/ui/page/channelsFollowing/view.jsx b/ui/page/channelsFollowing/view.jsx index 4d82d232a..38e3e682b 100644 --- a/ui/page/channelsFollowing/view.jsx +++ b/ui/page/channelsFollowing/view.jsx @@ -33,8 +33,8 @@ function ChannelsFollowingPage(props: Props) { meta={
-
- )} - + } + titleActions={ +
+
{}} className="wunderbar--inline"> + + + +
+ } + isBodyList + body={ +
+ null} + empty={ + viewMode === VIEW_PURCHASES && !query ? ( +
{__("You haven't purchased anything yet silly goose.")}
+ ) : ( + __('No results for %query%', { query }) + ) + } + uris={viewMode === VIEW_PURCHASES ? myPurchases : myDownloads} + loading={loading} + /> + {!query && ( + + )} +
+ } + /> ); } diff --git a/ui/page/fileListPublished/index.js b/ui/page/fileListPublished/index.js index 5236dc835..cc709d825 100644 --- a/ui/page/fileListPublished/index.js +++ b/ui/page/fileListPublished/index.js @@ -11,13 +11,13 @@ import { selectUploadCount } from 'lbryinc'; import { doCheckPendingPublishesApp } from 'redux/actions/publish'; import FileListPublished from './view'; import { withRouter } from 'react-router'; -import { PUBLISHES_PAGE_SIZE, PAGE_PARAM, PAGE_SIZE_PARAM } from 'constants/claim'; +import { MY_CLAIMS_PAGE_SIZE, PAGE_PARAM, PAGE_SIZE_PARAM } from 'constants/claim'; const select = (state, props) => { const { search } = props.location; const urlParams = new URLSearchParams(search); const page = Number(urlParams.get(PAGE_PARAM)) || '1'; - const pageSize = urlParams.get(PAGE_SIZE_PARAM) || String(PUBLISHES_PAGE_SIZE); + const pageSize = urlParams.get(PAGE_SIZE_PARAM) || String(MY_CLAIMS_PAGE_SIZE); return { page, diff --git a/ui/page/library/index.js b/ui/page/library/index.js index abb82e5be..48ade6b14 100644 --- a/ui/page/library/index.js +++ b/ui/page/library/index.js @@ -1,3 +1,17 @@ +import { connect } from 'react-redux'; +import { + selectDownloadUrlsCount, + selectIsFetchingFileList, + selectMyPurchases, + selectIsFetchingMyPurchases, +} from 'lbry-redux'; import LibraryPage from './view'; -export default LibraryPage; +const select = state => ({ + allDownloadedUrlsCount: selectDownloadUrlsCount(state), + fetchingFileList: selectIsFetchingFileList(state), + myPurchases: selectMyPurchases(state), + fetchingMyPurchases: selectIsFetchingMyPurchases(state), +}); + +export default connect(select)(LibraryPage); diff --git a/ui/page/library/view.jsx b/ui/page/library/view.jsx index 71bb0bfac..29e944d3d 100644 --- a/ui/page/library/view.jsx +++ b/ui/page/library/view.jsx @@ -1,12 +1,45 @@ // @flow import React from 'react'; +import Button from 'component/button'; import Page from 'component/page'; +import Spinner from 'component/spinner'; import DownloadList from 'page/fileListDownloaded'; +import Yrbl from 'component/yrbl'; + +type Props = { + allDownloadedUrlsCount: number, + myPurchases: Array, + fetchingMyPurchases: boolean, + fetchingFileList: boolean, +}; + +function LibraryPage(props: Props) { + const { allDownloadedUrlsCount, myPurchases, fetchingMyPurchases, fetchingFileList } = props; + const hasDownloads = allDownloadedUrlsCount > 0 || (myPurchases && myPurchases.length); + const loading = fetchingFileList || fetchingMyPurchases; -function LibraryPage() { return ( - + {loading && !hasDownloads && ( +
+ +
+ )} + + {!loading && !hasDownloads && ( +
+ +
+ } + /> + + )} + + {hasDownloads && }
); } diff --git a/ui/page/tagsFollowing/view.jsx b/ui/page/tagsFollowing/view.jsx index 390edd7c9..d6eb55ae7 100644 --- a/ui/page/tagsFollowing/view.jsx +++ b/ui/page/tagsFollowing/view.jsx @@ -22,7 +22,7 @@ function DiscoverPage() { defaultTags={CS.TAGS_FOLLOWED} meta={