Skip to content

Commit

Permalink
Shop homepage redesign (#208)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
bugswritter authored Jul 18, 2024
1 parent 0f85d6c commit 6b29961
Show file tree
Hide file tree
Showing 25 changed files with 2,110 additions and 1,606 deletions.
12 changes: 4 additions & 8 deletions src/components/FAQ.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
import { FaChevronDown, FaChevronUp } from "react-icons/fa";
import { useState } from "react";

import { questions } from "../pages/landingPage/data";

function FAQ() {
function FAQ({ questions }) {
const [activeQuestion, setActiveQuestion] = useState(null);

const toggleQuestion = (index) => {
Expand All @@ -16,14 +14,12 @@ function FAQ() {
{questions.map((question, index) => (
<div
key={question.id}
className={`rounded-xl bg-white ${
activeQuestion === index && "mb-4"
}`}
className={`rounded-xl bg-white border shadow-sm mb-4 p-4 `}
>
<h2 className="mb-4 font-semibold" id={`flush-heading${index + 1}`}>
<button
aria-label={question.question}
className={`group relative flex w-full items-center rounded-none border-0 py-4 px-5 text-left text-base transition ${
className={`group relative flex w-full items-center rounded-none border-0 text-left text-base transition ${
activeQuestion === index
? ""
: "overflow-anchor:none hover:z-[2] focus:z-[3]"
Expand Down Expand Up @@ -63,7 +59,7 @@ function FAQ() {
aria-labelledby={`flush-heading${index + 1}`}
data-te-parent="#accordionFlushExample"
>
<div className="py-4 px-5">{question.answer}</div>
<div className=" ">{question.answer}</div>
</div>
</div>
))}
Expand Down
67 changes: 38 additions & 29 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link, useLocation } from "react-router-dom";

import logo from "../assets/images/sytLogo.png";
import CartIcon from "./shop/CartIcon";

const navLinks = [
{
Expand Down Expand Up @@ -37,11 +38,11 @@ const navLinks = [
link: "Resources",
route: "/resources",
},
// {
// id: 7,
// link: "Shop",
// route: "/shop",
// },
{
id: 7,
link: "Shop",
route: "/shop",
},
// {
// id: 8,
// link: "Donate",
Expand All @@ -63,30 +64,38 @@ function Header() {
</Link>

{/* mobile menu */}
{showNavlinks ? (
<button
type="button"
aria-label="Close menu"
className="md:hidden"
onClick={() => setShowNavlinks(false)}
>
<AiOutlineClose className="h-6 w-6 text-white" aria-hidden="true" />{" "}
{/* Close Icon */}
</button>
) : (
<button
type="button"
aria-label="Open menu"
className="md:hidden"
onClick={() => setShowNavlinks(true)}
>
<HiOutlineMenuAlt4
className="h-6 w-6 text-white"
aria-hidden="true"
/>{" "}
{/* Menu Icon */}
</button>
)}
<div className="flex gap-4 items-center">
<div className="flex md:hidden">
<CartIcon />
</div>
{showNavlinks ? (
<button
type="button"
aria-label="Close menu"
className="md:hidden"
onClick={() => setShowNavlinks(false)}
>
<AiOutlineClose
className="h-6 w-6 text-white"
aria-hidden="true"
/>{" "}
{/* Close Icon */}
</button>
) : (
<button
type="button"
aria-label="Open menu"
className="md:hidden"
onClick={() => setShowNavlinks(true)}
>
<HiOutlineMenuAlt4
className="h-6 w-6 text-white"
aria-hidden="true"
/>{" "}
{/* Menu Icon */}
</button>
)}
</div>

{/* mobile navlinks */}
<nav
Expand Down
17 changes: 17 additions & 0 deletions src/components/shop/CartIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { MdAddShoppingCart } from "react-icons/md";
import SectionWrapper from "./SectionWrapper";

const CartIcon = () => {
return (
<SectionWrapper>
<div className="flex justify-end ">
<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">
<div className="flex w-full h-full p-1.5 md:p-2 rounded-full justify-center items-center bg-green-dark">
<MdAddShoppingCart color="white" className="h-full w-full" />
</div>
</div>
</div>
</SectionWrapper>
);
};
export default CartIcon;
63 changes: 63 additions & 0 deletions src/components/shop/ProductCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { addCommaSeparator, categoryColors, cn } from "@/utilities/utils";
import { CiShoppingTag } from "react-icons/ci";
import { MdAddShoppingCart } from "react-icons/md";
import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link } from "react-router-dom";

const ProductCard = ({ product }) => {
const { backgroundColor, color } = categoryColors(product.category);

return (
<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 ">
<Link
to={`/shop/item/${product.id}`}
className="aspect-h-1 aspect-w-1 w-full bg-gray-200 lg:aspect-none group-hover:opacity-75 lg:h-96"
>
<LazyLoadImage
src={product.image}
alt="Product image"
className="w-full h-80 object-cover object-center lg:h-full lg:w-full"
/>
</Link>
<Link
to={`/shop/item/${product.id}`}
className="flex justify-between pr-1"
>
<h3 className="text-md uppercase font-bold text-gray-600">
{product.name}
</h3>
<div className="p-1 rounded-xl bg-green-dark/10">
{product.stock > 0 ? (
<p className="text-green-dark font-medium text-sm px-1">
<span> {product.stock}</span>
<span className="ml-2">items left</span>
</p>
) : (
<div className=" text-red-800 p-1 rounded-lg bg-red-800/20 font-bold text-base">
<p>Out of stock</p>
</div>
)}
</div>
</Link>
<div className="flex justify-start w-full">
<div
style={{ backgroundColor, color }}
className="px-2 rounded-2xl flex gap-2 items-center"
>
<CiShoppingTag size={28} />
<p className="font-medium text-sm">{product.category}</p>
</div>
</div>
<div className="flex justify-between pr-1">
<h3 className="text-lg font-bold text-gray-700">
KES {addCommaSeparator(Number(product.price))}
</h3>
<div className="flex text-green-dark gap-2 items-center md:opacity-0 md:group-hover:opacity-100 transition-opacity cursor-pointer">
<MdAddShoppingCart size={20} />
<p className="font-bold text-base">Add to cart</p>
</div>
</div>
</div>
);
};
export default ProductCard;
36 changes: 36 additions & 0 deletions src/components/shop/SearchInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useState } from "react";
import { IoMdSearch } from "react-icons/io";
import { useNavigate } from "react-router-dom";

const SearchInput = () => {
const [searchText, setSearchText] = useState("");
const navigate = useNavigate();

function handleSubmit(e) {
e.preventDefault();
navigate(`/shop/items?search=${searchText}`);
}

return (
<form
onSubmit={handleSubmit}
className="flex justify-between w-full relative "
>
<input
type="text"
placeholder="Search item"
className="rounded-l-lg pl-16 text-sm shadow-sm w-full border outline-none py-3 text-gray-600 "
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
/>
<IoMdSearch className="absolute top-3 left-8 text-gray-400 " size={24} />
<button
type="submit"
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"
>
Search
</button>
</form>
);
};
export default SearchInput;
4 changes: 4 additions & 0 deletions src/components/shop/SectionWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const SectionWrapper = ({ children }) => {
return <div className="px-4 md:px-10 lg:px-20 md:my-4">{children}</div>;
};
export default SectionWrapper;
41 changes: 41 additions & 0 deletions src/components/shop/SortItems.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { IoFilter } from "react-icons/io5";
import { Menu } from "@headlessui/react";
import { Link, useLocation } from "react-router-dom";

const SortItems = () => {
const { pathname } = useLocation();
const path = pathname.includes("category") ? pathname : "/shop/items";

return (
<div className="flex flex-col gap-4 relative h-full">
<Menu>
<Menu.Button className="rounded-lg border shadow-sm py-2 px-4 flex items-center gap-2">
<IoFilter size={30} className="text-gray-400" />
<p className="text-sm hidden md:block text-gray-500"> Sort</p>
</Menu.Button>
<Menu.Items
anchor="bottom"
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"
>
<Menu.Item>
<Link
to={`${path}?sort=low`}
className="text-sm p-2 text-gray-500 cursor-pointer hover:text-green-dark"
>
<p>Lowest price first</p>
</Link>
</Menu.Item>
<Menu.Item>
<Link
to={`${path}?sort=high`}
className="text-sm p-2 text-gray-500 cursor-pointer hover:text-green-dark"
>
<p>Highest price first</p>
</Link>
</Menu.Item>
</Menu.Items>
</Menu>
</div>
);
};
export default SortItems;
2 changes: 1 addition & 1 deletion src/hooks/Queries/shop/useSwagList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ const useSingleSwag = (id) =>
refetchOnWindowFocus: false,
});

export { useSwagList, useSingleSwag };
export { useSwagList, useSingleSwag };
Loading

0 comments on commit 6b29961

Please sign in to comment.