-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sort and search on uploads page - Improvement attempt (#3105)
* Change "Uploads" to mass fetch all claims * Reset page number when filter changes * Add sorting options and search on uploads page (Copied from playlists page) * Bring back old logic Add toggle to enable filters * Mass fetch all my uploads only once * Show info text + spinner, if loading all claims takes long * Appstring * Fix Refresh button on claim_search tabs * Creation Time -> Release Time * Use reposted claim when searching and sorting by name * Sort by name: handle numeric --------- Co-authored-by: miko <[email protected]>
- Loading branch information
Showing
13 changed files
with
650 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
export const FILTER_TYPE_KEY = 'filterType'; | ||
|
||
export const SEARCH_TERM_KEY = 'search'; | ||
|
||
export const PAGE_SIZE_ALL_ITEMS = 99999; | ||
|
||
export const FILE_TYPE = Object.freeze({ | ||
ALL: { key: 'All', cmd: 'stream,repost', label: 'All', ariaLabel: 'All uploads' }, | ||
UPLOADS: { key: 'Uploads', cmd: 'stream', label: 'Uploads' }, | ||
REPOSTS: { key: 'Reposts', cmd: 'repost', label: 'Reposts' }, | ||
UNLISTED: { key: 'Unlisted', cmd: '', label: 'Unlisted' }, | ||
SCHEDULED: { key: 'Scheduled', cmd: '', label: 'Scheduled' }, | ||
}); | ||
|
||
export const SORT_ORDER = Object.freeze({ | ||
ASC: 'asc', // ascending | ||
DESC: 'desc', // descending | ||
}); | ||
|
||
export const SORT_KEYS = Object.freeze({ | ||
NAME: 'name', | ||
RELEASED_AT: 'releasedAt', | ||
UPDATED_AT: 'updatedAt', | ||
}); | ||
|
||
export const SORT_VALUES = Object.freeze({ | ||
[SORT_KEYS.NAME]: { str: 'Name', orders: { [SORT_ORDER.ASC]: 'A-Z', [SORT_ORDER.DESC]: 'Z-A' } }, | ||
[SORT_KEYS.RELEASED_AT]: { | ||
str: 'Release Time', | ||
orders: { [SORT_ORDER.ASC]: 'Newest First', [SORT_ORDER.DESC]: 'Oldest First' }, | ||
}, | ||
[SORT_KEYS.UPDATED_AT]: { | ||
str: 'Updated Time', | ||
orders: { [SORT_ORDER.ASC]: 'Newest First', [SORT_ORDER.DESC]: 'Oldest First' }, | ||
}, | ||
}); | ||
|
||
export const METHOD = Object.freeze({ | ||
CLAIM_LIST: 'CLAIM_LIST', | ||
CLAIM_SEARCH: 'CLAIM_SEARCH', | ||
}); | ||
|
||
export const DEFAULT_SORT = { key: SORT_KEYS.UPDATED_AT, value: SORT_ORDER.ASC }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
ui/page/fileListPublished/internal/fileListHeader/index.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// @flow | ||
import React from 'react'; | ||
import Button from 'component/button'; | ||
import * as FILE_LIST from 'constants/file_list'; | ||
import { FileListContext } from 'page/fileListPublished/view'; | ||
import classnames from 'classnames'; | ||
import { FormField } from 'component/common/form'; | ||
import { useHistory } from 'react-router'; | ||
import RightSideActions from './internal/rightSideActions/index'; | ||
|
||
type Props = { | ||
filterType: string, | ||
sortOption: { key: string, value: string }, | ||
setFilterType: (type: string) => void, | ||
setSortOption: (params: { key: string, value: string }) => void, | ||
}; | ||
|
||
export default function ClaimListHeader(props: Props) { | ||
const { filterType, sortOption, setFilterType, setSortOption } = props; | ||
|
||
const { isFilteringEnabled } = React.useContext(FileListContext); | ||
|
||
const history = useHistory(); | ||
const { | ||
location: { search }, | ||
} = history; | ||
|
||
const urlParams = new URLSearchParams(search); | ||
|
||
function handleChange(sortObj) { | ||
// can only have one sorting option at a time | ||
Object.keys(FILE_LIST.SORT_VALUES).forEach((k) => urlParams.get(k) && urlParams.delete(k)); | ||
|
||
urlParams.set(sortObj.key, sortObj.value); | ||
setSortOption(sortObj); | ||
|
||
const url = `?${urlParams.toString()}`; | ||
history.push(url); | ||
} | ||
|
||
function handleFilterTypeChange(value) { | ||
urlParams.set(FILE_LIST.FILTER_TYPE_KEY, value); | ||
setFilterType(value); | ||
|
||
const url = `?${urlParams.toString()}`; | ||
history.push(url); | ||
} | ||
|
||
return ( | ||
<div className="section__header-action-stack"> | ||
<div className="section__header--actions"> | ||
<div className="claim-search__wrapper--wrap"> | ||
{/* Filter Options */} | ||
<div className="claim-search__menu-group"> | ||
<div className="claim-search__menu-subgroup"> | ||
{/* $FlowFixMe */} | ||
{Object.values(FILE_LIST.FILE_TYPE).map((info: FilterInfo) => ( | ||
<Button | ||
button="alt" | ||
key={info.label} | ||
label={__(info.label)} | ||
aria-label={info.ariaLabel} | ||
onClick={() => handleFilterTypeChange(info.key)} | ||
className={classnames(`button-toggle`, { 'button-toggle--active': filterType === info.key })} | ||
/> | ||
))} | ||
</div> | ||
{isFilteringEnabled && ( | ||
<div className="claim-search__menu-subgroup"> | ||
<FormField | ||
className="claim-search__dropdown" | ||
type="select" | ||
name="sort_by" | ||
value={sortOption.key} | ||
onChange={(e) => handleChange({ key: e.target.value, value: FILE_LIST.SORT_ORDER.ASC })} | ||
> | ||
{Object.entries(FILE_LIST.SORT_VALUES).map(([key, value]) => ( | ||
<option key={key} value={key}> | ||
{/* $FlowFixMe */} | ||
{__(value.str)} | ||
</option> | ||
))} | ||
</FormField> | ||
<FormField | ||
className="claim-search__dropdown" | ||
type="select" | ||
name="order_by" | ||
value={sortOption.value} | ||
onChange={(e) => handleChange({ key: sortOption.key, value: e.target.value })} | ||
> | ||
{Object.entries(FILE_LIST.SORT_ORDER).map(([key, value]) => ( | ||
// $FlowFixMe | ||
<option key={value} value={value}> | ||
{__(FILE_LIST.SORT_VALUES[sortOption.key].orders[value])} | ||
</option> | ||
))} | ||
</FormField> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
|
||
<RightSideActions /> | ||
</div> | ||
</div> | ||
); | ||
} |
10 changes: 10 additions & 0 deletions
10
ui/page/fileListPublished/internal/fileListHeader/internal/rightSideActions/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { connect } from 'react-redux'; | ||
import { doClearClaimSearch, doFetchClaimListMine } from 'redux/actions/claims'; | ||
import RightSideActions from './view'; | ||
|
||
const perform = { | ||
doClearClaimSearch, | ||
fetchClaimListMine: doFetchClaimListMine, | ||
}; | ||
|
||
export default connect(null, perform)(RightSideActions); |
106 changes: 106 additions & 0 deletions
106
ui/page/fileListPublished/internal/fileListHeader/internal/rightSideActions/view.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// @flow | ||
import type { DoFetchClaimListMine } from 'redux/actions/claims'; | ||
|
||
import React from 'react'; | ||
import { FormField, Form } from 'component/common/form'; | ||
import { useHistory } from 'react-router'; | ||
import { FileListContext } from 'page/fileListPublished/view'; | ||
import * as FILE_LIST from 'constants/file_list'; | ||
import * as KEYCODES from 'constants/keycodes'; | ||
import * as ICONS from 'constants/icons'; | ||
import Icon from 'component/common/icon'; | ||
import Button from 'component/button'; | ||
|
||
type Props = { | ||
// -- redux -- | ||
fetchClaimListMine: DoFetchClaimListMine, | ||
doClearClaimSearch: () => void, | ||
}; | ||
|
||
const RightSideActions = (props: Props) => { | ||
const { fetchClaimListMine, doClearClaimSearch } = props; | ||
const { searchText, setSearchText, isFilteringEnabled, setIsFilteringEnabled, fetching, method } = | ||
React.useContext(FileListContext); | ||
|
||
const history = useHistory(); | ||
const { | ||
location: { search }, | ||
} = history; | ||
const urlParams = new URLSearchParams(search); | ||
|
||
function handleSearchTextChange(value) { | ||
setSearchText(value); | ||
|
||
if (value === '') { | ||
urlParams.get(FILE_LIST.SEARCH_TERM_KEY) && urlParams.delete(FILE_LIST.SEARCH_TERM_KEY); | ||
} else { | ||
urlParams.set(FILE_LIST.SEARCH_TERM_KEY, value); | ||
} | ||
|
||
const url = `?${urlParams.toString()}`; | ||
history.push(url); | ||
} | ||
|
||
function escapeListener(e: SyntheticKeyboardEvent<*>) { | ||
if (e.keyCode === KEYCODES.ESCAPE) { | ||
e.preventDefault(); | ||
setSearchText(''); | ||
} | ||
} | ||
|
||
function onTextareaFocus() { | ||
window.addEventListener('keydown', escapeListener); | ||
} | ||
|
||
function onTextareaBlur() { | ||
window.removeEventListener('keydown', escapeListener); | ||
} | ||
|
||
return ( | ||
<div className="claim-search__wrapper--wrap"> | ||
{/* Search Field */} | ||
<div className="claim-search__menu-group"> | ||
{isFilteringEnabled && ( | ||
<Form onSubmit={() => {}} className="wunderbar--inline"> | ||
<Icon icon={ICONS.SEARCH} /> | ||
<FormField | ||
name="collection_search" | ||
onFocus={onTextareaFocus} | ||
onBlur={onTextareaBlur} | ||
className="wunderbar__input--inline" | ||
value={searchText} | ||
onChange={(e) => handleSearchTextChange(e.target.value)} | ||
type="text" | ||
placeholder={__('Search')} | ||
/> | ||
</Form> | ||
)} | ||
<div className="claim-search__menu-group enable-filters-checkbox"> | ||
<FormField | ||
label={__('Enable filters')} | ||
name="enable_filters" | ||
type="checkbox" | ||
checked={isFilteringEnabled} | ||
onChange={() => setIsFilteringEnabled(!isFilteringEnabled)} | ||
/> | ||
</div> | ||
</div> | ||
{/* Playlist Create Button */} | ||
<Button | ||
button="alt" | ||
label={__('Refresh')} | ||
disabled={fetching} | ||
icon={ICONS.REFRESH} | ||
onClick={() => { | ||
if (method === FILE_LIST.METHOD.CLAIM_LIST) { | ||
fetchClaimListMine(1, FILE_LIST.PAGE_SIZE_ALL_ITEMS, true, [], true); | ||
} else { | ||
doClearClaimSearch(); | ||
} | ||
}} | ||
/>{' '} | ||
</div> | ||
); | ||
}; | ||
|
||
export default RightSideActions; |
Oops, something went wrong.