// @flow import { SIMPLE_SITE } from 'config'; import * as CS from 'constants/claim_search'; import * as ICONS from 'constants/icons'; import type { Node } from 'react'; import classnames from 'classnames'; import React from 'react'; import usePersistedState from 'effects/use-persisted-state'; import { useHistory } from 'react-router'; import { SETTINGS } from 'lbry-redux'; import { FormField } from 'component/common/form'; import Button from 'component/button'; import { toCapitalCase } from 'util/string'; import SEARCHABLE_LANGUAGES from 'constants/searchable_languages'; type Props = { defaultTags: string, followedTags?: Array, tags: string, freshness?: string, defaultFreshness?: string, claimType?: Array, streamType?: string | Array, defaultStreamType?: string | Array, feeAmount: string, orderBy?: Array, defaultOrderBy?: string, hideAdvancedFilter: boolean, hasMatureTags: boolean, hiddenNsfwMessage?: Node, channelIds?: Array, tileLayout: boolean, doSetClientSetting: (string, boolean, ?boolean) => void, setPage: number => void, hideFilters: boolean, searchInLanguage: boolean, languageSetting: string, }; function ClaimListHeader(props: Props) { const { defaultTags, followedTags, tags, freshness, defaultFreshness, claimType, streamType, defaultStreamType, feeAmount, orderBy, defaultOrderBy, hideAdvancedFilter, hasMatureTags, hiddenNsfwMessage, channelIds, tileLayout, doSetClientSetting, setPage, hideFilters, searchInLanguage, languageSetting, } = props; const { action, push, location } = useHistory(); const { search } = location; const [expanded, setExpanded] = usePersistedState(`expanded-${location.pathname}`, false); const [orderParamEntry, setOrderParamEntry] = usePersistedState(`entry-${location.pathname}`, CS.ORDER_BY_TRENDING); const [orderParamUser, setOrderParamUser] = usePersistedState(`orderUser-${location.pathname}`, CS.ORDER_BY_TRENDING); const followed = (followedTags && followedTags.map(t => t.name)) || []; const urlParams = new URLSearchParams(search); 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 freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness; const contentTypeParam = urlParams.get(CS.CONTENT_KEY); const streamTypeParam = streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null; const durationParam = urlParams.get(CS.DURATION_KEY) || null; const languageParam = urlParams.get(CS.LANGUAGE_KEY) || null; const channelIdsInUrl = urlParams.get(CS.CHANNEL_IDS_KEY); const channelIdsParam = channelIdsInUrl ? channelIdsInUrl.split(',') : channelIds; const feeAmountParam = urlParams.get('fee_amount') || feeAmount || CS.FEE_AMOUNT_ANY; 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) || urlParams.get(CS.TAGS_KEY) || urlParams.get(CS.FEE_AMOUNT_KEY) || urlParams.get(CS.LANGUAGE_KEY) ); const languageValue = searchInLanguage ? languageParam === null ? languageSetting : languageParam : languageParam === null ? CS.LANGUAGES_ALL : languageParam; const shouldHighlight = searchInLanguage ? languageParam !== languageSetting && languageParam !== null : languageParam !== CS.LANGUAGES_ALL && languageParam !== null; React.useEffect(() => { if (action !== 'POP' && isFiltered()) { setExpanded(true); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); let orderParam = orderBy || urlParams.get(CS.ORDER_BY_KEY) || defaultOrderBy; if (!orderParam) { if (action === 'POP') { // Reaching here means user have popped back to the page's entry point (e.g. '/$/tags' without any '?order='). orderParam = orderParamEntry; } else { // This is the direct entry into the page, so we load the user's previous value. orderParam = orderParamUser; } } React.useEffect(() => { setOrderParamUser(orderParam); }, [orderParam]); React.useEffect(() => { // One-time update to stash the finalized 'orderParam' at entry. if (action !== 'POP') { setOrderParamEntry(orderParam); } }, []); function handleChange(change) { const url = buildUrl(change); setPage(1); push(url); } function handleAdvancedReset() { const newUrlParams = new URLSearchParams(search); newUrlParams.delete('claim_type'); newUrlParams.delete('channel_ids'); const newSearch = `?${newUrlParams.toString()}`; push(newSearch); } 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(location.search); CS.KEYS.forEach(k => { // $FlowFixMe get() can return null if (urlParams.get(k) !== null) newUrlParams.set(k, urlParams.get(k)); }); switch (delta.key) { case CS.ORDER_BY_KEY: newUrlParams.set(CS.ORDER_BY_KEY, delta.value); break; case CS.FRESH_KEY: if (delta.value === defaultFreshness || delta.value === CS.FRESH_DEFAULT) { newUrlParams.delete(CS.FRESH_KEY); } else { newUrlParams.set(CS.FRESH_KEY, delta.value); } break; case CS.CONTENT_KEY: if (delta.value === CS.CLAIM_CHANNEL || delta.value === CS.CLAIM_REPOST) { newUrlParams.delete(CS.DURATION_KEY); newUrlParams.set(CS.CONTENT_KEY, delta.value); } else if (delta.value === CS.CONTENT_ALL) { newUrlParams.delete(CS.CONTENT_KEY); } else { newUrlParams.set(CS.CONTENT_KEY, delta.value); } break; case CS.DURATION_KEY: if (delta.value === CS.DURATION_ALL) { newUrlParams.delete(CS.DURATION_KEY); } else { newUrlParams.set(CS.DURATION_KEY, delta.value); } break; case CS.LANGUAGE_KEY: newUrlParams.set(CS.LANGUAGE_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; case CS.FEE_AMOUNT_KEY: if (delta.value === CS.FEE_AMOUNT_ANY) { newUrlParams.delete(CS.FEE_AMOUNT_KEY); } else { newUrlParams.set(CS.FEE_AMOUNT_KEY, delta.value); } break; } return `?${newUrlParams.toString()}`; } return ( <>
{!hideFilters && CS.ORDER_BY_TYPES.map(type => (
{!hideAdvancedFilter && !SIMPLE_SITE && (
{expanded && !SIMPLE_SITE && ( <>
{/* FRESHNESS FIELD */} {orderParam === CS.ORDER_BY_TOP && (
handleChange({ key: CS.FRESH_KEY, value: e.target.value, }) } > {CS.FRESH_TYPES.map(time => ( ))}
)} {/* CONTENT_TYPES FIELD */} {!claimType && (
handleChange({ key: CS.CONTENT_KEY, value: e.target.value, }) } > {CS.CONTENT_TYPES.map(type => { if (type !== CS.CLAIM_CHANNEL || (type === CS.CLAIM_CHANNEL && !channelIdsParam)) { return ( ); } })}
)} {/* LANGUAGE FIELD */} {!claimType && (
handleChange({ key: CS.LANGUAGE_KEY, value: e.target.value, }) } > {Object.entries(SEARCHABLE_LANGUAGES).map(([code, label]) => { return ( ); })}
)} {/* DURATIONS FIELD */} {showDuration && (
handleChange({ key: CS.DURATION_KEY, value: e.target.value, }) } > {CS.DURATION_TYPES.map(dur => ( ))}
)} {/* 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 => ( ))}
)} {/* PAID FIELD */}
handleChange({ key: CS.FEE_AMOUNT_KEY, value: e.target.value, }) } > ))}
{channelIdsInUrl && (
)}
)}
{hasMatureTags && hiddenNsfwMessage} ); } export default ClaimListHeader;