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} + +

+ + + {title} + + +

+
+
+ +
+
+

+ + {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();