Skip to content

Commit

Permalink
feat(products): Implement product update and deletion by sellers
Browse files Browse the repository at this point in the history
- a seller should be able to update a product from their collection
- a seller should be able to delete a product from their collection

Delivers #187419126
  • Loading branch information
Heisjabo committed Jun 27, 2024
1 parent 1b6ad2e commit 013cb19
Show file tree
Hide file tree
Showing 11 changed files with 396 additions and 7 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module.exports = {
"@typescript-eslint/ban-ts-comment": "off",
"react/no-unescaped-entities": "off",
'@typescript-eslint/no-explicit-any': 0,
"jsx-a11y/control-has-associated-label": "off",
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
Expand Down
1 change: 0 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from "react";
import "react-toastify/dist/ReactToastify.css";
import "./App.css";
import "react-toastify/dist/ReactToastify.css";

import AppRoutes from "./routes/AppRoutes";

Expand Down
6 changes: 3 additions & 3 deletions src/components/dashboard/CustomSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
return (
<div className="relative min-w-40">
<div
className="appearance-none rounded-[8px] border-[0.5px] border-[#E5E5E5] px-4 py-3 bg-white text-dark-gray flex items-center justify-between text-md gap-2 border-dark-gray text-dark-gray cursor-pointer"
className="appearance-none rounded-[8px] border-[0.5px] border-[#E5E5E5] px-4 py-3 bg-white flex items-center justify-between text-md gap-2 text-black cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
data-testid={testId}
>
Expand All @@ -39,7 +39,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
<FaAngleDown />
</div>
{isOpen && (
<div className="absolute category-options top-full h-64 overflow-y-scroll w-full left-0 z-10 dark:bg-secondary-black shadow rounded-[8px] py-3 bg-white text-[#161616] border-dark-gray mt-1">
<div className="absolute category-options top-full h-64 overflow-y-scroll w-full left-0 z-10 shadow rounded-[8px] py-3 bg-white text-[#161616] border-gray-800 mt-1">
{loading ? (
<div className="flex items-center justify-center select-none py-6">
loading categories...
Expand All @@ -52,7 +52,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
options.map((option) => (
<div
key={option.id}
className="px-4 py-2 text-dark-gray text-md hover:bg-[#F7F8FA] cursor-pointer"
className="px-4 py-2 text-gray-700 text-md hover:bg-[#F7F8FA] cursor-pointer"
onClick={() => handleOptionClick(option)}
>
{option.name}
Expand Down
2 changes: 1 addition & 1 deletion src/components/dashboard/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface HeaderProps {
}

const Header: React.FC<HeaderProps> = ({ toggleSidebar }) => (
<header className="flex lg:w-[80%] lg:ml-[5%] px-8 fixed z-30 top-0 items-center w-full justify-between py-4 bg-white dark:bg-secondary-black">
<header className="flex lg:w-[80%] lg:ml-[5%] px-8 fixed z-30 top-0 items-center w-full justify-between py-4 bg-white">
<div className="relative flex items-center justify-between w-full lg:hidden">
<FiMenu className="text-black w-6 h-6 mr-3" onClick={toggleSidebar} />
<div className="flex items-center gap-4">
Expand Down
67 changes: 67 additions & 0 deletions src/components/dashboard/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";

interface PaginationProps {
currentPage: number;
totalItems: number;
itemsPerPage: number;
onPageChange: (page: number) => void;
onItemsPerPageChange: (itemsPerPage: number) => void;
}

const Pagination: React.FC<PaginationProps> = ({
currentPage,
totalItems,
itemsPerPage,
onPageChange,
onItemsPerPageChange,
}) => {
const totalPages = Math.ceil(totalItems / itemsPerPage);

return (
<div className="flex justify-between flex-col md:flex-row items-center mt-4">
<div className="flex items-center">
<label htmlFor="itemsPerPage" className="mr-2 text-black">
Show result:
</label>
<select
id="itemsPerPage"
value={itemsPerPage}
onChange={(e) => onItemsPerPageChange(Number(e.target.value))}
className=" bg-transparent border-[0.5px] border-gray-500 text-center bg-slate-100 focus:outline-none text-black px-2 py-1 rounded-lg"
>
<option value={2}>2</option>
<option value={5}>5</option>
<option value={10}>10</option>
</select>
</div>
<div className="flex items-center py-4">
<button
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
className="px-3 py-1 mx-1 rounded-lg bg-gray-200 text-black"
>
<FaChevronLeft />
</button>
{Array.from({ length: totalPages }, (_, index) => (
<button
key={index + 1}
onClick={() => onPageChange(index + 1)}
className={`px-3 py-1 mx-1 rounded-lg ${currentPage === index + 1 ? "bg-[#DB4444] text-white" : "bg-gray-200 text-black"}`}
>
{index + 1}
</button>
))}
<button
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
className="px-3 py-1 mx-1 rounded-lg bg-gray-200 text-black"
>
<FaChevronRight />
</button>
</div>
</div>
);
};

export default Pagination;
4 changes: 2 additions & 2 deletions src/components/dashboard/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const SideBar: React.FC<SidebarProps> = ({ isOpen }) => (
</NavLink>

<NavLink
to="/products"
to="/dashboard/products"
className="py-2.5 px-4 flex items-center gap-2 text-lg rounded transition duration-200"
>
<AiFillProduct className="text-xl" />
Expand Down Expand Up @@ -81,7 +81,7 @@ const SideBar: React.FC<SidebarProps> = ({ isOpen }) => (
</NavLink>
</nav>
</div>
<div className=" flex justify-center items-center gap-4 cursor-pointer text-dark-gray">
<div className="flex justify-center items-center gap-4 cursor-pointer text-gray-700">
<FiLogOut className="text-xl" />
{' '}
Log Out
Expand Down
59 changes: 59 additions & 0 deletions src/components/dashboard/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from "react";

interface ToggleSwitchProps {
checked: boolean;
onChange: () => void;
}

const ToggleSwitch: React.FC<ToggleSwitchProps> = ({ checked, onChange }) => (
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
className="sr-only"
checked={checked}
onChange={onChange}
/>
<div
className={`block w-14 h-8 rounded-full ${checked ? "bg-[#DB4444]" : "bg-[#D4D4D4]"}`}
/>
<div
className={`dot absolute left-1 top-1 flex justify-center bg-white w-6 h-6 rounded-full transition ${
checked ? "transform translate-x-6" : ""
}`}
>
{checked ? (
<svg
className="w-4 h-4 text-brand-blue mx-auto my-auto"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
) : (
<svg
className="w-4 h-4 text-gray-700 mx-auto my-auto"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 12h12"
/>
</svg>
)}
</div>
</label>
);

export default ToggleSwitch;
51 changes: 51 additions & 0 deletions src/components/dashboard/products/CategorySelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from "react";
import { FaAngleDown } from "react-icons/fa";

interface CategorySelectProps {
options: string[];
defaultValue: string;
onSelect: (option: string) => void;
}

const CategorySelect: React.FC<CategorySelectProps> = ({
options,
defaultValue,
onSelect,
}) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState(defaultValue);

const handleOptionClick = (option: string) => {
setSelectedOption(option);
setIsOpen(false);
onSelect(option);
};

return (
<div className="relative min-w-40">
<div
className="appearance-none bg-transparent border-[0.5px] flex items-center justify-between text-md gap-2 border-gray-400 text-dark-gray px-4 py-2 rounded-lg cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
>
{selectedOption}
{' '}
<FaAngleDown />
</div>
{isOpen && (
<div className="absolute top-full left-0 z-10 bg-white w-full text-dark-gray rounded-lg border-[0.5px] border-gray-400 mt-1">
{options.map((option) => (
<div
key={option}
className="px-4 py-2 text-dark-gray whitespace-nowrap text-md hover:bg-slate-50 cursor-pointer"
onClick={() => handleOptionClick(option)}
>
{option}
</div>
))}
</div>
)}
</div>
);
};

export default CategorySelect;
Loading

0 comments on commit 013cb19

Please sign in to comment.