Working on search
This commit is contained in:
parent
bb9a71805b
commit
768326fb4a
10 changed files with 158 additions and 34 deletions
|
@ -1,9 +1,12 @@
|
||||||
import * as types from 'constants/action_types'
|
import * as types from 'constants/action_types'
|
||||||
import lbry from 'lbry'
|
import lbry from 'lbry'
|
||||||
import lbryio from 'lbryio';
|
import lbryio from 'lbryio'
|
||||||
import {
|
import {
|
||||||
selectCurrentUri,
|
selectCurrentUri,
|
||||||
} from 'selectors/app'
|
} from 'selectors/app'
|
||||||
|
import {
|
||||||
|
selectSearchTerm,
|
||||||
|
} from 'selectors/content'
|
||||||
import {
|
import {
|
||||||
selectCurrentResolvedUriClaimOutpoint,
|
selectCurrentResolvedUriClaimOutpoint,
|
||||||
} from 'selectors/content'
|
} from 'selectors/content'
|
||||||
|
|
28
ui/js/actions/search.js
Normal file
28
ui/js/actions/search.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import * as types from 'constants/action_types'
|
||||||
|
import lbry from 'lbry'
|
||||||
|
import lbryio from 'lbryio'
|
||||||
|
import lighthouse from 'lighthouse'
|
||||||
|
import {
|
||||||
|
selectSearchQuery,
|
||||||
|
} from 'selectors/search'
|
||||||
|
|
||||||
|
export function doSearchContent(query) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
const state = getState()
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: types.SEARCH_STARTED,
|
||||||
|
data: { query }
|
||||||
|
})
|
||||||
|
|
||||||
|
lighthouse.search(query).then(results => {
|
||||||
|
dispatch({
|
||||||
|
type: types.SEARCH_COMPLETED,
|
||||||
|
data: {
|
||||||
|
query,
|
||||||
|
results,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ import {
|
||||||
import {
|
import {
|
||||||
doNavigate,
|
doNavigate,
|
||||||
} from 'actions/app'
|
} from 'actions/app'
|
||||||
|
import {
|
||||||
|
doSearchContent,
|
||||||
|
} from 'actions/search'
|
||||||
import Header from './view'
|
import Header from './view'
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
|
@ -18,6 +21,7 @@ const select = (state) => ({
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
navigate: (path) => dispatch(doNavigate(path)),
|
navigate: (path) => dispatch(doNavigate(path)),
|
||||||
|
search: (query) => dispatch(doSearchContent(query)),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default connect(select, perform)(Header)
|
export default connect(select, perform)(Header)
|
||||||
|
|
|
@ -47,3 +47,7 @@ export const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED'
|
||||||
export const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED'
|
export const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED'
|
||||||
export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'
|
export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'
|
||||||
export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'
|
export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'
|
||||||
|
|
||||||
|
// Search
|
||||||
|
export const SEARCH_STARTED = 'SEARCH_STARTED'
|
||||||
|
export const SEARCH_COMPLETED = 'SEARCH_COMPLETED'
|
||||||
|
|
|
@ -5,10 +5,21 @@ import {
|
||||||
import {
|
import {
|
||||||
selectFeaturedContentByCategory
|
selectFeaturedContentByCategory
|
||||||
} from 'selectors/content'
|
} from 'selectors/content'
|
||||||
|
import {
|
||||||
|
doSearchContent,
|
||||||
|
} from 'actions/search'
|
||||||
|
import {
|
||||||
|
selectIsSearching,
|
||||||
|
selectSearchQuery,
|
||||||
|
selectCurrentSearchResults,
|
||||||
|
} from 'selectors/search'
|
||||||
import DiscoverPage from './view'
|
import DiscoverPage from './view'
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
featuredContentByCategory: selectFeaturedContentByCategory(state),
|
featuredContentByCategory: selectFeaturedContentByCategory(state),
|
||||||
|
isSearching: selectIsSearching(state),
|
||||||
|
query: selectSearchQuery(state),
|
||||||
|
results: selectCurrentSearchResults(state),
|
||||||
})
|
})
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
|
|
|
@ -60,6 +60,6 @@ let DiscoverPage = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
}</main>;
|
}</main>;
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
export default DiscoverPage;
|
export default DiscoverPage;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import lbry from 'lbry.js';
|
import lbry from 'lbry.js';
|
||||||
import lighthouse from 'lighthouse.js';
|
import lighthouse from 'lighthouse.js';
|
||||||
import lbryuri from 'lbryuri.js';
|
import lbryuri from 'lbryuri.js';
|
||||||
import {Video} from 'page/watch.js'
|
import Video from 'page/video'
|
||||||
import {
|
import {
|
||||||
TruncatedText,
|
TruncatedText,
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
|
@ -13,22 +13,30 @@ import {FileActions} from 'component/file-actions.js';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import UriIndicator from 'component/channel-indicator.js';
|
import UriIndicator from 'component/channel-indicator.js';
|
||||||
|
|
||||||
var FormatItem = React.createClass({
|
const FormatItem = (props) => {
|
||||||
propTypes: {
|
const {
|
||||||
metadata: React.PropTypes.object,
|
contentType,
|
||||||
contentType: React.PropTypes.string,
|
metadata,
|
||||||
uri: React.PropTypes.string,
|
cost,
|
||||||
outpoint: React.PropTypes.string,
|
uri,
|
||||||
},
|
outpoint,
|
||||||
render: function() {
|
costIncludesData,
|
||||||
const {thumbnail, author, title, description, language, license} = this.props.metadata;
|
} = props
|
||||||
const mediaType = lbry.getMediaType(this.props.contentType);
|
const {
|
||||||
|
thumbnail,
|
||||||
|
author,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
language,
|
||||||
|
license
|
||||||
|
} = metadata;
|
||||||
|
const mediaType = lbry.getMediaType(contentType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="table-standard">
|
<table className="table-standard">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Content-Type</td><td>{this.props.contentType}</td>
|
<td>Content-Type</td><td>{contentType}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Author</td><td>{author}</td>
|
<td>Author</td><td>{author}</td>
|
||||||
|
@ -41,9 +49,8 @@ var FormatItem = React.createClass({
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
let ChannelPage = React.createClass({
|
let ChannelPage = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
36
ui/js/reducers/search.js
Normal file
36
ui/js/reducers/search.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import * as types from 'constants/action_types'
|
||||||
|
|
||||||
|
const reducers = {}
|
||||||
|
const defaultState = {
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.SEARCH_STARTED] = function(state, action) {
|
||||||
|
const {
|
||||||
|
query,
|
||||||
|
} = action.data
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
searching: true,
|
||||||
|
query: query,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.SEARCH_COMPLETED] = function(state, action) {
|
||||||
|
const {
|
||||||
|
query,
|
||||||
|
} = action.data
|
||||||
|
const newResults = Object.assign({}, state.results)
|
||||||
|
const newByQuery = Object.assign({}, newResults.byQuery)
|
||||||
|
newByQuery[query] = action.data.results
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
searching: false,
|
||||||
|
results: newResults,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function reducer(state = defaultState, action) {
|
||||||
|
const handler = reducers[action.type];
|
||||||
|
if (handler) return handler(state, action);
|
||||||
|
return state;
|
||||||
|
}
|
29
ui/js/selectors/search.js
Normal file
29
ui/js/selectors/search.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { createSelector } from 'reselect'
|
||||||
|
|
||||||
|
export const _selectState = state => state.search || {}
|
||||||
|
|
||||||
|
export const selectSearchQuery = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.query
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectIsSearching = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => !!state.searching
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectSearchResults = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.results || {}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectSearchResultsByQuery = createSelector(
|
||||||
|
selectSearchResults,
|
||||||
|
(results) => results.byQuery || {}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectCurrentSearchResults = createSelector(
|
||||||
|
selectSearchQuery,
|
||||||
|
selectSearchResultsByQuery,
|
||||||
|
(query, byQuery) => byQuery[query] || []
|
||||||
|
)
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import appReducer from 'reducers/app';
|
import appReducer from 'reducers/app';
|
||||||
import contentReducer from 'reducers/content';
|
import contentReducer from 'reducers/content';
|
||||||
import rewardsReducer from 'reducers/rewards'
|
import rewardsReducer from 'reducers/rewards'
|
||||||
|
import searchReducer from 'reducers/search'
|
||||||
import walletReducer from 'reducers/wallet'
|
import walletReducer from 'reducers/wallet'
|
||||||
|
|
||||||
function isFunction(object) {
|
function isFunction(object) {
|
||||||
|
@ -22,6 +23,7 @@ const reducers = redux.combineReducers({
|
||||||
app: appReducer,
|
app: appReducer,
|
||||||
content: contentReducer,
|
content: contentReducer,
|
||||||
rewards: rewardsReducer,
|
rewards: rewardsReducer,
|
||||||
|
search: searchReducer,
|
||||||
wallet: walletReducer,
|
wallet: walletReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue