Skip to content

Commit 4ff3f27

Browse files
EJ2-981297: Modified the layout of HR portal
1 parent 8be40ad commit 4ff3f27

20 files changed

+3212
-1424
lines changed

Employee_Managment_App/src/App.tsx

Lines changed: 124 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,75 @@
11
// src/App.tsx
2-
import React, { useState } from 'react';
2+
import React, { useState, useEffect } from 'react';
33
import { BrowserRouter as Router, Routes, Route, NavLink } from 'react-router-dom';
44
import './App.css';
55
import TopNav from './components/TopNav';
66
import MyProfile from './components/MyProfile';
77
import Policies from './components/Policies';
88
import Achievements from './components/Achievements';
9-
import Announcement from './components/Announcement';
109
import Organization from './components/Organization';
1110
import EmployeeInfo from './components/EmployeeInfo';
1211

13-
// Extend CSSProperties so TS accepts our custom CSS variables
12+
// Syncfusion Sidebar
13+
import { SidebarComponent } from '@syncfusion/ej2-react-navigations';
14+
1415
type LayoutCSSVars = React.CSSProperties & {
1516
['--sidebar-expanded']?: string;
1617
['--sidebar-collapsed']?: string;
1718
['--header-h']?: string;
1819
['--sidebar-current-width']?: string;
1920
};
2021

22+
function useMediaQuery(query: string) {
23+
const [matches, setMatches] = useState<boolean>(() =>
24+
typeof window !== 'undefined' ? window.matchMedia(query).matches : false
25+
);
26+
useEffect(() => {
27+
if (typeof window === 'undefined') return;
28+
const mq = window.matchMedia(query);
29+
const onChange = () => setMatches(mq.matches);
30+
mq.addEventListener?.('change', onChange);
31+
mq.addListener?.(onChange);
32+
return () => {
33+
mq.removeEventListener?.('change', onChange);
34+
mq.removeListener?.(onChange);
35+
};
36+
}, [query]);
37+
return matches;
38+
}
39+
2140
function App() {
22-
// Layout constants
2341
const SIDEBAR_WIDTH = 240;
2442
const SIDEBAR_WIDTH_COLLAPSED = 72;
2543
const HEADER_HEIGHT = 56;
2644

27-
// UI state
28-
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
29-
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
45+
const [sidebarCollapsed, setSidebarCollapsed] = useState(false); // desktop dock
46+
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); // mobile overlay
47+
const isDesktop = useMediaQuery('(min-width: 992px)');
48+
49+
useEffect(() => {
50+
if (isDesktop) setMobileSidebarOpen(false);
51+
}, [isDesktop]);
3052

31-
// CSS vars consumed by App.css
3253
const layoutVars: LayoutCSSVars = {
3354
'--sidebar-expanded': `${SIDEBAR_WIDTH}px`,
3455
'--sidebar-collapsed': `${SIDEBAR_WIDTH_COLLAPSED}px`,
3556
'--header-h': `${HEADER_HEIGHT}px`,
36-
'--sidebar-current-width': sidebarCollapsed
37-
? `${SIDEBAR_WIDTH_COLLAPSED}px`
38-
: `${SIDEBAR_WIDTH}px`,
57+
'--sidebar-current-width': isDesktop
58+
? sidebarCollapsed
59+
? `${SIDEBAR_WIDTH_COLLAPSED}px`
60+
: `${SIDEBAR_WIDTH}px`
61+
: '0px',
3962
};
4063

4164
const toggleDesktopSidebar = () => setSidebarCollapsed((v) => !v);
4265
const toggleMobileSidebar = () => setMobileSidebarOpen((v) => !v);
4366

