import { useState, useEffect } from "react"; import styles from "../styles/apps.module.scss"; import SingleApp from "../components/SingleApp"; import Footer from "../components/Footer"; import ListSort from "../components/ListSort"; import MetaTags from "../components/MetaTags"; import Search from "../components/Search"; import { FiChevronLeft, FiChevronRight, FiArrowLeftCircle, FiArrowRightCircle, } from "react-icons/fi"; import Router from "next/router"; import fetchWinstallAPI from "../utils/fetchWinstallAPI"; import Error from "../components/Error"; function Store({ data, error }) { if (error) return <Error title="Oops!" subtitle={error} />; const [apps, setApps] = useState([]); const [searchInput, setSearchInput] = useState(); const [offset, setOffset] = useState(0); const [sort, setSort] = useState(); const appsPerPage = 60; const totalPages = Math.ceil(apps.length / appsPerPage); useEffect(() => { if (Router.query.sort && Router.query.sort === "update-desc") { setSort(Router.query.sort); setApps(data.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))); } else { setSort("name-asc"); setApps(data.sort((a, b) => a.name.localeCompare(b.name))); } let handlePagination = (e) => { if (e.keyCode === 39) { let nextBtn = document.getElementById("next"); if (nextBtn) { document.getElementById("next").click(); } } else if (e.keyCode === 37) { let previousBtn = document.getElementById("previous"); if (previousBtn) { document.getElementById("previous").click(); } } }; document.addEventListener("keydown", handlePagination); setPagination(apps.length); return () => document.removeEventListener("keydown", handlePagination); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const setPagination = (appCount) => { let requestedPage = parseInt(Router.query.page); if (requestedPage) { let maxPages = Math.round(appCount / appsPerPage) + 1; // we check if its a valid page number if (requestedPage > maxPages || requestedPage < 2) return; // if it is, we continue let calculateOffset = appsPerPage * (requestedPage - 1); setOffset(calculateOffset); } }; let handleNext = () => { window.scrollTo(0, 0); setOffset((offset) => offset + appsPerPage); Router.replace({ pathname: "/apps", query: { page: Math.round((offset + appsPerPage - 1) / appsPerPage) + 1, }, }); }; let handlePrevious = () => { window.scrollTo(0, 0); setOffset((offset) => offset - appsPerPage); Router.replace({ pathname: "/apps", query: { page: Math.round((offset + appsPerPage - 1) / appsPerPage) - 1, }, }); }; let Pagination = ({ small, disable }) => { return ( <div className={small ? styles.minPagination : styles.pagbtn}> <button className={`button ${small ? styles.smallBtn : null}`} id={!small ? "previous" : ""} onClick={handlePrevious} title="Previous page of apps" disabled={offset > 0 ? (disable ? "disabled" : null) : "disabled"} > <FiChevronLeft /> {!small ? "Previous" : ""} </button> <button className={`button ${small ? styles.smallBtn : null}`} id={!small ? "next" : ""} title="Next page of apps" onClick={handleNext} disabled={ offset + appsPerPage < apps.length ? disable ? "disabled" : null : "disabled" } > {!small ? "Next" : ""} <FiChevronRight /> </button> </div> ); }; const Title = () => { return ( <> {!searchInput && <h1>All apps {`(${apps.length})`}</h1>} {searchInput && ( <> {searchInput.startsWith("tags: ") && ( <h1>Tag: {searchInput.split(": ")[1]}</h1> )} {!searchInput.startsWith("tags: ") && <h1>Search results</h1>} </> )} </> ); }; if (!apps) return <></>; return ( <div> <MetaTags title="Apps - winstall" /> <div className={styles.controls}> <Title /> <Pagination small disable={searchInput ? true : false} /> </div> <Search apps={apps} onSearch={(q) => setSearchInput(q)} label={"Search for apps"} placeholder={"Enter you search term here"} /> <div className={styles.controls}> {!searchInput && ( <> <p> Showing {apps.slice(offset, offset + appsPerPage).length} apps (page {Math.round((offset + appsPerPage - 1) / appsPerPage)} of{" "} {totalPages}). </p> <ListSort apps={apps} defaultSort={sort} onSort={(sort) => setSort(sort)} /> </> )} </div> {!searchInput && ( <ul className={`${styles.all} ${styles.storeList}`}> {apps.slice(offset, offset + appsPerPage).map((app) => ( <SingleApp app={app} key={app._id} showTime={sort.includes("update-") ? true : false} /> ))} </ul> )} <div className={styles.pagination}> <Pagination disable={searchInput ? true : false} /> <em> Hit the <FiArrowLeftCircle /> and <FiArrowRightCircle /> keys on your keyboard to navigate between pages quickly. </em> </div> <Footer /> </div> ); } export async function getStaticProps() { let { response: apps, error } = await fetchWinstallAPI(`/apps`); if (error) return { props: { error } }; return { props: { data: apps, }, }; } export default Store;