Channel Page: enable filters; add "sort by" filter (#7069)

* Sort props to clarify "client vs. redux". No functional change.

* ClaimListHeader: remove SIMPLE_SITE gating

* Channel Page: enable filters; add "sort by" filter.

## Issue
7059 Add option to sort oldest first on channel page

## Changes
- Enabled filters for Odysee.
- Added a new "Sort By" filter, which will only appear for "New" ordering. It doesn't make sense for "Trending" or "Top".
This commit is contained in:
infinite-persistence 2021-09-13 23:23:53 +08:00 committed by GitHub
parent 67d9f3907f
commit 30fedf6b45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 11 deletions

View file

@ -38,8 +38,9 @@ type Props = {
showNoSourceClaims?: boolean, showNoSourceClaims?: boolean,
tileLayout: boolean, tileLayout: boolean,
orderBy?: Array<string>, orderBy?: Array<string>, // Trending, New, Top
defaultOrderBy?: string, defaultOrderBy?: string,
sortBy?: Array<string>, // Newest First, Oldest First
freshness?: string, freshness?: string,
defaultFreshness?: string, defaultFreshness?: string,
@ -115,6 +116,7 @@ function ClaimListDiscover(props: Props) {
blockedUris, blockedUris,
hiddenNsfwMessage, hiddenNsfwMessage,
defaultOrderBy, defaultOrderBy,
sortBy,
orderBy, orderBy,
headerLabel, headerLabel,
header, header,
@ -170,6 +172,7 @@ function ClaimListDiscover(props: Props) {
(urlParams.get(CS.TAGS_KEY) !== null && urlParams.get(CS.TAGS_KEY)) || (urlParams.get(CS.TAGS_KEY) !== null && urlParams.get(CS.TAGS_KEY)) ||
(defaultTags && getParamFromTags(defaultTags)); (defaultTags && getParamFromTags(defaultTags));
const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness; const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness;
const sortByParam = sortBy || urlParams.get(CS.SORT_BY_KEY) || CS.SORT_BY.NEWEST.key;
const mutedAndBlockedChannelIds = Array.from( const mutedAndBlockedChannelIds = Array.from(
new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1])) new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1]))
); );
@ -255,12 +258,7 @@ function ClaimListDiscover(props: Props) {
no_totals: true, no_totals: true,
not_channel_ids: isChannel ? undefined : mutedAndBlockedChannelIds, not_channel_ids: isChannel ? undefined : mutedAndBlockedChannelIds,
not_tags: !showNsfw ? MATURE_TAGS : [], not_tags: !showNsfw ? MATURE_TAGS : [],
order_by: order_by: resolveOrderByOption(orderParam, sortByParam),
orderParam === CS.ORDER_BY_TRENDING
? CS.ORDER_BY_TRENDING_VALUE
: orderParam === CS.ORDER_BY_NEW
? CS.ORDER_BY_NEW_VALUE
: CS.ORDER_BY_TOP_VALUE, // Sort by top
}; };
if (ENABLE_NO_SOURCE_CLAIMS && hasNoSource) { if (ENABLE_NO_SOURCE_CLAIMS && hasNoSource) {
@ -551,6 +549,21 @@ function ClaimListDiscover(props: Props) {
} }
} }
function resolveOrderByOption(orderBy: string | Array<string>, sortBy: string | Array<string>) {
const order_by =
orderBy === CS.ORDER_BY_TRENDING
? CS.ORDER_BY_TRENDING_VALUE
: orderBy === CS.ORDER_BY_NEW
? CS.ORDER_BY_NEW_VALUE
: CS.ORDER_BY_TOP_VALUE;
if (orderBy === CS.ORDER_BY_NEW && sortBy === CS.SORT_BY.OLDEST.key) {
return order_by.map((x) => `${CS.SORT_BY.OLDEST.opt}${x}`);
}
return order_by;
}
// ************************************************************************** // **************************************************************************
// ************************************************************************** // **************************************************************************

View file

