merge design protal and backoffice

This commit is contained in:
mengstabketemaw
2026-06-17 13:50:20 +03:00
parent 36234a2948
commit 85e070db33
25 changed files with 2618 additions and 847 deletions

View File

@@ -1,31 +1,112 @@
import { useState } from 'react';
import { useCallback, useState } from 'react';
import { AppShell } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { Outlet } from 'react-router-dom';
import { AppHeader } from './components/AppHeader';
import { AppSidebar } from './components/AppSidebar';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { logout } from '@ema-platform/auth';
import { AppHeader, AppSidebar } from '@ema-platform/ui';
import type { NavItem } from '@ema-platform/ui';
import {
IconLayoutDashboard,
IconUsers,
IconUser,
} from '@tabler/icons-react';
import { notify } from '@ema-platform/ui';
import { SUPPORTED_LANGUAGES } from '../i18n/config';
const NAV_ITEMS: NavItem[] = [
{ to: '/dashboard', label: 'Dashboard', icon: IconLayoutDashboard },
{ to: '/um/user-management/dashboard', label: 'User Management', icon: IconUsers },
{ to: '/profile', label: 'Profile', icon: IconUser },
];
export function BackofficeLayout() {
const [opened, { toggle }] = useDisclosure();
const { t } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
const dispatch = useDispatch();
const [opened, { toggle: toggleNav }] = useDisclosure();
const [collapsed, setCollapsed] = useState(false);
const handleToggleCollapse = () => setCollapsed((prev) => !prev);
const handleLogout = useCallback(() => {
dispatch(logout());
navigate('/login');
}, [dispatch, navigate]);
// Breadcrumbs
const segments = location.pathname.split('/').filter(Boolean);
const crumbs = [
{ label: t('nav.dashboard'), path: '/dashboard' },
...segments
.map((_, i) => '/' + segments.slice(0, i + 1).join('/'))
.filter((path) => path !== '/dashboard')
.filter((path) => !path.startsWith('/um'))
.map((path) => ({ label: t('nav.dashboard'), path })),
];
const go = (item: NavItem) => {
if (item.soon) {
notify.info(`${item.label} — coming soon.`);
return;
}
if (item.to) {
navigate(item.to);
}
};
return (
<AppShell
header={{ height: 64 }}
navbar={{ width: collapsed ? 80 : 264, breakpoint: 'sm', collapsed: { mobile: !opened } }}
header={{ height: 74 }}
navbar={{
width: collapsed ? 72 : 264,
breakpoint: 'sm',
collapsed: { mobile: !opened },
}}
padding="lg"
styles={{ main: { backgroundColor: '#f5f7fb' } }}
>
<AppShell.Header>
<AppHeader onToggle={toggle} />
<AppShell.Header
style={{
background: 'var(--mantine-color-body)',
borderBottom: '1px solid var(--mantine-color-gray-2)',
}}
>
<AppHeader
onToggleNav={toggleNav}
onToggleSidebar={handleToggleCollapse}
navOpened={opened}
breadcrumbs={crumbs}
onNavigate={navigate}
onLogout={handleLogout}
userName={t('app.name')}
userInitials="AD"
supportedLanguages={SUPPORTED_LANGUAGES}
/>
</AppShell.Header>
<AppShell.Navbar p="md">
<AppSidebar collapsed={collapsed} onToggleCollapse={handleToggleCollapse} />
<AppShell.Navbar
p={0}
style={{
overflow: 'hidden',
transition: 'width 200ms ease',
background: 'var(--mantine-color-body)',
borderRight: '1px solid var(--mantine-color-gray-2)',
}}
>
<AppSidebar
navItems={NAV_ITEMS}
collapsed={collapsed}
activePath={location.pathname}
onToggleCollapse={handleToggleCollapse}
onNavigate={go}
brandName={t('app.name')}
brandSubtitle={t('app.authority')}
/>
</AppShell.Navbar>
<AppShell.Main>
<Outlet />
<div key={location.pathname} className="ema-page-enter">
<Outlet />
</div>
</AppShell.Main>
</AppShell>
);