From d9e65e8328058a4d7c350f307ca536846c8c728b Mon Sep 17 00:00:00 2001 From: jessop Date: Wed, 11 Mar 2020 21:43:52 -0400 Subject: [PATCH] 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 --- package.json | 2 +- static/app-strings.json | 2 + ui/component/app/index.js | 9 +- ui/component/app/view.jsx | 6 +- ui/component/claimListDiscover/index.js | 2 + ui/component/claimListDiscover/view.jsx | 183 ++++++++++++++----- ui/component/claimTilesDiscover/view.jsx | 6 +- ui/component/publishForm/view.jsx | 2 +- ui/component/tagsSearch/view.jsx | 12 +- ui/component/tagsSelect/view.jsx | 9 +- ui/component/userChannelFollowIntro/index.js | 10 +- ui/component/userChannelFollowIntro/view.jsx | 32 +++- ui/component/userSignIn/view.jsx | 34 +++- ui/component/userTagFollowIntro/index.js | 9 + ui/component/userTagFollowIntro/view.jsx | 52 ++++++ ui/constants/claim_search.js | 3 + ui/page/channelsFollowingDiscover/view.jsx | 7 +- ui/page/discover/view.jsx | 21 ++- ui/page/tagsFollowing/view.jsx | 8 +- ui/page/tagsFollowingManage/view.jsx | 2 +- ui/scss/component/_claim-search.scss | 3 + yarn.lock | 4 +- 22 files changed, 325 insertions(+), 93 deletions(-) create mode 100644 ui/component/userTagFollowIntro/index.js create mode 100644 ui/component/userTagFollowIntro/view.jsx diff --git a/package.json b/package.json index 4dcb19bea..552525cc3 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "imagesloaded": "^4.1.4", "json-loader": "^0.5.4", "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", "lint-staged": "^7.0.2", "localforage": "^1.7.1", diff --git a/static/app-strings.json b/static/app-strings.json index 380a6cb86..91e2930ae 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -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.", "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", + "Known Tags": "Known Tags", + "More Channels": "More 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.", "View top claims for %normalized_uri%": "View top claims for %normalized_uri%", diff --git a/ui/component/app/index.js b/ui/component/app/index.js index f1c450769..90cf6e89c 100644 --- a/ui/component/app/index.js +++ b/ui/component/app/index.js @@ -9,6 +9,7 @@ import { selectUploadCount, selectUnclaimedRewards, doUserSetReferrer, + selectUserVerifiedEmail, } from 'lbryinc'; import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux'; import { makeSelectClientSetting, selectLoadedLanguages, selectThemePath } from 'redux/selectors/settings'; @@ -35,6 +36,7 @@ const select = state => ({ syncError: selectGetSyncErrorMessage(state), uploadCount: selectUploadCount(state), rewards: selectUnclaimedRewards(state), + isAuthenticated: selectUserVerifiedEmail(state), }); const perform = dispatch => ({ @@ -50,9 +52,4 @@ const perform = dispatch => ({ setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)), }); -export default hot( - connect( - select, - perform - )(App) -); +export default hot(connect(select, perform)(App)); diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index 9aa78a287..022b4ad91 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -68,6 +68,7 @@ type Props = { rewards: Array, setReferrer: (string, boolean) => void, analyticsTagSync: () => void, + isAuthenticated: boolean, }; function App(props: Props) { @@ -93,6 +94,7 @@ function App(props: Props) { rewards, setReferrer, analyticsTagSync, + isAuthenticated, } = props; const appRef = useRef(); @@ -242,11 +244,11 @@ function App(props: Props) { }, [hasVerifiedEmail, syncEnabled, checkSync]); useEffect(() => { - if (syncError) { + if (syncError && isAuthenticated) { history.push(`/$/${PAGES.AUTH}?redirect=${pathname}`); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [syncError, pathname]); + }, [syncError, pathname, isAuthenticated]); // @if TARGET='web' useEffect(() => { diff --git a/ui/component/claimListDiscover/index.js b/ui/component/claimListDiscover/index.js index 123f96b5e..6c621fe84 100644 --- a/ui/component/claimListDiscover/index.js +++ b/ui/component/claimListDiscover/index.js @@ -5,12 +5,14 @@ import { selectFetchingClaimSearch, selectBlockedChannels, SETTINGS, + selectFollowedTags, } from 'lbry-redux'; import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { makeSelectClientSetting } from 'redux/selectors/settings'; import ClaimListDiscover from './view'; const select = state => ({ + followedTags: selectFollowedTags(state), claimSearchByQuery: selectClaimSearchByQuery(state), loading: selectFetchingClaimSearch(state), showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state), diff --git a/ui/component/claimListDiscover/view.jsx b/ui/component/claimListDiscover/view.jsx index 75cdd2607..f084201e8 100644 --- a/ui/component/claimListDiscover/view.jsx +++ b/ui/component/claimListDiscover/view.jsx @@ -32,7 +32,8 @@ type Props = { hiddenUris: Array, hiddenNsfwMessage?: Node, channelIds?: Array, - tags: Array, + tags: string, // these are just going to be string. pass a CSV if you want multi + defaultTags: string, orderBy?: Array, defaultOrderBy?: string, freshness?: string, @@ -49,6 +50,7 @@ type Props = { renderProperties?: Claim => Node, includeSupportAction?: boolean, pageSize?: number, + followedTags?: Array, }; function ClaimListDiscover(props: Props) { @@ -56,11 +58,12 @@ function ClaimListDiscover(props: Props) { doClaimSearch, claimSearchByQuery, tags, + defaultTags, loading, meta, channelIds, showNsfw, - showReposts, + // showReposts, history, location, hiddenUris, @@ -81,6 +84,7 @@ function ClaimListDiscover(props: Props) { renderProperties, includeSupportAction, hideFilter, + followedTags, } = props; const didNavigateForward = history.action === 'PUSH'; const { search } = location; @@ -88,9 +92,12 @@ function ClaimListDiscover(props: Props) { const [page, setPage] = useState(1); const [forceRefresh, setForceRefresh] = useState(); const [expanded, setExpanded] = useState(false); - + const followed = (followedTags && followedTags.map(t => t.name)) || []; 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 freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness; const contentTypeParam = urlParams.get(CS.CONTENT_KEY); @@ -102,7 +109,12 @@ function ClaimListDiscover(props: Props) { const showDuration = !(claimType && claimType === CS.CLAIM_CHANNEL); 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(() => { if (isFiltered()) setExpanded(true); @@ -113,7 +125,7 @@ function ClaimListDiscover(props: Props) { page_size: number, page: number, no_totals: boolean, - any_tags: Array, + any_tags?: Array, not_tags: Array, channel_ids: Array, not_channel_ids: Array, @@ -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 // it's faster, but we will need to remove it if we start using total_pages no_totals: true, - any_tags: tagsParam || [], channel_ids: channelIds || [], 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 // if (!showReposts) { // 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 uris = claimSearchByQuery[claimSearchCacheQuery] || []; const shouldPerformSearch = @@ -265,6 +287,14 @@ function ClaimListDiscover(props: Props) { 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) { const newUrlParams = new URLSearchParams(); CS.KEYS.forEach(k => { @@ -300,6 +330,23 @@ function ClaimListDiscover(props: Props) { newUrlParams.set(CS.DURATION_KEY, delta.value); } 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()}`; } @@ -393,46 +440,48 @@ function ClaimListDiscover(props: Props) { )} {/* CONTENT_TYPES FIELD */} -
- - handleChange({ - key: CS.CONTENT_KEY, - value: e.target.value, - }) - } > - {CS.CONTENT_TYPES.map(type => { - if (type !== CS.CLAIM_CHANNEL || (type === CS.CLAIM_CHANNEL && !channelIds)) { - return ( - - ); + + handleChange({ + key: CS.CONTENT_KEY, + value: e.target.value, + }) } - })} - -
+ > + {CS.CONTENT_TYPES.map(type => { + if (type !== CS.CLAIM_CHANNEL || (type === CS.CLAIM_CHANNEL && !channelIds)) { + return ( + + ); + } + })} + + + )} {/* DURATIONS FIELD */} {showDuration && (
@@ -469,6 +518,50 @@ function ClaimListDiscover(props: Props) {
)} + {/* TAGS FIELD */} + {!tags && ( +
+ + 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 => ( + + ))} + +
+ )} )} diff --git a/ui/component/claimTilesDiscover/view.jsx b/ui/component/claimTilesDiscover/view.jsx index a287ad42a..0ba51fe05 100644 --- a/ui/component/claimTilesDiscover/view.jsx +++ b/ui/component/claimTilesDiscover/view.jsx @@ -6,7 +6,6 @@ import ClaimPreviewTile from 'component/claimPreviewTile'; type Props = { uris: Array, doClaimSearch: ({}) => void, - loading: boolean, showNsfw: boolean, showReposts: boolean, history: { action: string, push: string => void, replace: string => void }, @@ -29,9 +28,8 @@ function ClaimTilesDiscover(props: Props) { const { doClaimSearch, claimSearchByQuery, - loading, showNsfw, - showReposts, + // showReposts, hiddenUris, // Below are options to pass that are forwarded to claim_search tags, @@ -95,7 +93,7 @@ function ClaimTilesDiscover(props: Props) { const claimSearchCacheQuery = createNormalizedClaimSearchKey(options); 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 const optionsStringForEffect = JSON.stringify(options); diff --git a/ui/component/publishForm/view.jsx b/ui/component/publishForm/view.jsx index efb53d9d2..29c92f9d9 100644 --- a/ui/component/publishForm/view.jsx +++ b/ui/component/publishForm/view.jsx @@ -153,7 +153,7 @@ function PublishForm(props: Props) { hideHeader label={__('Selected Tags')} empty={__('No tags added')} - limit={TAGS_LIMIT} + limitSelect={TAGS_LIMIT} 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.' )} diff --git a/ui/component/tagsSearch/view.jsx b/ui/component/tagsSearch/view.jsx index e49a778a0..cc4eff86a 100644 --- a/ui/component/tagsSearch/view.jsx +++ b/ui/component/tagsSearch/view.jsx @@ -18,7 +18,8 @@ type Props = { placeholder?: string, label?: string, disabled?: boolean, - limit?: number, + limitSelect?: number, + limitShow?: number, }; /* @@ -42,7 +43,8 @@ export default function TagsSearch(props: Props) { placeholder, label, disabled, - limit, + limitSelect, + limitShow = 5, } = props; const [newTag, setNewTag] = useState(''); const doesTagMatch = name => { @@ -60,10 +62,10 @@ export default function TagsSearch(props: Props) { const suggestedTagsSet = setUnion(remainingFollowedTagsSet, unfollowedTagsSet); 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) .filter(doesTagMatch) - .slice(0, 5); + .slice(0, limitShow); // tack 'mature' onto the end if it's not already in the list if (!newTag && suggestMature && !suggestedTags.some(tag => tag === 'mature')) { @@ -116,7 +118,7 @@ export default function TagsSearch(props: Props) {