// Used in the reading list 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, skipPushState } = event.target; const selectedTagOrAll = value ?? dataset.tag; const selectedTag = selectedTagOrAll?.match(/all tags/i) ? null : selectedTagOrAll; const component = this; const { query, statusView } = component.state; component.setState({ selectedTag, page: 0, items: [] }); component.search(query, { tags: selectedTag ? [selectedTag] : [], statusView, appendItems: false, }); // persist the selected tag in query params if (!skipPushState) { const newQueryParams = selectedTag ? `?selectedTag=${selectedTag}` : ''; window.history.pushState(null, null, `/readinglist${newQueryParams}`); } } 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 async 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 ? [selectedTag] : [], statusView, appendItems: true, }); } export function checkForPersistedTag(availableTags) { // credit: https://stackoverflow.com/a/9870540 const params = (new URL(window.location)).searchParams const selectedTag = params.get('selectedTag'); if (availableTags?.includes(selectedTag)) return selectedTag; return null; }