import { h, Component, Fragment } from 'preact'; import PropTypes from 'prop-types'; import { loadNextPage, onSearchBoxType, performInitialSearch, search, selectTag, clearSelectedTags, } from '../searchableItemList/searchableItemList'; import { ItemListItem } from './components/ItemListItem'; import { ItemListItemArchiveButton } from './components/ItemListItemArchiveButton'; import { TagList } from './components/TagList'; import { MediaQuery } from '@components/MediaQuery'; import { BREAKPOINTS } from '@components/useMediaQuery'; import { debounceAction } from '@utilities/debounceAction'; import { Button } from '@crayons'; import { request } from '@utilities/http'; const NO_RESULTS_WITH_FILTER_MESSAGE = 'Nothing with this filter 🤔'; const STATUS_VIEW_VALID = 'valid,confirmed'; const STATUS_VIEW_ARCHIVED = 'archived'; const READING_LIST_ARCHIVE_PATH = '/readinglist/archive'; const READING_LIST_PATH = '/readinglist'; function ItemList({ items, archiveButtonLabel, toggleArchiveStatus }) { return items.map((item) => { return ( toggleArchiveStatus(e, item)} /> ); }); } export class ReadingList extends Component { constructor(props) { super(props); const { statusView } = this.props; this.state = { archiving: false, query: '', index: null, page: 0, hitsPerPage: 80, items: [], itemsLoaded: false, itemsTotal: 0, availableTags: [], selectedTag: '', showLoadMoreButton: false, statusView, }; // bind and initialize all shared functions this.onSearchBoxType = debounceAction(onSearchBoxType.bind(this), { leading: true, }); this.loadNextPage = loadNextPage.bind(this); this.performInitialSearch = performInitialSearch.bind(this); this.search = search.bind(this); this.selectTag = selectTag.bind(this); this.clearSelectedTags = clearSelectedTags.bind(this); } componentDidMount() { const { statusView } = this.state; this.performInitialSearch({ searchOptions: { status: `${statusView}` }, }); } toggleStatusView = (event) => { event.preventDefault(); const { query, selectedTag } = this.state; const isStatusViewValid = this.statusViewValid(); const newStatusView = isStatusViewValid ? STATUS_VIEW_ARCHIVED : STATUS_VIEW_VALID; const newPath = isStatusViewValid ? READING_LIST_ARCHIVE_PATH : READING_LIST_PATH; // empty items so that changing the view will start from scratch this.setState({ statusView: newStatusView, items: [], selectedTag }); this.search(query, { page: 0, tags: selectedTag ? [selectedTag] : [], statusView: newStatusView, }); // change path in the address bar window.history.replaceState(null, null, newPath); }; toggleArchiveStatus = (event, item) => { event.preventDefault(); const { statusView, items } = this.state; request(`/reading_list_items/${item.id}`, { method: 'PUT', body: { current_status: statusView }, }); const newItems = items; newItems.splice(newItems.indexOf(item), 1); this.setState({ archiving: true, items: newItems, }); // hide the snackbar in a few moments setTimeout(() => { this.setState({ archiving: false }); }, 1000); }; statusViewValid() { const { statusView } = this.state; return statusView === STATUS_VIEW_VALID; } renderEmptyItems() { const { itemsLoaded, selectedTag = '', query } = this.state; const showMessage = selectedTag.length === 0 && query.length === 0; if (itemsLoaded && this.statusViewValid()) { return (

{showMessage ? 'Your reading list is empty' : NO_RESULTS_WITH_FILTER_MESSAGE}

Click the{' '} bookmark reaction when viewing a post to add it to your reading list.

); } return (

{showMessage ? 'Your Archive is empty...' : NO_RESULTS_WITH_FILTER_MESSAGE}

); } render() { const { items = [], itemsTotal, availableTags, selectedTag = '', showLoadMoreButton, archiving, loading = false, } = this.state; const isStatusViewValid = this.statusViewValid(); const archiveButtonLabel = isStatusViewValid ? 'Archive' : 'Unarchive'; const snackBar = archiving ? (
{isStatusViewValid ? 'Archiving...' : 'Unarchiving...'}
) : ( '' ); return (

{isStatusViewValid ? 'Reading list' : 'Archive'} {` (${itemsTotal})`}

Filter { return ( matches && ( ) ); }} />
{ return (
{matches && (
)}
{items.length > 0 ? ( {showLoadMoreButton && (
)}
) : loading ? null : ( this.renderEmptyItems() )}
); }} /> {snackBar}
); } } ReadingList.defaultProps = { statusView: STATUS_VIEW_VALID, }; ReadingList.propTypes = { availableTags: PropTypes.arrayOf(PropTypes.string).isRequired, statusView: PropTypes.oneOf([STATUS_VIEW_VALID, STATUS_VIEW_ARCHIVED]), };