240 lines
7.4 KiB
TypeScript
240 lines
7.4 KiB
TypeScript
'use client'
|
||
|
||
import * as React from 'react'
|
||
import {
|
||
ColumnDef,
|
||
ColumnFiltersState,
|
||
SortingState,
|
||
VisibilityState,
|
||
flexRender,
|
||
getCoreRowModel,
|
||
getFilteredRowModel,
|
||
getPaginationRowModel,
|
||
getSortedRowModel,
|
||
useReactTable
|
||
} from '@tanstack/react-table'
|
||
|
||
import { Button } from '@/components/ui/button'
|
||
import {
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableHead,
|
||
TableHeader,
|
||
TableRow
|
||
} from '@/components/ui/table'
|
||
import { ArrowLeft2, ArrowRight2 } from 'iconsax-react'
|
||
import { ef } from '@/lib/helpers/utfNumbers'
|
||
import { Transaction } from '../types/Types'
|
||
import Status from '@/components/utils/Status'
|
||
|
||
interface TransactionsTableProps {
|
||
transactions: Transaction[]
|
||
}
|
||
|
||
const formatDate = (dateString: string): string => {
|
||
const date = new Date(dateString);
|
||
return date.toLocaleDateString('fa-IR', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit'
|
||
});
|
||
};
|
||
|
||
export const columns: ColumnDef<Transaction>[] = [
|
||
{
|
||
accessorKey: 'order.orderNumber',
|
||
header: () => <div className='text-right pr-6'>شماره سفارش</div>,
|
||
cell: ({ row }) => {
|
||
const orderNumber = row.original.order?.orderNumber;
|
||
return (
|
||
<div className='text-right pr-6'>{ef(orderNumber?.toString() || '-')}</div>
|
||
)
|
||
}
|
||
},
|
||
{
|
||
accessorKey: 'type',
|
||
header: () => <div className='text-center'>نوع تراکنش</div>,
|
||
cell: ({ row }) => {
|
||
const type = row.original.order?.paymentMethod?.description || '-';
|
||
return <div className='text-center'>{type}</div>
|
||
}
|
||
},
|
||
{
|
||
accessorKey: 'amount',
|
||
header: () => <div className='text-center'>مبلغ</div>,
|
||
cell: ({ row }) => {
|
||
const amount = row.original.amount;
|
||
const formatted = Math.abs(amount).toLocaleString('fa-IR');
|
||
return <div className='text-center'>{ef(formatted)} ریال</div>
|
||
}
|
||
},
|
||
{
|
||
accessorKey: 'createdAt',
|
||
header: () => <div className='text-center'>تاریخ</div>,
|
||
cell: ({ row }) => {
|
||
const date = formatDate(row.original.createdAt);
|
||
return <div className='text-center'>{ef(date)}</div>
|
||
}
|
||
},
|
||
{
|
||
accessorKey: 'status',
|
||
header: () => <div className='text-center'>وضعیت</div>,
|
||
cell: ({ row }) => {
|
||
const status = row.original.status;
|
||
return <Status status={status} className='text-right' />
|
||
}
|
||
}
|
||
]
|
||
|
||
export function TransactionsTable({ transactions }: TransactionsTableProps) {
|
||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||
[]
|
||
)
|
||
const [columnVisibility, setColumnVisibility] =
|
||
React.useState<VisibilityState>({})
|
||
const [rowSelection, setRowSelection] = React.useState({})
|
||
|
||
const table = useReactTable({
|
||
data: transactions,
|
||
columns,
|
||
onSortingChange: setSorting,
|
||
onColumnFiltersChange: setColumnFilters,
|
||
getCoreRowModel: getCoreRowModel(),
|
||
getPaginationRowModel: getPaginationRowModel(),
|
||
getSortedRowModel: getSortedRowModel(),
|
||
getFilteredRowModel: getFilteredRowModel(),
|
||
onColumnVisibilityChange: setColumnVisibility,
|
||
onRowSelectionChange: setRowSelection,
|
||
state: {
|
||
sorting,
|
||
columnFilters,
|
||
columnVisibility,
|
||
rowSelection
|
||
},
|
||
initialState: {
|
||
pagination: {
|
||
pageSize: 8
|
||
}
|
||
}
|
||
})
|
||
|
||
return (
|
||
<div className='w-full'>
|
||
<div className='rounded-3xl min-h-[507px] w-full'>
|
||
<Table className='w-[727px] md:w-full'>
|
||
<TableHeader>
|
||
{table.getHeaderGroups().map(headerGroup => (
|
||
<TableRow
|
||
className='dark:border-neutral-400 border-[#EAEDF5] h-14'
|
||
key={headerGroup.id}
|
||
>
|
||
{headerGroup.headers.map(header => {
|
||
return (
|
||
<TableHead
|
||
key={header.id}
|
||
className='font-light text-xs text-disabled-text text-center'
|
||
>
|
||
{header.isPlaceholder
|
||
? null
|
||
: flexRender(
|
||
header.column.columnDef.header,
|
||
header.getContext()
|
||
)}
|
||
</TableHead>
|
||
)
|
||
})}
|
||
</TableRow>
|
||
))}
|
||
</TableHeader>
|
||
<TableBody>
|
||
{table.getRowModel().rows?.length ? (
|
||
table.getRowModel().rows.map(row => (
|
||
<TableRow
|
||
key={row.id}
|
||
className='text-center w-full border-b-[#EAEDF5] dark:border-b-background text-xs odd:bg-[#E9EBF433] bg-border dark:odd:bg-background/80 even:bg-container border-0 border-b! h-14 border-r-4! border-r-transparent active:border-r-primary dark:active:border-r-foreground'
|
||
>
|
||
{row.getVisibleCells().map(cell => (
|
||
<TableCell key={cell.id}>
|
||
{flexRender(
|
||
cell.column.columnDef.cell,
|
||
cell.getContext()
|
||
)}
|
||
</TableCell>
|
||
))}
|
||
</TableRow>
|
||
))
|
||
) : (
|
||
<TableRow>
|
||
<TableCell
|
||
colSpan={columns.length}
|
||
className='h-24 text-center'
|
||
>
|
||
تراکنشی یافت نشد.
|
||
</TableCell>
|
||
</TableRow>
|
||
)}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
<div className='flex items-center justify-end space-x-2 pt-4 px-7 pb-11 select-none'>
|
||
<div className='flex-1 text-sm text-disabled-text'>
|
||
نمایش:{' '}
|
||
<span className='text-primary dark:text-foreground'>
|
||
{ef(table.getRowModel().rows.length)}
|
||
</span>{' '}
|
||
از {ef(table.getFilteredRowModel().rows.length)}
|
||
</div>
|
||
<div className='space-x-2 justify-center flex'>
|
||
<Button
|
||
variant='ghost'
|
||
size='sm'
|
||
className='size-6'
|
||
onClick={() => table.previousPage()}
|
||
hidden={!table.getCanPreviousPage()}
|
||
>
|
||
<ArrowRight2 size={12} className='stroke-[#A8ABBF]' />
|
||
</Button>
|
||
<Button
|
||
variant='secondary'
|
||
size='sm'
|
||
className='dark:bg-disabled bg-[#EAECF5] text-xs size-6'
|
||
onClick={() => table.previousPage()}
|
||
hidden={!table.getCanPreviousPage()}
|
||
>
|
||
{ef(table.getState().pagination.pageIndex)}
|
||
</Button>
|
||
<Button
|
||
variant='default'
|
||
className='text-white dark:text-foreground text-xs size-6'
|
||
size='sm'
|
||
hidden={!table.getCanPreviousPage() && !table.getCanNextPage()}
|
||
>
|
||
{ef(table.getState().pagination.pageIndex + 1)}
|
||
</Button>
|
||
<Button
|
||
variant='secondary'
|
||
size='sm'
|
||
className='dark:bg-disabled bg-[#EAECF5] text-xs size-6'
|
||
onClick={() => table.nextPage()}
|
||
hidden={!table.getCanNextPage()}
|
||
>
|
||
{ef(table.getState().pagination.pageIndex + 2)}
|
||
</Button>
|
||
|
||
<Button
|
||
variant='ghost'
|
||
size='sm'
|
||
className='size-6'
|
||
onClick={() => table.nextPage()}
|
||
hidden={!table.getCanNextPage()}
|
||
>
|
||
<ArrowLeft2 size={12} className='stroke-[#A8ABBF]' />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|