67+
const sbIsOpen = isDesktop ? !sidebarCollapsed : mobileSidebarOpen;
68+
const sbEnableDock = isDesktop;
69+
const sbType = isDesktop ? 'Push' : 'Over';
70+
71+
const collapsed = isDesktop && sidebarCollapsed;
72+
4473
return (
4574
<div
4675
className={`app-layout ${sidebarCollapsed ? 'sidebar-is-collapsed' : ''} ${
@@ -50,49 +79,102 @@ function App() {
5079
>
5180
<Router>
5281
<TopNav
53-
companyName="Syncfusion Software"
82+
companyName="NexGen7 Software"
5483
userFullName="Test Person"
55-
sidebarWidth={SIDEBAR_WIDTH}
56-
collapsedSidebarWidth={SIDEBAR_WIDTH_COLLAPSED}
57-
sidebarCollapsed={sidebarCollapsed}
58-
onToggleSidebar={toggleDesktopSidebar}
84+
headerOffsetLeft={isDesktop ? (sidebarCollapsed ? SIDEBAR_WIDTH_COLLAPSED : SIDEBAR_WIDTH) : 0}
5985
onSearch={(q) => console.log('Search:', q)}
6086
/>
6187

62-
{/* Sidebar */}
63-
<aside className="app-sidebar" role="navigation" aria-label="Main">
64-
<div className="sidebar-brand">
65-
<div className="title">HR Portal</div>
66-
<span className="e-icons e-line-very-small"></span>
67-
</div>
88+
{/* Syncfusion Sidebar */}
89+
<SidebarComponent
90+
width={`${SIDEBAR_WIDTH}px`}
91+
dockSize={`${SIDEBAR_WIDTH_COLLAPSED}px`}
92+
enableDock={sbEnableDock}
93+
isOpen={sbIsOpen}
94+
type={sbType as any}
95+
position="Left"
96+
showBackdrop={!isDesktop}
97+
closeOnDocumentClick={!isDesktop}
98+
open={() => {
99+
if (!isDesktop) setMobileSidebarOpen(true);
100+
}}
101+
close={() => {
102+
if (!isDesktop) setMobileSidebarOpen(false);
103+
}}
104+
>
105+
<aside className="app-sidebar" role="navigation" aria-label="Main">
106+
{/* Sidebar header with toggle inside sidebar */}
107+
<div className="sidebar-brand">
108+
<div className="title">{collapsed ? 'HR' : 'HR Portal'}</div>
109+
<button
110+
type="button"
111+
className="sidebar-toggle"
112+
aria-label={collapsed ? 'Expand menu' : 'Collapse menu'}
113+
title={collapsed ? 'Expand' : 'Collapse'}
114+
onClick={isDesktop ? toggleDesktopSidebar : toggleMobileSidebar}
115+
>
116+
{/* menu icon */}
117+
<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true">
118+
<path fill="currentColor" d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z" />
119+
</svg>
120+
</button>
121+
</div>
68122

69-
<ul className="nav flex-column">
70-
<li className="nav-item">
71-
<NavLink className="nav-link" to="/" end>My Profile</NavLink>
72-
</li>
73-
<li className="nav-item">
74-
<NavLink className="nav-link" to="/organization">Organization</NavLink>
75-
</li>
76-
<li className="nav-item">
77-
<NavLink className="nav-link" to="/policies">Policies</NavLink>
78-
</li>
79-
<li className="nav-item">
80-
<NavLink className="nav-link" to="/achievements">Achievements</NavLink>
81-
</li>
82-
<li className="nav-item">
83-
<NavLink className="nav-link" to="/announcement">Announcement</NavLink>
84-
</li>
85-
</ul>
86-
</aside>
123+
<ul className="nav flex-column">
124+
<li className="nav-item">
125+
<NavLink className="nav-link" to="/" end>
126+
<span className="nav-icon" aria-hidden="true">
127+
{/* user/profile */}
128+
<svg width="18" height="18" viewBox="0 0 24 24">
129+
<path fill="currentColor" d="M12 12a5 5 0 1 0-5-5a5 5 0 0 0 5 5zm0 2c-4.418 0-8 2.239-8 5v1h16v-1c0-2.761-3.582-5-8-5z" />
130+
</svg>
131+
</span>
132+
{!collapsed && <span className="nav-text">My Profile</span>}
133+
</NavLink>
134+
</li>
135+
<li className="nav-item">
136+
<NavLink className="nav-link" to="/organization">
137+
<span className="nav-icon" aria-hidden="true">
138+
{/* organization/people */}
139+
<svg width="18" height="18" viewBox="0 0 24 24">
140+
<path fill="currentColor" d="M16 11a4 4 0 1 0-3.465-2H11V7H8V5H4v2H1v3h3v2h3v2h3v2h3.535A4 4 0 1 0 16 11zM6 7h2v2H6zm10-2a2 2 0 1 1 0 4a2 2 0 0 1 0-4zm0 10a2 2 0 1 1 0 4a2 2 0 0 1 0-4z" />
141+
</svg>
142+
</span>
143+
{!collapsed && <span className="nav-text">Organization</span>}
144+
</NavLink>
145+
</li>
146+
<li className="nav-item">
147+
<NavLink className="nav-link" to="/policies">
148+
<span className="nav-icon" aria-hidden="true">
149+
{/* policy/document */}
150+
<svg width="18" height="18" viewBox="0 0 24 24">
151+
<path fill="currentColor" d="M6 2h9l5 5v15H6zM8 4v16h10V9h-5V4zm2 7h6v2h-6zm0 4h6v2h-6z" />
152+
</svg>
153+
</span>
154+
{!collapsed && <span className="nav-text">Policies</span>}
155+
</NavLink>
156+
</li>
157+
<li className="nav-item">
158+
<NavLink className="nav-link" to="/achievements">
159+
<span className="nav-icon" aria-hidden="true">
160+
{/* trophy */}
161+
<svg width="18" height="18" viewBox="0 0 24 24">
162+
<path fill="currentColor" d="M17 3H7v4a5 5 0 0 0 4 4.9V14H8v2h8v-2h-3v-2.1A5 5 0 0 0 17 7zM7 7V5h10v2a3 3 0 0 1-6 0H9a3 3 0 0 1-2 3z" />
163+
</svg>
164+
</span>
165+
{!collapsed && <span className="nav-text">Achievements</span>}
166+
</NavLink>
167+
</li>
168+
</ul>
169+
</aside>
170+
</SidebarComponent>
87171

88-
{/* Main content */}
89172
<main className="app-main">
90173
<Routes>
91174
<Route path="/" element={<MyProfile />} />
92175
<Route path="/organization" element={<Organization />} />
93176
<Route path="/policies" element={<Policies />} />
94177
<Route path="/achievements" element={<Achievements />} />
95-
<Route path="/announcement" element={<Announcement />} />
96178
<Route path="/employeeinfo" element={<EmployeeInfo />} />
97179
</Routes>
98180
</main>

0 commit comments

Comments
 (0)