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,
tileLayout: boolean,
orderBy?: Array<string>,
orderBy?: Array<string>, // Trending, New, Top
defaultOrderBy?: string,
sortBy?: Array<string>, // Newest First, Oldest First
freshness?: string,
defaultFreshness?: string,
@ -115,6 +116,7 @@ function ClaimListDiscover(props: Props) {
blockedUris,
hiddenNsfwMessage,
defaultOrderBy,
sortBy,
orderBy,
headerLabel,
header,
@ -170,6 +172,7 @@ function ClaimListDiscover(props: Props) {
(urlParams.get(CS.TAGS_KEY) !== null && urlParams.get(CS.TAGS_KEY)) ||
(defaultTags && getParamFromTags(defaultTags));
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(
new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1]))
);
@ -255,12 +258,7 @@ function ClaimListDiscover(props: Props) {
no_totals: true,
not_channel_ids: isChannel ? undefined : mutedAndBlockedChannelIds,
not_tags: !showNsfw ? MATURE_TAGS : [],
order_by:
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
order_by: resolveOrderByOption(orderParam, sortByParam),
};
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
import { SIMPLE_SITE } from 'config';
import * as CS from 'constants/claim_search';
import * as ICONS from 'constants/icons';
import type { Node } from 'react';
@ -21,6 +20,7 @@ type Props = {
streamType?: string | Array<string>,
defaultStreamType?: string | Array<string>,
feeAmount: string,
sortBy?: string,
orderBy?: Array<string>,
defaultOrderBy?: string,
hideAdvancedFilter: boolean,
@ -45,6 +45,7 @@ function ClaimListHeader(props: Props) {
streamType,
defaultStreamType,
feeAmount,
sortBy,
orderBy,
defaultOrderBy,
hideAdvancedFilter,
@ -71,6 +72,7 @@ function ClaimListHeader(props: Props) {
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;
@ -153,6 +155,13 @@ function ClaimListHeader(props: Props) {
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);
@ -240,7 +249,7 @@ function ClaimListHeader(props: Props) {
</div>
)}
<div className="claim-search__menu-group">
{!hideAdvancedFilter && !SIMPLE_SITE && (
{!hideAdvancedFilter && (
<Button
button="alt"
aria-label={__('More')}
@ -266,7 +275,7 @@ function ClaimListHeader(props: Props) {
)}
</div>
</div>
{expanded && !SIMPLE_SITE && (
{expanded && (
<>
<div className={classnames(`card claim-search__menus`)}>
{/* FRESHNESS FIELD */}
@ -449,6 +458,32 @@ function ClaimListHeader(props: Props) {
</FormField>
</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 && (
<div className={'claim-search__input-container'}>
<label>{__('Advanced Filters from URL')}</label>

View file

@ -1,7 +1,8 @@
export const PAGE_SIZE = 20;
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 LANGUAGE_KEY = 'language';
export const TAGS_KEY = 't';
@ -39,6 +40,14 @@ export const DURATION_LONG = 'long';
export const DURATION_ALL = 'all';
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_AUDIO = 'audio';
export const FILE_DOCUMENT = 'document';