Indicate content eligible for Hot Right Now reward

This commit is contained in:
Alex Liebowitz 2017-07-25 03:07:54 -04:00 committed by Jeremy Kauffman
parent 1f588ff923
commit 230d2a451c
12 changed files with 97 additions and 6 deletions

View file

@ -133,6 +133,34 @@ export function doFetchFeaturedUris() {
}; };
} }
export function doFetchHotRightNowContent() {
return function(dispatch, getState) {
const state = getState();
const success = nameToClaimId => {
dispatch({
type: types.FETCH_HOT_RIGHT_NOW_CONTENT_COMPLETED,
data: {
claimIds: Object.values(nameToClaimId),
success: true,
},
});
};
const failure = () => {
dispatch({
type: types.FETCH_HOT_RIGHT_NOW_CONTENT_COMPLETED,
data: {
claimIds: [],
success: false,
},
});
};
lbryio.call("reward", "list_featured").then(success, failure);
};
}
export function doUpdateLoadStatus(uri, outpoint) { export function doUpdateLoadStatus(uri, outpoint) {
return function(dispatch, getState) { return function(dispatch, getState) {
const state = getState(); const state = getState();

View file

@ -7,6 +7,8 @@ import {
doAlertError, doAlertError,
doRecordScroll, doRecordScroll,
} from "actions/app"; } from "actions/app";
import { doFetchHotRightNowContent } from "actions/content";
import { doUpdateBalance } from "actions/wallet"; import { doUpdateBalance } from "actions/wallet";
import { selectWelcomeModalAcknowledged } from "selectors/app"; import { selectWelcomeModalAcknowledged } from "selectors/app";
import { selectUser } from "selectors/user"; import { selectUser } from "selectors/user";
@ -24,6 +26,7 @@ const perform = dispatch => ({
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()), checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)), openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)),
updateBalance: balance => dispatch(doUpdateBalance(balance)), updateBalance: balance => dispatch(doUpdateBalance(balance)),
fetchHotRightNowContent: () => dispatch(doFetchHotRightNowContent()),
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)), recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
}); });

View file

