remove toggle for dark mode
fix some minor design issues
This commit is contained in:
parent
f7d462b359
commit
1b3847b98d
@ -4,7 +4,7 @@ import { useSession, signOut } from 'next-auth/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState, Fragment } from 'react';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
import { useTheme } from '@/context/ThemeContext'; // Pfad zum ThemeContext anpassen
|
||||
// import { useTheme } from '../../context/ThemeContext'; // Entfernt
|
||||
|
||||
// Typen für die Admin-Seite (Frontend)
|
||||
interface AdminUser {
|
||||
@ -58,46 +58,6 @@ interface SetApprovalStatusApiResponse {
|
||||
approvedAt: Date | null;
|
||||
}
|
||||
|
||||
// ThemeSwitcher Komponente (kopiert aus Dashboard, ggf. in eine separate Datei auslagern)
|
||||
const ThemeSwitcher: React.FC = () => {
|
||||
const { theme, setTheme, resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
if (!mounted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cycleTheme = () => {
|
||||
if (theme === 'light') setTheme('dark');
|
||||
else if (theme === 'dark') setTheme('system');
|
||||
else setTheme('light');
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={cycleTheme}
|
||||
aria-label="Theme wechseln"
|
||||
className="p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
{resolvedTheme === 'dark' ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-yellow-400">
|
||||
<path fillRule="evenodd" d="M9.528 1.718a.75.75 0 0 1 .162.819A8.97 8.97 0 0 0 9 6a9 9 0 0 0 9 9 8.97 8.97 0 0 0 3.463-.69.75.75 0 0 1 .981.981A10.503 10.503 0 0 1 18 19.5a10.5 10.5 0 0 1-10.5-10.5A10.503 10.503 0 0 1 9.528 1.718Z" clipRule="evenodd" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-orange-500">
|
||||
<path d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-2.25A.75.75 0 0 1 12 18ZM7.758 17.303a.75.75 0 0 0-1.061-1.06l-1.591 1.59a.75.75 0 0 0 1.06 1.061l1.591-1.59ZM6.166 7.758a.75.75 0 0 0-1.06 1.061l1.59 1.591a.75.75 0 0 0 1.061-1.06l-1.59-1.591ZM12 3.5A8.5 8.5 0 0 1 20.5 12c0 .312-.022.618-.065.916a.75.75 0 0 0-1.435-.276A7.001 7.001 0 0 0 12 5c-3.865 0-7 3.135-7 7 0 .096.005.19.014.284a.75.75 0 0 0 .727.71A.751.751 0 0 0 6.02 13a7.001 7.001 0 0 0 5.98-2.088.75.75 0 0 0-.364-1.118A8.502 8.502 0 0 1 12 3.5Z" />
|
||||
</svg>
|
||||
)}
|
||||
<span className="ml-2 text-xs text-gray-500 dark:text-gray-400 capitalize">
|
||||
{theme === 'system' ? `System (${resolvedTheme})` : theme}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const AdminPanelPage: NextPage = () => {
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
@ -292,56 +252,56 @@ const AdminPanelPage: NextPage = () => {
|
||||
|
||||
if (status === 'loading' || (status === 'authenticated' && session?.user?.role !== 'admin' && !isLoadingUsers) ) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900"> {/* Dark Mode Hintergrund */}
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">Laden oder Zugriff wird geprüft...</p> {/* Dark Mode Text */}
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">Laden oder Zugriff wird geprüft...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === 'unauthenticated') {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900"> {/* Dark Mode Hintergrund */}
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">Bitte als Admin anmelden.</p> {/* Dark Mode Text */}
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">Bitte als Admin anmelden.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 dark:bg-slate-900 p-4 sm:p-6 lg:p-8 transition-colors duration-300"> {/* Dark Mode Hintergrund */}
|
||||
<header className="mb-8 flex justify-between items-center">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-800 dark:text-gray-100">Admin Panel</h1> {/* Dark Mode Text */}
|
||||
<p className="text-gray-600 dark:text-gray-400">Benutzerverwaltung & Übersicht</p> {/* Dark Mode Text */}
|
||||
<div className="min-h-screen bg-gray-100 dark:bg-slate-900 p-4 sm:p-6 lg:p-8 transition-colors duration-300">
|
||||
{/* Header angepasst für mobile Ansicht */}
|
||||
<header className="mb-8 flex flex-col sm:flex-row sm:justify-between sm:items-center">
|
||||
<div className="mb-4 sm:mb-0"> {/* Div für Admin Panel Text */}
|
||||
<h1 className="text-3xl font-bold text-gray-800 dark:text-gray-100">Admin Panel</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400">Benutzerverwaltung & Übersicht</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4"> {/* Container für Buttons */}
|
||||
<ThemeSwitcher /> {/* NEU: Theme-Schalter hinzugefügt */}
|
||||
<div className="flex flex-col space-y-2 sm:flex-row sm:space-y-0 sm:space-x-4"> {/* Container für Buttons */}
|
||||
<button
|
||||
onClick={() => router.push('/dashboard')}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||
className="w-full sm:w-auto px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||
>
|
||||
Zum Dashboard
|
||||
</button>
|
||||
<button
|
||||
onClick={() => signOut({ callbackUrl: '/auth/signin' })}
|
||||
className="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||
className="w-full sm:w-auto px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||
>
|
||||
Abmelden
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{error && <div className="mb-4 p-3 bg-red-100 text-red-700 border border-red-300 rounded-md dark:bg-red-900 dark:text-red-200 dark:border-red-700">{error}</div>} {/* Dark Mode Fehler */}
|
||||
{successMessage && <div className="mb-4 p-3 bg-green-100 text-green-700 border border-green-300 rounded-md dark:bg-green-900 dark:text-green-200 dark:border-green-700">{successMessage}</div>} {/* Dark Mode Erfolg */}
|
||||
{error && <div className="mb-4 p-3 bg-red-100 text-red-700 border border-red-300 rounded-md dark:bg-red-900 dark:text-red-200 dark:border-red-700">{error}</div>}
|
||||
{successMessage && <div className="mb-4 p-3 bg-green-100 text-green-700 border border-green-300 rounded-md dark:bg-green-900 dark:text-green-200 dark:border-green-700">{successMessage}</div>}
|
||||
|
||||
{/* Gesamtübersicht Sektion */}
|
||||
<section className="mb-8 p-6 bg-white dark:bg-slate-800 shadow-lg rounded-lg"> {/* Dark Mode Sektion */}
|
||||
<h2 className="text-2xl font-semibold text-gray-700 dark:text-gray-200 mb-4">Gesamtübersicht</h2> {/* Dark Mode Text */}
|
||||
<section className="mb-8 p-6 bg-white dark:bg-slate-800 shadow-lg rounded-lg">
|
||||
<h2 className="text-2xl font-semibold text-gray-700 dark:text-gray-200 mb-4">Gesamtübersicht</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="p-4 bg-indigo-50 dark:bg-indigo-900/30 rounded-lg"> {/* Dark Mode Kachel */}
|
||||
<div className="p-4 bg-indigo-50 dark:bg-indigo-900/30 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-indigo-700 dark:text-indigo-300">Anzahl Benutzer</h3>
|
||||
<p className="mt-1 text-3xl font-semibold text-indigo-600 dark:text-indigo-400">{users.length}</p>
|
||||
</div>
|
||||
<div className="p-4 bg-green-50 dark:bg-green-900/30 rounded-lg"> {/* Dark Mode Kachel */}
|
||||
<div className="p-4 bg-green-50 dark:bg-green-900/30 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-green-700 dark:text-green-300">Gesamtsaldo</h3>
|
||||
{isLoadingUsers ? (
|
||||
<p className="mt-1 text-3xl font-semibold text-green-600 dark:text-green-400">Lade...</p>
|
||||
@ -355,14 +315,14 @@ const AdminPanelPage: NextPage = () => {
|
||||
</section>
|
||||
|
||||
{/* Benutzerliste */}
|
||||
<section className="p-6 bg-white dark:bg-slate-800 shadow-lg rounded-lg"> {/* Dark Mode Sektion */}
|
||||
<h2 className="text-2xl font-semibold text-gray-700 dark:text-gray-200 mb-4">Benutzerübersicht</h2> {/* Dark Mode Text */}
|
||||
<section className="p-6 bg-white dark:bg-slate-800 shadow-lg rounded-lg">
|
||||
<h2 className="text-2xl font-semibold text-gray-700 dark:text-gray-200 mb-4">Benutzerübersicht</h2>
|
||||
{isLoadingUsers ? (
|
||||
<p className="text-gray-500 dark:text-gray-400">Benutzerliste wird geladen...</p>
|
||||
) : users.length > 0 ? (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700"> {/* Dark Mode Tabelle */}
|
||||
<thead className="bg-gray-50 dark:bg-slate-700"> {/* Dark Mode Tabellenkopf */}
|
||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead className="bg-gray-50 dark:bg-slate-700">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Name</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">E-Mail</th>
|
||||
@ -372,9 +332,9 @@ const AdminPanelPage: NextPage = () => {
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white dark:bg-slate-800 divide-y divide-gray-200 dark:divide-gray-700"> {/* Dark Mode Tabellenkörper */}
|
||||
<tbody className="bg-white dark:bg-slate-800 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
{users.map((user) => (
|
||||
<tr key={user.id} className="dark:hover:bg-slate-700/50"> {/* Dark Mode Hover */}
|
||||
<tr key={user.id} className="dark:hover:bg-slate-700/50">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">{user.name || 'N/A'}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300">{user.email || 'N/A'}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700 dark:text-gray-300 font-medium">{user.balance ? `${user.balance} €` : '0.00 €'}</td>
|
||||
@ -432,7 +392,7 @@ const AdminPanelPage: NextPage = () => {
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="absolute inset-0 bg-black/30 backdrop-blur-sm dark:bg-slate-900/80" /> {/* Dark Mode Backdrop */}
|
||||
<div className="absolute inset-0 bg-black/30 backdrop-blur-sm dark:bg-slate-900/80" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
@ -525,7 +485,7 @@ const AdminPanelPage: NextPage = () => {
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="absolute inset-0 bg-black/30 backdrop-blur-sm dark:bg-slate-900/80" /> {/* Dark Mode Backdrop */}
|
||||
<div className="absolute inset-0 bg-black/30 backdrop-blur-sm dark:bg-slate-900/80" />
|
||||
</Transition.Child>
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
|
||||
@ -3,7 +3,6 @@ import type { NextPage } from 'next';
|
||||
import { useSession, signOut } from 'next-auth/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTheme } from '../context/ThemeContext'; // NEU: useTheme importieren
|
||||
|
||||
// Typ für Transaktionen, wie sie vom Backend (API) erwartet werden
|
||||
interface DashboardTransaction {
|
||||
@ -36,54 +35,9 @@ interface IncreaseBalanceApiResponse {
|
||||
transactionId: string;
|
||||
}
|
||||
|
||||
const ThemeSwitcher: React.FC = () => {
|
||||
const { theme, setTheme, resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
if (!mounted) {
|
||||
// Verhindere Hydration Mismatch, indem der Schalter erst nach dem Mounten gerendert wird
|
||||
return null;
|
||||
}
|
||||
|
||||
// toggleTheme wurde entfernt, da cycleTheme verwendet wird
|
||||
|
||||
// Erweiterter Theme-Wechsel: Light, Dark, System
|
||||
const cycleTheme = () => {
|
||||
if (theme === 'light') setTheme('dark');
|
||||
else if (theme === 'dark') setTheme('system');
|
||||
else setTheme('light');
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={cycleTheme}
|
||||
aria-label="Theme wechseln"
|
||||
className="p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
{/* Icon basierend auf resolvedTheme oder theme */}
|
||||
{resolvedTheme === 'dark' ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-yellow-400">
|
||||
<path fillRule="evenodd" d="M9.528 1.718a.75.75 0 0 1 .162.819A8.97 8.97 0 0 0 9 6a9 9 0 0 0 9 9 8.97 8.97 0 0 0 3.463-.69.75.75 0 0 1 .981.981A10.503 10.503 0 0 1 18 19.5a10.5 10.5 0 0 1-10.5-10.5A10.503 10.503 0 0 1 9.528 1.718Z" clipRule="evenodd" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-orange-500">
|
||||
<path d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-2.25A.75.75 0 0 1 12 18ZM7.758 17.303a.75.75 0 0 0-1.061-1.06l-1.591 1.59a.75.75 0 0 0 1.06 1.061l1.591-1.59ZM6.166 7.758a.75.75 0 0 0-1.06 1.061l1.59 1.591a.75.75 0 0 0 1.061-1.06l-1.59-1.591ZM12 3.5A8.5 8.5 0 0 1 20.5 12c0 .312-.022.618-.065.916a.75.75 0 0 0-1.435-.276A7.001 7.001 0 0 0 12 5c-3.865 0-7 3.135-7 7 0 .096.005.19.014.284a.75.75 0 0 0 .727.71A.751.751 0 0 0 6.02 13a7.001 7.001 0 0 0 5.98-2.088.75.75 0 0 0-.364-1.118A8.502 8.502 0 0 1 12 3.5Z" />
|
||||
</svg>
|
||||
)}
|
||||
<span className="ml-2 text-xs text-gray-500 dark:text-gray-400 capitalize">
|
||||
{theme === 'system' ? `System (${resolvedTheme})` : theme}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const DashboardPage: NextPage = () => {
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
// const { theme } = useTheme(); // Entfernt, da nicht direkt in DashboardPage verwendet
|
||||
|
||||
const [balance, setBalance] = useState<string | null>(null);
|
||||
const [userName, setUserName] = useState<string | null>(null);
|
||||
@ -205,24 +159,24 @@ const DashboardPage: NextPage = () => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 dark:bg-slate-900 p-4 sm:p-6 lg:p-8 transition-colors duration-300">
|
||||
<header className="mb-8 flex justify-between items-center">
|
||||
<div>
|
||||
{/* Header angepasst für mobile Ansicht */}
|
||||
<header className="mb-8 flex flex-col sm:flex-row sm:justify-between sm:items-center">
|
||||
<div className="mb-4 sm:mb-0"> {/* Div für Willkommenstext */}
|
||||
<h1 className="text-3xl font-bold text-gray-800 dark:text-gray-100">Willkommen, {userName || session.user.name}!</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400">Deine Strichliste</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<ThemeSwitcher />
|
||||
<div className="flex flex-col space-y-2 sm:flex-row sm:space-y-0 sm:space-x-4"> {/* Container für Buttons */}
|
||||
{session?.user?.role === 'admin' && (
|
||||
<button
|
||||
onClick={() => router.push('/admin')}
|
||||
className="px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
|
||||
className="w-full sm:w-auto px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
|
||||
>
|
||||
Admin Panel
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => signOut({ callbackUrl: '/auth/signin' })}
|
||||
className="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||
className="w-full sm:w-auto px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||
>
|
||||
Abmelden
|
||||
</button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user