Skip to content

Commit 6b29961

Browse files
authored
Shop homepage redesign (#208)
* added embla carousal * banner styles * added banner * lazy load img * faq update * carticon * search design * sort design * filter section design * fixed mobile responsiveness * section wrapper * updated category filter * sort functionality * updated search * added items page * updated itemheader * shoplink update * featured products design * added product card * updated categories data * helper fns * new products section * rm unused imprts * query categoires * rm hover on mobile * rm query category * carticon update * filter items update * rm packages on banner carousal * css update * popular prods * carousal featured prods * update * fix link * update css * rm unused packages * update link * updated product section
1 parent 0f85d6c commit 6b29961

25 files changed

+2110
-1606
lines changed

src/components/FAQ.jsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
import { FaChevronDown, FaChevronUp } from "react-icons/fa";
33
import { useState } from "react";
44

5-
import { questions } from "../pages/landingPage/data";
6-
7-
function FAQ() {
5+
function FAQ({ questions }) {
86
const [activeQuestion, setActiveQuestion] = useState(null);
97

108
const toggleQuestion = (index) => {
@@ -16,14 +14,12 @@ function FAQ() {
1614
{questions.map((question, index) => (
1715
<div
1816
key={question.id}
19-
className={`rounded-xl bg-white ${
20-
activeQuestion === index && "mb-4"
21-
}`}
17+
className={`rounded-xl bg-white border shadow-sm mb-4 p-4 `}
2218
>
2319
<h2 className="mb-4 font-semibold" id={`flush-heading${index + 1}`}>
2420
<button
2521
aria-label={question.question}
26-
className={`group relative flex w-full items-center rounded-none border-0 py-4 px-5 text-left text-base transition ${
22+
className={`group relative flex w-full items-center rounded-none border-0 text-left text-base transition ${
2723
activeQuestion === index
2824
? ""
2925
: "overflow-anchor:none hover:z-[2] focus:z-[3]"
@@ -63,7 +59,7 @@ function FAQ() {
6359
aria-labelledby={`flush-heading${index + 1}`}
6460
data-te-parent="#accordionFlushExample"
6561
>
66-
<div className="py-4 px-5">{question.answer}</div>
62+
<div className=" ">{question.answer}</div>
6763
</div>
6864
</div>
6965
))}

src/components/Header.jsx

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { LazyLoadImage } from "react-lazy-load-image-component";
55
import { Link, useLocation } from "react-router-dom";
66

77
import logo from "../assets/images/sytLogo.png";
8+
import CartIcon from "./shop/CartIcon";
89

910
const navLinks = [
1011
{
@@ -37,11 +38,11 @@ const navLinks = [
3738
link: "Resources",
3839
route: "/resources",
3940
},
40-
// {
41-
// id: 7,
42-
// link: "Shop",
43-
// route: "/shop",
44-
// },
41+
{
42+
id: 7,
43+
link: "Shop",
44+
route: "/shop",
45+
},
4546
// {
4647
// id: 8,
4748
// link: "Donate",
@@ -63,30 +64,38 @@ function Header() {
6364
</Link>
6465

6566
{/* mobile menu */}
66-
{showNavlinks ? (
67-
<button
68-
type="button"
69-
aria-label="Close menu"
70-
className="md:hidden"
71-
onClick={() => setShowNavlinks(false)}
72-
>
73-
<AiOutlineClose className="h-6 w-6 text-white" aria-hidden="true" />{" "}
74-
{/* Close Icon */}
75-
</button>
76-
) : (
77-
<button
78-
type="button"
79-
aria-label="Open menu"
80-
className="md:hidden"
81-
onClick={() => setShowNavlinks(true)}
82-
>
83-
<HiOutlineMenuAlt4
84-
className="h-6 w-6 text-white"
85-
aria-hidden="true"
86-
/>{" "}
87-
{/* Menu Icon */}
88-
</button>
89-
)}
67+
<div className="flex gap-4 items-center">
68+
<div className="flex md:hidden">
69+
<CartIcon />
70+
</div>
71+
{showNavlinks ? (
72+
<button
73+
type="button"
74+
aria-label="Close menu"
75+
className="md:hidden"
76+
onClick={() => setShowNavlinks(false)}
77+
>
78+
<AiOutlineClose
79+
className="h-6 w-6 text-white"
80+
aria-hidden="true"
81+
/>{" "}
82+
{/* Close Icon */}
83+
</button>
84+
) : (
85+
<button
86+
type="button"
87+
aria-label="Open menu"
88+
className="md:hidden"
89+
onClick={() => setShowNavlinks(true)}
90+
>
91+
<HiOutlineMenuAlt4
92+
className="h-6 w-6 text-white"
93+
aria-hidden="true"
94+
/>{" "}
95+
{/* Menu Icon */}
96+
</button>
97+
)}
98+
</div>
9099

91100
{/* mobile navlinks */}
92101
<nav

src/components/shop/CartIcon.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { MdAddShoppingCart } from "react-icons/md";
2+
import SectionWrapper from "./SectionWrapper";
3+
4+
const CartIcon = () => {
5+
return (
6+
<SectionWrapper>
7+
<div className="flex justify-end ">
8+
<div className="w-12 md:w-16 h-12 md:h-16 rounded-full p-0.5 md:p-1 bg-white border shadow-lg cursor-pointer">
9+
<div className="flex w-full h-full p-1.5 md:p-2 rounded-full justify-center items-center bg-green-dark">
10+
<MdAddShoppingCart color="white" className="h-full w-full" />
11+
</div>
12+
</div>
13+
</div>
14+
</SectionWrapper>
15+
);
16+
};
17+
export default CartIcon;

src/components/shop/ProductCard.jsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { addCommaSeparator, categoryColors, cn } from "@/utilities/utils";
2+
import { CiShoppingTag } from "react-icons/ci";
3+
import { MdAddShoppingCart } from "react-icons/md";
4+
import { LazyLoadImage } from "react-lazy-load-image-component";
5+
import { Link } from "react-router-dom";
6+
7+
const ProductCard = ({ product }) => {
8+
const { backgroundColor, color } = categoryColors(product.category);
9+
10+
return (
11+
<div className="border rounded-lg p-2.5 pr-1.5 shadow-sm group hover:bg-green-dark/10 bg-white flex flex-col gap-4 ">
12+
<Link
13+
to={`/shop/item/${product.id}`}
14+
className="aspect-h-1 aspect-w-1 w-full bg-gray-200 lg:aspect-none group-hover:opacity-75 lg:h-96"
15+
>
16+
<LazyLoadImage
17+
src={product.image}
18+
alt="Product image"
19+
className="w-full h-80 object-cover object-center lg:h-full lg:w-full"
20+
/>
21+
</Link>
22+
<Link
23+
to={`/shop/item/${product.id}`}
24+
className="flex justify-between pr-1"
25+
>
26+
<h3 className="text-md uppercase font-bold text-gray-600">
27+
{product.name}
28+
</h3>
29+
<div className="p-1 rounded-xl bg-green-dark/10">
30+
{product.stock > 0 ? (
31+
<p className="text-green-dark font-medium text-sm px-1">
32+
<span> {product.stock}</span>
33+
<span className="ml-2">items left</span>
34+
</p>
35+
) : (
36+
<div className=" text-red-800 p-1 rounded-lg bg-red-800/20 font-bold text-base">
37+
<p>Out of stock</p>
38+
</div>
39+
)}
40+
</div>
41+
</Link>
42+
<div className="flex justify-start w-full">
43+
<div
44+
style={{ backgroundColor, color }}
45+
className="px-2 rounded-2xl flex gap-2 items-center"
46+
>
47+
<CiShoppingTag size={28} />
48+
<p className="font-medium text-sm">{product.category}</p>
49+
</div>
50+
</div>
51+
<div className="flex justify-between pr-1">
52+
<h3 className="text-lg font-bold text-gray-700">
53+
KES {addCommaSeparator(Number(product.price))}
54+
</h3>
55+
<div className="flex text-green-dark gap-2 items-center md:opacity-0 md:group-hover:opacity-100 transition-opacity cursor-pointer">
56+
<MdAddShoppingCart size={20} />
57+
<p className="font-bold text-base">Add to cart</p>
58+
</div>
59+
</div>
60+
</div>
61+
);
62+
};
63+
export default ProductCard;

src/components/shop/SearchInput.jsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useState } from "react";
2+
import { IoMdSearch } from "react-icons/io";
3+
import { useNavigate } from "react-router-dom";
4+
5+
const SearchInput = () => {
6+
const [searchText, setSearchText] = useState("");
7+
const navigate = useNavigate();
8+
9+
function handleSubmit(e) {
10+
e.preventDefault();
11+
navigate(`/shop/items?search=${searchText}`);
12+
}
13+
14+
return (
15+
<form
16+
onSubmit={handleSubmit}
17+
className="flex justify-between w-full relative "
18+
>
19+
<input
20+
type="text"
21+
placeholder="Search item"
22+
className="rounded-l-lg pl-16 text-sm shadow-sm w-full border outline-none py-3 text-gray-600 "
23+
value={searchText}
24+
onChange={(e) => setSearchText(e.target.value)}
25+
/>
26+
<IoMdSearch className="absolute top-3 left-8 text-gray-400 " size={24} />
27+
<button
28+
type="submit"
29+
className="text-white hidden md:block text-sm bg-gradient-to-b to-primary from-green-dark py-2 px-4 md:px-20 rounded-r-lg"
30+
>
31+
Search
32+
</button>
33+
</form>
34+
);
35+
};
36+
export default SearchInput;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const SectionWrapper = ({ children }) => {
2+
return <div className="px-4 md:px-10 lg:px-20 md:my-4">{children}</div>;
3+
};
4+
export default SectionWrapper;

src/components/shop/SortItems.jsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { IoFilter } from "react-icons/io5";
2+
import { Menu } from "@headlessui/react";
3+
import { Link, useLocation } from "react-router-dom";
4+
5+
const SortItems = () => {
6+
const { pathname } = useLocation();
7+
const path = pathname.includes("category") ? pathname : "/shop/items";
8+
9+
return (
10+
<div className="flex flex-col gap-4 relative h-full">
11+
<Menu>
12+
<Menu.Button className="rounded-lg border shadow-sm py-2 px-4 flex items-center gap-2">
13+
<IoFilter size={30} className="text-gray-400" />
14+
<p className="text-sm hidden md:block text-gray-500"> Sort</p>
15+
</Menu.Button>
16+
<Menu.Items
17+
anchor="bottom"
18+
className="absolute top-10 z-10 right-0 w-48 bg-white py-2 px-4 rounded-md flex flex-col gap-2 border shadow-sm"
19+
>
20+
<Menu.Item>
21+
<Link
22+
to={`${path}?sort=low`}
23+
className="text-sm p-2 text-gray-500 cursor-pointer hover:text-green-dark"
24+
>
25+
<p>Lowest price first</p>
26+
</Link>
27+
</Menu.Item>
28+
<Menu.Item>
29+
<Link
30+
to={`${path}?sort=high`}
31+
className="text-sm p-2 text-gray-500 cursor-pointer hover:text-green-dark"
32+
>
33+
<p>Highest price first</p>
34+
</Link>
35+
</Menu.Item>
36+
</Menu.Items>
37+
</Menu>
38+
</div>
39+
);
40+
};
41+
export default SortItems;

src/hooks/Queries/shop/useSwagList.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ const useSingleSwag = (id) =>
3838
refetchOnWindowFocus: false,
3939
});
4040

41-
export { useSwagList, useSingleSwag };
41+
export { useSwagList, useSingleSwag };

0 commit comments

Comments
 (0)