139 lines
4.3 KiB
TypeScript
139 lines
4.3 KiB
TypeScript
/**
|
|
* MainLayout
|
|
*
|
|
* Hauptlayout der Anwendung mit Sidebar und Content-Bereich.
|
|
* Enthält den FeatureProvider für das Multi-Tenant-System.
|
|
*/
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import { Outlet, useLocation } from 'react-router-dom';
|
|
import { FeatureProvider, useFeatureStore } from '../stores/featureStore';
|
|
import { MandateNavigation } from '../components/Navigation/MandateNavigation';
|
|
import { UserSection } from '../components/Navigation/UserSection';
|
|
import { WorkspaceKeepAlive } from '../pages/views/workspace/WorkspaceKeepAlive';
|
|
import { CommcoachKeepAlive } from '../pages/views/commcoach/CommcoachKeepAlive';
|
|
import styles from './MainLayout.module.css';
|
|
|
|
const _WORKSPACE_ROUTE_RE = /\/mandates\/[^/]+\/workspace\/[^/]+\/dashboard/;
|
|
const _COMMCOACH_ROUTE_RE = /\/mandates\/[^/]+\/commcoach\/[^/]+\/(?:coaching|dossier)/;
|
|
|
|
// =============================================================================
|
|
// INNER LAYOUT (mit Zugriff auf Store)
|
|
// =============================================================================
|
|
|
|
const MainLayoutInner: React.FC = () => {
|
|
const { loadFeatures, initialized, loading, error } = useFeatureStore();
|
|
const location = useLocation();
|
|
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
|
|
const isWorkspaceKeepAliveVisible = _WORKSPACE_ROUTE_RE.test(location.pathname);
|
|
const isCommcoachKeepAliveVisible = _COMMCOACH_ROUTE_RE.test(location.pathname);
|
|
const hideOutletShell = isWorkspaceKeepAliveVisible || isCommcoachKeepAliveVisible;
|
|
|
|
// Features laden beim Mount
|
|
useEffect(() => {
|
|
if (!initialized && !loading) {
|
|
loadFeatures();
|
|
}
|
|
}, [initialized, loading, loadFeatures]);
|
|
|
|
useEffect(() => {
|
|
setIsMobileSidebarOpen(false);
|
|
}, [location.pathname]);
|
|
|
|
useEffect(() => {
|
|
const handleResize = () => {
|
|
if (window.innerWidth > 1024) {
|
|
setIsMobileSidebarOpen(false);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
return () => window.removeEventListener('resize', handleResize);
|
|
}, []);
|
|
|
|
return (
|
|
<div className={styles.mainLayout}>
|
|
{isMobileSidebarOpen && (
|
|
<button
|
|
className={styles.mobileBackdrop}
|
|
onClick={() => setIsMobileSidebarOpen(false)}
|
|
aria-label="Navigation schliessen"
|
|
/>
|
|
)}
|
|
|
|
{/* Sidebar */}
|
|
<aside className={`${styles.sidebar} ${isMobileSidebarOpen ? styles.sidebarOpen : ''}`}>
|
|
<div className={styles.logoContainer}>
|
|
<img
|
|
src="/logos/poweron-logo.png"
|
|
alt="PowerOn"
|
|
className={styles.logoImage}
|
|
/>
|
|
</div>
|
|
|
|
<nav className={styles.navigation}>
|
|
{loading && (
|
|
<div className={styles.loadingNav}>
|
|
Lade Navigation...
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className={styles.errorNav}>
|
|
Fehler: {error}
|
|
</div>
|
|
)}
|
|
|
|
{initialized && !loading && (
|
|
<MandateNavigation />
|
|
)}
|
|
</nav>
|
|
|
|
{/* User-Bereich am unteren Rand */}
|
|
<UserSection />
|
|
</aside>
|
|
|
|
{/* Content */}
|
|
<main className={styles.content}>
|
|
<div className={styles.mobileTopBar}>
|
|
<button
|
|
className={styles.mobileMenuButton}
|
|
onClick={() => setIsMobileSidebarOpen(true)}
|
|
aria-label="Navigation oeffnen"
|
|
>
|
|
☰
|
|
</button>
|
|
<img
|
|
src="/logos/poweron-logo.png"
|
|
alt="PowerOn"
|
|
className={styles.mobileLogo}
|
|
/>
|
|
</div>
|
|
|
|
<WorkspaceKeepAlive isVisible={isWorkspaceKeepAliveVisible} />
|
|
<CommcoachKeepAlive isVisible={isCommcoachKeepAliveVisible} />
|
|
|
|
<div
|
|
className={styles.outletShell}
|
|
style={{ display: hideOutletShell ? 'none' : undefined }}
|
|
>
|
|
<Outlet />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// MAIN LAYOUT (mit Provider)
|
|
// =============================================================================
|
|
|
|
export const MainLayout: React.FC = () => {
|
|
return (
|
|
<FeatureProvider>
|
|
<MainLayoutInner />
|
|
</FeatureProvider>
|
|
);
|
|
};
|
|
|
|
export default MainLayout;
|