Skip to content

Instantly share code, notes, and snippets.

@Aslam97
Created March 28, 2024 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aslam97/4b3b9a36f92cf395773f6034a1e904cd to your computer and use it in GitHub Desktop.
Save Aslam97/4b3b9a36f92cf395773f6034a1e904cd to your computer and use it in GitHub Desktop.
Laravel @TanStack table using shadcn

api response

{
    "data": [
        ...
    ],
    "links": {
        "first": "https://example.com/pagination?page=1",
        "last": "https://example.com/pagination?page=10",
        "prev": null,
        "next": "https://example.com/pagination?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 10,
        "links": [
            ...
        ],
        "path": "https://example.com/pagination",
        "per_page": 15,
        "to": 15,
        "total": 150
    }
}

main.tsx

  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: 1,
    pageSize: 10
  })
  
  const {
    data
  } = useQuery({
    queryKey: ['tasks', pagination],
    queryFn: () => fetchTasks(pagination),
    placeholderData: keepPreviousData
  })
  
  const table = useReactTable({
    data: data?.rows ?? defaultData,
    columns,
    rowCount: data?.rowCount,
    state: {
      pagination,
      columnPinning: {
        right: ['action']
      }
    },
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    manualPagination: true,
    debugTable: true
  })
  
  <Table></Table>
  <TablePagination data={data} pagination={pagination} table={table} />

fetch.ts

import fetchClient from '@/lib/fetch-client'
import { tableParser } from '@/lib/utils'
import QueryString from 'qs'

interface FetchTaskProps {
  pageIndex: number
  pageSize: number
}

export async function fetchTasks({ pageIndex, pageSize }: FetchTaskProps) {
  const url = process.env.NEXT_PUBLIC_API_URL + '/api/tasks'
  const query = QueryString.stringify({
    include: 'farms,workers,settings',
    page: pageIndex,
    paginate: pageSize
  })

  const response = await fetchClient({
    url: `${url}?${query}`,
    method: 'GET'
  })

  const data = await response.json()

  return tableParser({ data, pageSize })
}

utils.ts

export const tableParser = ({
  data,
  pageSize
}: {
  data: any
  pageSize: number
}) => {
  const { data: rows, ...rest } = data

  const elements = () => {
    let current = rest.meta.current_page
    let last = rest.meta.last_page
    let delta = 1
    let left = current - delta
    let right = current + delta + 1
    let range = []
    let rangeWithDots = []
    let l

    // use rangeWithDotsMax to limit the number of elements in the pagination
    for (let i = 1; i <= last; i++) {
      if (i == 1 || i == last || (i >= left && i < right)) {
        range.push(i)
      }
    }

    for (let i of range) {
      if (l) {
        if (i - l === 2) {
          rangeWithDots.push(l + 1)
        } else if (i - l !== 1) {
          rangeWithDots.push('...')
        }
      }

      rangeWithDots.push(i)
      l = i
    }

    console.log({
      range,
      rangeWithDots
    })

    return rangeWithDots
  }

  return {
    rows,
    elements: elements(),
    pageCount: Math.ceil(rows.length / pageSize),
    rowCount: rest.meta.total,
    ...rest
  }
}

table-pagination.tsx

import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons'
import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious
} from '@/components/ui/pagination'
import { cn } from '@/lib/utils'
import type { PaginationState } from '@tanstack/react-table'

const TablePagination = ({
  data,
  pagination,
  table
}: {
  data: any
  pagination: PaginationState
  table: any
}) => {
  const prevPage =
    pagination.pageIndex === 2
      ? 0
      : pagination.pageIndex - 1 < 0
        ? 0
        : pagination.pageIndex - 1
  const nextPage =
    pagination.pageIndex === 0
      ? pagination.pageIndex + 2
      : pagination.pageIndex + 1

  return (
    <Pagination className="items-end justify-end py-4">
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious
            onClick={() => {
              if (prevPage === 2) return
              table.setPageIndex(prevPage)
            }}
            className={cn('size-9 p-0 cursor-pointer', {
              'cursor-not-allowed': nextPage === 2
            })}
          >
            <ChevronLeftIcon className="size-4" />
          </PaginationPrevious>
        </PaginationItem>

        {data?.elements.map((element: any, index: number) => {
          if (element === '...') {
            return (
              <PaginationEllipsis key={index}>
                <span>...</span>
              </PaginationEllipsis>
            )
          }

          return (
            <PaginationItem key={index}>
              <PaginationLink
                className="size-9 p-0 cursor-pointer"
                isActive={
                  element ===
                  (pagination.pageIndex === 0
                    ? pagination.pageIndex + 1
                    : pagination.pageIndex)
                }
                onClick={() => {
                  table.setPageIndex(element)
                }}
              >
                {element}
              </PaginationLink>
            </PaginationItem>
          )
        })}

        <PaginationItem>
          <PaginationNext
            onClick={() => {
              if (nextPage > data?.meta.last_page) return

              table.setPageIndex(nextPage)
            }}
            className={cn('size-9 p-0 cursor-pointer', {
              'cursor-not-allowed': nextPage > data?.meta.last_page
            })}
          >
            <ChevronRightIcon className="size-4" />
          </PaginationNext>
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  )
}

export default TablePagination
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment