Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add listing pagination to public site #142

Merged
merged 14 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions sites/partners/lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useContext } from "react"
import useSWR, { mutate } from "swr"
import { Listing } from "@bloom-housing/backend-core/types"


import { AuthContext } from "@bloom-housing/ui-components"

Expand All @@ -24,6 +22,7 @@ export function useSingleListingData(listingId: string) {
}
}

/* TODO: move this function so it can be shared between public and partner sites.*/
export function useListingsData() {
const { listingsService } = useContext(AuthContext)
const fetcher = () => listingsService.list()
Expand Down
2 changes: 1 addition & 1 deletion sites/public/layouts/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Layout = (props) => {
codes: router?.locales,
}}
>
<Link href="/listings">
<Link href="/listings?page=1">
abbiefarr marked this conversation as resolved.
Show resolved Hide resolved
<a className="navbar-item">{t("nav.listings")}</a>
</Link>
{/* Only show Get Assistance if housing counselor data is available */}
Expand Down
31 changes: 29 additions & 2 deletions sites/public/lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useContext, useEffect } from "react"
import { useContext, useEffect, useRef } from "react"
import { useRouter } from "next/router"
import { isInternalLink } from "@bloom-housing/ui-components"
import useSWR from "swr"
import { isInternalLink, AuthContext } from "@bloom-housing/ui-components"
import { AppSubmissionContext } from "./AppSubmissionContext"
import { ParsedUrlQuery } from "querystring"
import { ListingsService } from "@bloom-housing/backend-core/types"

export const useRedirectToPrevPage = (defaultPath = "/") => {
const router = useRouter()
Expand Down Expand Up @@ -30,3 +32,28 @@ export const useFormConductor = (stepName: string) => {
}, [conductor])
return context
}

const listingsFetcher = function (listingsService: ListingsService) {
return (_url: string, page: number, limit: number) => {
const params = {
page,
limit,
}
return listingsService?.list(params)
}
}

