108 lines
4.3 KiB
TypeScript
108 lines
4.3 KiB
TypeScript
import Link from 'next/link';
|
|
import { redirect } from 'next/navigation';
|
|
import { getSession } from '@/lib/session';
|
|
import { listUsers, listObjekte } from './actions';
|
|
import ResetButton from './ResetButton';
|
|
import ObjekteManager from './ObjekteManager';
|
|
|
|
type Tab = 'benutzer' | 'objekte';
|
|
|
|
export default async function AdminPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ tab?: string }>;
|
|
}) {
|
|
const session = await getSession();
|
|
if (!session) redirect('/login');
|
|
if (session.role === null || !session.role.includes('admin')) redirect('/');
|
|
|
|
const { tab: tabParam } = await searchParams;
|
|
const activeTab: Tab = tabParam === 'objekte' ? 'objekte' : 'benutzer';
|
|
|
|
const [users, objekte] = await Promise.all([
|
|
activeTab === 'benutzer' ? listUsers() : Promise.resolve([]),
|
|
activeTab === 'objekte' ? listObjekte() : Promise.resolve([]),
|
|
]);
|
|
|
|
const tabs: { id: Tab; label: string }[] = [
|
|
{ id: 'benutzer', label: 'Benutzerverwaltung' },
|
|
{ id: 'objekte', label: 'Objektverwaltung' },
|
|
];
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white py-4 px-4">
|
|
<main className="max-w-6xl mx-auto border-2 border-black rounded-lg p-6 bg-[#EEF4FF]">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h1 className="text-3xl font-bold">Führungsbuch — Sternwarte Welzheim</h1>
|
|
<Link href="/" className="text-sm text-blue-600 hover:underline">← Zurück</Link>
|
|
</div>
|
|
|
|
{/* Tabs */}
|
|
<div className="flex gap-1 mb-6 border-b border-gray-200">
|
|
{tabs.map(({ id, label }) => (
|
|
<Link
|
|
key={id}
|
|
href={`/admin?tab=${id}`}
|
|
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
|
|
activeTab === id
|
|
? 'border-[#85B7D7] text-gray-900'
|
|
: 'border-transparent text-gray-500 hover:text-gray-700'
|
|
}`}
|
|
>
|
|
{label}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
|
|
{/* Benutzerverwaltung */}
|
|
{activeTab === 'benutzer' && (
|
|
<>
|
|
<div className="bg-white border border-gray-300 rounded-xl shadow-sm overflow-hidden">
|
|
<table className="w-full text-sm">
|
|
<thead className="bg-gray-100 text-gray-700">
|
|
<tr>
|
|
<th className="text-left px-4 py-3 font-semibold">Kürzel</th>
|
|
<th className="text-left px-4 py-3 font-semibold">Name</th>
|
|
<th className="text-left px-4 py-3 font-semibold">Vorname</th>
|
|
<th className="text-left px-4 py-3 font-semibold">Rolle</th>
|
|
<th className="text-left px-4 py-3 font-semibold">Passwort</th>
|
|
<th className="px-4 py-3"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{users.map((user, idx) => (
|
|
<tr key={user.id} className={idx % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
|
|
<td className="px-4 py-3 font-mono">{user.kürzel ?? '—'}</td>
|
|
<td className="px-4 py-3">{user.name}</td>
|
|
<td className="px-4 py-3">{user.vorname ?? '—'}</td>
|
|
<td className="px-4 py-3">{user.role ?? '—'}</td>
|
|
<td className="px-4 py-3">
|
|
{user.hasPw ? (
|
|
<span className="text-green-700">gesetzt</span>
|
|
) : (
|
|
<span className="text-amber-600 font-medium">Standard</span>
|
|
)}
|
|
</td>
|
|
<td className="px-4 py-3 text-right">
|
|
<ResetButton userId={user.id} userName={`${user.vorname ?? ''} ${user.name}`.trim()} />
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p className="mt-4 text-xs text-gray-500">
|
|
„Zurücksetzen“ setzt das Passwort auf NULL. Der Benutzer muss sich danach mit dem Standard-Passwort anmelden und es sofort ändern.
|
|
</p>
|
|
</>
|
|
)}
|
|
|
|
{/* Objektverwaltung */}
|
|
{activeTab === 'objekte' && (
|
|
<ObjekteManager initialObjekte={objekte} />
|
|
)}
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|