diff --git a/src/components/ui/filters.tsx b/src/components/ui/filters.tsx index 931826e..dd17916 100644 --- a/src/components/ui/filters.tsx +++ b/src/components/ui/filters.tsx @@ -1,15 +1,23 @@ import { cn } from "../../lib/utils"; import { Filter } from "../utilities/filter"; -export default function Filters() { +export default function Filters({ + categories, + selectedCategory, + setSelectedCategory, +}: { + categories: string[]; + selectedCategory: string; + setSelectedCategory: (category: string) => void; +}) { return (
- - - - - - +
); -} \ No newline at end of file +} diff --git a/src/components/ui/header.tsx b/src/components/ui/header.tsx index f47e3c5..485bc28 100644 --- a/src/components/ui/header.tsx +++ b/src/components/ui/header.tsx @@ -2,7 +2,13 @@ import SearchBar from "./searchbar"; import UserMenu from "./userMenu"; import { cn } from "../../lib/utils"; -export function Header() { +export function Header({ + search, + setSearch, +}: { + search: string; + setSearch: (search: string) => void; +}) { const handleLogout = () => { localStorage.removeItem("token"); localStorage.clear(); @@ -12,7 +18,7 @@ export function Header() { return (
- +

Witaj,{user}

diff --git a/src/components/ui/searchbar.tsx b/src/components/ui/searchbar.tsx index c35a479..8f2791b 100644 --- a/src/components/ui/searchbar.tsx +++ b/src/components/ui/searchbar.tsx @@ -3,13 +3,25 @@ import Button from "../utilities/button"; import Icon from "../../lib/iconConfig"; import { CustomClasses } from "../utilities/customClasses"; -export default function SearchBar() { +export default function SearchBar({ + search, + setSearch, +}: { + search: string; + setSearch: (search: string) => void; +}) { return (
- + setSearch(event.target.value)} + className={cn("border-none outline-none m-1 ml-2 w-full text-xs")} + />
); -} \ No newline at end of file +} diff --git a/src/components/ui/sideBar.tsx b/src/components/ui/sideBar.tsx index 1fdfee8..59ed4f7 100644 --- a/src/components/ui/sideBar.tsx +++ b/src/components/ui/sideBar.tsx @@ -4,7 +4,17 @@ import Filters from "./filters"; import Icon from "../../lib/iconConfig"; import Button from "../utilities/button"; -export default function SideBar() { +export default function SideBar({ + categories, + selectedCategory, + setSelectedCategory, + clearFilters, +}: { + categories: string[]; + selectedCategory: string; + setSelectedCategory: (category: string) => void; + clearFilters: () => void; +}) { return (
@@ -17,12 +27,16 @@ export default function SideBar() {

- +
); -} \ No newline at end of file +} diff --git a/src/components/utilities/filter.tsx b/src/components/utilities/filter.tsx index 9091fa5..528d44a 100644 --- a/src/components/utilities/filter.tsx +++ b/src/components/utilities/filter.tsx @@ -2,7 +2,17 @@ import { cn } from "../../lib/utils"; import Icon from "../../lib/iconConfig"; import { CustomClasses } from "./customClasses"; -export function Filter({name, items}: {name: string, items: string[]}) { +export function Filter({ + name, + items, + selectedItem, + setSelectedItem, +}: { + name: string; + items: string[]; + selectedItem: string; + setSelectedItem: (item: string) => void; +}) { return (

@@ -16,7 +26,12 @@ export function Filter({name, items}: {name: string, items: string[]}) { {items.map((item, index) => (
  • @@ -24,4 +39,4 @@ export function Filter({name, items}: {name: string, items: string[]}) {

    ); -} \ No newline at end of file +} diff --git a/src/hooks/useTableFilters.ts b/src/hooks/useTableFilters.ts new file mode 100644 index 0000000..dc052f0 --- /dev/null +++ b/src/hooks/useTableFilters.ts @@ -0,0 +1,48 @@ +import { useSearchParams } from "react-router-dom"; + +export function useTableFilters() { + const [params, setParams] = useSearchParams(); + + const page = Math.max(1, Math.floor(Number(params.get("page")) || 1)); + const search = params.get("search") ?? ""; + const category = params.get("category") ?? ""; + + const updateParam = (key: "search" | "page" | "category", value: string) => { + setParams((currentParams) => { + const nextParams = new URLSearchParams(currentParams); + const nextValue = value.trim(); + + if (!nextValue || (key === "page" && nextValue === "1")) { + nextParams.delete(key); + } else { + nextParams.set(key, nextValue); + } + + if (key !== "page") { + nextParams.delete("page"); + } + + return nextParams; + }); + }; + + return { + page, + search, + category, + setPage: (nextPage: number) => updateParam("page", String(nextPage)), + setSearch: (nextSearch: string) => updateParam("search", nextSearch), + setCategory: (nextCategory: string) => updateParam("category", nextCategory), + clearFilters: () => { + setParams((currentParams) => { + const nextParams = new URLSearchParams(currentParams); + + nextParams.delete("search"); + nextParams.delete("page"); + nextParams.delete("category"); + + return nextParams; + }); + }, + }; +} diff --git a/src/pages/layout.tsx b/src/pages/layout.tsx index 321f9d5..696a537 100644 --- a/src/pages/layout.tsx +++ b/src/pages/layout.tsx @@ -9,28 +9,59 @@ import { CustomClasses } from "../components/utilities/customClasses"; import EditForm from "../components/ui/editForm"; import { mockedProducts } from "../api/mockeddata"; import TableNavigation from "../components/ui/tableNavigation"; -import { useState } from "react"; +import { useEffect, useMemo, useState } from "react"; +import { useTableFilters } from "../hooks/useTableFilters"; export default function Layout() { const [isEditFormOpen, setIsEditFormOpen] = useState(false); - const [currentPage, setCurrentPage] = useState(1); + const tableFilters = useTableFilters(); function handleSetCurrentPage(page: number) { if (page < 1) { - setCurrentPage(1); + tableFilters.setPage(1); } else if (page > pages) { - setCurrentPage(pages); + tableFilters.setPage(pages); } else { - setCurrentPage(page); + tableFilters.setPage(page); } } const itemsPerPage = 7; - const pages = Math.ceil(mockedProducts.length / itemsPerPage); + const categories = useMemo( + () => Array.from(new Set(mockedProducts.map((product) => product.category))), + [], + ); + const filteredProducts = useMemo(() => { + const search = tableFilters.search.toLowerCase(); + + return mockedProducts.filter((product) => { + const matchesCategory = + !tableFilters.category || product.category === tableFilters.category; + const matchesSearch = + !search || + product.productName.toLowerCase().includes(search) || + product.barcode.toLowerCase().includes(search) || + product.producer.toLowerCase().includes(search); + + return matchesCategory && matchesSearch; + }); + }, [tableFilters.category, tableFilters.search]); + const pages = Math.max(1, Math.ceil(filteredProducts.length / itemsPerPage)); + + useEffect(() => { + if (tableFilters.page > pages) { + tableFilters.setPage(pages); + } + }, [pages, tableFilters]); return (
    -
    +
    - +
    @@ -78,14 +91,14 @@ export default function Layout() {