feat list product and category

This commit is contained in:
ferdiansyah783
2025-08-05 14:34:36 +07:00
parent fffa2ead5c
commit 0fde122ac4
8 changed files with 388 additions and 382 deletions
@@ -1,7 +1,7 @@
'use client'
// React Imports
import { useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
@@ -39,6 +39,10 @@ import TablePaginationComponent from '@components/TablePaginationComponent'
// Style Imports
import tableStyles from '@core/styles/table.module.css'
import { useCategoriesQuery } from '../../../../../services/queries/categories'
import { Category } from '../../../../../types/services/category'
import { Box, CircularProgress } from '@mui/material'
import Loading from '../../../../../components/layout/shared/Loading'
declare module '@tanstack/table-core' {
interface FilterFns {
@@ -49,16 +53,7 @@ declare module '@tanstack/table-core' {
}
}
export type categoryType = {
id: number
categoryTitle: string
description: string
totalProduct: number
totalEarning: number
image: string
}
type CategoryWithActionsType = categoryType & {
type CategoryWithActionsType = Category & {
actions?: string
}
@@ -104,106 +99,6 @@ const DebouncedInput = ({
return <CustomTextField {...props} value={value} onChange={e => setValue(e.target.value)} />
}
// Vars
const categoryData: categoryType[] = [
{
id: 1,
categoryTitle: 'Smart Phone',
description: 'Choose from wide range of smartphones online at best prices.',
totalProduct: 12548,
totalEarning: 98784,
image: '/images/apps/ecommerce/product-1.png'
},
{
id: 2,
categoryTitle: 'Clothing, Shoes, and jewellery',
description: 'Fashion for a wide selection of clothing, shoes, jewellery and watches.',
totalProduct: 4689,
totalEarning: 45627,
image: '/images/apps/ecommerce/product-9.png'
},
{
id: 3,
categoryTitle: 'Home and Kitchen',
description: 'Browse through the wide range of Home and kitchen products.',
totalProduct: 11297,
totalEarning: 51097,
image: '/images/apps/ecommerce/product-10.png'
},
{
id: 4,
categoryTitle: 'Beauty and Personal Care',
description: 'Explore beauty and personal care products, shop makeup and etc.',
totalProduct: 9474,
totalEarning: 74829,
image: '/images/apps/ecommerce/product-19.png'
},
{
id: 5,
categoryTitle: 'Books',
description: 'Over 25 million titles across categories such as business and etc.',
totalProduct: 10257,
totalEarning: 63618,
image: '/images/apps/ecommerce/product-25.png'
},
{
id: 6,
categoryTitle: 'Games',
description: 'Every month, get exclusive in-game loot, free games, a free subscription.',
totalProduct: 14501,
totalEarning: 65920,
image: '/images/apps/ecommerce/product-12.png'
},
{
id: 7,
categoryTitle: 'Baby Products',
description: 'Buy baby products across different categories from top brands.',
totalProduct: 8624,
totalEarning: 38838,
image: '/images/apps/ecommerce/product-14.png'
},
{
id: 8,
categoryTitle: 'Growsari',
description: 'Shop grocery Items through at best prices in India.',
totalProduct: 7389,
totalEarning: 72652,
image: '/images/apps/ecommerce/product-26.png'
},
{
id: 9,
categoryTitle: 'Computer Accessories',
description: 'Enhance your computing experience with our range of computer accessories.',
totalProduct: 9876,
totalEarning: 65421,
image: '/images/apps/ecommerce/product-17.png'
},
{
id: 10,
categoryTitle: 'Fitness Tracker',
description: 'Monitor your health and fitness goals with our range of advanced fitness trackers.',
totalProduct: 1987,
totalEarning: 32067,
image: '/images/apps/ecommerce/product-10.png'
},
{
id: 11,
categoryTitle: 'Smart Home Devices',
description: 'Transform your home into a smart home with our innovative smart home devices.',
totalProduct: 2345,
totalEarning: 87654,
image: '/images/apps/ecommerce/product-11.png'
},
{
id: 12,
categoryTitle: 'Audio Speakers',
description: 'Immerse yourself in rich audio quality with our wide range of speakers.',
totalProduct: 5678,
totalEarning: 32145,
image: '/images/apps/ecommerce/product-2.png'
}
]
// Column Definitions
const columnHelper = createColumnHelper<CategoryWithActionsType>()
@@ -211,8 +106,28 @@ const ProductCategoryTable = () => {
// States
const [addCategoryOpen, setAddCategoryOpen] = useState(false)
const [rowSelection, setRowSelection] = useState({})
const [data, setData] = useState(...[categoryData])
const [globalFilter, setGlobalFilter] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
// Fetch products with pagination and search
const { data, isLoading, error, isFetching } = useCategoriesQuery.getCategories({
page: currentPage,
limit: pageSize
})
const categories = data?.categories ?? []
const totalCount = data?.total_count ?? 0
const handlePageChange = useCallback((event: unknown, newPage: number) => {
setCurrentPage(newPage)
}, [])
// Handle page size change
const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const newPageSize = parseInt(event.target.value, 10)
setPageSize(newPageSize)
setCurrentPage(0) // Reset to first page
}, [])
const columns = useMemo<ColumnDef<CategoryWithActionsType, any>[]>(
() => [
@@ -238,31 +153,27 @@ const ProductCategoryTable = () => {
/>
)
},
columnHelper.accessor('categoryTitle', {
header: 'Categories',
columnHelper.accessor('name', {
header: 'Name',
cell: ({ row }) => (
<div className='flex items-center gap-3'>
<img src={row.original.image} width={38} height={38} className='rounded bg-actionHover' />
{/* <img src={row.original.image} width={38} height={38} className='rounded bg-actionHover' /> */}
<div className='flex flex-col items-start'>
<Typography className='font-medium' color='text.primary'>
{row.original.categoryTitle}
{row.original.name}
</Typography>
<Typography variant='body2'>{row.original.description}</Typography>
</div>
</div>
)
}),
columnHelper.accessor('totalProduct', {
header: 'Total Products',
cell: ({ row }) => <Typography>{row.original.totalProduct.toLocaleString()}</Typography>
columnHelper.accessor('description', {
header: 'Decription',
cell: ({ row }) => <Typography>{row.original.description || '-'}</Typography>
}),
columnHelper.accessor('totalEarning', {
header: 'Total Earning',
cell: ({ row }) => (
<Typography>
{row.original.totalEarning.toLocaleString('en-IN', { style: 'currency', currency: 'USD' })}
</Typography>
)
columnHelper.accessor('business_type', {
header: 'Business Type',
cell: ({ row }) => <Typography>{row.original.business_type}</Typography>
}),
columnHelper.accessor('actions', {
header: 'Actions',
@@ -279,7 +190,7 @@ const ProductCategoryTable = () => {
{
text: 'Delete',
icon: 'tabler-trash',
menuItemProps: { onClick: () => setData(data.filter(category => category.id !== row.original.id)) }
menuItemProps: { onClick: () => console.log('click') }
},
{ text: 'Duplicate', icon: 'tabler-copy' }
]}
@@ -294,32 +205,24 @@ const ProductCategoryTable = () => {
)
const table = useReactTable({
data: data as categoryType[],
data: categories as Category[],
columns,
filterFns: {
fuzzy: fuzzyFilter
},
state: {
rowSelection,
globalFilter
},
initialState: {
pagination: {
pageSize: 10
pageIndex: currentPage, // <= penting!
pageSize
}
},
enableRowSelection: true, //enable row selection for all rows
// enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row
globalFilterFn: fuzzyFilter,
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
onGlobalFilterChange: setGlobalFilter,
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues()
// Disable client-side pagination since we're handling it server-side
manualPagination: true,
pageCount: Math.ceil(totalCount / pageSize)
})
return (
@@ -327,9 +230,9 @@ const ProductCategoryTable = () => {
<Card>
<div className='flex flex-wrap justify-between gap-4 p-6'>
<DebouncedInput
value={globalFilter ?? ''}
onChange={value => setGlobalFilter(String(value))}
placeholder='Search'
value={'search'}
onChange={value => console.log(value)}
placeholder='Search Product'
className='max-sm:is-full'
/>
<div className='flex max-sm:flex-col items-start sm:items-center gap-4 max-sm:is-full'>
@@ -354,74 +257,103 @@ const ProductCategoryTable = () => {
</div>
</div>
<div className='overflow-x-auto'>
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
No data available
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
{isLoading ? (
<Loading />
) : (
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
No data available
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
)}
{isFetching && !isLoading && (
<Box
position='absolute'
top={0}
left={0}
right={0}
bottom={0}
display='flex'
alignItems='center'
justifyContent='center'
bgcolor='rgba(255,255,255,0.7)'
zIndex={1}
>
<CircularProgress size={24} />
</Box>
)}
</div>
<TablePagination
component={() => <TablePaginationComponent table={table} />}
count={table.getFilteredRowModel().rows.length}
rowsPerPage={table.getState().pagination.pageSize}
page={table.getState().pagination.pageIndex}
onPageChange={(_, page) => {
table.setPageIndex(page)
}}
component={() => (
<TablePaginationComponent
pageIndex={currentPage}
pageSize={pageSize}
totalCount={totalCount}
onPageChange={handlePageChange}
/>
)}
count={totalCount}
rowsPerPage={pageSize}
page={currentPage}
onPageChange={handlePageChange}
onRowsPerPageChange={handlePageSizeChange}
rowsPerPageOptions={[10, 25, 50]}
disabled={isLoading}
/>
</Card>
<AddCategoryDrawer
open={addCategoryOpen}
categoryData={data}
setData={setData}
categoryData={categories}
setData={() => {}}
handleClose={() => setAddCategoryOpen(!addCategoryOpen)}
/>
</>
@@ -1,63 +1,50 @@
'use client'
// React Imports
import { useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
// Next Imports
import Link from 'next/link'
import { useParams } from 'next/navigation'
// MUI Imports
import Button from '@mui/material/Button'
import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader'
import Button from '@mui/material/Button'
import Chip from '@mui/material/Chip'
import Checkbox from '@mui/material/Checkbox'
import Chip from '@mui/material/Chip'
import Divider from '@mui/material/Divider'
import IconButton from '@mui/material/IconButton'
import Switch from '@mui/material/Switch'
import MenuItem from '@mui/material/MenuItem'
import TablePagination from '@mui/material/TablePagination'
import Typography from '@mui/material/Typography'
import type { TextFieldProps } from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
// Third-party Imports
import classnames from 'classnames'
import { rankItem } from '@tanstack/match-sorter-utils'
import {
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
getFilteredRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFacetedMinMaxValues,
getPaginationRowModel,
getSortedRowModel
} from '@tanstack/react-table'
import type { ColumnDef, FilterFn } from '@tanstack/react-table'
import type { RankingInfo } from '@tanstack/match-sorter-utils'
import { rankItem } from '@tanstack/match-sorter-utils'
import type { ColumnDef, FilterFn } from '@tanstack/react-table'
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'
import classnames from 'classnames'
// Type Imports
import type { ThemeColor } from '@core/types'
import type { Locale } from '@configs/i18n'
import type { ProductType } from '@/types/apps/ecommerceTypes'
// Component Imports
import TableFilters from './TableFilters'
import CustomAvatar from '@core/components/mui/Avatar'
import TablePaginationComponent from '@components/TablePaginationComponent'
import CustomTextField from '@core/components/mui/TextField'
import OptionMenu from '@core/components/option-menu'
import TablePaginationComponent from '@components/TablePaginationComponent'
import TableFilters from './TableFilters'
// Util Imports
import { getLocalizedUrl } from '@/utils/i18n'
// Style Imports
import tableStyles from '@core/styles/table.module.css'
import { Box, CircularProgress } from '@mui/material'
import Loading from '../../../../../components/layout/shared/Loading'
import { useProductsQuery } from '../../../../../services/queries/products'
import { Product } from '../../../../../types/services/products'
import { Product } from '../../../../../types/services/product'
declare module '@tanstack/table-core' {
interface FilterFns {
@@ -72,20 +59,6 @@ type ProductWithActionsType = Product & {
actions?: string
}
type ProductCategoryType = {
[key: string]: {
icon: string
color: ThemeColor
}
}
type productStatusType = {
[key: string]: {
title: string
color: ThemeColor
}
}
const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
// Rank the item
const itemRank = rankItem(row.getValue(columnId), value)
@@ -128,36 +101,37 @@ const DebouncedInput = ({
return <CustomTextField {...props} value={value} onChange={e => setValue(e.target.value)} />
}
// Vars
const productCategoryObj: ProductCategoryType = {
Accessories: { icon: 'tabler-headphones', color: 'error' },
'Home Decor': { icon: 'tabler-smart-home', color: 'info' },
Electronics: { icon: 'tabler-device-laptop', color: 'primary' },
Shoes: { icon: 'tabler-shoe', color: 'success' },
Office: { icon: 'tabler-briefcase', color: 'warning' },
Games: { icon: 'tabler-device-gamepad-2', color: 'secondary' }
}
const productStatusObj: productStatusType = {
Scheduled: { title: 'Scheduled', color: 'warning' },
Published: { title: 'Publish', color: 'success' },
Inactive: { title: 'Inactive', color: 'error' }
}
// Column Definitions
const columnHelper = createColumnHelper<ProductWithActionsType>()
const ProductListTable = () => {
// States
const { data } = useProductsQuery.getProducts()
const [rowSelection, setRowSelection] = useState({})
const [filteredData, setFilteredData] = useState(data?.products ?? [])
const [globalFilter, setGlobalFilter] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
// Hooks
const { lang: locale } = useParams()
// Fetch products with pagination and search
const { data, isLoading, error, isFetching } = useProductsQuery.getProducts({
page: currentPage,
limit: pageSize
})
const products = data?.products ?? []
const totalCount = data?.total_count ?? 0
const handlePageChange = useCallback((event: unknown, newPage: number) => {
setCurrentPage(newPage)
}, [])
// Handle page size change
const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const newPageSize = parseInt(event.target.value, 10)
setPageSize(newPageSize)
setCurrentPage(0) // Reset to first page
}, [])
const columns = useMemo<ColumnDef<ProductWithActionsType, any>[]>(
() => [
{
@@ -226,7 +200,7 @@ const ProductListTable = () => {
}),
columnHelper.accessor('is_active', {
header: 'Status',
cell: ({row}) => (
cell: ({ row }) => (
<Chip
label={row.original.is_active ? 'Active' : 'Inactive'}
variant='tonal'
@@ -261,48 +235,40 @@ const ProductListTable = () => {
})
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[data, filteredData]
[]
)
const table = useReactTable({
data: filteredData as Product[],
data: products as Product[],
columns,
filterFns: {
fuzzy: fuzzyFilter
},
state: {
rowSelection,
globalFilter
},
initialState: {
pagination: {
pageSize: 10
pageIndex: currentPage, // <= penting!
pageSize
}
},
enableRowSelection: true, //enable row selection for all rows
// enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row
globalFilterFn: fuzzyFilter,
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
onGlobalFilterChange: setGlobalFilter,
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues()
// Disable client-side pagination since we're handling it server-side
manualPagination: true,
pageCount: Math.ceil(totalCount / pageSize)
})
return (
<>
<Card>
<CardHeader title='Filters' />
<TableFilters setData={setFilteredData} productData={data?.products} />
<TableFilters setData={() => {}} productData={[]} />
<Divider />
<div className='flex flex-wrap justify-between gap-4 p-6'>
<DebouncedInput
value={globalFilter ?? ''}
onChange={value => setGlobalFilter(String(value))}
value={'search'}
onChange={value => console.log(value)}
placeholder='Search Product'
className='max-sm:is-full'
/>
@@ -337,68 +303,98 @@ const ProductListTable = () => {
</div>
</div>
<div className='overflow-x-auto'>
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
No data available
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
{isLoading ? (
<Loading />
) : (
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
No data available
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
)}
{isFetching && !isLoading && (
<Box
position='absolute'
top={0}
left={0}
right={0}
bottom={0}
display='flex'
alignItems='center'
justifyContent='center'
bgcolor='rgba(255,255,255,0.7)'
zIndex={1}
>
<CircularProgress size={24} />
</Box>
)}
</div>
<TablePagination
component={() => <TablePaginationComponent table={table} />}
count={table.getFilteredRowModel().rows.length}
rowsPerPage={table.getState().pagination.pageSize}
page={table.getState().pagination.pageIndex}
onPageChange={(_, page) => {
table.setPageIndex(page)
}}
component={() => (
<TablePaginationComponent
pageIndex={currentPage}
pageSize={pageSize}
totalCount={totalCount}
onPageChange={handlePageChange}
/>
)}
count={totalCount}
rowsPerPage={pageSize}
page={currentPage}
onPageChange={handlePageChange}
onRowsPerPageChange={handlePageSizeChange}
rowsPerPageOptions={[10, 25, 50]}
disabled={isLoading}
/>
</Card>
</>
@@ -11,7 +11,7 @@ import type { ProductType } from '@/types/apps/ecommerceTypes'
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
import { Product } from '../../../../../types/services/products'
import { Product } from '../../../../../types/services/product'
type ProductStockType = { [key: string]: boolean }
@@ -21,13 +21,7 @@ const productStockObj: ProductStockType = {
'Out of Stock': false
}
const TableFilters = ({
setData,
productData
}: {
setData: (data: Product[]) => void
productData?: Product[]
}) => {
const TableFilters = ({ setData, productData }: { setData: (data: Product[]) => void; productData?: Product[] }) => {
// States
const [category, setCategory] = useState<Product['category_id']>('')
const [stock, setStock] = useState('')