Skip to content

Commit

Permalink
Update listings when new search filter is applied
Browse files Browse the repository at this point in the history
refs #49
  • Loading branch information
franthormel committed Aug 31, 2024
1 parent 5cfd24c commit 3a9504c
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 84 deletions.
9 changes: 9 additions & 0 deletions app/api/listings/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { fetchMatchedListings } from "@/app/listings/actions";
import { ListingsSearchFiltersRequest } from "@/app/listings/types";

export async function POST(request: Request) {
const searchFiltersJson = await request.json();
const searchFilters = searchFiltersJson as ListingsSearchFiltersRequest;
const listings = await fetchMatchedListings(searchFilters);
return Response.json({ listings });
}
25 changes: 11 additions & 14 deletions app/listings/actions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use server";

import prisma from "@/lib/db";
import { DEFAULT_LIST_FILTERS } from "./constants";
import { DEFAULT_REQUEST_FILTERS } from "./constants";
import {
BedsBathsOption,
Listing,
ListingsSearchFilters,
ListingsSearchFiltersRequest,
PrismaListing,
} from "./types";

Expand Down Expand Up @@ -36,8 +36,9 @@ const prismaListingMapper = (dbListing: PrismaListing) => {
return listing;
};

// TODO: Move to route.ts
export async function fetchMatchedListings(
filters: ListingsSearchFilters = DEFAULT_LIST_FILTERS
filters: ListingsSearchFiltersRequest = DEFAULT_REQUEST_FILTERS
): Promise<Listing[]> {
const prismaListings = await prisma.listing.findMany({
include: {
Expand All @@ -53,38 +54,34 @@ export async function fetchMatchedListings(
AND: {
// ... and must be greater than or equal than the minimum filter value ...
value: {
gte: filters.price.min.value,
gte: filters.price.min,
},
AND: {
// ... and must be lesser than or equal than the maximum filter value
value: {
lte: filters.price.max.value,
lte: filters.price.max,
},
},
},
},
},
// Filter (area): must be greater than or equal than the minimum filter value ...
area: {
gte: filters.area.min.value,
gte: filters.area.min,
},
AND: {
// ... and must be lesser than or equal than the maximum filter value
area: {
lte: filters.area.max.value,
lte: filters.area.max,
},
},
},
});

// It is easier to filter the beds/baths values programatically rather than using Prisma's filtering API for the use case.
// It is easier to filter the beds/baths values programatically rather than using Prisma's filtering API.
return prismaListings
.filter((listing) =>
bedsBathsOptionFilter(filters.beds.value, listing.beds)
)
.filter((listing) =>
bedsBathsOptionFilter(filters.baths.value, listing.baths)
)
.filter((listing) => bedsBathsOptionFilter(filters.beds, listing.beds))
.filter((listing) => bedsBathsOptionFilter(filters.baths, listing.baths))
.map(prismaListingMapper);
return prismaListings.map(prismaListingMapper);
}
Expand Down
19 changes: 18 additions & 1 deletion app/listings/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { BedsBathsOption, ListingsSearchFilters } from "./types";
import {
BedsBathsOption,
ListingsSearchFilters,
ListingsSearchFiltersRequest,
} from "./types";

export const LISTINGS_PER_PAGE = 15;
export const STARTING_PAGE = 1;
Expand Down Expand Up @@ -53,3 +57,16 @@ export const DEFAULT_LIST_FILTERS: ListingsSearchFilters = {
},
},
};

export const DEFAULT_REQUEST_FILTERS: ListingsSearchFiltersRequest = {
price: {
min: PRICE_MIN_FILTER,
max: PRICE_MAX_FILTER,
},
beds: BEDS_BATHS_DEFAULT,
baths: BEDS_BATHS_DEFAULT,
area: {
min: AREA_MIN_FILTER,
max: AREA_MAX_FILTER,
},
};
35 changes: 27 additions & 8 deletions app/listings/content.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
"use client"

import { useContext } from "react"
import { useContext, useEffect } from "react"
import { ListingSortCompareFunctions, makeSearchFiltersRequest } from "./functions"
import ListingsList from "./list"
import { ListingsListCountSort } from "./list-count-sort"
import { ListingsMap } from "./map"
import ListingsPagination from "./pagination"
import { ListingsContext } from "./provider"
import { Listing, ListingSortCompareFunctions } from "./types"
import { Listing } from "./types"

interface ListingsContentInterface {
listings: Listing[]
}

export default function ListingsContent(props: ListingsContentInterface) {
// TODO: Use context filter values, try to use useMemo if applicable
// TODO: try to use useMemo if applicable
const context = useContext(ListingsContext);

const sortedListings = props.listings.sort(ListingSortCompareFunctions.choose(context.sort.value))
useEffect(() => {
async function updateListings() {
const searchFiltersRequest = makeSearchFiltersRequest(context.searchFilters);
const request = await fetch("/api/listings", {
method: "POST",
body: JSON.stringify(searchFiltersRequest),
});
const json = await request.json()
console.log



context.listings.change(listings)
}
updateListings()
}, [])


const sortedListings = context.listings.value.sort(ListingSortCompareFunctions.choose(context.sort.value))

return (
<div className="flex h-[36rem]">
<ListingsMap listings={props.listings} />
{/* <ListingsMap listings={context.listings.value} />
<div className="flex basis-1/2 flex-col">
<ListingsListCountSort listingsCount={props.listings.length} />
<ListingsListCountSort />
<ListingsList listings={sortedListings} />
<ListingsPagination listingsCount={props.listings.length} />
</div>
<ListingsPagination />
</div> */}
</div>
)
}
3 changes: 0 additions & 3 deletions app/listings/function.ts

