From bf16a84ba4467ec0f18f9071b3581a6cb3f2e9f2 Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Tue, 21 Jul 2026 10:49:40 +0330 Subject: [PATCH] product list --- src/pages/product/List.tsx | 58 +++++++++++++++++++-- src/pages/product/hooks/useProductData.ts | 21 +++++--- src/pages/product/service/ProductService.ts | 34 ++++++++++-- 3 files changed, 98 insertions(+), 15 deletions(-) diff --git a/src/pages/product/List.tsx b/src/pages/product/List.tsx index c4228da..964b324 100644 --- a/src/pages/product/List.tsx +++ b/src/pages/product/List.tsx @@ -1,9 +1,10 @@ import Button from '@/components/Button' -import Filters from '@/components/Filters' +import Filters, { type FilterValues } from '@/components/Filters' import Table from '@/components/Table' +import Tabs from '@/components/Tabs' import { AddSquare, Edit, More2 } from 'iconsax-react' -import { type FC, useState } from 'react' -import { useDeleteProduct, useDuplicateProduct, useGetProducts } from './hooks/useProductData' +import { type FC, useMemo, useState } from 'react' +import { useDeleteProduct, useDuplicateProduct, useGetCategory, useGetProducts } from './hooks/useProductData' import { Link } from 'react-router-dom' import { Paths } from '@/config/Paths' import TrashWithConfrim from '@/components/TrashWithConfrim' @@ -12,8 +13,37 @@ import { toast } from 'react-toastify' import { extractErrorMessage } from '@/config/func' const ProductList: FC = () => { + const [page, setPage] = useState(1) + const [search, setSearch] = useState('') + const [categoryId, setCategoryId] = useState('') - const { data: products, refetch } = useGetProducts() + const { data: categoriesData } = useGetCategory({ limit: 1000 }) + const { data: products, refetch } = useGetProducts({ + page, + search: search || undefined, + categoryId: categoryId || undefined, + }) + + const categoryTabs = useMemo( + () => [ + { label: 'همه', value: '' }, + ...(categoriesData?.data?.map((category) => ({ + label: category.title, + value: category.id, + })) ?? []), + ], + [categoriesData?.data], + ) + + const handleFiltersChange = (filters: FilterValues) => { + setSearch((filters.search as string) ?? '') + setPage(1) + } + + const handleCategoryTabChange = (tab: string) => { + setCategoryId(tab) + setPage(1) + } const { mutate: deleteProduct, isPending: isDeleting } = useDeleteProduct() const { mutate: duplicateProduct, isPending: isDuplicating } = useDuplicateProduct() const [duplicatingId, setDuplicatingId] = useState(null) @@ -68,6 +98,14 @@ const ProductList: FC = () => { +
+ +
+
{ placeholder: 'جستجوی محصول' } ]} - onChange={() => { }} + onChange={handleFiltersChange} />
@@ -88,6 +126,11 @@ const ProductList: FC = () => { key: 'title', title: 'عنوان محصول', }, + { + key: 'category', + title: 'دسته‌بندی', + render: (item) => item.category?.title ?? '-', + }, { key: 'attribute', title: 'ویژگی ها', @@ -133,6 +176,11 @@ const ProductList: FC = () => { }, ]} data={products?.data} + pagination={{ + currentPage: page, + onPageChange: setPage, + totalPages: products?.meta?.totalPages ?? 1, + }} /> diff --git a/src/pages/product/hooks/useProductData.ts b/src/pages/product/hooks/useProductData.ts index a1e7328..cc97aad 100644 --- a/src/pages/product/hooks/useProductData.ts +++ b/src/pages/product/hooks/useProductData.ts @@ -12,10 +12,14 @@ import type { CreateProductType, } from "../types/Types"; -export const useGetCategory = () => { +export const useGetCategory = (params?: api.GetCategoryParams) => { + const page = params?.page ?? 1; + const limit = params?.limit; + const search = params?.search; + return useQuery({ - queryKey: ["category"], - queryFn: api.getCategory, + queryKey: ["category", page, limit, search], + queryFn: () => api.getCategory({ page, limit, search }), }); }; @@ -52,10 +56,15 @@ export const useGetCategoryDetail = (id: string) => { }); }; -export const useGetProducts = () => { +export const useGetProducts = (params?: api.GetProductsParams) => { + const page = params?.page ?? 1; + const search = params?.search; + const limit = params?.limit; + const categoryId = params?.categoryId; + return useQuery({ - queryKey: ["products"], - queryFn: api.getProducts, + queryKey: ["products", page, search, limit, categoryId], + queryFn: () => api.getProducts({ page, search, limit, categoryId }), }); }; diff --git a/src/pages/product/service/ProductService.ts b/src/pages/product/service/ProductService.ts index 6ed459c..404bce3 100644 --- a/src/pages/product/service/ProductService.ts +++ b/src/pages/product/service/ProductService.ts @@ -1,8 +1,20 @@ import axios from "@/config/axios"; import { type AttributeDetailResponseType, type AttributeResponseType, type AttributeValueDetailResponseType, type AttributeValuesResponseType, type CategoriesResponse, type CategoryResponse, type CreateAttributeType, type CreateAttributeValueType, type CreateCategoryType, type CreateProductType, type ProductDetailResponeType, type ProductResponeType } from "../types/Types"; -export const getCategory = async () => { - const { data } = await axios.get("/admin/category"); +export type GetCategoryParams = { + page?: number; + limit?: number; + search?: string; +}; + +export const getCategory = async (params?: GetCategoryParams) => { + const { data } = await axios.get("/admin/category", { + params: { + page: params?.page, + limit: params?.limit, + search: params?.search || undefined, + }, + }); return data; }; @@ -26,8 +38,22 @@ export const getCategoryDetail = async(id:string) => { return data } -export const getProducts = async () => { - const { data } = await axios.get("/admin/products"); +export type GetProductsParams = { + page?: number; + limit?: number; + search?: string; + categoryId?: string; +}; + +export const getProducts = async (params?: GetProductsParams) => { + const { data } = await axios.get("/admin/products", { + params: { + page: params?.page, + limit: params?.limit, + search: params?.search || undefined, + categoryId: params?.categoryId || undefined, + }, + }); return data; };