From 380084b675738d71c0ba7d66520fcf022488bd00 Mon Sep 17 00:00:00 2001 From: Elias Bennour Date: Wed, 21 May 2025 23:38:50 +0200 Subject: [PATCH] add sum of balance --- src/pages/admin/index.tsx | 46 ++++++++++++++++++++++++++---------- src/pages/api/admin/users.ts | 23 +++++++++++------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/pages/admin/index.tsx b/src/pages/admin/index.tsx index 02d9e3d..520bf7c 100644 --- a/src/pages/admin/index.tsx +++ b/src/pages/admin/index.tsx @@ -24,6 +24,7 @@ interface AdminUser { interface AdminUsersApiResponse { users: AdminUser[]; totalUsers: number; + totalBalance: string; // Gesamtsaldo } interface AdminTransaction { @@ -49,11 +50,11 @@ interface AdminUserTransactionsApiResponse { totalTransactions: number; } -interface SetApprovalStatusApiResponse { // Typ für die Antwort der /set-approval-status API +interface SetApprovalStatusApiResponse { message: string; userId: string; isApproved: boolean; - approvedAt: Date | null; // API liefert Date-Objekt, im Frontend ggf. als String behandeln + approvedAt: Date | null; } @@ -65,6 +66,7 @@ const AdminPanelPage: NextPage = () => { const [isLoadingUsers, setIsLoadingUsers] = useState(true); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); + const [totalBalance, setTotalBalance] = useState(null); // State für Gesamtsaldo const [selectedUserForAdjustment, setSelectedUserForAdjustment] = useState(null); const [adjustmentAmount, setAdjustmentAmount] = useState(''); @@ -103,10 +105,10 @@ const AdminPanelPage: NextPage = () => { const data: AdminUsersApiResponse = await res.json(); const formattedUsers = data.users.map(user => ({ ...user, - // approvedAt von der API kommt als ISO-String oder null approvedAt: user.approvedAt ? new Date(user.approvedAt).toLocaleString('de-DE') : null })); setUsers(formattedUsers); + setTotalBalance(data.totalBalance); // Gesamtsaldo setzen } catch (err: unknown) { if (err instanceof Error) { setError(err.message); @@ -218,7 +220,6 @@ const AdminPanelPage: NextPage = () => { } }; - // NEU: Benutzer Freigabestatus umschalten const handleToggleApproval = async (userId: string, currentApprovalStatus: boolean) => { setError(null); setSuccessMessage(null); @@ -230,14 +231,14 @@ const AdminPanelPage: NextPage = () => { const response = await fetch(`/api/admin/users/${userId}/set-approval-status`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ isApproved: !currentApprovalStatus }), // Den entgegengesetzten Status senden + body: JSON.stringify({ isApproved: !currentApprovalStatus }), }); - const data: SetApprovalStatusApiResponse = await response.json(); // Typ für die Antwort verwenden + const data: SetApprovalStatusApiResponse = await response.json(); if (!response.ok) { throw new Error(data.message || `Fehler beim ${actionText} des Benutzers.`); } setSuccessMessage(data.message); - await fetchUsers(); // Benutzerliste neu laden, um den aktualisierten Status anzuzeigen + await fetchUsers(); } catch (err: unknown) { if (err instanceof Error) { setError(err.message); @@ -270,7 +271,7 @@ const AdminPanelPage: NextPage = () => {

Admin Panel

-

Benutzerverwaltung

+

Benutzerverwaltung & Übersicht

@@ -355,7 +379,7 @@ const AdminPanelPage: NextPage = () => { )} - {/* Modal für Saldo anpassen */} + {/* Modals (bleiben unverändert) */} setIsAdjustModalOpen(false)}> { - {/* Modal für Transaktionsverlauf */} setIsTransactionsModalOpen(false)}> {
- ); }; diff --git a/src/pages/api/admin/users.ts b/src/pages/api/admin/users.ts index af51922..1fc2722 100644 --- a/src/pages/api/admin/users.ts +++ b/src/pages/api/admin/users.ts @@ -3,11 +3,9 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; import { authOptions } from '../auth/[...nextauth]'; // Pfad zu deiner authOptions anpassen import prisma from '../../../lib/prisma'; // Pfad zu deinem Prisma Client Singleton anpassen -// User-Typ von Prisma wird hier nicht mehr direkt für ApiAdminUser benötigt, -// da wir den Typ explizit definieren. +import { Decimal } from '@prisma/client/runtime/library'; // Import Decimal // Definiere den Typ für die Benutzerdaten, wie sie von dieser API gesendet werden. -// Dieser Typ enthält genau die Felder, die wir auswählen und transformieren. type ApiAdminUser = { id: string; name: string | null; @@ -19,7 +17,7 @@ type ApiAdminUser = { updatedAt: string; // Datum als ISO-String isApproved: boolean; // Freigabestatus approvedAt: string | null; // Freigabedatum als ISO-String oder null - _count?: { // _count ist optional und enthält die optionale Anzahl der Transaktionen + _count?: { transactions?: number; }; }; @@ -27,6 +25,7 @@ type ApiAdminUser = { interface AdminUsersApiResponse { users: ApiAdminUser[]; totalUsers: number; + totalBalance: string; // NEU: Gesamtsumme aller Salden als String } interface ErrorResponse { @@ -49,6 +48,7 @@ export default async function handler( } try { + // Benutzerdaten abrufen const usersFromDb = await prisma.user.findMany({ select: { id: true, @@ -70,8 +70,14 @@ export default async function handler( }, }); - // Konvertiere Decimal-Saldo und DateTime-Objekte in Strings für die JSON-Antwort - // und stelle sicher, dass die Struktur dem ApiAdminUser-Typ entspricht. + // NEU: Gesamtsaldo berechnen + const totalBalanceResult = await prisma.user.aggregate({ + _sum: { + balance: true, // Summiere das 'balance'-Feld + }, + }); + const totalBalanceDecimal = totalBalanceResult._sum.balance ?? new Decimal(0); + const apiAdminUsers: ApiAdminUser[] = usersFromDb.map(user => ({ id: user.id, name: user.name, @@ -83,14 +89,15 @@ export default async function handler( updatedAt: user.updatedAt.toISOString(), isApproved: user.isApproved, approvedAt: user.approvedAt ? user.approvedAt.toISOString() : null, - _count: { // Stelle sicher, dass _count immer ein Objekt ist, auch wenn transactions 0 ist - transactions: user._count?.transactions ?? 0 // Fallback auf 0, falls undefined + _count: { + transactions: user._count?.transactions ?? 0 } })); return res.status(200).json({ users: apiAdminUsers, totalUsers: apiAdminUsers.length, + totalBalance: totalBalanceDecimal.toFixed(2), // Gesamtsaldo als String hinzufügen }); } catch (error: unknown) {