This file was deleted.

67 changes: 67 additions & 0 deletions app/listings/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
Listing,
ListingSort,
ListingsSearchFilters,
ListingsSearchFiltersRequest,
} from "./types";

export function countListingsToSkip(currentPage: number, countPerPage: number) {
return (currentPage - 1) * countPerPage;
}

export function makeSearchFiltersRequest(
original: ListingsSearchFilters
): ListingsSearchFiltersRequest {
return {
price: {
min: original.price.min.value,
max: original.price.max.value,
},
beds: original.beds.value,
baths: original.baths.value,
area: {
min: original.area.min.value,
max: original.area.max.value,
},
};
}

type ListingSortCompareFunction = (a: Listing, b: Listing) => number;

export class ListingSortCompareFunctions {
static #NEWEST: ListingSortCompareFunction = (a, b) => {
if (a.createdDate < b.createdDate) {
return 1;
}

if (a.createdDate === b.createdDate) {
return 0;
}

return -1;
};

static #PRICE_DESC: ListingSortCompareFunction = (a, b) => {
return b.price.value - a.price.value;
};

static #PRICE_ASC: ListingSortCompareFunction = (a, b) => {
return a.price.value - b.price.value;
};

static choose(sort: ListingSort): ListingSortCompareFunction {
switch (sort) {
case ListingSort.NEWEST:
return ListingSortCompareFunctions.#NEWEST;
break;
case ListingSort.PRICE_DESC:
return ListingSortCompareFunctions.#PRICE_DESC;
break;
case ListingSort.PRICE_ASC:
return ListingSortCompareFunctions.#PRICE_ASC;
break;
default:
return ListingSortCompareFunctions.#NEWEST;
}
}
}
10 changes: 3 additions & 7 deletions app/listings/list-count-sort.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,16 @@ import { useContext } from "react";
import { ListingsContext } from "./provider";
import { ListingSort } from "./types";

export interface ListingsListCountSortInterface {
listingsCount: number
}

export function ListingsListCountSort(props: ListingsListCountSortInterface) {
export function ListingsListCountSort() {
const context = useContext(ListingsContext);

return (
<div>
<div className="basis-14 px-5 py-4 block md:flex md:flex-row border-y-[1px] border-gray-200">
{
props.listingsCount > 0 &&
context.listings.value.length > 0 &&
<span className="font-bold md:mr-6">
{formatAppend(props.listingsCount, "listings")}
{formatAppend(context.listings.value.length, "listings")}
</span>
}
<div>
Expand Down
2 changes: 1 addition & 1 deletion app/listings/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CardListing from "@/components/card-listing";
import { CURRENCY_FORMATTER } from "@/lib/formatter/currency";
import { useContext } from "react";
import { LISTINGS_PER_PAGE } from "./constants";
import { countListingsToSkip } from "./function";
import { countListingsToSkip } from "./functions";
import { ListingsContext } from "./provider";
import { Listing } from "./types";

Expand Down
8 changes: 2 additions & 6 deletions app/listings/pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import { useContext } from "react";
import { LISTINGS_PER_PAGE } from "./constants";
import { ListingsContext } from "./provider";

export interface ListingsPaginationProps {
listingsCount: number
}

export default function ListingsPagination(props: ListingsPaginationProps) {
export default function ListingsPagination() {
const context = useContext(ListingsContext);
const pages = Math.ceil(props.listingsCount / LISTINGS_PER_PAGE);
const pages = Math.ceil(context.listings.value.length / LISTINGS_PER_PAGE);

return (
<div className="flex basis-20 items-center justify-center border-y-[1px] border-gray-200">
Expand Down
19 changes: 16 additions & 3 deletions app/listings/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { createContext, useState } from "react"
import { DEFAULT_LIST_FILTERS, STARTING_PAGE } from "./constants"
import { BedsBathsOption, ListingContextType, ListingSort, ListingsSearchFilters } from "./types"
import { BedsBathsOption, Listing, ListingContextType, ListingSort, ListingsSearchFilters } from "./types"

interface ListingsContextInterface {
searchFilters: ListingsSearchFilters,
Expand All @@ -14,7 +14,8 @@ interface ListingsContextInterface {
changeToPreviousPage: () => void,
changeToNextPage: () => void,
currentPage: ListingContextType<number>
}
},
listings: ListingContextType<Listing[]>
}

export const ListingsContext = createContext<ListingsContextInterface>({
Expand All @@ -30,7 +31,11 @@ export const ListingsContext = createContext<ListingsContextInterface>({
value: STARTING_PAGE,
change: (value) => { }
},
}
},
listings: {
value: [],
change: (value) => { }
},
});

export default function ListingsProvider({ children }: { children: React.ReactNode }) {
Expand All @@ -46,6 +51,7 @@ export default function ListingsProvider({ children }: { children: React.ReactNo
const [listingSort, setListingSort] = useState<ListingSort>(ListingSort.NEWEST)

const [currentPage, setCurrentPage] = useState<number>(STARTING_PAGE);
const [listings, setListings] = useState<Listing[]>([]);

const stateValue: ListingsContextInterface = {
searchFilters: {
Expand Down Expand Up @@ -109,6 +115,13 @@ export default function ListingsProvider({ children }: { children: React.ReactNo
setCurrentPage(value)
},
}
},
listings: {
value: listings,
change: (value) => {
// TODO: Fix value is not being used? maybe not to transform object?
setListings(value)
},
}
}

Expand Down
Loading

0 comments on commit 3a9504c

Please sign in to comment.