This commit is contained in:
2025-11-10 00:48:39 -03:00
parent 24dfefe395
commit c3f370e86c
3 changed files with 152 additions and 149 deletions

View File

@@ -6,6 +6,7 @@ import {
useReactTable,
type ColumnDef,
type ColumnSort,
type RowSelectionState,
type SortingState,
type Table,
type VisibilityState
@@ -34,7 +35,7 @@ interface DataTableProps<TData, TValue> {
children?: ReactNode
columns: ColumnDef<TData, TValue>[]
data: TData[]
onRowSelectionChange?: (rowSelection: TData[]) => void
setSelectedRows?: (selectedRows: TData[]) => void
pageIndex: number
sort: SortingState
pageSize: number
@@ -62,16 +63,17 @@ export function DataTable<TData, TValue>({
pageIndex,
pageSize,
rowCount,
onRowSelectionChange,
setSelectedRows,
hiddenColumn = []
}: DataTableProps<TData, TValue>) {
const [searchParams, setSearchParams] = useSearchParams()
const hiddenColumn_ = Object.fromEntries(
const columnVisibilityInit = Object.fromEntries(
hiddenColumn.map((column) => [column, false])
)
const [searchParams, setSearchParams] = useSearchParams()
const [columnVisibility, setColumnVisibility] =
useState<VisibilityState>(hiddenColumn_)
const [rowSelection, setRowSelection] = useState({})
useState<VisibilityState>(columnVisibilityInit)
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const sortParam = searchParams.get('sort')
const sorting = sortParam
? sortParam.split(',').map((s) => {
@@ -84,9 +86,7 @@ export function DataTable<TData, TValue>({
const newState =
typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater
onRowSelectionChange?.([])
setRowSelection({})
setSearchParams((searchParams) => {
searchParams.set('p', newState?.pageIndex.toString())
searchParams.set('perPage', newState?.pageSize.toString())
@@ -135,8 +135,8 @@ export function DataTable<TData, TValue>({
useEffect(() => {
const selected = table.getSelectedRowModel().flatRows.map((r) => r.original)
onRowSelectionChange?.(selected)
}, [rowSelection, table])
setSelectedRows?.(selected)
}, [rowSelection])
return (
<TableContext value={{ table }}>

View File

@@ -52,3 +52,18 @@ export const sortings: Record<string, string> = {
failed_at: 'Reprovado em',
canceled_at: 'Cancelado em'
}
export const headers = {
id: 'ID',
'user.name': 'Nome',
'user.email': 'Email',
'user.cpf': 'CPF',
'course.name': 'Curso',
status: 'Status',
progress: 'Progresso',
created_at: 'Cadastrado em',
started_at: 'Iniciado em',
completed_at: 'Concluído em',
failed_at: 'Reprovado em',
canceled_at: 'Cancelado em'
}

View File

@@ -34,7 +34,7 @@ import {
} from '@repo/ui/components/ui/dropdown-menu'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { columns, type Enrollment } from './columns'
import { sortings, statuses } from './data'
import { headers, sortings, statuses } from './data'
export function meta({}: Route.MetaArgs) {
return [{ title: 'Matrículas' }]
@@ -83,7 +83,7 @@ const formatted = new Intl.DateTimeFormat('en-CA', {
export default function Route({ loaderData: { data } }) {
const [searchParams, setSearchParams] = useSearchParams()
const [rowSelection, setRowSelection] = useState<Enrollment[]>([])
const [selectedRows, setSelectedRows] = useState<Enrollment[]>([])
const status = searchParams.get('status')
const rangeParams = useRangeParams()
@@ -99,15 +99,14 @@ export default function Route({ loaderData: { data } }) {
</div>
<Await resolve={data}>
{({ hits, page, hitsPerPage, totalHits }) => {
return (
{({ hits, page, hitsPerPage, totalHits }) => (
<DataTable
sort={[{ id: 'created_at', desc: true }]}
columns={columns}
data={hits as Enrollment[]}
pageIndex={page - 1}
pageSize={hitsPerPage}
onRowSelectionChange={setRowSelection}
setSelectedRows={setSelectedRows}
rowCount={totalHits}
hiddenColumn={[
'completed_at',
@@ -117,13 +116,16 @@ export default function Route({ loaderData: { data } }) {
]}
>
<div className="flex gap-2.5 mb-2.5">
{rowSelection.length ? (
{selectedRows.length ? (
<>
<div className="flex gap-2.5 items-center">
<Button variant="outline">
<TagIcon /> Marcador
</Button>
<DropdownMenuExport rowSelection={rowSelection} />
<DropdownMenuExport
headers={headers}
selectedRows={selectedRows}
/>
</div>
</>
) : (
@@ -133,8 +135,8 @@ export default function Route({ loaderData: { data } }) {
defaultValue={searchParams.get('q') || ''}
placeholder={
<>
Digite <Kbd className="border font-mono">/</Kbd>{' '}
para pesquisar
Digite <Kbd className="border font-mono">/</Kbd> para
pesquisar
</>
}
onChange={(value) =>
@@ -224,8 +226,7 @@ export default function Route({ loaderData: { data } }) {
)}
</div>
</DataTable>
)
}}
)}
</Await>
</Suspense>
)
@@ -251,32 +252,19 @@ function useRangeParams() {
}
export function DropdownMenuExport({
rowSelection = []
headers,
selectedRows = []
}: {
rowSelection: object[]
headers: Record<string, string>
selectedRows: object[]
}) {
const headers = {
id: 'ID',
'user.name': 'Nome',
'user.email': 'Email',
'user.cpf': 'CPF',
'course.name': 'Curso',
status: 'Status',
progress: 'Progresso',
created_at: 'Cadastrado em',
started_at: 'Iniciado em',
completed_at: 'Concluído em',
failed_at: 'Reprovado em',
canceled_at: 'Cancelado em'
}
const handleExport = (bookType: BookType) => () => {
if (!rowSelection.length) {
if (!selectedRows.length) {
return
}
const header = Object.keys(headers)
const data = rowSelection.map((data) => {
const data = selectedRows.map((data) => {
const obj: Record<string, string> = flatten(data)
return Object.fromEntries(header.map((k) => [k, obj?.[k]]))
})