// TODO: move this so it can be shared with the partner site.
export function useListingsData(pageIndex: number, limit = 10) {
const { listingsService } = useContext(AuthContext)
const { data, error } = useSWR(
[`${process.env.listingServiceUrl}`, pageIndex, limit],
listingsFetcher(listingsService)
)

return {
listingsData: data,
listingsLoading: !error && !data,
listingsError: error,
}
}
2 changes: 1 addition & 1 deletion sites/public/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function Home(props: IndexProps) {
<Hero
title={heroTitle}
buttonTitle={t("welcome.seeRentalListings")}
buttonLink="/listings"
buttonLink="/listings?page=1"
abbiefarr marked this conversation as resolved.
Show resolved Hide resolved
listings={props.listings}
/>
<div className="homepage-extra">
Expand Down
114 changes: 54 additions & 60 deletions sites/public/pages/listings.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
import Head from "next/head"
import axios from "axios"
import moment from "moment"
import {
ListingsGroup,
ListingsList,
PageHeader,
openDateState,
AgPagination,
AG_PER_PAGE_OPTIONS,
t,
} from "@bloom-housing/ui-components"
import { Listing } from "@bloom-housing/backend-core/types"
import Layout from "../layouts/application"
import { MetaTags } from "../src/MetaTags"
import React, { useEffect, useState } from "react"
import { useRouter } from "next/router"
import { useListingsData } from "../lib/hooks"

export interface ListingsProps {
openListings: Listing[]
closedListings: Listing[]
}
const ListingsPage = () => {
const router = useRouter()

const openListings = (listings) => {
return listings.length > 0 ? (
<ListingsList listings={listings} />
) : (
<div className="notice-block">
<h3 className="m-auto text-gray-800">{t("listings.noOpenListings")}</h3>
</div>
)
}
/* Pagination state */
const [currentPage, setCurrentPage] = useState<number>(1)
const [itemsPerPage, setItemsPerPage] = useState<number>(AG_PER_PAGE_OPTIONS[0])

const closedListings = (listings) => {
return (
listings.length > 0 && (
<ListingsGroup
listings={listings}
header={t("listings.closedListings")}
hideButtonText={t("listings.hideClosedListings")}
showButtonText={t("listings.showClosedListings")}
/>
)
)
}
function setPage(page: number) {
if (page != currentPage) {
void router.push(
{
pathname: "/listings",
query: { page: page },
},
undefined,
{ shallow: true }
)
setCurrentPage(page)
}
}

useEffect(() => {
if (currentPage != 1) {
setPage(1)
}
}, [itemsPerPage])

// Checks if the url is updated manually.
useEffect(() => {
if (router.query.page && Number(router.query.page) != currentPage) {
setCurrentPage(Number(router.query.page))
}
}, [router.query.page])

const { listingsData, listingsLoading } = useListingsData(currentPage, itemsPerPage)

export default function ListingsPage(props: ListingsProps) {
const pageTitle = `${t("pageTitle.rent")} - ${t("nav.siteTitle")}`
const metaDescription = t("pageDescription.welcome", { regionName: t("region.name") })
const metaImage = "" // TODO: replace with hero image
Expand All @@ -52,36 +59,23 @@ export default function ListingsPage(props: ListingsProps) {
</Head>
<MetaTags title={t("nav.siteTitle")} image={metaImage} description={metaDescription} />
<PageHeader title={t("pageTitle.rent")} />
<div>
{openListings(props.openListings)}
{closedListings(props.closedListings)}
</div>
{!listingsLoading && (
<div>
{listingsData && <ListingsList listings={listingsData.items} />}
<AgPagination
totalItems={listingsData?.meta.totalItems}
totalPages={listingsData?.meta.totalPages}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
sticky={true}
quantityLabel={t("listings.totalListings")}
setCurrentPage={setPage}
setItemsPerPage={setItemsPerPage}
/>
</div>
)}
</Layout>
)
}

export async function getStaticProps() {
let openListings = []
let closedListings = []

try {
const response = await axios.get(
process.env.listingServiceUrl + "?filter[$comparison]=<>&filter[status]=pending"
)
const nowTime = moment()
openListings = response.data.items.filter((listing: Listing) => {
return (
openDateState(listing) ||
nowTime <= moment(listing.applicationDueDate) ||
listing.applicationDueDate == null
)
})
closedListings = response.data.items.filter((listing: Listing) => {
return nowTime > moment(listing.applicationDueDate)
})
} catch (error) {
console.error(error)
}

return { props: { openListings, closedListings }, revalidate: process.env.cacheRevalidate }
}
export default ListingsPage
11 changes: 9 additions & 2 deletions ui-components/src/global/vendor/AgPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ type AgPaginationProps = {
totalPages: number
currentPage: number
itemsPerPage: number
sticky?: boolean
quantityLabel?: string
setCurrentPage: React.Dispatch<React.SetStateAction<number>>
setCurrentPage: React.Dispatch<React.SetStateAction<number>> | ((page: number) => void)
setItemsPerPage: React.Dispatch<React.SetStateAction<number>>
onPageChange?: (page: number) => void
onPerPageChange?: (size: number) => void
Expand All @@ -20,6 +21,7 @@ const AgPagination = ({
totalPages,
currentPage,
itemsPerPage,
sticky,
quantityLabel,
setCurrentPage,
setItemsPerPage,
Expand All @@ -41,8 +43,13 @@ const AgPagination = ({
onPerPageChange && onPerPageChange(itemsPerPage)
}

const dataPagerClassName = ["data-pager flex flex-col md:flex-row"]
abbiefarr marked this conversation as resolved.
Show resolved Hide resolved
if (sticky) {
dataPagerClassName.push("sticky")
}

return (
<div className="data-pager flex flex-col md:flex-row">
<div className={dataPagerClassName.join(" ")}>
<div className="hidden md:block">
<Button
className="data-pager__previous data-pager__control"
Expand Down
7 changes: 7 additions & 0 deletions ui-components/src/global/vendor/ag_grid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@
@apply bg-gray-200;
}

.sticky {
@apply fixed;
@apply z-40;
@apply bottom-0;
@apply left-0;
}

.data-pager__control {
@apply px-4;

Expand Down