generated from 202306-NEA-DZ-FEW/capstone-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(products page): refactor code and fix search bar
fix search bar text disappears when refresh and infinite loop when click on clear button fixes #87
- Loading branch information
1 parent
1c0d974
commit 0d4866d
Showing
20 changed files
with
836 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { Menu, Transition } from "@headlessui/react"; | ||
import Link from "next/link"; | ||
import { Fragment } from "react"; | ||
import { BiCategory } from "react-icons/bi"; | ||
import { IoMdArrowDropdown } from "react-icons/io"; | ||
|
||
import getAllCategories from "@/lib/getAllCategories"; | ||
|
||
function CategoryFilter({ t, queryParams }) { | ||
function classNames(...classes) { | ||
return classes.filter(Boolean).join(" "); | ||
} | ||
const categories = getAllCategories(t); | ||
|
||
return ( | ||
<> | ||
<Menu as='div' className='relative w-full flex justify-center text-left'> | ||
<Menu.Button className='flex items-center gap-2 w-full justify-between border bg-white input-sm rounded-full tracking-wider'> | ||
<div className='flex gap-2 items-center'> | ||
<BiCategory className='w-5 h-5' /> | ||
<span> | ||
{queryParams.category | ||
? t(`categories:${queryParams.category}`) | ||
: t("productsPage:all")} | ||
</span> | ||
</div> | ||
<IoMdArrowDropdown /> | ||
</Menu.Button> | ||
|
||
<Transition | ||
as={Fragment} | ||
enter='transition ease-out duration-100' | ||
enterFrom='transform opacity-0 scale-95' | ||
enterTo='transform opacity-100 scale-100' | ||
leave='transition ease-in duration-75' | ||
leaveFrom='transform opacity-100 scale-100' | ||
leaveTo='transform opacity-0 scale-95' | ||
> | ||
<Menu.Items className='absolute max-h-52 overflow-y-scroll no-scrollbar bg-white z-10 rounded-lg top-10 w-full ring-1 ring-black ring-opacity-5 drop-shadow-xl'> | ||
<div className='py-1'> | ||
{categories.map(({ name, dataKey }) => ( | ||
<Link | ||
scroll={false} | ||
key={dataKey} | ||
href={{ | ||
pathname: "/products", | ||
query: { ...queryParams, category: dataKey }, | ||
}} | ||
> | ||
<Menu.Item> | ||
{({ active }) => ( | ||
<p | ||
className={classNames( | ||
active | ||
? "bg-gray-100 text-gray-900" | ||
: "text-gray-700", | ||
"block px-4 py-2 tracking-wider my-2" | ||
)} | ||
> | ||
{name} | ||
</p> | ||
)} | ||
</Menu.Item> | ||
</Link> | ||
))} | ||
</div> | ||
</Menu.Items> | ||
</Transition> | ||
</Menu> | ||
</> | ||
); | ||
} | ||
|
||
export default CategoryFilter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from "react"; | ||
import { MdFilterListOff } from "react-icons/md"; | ||
|
||
function ClearFilterButton({ t, handleClearFilters }) { | ||
return ( | ||
<button | ||
onClick={handleClearFilters} | ||
className='btn btn-sm rounded-full btn-neutral normal-case font-light tracking-wider' | ||
> | ||
<MdFilterListOff /> | ||
{t("productsPage:clearFilter")} | ||
</button> | ||
); | ||
} | ||
|
||
export default ClearFilterButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { Menu, Transition } from "@headlessui/react"; | ||
import Link from "next/link"; | ||
import { Fragment } from "react"; | ||
import { IoMdArrowDropdown } from "react-icons/io"; | ||
import { TbSitemap } from "react-icons/tb"; | ||
|
||
function ListingTypeFilter({ t, queryParams }) { | ||
function classNames(...classes) { | ||
return classes.filter(Boolean).join(" "); | ||
} | ||
const listingTypes = ["exchangeButton", "requestButton", "donationButton"]; | ||
|
||
return ( | ||
<> | ||
<Menu as='div' className='relative w-full flex justify-center text-left'> | ||
<Menu.Button className='flex items-center gap-2 w-full justify-between border bg-white input-sm rounded-full tracking-wider'> | ||
<div className='flex gap-2 items-center'> | ||
<TbSitemap className='w-5 h-5' /> | ||
<span> | ||
{queryParams.listingType | ||
? t(`addItem:${queryParams.listingType}`) | ||
: "Listing type"} | ||
</span> | ||
</div> | ||
<IoMdArrowDropdown /> | ||
</Menu.Button> | ||
|
||
<Transition | ||
as={Fragment} | ||
enter='transition ease-out duration-100' | ||
enterFrom='transform opacity-0 scale-95' | ||
enterTo='transform opacity-100 scale-100' | ||
leave='transition ease-in duration-75' | ||
leaveFrom='transform opacity-100 scale-100' | ||
leaveTo='transform opacity-0 scale-95' | ||
> | ||
<Menu.Items className='absolute max-h-52 overflow-y-scroll no-scrollbar bg-white z-10 rounded-lg top-10 w-full ring-1 ring-black ring-opacity-5 drop-shadow-xl'> | ||
<div className='py-1'> | ||
{listingTypes.map((type) => ( | ||
<Link | ||
scroll={false} | ||
key={type} | ||
href={{ | ||
pathname: "/products", | ||
query: { ...queryParams, listingType: type }, | ||
}} | ||
> | ||
<Menu.Item> | ||
{({ active }) => ( | ||
<p | ||
className={classNames( | ||
active | ||
? "bg-gray-100 text-gray-900" | ||
: "text-gray-700", | ||
"block px-4 py-2 tracking-wider my-2" | ||
)} | ||
> | ||
{t(`addItem:${type}`)} | ||
</p> | ||
)} | ||
</Menu.Item> | ||
</Link> | ||
))} | ||
</div> | ||
</Menu.Items> | ||
</Transition> | ||
</Menu> | ||
</> | ||
); | ||
} | ||
|
||
export default ListingTypeFilter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Menu, Transition } from "@headlessui/react"; | ||
import Link from "next/link"; | ||
import { Fragment } from "react"; | ||
import { HiOutlineLocationMarker } from "react-icons/hi"; | ||
import { IoMdArrowDropdown } from "react-icons/io"; | ||
|
||
import getAllStates from "@/lib/getAllStates"; | ||
|
||
function LocationFilter({ t, queryParams }) { | ||
function classNames(...classes) { | ||
return classes.filter(Boolean).join(" "); | ||
} | ||
//This is to test the LocationFilter | ||
const states = getAllStates(t); | ||
|
||
return ( | ||
<> | ||
<Menu as='div' className='relative w-full flex justify-center text-left'> | ||
<Menu.Button className='flex items-center gap-2 w-full justify-between border bg-white input-sm rounded-full tracking-wider'> | ||
<div className='flex gap-2 items-center'> | ||
<HiOutlineLocationMarker className='w-5 h-5' /> | ||
<span> | ||
{queryParams.location | ||
? t(`states:${queryParams.location}`) | ||
: t("productsPage:location")} | ||
</span> | ||
</div> | ||
<IoMdArrowDropdown /> | ||
</Menu.Button> | ||
|
||
<Transition | ||
as={Fragment} | ||
enter='transition ease-out duration-100' | ||
enterFrom='transform opacity-0 scale-95' | ||
enterTo='transform opacity-100 scale-100' | ||
leave='transition ease-in duration-75' | ||
leaveFrom='transform opacity-100 scale-100' | ||
leaveTo='transform opacity-0 scale-95' | ||
> | ||
<Menu.Items className='absolute max-h-52 no-scrollbar overflow-y-scroll bg-white z-10 rounded-lg top-10 w-full ring-1 ring-black ring-opacity-5 drop-shadow-xl'> | ||
<div className='py-1'> | ||
{states.map(({ name, dataKey }) => ( | ||
<Link | ||
scroll={false} | ||
key={dataKey} | ||
href={{ | ||
pathname: "/products", | ||
query: { ...queryParams, location: dataKey }, | ||
}} | ||
> | ||
<Menu.Item> | ||
{({ active }) => ( | ||
<p | ||
className={classNames( | ||
active | ||
? "bg-gray-100 text-gray-900" | ||
: "text-gray-700", | ||
"block px-4 py-2 tracking-wider my-2" | ||
)} | ||
> | ||
{name} | ||
</p> | ||
)} | ||
</Menu.Item> | ||
</Link> | ||
))} | ||
</div> | ||
</Menu.Items> | ||
</Transition> | ||
</Menu> | ||
</> | ||
); | ||
} | ||
|
||
export default LocationFilter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { useRouter } from "next/router"; | ||
import { BiLeftArrow, BiRightArrow } from "react-icons/bi"; | ||
|
||
function Pagination({ page, pageSize, totalItems, queryParams, totalPages }) { | ||
const router = useRouter(); | ||
|
||
const hasPrev = pageSize * (parseInt(page) - 1) > 0; | ||
const hasNext = pageSize * (parseInt(page) - 1) + pageSize < totalItems; | ||
|
||
const handleChangePage = (type) => { | ||
type === "prev" | ||
? router.push( | ||
{ | ||
pathname: `/products`, | ||
query: { ...queryParams, page: page - 1 }, | ||
}, | ||
undefined, | ||
{ scroll: false } | ||
) | ||
: router.push( | ||
{ | ||
pathname: `/products`, | ||
query: { ...queryParams, page: page + 1 }, | ||
}, | ||
undefined, | ||
{ scroll: false } | ||
); | ||
}; | ||
|
||
return ( | ||
<div className='flex items-center justify-center md:justify-between flex-wrap gap-4'> | ||
<div className='flex gap-4'> | ||
<button | ||
className='btn btn-sm normal-case font-normal tracking-wide' | ||
disabled={!hasPrev} | ||
onClick={() => handleChangePage("prev")} | ||
> | ||
<BiLeftArrow /> Previous | ||
</button> | ||
<button | ||
className='btn btn-sm normal-case font-normal tracking-wide' | ||
disabled={!hasNext} | ||
onClick={() => handleChangePage("next")} | ||
> | ||
Next <BiRightArrow /> | ||
</button> | ||
</div> | ||
<div> | ||
<p className='font-normal opacity-50 text-sm tracking-wide'> | ||
page: {page} of {totalPages} | ||
</p> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default Pagination; |
12 changes: 12 additions & 0 deletions
12
src/components/Items/Filters/__test__/CategoryFilter.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import renderer from "react-test-renderer"; | ||
|
||
import CategoryFilter from "../CategoryFilter"; | ||
|
||
it("renders correctly", () => { | ||
const queryParams = {}; | ||
const mockT = jest.fn(); | ||
const tree = renderer | ||
.create(<CategoryFilter queryParams={queryParams} t={mockT} />) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
9 changes: 9 additions & 0 deletions
9
src/components/Items/Filters/__test__/ClearFilterButton.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import renderer from "react-test-renderer"; | ||
|
||
import ClearFilterButton from "../ClearFilterButton"; | ||
|
||
it("renders correctly", () => { | ||
const mockT = jest.fn(); | ||
const tree = renderer.create(<ClearFilterButton t={mockT} />).toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
12 changes: 12 additions & 0 deletions
12
src/components/Items/Filters/__test__/ListingTypeFilter.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import renderer from "react-test-renderer"; | ||
|
||
import ListingTypeFilter from "../ListingTypeFilter"; | ||
|
||
it("renders correctly", () => { | ||
const queryParams = {}; | ||
const mockT = jest.fn(); | ||
const tree = renderer | ||
.create(<ListingTypeFilter queryParams={queryParams} t={mockT} />) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
12 changes: 12 additions & 0 deletions
12
src/components/Items/Filters/__test__/LocationFilter.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import renderer from "react-test-renderer"; | ||
|
||
import LocationFilter from "../LocationFilter"; | ||
|
||
it("renders correctly", () => { | ||
const queryParams = {}; | ||
const mockT = jest.fn(); | ||
const tree = renderer | ||
.create(<LocationFilter queryParams={queryParams} t={mockT} />) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import renderer from "react-test-renderer"; | ||
|
||
import Pagination from "../Pagination"; | ||
|
||
it("renders correctly", () => { | ||
const queryParams = {}; | ||
const mockT = jest.fn(); | ||
const tree = renderer | ||
.create( | ||
<Pagination | ||
page={1} | ||
totalItems={4} | ||
totalPages={3} | ||
pageSize={4} | ||
queryParams={queryParams} | ||
t={mockT} | ||
/> | ||
) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
Oops, something went wrong.