stats
This commit is contained in:
parent
6fb3d2bdbe
commit
0779aa6199
8 changed files with 192 additions and 8 deletions
|
@ -12,7 +12,7 @@ export default function GlobalError({
|
||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<CardGrid>
|
<CardGrid max_rows={1}>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-center text-2xl text-red-400">Error</CardTitle>
|
<CardTitle className="text-center text-2xl text-red-400">Error</CardTitle>
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default function GlobalError({
|
||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<CardGrid>
|
<CardGrid max_rows={1}>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-center text-2xl text-red-400">404 - Not Found</CardTitle>
|
<CardTitle className="text-center text-2xl text-red-400">404 - Not Found</CardTitle>
|
||||||
|
|
30
src/app/stats/columns.tsx
Normal file
30
src/app/stats/columns.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"use client";
|
||||||
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
export type UrlTable = {
|
||||||
|
clicks: number;
|
||||||
|
date_accessed: Date;
|
||||||
|
date_added: Date;
|
||||||
|
id: string;
|
||||||
|
long_url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const columns: ColumnDef<UrlTable>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "clicks",
|
||||||
|
header: "Clicks",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "long_url",
|
||||||
|
header: "URL",
|
||||||
|
},
|
||||||
|
{ accessorKey: "id", header: "ID" },
|
||||||
|
{
|
||||||
|
accessorKey: "date_accessed",
|
||||||
|
header: "Date Accessed",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "date_added",
|
||||||
|
header: "Date Added",
|
||||||
|
},
|
||||||
|
];
|
79
src/app/stats/data-table.tsx
Normal file
79
src/app/stats/data-table.tsx
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
"use client";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import {
|
||||||
|
ColumnDef,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
useReactTable
|
||||||
|
} from "@tanstack/react-table";
|
||||||
|
|
||||||
|
interface DataTableProps<TData, TValue> {
|
||||||
|
columns: ColumnDef<TData, TValue>[];
|
||||||
|
data: TData[];
|
||||||
|
slug: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTable<TData, TValue>({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
}: DataTableProps<TData, TValue>) {
|
||||||
|
const table = useReactTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
19
src/app/stats/db.tsx
Normal file
19
src/app/stats/db.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"use server";
|
||||||
|
import { initConnection } from "@/components/db-utils";
|
||||||
|
|
||||||
|
export async function querydb() {
|
||||||
|
try {
|
||||||
|
let db = await initConnection();
|
||||||
|
let stats = await db.query(`
|
||||||
|
select * from url
|
||||||
|
order by clicks desc
|
||||||
|
limit 50;
|
||||||
|
`);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
console.log(stats);
|
||||||
|
return stats;
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
23
src/app/stats/loading.tsx
Normal file
23
src/app/stats/loading.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"use client";
|
||||||
|
import CardGrid from "@/components/card-grid";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
|
||||||
|
export default function GlobalError({
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string }
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<CardGrid max_rows={1}>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-1xl text-amber-400">Loading...</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
</CardGrid>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,8 +1,16 @@
|
||||||
|
import CardGrid from "@/components/card-grid";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { columns } from "./columns";
|
||||||
|
import { DataTable } from "./data-table";
|
||||||
|
import { querydb } from "./db";
|
||||||
|
|
||||||
export default function StatsPage() {
|
export default async function StatsPage() {
|
||||||
|
let data = await querydb();
|
||||||
return (
|
return (
|
||||||
<div>
|
<CardGrid max_rows={1}>
|
||||||
<h1>Stats</h1>
|
<Card>
|
||||||
</div>
|
<DataTable columns={columns} data={data[0]} />
|
||||||
|
</Card>
|
||||||
|
</CardGrid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,40 @@
|
||||||
export default function CardGrid({
|
export default function CardGrid({
|
||||||
|
max_rows = 4,
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
|
max_rows?: number;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
|
let baseClassName = `hidden items-start justify-center gap-6 rounded-lg p-8 md:grid`;
|
||||||
|
|
||||||
|
switch (max_rows) {
|
||||||
|
case 1:
|
||||||
|
baseClassName += " md:grid-cols-1 ";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
baseClassName += " md:grid-cols-1 lg:grid-cols-2 ";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
baseClassName += " md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 ";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
baseClassName += " md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 ";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (className == undefined) {
|
||||||
|
className = baseClassName;
|
||||||
|
} else {
|
||||||
|
className = baseClassName + className;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`hidden items-start justify-center gap-6 rounded-lg p-8 md:grid lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4" ${className}`}
|
className={`hidden items-start justify-center gap-6 rounded-lg p-8 md:grid " ${className}`}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue