add filter order

This commit is contained in:
efrilm 2026-01-30 17:22:18 +07:00
parent f4783236d2
commit 3c13aa897c
2 changed files with 107 additions and 27 deletions

View File

@ -6,6 +6,8 @@ interface OrdersQueryParams {
page?: number page?: number
limit?: number limit?: number
search?: string search?: string
date_from?: string
date_to?: string
} }
export function useOrders(params: OrdersQueryParams = {}) { export function useOrders(params: OrdersQueryParams = {}) {

View File

@ -13,8 +13,10 @@ import Checkbox from '@mui/material/Checkbox'
import Chip from '@mui/material/Chip' import Chip from '@mui/material/Chip'
import MenuItem from '@mui/material/MenuItem' import MenuItem from '@mui/material/MenuItem'
import TablePagination from '@mui/material/TablePagination' import TablePagination from '@mui/material/TablePagination'
import TextField from '@mui/material/TextField'
import type { TextFieldProps } from '@mui/material/TextField' import type { TextFieldProps } from '@mui/material/TextField'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import { Box, CircularProgress, useTheme } from '@mui/material'
// Third-party Imports // Third-party Imports
import type { RankingInfo } from '@tanstack/match-sorter-utils' import type { RankingInfo } from '@tanstack/match-sorter-utils'
@ -40,11 +42,10 @@ import { getLocalizedUrl } from '@/utils/i18n'
// Style Imports // Style Imports
import tableStyles from '@core/styles/table.module.css' import tableStyles from '@core/styles/table.module.css'
import { Box, CircularProgress } from '@mui/material'
import Loading from '../../../../../components/layout/shared/Loading' import Loading from '../../../../../components/layout/shared/Loading'
import { useOrders } from '../../../../../services/queries/orders' import { useOrders } from '../../../../../services/queries/orders'
import { Order } from '../../../../../types/services/order' import { Order } from '../../../../../types/services/order'
import { formatCurrency } from '../../../../../utils/transform' import { formatCurrency, formatDateDDMMYYYY, formatForInputDate } from '../../../../../utils/transform'
declare module '@tanstack/table-core' { declare module '@tanstack/table-core' {
interface FilterFns { interface FilterFns {
@ -105,15 +106,28 @@ const DebouncedInput = ({
const columnHelper = createColumnHelper<ECommerceOrderTypeWithAction>() const columnHelper = createColumnHelper<ECommerceOrderTypeWithAction>()
const OrderListTable = () => { const OrderListTable = () => {
const theme = useTheme()
// States // States
const [rowSelection, setRowSelection] = useState({}) const [rowSelection, setRowSelection] = useState({})
const [currentPage, setCurrentPage] = useState(1) const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(10) const [pageSize, setPageSize] = useState(10)
const [search, setSearch] = useState('') const [search, setSearch] = useState('')
// Set default date range to current month
const today = new Date()
const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1)
const [filter, setFilter] = useState({
date_from: formatForInputDate(firstDayOfMonth),
date_to: formatForInputDate(today)
})
const { data, isLoading, error, isFetching } = useOrders({ const { data, isLoading, error, isFetching } = useOrders({
page: currentPage, page: currentPage,
limit: pageSize, limit: pageSize,
date_from: formatDateDDMMYYYY(new Date(filter.date_from)),
date_to: formatDateDDMMYYYY(new Date(filter.date_to)),
search search
}) })
@ -203,6 +217,10 @@ const OrderListTable = () => {
header: 'Discount', header: 'Discount',
cell: ({ row }) => <Typography>{formatCurrency(row.original.discount_amount)}</Typography> cell: ({ row }) => <Typography>{formatCurrency(row.original.discount_amount)}</Typography>
}), }),
columnHelper.accessor('created_at', {
header: 'Created At',
cell: ({ row }) => <Typography>{formatDateDDMMYYYY(new Date(row.original.created_at))}</Typography>
}),
columnHelper.accessor('action', { columnHelper.accessor('action', {
header: 'Action', header: 'Action',
cell: ({ row }) => ( cell: ({ row }) => (
@ -245,44 +263,104 @@ const OrderListTable = () => {
state: { state: {
rowSelection, rowSelection,
pagination: { pagination: {
pageIndex: currentPage, // <= penting! pageIndex: currentPage,
pageSize pageSize
} }
}, },
enableRowSelection: true, //enable row selection for all rows enableRowSelection: true,
onRowSelectionChange: setRowSelection, onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
// Disable client-side pagination since we're handling it server-side
manualPagination: true, manualPagination: true,
pageCount: Math.ceil(totalCount / pageSize) pageCount: Math.ceil(totalCount / pageSize)
}) })
return ( return (
<Card> <Card>
<CardContent className='flex justify-between max-sm:flex-col sm:items-center gap-4'> <CardContent className='flex flex-col gap-4'>
<DebouncedInput {/* Date Range Filter */}
value={search} <div className='flex items-center gap-4 max-sm:flex-col'>
onChange={value => setSearch(value as string)} <Typography variant='body2' className='min-w-fit'>
placeholder='Search Order' Filter by Date:
className='sm:is-auto' </Typography>
/> <TextField
<div className='flex items-center max-sm:flex-col gap-4 max-sm:is-full is-auto'> type='date'
<CustomTextField select value={pageSize} onChange={handlePageSizeChange} className='is-[70px] max-sm:is-full'> value={filter.date_from}
<MenuItem value='10'>10</MenuItem> onChange={e => {
<MenuItem value='25'>25</MenuItem> setFilter({
<MenuItem value='50'>50</MenuItem> ...filter,
<MenuItem value='100'>100</MenuItem> date_from: e.target.value
</CustomTextField> })
<Button setCurrentPage(1)
variant='tonal' }}
color='secondary' size='small'
startIcon={<i className='tabler-upload' />} sx={{
className='max-sm:is-full is-auto' '& .MuiOutlinedInput-root': {
> '&.Mui-focused fieldset': {
Export borderColor: 'primary.main'
</Button> },
'& fieldset': {
borderColor: theme.palette.mode === 'dark' ? 'rgba(231, 227, 252, 0.22)' : theme.palette.divider
}
}
}}
/>
<Typography>-</Typography>
<TextField
type='date'
value={filter.date_to}
onChange={e => {
setFilter({
...filter,
date_to: e.target.value
})
setCurrentPage(1)
}}
size='small'
sx={{
'& .MuiOutlinedInput-root': {
'&.Mui-focused fieldset': {
borderColor: 'primary.main'
},
'& fieldset': {
borderColor: theme.palette.mode === 'dark' ? 'rgba(231, 227, 252, 0.22)' : theme.palette.divider
}
}
}}
/>
</div>
{/* Search and Actions */}
<div className='flex justify-between max-sm:flex-col sm:items-center gap-4'>
<DebouncedInput
value={search}
onChange={value => setSearch(value as string)}
placeholder='Search Order'
className='sm:is-auto'
/>
<div className='flex items-center max-sm:flex-col gap-4 max-sm:is-full is-auto'>
<CustomTextField
select
value={pageSize}
onChange={handlePageSizeChange}
className='is-[70px] max-sm:is-full'
>
<MenuItem value='10'>10</MenuItem>
<MenuItem value='25'>25</MenuItem>
<MenuItem value='50'>50</MenuItem>
<MenuItem value='100'>100</MenuItem>
</CustomTextField>
<Button
variant='tonal'
color='secondary'
startIcon={<i className='tabler-upload' />}
className='max-sm:is-full is-auto'
>
Export
</Button>
</div>
</div> </div>
</CardContent> </CardContent>
<div className='overflow-x-auto'> <div className='overflow-x-auto'>
{isLoading ? ( {isLoading ? (
<Loading /> <Loading />