@ -12,7 +12,12 @@ import * as modals from "constants/modal_types";
class App extends React.PureComponent { class App extends React.PureComponent {
componentWillMount() { componentWillMount() {
const { alertError, checkUpgradeAvailable, updateBalance } = this.props; const {
alertError,
checkUpgradeAvailable,
updateBalance,
fetchHotRightNowContent,
} = this.props;
document.addEventListener("unhandledError", event => { document.addEventListener("unhandledError", event => {
alertError(event.detail); alertError(event.detail);
@ -26,6 +31,8 @@ class App extends React.PureComponent {
updateBalance(balance); updateBalance(balance);
}); });
fetchHotRightNowContent();
this.showWelcome(this.props); this.showWelcome(this.props);
this.scrollListener = () => this.props.recordScroll(window.scrollY); this.scrollListener = () => this.props.recordScroll(window.scrollY);

View file

@ -8,7 +8,10 @@ import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
} from "selectors/claims"; } from "selectors/claims";
import { makeSelectFileInfoForUri } from "selectors/file_info"; import { makeSelectFileInfoForUri } from "selectors/file_info";
import { makeSelectIsResolvingForUri } from "selectors/content"; import {
makeSelectIsResolvingForUri,
selectHotRightNowClaimIds,
} from "selectors/content";
import FileCard from "./view"; import FileCard from "./view";
const makeSelect = () => { const makeSelect = () => {
@ -22,6 +25,7 @@ const makeSelect = () => {
fileInfo: selectFileInfoForUri(state, props), fileInfo: selectFileInfoForUri(state, props),
obscureNsfw: !selectShowNsfw(state), obscureNsfw: !selectShowNsfw(state),
metadata: selectMetadataForUri(state, props), metadata: selectMetadataForUri(state, props),
hotRightNowClaimIds: selectHotRightNowClaimIds(state, props),
isResolvingUri: selectResolvingUri(state, props), isResolvingUri: selectResolvingUri(state, props),
}); });

View file

@ -46,7 +46,14 @@ class FileCard extends React.PureComponent {
} }
render() { render() {
const { claim, fileInfo, metadata, isResolvingUri, navigate } = this.props; const {
claim,
fileInfo,
metadata,
isResolvingUri,
navigate,
hotRightNowClaimIds,
} = this.props;
const uri = lbryuri.normalize(this.props.uri); const uri = lbryuri.normalize(this.props.uri);
const title = metadata && metadata.title ? metadata.title : uri; const title = metadata && metadata.title ? metadata.title : uri;
@ -54,6 +61,7 @@ class FileCard extends React.PureComponent {
? metadata.thumbnail ? metadata.thumbnail
: null; : null;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw; const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isHotRightNow = claim && hotRightNowClaimIds.includes(claim.claim_id);
let description = ""; let description = "";
if (isResolvingUri && !claim) { if (isResolvingUri && !claim) {
@ -83,6 +91,7 @@ class FileCard extends React.PureComponent {
<div className="card__title" title={title}> <div className="card__title" title={title}>
<TruncatedText lines={1}>{title}</TruncatedText> <TruncatedText lines={1}>{title}</TruncatedText>
</div> </div>
{isHotRightNow && <span>&#128293; Hot Right Now</span>}
<div className="card__subtitle"> <div className="card__subtitle">
<span style={{ float: "right" }}> <span style={{ float: "right" }}>
<FilePrice uri={uri} /> <FilePrice uri={uri} />

View file

@ -8,7 +8,10 @@ import {
} from "selectors/claims"; } from "selectors/claims";
import { makeSelectFileInfoForUri } from "selectors/file_info"; import { makeSelectFileInfoForUri } from "selectors/file_info";
import { selectShowNsfw } from "selectors/settings"; import { selectShowNsfw } from "selectors/settings";
import { makeSelectIsResolvingForUri } from "selectors/content"; import {
makeSelectIsResolvingForUri,
selectHotRightNowClaimIds,
} from "selectors/content";
import FileTile from "./view"; import FileTile from "./view";
const makeSelect = () => { const makeSelect = () => {
@ -23,6 +26,7 @@ const makeSelect = () => {
obscureNsfw: !selectShowNsfw(state), obscureNsfw: !selectShowNsfw(state),
metadata: selectMetadataForUri(state, props), metadata: selectMetadataForUri(state, props),
isResolvingUri: selectResolvingUri(state, props), isResolvingUri: selectResolvingUri(state, props),
hotRightNowClaimIds: selectHotRightNowClaimIds(state, props),
}); });
return select; return select;

View file

@ -58,6 +58,7 @@ class FileTile extends React.PureComponent {
showEmpty, showEmpty,
navigate, navigate,
hidePrice, hidePrice,
hotRightNowClaimIds,
} = this.props; } = this.props;
const uri = lbryuri.normalize(this.props.uri); const uri = lbryuri.normalize(this.props.uri);
@ -70,6 +71,8 @@ class FileTile extends React.PureComponent {
? metadata.thumbnail ? metadata.thumbnail
: null; : null;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw; const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isHotRightNow = claim && hotRightNowClaimIds.includes(claim.claim_id);
let onClick = () => navigate("/show", { uri }); let onClick = () => navigate("/show", { uri });
let description = ""; let description = "";
@ -108,6 +111,7 @@ class FileTile extends React.PureComponent {
{!hidePrice ? <FilePrice uri={this.props.uri} /> : null} {!hidePrice ? <FilePrice uri={this.props.uri} /> : null}
<div className="meta">{uri}</div> <div className="meta">{uri}</div>
<h3><TruncatedText lines={1}>{title}</TruncatedText></h3> <h3><TruncatedText lines={1}>{title}</TruncatedText></h3>
{isHotRightNow && <span>&#128293; Hot Right Now</span>}
</div> </div>
<div className="card__content card__subtext"> <div className="card__content card__subtext">
<TruncatedText lines={3}> <TruncatedText lines={3}>

View file

@ -112,3 +112,5 @@ export const CLAIM_REWARD_STARTED = "CLAIM_REWARD_STARTED";
export const CLAIM_REWARD_SUCCESS = "CLAIM_REWARD_SUCCESS"; export const CLAIM_REWARD_SUCCESS = "CLAIM_REWARD_SUCCESS";
export const CLAIM_REWARD_FAILURE = "CLAIM_REWARD_FAILURE"; export const CLAIM_REWARD_FAILURE = "CLAIM_REWARD_FAILURE";
export const CLAIM_REWARD_CLEAR_ERROR = "CLAIM_REWARD_CLEAR_ERROR"; export const CLAIM_REWARD_CLEAR_ERROR = "CLAIM_REWARD_CLEAR_ERROR";
export const FETCH_HOT_RIGHT_NOW_CONTENT_COMPLETED =
"FETCH_HOT_RIGHT_NOW_CONTENT_COMPLETED";

View file

@ -3,6 +3,7 @@ import { connect } from "react-redux";
import { doNavigate } from "actions/app"; import { doNavigate } from "actions/app";
import { doFetchFileInfo } from "actions/file_info"; import { doFetchFileInfo } from "actions/file_info";
import { makeSelectFileInfoForUri } from "selectors/file_info"; import { makeSelectFileInfoForUri } from "selectors/file_info";
import { selectHotRightNowClaimIds } from "selectors/content";
import { doFetchCostInfoForUri } from "actions/cost_info"; import { doFetchCostInfoForUri } from "actions/cost_info";
import { import {
makeSelectClaimForUri, makeSelectClaimForUri,
@ -27,6 +28,7 @@ const makeSelect = () => {
metadata: selectMetadata(state, props), metadata: selectMetadata(state, props),
obscureNsfw: !selectShowNsfw(state), obscureNsfw: !selectShowNsfw(state),
fileInfo: selectFileInfo(state, props), fileInfo: selectFileInfo(state, props),
hotRightNowClaimIds: selectHotRightNowClaimIds(state, props),
}); });
return select; return select;

View file

@ -54,7 +54,14 @@ class FilePage extends React.PureComponent {
} }
render() { render() {
const { claim, fileInfo, metadata, contentType, uri } = this.props; const {
claim,
fileInfo,
metadata,
contentType,
uri,
hotRightNowClaimIds,
} = this.props;
if (!claim || !metadata) { if (!claim || !metadata) {
return ( return (
@ -80,6 +87,7 @@ class FilePage extends React.PureComponent {
? lbryuri.build({ channelName, claimId: channelClaimId }, false) ? lbryuri.build({ channelName, claimId: channelClaimId }, false)
: null; : null;
const uriIndicator = <UriIndicator uri={uri} />; const uriIndicator = <UriIndicator uri={uri} />;
const isHotRightNow = hotRightNowClaimIds.includes(claim.claim_id);
const mediaType = lbry.getMediaType(contentType); const mediaType = lbry.getMediaType(contentType);
const player = require("render-media"); const player = require("render-media");
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw; const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
@ -105,6 +113,7 @@ class FilePage extends React.PureComponent {
</span> </span>
: null} : null}
<h1>{title}</h1> <h1>{title}</h1>
{isHotRightNow && <span>&#128293; Hot Right Now</span>}
<div className="card__subtitle"> <div className="card__subtitle">
{channelUri {channelUri
? <Link ? <Link

View file

@ -1,7 +1,9 @@
import * as types from "constants/action_types"; import * as types from "constants/action_types";
const reducers = {}; const reducers = {};
const defaultState = {}; const defaultState = {
hotRightNowClaimIds: [],
};
reducers[types.FETCH_FEATURED_CONTENT_STARTED] = function(state, action) { reducers[types.FETCH_FEATURED_CONTENT_STARTED] = function(state, action) {
return Object.assign({}, state, { return Object.assign({}, state, {
@ -19,6 +21,18 @@ reducers[types.FETCH_FEATURED_CONTENT_COMPLETED] = function(state, action) {
}); });
}; };
reducers[types.FETCH_HOT_RIGHT_NOW_CONTENT_COMPLETED] = function(
state,
action
) {
const { claimIds, success } = action.data;
return Object.assign({}, state, {
hotRightNowClaimIds: claimIds,
fetchingHotRightNowContentFailed: !success,
});
};
reducers[types.RESOLVE_URI_STARTED] = function(state, action) { reducers[types.RESOLVE_URI_STARTED] = function(state, action) {
const { uri } = action.data; const { uri } = action.data;

View file

@ -37,3 +37,8 @@ const selectTotalPagesForChannel = (state, props) => {
export const makeSelectTotalPagesForChannel = () => { export const makeSelectTotalPagesForChannel = () => {
return createSelector(selectTotalPagesForChannel, totalPages => totalPages); return createSelector(selectTotalPagesForChannel, totalPages => totalPages);
}; };
export const selectHotRightNowClaimIds = createSelector(
_selectState,
state => state.hotRightNowClaimIds
);