feat(02-02): user CRUD API + admin page, tenant CRUD API + admin page
- Create UserController with GET/POST/PATCH/DELETE endpoints at /users - ADMIN sees own-tenant users only; SUPER_ADMIN sees all (T-02-10) - ADMIN cannot escalate to SUPER_ADMIN role (T-02-08) - ADMIN cannot delete self or cross-tenant users - Create TenantController with GET/POST/PATCH/DELETE at /tenants - SUPER_ADMIN-only access (D-10) - Tenant deletion blocked if active users exist (T-02-09) - Create CreateUserDto, UpdateUserDto, CreateTenantDto with class-validator - Create admin/users page with user table, create/edit/delete modals - Create admin/tenants page with tenant table, create/edit/deactivate (SUPER_ADMIN only) - Add admin section to sidebar: Verwaltung > Benutzer + Mandanten - Verwaltung visible for ADMIN/SUPER_ADMIN; Tenants link SUPER_ADMIN only - Install @nestjs/mapped-types for PartialType DTO pattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useSidebarStore } from '@/lib/stores/sidebar-store';
|
||||
import { useAuthStore } from '@/lib/stores/auth-store';
|
||||
import { SidebarFooter } from '@/components/layout/sidebar-footer';
|
||||
|
||||
export function Sidebar() {
|
||||
@@ -10,6 +11,11 @@ export function Sidebar() {
|
||||
const tCommon = useTranslations('common');
|
||||
const { isCollapsed, isMobileOpen, toggle, setMobileOpen } = useSidebarStore();
|
||||
const [categoriesOpen, setCategoriesOpen] = useState(false);
|
||||
const user = useAuthStore((s) => s.user);
|
||||
|
||||
// Admin section visibility based on role
|
||||
const isAdmin = user?.role === 'ADMIN' || user?.role === 'SUPER_ADMIN';
|
||||
const isSuperAdmin = user?.role === 'SUPER_ADMIN';
|
||||
|
||||
const sidebarContent = (
|
||||
<div className="flex h-full flex-col bg-sidebar">
|
||||
@@ -100,6 +106,74 @@ export function Sidebar() {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Admin section -- Verwaltung (D-12) */}
|
||||
{isAdmin && (
|
||||
<div className="mt-6">
|
||||
{!isCollapsed && (
|
||||
<div className="px-2 py-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{t('admin')}
|
||||
</div>
|
||||
)}
|
||||
<ul className="flex flex-col gap-1">
|
||||
{/* Users link -- ADMIN and SUPER_ADMIN */}
|
||||
<li>
|
||||
<a
|
||||
href="/admin/users"
|
||||
className="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-sidebar-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="shrink-0"
|
||||
>
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87" />
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||
</svg>
|
||||
{!isCollapsed && <span className="truncate">{t('users')}</span>}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{/* Tenants link -- SUPER_ADMIN only (D-10) */}
|
||||
{isSuperAdmin && (
|
||||
<li>
|
||||
<a
|
||||
href="/admin/tenants"
|
||||
className="flex items-center gap-3 rounded-md px-2 py-2 text-sm text-sidebar-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="shrink-0"
|
||||
>
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<polyline points="9 22 9 12 15 12 15 22" />
|
||||
</svg>
|
||||
{!isCollapsed && (
|
||||
<span className="truncate">{t('tenants')}</span>
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
{/* Collapse/Expand toggle */}
|
||||
|
||||
Reference in New Issue
Block a user