require('./vaultPage.less'); const React = require('react'); const { useState, useEffect, useRef } = React; const cx = require('classnames'); const Nav = require('naturalcrit/nav/nav.jsx'); const Navbar = require('../../navbar/navbar.jsx'); const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; const Account = require('../../navbar/account.navitem.jsx'); const NewBrew = require('../../navbar/newbrew.navitem.jsx'); const HelpNavItem = require('../../navbar/help.navitem.jsx'); const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx'); const SplitPane = require('../../../../shared/naturalcrit/splitPane/splitPane.jsx'); const request = require('../../utils/request-middleware.js'); const VaultPage = (props) => { const [title, setTitle] = useState(props.query.title || ''); //state author const [author, setAuthor] = useState(props.query.author || ''); const [legacy, setLegacy] = useState(props.query.legacy !== 'false'); const [v3, setV3] = useState(props.query.v3 !== 'false'); const [count, setCount] = useState(props.query.count || 20); const [page, setPage] = useState(parseInt(props.query.page) || 1); const [brewCollection, setBrewCollection] = useState(null); const [totalBrews, setTotalBrews] = useState(null); const [searching, setSearching] = useState(false); const [error, setError] = useState(null); const titleRef = useRef(null); const authorRef = useRef(null); const countRef = useRef(null); const v3Ref = useRef(null); const legacyRef = useRef(null); const searchButtonRef = useRef(null); useEffect(() => { disableSubmitIfFormInvalid(); loadPage(page, false, true); }, []); const updateStateWithBrews = (brews, page) => { setBrewCollection(brews || null); setPage(parseInt(page) || 1); setSearching(false); }; const updateUrl = (title, author, count, v3, legacy, page) => { const url = new URL(window.location.href); const urlParams = new URLSearchParams(); Object.entries({ title, author, count, v3, legacy, page, }).forEach(([key, value]) => urlParams.set(key, value)); url.search = urlParams.toString(); window.history.replaceState(null, null, url); }; const loadPage = async (page, update, total) => { //Different searches use the update or total props to make only the necessary queries and functions if (!validateForm()) { console.log( 'Invalid search, title should be more than 3 characters, or an author specified, and at least one renderer specified.' ); return; } setSearching(true); setError(null); const performSearch = async ({ title, author, count, v3, legacy }) => { updateUrl(title, author, count, v3, legacy, page); if ((title || author) && (v3 || legacy)) { try { const response = await request.get( `/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&count=${count}&page=${page}` ); if (response.ok) { updateStateWithBrews(response.body.brews, page); } else { throw new Error(`Error: ${response.status}`); } } catch (error) { console.log('error at loadPage: ', error); setError( `${ error.response ? error.response.status : error.message }` ); updateStateWithBrews([], 1); } } else { setError('404'); } }; const loadTotal = async ({ title, v3, legacy }) => { setTotalBrews(null); setError(null); if ((title || author) && (v3 || legacy)) { try { const response = await request.get( `/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}` ); if (response.ok) { setTotalBrews(response.body.totalBrews); } else { throw new Error( `Failed to load total brews: ${response.statusText}` ); } } catch (error) { console.log('error at loadTotal: ', error); setError(`${error.response.status}`); updateStateWithBrews([], 1); } } }; const titleValue = titleRef.current.value || ''; const authorValue = authorRef.current.value || ''; const countValue = countRef.current.value || 10; const v3Value = v3Ref.current.checked != false; const legacyValue = legacyRef.current.checked != false; if (update) { setTitle(titleValue); setAuthor(authorValue); setCount(countValue); setV3(v3Value); setLegacy(legacyValue); } // Perform search with the latest input values, because state is not fast enough performSearch({ titleValue, authorValue, countValue, v3Value, legacyValue }); if (total) { loadTotal({ titleValue, authorValue, v3Value, legacyValue }); } }; const renderNavItems = () => ( Vault: Search for brews ); const validateForm = () => { //form validity: title or author must be written, and at least one renderer set const { current: titleInput } = titleRef; const { current: legacyCheckbox } = legacyRef; const { current: v3Checkbox } = v3Ref; const { current: authorInput } = authorRef; const isTitleValid = titleInput.validity.valid && titleInput.value; //because a pattern attr is set in the input, title must be over 2 chars long const isAuthorValid = authorInput.validity.valid && authorInput.value; const isCheckboxChecked = legacyCheckbox.checked || v3Checkbox.checked; const isFormValid = (isTitleValid || isAuthorValid) && isCheckboxChecked; return isFormValid; }; const disableSubmitIfFormInvalid = () => { const { current: submitButton } = searchButtonRef; submitButton.disabled = !validateForm(); }; const renderForm = () => (

Brew Lookup

Tip! you can use - to negate words, and{' '} "word" to specify an exact string. Remember, usernames are case sensitive.
Remember, you can only search brews with this tool if they are published
); const renderPaginationControls = () => { if (!totalBrews) return null; const countInt = parseInt(count); const totalPages = Math.ceil(totalBrews / countInt); let startPage, endPage; if (page <= 6) { startPage = 1; endPage = Math.min(totalPages, 10); } else if (page + 4 >= totalPages) { startPage = Math.max(1, totalPages - 9); endPage = totalPages; } else { startPage = page - 5; endPage = page + 4; } const pagesAroundCurrent = new Array(endPage - startPage + 1) .fill() .map((_, index) => ( loadPage(startPage + index, false, false)} > {startPage + index} )); return (
    {startPage > 1 && ( loadPage(1, false, false)} > 1 ... )} {pagesAroundCurrent} {endPage < totalPages && ( loadPage(totalPages, false, false)} > ... {totalPages} )}
); }; const renderFoundBrews = () => { if (searching) { return (

Searching

); } if (error) { console.log('render Error: ', error); let errorMessage; switch (error.errorCode) { case '404': errorMessage = "404 - We didn't find any brew"; break; case '503': errorMessage = '503 - Service Unavailable, try again later, sorry.'; break; case '500': errorMessage = "500 - We don't know what happened, go ahead and contact the mods or report as a mistake."; break; default: errorMessage = 'An unexpected error occurred'; } return (

Error: {errorMessage}

); } if (!brewCollection) { return (

No search yet

); } if (brewCollection.length === 0) { return (

No brews found

); } return (
{`Brews found: `} {totalBrews} {brewCollection.map((brew, index) => ( ))} {renderPaginationControls()}
); }; return (
{renderNavItems()}
{renderForm()}
{renderFoundBrews()}
); }; module.exports = VaultPage;