import { h, Component } from 'preact'; import { PropTypes } from 'preact-compat'; import debounceAction from '../utilities/debounceAction'; import { defaultState, loadNextPage, onSearchBoxType, performInitialSearch, search, toggleTag, clearSelectedTags, } from '../searchableItemList/searchableItemList'; import { ItemListItem } from './components/ItemListItem'; import { ItemListItemArchiveButton } from './components/ItemListItemArchiveButton'; import { ItemListLoadMoreButton } from './components/ItemListLoadMoreButton'; import { ItemListTags } from './components/ItemListTags'; const STATUS_VIEW_VALID = 'valid,confirmed'; const STATUS_VIEW_ARCHIVED = 'archived'; const READING_LIST_ARCHIVE_PATH = '/readinglist/archive'; const READING_LIST_PATH = '/readinglist'; const FilterText = ({ selectedTags, query, value }) => { return (

{selectedTags.length === 0 && query.length === 0 ? value : 'Nothing with this filter 🤔'}

); }; export class ReadingList extends Component { constructor(props) { super(props); const { availableTags, statusView } = this.props; this.state = defaultState({ availableTags, archiving: 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.toggleTag = toggleTag.bind(this); this.clearSelectedTags = clearSelectedTags.bind(this); } componentDidMount() { const { statusView } = this.state; this.performInitialSearch({ searchOptions: { status: `${statusView}` }, }); } toggleStatusView = (event) => { event.preventDefault(); const { query, selectedTags } = 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: [] }); this.search(query, { page: 0, tags: selectedTags, statusView: newStatusView, }); // change path in the address bar window.history.replaceState(null, null, newPath); }; toggleArchiveStatus = (event, item) => { event.preventDefault(); const { statusView, items, totalCount } = this.state; window.fetch(`/reading_list_items/${item.id}`, { method: 'PUT', headers: { 'X-CSRF-Token': window.csrfToken, 'Content-Type': 'application/json', }, body: JSON.stringify({ current_status: statusView }), credentials: 'same-origin', }); const t = this; const newItems = items; newItems.splice(newItems.indexOf(item), 1); t.setState({ archiving: true, items: newItems, totalCount: totalCount - 1, }); // hide the snackbar in a few moments setTimeout(() => { t.setState({ archiving: false }); }, 1000); }; statusViewValid() { const { statusView } = this.state; return statusView === STATUS_VIEW_VALID; } renderEmptyItems() { const { itemsLoaded, selectedTags, query } = this.state; if (itemsLoaded && this.statusViewValid()) { return (

Hit the SAVE or Bookmark 🔖 to start your Collection

); } return (
); } render() { const { items, itemsLoaded, totalCount, availableTags, selectedTags, showLoadMoreButton, archiving, } = this.state; const isStatusViewValid = this.statusViewValid(); const archiveButtonLabel = isStatusViewValid ? 'archive' : 'unarchive'; const itemsToRender = items.map((item) => { return ( this.toggleArchiveStatus(e, item)} /> ); }); const snackBar = archiving ? (
{isStatusViewValid ? 'Archiving...' : 'Unarchiving...'}
) : ( '' ); return (

my tags

{Boolean(selectedTags.length) && ( clear all )}
this.toggleStatusView(e)} data-no-instant > {isStatusViewValid ? 'View Archive' : 'View Reading List'}
{isStatusViewValid ? 'Reading List' : 'Archive'} {` (${totalCount > 0 ? totalCount : 'empty'})`}
{items.length > 0 ? itemsToRender : 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]), }; FilterText.propTypes = { selectedTags: PropTypes.arrayOf(PropTypes.string).isRequired, value: PropTypes.string.isRequired, query: PropTypes.arrayOf(PropTypes.string).isRequired, };