docbrown/app/javascript/searchableItemList/searchableItemList.js
Nick Taylor 86deddbb75
Fixed Reading List on Mobile + Small Improvements (#12755)
* Some div soup to semantic markup.

* Small refactor to inline mapping of available tags.

* Renamed <ItemListTags /> component to <TagList />.

* Now a select is used for picking a tag to filter on.

* Added custom Cypress command to create an article.

* Added documentation for the create article custom command.

* Removed unnecesary properties from payload to create an article.

* reading list mobile view wip.

* Reworked styles in <TagList />.

* Reworked reading list to use <MediaQuery /> component.

* Removed bottom padding from reading list header.

* styling tweaks if there are no available tags.

* Added some E2E tests.

* Removed reading list component test in favour of e2e test.

* Made breakpoint values numbers.

* Added some padding and more grid gap to filter on small screens.

* Adjusted jest coverage thresholds as we're moving some tests to e2e tests.

* Reverting a VS Code setting change caused by one of my extensions.

* First pass for E2E tests for the reading list.

* Added some more grid gap.

* Fixed load next page to send tags properly.

* Added some more tests.

* Improved label and placeholder for text filter in reading list.

* Added more tests

* Fixed media queries so it works in Chrome as well.

* Removed aside as tag filters are not complimentary information.

* Update app/javascript/readingList/components/TagList.jsx

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Update docs/tests/e2e-tests.md

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Turned off deprecated rule in jsx-a11y eslint plugin.

* Reverted to links instead of radio buttons.

* Added an all tags link and select option.

* Fixed relayout issue.

* Fixed View Archive button size.

* Fixed styling of the load more button.

* Fixed empty list issue toggling between archive and reading list.

* Fixed request changes from PR review.

* Removed CSS change that is no longer required.

* Trigger Build

* Fixed centering of items in top fieldset.

* Fixed issue with search text field resetting reading list.

* Fixed component tests for the reading list.

* Fixed empty state popping up between search queries.

* Fixed casing of fixture filenames.

* Update app/javascript/readingList/readingList.jsx

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>

* Reverted change in reading list component test.

* Added missing JSDoc comment.

* Now links are in an unordered list.

* Promoted some CSS classes from the <nav /> to the <ul /> for spacing.

Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
2021-04-08 12:53:43 +01:00

137 lines
3.7 KiB
JavaScript

// Shared behavior between the reading list and history pages
import { fetchSearch } from '../utilities/search';
// Starts the search when the user types in the search box
export function onSearchBoxType(event) {
const component = this;
const query = event.target.value;
const { selectedTag, statusView } = component.state;
component.setState({ page: 0 });
component.search(query, {
tags: selectedTag ? [selectedTag] : [],
statusView,
appendItems: false,
});
}
export function selectTag(event) {
event.preventDefault();
const { value, dataset } = event.target;
const selectedTag = value ?? dataset.tag;
const component = this;
const { query, statusView } = component.state;
component.setState({ selectedTag, page: 0, items: [] });
component.search(query, {
tags: selectedTag ? [selectedTag] : [],
statusView,
appendItems: false,
});
}
export function clearSelectedTags(event) {
event.preventDefault();
const component = this;
const { query, statusView } = component.state;
component.setState({ selectedTag: '', page: 0, items: [] });
component.search(query, { tags: [], statusView, appendItems: false });
}
// Perform the initial search
export function performInitialSearch({ searchOptions = {} }) {
const component = this;
const { hitsPerPage } = component.state;
const dataHash = { page: 0, per_page: hitsPerPage };
component.setState({ loading: true });
if (searchOptions.status) {
dataHash.status = searchOptions.status.split(',');
}
const responsePromise = fetchSearch('reactions', dataHash);
return responsePromise.then((response) => {
const reactions = response.result;
// FIXME: [@rhymes] the list of tags in the left column of the reading list
// is populated with only the tags belonging to items in the first page
const availableTags = [
...new Set(reactions.flatMap((rxn) => rxn.reactable.tag_list)),
].sort();
component.setState({
page: 0,
items: reactions,
itemsLoaded: true,
itemsTotal: response.total,
showLoadMoreButton: hitsPerPage < response.total,
availableTags,
loading: false,
});
});
}
// Main search function
export function search(query, { page, tags, statusView, appendItems = false }) {
const component = this;
component.setState({ loading: true });
// allow the page number to come from the calling function
// we check `undefined` because page can be 0
const newPage = page === undefined ? component.state.page : page;
const { hitsPerPage, items: existingItems } = component.state;
const dataHash = {
search_fields: query,
page: newPage,
per_page: hitsPerPage,
};
if (tags && tags.length > 0) {
dataHash.tag_names = tags;
dataHash.tag_boolean_mode = 'all';
}
if (statusView) {
dataHash.status = statusView.split(',');
}
const responsePromise = fetchSearch('reactions', dataHash);
return responsePromise.then((response) => {
const reactions = response.result;
let items;
if (appendItems) {
// we append the new reactions at the bottom of the list, for pagination
items = [...existingItems, ...reactions];
} else {
items = reactions;
}
component.setState({
query,
page: newPage,
items,
itemsTotal: response.total,
showLoadMoreButton: items.length < response.total,
loading: false,
});
});
}
// Retrieve the results in the next page
export function loadNextPage() {
const component = this;
const { query, selectedTag, page, statusView } = component.state;
component.setState({ page: page + 1 });
component.search(query, {
page: page + 1,
tags: [selectedTag],
statusView,
appendItems: true,
});
}