'use client' // React Imports 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 Checkbox from '@mui/material/Checkbox' import Chip from '@mui/material/Chip' import IconButton from '@mui/material/IconButton' import MenuItem from '@mui/material/MenuItem' import { styled } from '@mui/material/styles' import type { TextFieldProps } from '@mui/material/TextField' import Typography from '@mui/material/Typography' // Third-party Imports 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 { UsersType } from '@/types/apps/userTypes' import type { Locale } from '@configs/i18n' // Component Imports import CustomAvatar from '@core/components/mui/Avatar' import CustomTextField from '@core/components/mui/TextField' import OptionMenu from '@core/components/option-menu' // Util Imports import { getInitials } from '@/utils/getInitials' import { getLocalizedUrl } from '@/utils/i18n' // Style Imports import tableStyles from '@core/styles/table.module.css' import { Box, CircularProgress, TablePagination } from '@mui/material' import Loading from '../../../../components/layout/shared/Loading' import TablePaginationComponent from '../../../../components/TablePaginationComponent' import { useUsers } from '../../../../services/queries/users' import { User } from '../../../../types/services/user' import AddUserDrawer from './AddUserDrawer' import { useDispatch } from 'react-redux' import { setUser } from '../../../../redux-store/slices/user' import { useUsersMutation } from '../../../../services/mutations/users' import ConfirmDeleteDialog from '../../../../components/dialogs/confirm-delete' declare module '@tanstack/table-core' { interface FilterFns { fuzzy: FilterFn } interface FilterMeta { itemRank: RankingInfo } } type UsersTypeWithAction = User & { actions?: string } type UserRoleType = { [key: string]: { icon: string; color: string } } // Styled Components const Icon = styled('i')({}) const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { // Rank the item const itemRank = rankItem(row.getValue(columnId), value) // Store the itemRank info addMeta({ itemRank }) // Return if the item should be filtered in/out return itemRank.passed } const DebouncedInput = ({ value: initialValue, onChange, debounce = 500, ...props }: { value: string | number onChange: (value: string | number) => void debounce?: number } & Omit) => { // States const [value, setValue] = useState(initialValue) useEffect(() => { setValue(initialValue) }, [initialValue]) useEffect(() => { const timeout = setTimeout(() => { onChange(value) }, debounce) return () => clearTimeout(timeout) // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]) return setValue(e.target.value)} /> } // Vars const userRoleObj: UserRoleType = { admin: { icon: 'tabler-crown', color: 'error' }, author: { icon: 'tabler-device-desktop', color: 'warning' }, editor: { icon: 'tabler-edit', color: 'info' }, cashier: { icon: 'tabler-chart-pie', color: 'success' }, subscriber: { icon: 'tabler-user', color: 'primary' } } // Column Definitions const columnHelper = createColumnHelper() const UserListTable = () => { const dispatch = useDispatch() // States const [addUserOpen, setAddUserOpen] = useState(false) const [rowSelection, setRowSelection] = useState({}) const [currentPage, setCurrentPage] = useState(1) const [pageSize, setPageSize] = useState(10) const [openConfirm, setOpenConfirm] = useState(false) const [userId, setUserId] = useState('') const [search, setSearch] = useState('') // Hooks const { lang: locale } = useParams() const { data, isLoading, error, isFetching } = useUsers({ page: currentPage, limit: pageSize, search }) const { deleteUser } = useUsersMutation() const users = data?.users ?? [] const totalCount = data?.pagination.total_count ?? 0 const handlePageChange = useCallback((event: unknown, newPage: number) => { setCurrentPage(newPage) }, []) // Handle page size change const handlePageSizeChange = useCallback((event: React.ChangeEvent) => { const newPageSize = parseInt(event.target.value, 10) setPageSize(newPageSize) setCurrentPage(1) // Reset to first page }, []) const handleDelete = () => { deleteUser.mutate(userId, { onSuccess: () => setOpenConfirm(false) }) } const columns = useMemo[]>( () => [ { id: 'select', header: ({ table }) => ( ), cell: ({ row }) => ( ) }, columnHelper.accessor('name', { header: 'User', cell: ({ row }) => (
{getAvatar({ avatar: '', fullName: row.original.name })}
{row.original.name}
) }), columnHelper.accessor('role', { header: 'Role', cell: ({ row }) => (
{row.original.role}
) }), columnHelper.accessor('email', { header: 'Email', cell: ({ row }) => {row.original.email} }), columnHelper.accessor('is_active', { header: 'Status', cell: ({ row }) => (
) }), columnHelper.accessor('actions', { header: 'Action', cell: ({ row }) => (
{ setUserId(row.original.id) setOpenConfirm(true) }} > { dispatch(setUser(row.original)) setAddUserOpen(true) } } } ]} />
), enableSorting: false }) ], // eslint-disable-next-line react-hooks/exhaustive-deps [data] ) const table = useReactTable({ data: users as User[], columns, filterFns: { fuzzy: fuzzyFilter }, state: { rowSelection, pagination: { pageIndex: currentPage, pageSize } }, enableRowSelection: true, //enable row selection for all rows onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), // Disable client-side pagination since we're handling it server-side manualPagination: true, pageCount: Math.ceil(totalCount / pageSize) }) const getAvatar = (params: Pick) => { const { avatar, fullName } = params if (avatar) { return } else { return {getInitials(fullName as string)} } } return ( <> {/* */} {/* */}
setSearch(value as string)} placeholder='Search User' className='max-sm:is-full' />
10 25 50
{isLoading ? ( ) : ( {table.getHeaderGroups().map(headerGroup => ( {headerGroup.headers.map(header => ( ))} ))} {table.getFilteredRowModel().rows.length === 0 ? ( ) : ( {table .getRowModel() .rows.slice(0, table.getState().pagination.pageSize) .map(row => { return ( {row.getVisibleCells().map(cell => ( ))} ) })} )}
{header.isPlaceholder ? null : ( <>
{flexRender(header.column.columnDef.header, header.getContext())} {{ asc: , desc: }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
)}
No data available
{flexRender(cell.column.columnDef.cell, cell.getContext())}
)} {isFetching && !isLoading && ( )}
( )} count={totalCount} rowsPerPage={pageSize} page={currentPage} onPageChange={handlePageChange} onRowsPerPageChange={handlePageSizeChange} rowsPerPageOptions={[10, 25, 50]} disabled={isLoading} />
setAddUserOpen(!addUserOpen)} /> setOpenConfirm(false)} onConfirm={handleDelete} isLoading={deleteUser.isPending} title='Delete User' message='Are you sure you want to delete this User? This action cannot be undone.' /> ) } export default UserListTable