move channel search into ChannelContent component
This commit is contained in:
parent
a479c70021
commit
fa246a7f1f
5 changed files with 78 additions and 95 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import * as SETTINGS from 'constants/settings';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { PAGE_SIZE } from 'constants/claim';
|
import { PAGE_SIZE } from 'constants/claim';
|
||||||
import {
|
import {
|
||||||
|
@ -10,6 +11,8 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
|
||||||
import ChannelPage from './view';
|
import ChannelPage from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
@ -24,6 +27,7 @@ const select = (state, props) => {
|
||||||
channelIsBlocked: selectChannelIsBlocked(props.uri)(state),
|
channelIsBlocked: selectChannelIsBlocked(props.uri)(state),
|
||||||
claim: props.uri && makeSelectClaimForUri(props.uri)(state),
|
claim: props.uri && makeSelectClaimForUri(props.uri)(state),
|
||||||
isAuthenticated: selectUserVerifiedEmail(state),
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
|
showMature: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import * as CS from 'constants/claim_search';
|
||||||
|
import * as ICONS from 'constants/icons';
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
|
import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import ClaimListDiscover from 'component/claimListDiscover';
|
import ClaimListDiscover from 'component/claimListDiscover';
|
||||||
import * as CS from 'constants/claim_search';
|
|
||||||
import Ads from 'web/component/ads';
|
import Ads from 'web/component/ads';
|
||||||
|
import Icon from 'component/common/icon';
|
||||||
|
import { Form, FormField } from 'component/common/form';
|
||||||
|
import { DEBOUNCE_WAIT_DURATION_MS } from 'constants/search';
|
||||||
|
|
||||||
|
const LIGHTHOUSE_URL = 'https://lighthouse.lbry.com/search';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -21,6 +27,7 @@ type Props = {
|
||||||
defaultInfiniteScroll?: Boolean,
|
defaultInfiniteScroll?: Boolean,
|
||||||
claim: ?Claim,
|
claim: ?Claim,
|
||||||
isAuthenticated: boolean,
|
isAuthenticated: boolean,
|
||||||
|
showMature: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ChannelContent(props: Props) {
|
function ChannelContent(props: Props) {
|
||||||
|
@ -34,8 +41,56 @@ function ChannelContent(props: Props) {
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
defaultPageSize = CS.PAGE_SIZE,
|
defaultPageSize = CS.PAGE_SIZE,
|
||||||
defaultInfiniteScroll = true,
|
defaultInfiniteScroll = true,
|
||||||
|
showMature,
|
||||||
} = props;
|
} = props;
|
||||||
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
||||||
|
const [searchQuery, setSearchQuery] = React.useState('');
|
||||||
|
const [searchResults, setSearchResults] = React.useState(undefined);
|
||||||
|
const {
|
||||||
|
location: { pathname, search },
|
||||||
|
} = useHistory();
|
||||||
|
const url = `${pathname}${search}`;
|
||||||
|
const claimId = claim && claim.claim_id;
|
||||||
|
|
||||||
|
function handleInputChange(e) {
|
||||||
|
const { value } = e.target;
|
||||||
|
setSearchQuery(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResults(fetchUrl) {
|
||||||
|
fetch(fetchUrl)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(results => {
|
||||||
|
const urls = results.map(({ name, claimId }) => {
|
||||||
|
return `lbry://${name}#${claimId}`;
|
||||||
|
});
|
||||||
|
setSearchResults(urls);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setSearchResults(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (searchQuery === '' || !claimId) {
|
||||||
|
// In order to display original search results, search results must be set to null. A query of '' should display original results.
|
||||||
|
return setSearchResults(null);
|
||||||
|
} else {
|
||||||
|
getResults(
|
||||||
|
`${LIGHTHOUSE_URL}?s=${encodeURIComponent(searchQuery)}&channel_id=${encodeURIComponent(claimId)}${
|
||||||
|
!showMature ? '&nsfw=false' : ''
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, DEBOUNCE_WAIT_DURATION_MS);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [claimId, searchQuery, showMature]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setSearchQuery('');
|
||||||
|
setSearchResults(null);
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
@ -66,11 +121,24 @@ function ChannelContent(props: Props) {
|
||||||
|
|
||||||
{claim && claimsInChannel > 0 ? (
|
{claim && claimsInChannel > 0 ? (
|
||||||
<ClaimListDiscover
|
<ClaimListDiscover
|
||||||
|
uris={searchResults}
|
||||||
channelIds={[claim.claim_id]}
|
channelIds={[claim.claim_id]}
|
||||||
defaultOrderBy={CS.ORDER_BY_NEW}
|
defaultOrderBy={CS.ORDER_BY_NEW}
|
||||||
pageSize={defaultPageSize}
|
pageSize={defaultPageSize}
|
||||||
infiniteScroll={defaultInfiniteScroll}
|
infiniteScroll={defaultInfiniteScroll}
|
||||||
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" />}
|
injectedItem={!isAuthenticated && IS_WEB && <Ads type="video" />}
|
||||||
|
meta={
|
||||||
|
<Form onSubmit={() => {}} className="wunderbar--inline">
|
||||||
|
<Icon icon={ICONS.SEARCH} />
|
||||||
|
<FormField
|
||||||
|
className="wunderbar__input"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
type="text"
|
||||||
|
placeholder={__('Search')}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<section className="main--empty">{__("This channel hasn't published anything yet")}</section>
|
<section className="main--empty">{__("This channel hasn't published anything yet")}</section>
|
||||||
|
@ -79,4 +147,4 @@ function ChannelContent(props: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(ChannelContent);
|
export default ChannelContent;
|
||||||
|
|
|
@ -95,6 +95,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
followedTags,
|
followedTags,
|
||||||
injectedItem,
|
injectedItem,
|
||||||
feeAmount,
|
feeAmount,
|
||||||
|
uris,
|
||||||
} = props;
|
} = props;
|
||||||
const didNavigateForward = history.action === 'PUSH';
|
const didNavigateForward = history.action === 'PUSH';
|
||||||
const { search } = location;
|
const { search } = location;
|
||||||
|
@ -694,7 +695,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
isCardBody
|
isCardBody
|
||||||
id={claimSearchCacheQuery}
|
id={claimSearchCacheQuery}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
uris={claimSearchResult}
|
uris={uris || claimSearchResult}
|
||||||
onScrollBottom={handleScrollBottom}
|
onScrollBottom={handleScrollBottom}
|
||||||
page={page}
|
page={page}
|
||||||
pageSize={CS.PAGE_SIZE}
|
pageSize={CS.PAGE_SIZE}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as settings from 'constants/settings';
|
|
||||||
import {
|
import {
|
||||||
makeSelectClaimIsMine,
|
makeSelectClaimIsMine,
|
||||||
makeSelectTitleForUri,
|
makeSelectTitleForUri,
|
||||||
|
@ -11,7 +10,6 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc';
|
import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc';
|
||||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
|
||||||
import ChannelPage from './view';
|
import ChannelPage from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
|
@ -24,7 +22,6 @@ const select = (state, props) => ({
|
||||||
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
|
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
|
||||||
channelIsBlocked: selectChannelIsBlocked(props.uri)(state),
|
channelIsBlocked: selectChannelIsBlocked(props.uri)(state),
|
||||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||||
showMature: makeSelectClientSetting(settings.SHOW_MATURE)(state),
|
|
||||||
subCount: makeSelectSubCountForUri(props.uri)(state),
|
subCount: makeSelectSubCountForUri(props.uri)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,14 @@ import ChannelThumbnail from 'component/channelThumbnail';
|
||||||
import ChannelEdit from 'component/channelEdit';
|
import ChannelEdit from 'component/channelEdit';
|
||||||
import ClaimUri from 'component/claimUri';
|
import ClaimUri from 'component/claimUri';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { Form, FormField } from 'component/common/form';
|
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import HelpLink from 'component/common/help-link';
|
import HelpLink from 'component/common/help-link';
|
||||||
import { DEBOUNCE_WAIT_DURATION_MS } from 'constants/search';
|
|
||||||
import ClaimList from 'component/claimList';
|
|
||||||
import DateTime from 'component/dateTime';
|
import DateTime from 'component/dateTime';
|
||||||
import ClaimSupportButton from 'component/claimSupportButton';
|
import ClaimSupportButton from 'component/claimSupportButton';
|
||||||
|
|
||||||
const PAGE_VIEW_QUERY = `view`;
|
const PAGE_VIEW_QUERY = `view`;
|
||||||
const ABOUT_PAGE = `about`;
|
const ABOUT_PAGE = `about`;
|
||||||
const DISCUSSION_PAGE = `discussion`;
|
const DISCUSSION_PAGE = `discussion`;
|
||||||
const LIGHTHOUSE_URL = 'https://lighthouse.lbry.com/search';
|
|
||||||
const ARROW_LEFT_KEYCODE = 37;
|
|
||||||
const ARROW_RIGHT_KEYCODE = 39;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -52,7 +46,6 @@ type Props = {
|
||||||
}>,
|
}>,
|
||||||
fetchSubCount: string => void,
|
fetchSubCount: string => void,
|
||||||
subCount: number,
|
subCount: number,
|
||||||
showMature: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ChannelPage(props: Props) {
|
function ChannelPage(props: Props) {
|
||||||
|
@ -69,7 +62,6 @@ function ChannelPage(props: Props) {
|
||||||
isSubscribed,
|
isSubscribed,
|
||||||
channelIsBlocked,
|
channelIsBlocked,
|
||||||
blackListedOutpoints,
|
blackListedOutpoints,
|
||||||
showMature,
|
|
||||||
fetchSubCount,
|
fetchSubCount,
|
||||||
subCount,
|
subCount,
|
||||||
} = props;
|
} = props;
|
||||||
|
@ -83,8 +75,6 @@ function ChannelPage(props: Props) {
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [thumbPreview, setThumbPreview] = useState(thumbnail);
|
const [thumbPreview, setThumbPreview] = useState(thumbnail);
|
||||||
const [coverPreview, setCoverPreview] = useState(cover);
|
const [coverPreview, setCoverPreview] = useState(cover);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
|
||||||
const [searchResults, setSearchResults] = useState(undefined);
|
|
||||||
const [lastYtSyncDate, setLastYtSyncDate] = useState();
|
const [lastYtSyncDate, setLastYtSyncDate] = useState();
|
||||||
const claimId = claim.claim_id;
|
const claimId = claim.claim_id;
|
||||||
const formattedSubCount = Number(subCount).toLocaleString();
|
const formattedSubCount = Number(subCount).toLocaleString();
|
||||||
|
@ -99,7 +89,6 @@ function ChannelPage(props: Props) {
|
||||||
let search = '?';
|
let search = '?';
|
||||||
|
|
||||||
if (newTabIndex === 0) {
|
if (newTabIndex === 0) {
|
||||||
setSearchResults(null);
|
|
||||||
search += `page=${page}`;
|
search += `page=${page}`;
|
||||||
} else if (newTabIndex === 1) {
|
} else if (newTabIndex === 1) {
|
||||||
search += `${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`;
|
search += `${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`;
|
||||||
|
@ -109,36 +98,6 @@ function ChannelPage(props: Props) {
|
||||||
history.push(`${url}${search}`);
|
history.push(`${url}${search}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResults(fetchUrl) {
|
|
||||||
fetch(fetchUrl)
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(results => {
|
|
||||||
const urls = results.map(({ name, claimId }) => {
|
|
||||||
return `lbry://${name}#${claimId}`;
|
|
||||||
});
|
|
||||||
setSearchResults(urls);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setSearchResults(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
if (searchQuery === '') {
|
|
||||||
// In order to display original search results, search results must be set to null. A query of '' should display original results.
|
|
||||||
return setSearchResults(null);
|
|
||||||
} else {
|
|
||||||
getResults(
|
|
||||||
`${LIGHTHOUSE_URL}?s=${encodeURIComponent(searchQuery)}&channel_id=${encodeURIComponent(claimId)}${
|
|
||||||
!showMature ? '&nsfw=false' : ''
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, DEBOUNCE_WAIT_DURATION_MS);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [claimId, searchQuery]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Lbryio.call('yt', 'get_youtuber', { channel_claim_id: claimId }).then(response => {
|
Lbryio.call('yt', 'get_youtuber', { channel_claim_id: claimId }).then(response => {
|
||||||
if (response.is_verified_youtuber) {
|
if (response.is_verified_youtuber) {
|
||||||
|
@ -147,22 +106,6 @@ function ChannelPage(props: Props) {
|
||||||
});
|
});
|
||||||
}, [claimId]);
|
}, [claimId]);
|
||||||
|
|
||||||
function handleInputChange(e) {
|
|
||||||
const { value } = e.target;
|
|
||||||
setSearchQuery(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Since the search is inside of TabList, the left and right arrow keys change the tabIndex.
|
|
||||||
This results in the user not being able to navigate the search string by using arrow keys.
|
|
||||||
This function allows the event to change cursor position and then stops propagation to prevent tab changing.
|
|
||||||
*/
|
|
||||||
function handleSearchArrowKeys(e) {
|
|
||||||
if (e.keyCode === ARROW_LEFT_KEYCODE || e.keyCode === ARROW_RIGHT_KEYCODE) {
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let channelIsBlackListed = false;
|
let channelIsBlackListed = false;
|
||||||
|
|
||||||
if (claim && blackListedOutpoints) {
|
if (claim && blackListedOutpoints) {
|
||||||
|
@ -172,9 +115,6 @@ function ChannelPage(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setSearchResults(null);
|
|
||||||
setSearchQuery('');
|
|
||||||
|
|
||||||
fetchSubCount(claimId);
|
fetchSubCount(claimId);
|
||||||
}, [uri, fetchSubCount, claimId]);
|
}, [uri, fetchSubCount, claimId]);
|
||||||
|
|
||||||
|
@ -252,38 +192,11 @@ function ChannelPage(props: Props) {
|
||||||
<Tab disabled={editing}>{__('Content')}</Tab>
|
<Tab disabled={editing}>{__('Content')}</Tab>
|
||||||
<Tab>{editing ? __('Editing Your Channel') : __('About')}</Tab>
|
<Tab>{editing ? __('Editing Your Channel') : __('About')}</Tab>
|
||||||
<Tab disabled={editing}>{__('Comments')}</Tab>
|
<Tab disabled={editing}>{__('Comments')}</Tab>
|
||||||
{/* only render searchbar on content page (tab index 0 === content page) */}
|
|
||||||
{tabIndex === 0 ? (
|
|
||||||
<Form onSubmit={() => {}} className="wunderbar--inline">
|
|
||||||
<Icon icon={ICONS.SEARCH} />
|
|
||||||
<FormField
|
|
||||||
className="wunderbar__input"
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
onKeyDown={handleSearchArrowKeys}
|
|
||||||
type="text"
|
|
||||||
placeholder={__('Search')}
|
|
||||||
/>
|
|
||||||
</Form>
|
|
||||||
) : (
|
|
||||||
<div />
|
|
||||||
)}
|
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanels>
|
<TabPanels>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
{searchResults ? (
|
|
||||||
<ClaimList
|
|
||||||
header={false}
|
|
||||||
headerAltControls={null}
|
|
||||||
id={`search-results-for-${claimId}`}
|
|
||||||
loading={false}
|
|
||||||
showHiddenByUser={false}
|
|
||||||
uris={searchResults}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ChannelContent uri={uri} channelIsBlackListed={channelIsBlackListed} />
|
<ChannelContent uri={uri} channelIsBlackListed={channelIsBlackListed} />
|
||||||
)}
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
{editing ? (
|
{editing ? (
|
||||||
|
|
Loading…
Reference in a new issue