add columns

This commit is contained in:
2025-11-19 00:46:57 -03:00
parent 786c5e1580
commit a180e269f2
6 changed files with 94 additions and 64 deletions

View File

@@ -26,9 +26,9 @@ export function DataTableColumnHeader<TData, TValue>({
return (
<Button
variant="ghost"
variant="link"
size="sm"
className={cn('-ml-3 cursor-pointer', className)}
className={cn('-ml-3 cursor-pointer text-inherit h-auto', className)}
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
>
<span>{title}</span>

View File

@@ -17,6 +17,7 @@ import {
useContext,
useEffect,
useMemo,
useRef,
useState,
type ReactNode
} from 'react'
@@ -43,7 +44,7 @@ interface DataTableProps<TData, TValue> {
sort: SortingState
pageSize: number
rowCount: number
columnInvisibilityInit?: string[]
columnVisibilityInit?: VisibilityState
}
interface TableContextProps<TData> {
@@ -71,21 +72,33 @@ export function DataTable<TData, TValue>({
pageSize,
rowCount,
setSelectedRows,
columnInvisibilityInit = []
columnVisibilityInit = {}
}: DataTableProps<TData, TValue>) {
const [dataTable, setDataTable] = useState<TData[]>(data)
const columnInvisibility = useMemo<VisibilityState>(
() =>
Object.fromEntries(
columnInvisibilityInit.map((column) => [column, false])
),
[columnInvisibilityInit]
)
const [searchParams, setSearchParams] = useSearchParams()
const [columnVisibility, setColumnVisibility] =
useState<VisibilityState>(columnInvisibility)
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const columnVisibilityInit_ = useMemo<VisibilityState>(() => {
const columns = searchParams.get('columns')
if (columns === null) {
return columnVisibilityInit
}
const columnVisibility = columns ? columns.split(',') : []
return Object.keys(columnVisibilityInit).reduce<VisibilityState>(
(acc, col) => ({
...acc,
[col]: columnVisibility.includes(col)
}),
{}
)
}, [])
const [columnVisibility, setColumnVisibility_] = useState<VisibilityState>(
columnVisibilityInit_
)
const sorting = useMemo(() => {
const sortParam = searchParams.get('sort')
@@ -110,6 +123,7 @@ export function DataTable<TData, TValue>({
setSearchParams((prev) => {
prev.set('p', newState?.pageIndex.toString())
prev.set('perPage', newState?.pageSize.toString())
return prev
})
},
@@ -130,17 +144,47 @@ export function DataTable<TData, TValue>({
} else {
prev.delete('sort')
}
return prev
})
},
[sorting, setSearchParams]
)
const setColumnVisibility = useCallback(
(updater: any) => {
const newColumnVisibility =
typeof updater === 'function' ? updater(columnVisibility) : updater
setColumnVisibility_(newColumnVisibility)
setSearchParams((prev) => {
const columns = Object.entries(newColumnVisibility)
.filter(([_, visible]) => visible)
.map(([col, _]) => col)
if (columns.length > 0) {
prev.set('columns', columns.join(','))
} else {
prev.set('columns', '')
}
return prev
})
},
[setSearchParams, setColumnVisibility_]
)
useEffect(() => {
setDataTable(data)
}, [data])
const tableConfig = useMemo(
() => ({
const getRowId = useCallback((row: any) => row.id, [])
const removeRow = useCallback((rowId: string) => {
setDataTable((rows) => rows.filter((row: any) => row.id !== rowId))
}, [])
const table = useReactTable({
data: dataTable,
columns,
rowCount,
@@ -148,42 +192,19 @@ export function DataTable<TData, TValue>({
sorting,
rowSelection,
columnVisibility,
pagination: {
pageIndex,
pageSize
}
pagination: { pageIndex, pageSize }
},
manualSorting: true,
manualPagination: true,
enableRowSelection: true,
getRowId: (row: any) => row.id,
getRowId,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
onSortingChange: setSorting,
onColumnVisibilityChange: setColumnVisibility,
onPaginationChange: setPagination,
meta: {
removeRow: (rowId: string) => {
setDataTable((rows) => rows.filter((row: any) => row?.id !== rowId))
}
}
}),
[
dataTable,
columns,
rowCount,
sorting,
rowSelection,
columnVisibility,
setColumnVisibility,
pageIndex,
pageSize,
setSorting,
setPagination
]
)
const table = useReactTable(tableConfig)
meta: { removeRow }
})
useEffect(() => {
if (!setSelectedRows) return

View File

@@ -41,6 +41,7 @@ export function DataTableViewOptions<TData>({
<DropdownMenuCheckboxItem
key={column.id}
checked={column.getIsVisible()}
onSelect={(e) => e.preventDefault()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
>
{title}

View File

@@ -1,7 +1,7 @@
import { isbot } from 'isbot'
import { renderToReadableStream } from 'react-dom/server'
import type { AppLoadContext, EntryContext } from 'react-router'
import { ServerRouter } from 'react-router'
import { ServerRouter, type HandleErrorFunction } from 'react-router'
export default async function handleRequest(
request: Request,
@@ -44,3 +44,10 @@ export default async function handleRequest(
// https://reactrouter.com/how-to/suspense#timeouts
export const streamTimeout = 7_000
// https://reactrouter.com/how-to/error-reporting
export const handleError: HandleErrorFunction = (error, { request }) => {
if (!request.signal.aborted) {
console.error(error)
}
}

View File

@@ -107,12 +107,13 @@ export default function Route({ loaderData: { data } }) {
pageSize={hitsPerPage}
setSelectedRows={setSelectedRows}
rowCount={totalHits}
hiddenColumn={[
'completed_at',
'started_at',
'failed_at',
'canceled_at'
]}
columnVisibilityInit={{
created_at: true,
completed_at: false,
started_at: false,
failed_at: false,
canceled_at: false
}}
>
<div className="flex gap-2.5 mb-2.5">
{selectedRows.length ? (

View File

@@ -117,7 +117,7 @@ export async function action({ params, request, context }: Route.ActionArgs) {
return { ok: true }
}
export default function Route() {
export default function Route({}: Route.ComponentProps) {
const fetcher = useFetcher()
const { activeWorkspace } = useWorksapce()
const form = useForm({
@@ -143,7 +143,7 @@ export default function Route() {
case 'UserConflictError':
toast.error('O colaborador já foi vinculado anteriormente')
}
}, [fetcher.data])
}, [fetcher.data, reset])
useEffect(() => {
if (givenEmail) {