select tags before channels and filter channels by tag
moartags CS tags followed category continue button, Remove card header on tags select limitShow tags count tags limit fix debug cs tags highlighting bugfix yarnlock
This commit is contained in:
parent
f8357c4ec6
commit
d9e65e8328
22 changed files with 325 additions and 93 deletions
|
@ -131,7 +131,7 @@
|
||||||
"imagesloaded": "^4.1.4",
|
"imagesloaded": "^4.1.4",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#8245b055746216f7e1a12744fe6fbda3e3e90705",
|
"lbry-redux": "lbryio/lbry-redux#6ed0dde5cbd7c25aa02631d5fa31fb6a4de76876",
|
||||||
"lbryinc": "lbryio/lbryinc#275f35b31ec614e2b89689f860fe19e645deee68",
|
"lbryinc": "lbryio/lbryinc#275f35b31ec614e2b89689f860fe19e645deee68",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
|
|
|
@ -1034,6 +1034,8 @@
|
||||||
"Deleting or editing comments is not currently possible. Please be mindful of this when posting.": "Deleting or editing comments is not currently possible. Please be mindful of this when posting.",
|
"Deleting or editing comments is not currently possible. Please be mindful of this when posting.": "Deleting or editing comments is not currently possible. Please be mindful of this when posting.",
|
||||||
"When the alpha ends, we will attempt to transition comments, but do not promise to do so.": "When the alpha ends, we will attempt to transition comments, but do not promise to do so.",
|
"When the alpha ends, we will attempt to transition comments, but do not promise to do so.": "When the alpha ends, we will attempt to transition comments, but do not promise to do so.",
|
||||||
"More Channels": "More Channels",
|
"More Channels": "More Channels",
|
||||||
|
"Known Tags": "Known Tags",
|
||||||
|
"More Channels": "More Channels",
|
||||||
"You aren’t blocking any channels": "You aren’t blocking any channels",
|
"You aren’t blocking any channels": "You aren’t blocking any channels",
|
||||||
"When you block a channel, all content from that channel will be hidden.": "When you block a channel, all content from that channel will be hidden.",
|
"When you block a channel, all content from that channel will be hidden.": "When you block a channel, all content from that channel will be hidden.",
|
||||||
"View top claims for %normalized_uri%": "View top claims for %normalized_uri%",
|
"View top claims for %normalized_uri%": "View top claims for %normalized_uri%",
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
selectUploadCount,
|
selectUploadCount,
|
||||||
selectUnclaimedRewards,
|
selectUnclaimedRewards,
|
||||||
doUserSetReferrer,
|
doUserSetReferrer,
|
||||||
|
selectUserVerifiedEmail,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux';
|
import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux';
|
||||||
import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings';
|
||||||
|
@ -35,6 +36,7 @@ const select = state => ({
|
||||||
syncError: selectGetSyncErrorMessage(state),
|
syncError: selectGetSyncErrorMessage(state),
|
||||||
uploadCount: selectUploadCount(state),
|
uploadCount: selectUploadCount(state),
|
||||||
rewards: selectUnclaimedRewards(state),
|
rewards: selectUnclaimedRewards(state),
|
||||||
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
@ -50,9 +52,4 @@ const perform = dispatch => ({
|
||||||
setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)),
|
setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default hot(
|
export default hot(connect(select, perform)(App));
|
||||||
connect(
|
|
||||||
select,
|
|
||||||
perform
|
|
||||||
)(App)
|
|
||||||
);
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ type Props = {
|
||||||
rewards: Array<Reward>,
|
rewards: Array<Reward>,
|
||||||
setReferrer: (string, boolean) => void,
|
setReferrer: (string, boolean) => void,
|
||||||
analyticsTagSync: () => void,
|
analyticsTagSync: () => void,
|
||||||
|
isAuthenticated: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function App(props: Props) {
|
function App(props: Props) {
|
||||||
|
@ -93,6 +94,7 @@ function App(props: Props) {
|
||||||
rewards,
|
rewards,
|
||||||
setReferrer,
|
setReferrer,
|
||||||
analyticsTagSync,
|
analyticsTagSync,
|
||||||
|
isAuthenticated,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const appRef = useRef();
|
const appRef = useRef();
|
||||||
|
@ -242,11 +244,11 @@ function App(props: Props) {
|
||||||
}, [hasVerifiedEmail, syncEnabled, checkSync]);
|
}, [hasVerifiedEmail, syncEnabled, checkSync]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (syncError) {
|
if (syncError && isAuthenticated) {
|
||||||
history.push(`/$/${PAGES.AUTH}?redirect=${pathname}`);
|
history.push(`/$/${PAGES.AUTH}?redirect=${pathname}`);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [syncError, pathname]);
|
}, [syncError, pathname, isAuthenticated]);
|
||||||
|
|
||||||
// @if TARGET='web'
|
// @if TARGET='web'
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -5,12 +5,14 @@ import {
|
||||||
selectFetchingClaimSearch,
|
selectFetchingClaimSearch,
|
||||||
selectBlockedChannels,
|
selectBlockedChannels,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
selectFollowedTags,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doToggleTagFollowDesktop } from 'redux/actions/tags';
|
import { doToggleTagFollowDesktop } from 'redux/actions/tags';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import ClaimListDiscover from './view';
|
import ClaimListDiscover from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
followedTags: selectFollowedTags(state),
|
||||||
claimSearchByQuery: selectClaimSearchByQuery(state),
|
claimSearchByQuery: selectClaimSearchByQuery(state),
|
||||||
loading: selectFetchingClaimSearch(state),
|
loading: selectFetchingClaimSearch(state),
|
||||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||||
|
|
|
@ -32,7 +32,8 @@ type Props = {
|
||||||
hiddenUris: Array<string>,
|
hiddenUris: Array<string>,
|
||||||
hiddenNsfwMessage?: Node,
|
hiddenNsfwMessage?: Node,
|
||||||
channelIds?: Array<string>,
|
channelIds?: Array<string>,
|
||||||
tags: Array<string>,
|
tags: string, // these are just going to be string. pass a CSV if you want multi
|
||||||
|
defaultTags: string,
|
||||||
orderBy?: Array<string>,
|
orderBy?: Array<string>,
|
||||||
defaultOrderBy?: string,
|
defaultOrderBy?: string,
|
||||||
freshness?: string,
|
freshness?: string,
|
||||||
|
@ -49,6 +50,7 @@ type Props = {
|
||||||
renderProperties?: Claim => Node,
|
renderProperties?: Claim => Node,
|
||||||
includeSupportAction?: boolean,
|
includeSupportAction?: boolean,
|
||||||
pageSize?: number,
|
pageSize?: number,
|
||||||
|
followedTags?: Array<Tag>,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ClaimListDiscover(props: Props) {
|
function ClaimListDiscover(props: Props) {
|
||||||
|
@ -56,11 +58,12 @@ function ClaimListDiscover(props: Props) {
|
||||||
doClaimSearch,
|
doClaimSearch,
|
||||||
claimSearchByQuery,
|
claimSearchByQuery,
|
||||||
tags,
|
tags,
|
||||||
|
defaultTags,
|
||||||
loading,
|
loading,
|
||||||
meta,
|
meta,
|
||||||
channelIds,
|
channelIds,
|
||||||
showNsfw,
|
showNsfw,
|
||||||
showReposts,
|
// showReposts,
|
||||||
history,
|
history,
|
||||||
location,
|
location,
|
||||||
hiddenUris,
|
hiddenUris,
|
||||||
|
@ -81,6 +84,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
renderProperties,
|
renderProperties,
|
||||||
includeSupportAction,
|
includeSupportAction,
|
||||||
hideFilter,
|
hideFilter,
|
||||||
|
followedTags,
|
||||||
} = props;
|
} = props;
|
||||||
const didNavigateForward = history.action === 'PUSH';
|
const didNavigateForward = history.action === 'PUSH';
|
||||||
const { search } = location;
|
const { search } = location;
|
||||||
|
@ -88,9 +92,12 @@ function ClaimListDiscover(props: Props) {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [forceRefresh, setForceRefresh] = useState();
|
const [forceRefresh, setForceRefresh] = useState();
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
const followed = (followedTags && followedTags.map(t => t.name)) || [];
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const tagsParam = tags || urlParams.get(CS.TAGS_KEY) || null;
|
const tagsParam = // can be 'x,y,z' or 'x' or ['x','y'] or CS.CONSTANT
|
||||||
|
(tags && getParamFromTags(tags)) ||
|
||||||
|
(urlParams.get(CS.TAGS_KEY) !== null && urlParams.get(CS.TAGS_KEY)) ||
|
||||||
|
(defaultTags && getParamFromTags(defaultTags));
|
||||||
const orderParam = orderBy || urlParams.get(CS.ORDER_BY_KEY) || defaultOrderBy || CS.ORDER_BY_TRENDING;
|
const orderParam = orderBy || urlParams.get(CS.ORDER_BY_KEY) || defaultOrderBy || CS.ORDER_BY_TRENDING;
|
||||||
const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness;
|
const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness;
|
||||||
const contentTypeParam = urlParams.get(CS.CONTENT_KEY);
|
const contentTypeParam = urlParams.get(CS.CONTENT_KEY);
|
||||||
|
@ -102,7 +109,12 @@ function ClaimListDiscover(props: Props) {
|
||||||
|
|
||||||
const showDuration = !(claimType && claimType === CS.CLAIM_CHANNEL);
|
const showDuration = !(claimType && claimType === CS.CLAIM_CHANNEL);
|
||||||
const isFiltered = () =>
|
const isFiltered = () =>
|
||||||
Boolean(urlParams.get(CS.FRESH_KEY) || urlParams.get(CS.CONTENT_KEY) || urlParams.get(CS.DURATION_KEY));
|
Boolean(
|
||||||
|
urlParams.get(CS.FRESH_KEY) ||
|
||||||
|
urlParams.get(CS.CONTENT_KEY) ||
|
||||||
|
urlParams.get(CS.DURATION_KEY) ||
|
||||||
|
urlParams.get(CS.TAGS_KEY)
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFiltered()) setExpanded(true);
|
if (isFiltered()) setExpanded(true);
|
||||||
|
@ -113,7 +125,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
page_size: number,
|
page_size: number,
|
||||||
page: number,
|
page: number,
|
||||||
no_totals: boolean,
|
no_totals: boolean,
|
||||||
any_tags: Array<string>,
|
any_tags?: Array<string>,
|
||||||
not_tags: Array<string>,
|
not_tags: Array<string>,
|
||||||
channel_ids: Array<string>,
|
channel_ids: Array<string>,
|
||||||
not_channel_ids: Array<string>,
|
not_channel_ids: Array<string>,
|
||||||
|
@ -131,7 +143,6 @@ function ClaimListDiscover(props: Props) {
|
||||||
// no_totals makes it so the sdk doesn't have to calculate total number pages for pagination
|
// no_totals makes it so the sdk doesn't have to calculate total number pages for pagination
|
||||||
// it's faster, but we will need to remove it if we start using total_pages
|
// it's faster, but we will need to remove it if we start using total_pages
|
||||||
no_totals: true,
|
no_totals: true,
|
||||||
any_tags: tagsParam || [],
|
|
||||||
channel_ids: channelIds || [],
|
channel_ids: channelIds || [],
|
||||||
not_channel_ids:
|
not_channel_ids:
|
||||||
// If channelIds were passed in, we don't need not_channel_ids
|
// If channelIds were passed in, we don't need not_channel_ids
|
||||||
|
@ -211,6 +222,17 @@ function ClaimListDiscover(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tagsParam) {
|
||||||
|
if (tagsParam !== CS.TAGS_ALL && tagsParam !== '') {
|
||||||
|
if (tagsParam === CS.TAGS_FOLLOWED) {
|
||||||
|
options.any_tags = followed;
|
||||||
|
} else if (Array.isArray(tagsParam)) {
|
||||||
|
options.any_tags = tagsParam;
|
||||||
|
} else {
|
||||||
|
options.any_tags = tagsParam.split(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// https://github.com/lbryio/lbry-desktop/issues/3774
|
// https://github.com/lbryio/lbry-desktop/issues/3774
|
||||||
// if (!showReposts) {
|
// if (!showReposts) {
|
||||||
// if (Array.isArray(options.claim_type)) {
|
// if (Array.isArray(options.claim_type)) {
|
||||||
|
@ -220,7 +242,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const hasMatureTags = tags && tags.some(t => MATURE_TAGS.includes(t));
|
const hasMatureTags = tagsParam && tagsParam.split(',').some(t => MATURE_TAGS.includes(t));
|
||||||
const claimSearchCacheQuery = createNormalizedClaimSearchKey(options);
|
const claimSearchCacheQuery = createNormalizedClaimSearchKey(options);
|
||||||
const uris = claimSearchByQuery[claimSearchCacheQuery] || [];
|
const uris = claimSearchByQuery[claimSearchCacheQuery] || [];
|
||||||
const shouldPerformSearch =
|
const shouldPerformSearch =
|
||||||
|
@ -265,6 +287,14 @@ function ClaimListDiscover(props: Props) {
|
||||||
history.push(url);
|
history.push(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParamFromTags(t) {
|
||||||
|
if (t === CS.TAGS_ALL || t === CS.TAGS_FOLLOWED) {
|
||||||
|
return t;
|
||||||
|
} else if (Array.isArray(t)) {
|
||||||
|
return t.join(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildUrl(delta) {
|
function buildUrl(delta) {
|
||||||
const newUrlParams = new URLSearchParams();
|
const newUrlParams = new URLSearchParams();
|
||||||
CS.KEYS.forEach(k => {
|
CS.KEYS.forEach(k => {
|
||||||
|
@ -300,6 +330,23 @@ function ClaimListDiscover(props: Props) {
|
||||||
newUrlParams.set(CS.DURATION_KEY, delta.value);
|
newUrlParams.set(CS.DURATION_KEY, delta.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CS.TAGS_KEY:
|
||||||
|
if (delta.value === CS.TAGS_ALL) {
|
||||||
|
if (defaultTags === CS.TAGS_ALL) {
|
||||||
|
newUrlParams.delete(CS.TAGS_KEY);
|
||||||
|
} else {
|
||||||
|
newUrlParams.set(CS.TAGS_KEY, delta.value);
|
||||||
|
}
|
||||||
|
} else if (delta.value === CS.TAGS_FOLLOWED) {
|
||||||
|
if (defaultTags === CS.TAGS_FOLLOWED) {
|
||||||
|
newUrlParams.delete(CS.TAGS_KEY);
|
||||||
|
} else {
|
||||||
|
newUrlParams.set(CS.TAGS_KEY, delta.value); // redundant but special
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newUrlParams.set(CS.TAGS_KEY, delta.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return `?${newUrlParams.toString()}`;
|
return `?${newUrlParams.toString()}`;
|
||||||
}
|
}
|
||||||
|
@ -393,46 +440,48 @@ function ClaimListDiscover(props: Props) {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* CONTENT_TYPES FIELD */}
|
{/* CONTENT_TYPES FIELD */}
|
||||||
<div
|
{!claimType && (
|
||||||
className={classnames('claim-search__input-container', {
|
<div
|
||||||
'claim-search__input-container--selected': contentTypeParam,
|
className={classnames('claim-search__input-container', {
|
||||||
})}
|
'claim-search__input-container--selected': contentTypeParam,
|
||||||
>
|
|
||||||
<FormField
|
|
||||||
className={classnames('claim-search__dropdown', {
|
|
||||||
'claim-search__dropdown--selected': contentTypeParam,
|
|
||||||
})}
|
})}
|
||||||
type="select"
|
|
||||||
name="claimType"
|
|
||||||
label={__('Content Type')}
|
|
||||||
value={contentTypeParam || CS.CONTENT_ALL}
|
|
||||||
onChange={e =>
|
|
||||||
handleChange({
|
|
||||||
key: CS.CONTENT_KEY,
|
|
||||||
value: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{CS.CONTENT_TYPES.map(type => {
|
<FormField
|
||||||
if (type !== CS.CLAIM_CHANNEL || (type === CS.CLAIM_CHANNEL && !channelIds)) {
|
className={classnames('claim-search__dropdown', {
|
||||||
return (
|
'claim-search__dropdown--selected': contentTypeParam,
|
||||||
<option key={type} value={type}>
|
})}
|
||||||
{/* i18fixme */}
|
type="select"
|
||||||
{type === CS.CLAIM_CHANNEL && __('Channel')}
|
name="claimType"
|
||||||
{type === CS.CLAIM_REPOST && __('Repost')}
|
label={__('Content Type')}
|
||||||
{type === CS.FILE_VIDEO && __('Video')}
|
value={contentTypeParam || CS.CONTENT_ALL}
|
||||||
{type === CS.FILE_AUDIO && __('Audio')}
|
onChange={e =>
|
||||||
{type === CS.FILE_IMAGE && __('Image')}
|
handleChange({
|
||||||
{type === CS.FILE_MODEL && __('Model')}
|
key: CS.CONTENT_KEY,
|
||||||
{type === CS.FILE_BINARY && __('Other')}
|
value: e.target.value,
|
||||||
{type === CS.FILE_DOCUMENT && __('Document')}
|
})
|
||||||
{type === CS.CONTENT_ALL && __('Any')}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})}
|
>
|
||||||
</FormField>
|
{CS.CONTENT_TYPES.map(type => {
|
||||||
</div>
|
if (type !== CS.CLAIM_CHANNEL || (type === CS.CLAIM_CHANNEL && !channelIds)) {
|
||||||
|
return (
|
||||||
|
<option key={type} value={type}>
|
||||||
|
{/* i18fixme */}
|
||||||
|
{type === CS.CLAIM_CHANNEL && __('Channel')}
|
||||||
|
{type === CS.CLAIM_REPOST && __('Repost')}
|
||||||
|
{type === CS.FILE_VIDEO && __('Video')}
|
||||||
|
{type === CS.FILE_AUDIO && __('Audio')}
|
||||||
|
{type === CS.FILE_IMAGE && __('Image')}
|
||||||
|
{type === CS.FILE_MODEL && __('Model')}
|
||||||
|
{type === CS.FILE_BINARY && __('Other')}
|
||||||
|
{type === CS.FILE_DOCUMENT && __('Document')}
|
||||||
|
{type === CS.CONTENT_ALL && __('Any')}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{/* DURATIONS FIELD */}
|
{/* DURATIONS FIELD */}
|
||||||
{showDuration && (
|
{showDuration && (
|
||||||
<div className={'claim-search__input-container'}>
|
<div className={'claim-search__input-container'}>
|
||||||
|
@ -469,6 +518,50 @@ function ClaimListDiscover(props: Props) {
|
||||||
</FormField>
|
</FormField>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{/* TAGS FIELD */}
|
||||||
|
{!tags && (
|
||||||
|
<div className={'claim-search__input-container'}>
|
||||||
|
<FormField
|
||||||
|
className={classnames('claim-search__dropdown', {
|
||||||
|
'claim-search__dropdown--selected':
|
||||||
|
((!defaultTags || defaultTags === CS.TAGS_ALL) && tagsParam && tagsParam !== CS.TAGS_ALL) ||
|
||||||
|
(defaultTags === CS.TAGS_FOLLOWED && tagsParam !== CS.TAGS_FOLLOWED),
|
||||||
|
})}
|
||||||
|
label={__('Tags')}
|
||||||
|
type="select"
|
||||||
|
name="tags"
|
||||||
|
value={tagsParam || CS.TAGS_ALL}
|
||||||
|
onChange={e =>
|
||||||
|
handleChange({
|
||||||
|
key: CS.TAGS_KEY,
|
||||||
|
value: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
CS.TAGS_ALL,
|
||||||
|
CS.TAGS_FOLLOWED,
|
||||||
|
...followed,
|
||||||
|
...(followed.includes(tagsParam) || tagsParam === CS.TAGS_ALL || tagsParam === CS.TAGS_FOLLOWED
|
||||||
|
? []
|
||||||
|
: [tagsParam]), // if they unfollow while filtered, add Other
|
||||||
|
].map(tag => (
|
||||||
|
<option
|
||||||
|
key={tag}
|
||||||
|
value={tag}
|
||||||
|
className={classnames({
|
||||||
|
'claim-search__input-special': !followed.includes(tag),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{followed.includes(tag) && typeof tag === 'string' && toCapitalCase(__(tag))}
|
||||||
|
{tag === CS.TAGS_ALL && __('Any')}
|
||||||
|
{tag === CS.TAGS_FOLLOWED && __('Following')}
|
||||||
|
{!followed.includes(tag) && tag !== CS.TAGS_ALL && tag !== CS.TAGS_FOLLOWED && __('Other')}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import ClaimPreviewTile from 'component/claimPreviewTile';
|
||||||
type Props = {
|
type Props = {
|
||||||
uris: Array<string>,
|
uris: Array<string>,
|
||||||
doClaimSearch: ({}) => void,
|
doClaimSearch: ({}) => void,
|
||||||
loading: boolean,
|
|
||||||
showNsfw: boolean,
|
showNsfw: boolean,
|
||||||
showReposts: boolean,
|
showReposts: boolean,
|
||||||
history: { action: string, push: string => void, replace: string => void },
|
history: { action: string, push: string => void, replace: string => void },
|
||||||
|
@ -29,9 +28,8 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
const {
|
const {
|
||||||
doClaimSearch,
|
doClaimSearch,
|
||||||
claimSearchByQuery,
|
claimSearchByQuery,
|
||||||
loading,
|
|
||||||
showNsfw,
|
showNsfw,
|
||||||
showReposts,
|
// showReposts,
|
||||||
hiddenUris,
|
hiddenUris,
|
||||||
// Below are options to pass that are forwarded to claim_search
|
// Below are options to pass that are forwarded to claim_search
|
||||||
tags,
|
tags,
|
||||||
|
@ -95,7 +93,7 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
|
|
||||||
const claimSearchCacheQuery = createNormalizedClaimSearchKey(options);
|
const claimSearchCacheQuery = createNormalizedClaimSearchKey(options);
|
||||||
const uris = claimSearchByQuery[claimSearchCacheQuery] || [];
|
const uris = claimSearchByQuery[claimSearchCacheQuery] || [];
|
||||||
const shouldPerformSearch = !hasSearched || uris.length === 0 || (!loading && uris.length < pageSize);
|
const shouldPerformSearch = !hasSearched || uris.length === 0;
|
||||||
// Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time
|
// Don't use the query from createNormalizedClaimSearchKey for the effect since that doesn't include page & release_time
|
||||||
const optionsStringForEffect = JSON.stringify(options);
|
const optionsStringForEffect = JSON.stringify(options);
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ function PublishForm(props: Props) {
|
||||||
hideHeader
|
hideHeader
|
||||||
label={__('Selected Tags')}
|
label={__('Selected Tags')}
|
||||||
empty={__('No tags added')}
|
empty={__('No tags added')}
|
||||||
limit={TAGS_LIMIT}
|
limitSelect={TAGS_LIMIT}
|
||||||
help={__(
|
help={__(
|
||||||
'Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.'
|
'Add tags that are relevant to your content. If mature content, ensure it is tagged mature. Tag abuse and missing mature tags will not be tolerated.'
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -18,7 +18,8 @@ type Props = {
|
||||||
placeholder?: string,
|
placeholder?: string,
|
||||||
label?: string,
|
label?: string,
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
limit?: number,
|
limitSelect?: number,
|
||||||
|
limitShow?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -42,7 +43,8 @@ export default function TagsSearch(props: Props) {
|
||||||
placeholder,
|
placeholder,
|
||||||
label,
|
label,
|
||||||
disabled,
|
disabled,
|
||||||
limit,
|
limitSelect,
|
||||||
|
limitShow = 5,
|
||||||
} = props;
|
} = props;
|
||||||
const [newTag, setNewTag] = useState('');
|
const [newTag, setNewTag] = useState('');
|
||||||
const doesTagMatch = name => {
|
const doesTagMatch = name => {
|
||||||
|
@ -60,10 +62,10 @@ export default function TagsSearch(props: Props) {
|
||||||
const suggestedTagsSet = setUnion(remainingFollowedTagsSet, unfollowedTagsSet);
|
const suggestedTagsSet = setUnion(remainingFollowedTagsSet, unfollowedTagsSet);
|
||||||
|
|
||||||
const countWithoutMature = selectedTagsSet.has('mature') ? selectedTagsSet.size - 1 : selectedTagsSet.size;
|
const countWithoutMature = selectedTagsSet.has('mature') ? selectedTagsSet.size - 1 : selectedTagsSet.size;
|
||||||
const maxed = Boolean(limit && countWithoutMature >= limit);
|
const maxed = Boolean(limitSelect && countWithoutMature >= limitSelect);
|
||||||
const suggestedTags = Array.from(suggestedTagsSet)
|
const suggestedTags = Array.from(suggestedTagsSet)
|
||||||
.filter(doesTagMatch)
|
.filter(doesTagMatch)
|
||||||
.slice(0, 5);
|
.slice(0, limitShow);
|
||||||
|
|
||||||
// tack 'mature' onto the end if it's not already in the list
|
// tack 'mature' onto the end if it's not already in the list
|
||||||
if (!newTag && suggestMature && !suggestedTags.some(tag => tag === 'mature')) {
|
if (!newTag && suggestMature && !suggestedTags.some(tag => tag === 'mature')) {
|
||||||
|
@ -116,7 +118,7 @@ export default function TagsSearch(props: Props) {
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Form className="tags__input-wrapper" onSubmit={handleSubmit}>
|
<Form className="tags__input-wrapper" onSubmit={handleSubmit}>
|
||||||
<label>
|
<label>
|
||||||
{limit ? (
|
{limitSelect ? (
|
||||||
<I18nMessage
|
<I18nMessage
|
||||||
tokens={{
|
tokens={{
|
||||||
number: 5 - countWithoutMature,
|
number: 5 - countWithoutMature,
|
||||||
|
|
|
@ -24,7 +24,8 @@ type Props = {
|
||||||
placeholder?: string,
|
placeholder?: string,
|
||||||
disableAutoFocus?: boolean,
|
disableAutoFocus?: boolean,
|
||||||
hideHeader?: boolean,
|
hideHeader?: boolean,
|
||||||
limit?: number,
|
limitShow?: number,
|
||||||
|
limitSelect?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -45,7 +46,8 @@ export default function TagsSelect(props: Props) {
|
||||||
placeholder,
|
placeholder,
|
||||||
hideHeader,
|
hideHeader,
|
||||||
label,
|
label,
|
||||||
limit,
|
limitShow,
|
||||||
|
limitSelect,
|
||||||
} = props;
|
} = props;
|
||||||
const [hasClosed, setHasClosed] = usePersistedState('tag-select:has-closed', false);
|
const [hasClosed, setHasClosed] = usePersistedState('tag-select:has-closed', false);
|
||||||
const tagsToDisplay = tagsChosen || followedTags;
|
const tagsToDisplay = tagsChosen || followedTags;
|
||||||
|
@ -107,7 +109,8 @@ export default function TagsSelect(props: Props) {
|
||||||
disableAutoFocus={disableAutoFocus}
|
disableAutoFocus={disableAutoFocus}
|
||||||
tagsPassedIn={tagsToDisplay}
|
tagsPassedIn={tagsToDisplay}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
limit={limit}
|
limitShow={limitShow}
|
||||||
|
limitSelect={limitSelect}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectFollowedTags } from 'lbry-redux';
|
import { selectFollowedTags } from 'lbry-redux';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
|
import { doChannelSubscribe } from 'redux/actions/subscriptions';
|
||||||
import UserChannelFollowIntro from './view';
|
import UserChannelFollowIntro from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -8,4 +9,11 @@ const select = state => ({
|
||||||
subscribedChannels: selectSubscriptions(state),
|
subscribedChannels: selectSubscriptions(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select)(UserChannelFollowIntro);
|
const perform = dispatch => ({
|
||||||
|
channelSubscribe: uri => dispatch(doChannelSubscribe(uri)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserChannelFollowIntro);
|
||||||
|
|
|
@ -1,18 +1,32 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import ClaimListDiscover from 'component/claimListDiscover';
|
import ClaimListDiscover from 'component/claimListDiscover';
|
||||||
import * as CS from 'constants/claim_search';
|
import * as CS from 'constants/claim_search';
|
||||||
import Nag from 'component/common/nag';
|
import Nag from 'component/common/nag';
|
||||||
|
import { parseURI } from 'lbry-redux';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import { Form } from 'component/common/form-components/form';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
subscribedChannels: Array<Subscription>,
|
subscribedChannels: Array<Subscription>,
|
||||||
onContinue: () => void,
|
onContinue: () => void,
|
||||||
|
onBack: () => void,
|
||||||
|
channelSubscribe: (sub: Subscription) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const LBRYURI = 'lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a';
|
||||||
function UserChannelFollowIntro(props: Props) {
|
function UserChannelFollowIntro(props: Props) {
|
||||||
const { subscribedChannels, onContinue } = props;
|
const { subscribedChannels, channelSubscribe, onContinue, onBack } = props;
|
||||||
const followingCount = (subscribedChannels && subscribedChannels.length) || 0;
|
const followingCount = (subscribedChannels && subscribedChannels.length) || 0;
|
||||||
|
|
||||||
|
// subscribe to lbry
|
||||||
|
useEffect(() => {
|
||||||
|
channelSubscribe({
|
||||||
|
channelName: parseURI(LBRYURI).claimName,
|
||||||
|
uri: LBRYURI,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h1 className="section__title--large">{__('Find Channels to Follow')}</h1>
|
<h1 className="section__title--large">{__('Find Channels to Follow')}</h1>
|
||||||
|
@ -21,13 +35,25 @@ function UserChannelFollowIntro(props: Props) {
|
||||||
'LBRY works better if you find and follow at least 5 creators you like. You can also block channels you never want to see.'
|
'LBRY works better if you find and follow at least 5 creators you like. You can also block channels you never want to see.'
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
<Form onSubmit={onContinue} className="section__body">
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button button="secondary" onClick={onBack} label={__('Back')} />
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
type="Submit"
|
||||||
|
onClick={onContinue}
|
||||||
|
label={__('Continue')}
|
||||||
|
disabled={subscribedChannels.length < 2}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
<div className="section__body">
|
<div className="section__body">
|
||||||
<ClaimListDiscover
|
<ClaimListDiscover
|
||||||
defaultOrderBy={CS.ORDER_BY_TOP}
|
defaultOrderBy={CS.ORDER_BY_TOP}
|
||||||
defaultFreshness={CS.FRESH_ALL}
|
defaultFreshness={CS.FRESH_ALL}
|
||||||
claimType="channel"
|
claimType="channel"
|
||||||
hideBlock
|
hideBlock
|
||||||
hideFilter
|
defaultTags={CS.TAGS_FOLLOWED}
|
||||||
/>
|
/>
|
||||||
{followingCount > 0 && (
|
{followingCount > 0 && (
|
||||||
<Nag
|
<Nag
|
||||||
|
|
|
@ -6,6 +6,7 @@ import UserEmailNew from 'component/userEmailNew';
|
||||||
import UserEmailVerify from 'component/userEmailVerify';
|
import UserEmailVerify from 'component/userEmailVerify';
|
||||||
import UserFirstChannel from 'component/userFirstChannel';
|
import UserFirstChannel from 'component/userFirstChannel';
|
||||||
import UserChannelFollowIntro from 'component/userChannelFollowIntro';
|
import UserChannelFollowIntro from 'component/userChannelFollowIntro';
|
||||||
|
import UserTagFollowIntro from 'component/userTagFollowIntro';
|
||||||
import { DEFAULT_BID_FOR_FIRST_CHANNEL } from 'component/userFirstChannel/view';
|
import { DEFAULT_BID_FOR_FIRST_CHANNEL } from 'component/userFirstChannel/view';
|
||||||
import { rewards as REWARDS, YOUTUBE_STATUSES } from 'lbryinc';
|
import { rewards as REWARDS, YOUTUBE_STATUSES } from 'lbryinc';
|
||||||
import UserVerify from 'component/userVerify';
|
import UserVerify from 'component/userVerify';
|
||||||
|
@ -59,10 +60,12 @@ function UserSignIn(props: Props) {
|
||||||
const { search } = location;
|
const { search } = location;
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const redirect = urlParams.get('redirect');
|
const redirect = urlParams.get('redirect');
|
||||||
|
const step = urlParams.get('step');
|
||||||
const shouldRedirectImmediately = urlParams.get('immediate');
|
const shouldRedirectImmediately = urlParams.get('immediate');
|
||||||
const [initialSignInStep, setInitialSignInStep] = React.useState();
|
const [initialSignInStep, setInitialSignInStep] = React.useState();
|
||||||
const [hasSeenFollowList, setHasSeenFollowList] = usePersistedState('channel-follow-intro', false);
|
const [hasSeenFollowList, setHasSeenFollowList] = usePersistedState('channel-follow-intro', false);
|
||||||
const [hasSkippedRewards, setHasSkippedRewards] = usePersistedState('skip-rewards-intro', false);
|
const [hasSkippedRewards, setHasSkippedRewards] = usePersistedState('skip-rewards-intro', false);
|
||||||
|
const [hasSeenTagsList, setHasSeenTagsList] = usePersistedState('channel-follow-intro', false);
|
||||||
const hasVerifiedEmail = user && user.has_verified_email;
|
const hasVerifiedEmail = user && user.has_verified_email;
|
||||||
const rewardsApproved = user && user.is_reward_approved;
|
const rewardsApproved = user && user.is_reward_approved;
|
||||||
const isIdentityVerified = user && user.is_identity_verified;
|
const isIdentityVerified = user && user.is_identity_verified;
|
||||||
|
@ -92,7 +95,8 @@ function UserSignIn(props: Props) {
|
||||||
channelCount === 0 &&
|
channelCount === 0 &&
|
||||||
!hasYoutubeChannels;
|
!hasYoutubeChannels;
|
||||||
const showYoutubeTransfer = hasVerifiedEmail && hasYoutubeChannels && !isYoutubeTransferComplete;
|
const showYoutubeTransfer = hasVerifiedEmail && hasYoutubeChannels && !isYoutubeTransferComplete;
|
||||||
const showFollowIntro = hasVerifiedEmail && !hasSeenFollowList;
|
const showFollowIntro = step === 'channels' || (hasVerifiedEmail && !hasSeenFollowList);
|
||||||
|
const showTagsIntro = step === 'tags' || (hasVerifiedEmail && !hasSeenTagsList);
|
||||||
const canHijackSignInFlowWithSpinner = hasVerifiedEmail && !getSyncError && !showFollowIntro;
|
const canHijackSignInFlowWithSpinner = hasVerifiedEmail && !getSyncError && !showFollowIntro;
|
||||||
const isCurrentlyFetchingSomething = fetchingChannels || claimingReward || syncingWallet || creatingChannel;
|
const isCurrentlyFetchingSomething = fetchingChannels || claimingReward || syncingWallet || creatingChannel;
|
||||||
const isWaitingForSomethingToFinish =
|
const isWaitingForSomethingToFinish =
|
||||||
|
@ -136,6 +140,34 @@ function UserSignIn(props: Props) {
|
||||||
history.replace(url);
|
history.replace(url);
|
||||||
setHasSeenFollowList(true);
|
setHasSeenFollowList(true);
|
||||||
}}
|
}}
|
||||||
|
onBack={() => {
|
||||||
|
let url = `/$/${PAGES.AUTH}?reset_scroll=1&step=tags`;
|
||||||
|
if (redirect) {
|
||||||
|
url += `&redirect=${redirect}`;
|
||||||
|
}
|
||||||
|
if (shouldRedirectImmediately) {
|
||||||
|
url += `&immediate=true`;
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replace(url);
|
||||||
|
setHasSeenFollowList(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
showTagsIntro && (
|
||||||
|
<UserTagFollowIntro
|
||||||
|
onContinue={() => {
|
||||||
|
let url = `/$/${PAGES.AUTH}?reset_scroll=1&step=channels`;
|
||||||
|
if (redirect) {
|
||||||
|
url += `&redirect=${redirect}`;
|
||||||
|
}
|
||||||
|
if (shouldRedirectImmediately) {
|
||||||
|
url += `&immediate=true`;
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replace(url);
|
||||||
|
setHasSeenTagsList(true);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
showYoutubeTransfer && (
|
showYoutubeTransfer && (
|
||||||
|
|
9
ui/component/userTagFollowIntro/index.js
Normal file
9
ui/component/userTagFollowIntro/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectFollowedTags } from 'lbry-redux';
|
||||||
|
import UserTagFollowIntro from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
followedTags: selectFollowedTags(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(UserTagFollowIntro);
|
52
ui/component/userTagFollowIntro/view.jsx
Normal file
52
ui/component/userTagFollowIntro/view.jsx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import Nag from 'component/common/nag';
|
||||||
|
import TagsSelect from 'component/tagsSelect';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import { Form } from 'component/common/form';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
subscribedChannels: Array<Subscription>,
|
||||||
|
onContinue: () => void,
|
||||||
|
followedTags: Array<Tag>,
|
||||||
|
};
|
||||||
|
|
||||||
|
function UserChannelFollowIntro(props: Props) {
|
||||||
|
const { onContinue, followedTags } = props;
|
||||||
|
const followingCount = (followedTags && followedTags.length) || 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<h1 className="section__title--large">{__('Tag Selection')}</h1>
|
||||||
|
<p className="section__subtitle">{__('Select some tags to help us show you interesting things.')}</p>
|
||||||
|
<Form onSubmit={onContinue} className="section__body">
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
type="Submit"
|
||||||
|
onClick={onContinue}
|
||||||
|
label={__('Continue')}
|
||||||
|
disabled={followedTags.length < 1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
<div className="section__body">
|
||||||
|
<TagsSelect hideHeader limitShow={300} help={false} showClose={false} title={__('Follow New Tags')} />
|
||||||
|
{followingCount > 0 && (
|
||||||
|
<Nag
|
||||||
|
type="helpful"
|
||||||
|
message={
|
||||||
|
followingCount === 1
|
||||||
|
? __('You are currently following %followingCount% tag', { followingCount })
|
||||||
|
: __('You are currently following %followingCount% tags', { followingCount })
|
||||||
|
}
|
||||||
|
actionText={__('Continue')}
|
||||||
|
onClick={onContinue}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserChannelFollowIntro;
|
|
@ -6,6 +6,9 @@ export const DURATION_KEY = 'duration';
|
||||||
export const TAGS_KEY = 't';
|
export const TAGS_KEY = 't';
|
||||||
export const CONTENT_KEY = 'content';
|
export const CONTENT_KEY = 'content';
|
||||||
|
|
||||||
|
export const TAGS_ALL = 'tags_any';
|
||||||
|
export const TAGS_FOLLOWED = 'tags_followed';
|
||||||
|
|
||||||
export const FRESH_DAY = 'day';
|
export const FRESH_DAY = 'day';
|
||||||
export const FRESH_WEEK = 'week';
|
export const FRESH_WEEK = 'week';
|
||||||
export const FRESH_MONTH = 'month';
|
export const FRESH_MONTH = 'month';
|
||||||
|
|
|
@ -119,12 +119,7 @@ function ChannelsFollowingDiscover(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<h1 className="claim-grid__title">{__('More Channels')}</h1>
|
<h1 className="claim-grid__title">{__('More Channels')}</h1>
|
||||||
<ClaimListDiscover
|
<ClaimListDiscover defaultOrderBy={CS.ORDER_BY_TOP} defaultFreshness={CS.FRESH_ALL} claimType="channel" />
|
||||||
defaultOrderBy={CS.ORDER_BY_TOP}
|
|
||||||
defaultFreshness={CS.FRESH_ALL}
|
|
||||||
claimType="channel"
|
|
||||||
hideFilter
|
|
||||||
/>
|
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import useHover from 'effects/use-hover';
|
||||||
import analytics from 'analytics';
|
import analytics from 'analytics';
|
||||||
import HiddenNsfw from 'component/common/hidden-nsfw';
|
import HiddenNsfw from 'component/common/hidden-nsfw';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
import * as CS from 'constants/claim_search';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
location: { search: string },
|
location: { search: string },
|
||||||
|
@ -26,11 +27,11 @@ function TagsPage(props: Props) {
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const claimType = urlParams.get('claim_type');
|
const claimType = urlParams.get('claim_type');
|
||||||
const tagsQuery = urlParams.get('t') || '';
|
const tagsQuery = urlParams.get('t') || null;
|
||||||
const tags = tagsQuery.split(',');
|
const tags = tagsQuery ? tagsQuery.split(',') : null;
|
||||||
// Eventually allow more than one tag on this page
|
// Eventually allow more than one tag on this page
|
||||||
// Restricting to one to make follow/unfollow simpler
|
// Restricting to one to make follow/unfollow simpler
|
||||||
const tag = tags[0];
|
const tag = (tags && tags[0]) || null;
|
||||||
|
|
||||||
const isFollowing = followedTags.map(({ name }) => name).includes(tag);
|
const isFollowing = followedTags.map(({ name }) => name).includes(tag);
|
||||||
let label = isFollowing ? __('Following') : __('Follow');
|
let label = isFollowing ? __('Following') : __('Follow');
|
||||||
|
@ -39,10 +40,12 @@ function TagsPage(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFollowClick() {
|
function handleFollowClick() {
|
||||||
doToggleTagFollowDesktop(tag);
|
if (tag) {
|
||||||
|
doToggleTagFollowDesktop(tag);
|
||||||
|
|
||||||
const nowFollowing = !isFollowing;
|
const nowFollowing = !isFollowing;
|
||||||
analytics.tagFollowEvent(tag, nowFollowing, 'tag-page');
|
analytics.tagFollowEvent(tag, nowFollowing, 'tag-page');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -53,7 +56,9 @@ function TagsPage(props: Props) {
|
||||||
tag ? (
|
tag ? (
|
||||||
<span>
|
<span>
|
||||||
<Icon icon={ICONS.TAG} size={10} />
|
<Icon icon={ICONS.TAG} size={10} />
|
||||||
{tag}
|
{(tag === CS.TAGS_ALL && __('All Content')) ||
|
||||||
|
(tag === CS.TAGS_FOLLOWED && __('Followed Tags')) ||
|
||||||
|
__(tag)}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>
|
<span>
|
||||||
|
@ -62,7 +67,7 @@ function TagsPage(props: Props) {
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
tags={tags}
|
defaultTags={CS.TAGS_ALL}
|
||||||
hiddenNsfwMessage={<HiddenNsfw type="page" />}
|
hiddenNsfwMessage={<HiddenNsfw type="page" />}
|
||||||
meta={
|
meta={
|
||||||
tag && (
|
tag && (
|
||||||
|
|
|
@ -7,18 +7,18 @@ import TagsSelect from 'component/tagsSelect';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
import * as CS from 'constants/claim_search';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
followedTags: Array<Tag>,
|
|
||||||
email: string,
|
email: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
function DiscoverPage(props: Props) {
|
function DiscoverPage(props: Props) {
|
||||||
const { followedTags, email } = props;
|
const { email } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
{(email || !IS_WEB) && <TagsSelect showClose title={__('Find New Tags To Follow')} />}
|
{(email || !IS_WEB) && <TagsSelect showClose limitShow={300} title={__('Find New Tags To Follow')} />}
|
||||||
<ClaimListDiscover
|
<ClaimListDiscover
|
||||||
headerLabel={
|
headerLabel={
|
||||||
<span>
|
<span>
|
||||||
|
@ -28,7 +28,7 @@ function DiscoverPage(props: Props) {
|
||||||
}
|
}
|
||||||
hideCustomization={IS_WEB && !email}
|
hideCustomization={IS_WEB && !email}
|
||||||
personalView
|
personalView
|
||||||
tags={followedTags.map(tag => tag.name)}
|
defaultTags={CS.TAGS_FOLLOWED}
|
||||||
meta={
|
meta={
|
||||||
<Button
|
<Button
|
||||||
button="link"
|
button="link"
|
||||||
|
|
|
@ -6,7 +6,7 @@ import TagsSelect from 'component/tagsSelect';
|
||||||
function FollowingPage() {
|
function FollowingPage() {
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<TagsSelect showClose={false} title={__('Follow New Tags')} />
|
<TagsSelect limitShow={300} showClose={false} title={__('Follow New Tags')} />
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.claim-search__input-special {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
.claim-search__extra {
|
.claim-search__extra {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -7081,9 +7081,9 @@ lazy-val@^1.0.4:
|
||||||
yargs "^13.2.2"
|
yargs "^13.2.2"
|
||||||
zstd-codec "^0.1.1"
|
zstd-codec "^0.1.1"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#8245b055746216f7e1a12744fe6fbda3e3e90705:
|
lbry-redux@lbryio/lbry-redux#6ed0dde5cbd7c25aa02631d5fa31fb6a4de76876:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/8245b055746216f7e1a12744fe6fbda3e3e90705"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/6ed0dde5cbd7c25aa02631d5fa31fb6a4de76876"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue