// @flow import * as CS from 'constants/claim_search'; import * as ICONS from 'constants/icons'; import * as SETTINGS from 'constants/settings'; 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 { 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, freshness?: string, defaultFreshness?: string, claimType?: Array, streamType?: string | Array, defaultStreamType?: string | Array, feeAmount: string, sortBy?: string, orderBy?: Array, defaultOrderBy?: string, hideAdvancedFilter: boolean, hideLayoutButton: boolean, hasMatureTags: boolean, hiddenNsfwMessage?: Node, channelIds?: Array, tileLayout: boolean, doSetClientSetting: (string, boolean, ?boolean) => void, setPage: (number) => void, hideFilters: boolean, searchInLanguage: boolean, languageSetting: string, scrollAnchor?: string, }; function ClaimListHeader(props: Props) { const { defaultTags, freshness, defaultFreshness, claimType, streamType, defaultStreamType, feeAmount, sortBy, orderBy, defaultOrderBy, hideAdvancedFilter, hideLayoutButton, hasMatureTags, hiddenNsfwMessage, channelIds, tileLayout, doSetClientSetting, setPage, hideFilters, searchInLanguage, languageSetting, scrollAnchor, } = 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 urlParams = new URLSearchParams(search); 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 sortByParam = sortBy || urlParams.get(CS.SORT_BY_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 && claimType === CS.CLAIM_COLLECTION); 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 }, []); React.useEffect(() => { if (hideAdvancedFilter) { setExpanded(false); } // 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, setOrderParamUser]); React.useEffect(() => { // One-time update to stash the finalized 'orderParam' at entry. if (action !== 'POP') { setOrderParamEntry(orderParam); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); 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 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.SORT_BY_KEY: if (delta.value === CS.SORT_BY.NEWEST.key) { newUrlParams.delete(CS.SORT_BY_KEY); } else { newUrlParams.set(CS.SORT_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 || delta.value === CS.CLAIM_COLLECTION ) { 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()}` + (scrollAnchor ? '#' + scrollAnchor : ''); } return ( <>
{!hideFilters && (
{CS.ORDER_BY_TYPES.map((type) => (
)}
{!hideAdvancedFilter && (
{expanded && ( <>
{/* 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) => ( ))}
)} {/* PAID FIELD */}
handleChange({ key: CS.FEE_AMOUNT_KEY, value: e.target.value, }) } > ))}
{/* SORT FIELD */} {orderParam === CS.ORDER_BY_NEW && (
handleChange({ key: CS.SORT_BY_KEY, value: e.target.value })} > {Object.entries(CS.SORT_BY).map(([key, value]) => { return ( // $FlowFixMe https://github.com/facebook/flow/issues/2221 ); })}
)} {channelIdsInUrl && (
)}
)}
{hasMatureTags && hiddenNsfwMessage} ); } export default ClaimListHeader;