Skip to content

Commit

Permalink
Merge pull request #93 from sgcarstrends/1-add-a-responsive-table-to-…
Browse files Browse the repository at this point in the history
…show-the-data-and-trends

Add DataTable and refactor existing table in makes
  • Loading branch information
ruchernchong authored Aug 19, 2024
2 parents 16926d3 + 12e0504 commit 5627ae1
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 49 deletions.
40 changes: 40 additions & 0 deletions app/make/[make]/columns.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import Link from "next/link";
import { ArrowUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { Car } from "@/types";
import type { ColumnDef } from "@tanstack/react-table";

export const columns: ColumnDef<Car>[] = [
{
accessorKey: "month",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Month
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
},
},
{
accessorKey: "fuel_type",
header: "Fuel Type",
cell: ({ row }) => {
const type = row.getValue("fuel_type") as string;
return <Link href={`/cars/${type.toLowerCase()}`}>{type}</Link>;
},
},
{
accessorKey: "vehicle_type",
header: "Vehicle Type",
},
{
accessorKey: "number",
header: "Count",
},
];
52 changes: 3 additions & 49 deletions app/make/[make]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import Link from "next/link";
import { MakeSelector } from "@/app/components/MakeSelector";
import { columns } from "@/app/make/[make]/columns";
import { StructuredData } from "@/components/StructuredData";
import Typography from "@/components/Typography";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { DataTable } from "@/components/ui/data-table";
import { API_URL, SITE_URL } from "@/config";
import { MAKE } from "@/constants";
import { type Car, type LatestMonth, type Make, RevalidateTags } from "@/types";
import { fetchApi } from "@/utils/fetchApi";
import type { WebSite, WithContext } from "schema-dts";
Expand Down Expand Up @@ -99,45 +91,7 @@ const CarMakePage = async ({ params, searchParams }: Props) => {
<CardTitle>Trends</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
{Object.values(MAKE.TABLE.HEADERS).map((header) => (
<TableHead key={header}>{header}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{filteredCars.length === 0 && (
<TableRow>
<TableCell
colSpan={Object.entries(MAKE.TABLE.HEADERS).length}
className="text-center"
>
<Typography.H4>No data available</Typography.H4>
</TableCell>
</TableRow>
)}
{filteredCars.map((car, index) => (
<TableRow
key={`${car.fuel_type}-${car.vehicle_type}`}
className="even:bg-muted"
>
<TableCell>{car.month}</TableCell>
<TableCell>
<Link
href={`/cars/${car.fuel_type.toLowerCase()}?month=${car.month}`}
className="hover:underline"
>
{car.fuel_type}
</Link>
</TableCell>
<TableCell>{car.vehicle_type}</TableCell>
<TableCell>{car.number}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<DataTable columns={columns} data={filteredCars} />
</CardContent>
</Card>
</div>
Expand Down
135 changes: 135 additions & 0 deletions components/ui/data-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"use client";

import { useState } from "react";
import {
type ColumnDef,
type ColumnFiltersState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
type SortingState,
useReactTable,
type VisibilityState,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";

interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
}

export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});

const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
onColumnFiltersChange: setColumnFilters,
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: { sorting, columnFilters, columnVisibility },
});

return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter months..."
value={(table.getColumn("month")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("month")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{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}
data-state={row.getIsSelected() && "selected"}
>
{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"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.1.2",
"@tanstack/react-table": "^8.20.1",
"class-variance-authority": "^0.7.0",
"classnames": "^2.3.2",
"clsx": "^2.1.1",
Expand Down
22 changes: 22 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5627ae1

Please sign in to comment.