Search kind of working, but nasty

This commit is contained in:
6ea86b96 2017-05-05 15:01:16 +07:00
parent daabe975e1
commit 29c53a9bf8
No known key found for this signature in database
GPG key ID: B282D183E4931E8F
7 changed files with 139 additions and 168 deletions

View file

@ -13,6 +13,7 @@ import RewardsPage from 'page/rewards.js';
import FileListDownloaded from 'page/fileListDownloaded'
import FileListPublished from 'page/fileListPublished'
import ChannelPage from 'page/channel'
import SearchPage from 'page/search'
const route = (page, routesMap) => {
const component = routesMap[page]
@ -42,6 +43,7 @@ const Router = (props) => {
'developer': <DeveloperPage {...props} />,
'discover': <DiscoverPage {...props} />,
'rewards': <RewardsPage {...props} />,
'search': <SearchPage {...props} />,
})
}

View file

@ -25,8 +25,8 @@ const perform = (dispatch) => ({
// navigate: (path) => dispatch(doNavigate(path)),
onSearch: (query) => dispatch(doSearchContent(query)),
onSubmit: (query) => dispatch(doSearchContent(query)),
// activateSearch: () => dispatch(doActivateSearch()),
// deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50),
activateSearch: () => dispatch(doActivateSearch()),
deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50),
})
export default connect(select, perform)(Wunderbar)

View file