@ -1,5 +1,4 @@
// @flow // @flow
import { SIMPLE_SITE } from 'config';
import * as CS from 'constants/claim_search'; import * as CS from 'constants/claim_search';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import type { Node } from 'react'; import type { Node } from 'react';
@ -21,6 +20,7 @@ type Props = {
streamType?: string | Array<string>, streamType?: string | Array<string>,
defaultStreamType?: string | Array<string>, defaultStreamType?: string | Array<string>,
feeAmount: string, feeAmount: string,
sortBy?: string,
orderBy?: Array<string>, orderBy?: Array<string>,
defaultOrderBy?: string, defaultOrderBy?: string,
hideAdvancedFilter: boolean, hideAdvancedFilter: boolean,
@ -45,6 +45,7 @@ function ClaimListHeader(props: Props) {
streamType, streamType,
defaultStreamType, defaultStreamType,
feeAmount, feeAmount,
sortBy,
orderBy, orderBy,
defaultOrderBy, defaultOrderBy,
hideAdvancedFilter, hideAdvancedFilter,
@ -71,6 +72,7 @@ function ClaimListHeader(props: Props) {
streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null; streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null;
const durationParam = urlParams.get(CS.DURATION_KEY) || null; const durationParam = urlParams.get(CS.DURATION_KEY) || null;
const languageParam = urlParams.get(CS.LANGUAGE_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 channelIdsInUrl = urlParams.get(CS.CHANNEL_IDS_KEY);
const channelIdsParam = channelIdsInUrl ? channelIdsInUrl.split(',') : channelIds; const channelIdsParam = channelIdsInUrl ? channelIdsInUrl.split(',') : channelIds;
const feeAmountParam = urlParams.get('fee_amount') || feeAmount || CS.FEE_AMOUNT_ANY; const feeAmountParam = urlParams.get('fee_amount') || feeAmount || CS.FEE_AMOUNT_ANY;
@ -153,6 +155,13 @@ function ClaimListHeader(props: Props) {
case CS.ORDER_BY_KEY: case CS.ORDER_BY_KEY:
newUrlParams.set(CS.ORDER_BY_KEY, delta.value); newUrlParams.set(CS.ORDER_BY_KEY, delta.value);
break; 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: case CS.FRESH_KEY:
if (delta.value === defaultFreshness || delta.value === CS.FRESH_DEFAULT) { if (delta.value === defaultFreshness || delta.value === CS.FRESH_DEFAULT) {
newUrlParams.delete(CS.FRESH_KEY); newUrlParams.delete(CS.FRESH_KEY);
@ -240,7 +249,7 @@ function ClaimListHeader(props: Props) {
</div> </div>
)} )}
<div className="claim-search__menu-group"> <div className="claim-search__menu-group">
{!hideAdvancedFilter && !SIMPLE_SITE && ( {!hideAdvancedFilter && (
<Button <Button
button="alt" button="alt"
aria-label={__('More')} aria-label={__('More')}
@ -266,7 +275,7 @@ function ClaimListHeader(props: Props) {
)} )}
</div> </div>
</div> </div>
{expanded && !SIMPLE_SITE && ( {expanded && (
<> <>
<div className={classnames(`card claim-search__menus`)}> <div className={classnames(`card claim-search__menus`)}>
{/* FRESHNESS FIELD */} {/* FRESHNESS FIELD */}
@ -449,6 +458,32 @@ function ClaimListHeader(props: Props) {
</FormField> </FormField>
</div> </div>
{/* SORT FIELD */}
{orderParam === CS.ORDER_BY_NEW && (
<div className={'claim-search__input-container'}>
<FormField
className={classnames('claim-search__dropdown', {
'claim-search__dropdown--selected': sortByParam,
})}
label={__('Sort By')}
type="select"
name="sort_by"
value={sortByParam || CS.SORT_BY.NEWEST.key}
onChange={(e) => 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
<option key={value.key} value={value.key}>
{/* $FlowFixMe */}
{__(value.str)}
</option>
);
})}
</FormField>
</div>
)}
{channelIdsInUrl && ( {channelIdsInUrl && (
<div className={'claim-search__input-container'}> <div className={'claim-search__input-container'}>
<label>{__('Advanced Filters from URL')}</label> <label>{__('Advanced Filters from URL')}</label>

View file

@ -1,7 +1,8 @@
export const PAGE_SIZE = 20; export const PAGE_SIZE = 20;
export const FRESH_KEY = 'fresh'; export const FRESH_KEY = 'fresh';
export const ORDER_BY_KEY = 'order'; export const ORDER_BY_KEY = 'order'; // Trending, Top, New
export const SORT_BY_KEY = 'sort'; // Newest vs Oldest First
export const DURATION_KEY = 'duration'; export const DURATION_KEY = 'duration';
export const LANGUAGE_KEY = 'language'; export const LANGUAGE_KEY = 'language';
export const TAGS_KEY = 't'; export const TAGS_KEY = 't';
@ -39,6 +40,14 @@ export const DURATION_LONG = 'long';
export const DURATION_ALL = 'all'; export const DURATION_ALL = 'all';
export const DURATION_TYPES = [DURATION_ALL, DURATION_SHORT, DURATION_LONG]; export const DURATION_TYPES = [DURATION_ALL, DURATION_SHORT, DURATION_LONG];
export const SORT_BY = {
// key: Enumeration; can be anything as long as unique. Also used as URLParam.
// opt: Value to use for 'claim_search' options; for this case, it is the prefix to 'order_by'.
// str: Customer-facing string representation.
NEWEST: { key: 'new', opt: '', str: 'Newest first' },
OLDEST: { key: 'old', opt: '^', str: 'Oldest first' },
};
export const FILE_VIDEO = 'video'; export const FILE_VIDEO = 'video';
export const FILE_AUDIO = 'audio'; export const FILE_AUDIO = 'audio';
export const FILE_DOCUMENT = 'document'; export const FILE_DOCUMENT = 'document';