added OrderBy functionality to Data Table

This commit is contained in:
PxlLoewe
2025-06-03 17:54:30 -07:00
parent 574472dcb9
commit 0eb3ba8104
11 changed files with 117 additions and 121 deletions

View File

@@ -47,7 +47,7 @@ export const SettingsBtn = () => {
setSelectedDevice(user.settingsMicDevice);
setMic(user.settingsMicDevice, user.settingsMicVolume || 1);
setMicVol(user.settingsMicVolume || 1);
setFunkVol(user.settingsFunkVolume || 0.8);
setFunkVol(user.settingsRadioVolume || 0.8);
setDmeVol(user.settingsDmeVolume || 0.8);
}
}, [user, setMic]);
@@ -205,7 +205,7 @@ export const SettingsBtn = () => {
user: {
settingsMicDevice: selectedDevice,
settingsMicVolume: micVol,
settingsFunkVolume: funkVolume,
settingsRadioVolume: funkVolume,
settingsDmeVolume: dmeVolume,
},
});

View File

@@ -1,6 +1,4 @@
import { PublicUser } from "@repo/db";
import { dispatchSocket } from "dispatch/socket";
import { serverApi } from "_helpers/axios";
import {
handleDisconnect,
handleLocalTrackUnpublished,

View File

@@ -49,14 +49,13 @@
"tailwindcss": "^4.1.8",
"zod": "^3.25.46",
"zustand": "^5.0.5",
"zustand-sync-tabs": "^0.2.2"
},
"devDependencies": {
"zustand-sync-tabs": "^0.2.2",
"@types/leaflet": "^1.9.18",
"@types/node": "^22.15.29",
"@types/react": "^19.1.6",
"@types/react-dom": "^19.1.5",
"daisyui": "^5.0.43",
"typescript": "^5.8.3"
}
},
"devDependencies": {}
}

View File