@ -61,6 +61,8 @@ class WunderBar extends React.PureComponent {
isActive: true
}
this.props.activateSearch()
this._focusPending = true;
//below is hacking, improved when we have proper routing
if (!this.state.address.startsWith('lbry://') && this.state.icon !== "icon-search") //onFocus, if they are not on an exact URL or a search page, clear the bar
@ -71,6 +73,7 @@ class WunderBar extends React.PureComponent {
}
onBlur() {
this.props.deactivateSearch()
let commonState = {isActive: false};
if (this._resetOnNextBlur) {
this.setState(Object.assign({}, this._stateBeforeSearch, commonState));

View file

@ -1,165 +0,0 @@
import React from 'react';
import lbry from '../lbry.js';
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';
import {ToolTip} from '../component/tooltip.js';
import {BusyMessage} from '../component/common.js';
var SearchNoResults = React.createClass({
render: function() {
return <section>
<span className="empty">
No one has checked anything in for {this.props.query} yet.
<Link label="Be the first" href="?publish" />
</span>
</section>;
}
});
var SearchResultList = React.createClass({
render: function() {
var rows = [],
seenNames = {}; //fix this when the search API returns claim IDs
for (let {name, claim, claim_id, channel_name, channel_id, txid, nout} of this.props.results) {
const uri = lbryuri.build({
channelName: channel_name,
contentName: name,
claimId: channel_id || claim_id,
});
rows.push(
<FileTileStream key={uri} uri={uri} outpoint={txid + ':' + nout} metadata={claim.stream.metadata} contentType={claim.stream.source.contentType} />
);
}
return (
<div>{rows}</div>
);
}
});
let SearchResults = React.createClass({
propTypes: {
query: React.PropTypes.string.isRequired
},
_isMounted: false,
search: function(term) {
lighthouse.search(term).then(this.searchCallback);
if (!this.state.searching) {
this.setState({ searching: true })
}
},
componentWillMount: function () {
this._isMounted = true;
this.search(this.props.query);
},
componentWillReceiveProps: function (nextProps) {
if (nextProps.query != this.props.query) {
this.search(nextProps.query);
}
},
componentWillUnmount: function () {
this._isMounted = false;
},
getInitialState: function () {
return {
results: [],
searching: true
};
},
searchCallback: function (results) {
if (this._isMounted) //could have canceled while results were pending, in which case nothing to do
{
this.setState({
results: results,
searching: false //multiple searches can be out, we're only done if we receive one we actually care about
});
}
},
render: function () {
return this.state.searching ?
<BusyMessage message="Looking up the Dewey Decimals" /> :
(this.state.results && this.state.results.length ?
<SearchResultList results={this.state.results} /> :
<SearchNoResults query={this.props.query} />);
}
});
let SearchPage = React.createClass({
_isMounted: false,
propTypes: {
query: React.PropTypes.string.isRequired
},
isValidUri: function(query) {
try {
lbryuri.parse(query);
return true;
} catch (e) {
return false;
}
},
componentWillMount: function() {
this._isMounted = true;
lighthouse.search(this.props.query).then(this.searchCallback);
},
componentWillUnmount: function() {
this._isMounted = false;
},
getInitialState: function() {
return {
results: [],
searching: true
};
},
searchCallback: function(results) {
if (this._isMounted) //could have canceled while results were pending, in which case nothing to do
{
this.setState({
results: results,
searching: false //multiple searches can be out, we're only done if we receive one we actually care about
});
}
},
render: function() {
return (
<main className="main--single-column">
{ this.isValidUri(this.props.query) ?
<section className="section-spaced">
<h3 className="card-row__header">
Exact URL
<ToolTip label="?" body="This is the resolution of a LBRY URL and not controlled by LBRY Inc." className="tooltip--header"/>
</h3>
<FileTile uri={this.props.query} showEmpty={true} />
</section> : '' }
<section className="section-spaced">
<h3 className="card-row__header">
Search Results for {this.props.query}
<ToolTip label="?" body="These search results are provided by LBRY Inc." className="tooltip--header"/>
</h3>
<SearchResults query={this.props.query} />
</section>
</main>
);
}
});
export default SearchPage;

View file

@ -0,0 +1,30 @@
import React from 'react'
import {
connect,
} from 'react-redux'
import {
doSearchContent,
} from 'actions/search'
import {
selectIsSearching,
selectSearchQuery,
selectCurrentSearchResults,
selectSearchActivated,
} from 'selectors/search'
import {
doNavigate,
} from 'actions/app'
import SearchPage from './view'
const select = (state) => ({
isSearching: selectIsSearching(state),
query: selectSearchQuery(state),
results: selectCurrentSearchResults(state),
searchActive: selectSearchActivated(state),
})
const perform = (dispatch) => ({
navigate: (path) => dispatch(doNavigate(path)),
})
export default connect(select, perform)(SearchPage)

View file

@ -0,0 +1,92 @@
import React from 'react';
import lbry from 'lbry';
import lbryio from 'lbryio';
import lbryuri from 'lbryuri';
import lighthouse from 'lighthouse';
import FileTile from 'component/fileTile'
import FileTileStream from 'component/fileTileStream'
import Link from 'component/link'
import {ToolTip} from 'component/tooltip.js';
import {BusyMessage} from 'component/common.js';
const SearchNoResults = (props) => {
const {
navigate,
query,
} = props
return <section>
<span className="empty">
No one has checked anything in for {query} yet.
<Link label="Be the first" href="#" onClick={() => navigate('publish')} />
</span>
</section>;
}
const SearchResultList = (props) => {
const {
results,
} = props
const rows = [],
seenNames = {}; //fix this when the search API returns claim IDs
for (let {name, claim, claim_id, channel_name, channel_id, txid, nout} of results) {
const uri = lbryuri.build({
channelName: channel_name,
contentName: name,
claimId: channel_id || claim_id,
});
rows.push(
<FileTileStream key={uri} uri={uri} />
);
}
return (
<div>{rows}</div>
);
}
const SearchResults = (props) => {
const {
searching,
results,
query,
} = props
return (
searching ?
<BusyMessage message="Looking up the Dewey Decimals" /> :
(results && results.length) ?
<SearchResultList {...props} /> :
<SearchNoResults {...props} />
)
}
const SearchPage = (props) => {
const isValidUri = (query) => true
const {
query,
} = props
return (
<main className="main--single-column">
{ isValidUri(query) ?
<section className="section-spaced">
<h3 className="card-row__header">
Exact URL
<ToolTip label="?" body="This is the resolution of a LBRY URL and not controlled by LBRY Inc." className="tooltip--header" />
</h3>
<FileTile uri={query} showEmpty={true} />
</section> : '' }
<section className="section-spaced">
<h3 className="card-row__header">
Search Results for {query}
<ToolTip label="?" body="These search results are provided by LBRY, Inc." className="tooltip--header" />
</h3>
<SearchResults {...props} />
</section>
</main>
)
}
export default SearchPage;

View file

@ -1,4 +1,8 @@
import {createSelector} from 'reselect'
import {
selectIsSearching,
selectSearchActivated,
} from 'selectors/search'
export const _selectState = state => state.app || {}
@ -14,7 +18,12 @@ export const selectCurrentPath = createSelector(
export const selectCurrentPage = createSelector(
selectCurrentPath,
(path) => path.split('=')[0]
selectSearchActivated,
(path, searchActivated) => {
if (searchActivated) return 'search'
return path.split('=')[0]
}
)
export const selectCurrentUri = createSelector(