From ecd2063fed856bfff8df96768b5b136c925afb09 Mon Sep 17 00:00:00 2001
From: 6ea86b96 <6ea86b96@gmail.com>
Date: Sun, 23 Apr 2017 16:56:50 +0700
Subject: [PATCH] Progress on featured content
---
ui/js/actions/content.js | 29 ++++
ui/js/app.js | 2 +-
ui/js/component/auth.js | 2 +-
ui/js/component/fileTile/index.js | 13 ++
.../{file-tile.js => fileTile/view.jsx} | 14 +-
ui/js/component/fileTileStream/index.js | 13 ++
ui/js/component/fileTileStream/view.jsx | 129 +++++++++++++++++
ui/js/component/header/view.jsx | 4 +-
ui/js/component/router/view.jsx | 4 +-
ui/js/component/video/index.js | 42 ++++++
ui/js/component/video/view.jsx | 130 ++++++++++++++++++
ui/js/constants/action_types.js | 4 +
ui/js/page/discover/index.js | 17 +++
ui/js/page/{discover.js => discover/view.jsx} | 35 +++--
ui/js/page/file-list.js | 17 ++-
ui/js/page/reward.js | 2 +-
ui/js/page/rewards.js | 2 +-
ui/js/page/search.js | 2 +-
ui/js/page/settings.js | 2 +-
ui/js/page/show.js | 2 +-
ui/js/reducers/content.js | 31 +++++
ui/js/selectors/content.js | 37 +++++
ui/js/store.js | 2 +
ui/js/triggers.js | 11 ++
24 files changed, 500 insertions(+), 46 deletions(-)
create mode 100644 ui/js/actions/content.js
create mode 100644 ui/js/component/fileTile/index.js
rename ui/js/component/{file-tile.js => fileTile/view.jsx} (96%)
create mode 100644 ui/js/component/fileTileStream/index.js
create mode 100644 ui/js/component/fileTileStream/view.jsx
create mode 100644 ui/js/component/video/index.js
create mode 100644 ui/js/component/video/view.jsx
create mode 100644 ui/js/page/discover/index.js
rename ui/js/page/{discover.js => discover/view.jsx} (64%)
create mode 100644 ui/js/reducers/content.js
create mode 100644 ui/js/selectors/content.js
diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js
new file mode 100644
index 000000000..a4e582ffe
--- /dev/null
+++ b/ui/js/actions/content.js
@@ -0,0 +1,29 @@
+import * as types from 'constants/action_types'
+import lbry from 'lbry'
+import lbryio from 'lbryio';
+
+export function doFetchFeaturedContent() {
+ return function(dispatch, getState) {
+ const state = getState()
+
+ dispatch({
+ type: types.FETCH_FEATURED_CONTENT_STARTED,
+ })
+
+ const success = ({ Categories, Uris }) => {
+ dispatch({
+ type: types.FETCH_FEATURED_CONTENT_COMPLETED,
+ data: {
+ categories: Categories,
+ uris: Uris,
+ }
+ })
+ }
+
+ const failure = () => {
+ }
+
+ lbryio.call('discover', 'list', { version: "early-access" } )
+ .then(success, failure)
+ }
+}
diff --git a/ui/js/app.js b/ui/js/app.js
index a7c7dd188..88ad0eef8 100644
--- a/ui/js/app.js
+++ b/ui/js/app.js
@@ -38,7 +38,7 @@ module.exports = app;
// import {FileListDownloaded, FileListPublished} from './page/file-list.js';
// import Header from './component/header.js';
// import {Modal, ExpandableModal} from './component/modal.js';
-// import {Link} from './component/link.js';
+// import {Link} from './component/link';
//
//
// const {remote, ipcRenderer, shell} = require('electron');
diff --git a/ui/js/component/auth.js b/ui/js/component/auth.js
index dc36367be..2575d2e9c 100644
--- a/ui/js/component/auth.js
+++ b/ui/js/component/auth.js
@@ -2,7 +2,7 @@ import React from "react";
import lbryio from "../lbryio.js";
import Modal from "./modal.js";
import ModalPage from "./modal-page.js";
-import {Link, RewardLink} from "../component/link.js";
+import {Link, RewardLink} from "../component/link";
import {FormRow} from "../component/form.js";
import {CreditAmount, Address} from "../component/common.js";
import {getLocal, getSession, setSession, setLocal} from '../utils.js';
diff --git a/ui/js/component/fileTile/index.js b/ui/js/component/fileTile/index.js
new file mode 100644
index 000000000..b410bc9c2
--- /dev/null
+++ b/ui/js/component/fileTile/index.js
@@ -0,0 +1,13 @@
+import React from 'react'
+import {
+ connect
+} from 'react-redux'
+import FileTile from './view'
+
+const select = (state) => ({
+})
+
+const perform = (dispatch) => ({
+})
+
+export default connect(select, perform)(FileTile)
diff --git a/ui/js/component/file-tile.js b/ui/js/component/fileTile/view.jsx
similarity index 96%
rename from ui/js/component/file-tile.js
rename to ui/js/component/fileTile/view.jsx
index ae8e0e3fe..b85b0ec6a 100644
--- a/ui/js/component/file-tile.js
+++ b/ui/js/component/fileTile/view.jsx
@@ -1,10 +1,10 @@
import React from 'react';
-import lbry from '../lbry.js';
-import lbryuri from '../lbryuri.js';
+import lbry from 'lbry.js';
+import lbryuri from 'lbryuri.js';
import Link from 'component/link';
-import {FileActions} from '../component/file-actions.js';
-import {BusyMessage, TruncatedText, FilePrice} from '../component/common.js';
-import UriIndicator from '../component/channel-indicator.js';
+import {FileActions} from 'component/file-actions.js';
+import {Thumbnail, TruncatedText, FilePrice} from 'component/common.js';
+import UriIndicator from 'component/channel-indicator.js';
/*should be merged into FileTile once FileTile is refactored to take a single id*/
export let FileTileStream = React.createClass({
@@ -217,7 +217,7 @@ export let FileCardStream = React.createClass({
}
});
-export let FileTile = React.createClass({
+let FileTile = React.createClass({
_isMounted: false,
_isResolvePending: false,
@@ -281,4 +281,4 @@ export let FileTile = React.createClass({
;
}
-});
+});
\ No newline at end of file
diff --git a/ui/js/component/fileTileStream/index.js b/ui/js/component/fileTileStream/index.js
new file mode 100644
index 000000000..b1536b363
--- /dev/null
+++ b/ui/js/component/fileTileStream/index.js
@@ -0,0 +1,13 @@
+import React from 'react'
+import {
+ connect
+} from 'react-redux'
+import FileTileStream from './view'
+
+const select = (state) => ({
+})
+
+const perform = (dispatch) => ({
+})
+
+export default connect(select, perform)(FileTileStream)
diff --git a/ui/js/component/fileTileStream/view.jsx b/ui/js/component/fileTileStream/view.jsx
new file mode 100644
index 000000000..d9c851352
--- /dev/null
+++ b/ui/js/component/fileTileStream/view.jsx
@@ -0,0 +1,129 @@
+import React from 'react';
+import lbry from 'lbry.js';
+import lbryuri from 'lbryuri.js';
+import Link from 'component/link';
+import {
+ FileActions
+} from 'component/file-actions.js';
+import {Thumbnail, TruncatedText, FilePrice} from 'component/common.js';
+import UriIndicator from 'component/channel-indicator.js';
+
+/*should be merged into FileTile once FileTile is refactored to take a single id*/
+const FileTileStream = React.createClass({
+ _fileInfoSubscribeId: null,
+ _isMounted: null,
+
+ propTypes: {
+ uri: React.PropTypes.string,
+ metadata: React.PropTypes.object,
+ contentType: React.PropTypes.string.isRequired,
+ outpoint: React.PropTypes.string,
+ hasSignature: React.PropTypes.bool,
+ signatureIsValid: React.PropTypes.bool,
+ hideOnRemove: React.PropTypes.bool,
+ hidePrice: React.PropTypes.bool,
+ obscureNsfw: React.PropTypes.bool
+ },
+ getInitialState: function() {
+ return {
+ showNsfwHelp: false,
+ isHidden: false,
+ }
+ },
+ getDefaultProps: function() {
+ return {
+ obscureNsfw: !lbry.getClientSetting('showNsfw'),
+ hidePrice: false,
+ hasSignature: false,
+ }
+ },
+ componentDidMount: function() {
+ this._isMounted = true;
+ if (this.props.hideOnRemove) {
+ this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
+ }
+ },
+ componentWillUnmount: function() {
+ if (this._fileInfoSubscribeId) {
+ lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
+ }
+ },
+ onFileInfoUpdate: function(fileInfo) {
+ if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
+ this.setState({
+ isHidden: true
+ });
+ }
+ },
+ handleMouseOver: function() {
+ if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) {
+ this.setState({
+ showNsfwHelp: true,
+ });
+ }
+ },
+ handleMouseOut: function() {
+ if (this.state.showNsfwHelp) {
+ this.setState({
+ showNsfwHelp: false,
+ });
+ }
+ },
+ render: function() {
+ if (this.state.isHidden) {
+ return null;
+ }
+
+ const uri = lbryuri.normalize(this.props.uri);
+ const metadata = this.props.metadata;
+ const isConfirmed = !!metadata;
+ const title = isConfirmed ? metadata.title : uri;
+ const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
+ return (
+
+
+
+
+
+ { !this.props.hidePrice
+ ?
+ : null}
+
+
+
+
+
+
+
+
+
+ {isConfirmed
+ ? metadata.description
+ : This file is pending confirmation.}
+
+
+
+
+
+ {this.state.showNsfwHelp
+ ?
+
+ This content is Not Safe For Work.
+ To view adult content, please change your .
+
+
+ : null}
+
+ );
+ }
+});
+
+export default FileTileStream
diff --git a/ui/js/component/header/view.jsx b/ui/js/component/header/view.jsx
index 34627e14a..e54bf3751 100644
--- a/ui/js/component/header/view.jsx
+++ b/ui/js/component/header/view.jsx
@@ -1,6 +1,6 @@
import React from 'react';
-import lbryuri from '../lbryuri.js';
-import {Icon, CreditAmount} from './common.js';
+import lbryuri from 'lbryuri.js';
+import {Icon, CreditAmount} from 'component/common.js';
import Link from 'component/link';
let Header = React.createClass({
diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx
index 208bb3f6d..9f553c9b7 100644
--- a/ui/js/component/router/view.jsx
+++ b/ui/js/component/router/view.jsx
@@ -1,13 +1,12 @@
import React from 'react';
import SettingsPage from 'page/settings.js';
import HelpPage from 'page/help';
-import WatchPage from 'page/watch.js';
import ReportPage from 'page/report.js';
import StartPage from 'page/start.js';
import WalletPage from 'page/wallet';
import DetailPage from 'page/show.js';
import PublishPage from 'page/publish.js';
-import DiscoverPage from 'page/discover.js';
+import DiscoverPage from 'page/discover';
import SplashScreen from 'component/splash.js';
import DeveloperPage from 'page/developer.js';
import {
@@ -30,7 +29,6 @@ const Router = (props) => {
return route(currentPage, {
'settings': ,
'help': ,
- 'watch': ,
'report': ,
'downloaded': ,
'published': ,
diff --git a/ui/js/component/video/index.js b/ui/js/component/video/index.js
new file mode 100644
index 000000000..94978f702
--- /dev/null
+++ b/ui/js/component/video/index.js
@@ -0,0 +1,42 @@
+import React from 'react'
+import {
+ connect,
+} from 'react-redux'
+import {
+ doCloseModal,
+} from 'actions/app'
+import {
+ selectCurrentModal,
+} from 'selectors/app'
+import {
+ doWatchVideo,
+ doLoadVideo,
+} from 'actions/content'
+import {
+ selectLoadingCurrentUri,
+ selectCurrentUriFileReadyToPlay,
+ selectCurrentUriIsPlaying,
+ selectCurrentUriFileInfo,
+ selectDownloadingCurrentUri,
+} from 'selectors/file_info'
+import {
+ selectCurrentUriCostInfo,
+} from 'selectors/cost_info'
+import Video from './view'
+
+const select = (state) => ({
+ costInfo: selectCurrentUriCostInfo(state),
+ fileInfo: selectCurrentUriFileInfo(state),
+ modal: selectCurrentModal(state),
+ isLoading: selectLoadingCurrentUri(state),
+ readyToPlay: selectCurrentUriFileReadyToPlay(state),
+ isDownloading: selectDownloadingCurrentUri(state),
+})
+
+const perform = (dispatch) => ({
+ loadVideo: () => dispatch(doLoadVideo()),
+ watchVideo: (elem) => dispatch(doWatchVideo()),
+ closeModal: () => dispatch(doCloseModal()),
+})
+
+export default connect(select, perform)(Video)
\ No newline at end of file
diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx
new file mode 100644
index 000000000..86d9a99ea
--- /dev/null
+++ b/ui/js/component/video/view.jsx
@@ -0,0 +1,130 @@
+import React from 'react';
+import {
+ Icon,
+ Thumbnail,
+} from 'component/common';
+import FilePrice from 'component/filePrice'
+import Link from 'component/link';
+import Modal from 'component/modal';
+
+const plyr = require('plyr')
+
+class Video extends React.Component {
+ constructor(props) {
+ super(props)
+
+ // TODO none of this mouse handling stuff seems to actually do anything?
+ this._controlsHideDelay = 3000 // Note: this needs to be shorter than the built-in delay in Electron, or Electron will hide the controls before us
+ this._controlsHideTimeout = null
+ this.state = {}
+ }
+ handleMouseMove() {
+ if (this._controlsTimeout) {
+ clearTimeout(this._controlsTimeout);
+ }
+
+ if (!this.state.controlsShown) {
+ this.setState({
+ controlsShown: true,
+ });
+ }
+ this._controlsTimeout = setTimeout(() => {
+ if (!this.isMounted) {
+ return;
+ }
+
+ this.setState({
+ controlsShown: false,
+ });
+ }, this._controlsHideDelay);
+ }
+
+ handleMouseLeave() {
+ if (this._controlsTimeout) {
+ clearTimeout(this._controlsTimeout);
+ }
+
+ if (this.state.controlsShown) {
+ this.setState({
+ controlsShown: false,
+ });
+ }
+ }
+
+ onWatchClick() {
+ this.props.watchVideo().then(() => {
+ if (!this.props.modal) {
+ this.setState({
+ isPlaying: true
+ })
+ }
+ })
+ }
+
+ startPlaying() {
+ this.setState({
+ isPlaying: true
+ })
+ }
+
+ render() {
+ const {
+ readyToPlay = false,
+ thumbnail,
+ metadata,
+ isLoading,
+ isDownloading,
+ fileInfo,
+ } = this.props
+ const {
+ isPlaying = false,
+ } = this.state
+
+ let loadStatusMessage = ''
+
+ if (isLoading) {
+ loadStatusMessage = "Requesting stream... it may sit here for like 15-20 seconds in a really awkward way... we're working on it"
+ } else if (isDownloading) {
+ loadStatusMessage = "Downloading stream... not long left now!"
+ }
+
+ return (
+
{
+ isPlaying ?
+ !readyToPlay ?
+
this is the world's worst loading screen and we shipped our software with it anyway...
{loadStatusMessage} :
+
:
+
+
+
+ }
+ );
+ }
+}
+
+class VideoPlayer extends React.PureComponent {
+ componentDidMount() {
+ const elem = this.refs.video
+ const {
+ downloadPath,
+ contentType,
+ } = this.props
+ const players = plyr.setup(elem)
+ players[0].play()
+ }
+
+ render() {
+ const {
+ downloadPath,
+ contentType,
+ } = this.props
+
+ return (
+
+ )
+ }
+}
+
+export default Video
\ No newline at end of file
diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js
index a17303b86..e0fae5d24 100644
--- a/ui/js/constants/action_types.js
+++ b/ui/js/constants/action_types.js
@@ -33,3 +33,7 @@ export const SET_DRAFT_TRANSACTION_ADDRESS = 'SET_DRAFT_TRANSACTION_ADDRESS'
export const SEND_TRANSACTION_STARTED = 'SEND_TRANSACTION_STARTED'
export const SEND_TRANSACTION_COMPLETED = 'SEND_TRANSACTION_COMPLETED'
export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED'
+
+// Content
+export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED'
+export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED'
diff --git a/ui/js/page/discover/index.js b/ui/js/page/discover/index.js
new file mode 100644
index 000000000..cdea28f62
--- /dev/null
+++ b/ui/js/page/discover/index.js
@@ -0,0 +1,17 @@
+import React from 'react'
+import {
+ connect
+} from 'react-redux'
+import {
+ selectFeaturedContentByCategory
+} from 'selectors/content'
+import DiscoverPage from './view'
+
+const select = (state) => ({
+ featuredContentByCategory: selectFeaturedContentByCategory(state),
+})
+
+const perform = (dispatch) => ({
+})
+
+export default connect(select, perform)(DiscoverPage)
diff --git a/ui/js/page/discover.js b/ui/js/page/discover/view.jsx
similarity index 64%
rename from ui/js/page/discover.js
rename to ui/js/page/discover/view.jsx
index 912a38f8c..a8ad512b7 100644
--- a/ui/js/page/discover.js
+++ b/ui/js/page/discover/view.jsx
@@ -1,27 +1,26 @@
import React from 'react';
-import lbry from '../lbry.js';
-import lighthouse from '../lighthouse.js';
-import {FileTile} from '../component/file-tile.js';
-import Link from 'component/link';
-import {ToolTip} from '../component/tooltip.js';
+import lbryio from 'lbryio.js';
+import FileTile from 'component/fileTile';
+import { FileTileStream } from 'component/fileTileStream'
+import {ToolTip} from 'component/tooltip.js';
const communityCategoryToolTipText = ('Community Content is a public space where anyone can share content with the ' +
'rest of the LBRY community. Bid on the names "one," "two," "three," "four" and ' +
'"five" to put your content here!');
-let FeaturedCategory = React.createClass({
- render: function() {
- return (
- { this.props.category ?
-
{this.props.category}
- { this.props.category.match(/^community/i) ?
-
- : '' }
- : '' }
- { this.props.names.map((name) => { return }) }
- )
- }
-})
+const FeaturedCategory = (props) => {
+ const {
+ category,
+ names,
+ } = props
+
+ return
+
{category}
+ {category && category.match(/^community/i) && }
+
+ {names.map(name => )}
+
+}
let DiscoverPage = React.createClass({
getInitialState: function() {
diff --git a/ui/js/page/file-list.js b/ui/js/page/file-list.js
index 8ae732dfe..7d609b3f4 100644
--- a/ui/js/page/file-list.js
+++ b/ui/js/page/file-list.js
@@ -1,14 +1,13 @@
import React from 'react';
-import lbry from '../lbry.js';
-import lbryuri from '../lbryuri.js';
+import lbry from 'lbry.js';
+import lbryuri from 'lbryuri.js';
import Link from 'component/link';
-import FormField from '../component/form.js';
-import {SubHeader} from '../component/header.js';
-import {FileTileStream} from '../component/file-tile.js';
-import rewards from '../rewards.js';
-import lbryio from '../lbryio.js';
-import {BusyMessage, Thumbnail} from '../component/common.js';
-
+import {FormField} from 'component/form.js';
+import SubHeader from '../component/sub-header';
+import {FileTileStream} from 'component/fileTile';
+import rewards from 'rewards.js';
+import lbryio from 'lbryio.js';
+import {BusyMessage, Thumbnail} from 'component/common.js';
export let FileListNav = React.createClass({
render: function() {
diff --git a/ui/js/page/reward.js b/ui/js/page/reward.js
index 2fb5b3e64..0a8aeebc6 100644
--- a/ui/js/page/reward.js
+++ b/ui/js/page/reward.js
@@ -1,6 +1,6 @@
import React from 'react';
import lbryio from '../lbryio.js';
-import {Link} from '../component/link.js';
+import {Link} from '../component/link';
import Notice from '../component/notice.js';
import {CreditAmount} from '../component/common.js';
//
diff --git a/ui/js/page/rewards.js b/ui/js/page/rewards.js
index 3462517c9..429a49a5e 100644
--- a/ui/js/page/rewards.js
+++ b/ui/js/page/rewards.js
@@ -5,7 +5,7 @@ import {CreditAmount, Icon} from '../component/common.js';
import rewards from '../rewards.js';
import Modal from '../component/modal.js';
import {WalletNav} from './wallet.js';
-import {RewardLink} from '../component/link.js';
+import {RewardLink} from '../component/link';
const RewardTile = React.createClass({
propTypes: {
diff --git a/ui/js/page/search.js b/ui/js/page/search.js
index dafeb30cf..f51541bcc 100644
--- a/ui/js/page/search.js
+++ b/ui/js/page/search.js
@@ -4,7 +4,7 @@ import lbryio from '../lbryio.js';
import lbryuri from '../lbryuri.js';
import lighthouse from '../lighthouse.js';
import {FileTile, FileTileStream} from '../component/file-tile.js';
-import {Link} from '../component/link.js';
+import {Link} from '../component/link';
import {ToolTip} from '../component/tooltip.js';
import {BusyMessage} from '../component/common.js';
diff --git a/ui/js/page/settings.js b/ui/js/page/settings.js
index cbc0765a8..09f45a9c5 100644
--- a/ui/js/page/settings.js
+++ b/ui/js/page/settings.js
@@ -1,6 +1,6 @@
import React from 'react';
import {FormField, FormRow} from '../component/form.js';
-import {SubHeader} from '../component/header.js';
+import {SubHeader} from '../component/sub-header.js';
import lbry from '../lbry.js';
export let SettingsNav = React.createClass({
diff --git a/ui/js/page/show.js b/ui/js/page/show.js
index f37994b7a..7624a8e17 100644
--- a/ui/js/page/show.js
+++ b/ui/js/page/show.js
@@ -2,7 +2,7 @@ import React from 'react';
import lbry from '../lbry.js';
import lighthouse from '../lighthouse.js';
import lbryuri from '../lbryuri.js';
-import {Video} from '../page/watch.js'
+import Video from 'component/video'
import {TruncatedText, Thumbnail, FilePrice, BusyMessage} from '../component/common.js';
import {FileActions} from '../component/file-actions.js';
import UriIndicator from '../component/channel-indicator.js';
diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js
new file mode 100644
index 000000000..aefdb11c7
--- /dev/null
+++ b/ui/js/reducers/content.js
@@ -0,0 +1,31 @@
+import * as types from 'constants/action_types'
+
+const reducers = {}
+const defaultState = {
+}
+
+reducers[types.FETCH_FEATURED_CONTENT_STARTED] = function(state, action) {
+ return Object.assign({}, state, {
+ fetchingFeaturedContent: true
+ })
+}
+
+reducers[types.FETCH_FEATURED_CONTENT_COMPLETED] = function(state, action) {
+ const {
+ uris
+ } = action.data
+ const newFeaturedContent = Object.assign({}, state.featuredContent, {
+ byCategory: uris,
+ })
+
+ return Object.assign({}, state, {
+ fetchingFeaturedContent: false,
+ featuredContent: newFeaturedContent
+ })
+}
+
+export default function reducer(state = defaultState, action) {
+ const handler = reducers[action.type];
+ if (handler) return handler(state, action);
+ return state;
+}
diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js
new file mode 100644
index 000000000..7e5905ecb
--- /dev/null
+++ b/ui/js/selectors/content.js
@@ -0,0 +1,37 @@
+import { createSelector } from 'reselect'
+import {
+ selectDaemonReady,
+ selectCurrentPage,
+} from 'selectors/app'
+
+export const _selectState = state => state.content || {}
+
+export const selectFeaturedContent = createSelector(
+ _selectState,
+ (state) => state.featuredContent || {}
+)
+
+export const selectFeaturedContentByCategory = createSelector(
+ selectFeaturedContent,
+ (featuredContent) => featuredContent.byCategory || {}
+)
+
+export const selectFetchingFeaturedContent = createSelector(
+ _selectState,
+ (state) => !!state.fetchingFeaturedContent
+)
+
+export const shouldFetchFeaturedContent = createSelector(
+ selectDaemonReady,
+ selectCurrentPage,
+ selectFetchingFeaturedContent,
+ selectFeaturedContentByCategory,
+ (daemonReady, page, fetching, byCategory) => {
+ if (!daemonReady) return false
+ if (page != 'discover') return false
+ if (fetching) return false
+ if (Object.keys(byCategory).length != 0) return false
+
+ return true
+ }
+)
diff --git a/ui/js/store.js b/ui/js/store.js
index 3d40d0d92..8b3d9e8a4 100644
--- a/ui/js/store.js
+++ b/ui/js/store.js
@@ -6,6 +6,7 @@ import {
createLogger
} from 'redux-logger'
import appReducer from 'reducers/app';
+import contentReducer from 'reducers/content';
import walletReducer from 'reducers/wallet'
function isFunction(object) {
@@ -18,6 +19,7 @@ function isNotFunction(object) {
const reducers = redux.combineReducers({
app: appReducer,
+ content: contentReducer,
wallet: walletReducer,
});
diff --git a/ui/js/triggers.js b/ui/js/triggers.js
index 85d44f360..8fe951df8 100644
--- a/ui/js/triggers.js
+++ b/ui/js/triggers.js
@@ -2,10 +2,16 @@ import {
shouldFetchTransactions,
shouldGetReceiveAddress,
} from 'selectors/wallet'
+import {
+ shouldFetchFeaturedContent,
+} from 'selectors/content'
import {
doFetchTransactions,
doGetNewAddress,
} from 'actions/wallet'
+import {
+ doFetchFeaturedContent,
+} from 'actions/content'
const triggers = []
@@ -19,6 +25,11 @@ triggers.push({
action: doGetNewAddress
})
+triggers.push({
+ selector: shouldFetchFeaturedContent,
+ action: doFetchFeaturedContent,
+})
+
const runTriggers = function() {
triggers.forEach(function(trigger) {
const state = app.store.getState();