INSIGHT-MVP/packages/frontend/src/shell/App.tsx
Thomas Reitz c8b25321e7 feat(core+frontend): Profilzugriff-Gruppen für Admin mit delegierten Berechtigungen
- Neue Prisma-Modelle ProfileAccessGroup + ProfileAccessGroupMember mit canView/canExport/canEdit
- Manuelle Migration 20260314_profile_access_groups
- ProfileAccessModule: CRUD-Endpoints für Gruppen und Mitglieder (nur PLATFORM_ADMIN)
- Neue Admin-Endpoints in ExpertProfileService/-Controller für alle Profil-Mutationen
- verifyOwnership mit skipCheck-Parameter für Admin-Bypass
- ExpertProfileTab + alle Section-Komponenten erhalten apiBase-Prop für Wiederverwendung
- AdminProfileAccessPage: Gruppen-Tab (CRUD) + Profile-Tab (alle User mit Aktionen)
- AdminProfileDetailPage: Profil eines beliebigen Users im Admin-Kontext bearbeiten
- Route /admin/profile-access + /admin/profiles/:userId + Nav-Tab Profilzugriff

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 10:47:36 +01:00

106 lines
5.2 KiB
TypeScript

import { Routes, Route, Navigate } from 'react-router-dom';
import { useAuth } from '../auth/AuthContext';
import { LoginPage } from '../auth/LoginPage';
import { SsoCallbackPage } from '../auth/SsoCallbackPage';
import { AppLayout } from './AppLayout';
import { DashboardPage } from './DashboardPage';
import { AdminLayout } from '../admin/AdminLayout';
import { AdminUsersPage } from '../admin/AdminUsersPage';
import { AdminTenantsPage } from '../admin/AdminTenantsPage';
import { AdminSsoPage } from '../admin/AdminSsoPage';
import { AdminExternalLinksPage } from '../admin/AdminExternalLinksPage';
import { AdminCustomizePage } from '../admin/AdminCustomizePage';
import { AdminEventsPage } from '../admin/AdminEventsPage';
import { AdminSslPage } from '../admin/AdminSslPage';
import { AdminCompanyPage } from '../admin/AdminCompanyPage';
import { AdminProfileAccessPage } from '../admin/AdminProfileAccessPage';
import { AdminProfileDetailPage } from '../admin/AdminProfileDetailPage';
import { ProfilePage } from '../profile/ProfilePage';
import { ContactsPage } from '../crm/contacts/ContactsPage';
import { ContactDetailPage } from '../crm/contacts/ContactDetailPage';
import { DealsPage } from '../crm/deals/DealsPage';
import { DealDetailPage } from '../crm/deals/DealDetailPage';
import { PipelinesPage } from '../crm/pipelines/PipelinesPage';
import { CompaniesPage } from '../crm/companies/CompaniesPage';
import { CompanyDetailPage } from '../crm/companies/CompanyDetailPage';
import { CrmSettingsProvider, CrmModuleGuard } from '../crm/settings/CrmSettingsContext';
import { CrmSettingsPage } from '../crm/settings/CrmSettingsPage';
import { LexwareSyncPage } from '../crm/lexware/LexwareSyncPage';
import { ForecastPage } from '../crm/forecast/ForecastPage';
import { KanbanPage } from '../crm/deals/KanbanPage';
import { Office365Page } from '../crm/office365/Office365Page';
function PrivateRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<p>Laden...</p>
</div>
);
}
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
export function App() {
return (
<Routes>
{/* Öffentliche Routen */}
<Route path="/login" element={<LoginPage />} />
<Route path="/auth/sso/callback" element={<SsoCallbackPage />} />
{/* Geschützte Routen */}
<Route
path="/"
element={
<PrivateRoute>
<CrmSettingsProvider>
<AppLayout />
</CrmSettingsProvider>
</PrivateRoute>
}
>
<Route index element={<DashboardPage />} />
<Route path="profile" element={<ProfilePage />} />
{/* CRM-Bereich */}
<Route path="crm/contacts" element={<CrmModuleGuard module="contacts"><ContactsPage /></CrmModuleGuard>} />
<Route path="crm/contacts/:id" element={<CrmModuleGuard module="contacts"><ContactDetailPage /></CrmModuleGuard>} />
<Route path="crm/companies" element={<CrmModuleGuard module="companies"><CompaniesPage /></CrmModuleGuard>} />
<Route path="crm/companies/:id" element={<CrmModuleGuard module="companies"><CompanyDetailPage /></CrmModuleGuard>} />
<Route path="crm/deals" element={<CrmModuleGuard module="deals"><DealsPage /></CrmModuleGuard>} />
<Route path="crm/deals/:id" element={<CrmModuleGuard module="deals"><DealDetailPage /></CrmModuleGuard>} />
<Route path="crm/pipelines" element={<CrmModuleGuard module="pipelines"><PipelinesPage /></CrmModuleGuard>} />
<Route path="crm/forecast" element={<CrmModuleGuard module="deals"><ForecastPage /></CrmModuleGuard>} />
<Route path="crm/kanban" element={<CrmModuleGuard module="deals"><KanbanPage /></CrmModuleGuard>} />
<Route path="crm/office365" element={<Office365Page />} />
<Route path="crm/import" element={<Navigate to="/crm/settings" replace />} />
<Route path="crm/settings" element={<CrmSettingsPage />} />
<Route path="crm/lexware-sync" element={<LexwareSyncPage />} />
{/* Admin-Bereich mit eigenem Layout (Top-Tabs) */}
<Route path="admin" element={<AdminLayout />}>
<Route index element={<Navigate to="users" replace />} />
<Route path="users" element={<AdminUsersPage />} />
<Route path="tenants" element={<AdminTenantsPage />} />
<Route path="sso" element={<AdminSsoPage />} />
<Route path="external-links" element={<AdminExternalLinksPage />} />
<Route path="customize" element={<AdminCustomizePage />} />
<Route path="company" element={<AdminCompanyPage />} />
<Route path="events" element={<AdminEventsPage />} />
<Route path="ssl" element={<AdminSslPage />} />
<Route path="profile-access" element={<AdminProfileAccessPage />} />
</Route>
{/* Admin-Profildetail außerhalb des Admin-Layouts (volle Seite) */}
<Route path="admin/profiles/:userId" element={<AdminProfileDetailPage />} />
</Route>
{/* Fallback */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
}