151 lines
5.1 KiB
TypeScript
151 lines
5.1 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 { GraphicalEditorKeepAlive } from '../pages/views/graphicalEditor/GraphicalEditorKeepAlive';
|
|
import { AdminLanguagesKeepAlive } from '../pages/admin/AdminLanguagesKeepAlive';
|
|
import styles from './MainLayout.module.css';
|
|
|
|
import { useLanguage } from '../providers/language/LanguageContext';
|
|
|
|
const _WORKSPACE_ROUTE_RE = /\/mandates\/[^/]+\/workspace\/[^/]+\/dashboard/;
|
|
const _COMMCOACH_ROUTE_RE = /\/mandates\/[^/]+\/commcoach\/[^/]+\/session/;
|
|
const _GE_EDITOR_ROUTE_RE = /\/mandates\/[^/]+\/graphicalEditor\/[^/]+\/editor/;
|
|
const _ADMIN_LANGUAGES_RE = /\/admin\/languages(?:$|\/)/;
|
|
|
|
// =============================================================================
|
|
// INNER LAYOUT (mit Zugriff auf Store)
|
|
// =============================================================================
|
|
|
|
const MainLayoutInner: React.FC = () => {
|
|
const { t } = useLanguage();
|
|
|
|
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 isGEEditorKeepAliveVisible = _GE_EDITOR_ROUTE_RE.test(location.pathname);
|
|
const isLanguagesKeepAliveVisible = _ADMIN_LANGUAGES_RE.test(location.pathname);
|
|
const hideOutletShell = isWorkspaceKeepAliveVisible || isCommcoachKeepAliveVisible || isGEEditorKeepAliveVisible || isLanguagesKeepAliveVisible;
|
|
|
|
// 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={t('Navigation schließen')}
|
|
/>
|
|
)}
|
|
|
|
{/* 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}>
|
|
{t('Lade Navigation…')}
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className={styles.errorNav}>
|
|
{t('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={t('Navigation öffnen')}
|
|
>
|
|
☰
|
|
</button>
|
|
<img
|
|
src="/logos/poweron-logo.png"
|
|
alt="PowerOn"
|
|
className={styles.mobileLogo}
|
|
/>
|
|
</div>
|
|
|
|
<WorkspaceKeepAlive isVisible={isWorkspaceKeepAliveVisible} />
|
|
<CommcoachKeepAlive isVisible={isCommcoachKeepAliveVisible} />
|
|
<GraphicalEditorKeepAlive isVisible={isGEEditorKeepAliveVisible} />
|
|
<AdminLanguagesKeepAlive isVisible={isLanguagesKeepAliveVisible} />
|
|
|
|
<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;
|