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:
parent
67d9f3907f
commit
30fedf6b45
3 changed files with 68 additions and 11 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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';
|
||||||
|
|
Loading…
Reference in a new issue