diff --git a/app/listings/actions.ts b/app/listings/actions.ts
new file mode 100644
index 00000000..0dbe3530
--- /dev/null
+++ b/app/listings/actions.ts
@@ -0,0 +1,45 @@
+"use server";
+
+import prisma from "@/lib/db";
+import { LISTINGS_PER_PAGE } from "./constants";
+import { countListingsToSkip } from "./function";
+import { Listing } from "./types";
+
+export async function fetchListingsByPage(currentPage: number) {
+ const dbListings = await prisma.listing.findMany({
+ skip: countListingsToSkip(currentPage, LISTINGS_PER_PAGE),
+ take: LISTINGS_PER_PAGE,
+ include: {
+ address: true,
+ prices: true,
+ },
+ });
+ const processedListings = dbListings.map((dbListing) => {
+ const dbListingPrice = dbListing.prices
+ .filter((dbListingPrice) => dbListingPrice.isCurrent)
+ .at(0)!
+ .value.toNumber();
+ const dbListingAddress = dbListing.address!;
+ const listing: Listing = {
+ id: dbListing.id,
+ imageUrls: dbListing.imageUrls,
+ beds: dbListing.beds,
+ baths: dbListing.baths,
+ area: dbListing.area.toNumber(),
+ createdDate: dbListing.createdDate,
+ address: {
+ addressLine: dbListingAddress.addressLine,
+ city: dbListingAddress.city,
+ state: dbListingAddress.state,
+ longitude: dbListingAddress.longitude.toNumber(),
+ latitude: dbListingAddress.latitude.toNumber(),
+ },
+ price: {
+ value: dbListingPrice,
+ },
+ };
+ return listing;
+ });
+
+ return processedListings;
+}
diff --git a/app/listings/constants.ts b/app/listings/constants.ts
index 54c1093f..11eb6262 100644
--- a/app/listings/constants.ts
+++ b/app/listings/constants.ts
@@ -1,2 +1,2 @@
-export const LISTINGS_PER_PAGE = 32;
+export const LISTINGS_PER_PAGE = 5;
export const STARTING_PAGE = 1;
diff --git a/app/listings/content.tsx b/app/listings/content.tsx
index 3baac70a..f155d249 100644
--- a/app/listings/content.tsx
+++ b/app/listings/content.tsx
@@ -1,21 +1,37 @@
+"use client"
+
+import { useContext, useEffect, useState } from "react"
+import { fetchListingsByPage } from "./actions"
import ListingsList from "./list"
import { ListingsListTop } from "./list-top"
import { ListingsMap } from "./map"
import ListingsPagination from "./pagination"
+import { ListingsContext } from "./provider"
import { Listing } from "./types"
export interface ListingsContentProps {
- listings: Listing[]
pages: number
}
export default function ListingsContent(props: ListingsContentProps) {
+ const [listings, setListings] = useState
([]);
+ const context = useContext(ListingsContext);
+ const currentPage = context.pagination.currentPage.value;
+
+ useEffect(() => {
+ async function updateListings() {
+ const newListings = await fetchListingsByPage(currentPage);
+ setListings(newListings);
+ }
+ updateListings();
+ }, [currentPage])
+
return (
diff --git a/app/listings/filter-beds-baths.tsx b/app/listings/filter-beds-baths.tsx
index fd8fcc66..1fa0b653 100644
--- a/app/listings/filter-beds-baths.tsx
+++ b/app/listings/filter-beds-baths.tsx
@@ -7,9 +7,11 @@ export default function ListingsFiltersBedsBaths() {
return (
+ values={bedsBathsOptions}
+ activeIndex={0} />
+ values={bedsBathsOptions}
+ activeIndex={0} />
);
diff --git a/app/listings/list.tsx b/app/listings/list.tsx
index 26fffb5c..90c67e35 100644
--- a/app/listings/list.tsx
+++ b/app/listings/list.tsx
@@ -2,20 +2,17 @@
import CardListing from "@/components/card-listing";
import { CURRENCY_FORMATTER } from "@/lib/formatter/currency";
-import { useState } from "react";
import { Listing } from "./types";
-export interface ListingsListInterface {
+export interface ListingsListProps {
listings: Listing[]
}
-export default function ListingsList(props: ListingsListInterface) {
- const [listings, setListings] = useState(props.listings);
-
+export default function ListingsList(props: ListingsListProps) {
return (
- {listings.map((listing) => {
+ {props.listings.map((listing) => {
const priceFormatted = CURRENCY_FORMATTER.format(listing.price.value)
return (
{
- const dbListingPrice = dbListing.prices.filter((dbListingPrice) => dbListingPrice.isCurrent).at(0)!.value.toNumber();
- const dbListingAddress = dbListing.address!;
- const listing: Listing = {
- id: dbListing.id,
- imageUrls: dbListing.imageUrls,
- beds: dbListing.beds,
- baths: dbListing.baths,
- area: dbListing.area.toNumber(),
- createdDate: dbListing.createdDate,
- address: {
- addressLine: dbListingAddress.addressLine,
- city: dbListingAddress.city,
- state: dbListingAddress.state,
- longitude: dbListingAddress.longitude.toNumber(),
- latitude: dbListingAddress.latitude.toNumber(),
- },
- price: {
- value: dbListingPrice
- }
- }
- return listing
- })
-
-
+ // TODO: Move down and the count must be equal to the number of matched listings based on filter values
const listingsCount = await prisma.listing.count()
const pages = Math.ceil(listingsCount / LISTINGS_PER_PAGE);
@@ -52,7 +13,7 @@ export default async function Listings() {
-
+
);
diff --git a/app/listings/pagination.tsx b/app/listings/pagination.tsx
index 91b32acb..1173fc53 100644
--- a/app/listings/pagination.tsx
+++ b/app/listings/pagination.tsx
@@ -13,7 +13,13 @@ export default function ListingsPagination(props: ListingsPaginationProps) {
return (
);
}
diff --git a/app/listings/provider.tsx b/app/listings/provider.tsx
index 13eb79ce..ded3dcfc 100644
--- a/app/listings/provider.tsx
+++ b/app/listings/provider.tsx
@@ -1,25 +1,52 @@
"use client"
-import { createContext } from "react"
+import { createContext, useState } from "react"
import { STARTING_PAGE } from "./constants"
-export interface ListingsContextInterface {
+interface ListingsContextInterface {
pagination: {
- currentPage: number
+ changeToPreviousPage: () => void,
+ changeToNextPage: () => void,
+ currentPage: {
+ value: number,
+ change: (page: number) => void
+ }
}
}
-const INITIAL_STATE: ListingsContextInterface = {
+export const ListingsContext = createContext({
pagination: {
- currentPage: STARTING_PAGE
+ changeToPreviousPage: () => { },
+ changeToNextPage: () => { },
+ currentPage: {
+ value: STARTING_PAGE,
+ change: (page) => { }
+ },
}
-}
-
-export const ListingsContext = createContext(INITIAL_STATE);
+});
export default function ListingsProvider({ children }: { children: React.ReactNode }) {
+ const [currentPage, setCurrentPage] = useState(STARTING_PAGE);
+
+ const stateValue: ListingsContextInterface = {
+ pagination: {
+ changeToPreviousPage: () => {
+ setCurrentPage(currentPage - 1)
+ },
+ changeToNextPage: () => {
+ setCurrentPage(currentPage + 1)
+ },
+ currentPage: {
+ value: currentPage,
+ change: (page: number) => {
+ setCurrentPage(page)
+ },
+ }
+ }
+ }
+
return (
-
+
{children}
)
diff --git a/components/buttons-segmented/labelled.tsx b/components/buttons-segmented/labelled.tsx
index 2059d44a..e48e431c 100644
--- a/components/buttons-segmented/labelled.tsx
+++ b/components/buttons-segmented/labelled.tsx
@@ -13,4 +13,4 @@ export default function ButtonsSegmentedLabelled(props: ButtonsSegmentedLabelled
);
-}
\ No newline at end of file
+}
diff --git a/components/pagination/function.ts b/components/pagination/function.ts
index a48aaf7d..c3dda17f 100644
--- a/components/pagination/function.ts
+++ b/components/pagination/function.ts
@@ -1,21 +1,21 @@
/**
*
- * Show the previous button only if the current page is not the first page
+ * Enable the previous button only if the current page is not the first page
*
* @param currentPage Current page
- * @returns `true` if the previous button should be shown, otherwise false.
+ * @returns `true` if the previous button should be enabled, otherwise false.
*/
-export function checkShowPreviousButton(currentPage: number) {
+export function checkPreviousButton(currentPage: number) {
return currentPage > 1;
}
/**
- * Show the next button only if the current page is not the last page
+ * Enable the next button only if the current page is not the last page
*
* @param pages Total number of pages
* @param currentPage Current page
- * @returns `true` if the next button should be shown, otherwise false.
+ * @returns `true` if the next button should be enabled, otherwise false.
*/
-export function checkShowNextButton(pages: number, currentPage: number) {
+export function checkNextButton(pages: number, currentPage: number) {
return currentPage < pages;
}
diff --git a/components/pagination/index.tsx b/components/pagination/index.tsx
index 67cf5297..ece42897 100644
--- a/components/pagination/index.tsx
+++ b/components/pagination/index.tsx
@@ -1,43 +1,64 @@
-import { checkShowNextButton, checkShowPreviousButton } from "./function"
+import { checkNextButton, checkPreviousButton } from "./function"
import PaginationItemNav from "./item-nav"
import PaginationItemNumber from "./item-number"
export interface PaginationProps {
pages: number
currentPage: number
+ changeToPreviousPage?: () => void
+ changeCurrentPage?: (page: number) => void
+ changeToNextPage?: () => void
}
export default function Pagination(props: PaginationProps) {
const pageNumbers = Array.from({ length: props.pages }, (elem, i) => i + 1)
- const showPreviousButton = checkShowPreviousButton(props.currentPage);
- const showNextButton = checkShowNextButton(props.pages, props.currentPage);
+ const previousButtonEnabled = checkPreviousButton(props.currentPage);
+ const nextButtonEnabled = checkNextButton(props.pages, props.currentPage);
return (
{/* Previous (hidden if the current page is the first page) */}
- {showPreviousButton &&
+
{
+ if (props.changeToPreviousPage && previousButtonEnabled) {
+ props.changeToPreviousPage()
+ }
+ }}>
- }
+
{pageNumbers.map((pageNumber) => {
const isCurrentPage = props.currentPage === pageNumber
- return
+ return (
+
{
+ if (props.changeCurrentPage) {
+ props.changeCurrentPage(pageNumber);
+ }
+ }}>
+
+
+ )
})}
{/* Next (hidden if current page is the last page) */}
- {showNextButton &&
+
{
+ if (props.changeToNextPage && nextButtonEnabled) {
+ props.changeToNextPage()
+ }
+ }}>
- }
+
)
}
diff --git a/tests/components/pagination.test.ts b/tests/components/pagination.test.ts
index 008f12c1..b936e5c3 100644
--- a/tests/components/pagination.test.ts
+++ b/tests/components/pagination.test.ts
@@ -1,6 +1,6 @@
import {
- checkShowNextButton,
- checkShowPreviousButton,
+ checkNextButton,
+ checkPreviousButton,
} from "../../components/pagination/function";
describe("Pagination", () => {
@@ -11,7 +11,7 @@ describe("Pagination", () => {
{ currentPage: 99, expected: true },
{ currentPage: NaN, expected: false },
])("checkShowPreviousButton($currentPage)", ({ currentPage, expected }) => {
- const output = checkShowPreviousButton(currentPage);
+ const output = checkPreviousButton(currentPage);
expect(output).toBe(expected);
});
@@ -27,7 +27,7 @@ describe("Pagination", () => {
])(
"checkShowNextButton($pages, $currentPage)",
({ pages, currentPage, expected }) => {
- const output = checkShowNextButton(pages, currentPage);
+ const output = checkNextButton(pages, currentPage);
expect(output).toBe(expected);
}
);