@@ -8,6 +8,7 @@ import { ColumnDef } from "@tanstack/react-table";
export default function ReportPage() {
return (
<PaginatedTable
initialOrderBy={[{ id: "timestamp", desc: true }]}
prismaModel="report"
include={{
Sender: true,
@@ -50,8 +51,7 @@ export default function ReportPage() {
{
accessorKey: "timestamp",
header: "Time",
cell: ({ row }) =>
new Date(row.getValue("timestamp")).toLocaleString(),
cell: ({ row }) => new Date(row.getValue("timestamp")).toLocaleString(),
},
{
accessorKey: "actions",

View File

@@ -15,7 +15,8 @@ export const EmailVerification = () => {
<div>
<h3 className="font-bold">E-Mail Adresse nicht bestätigt!</h3>
<div className="text-xs">
Wir haben dir bereits eine E-Mail gesendet. Wenn deine E-Mail Adresse nicht bestätigt ist, kannst du dich nicht mit der Leitstelle verbinden!
Wir haben dir bereits eine E-Mail gesendet. Wenn deine E-Mail Adresse nicht bestätigt ist,
kannst du dich nicht mit der Leitstelle verbinden!
</div>
</div>
<Button

View File

@@ -1,11 +1,5 @@
"use client";
import {
useEffect,
useState,
useCallback,
Ref,
useImperativeHandle,
} from "react";
import { useEffect, useState, useCallback, Ref, useImperativeHandle } from "react";
import SortableTable, { Pagination, SortableTableProps } from "./Table";
import { PrismaClient } from "@repo/db";
import { getData } from "./pagiantedTableActions";
@@ -14,8 +8,7 @@ export interface PaginatedTableRef {
refresh: () => void;
}
interface PaginatedTableProps<TData>
extends Omit<SortableTableProps<TData>, "data"> {
interface PaginatedTableProps<TData> extends Omit<SortableTableProps<TData>, "data"> {
prismaModel: keyof PrismaClient;
filter?: Record<string, any>;
rowsPerPage?: number;
@@ -48,6 +41,17 @@ export function PaginatedTable<TData>({
const [total, setTotal] = useState(0);
const [searchTerm, setSearchTerm] = useState("");
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm);
const [orderBy, setOrderBy] = useState<Record<string, "asc" | "desc">>(
restProps.initialOrderBy
? restProps.initialOrderBy.reduce(
(acc, sort) => {
acc[sort.id] = sort.desc ? "desc" : "asc";
return acc;
},
{} as Record<string, "asc" | "desc">,
)
: {},
);
const RefreshTableData = async () => {
getData(
@@ -58,6 +62,7 @@ export function PaginatedTable<TData>({
searchFields,
filter,
include,
orderBy,
).then((result) => {
if (result) {
setData(result.data);
@@ -68,7 +73,7 @@ export function PaginatedTable<TData>({
useEffect(() => {
RefreshTableData();
}, [filter]);
}, [filter, orderBy]);
useImperativeHandle(ref, () => ({
refresh: () => {
@@ -118,17 +123,14 @@ export function PaginatedTable<TData>({
data={data}
prismaModel={prismaModel}
showEditButton={showEditButton}
setOrderBy={setOrderBy}
{...restProps}
/>
)}
<div className="flex items-between">
{leftOfPagination}
{!hide && (
<Pagination
totalPages={Math.ceil(total / rowsPerPage)}
page={page}
setPage={setPage}
/>
<Pagination totalPages={Math.ceil(total / rowsPerPage)} page={page} setPage={setPage} />
)}
</div>
</div>

View File

@@ -1,5 +1,5 @@
"use client";
import { useState } from "react";
import { useEffect, useState } from "react";
import {
useReactTable,
getCoreRowModel,
@@ -17,15 +17,19 @@ export interface SortableTableProps<TData> {
columns: ColumnDef<TData>[];
showEditButton?: boolean;
prismaModel?: keyof PrismaClient;
setOrderBy?: (orderBy: Record<string, "asc" | "desc">) => void;
initialOrderBy?: SortingState;
}
export default function SortableTable<TData>({
data,
columns,
initialOrderBy = [],
prismaModel,
showEditButton,
setOrderBy,
}: SortableTableProps<TData>) {
const [sorting, setSorting] = useState<SortingState>([]);
const [sorting, setSorting] = useState<SortingState>(initialOrderBy);
const table = useReactTable({
data,
@@ -36,9 +40,7 @@ export default function SortableTable<TData>({
header: "Actions",
cell: ({ row }) => (
<div className="flex items-center gap-1">
<Link
href={`/admin/${prismaModel as string}/${(row.original as any).id}`}
>
<Link href={`/admin/${prismaModel as string}/${(row.original as any).id}`}>
<button className="btn btn-sm">Edit</button>
</Link>
</div>
@@ -52,6 +54,16 @@ export default function SortableTable<TData>({
state: { sorting },
});
useEffect(() => {
if (prismaModel) {
const orderBy: Record<string, "asc" | "desc"> = {};
sorting.forEach((sort) => {
orderBy[sort.id] = sort.desc ? "desc" : "asc";
});
setOrderBy?.(orderBy);
}
}, [sorting, prismaModel, setOrderBy]);
return (
<div className="overflow-x-auto">
<table className="table table-zebra w-full">
@@ -59,21 +71,11 @@ export default function SortableTable<TData>({
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
>
<th key={header.id} onClick={header.column.getToggleSortingHandler()}>
<div className="flex items-center gap-1 cursor-pointer">
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{header.column.getIsSorted() === "asc" && (
<ChevronUp size={16} />
)}
{header.column.getIsSorted() === "desc" && (
<ChevronDown size={16} />
)}
{flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getIsSorted() === "asc" && <ChevronUp size={16} />}
{header.column.getIsSorted() === "desc" && <ChevronDown size={16} />}
</div>
</th>
))}
@@ -84,9 +86,7 @@ export default function SortableTable<TData>({
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
))}
@@ -108,11 +108,7 @@ export const Pagination = ({
if (totalPages === 0) return null;
return (
<div className="join w-full justify-end">
<button
className="join-item btn"
disabled={page === 0}
onClick={() => setPage(page - 1)}
>
<button className="join-item btn" disabled={page === 0} onClick={() => setPage(page - 1)}>
<ArrowLeft size={16} />
</button>
<select

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use server";
import { prisma, PrismaClient } from "@repo/db";
@@ -9,6 +10,7 @@ export async function getData(
searchFields: string[],
filter?: Record<string, any>,
include?: Record<string, boolean>,
orderBy?: Record<string, "asc" | "desc">,
) {
if (!model || !prisma[model]) {
return { data: [], total: 0 };
@@ -34,6 +36,7 @@ export async function getData(
const data = await (prisma[model] as any).findMany({
where,
orderBy,
take: limit,
skip: offset,
include,

View File

@@ -40,9 +40,7 @@
"react-hot-toast": "^2.5.2",
"react-select": "^5.10.1",
"tailwind-merge": "^3.3.0",
"zod": "^3.25.46"
},
"devDependencies": {
"zod": "^3.25.46",
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4.1.8",
"@types/bcryptjs": "^3.0.0",
@@ -56,5 +54,6 @@
"postcss": "^8.5.4",
"tailwindcss": "^4.1.8",
"typescript": "^5.8.3"
}
},
"devDependencies": {}
}