alpe-temp 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/frontend-project/src/App.css +1 -0
  2. package/frontend-project/src/Auth/Login.jsx +85 -0
  3. package/frontend-project/src/Auth/Register.jsx +183 -0
  4. package/frontend-project/src/Intro.jsx +33 -0
  5. package/frontend-project/src/LayOut.jsx +38 -0
  6. package/frontend-project/src/api/ApiClient.js +92 -0
  7. package/frontend-project/src/assets/hero.png +0 -0
  8. package/frontend-project/src/assets/react.svg +1 -0
  9. package/frontend-project/src/assets/vite.svg +1 -0
  10. package/frontend-project/src/components/Aside.jsx +9 -0
  11. package/frontend-project/src/components/Button.jsx +100 -0
  12. package/frontend-project/src/components/Card.jsx +104 -0
  13. package/frontend-project/src/components/FormField.jsx +129 -0
  14. package/frontend-project/src/components/Modal.jsx +106 -0
  15. package/frontend-project/src/components/Table.jsx +127 -0
  16. package/frontend-project/src/components/Toast.jsx +64 -0
  17. package/frontend-project/src/components/index.js +14 -0
  18. package/frontend-project/src/config.js +66 -0
  19. package/frontend-project/src/design.js +115 -0
  20. package/frontend-project/src/index.css +60 -0
  21. package/frontend-project/src/layouts/BottomNav.jsx +156 -0
  22. package/frontend-project/src/layouts/TopNav.jsx +150 -0
  23. package/frontend-project/src/layouts/useShell.js +44 -0
  24. package/frontend-project/src/main.jsx +41 -0
  25. package/frontend-project/src/pages/Department.jsx +188 -0
  26. package/frontend-project/src/pages/Employee.jsx +274 -0
  27. package/frontend-project/src/pages/Home.jsx +79 -0
  28. package/frontend-project/src/pages/Profile.jsx +9 -0
  29. package/frontend-project/src/pages/Register.jsx +57 -0
  30. package/frontend-project/src/pages/Reports.jsx +91 -0
  31. package/frontend-project/src/pages/Salary.jsx +264 -0
  32. package/frontend-project/src/themes.js +175 -0
  33. package/package.json +1 -1
@@ -0,0 +1,115 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // 📐 DESIGN TOKENS — Turns config.js into CSS variables and utilities
3
+ // ═══════════════════════════════════════════════════════════════════════════
4
+ //
5
+ // WHAT THIS FILE DOES:
6
+ // Takes your config.js settings and turns them into:
7
+ // 1. CSS custom properties (variables) for global styling
8
+ // 2. Tailwind-compatible class names for components
9
+ //
10
+ // HOW IT WORKS:
11
+ // The Layout component calls `getDesignTokens(config)` to get an object
12
+ // with CSS variable values and utility class names. These are applied
13
+ // to the root div so every child component can use them.
14
+ //
15
+ // ═══════════════════════════════════════════════════════════════════════════
16
+
17
+ import { getTheme } from './themes';
18
+
19
+ // ─── RADIUS VALUES ───────────────────────────────────────────────────────────
20
+ const RADIUS = {
21
+ none: '0px',
22
+ sm: '0.125rem', // 2px
23
+ md: '0.375rem', // 6px
24
+ lg: '0.5rem', // 8px
25
+ xl: '0.75rem', // 12px
26
+ full: '9999px',
27
+ };
28
+
29
+ // ─── FONT SIZE SCALES ────────────────────────────────────────────────────────
30
+ const FONT_SCALE = {
31
+ normal: {
32
+ xs: '0.75rem', // 12px
33
+ sm: '0.8125rem', // 13px
34
+ base:'0.875rem', // 14px
35
+ lg: '1rem', // 16px
36
+ xl: '1.25rem', // 20px
37
+ '2xl':'1.5rem', // 24px
38
+ '3xl':'2rem', // 32px
39
+ },
40
+ large: {
41
+ xs: '0.8125rem', // 13px
42
+ sm: '0.875rem', // 14px
43
+ base:'1rem', // 16px
44
+ lg: '1.125rem', // 18px
45
+ xl: '1.375rem', // 22px
46
+ '2xl':'1.75rem', // 28px
47
+ '3xl':'2.25rem', // 36px
48
+ },
49
+ };
50
+
51
+ // ─── ROUNDED CLASS HELPER ────────────────────────────────────────────────────
52
+ // Use this in components to get the Tailwind rounded class for a given level.
53
+ // Example: getRoundedClass('md') → 'rounded-md'
54
+ //
55
+ export function getRoundedClass(level = 'md') {
56
+ const map = {
57
+ none: 'rounded-none',
58
+ sm: 'rounded-sm',
59
+ md: 'rounded-md',
60
+ lg: 'rounded-lg',
61
+ xl: 'rounded-xl',
62
+ full: 'rounded-full',
63
+ };
64
+ return map[level] || map.md;
65
+ }
66
+
67
+ // ─── GENERATE DESIGN TOKENS ──────────────────────────────────────────────────
68
+ // This is called once by the Layout component to produce:
69
+ // {
70
+ // cssVars: { '--color-primary': '#008A75', ... },
71
+ // roundedClass: 'rounded-md',
72
+ // theme: { ... resolved theme colors },
73
+ // }
74
+ //
75
+ export function getDesignTokens(config) {
76
+ const theme = getTheme(config.theme, config.colors);
77
+
78
+ // Merge user color overrides
79
+ const colors = { ...theme };
80
+ if (config.colors) {
81
+ Object.entries(config.colors).forEach(([key, val]) => {
82
+ if (val) colors[key] = val;
83
+ });
84
+ }
85
+
86
+ // Build CSS variable map
87
+ const cssVars = {
88
+ '--color-primary': colors.primary,
89
+ '--color-surface': colors.surface,
90
+ '--color-card': colors.card,
91
+ '--color-border': colors.border,
92
+ '--color-text': colors.text,
93
+ '--color-text-muted': colors.textMuted,
94
+ '--color-nav-bg': colors.navBg,
95
+ '--color-nav-text': colors.navText,
96
+ '--color-nav-active': colors.navActive,
97
+ '--color-danger': colors.danger,
98
+ '--color-success': colors.success,
99
+ '--color-warning': colors.warning,
100
+ '--color-info': colors.info,
101
+ '--radius': RADIUS[config.rounded] || RADIUS.md,
102
+ };
103
+
104
+ // Add font size variables
105
+ const fontSizes = FONT_SCALE[config.fontSize] || FONT_SCALE.normal;
106
+ Object.entries(fontSizes).forEach(([key, val]) => {
107
+ cssVars[`--text-${key}`] = val;
108
+ });
109
+
110
+ return {
111
+ cssVars,
112
+ roundedClass: getRoundedClass(config.rounded),
113
+ theme: colors,
114
+ };
115
+ }
@@ -0,0 +1,60 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ 🎨 GLOBAL STYLES — Tailwind + CSS custom properties
3
+ ═══════════════════════════════════════════════════════════════════════════
4
+
5
+ CSS VARIABLES (--color-*, --radius, --text-*):
6
+ These are set dynamically by design.js based on your config.js.
7
+ They are applied to the :root element by the Layout component.
8
+
9
+ HOW TO USE IN COMPONENTS:
10
+ style={{ color: 'var(--color-primary)' }}
11
+ or Tailwind: className="bg-[var(--color-primary)]"
12
+
13
+ ═══════════════════════════════════════════════════════════════════════════ */
14
+
15
+ @tailwind base;
16
+ @tailwind components;
17
+ @tailwind utilities;
18
+
19
+ /* ─── Custom CSS Variables (applied by Layout component) ───────────────── */
20
+ :root {
21
+ --color-primary: #008A75;
22
+ --color-surface: #F9FAFB;
23
+ --color-card: #FFFFFF;
24
+ --color-border: #E5E7EB;
25
+ --color-text: #1F2937;
26
+ --color-text-muted: #9CA3AF;
27
+ --color-nav-bg: #FFFFFF;
28
+ --color-nav-text: #4B5563;
29
+ --color-nav-active: #008A75;
30
+ --color-danger: #EF4444;
31
+ --color-success: #10B981;
32
+ --color-warning: #F59E0B;
33
+ --color-info: #3B82F6;
34
+ --radius: 0.375rem;
35
+ --text-xs: 0.75rem;
36
+ --text-sm: 0.8125rem;
37
+ --text-base: 0.875rem;
38
+ --text-lg: 1rem;
39
+ --text-xl: 1.25rem;
40
+ --text-2xl: 1.5rem;
41
+ --text-3xl: 2rem;
42
+ }
43
+
44
+ /* ─── Tailwind-like utilities using CSS variables ──────────────────────── */
45
+ @layer utilities {
46
+ .bg-primary { background-color: var(--color-primary); }
47
+ .text-primary { color: var(--color-primary); }
48
+ .border-primary { border-color: var(--color-primary); }
49
+ .bg-surface { background-color: var(--color-surface); }
50
+ .bg-card { background-color: var(--color-card); }
51
+ .text-muted { color: var(--color-text-muted); }
52
+ }
53
+
54
+ /* ─── Animations ───────────────────────────────────────────────────────── */
55
+ @keyframes spin {
56
+ to { transform: rotate(360deg); }
57
+ }
58
+ .animate-spin {
59
+ animation: spin 1s linear infinite;
60
+ }
@@ -0,0 +1,156 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // 📱 BOTTOM NAV LAYOUT — Navbar at the bottom (mobile-first style)
3
+ // ═══════════════════════════════════════════════════════════════════════════
4
+ //
5
+ // WHAT THIS FILE DOES:
6
+ // Renders the app shell with a bottom navigation bar.
7
+ // Switch to this by setting navigation: 'bottomnav' in config.js
8
+ //
9
+ // HOW IT LOOKS:
10
+ // ┌────────────────────────────────┐
11
+ // │ │
12
+ // │ PAGE CONTENT │ ← scrollable
13
+ // │ │
14
+ // ├────────────────────────────────┤
15
+ // │ 📊 👥 💰 🏢 📄 │ ← bottom nav (fixed)
16
+ // └────────────────────────────────┘
17
+ //
18
+ // ═══════════════════════════════════════════════════════════════════════════
19
+
20
+ import React, { useState } from 'react';
21
+ import { NavLink, Outlet } from 'react-router-dom';
22
+ import {
23
+ LayoutDashboard, Users, DollarSign, Building2,
24
+ FileText, User, LogOut, ChevronDown,
25
+ } from 'lucide-react';
26
+ import { useShell } from './useShell';
27
+
28
+ // ─── NAVIGATION ITEMS ────────────────────────────────────────────────────────
29
+ // Add new pages here. The icon + label + path = one nav item.
30
+ //
31
+ const NAV_ITEMS = [
32
+ { label: 'Home', path: '/dashboard/overview', Icon: LayoutDashboard },
33
+ { label: 'Employees',path: '/dashboard/employees', Icon: Users },
34
+ { label: 'Salary', path: '/dashboard/salary', Icon: DollarSign },
35
+ { label: 'Depts', path: '/dashboard/departments', Icon: Building2 },
36
+ { label: 'Reports', path: '/dashboard/reports', Icon: FileText },
37
+ ];
38
+
39
+ export default function BottomNav() {
40
+ const { user, handleLogout } = useShell();
41
+ const [menuOpen, setMenuOpen] = useState(false);
42
+
43
+ return (
44
+ <div className="flex flex-col h-screen overflow-hidden">
45
+ {/* ─── TOP BAR (user menu, logo) ─────────────────────────────────── */}
46
+ <header
47
+ className="flex-shrink-0 flex items-center h-[52px] px-4 gap-1 z-20"
48
+ style={{
49
+ backgroundColor: 'var(--color-nav-bg)',
50
+ color: 'var(--color-nav-text)',
51
+ borderBottom: '1px solid var(--color-border)',
52
+ }}
53
+ >
54
+ <div className="flex items-center gap-2 mr-4">
55
+ <img src="/logo.png" alt="logo" className="w-7 h-9" />
56
+ <div className="flex flex-col mt-4">
57
+ <span className="text-[15px] font-bold tracking-tight leading-tight">
58
+ EP<span style={{ color: 'var(--color-primary)' }}>MS</span>
59
+ </span>
60
+ <span className="text-[7px] font-medium uppercase tracking-wider leading-tight opacity-60">
61
+ Employee Payroll
62
+ </span>
63
+ </div>
64
+ </div>
65
+
66
+ {/* Spacer */}
67
+ <div className="flex-1" />
68
+
69
+ {/* User dropdown */}
70
+ <div className="relative">
71
+ <button
72
+ onClick={() => setMenuOpen((v) => !v)}
73
+ className="flex items-center gap-2 px-3 py-1.5 text-[12px] font-medium transition-colors hover:opacity-80"
74
+ >
75
+ <div
76
+ className="w-6 h-6 flex items-center justify-center"
77
+ style={{ backgroundColor: 'var(--color-primary)', color: '#fff' }}
78
+ >
79
+ <User className="w-3 h-3" />
80
+ </div>
81
+ <span className="hidden sm:inline">{user?.name ?? 'Admin'}</span>
82
+ <ChevronDown className={`w-3 h-3 transition-transform ${menuOpen ? 'rotate-180' : ''}`} />
83
+ </button>
84
+ {menuOpen && (
85
+ <>
86
+ <div className="fixed inset-0 z-10" onClick={() => setMenuOpen(false)} />
87
+ <div
88
+ className="absolute right-0 top-full mt-1 z-20 shadow-lg py-1 min-w-[150px]"
89
+ style={{ backgroundColor: 'var(--color-card)', border: '1px solid var(--color-border)' }}
90
+ >
91
+ <div className="px-3 py-2 border-b" style={{ borderColor: 'var(--color-border)' }}>
92
+ <p className="text-[12px] font-semibold" style={{ color: 'var(--color-text)' }}>
93
+ {user?.name ?? 'Admin'}
94
+ </p>
95
+ <p className="text-[11px]" style={{ color: 'var(--color-text-muted)' }}>
96
+ {user?.email ?? ''}
97
+ </p>
98
+ </div>
99
+ <button
100
+ onClick={() => { setMenuOpen(false); handleLogout(); }}
101
+ className="w-full flex items-center gap-2 px-3 py-2 text-[12px] font-medium transition-colors"
102
+ style={{ color: 'var(--color-danger)' }}
103
+ onMouseEnter={(e) => e.target.style.backgroundColor = 'var(--color-danger)'}
104
+ onMouseLeave={(e) => e.target.style.backgroundColor = 'transparent'}
105
+ >
106
+ <LogOut className="w-3.5 h-3.5" />
107
+ Logout
108
+ </button>
109
+ </div>
110
+ </>
111
+ )}
112
+ </div>
113
+ </header>
114
+
115
+ {/* ─── MAIN CONTENT ──────────────────────────────────────────────── */}
116
+ <main
117
+ className="flex-1 overflow-y-auto"
118
+ style={{
119
+ backgroundColor: 'var(--color-surface)',
120
+ padding: 'var(--text-base)',
121
+ }}
122
+ >
123
+ <div className="max-w-6xl mx-auto">
124
+ <Outlet />
125
+ </div>
126
+ </main>
127
+
128
+ {/* ─── BOTTOM NAV ──────────────────────────────────────────────────── */}
129
+ <nav
130
+ className="flex-shrink-0 flex items-center justify-around h-[64px] px-2 z-20"
131
+ style={{
132
+ backgroundColor: 'var(--color-nav-bg)',
133
+ borderTop: '1px solid var(--color-border)',
134
+ }}
135
+ >
136
+ {NAV_ITEMS.map(({ label, path, Icon }) => (
137
+ <NavLink
138
+ key={path}
139
+ to={path}
140
+ className="flex flex-col items-center gap-0.5 px-2 py-1 text-[10px] font-medium transition-colors"
141
+ style={({ isActive }) => ({
142
+ color: isActive ? 'var(--color-nav-active)' : 'var(--color-nav-text)',
143
+ })}
144
+ >
145
+ {({ isActive }) => (
146
+ <>
147
+ <Icon className="w-5 h-5" />
148
+ <span>{label}</span>
149
+ </>
150
+ )}
151
+ </NavLink>
152
+ ))}
153
+ </nav>
154
+ </div>
155
+ );
156
+ }
@@ -0,0 +1,150 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // 📐 TOP NAV LAYOUT — Navbar at the top (classic web style)
3
+ // ═══════════════════════════════════════════════════════════════════════════
4
+ //
5
+ // WHAT THIS FILE DOES:
6
+ // Renders the app shell with a horizontal nav bar at the top.
7
+ // This is the default layout (navigation: 'topnav' in config.js).
8
+ //
9
+ // HOW IT LOOKS:
10
+ // ┌──────────────────────────────────────────────┐
11
+ // │ LOGO Home Employees Salary Reports 👤│ ← top nav (fixed)
12
+ // ├──────────────────────────────────────────────┤
13
+ // │ │
14
+ // │ PAGE CONTENT │ ← scrollable
15
+ // │ │
16
+ // └──────────────────────────────────────────────┘
17
+ //
18
+ // HOW TO ADD A NEW NAV ITEM:
19
+ // Just add an entry to the NAV_ITEMS array below.
20
+ // Example: { label: 'Products', path: '/dashboard/products', Icon: Package }
21
+ //
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+
24
+ import React, { useState } from 'react';
25
+ import { NavLink, Outlet } from 'react-router-dom';
26
+ import {
27
+ LayoutDashboard, Users, DollarSign, Building2,
28
+ FileText, User, LogOut, ChevronDown,
29
+ } from 'lucide-react';
30
+ import { useShell } from './useShell';
31
+
32
+ // ─── NAVIGATION ITEMS ────────────────────────────────────────────────────────
33
+ // To add a new page, just add an object to this array.
34
+ // Each item needs: label (shown text), path (URL), Icon (from lucide-react)
35
+ //
36
+ const NAV_ITEMS = [
37
+ { label: 'Overview', path: '/dashboard/overview', Icon: LayoutDashboard },
38
+ { label: 'Employees', path: '/dashboard/employees', Icon: Users },
39
+ { label: 'Salary', path: '/dashboard/salary', Icon: DollarSign },
40
+ { label: 'Departments', path: '/dashboard/departments', Icon: Building2 },
41
+ { label: 'Reports', path: '/dashboard/reports', Icon: FileText },
42
+ ];
43
+
44
+ export default function TopNav() {
45
+ const { user, handleLogout } = useShell();
46
+ const [menuOpen, setMenuOpen] = useState(false);
47
+
48
+ return (
49
+ <div className="flex flex-col h-screen overflow-hidden">
50
+ {/* ─── TOP NAV BAR ───────────────────────────────────────────────── */}
51
+ <header
52
+ className="flex-shrink-0 flex items-center h-[52px] px-4 gap-1 z-20"
53
+ style={{
54
+ backgroundColor: 'var(--color-nav-bg)',
55
+ color: 'var(--color-nav-text)',
56
+ borderBottom: '1px solid var(--color-border)',
57
+ }}
58
+ >
59
+ {/* Logo + Brand */}
60
+ <div className="flex items-center gap-2 mr-4 pr-4" style={{ borderRight: '1px solid var(--color-border)' }}>
61
+ <img src="/logo.png" alt="logo" className="w-7 h-9" />
62
+ <div className="flex flex-col mt-4">
63
+ <span className="text-[15px] font-bold tracking-tight leading-tight">
64
+ EP<span style={{ color: 'var(--color-primary)' }}>MS</span>
65
+ </span>
66
+ <span className="text-[7px] font-medium uppercase tracking-wider leading-tight opacity-60">
67
+ Employee Payroll
68
+ </span>
69
+ </div>
70
+ </div>
71
+
72
+ {/* Navigation links */}
73
+ <nav className="flex items-center gap-0.5 flex-1">
74
+ {NAV_ITEMS.map(({ label, path, Icon }) => (
75
+ <NavLink
76
+ key={path}
77
+ to={path}
78
+ className="flex items-center gap-1.5 px-3 py-1.5 text-[12px] font-medium transition-colors"
79
+ style={({ isActive }) => ({
80
+ backgroundColor: isActive ? 'var(--color-primary)' : 'transparent',
81
+ color: isActive ? '#ffffff' : 'var(--color-nav-text)',
82
+ })}
83
+ >
84
+ <Icon className="w-3.5 h-3.5 flex-shrink-0" />
85
+ <span className="hidden sm:inline">{label}</span>
86
+ </NavLink>
87
+ ))}
88
+ </nav>
89
+
90
+ {/* User dropdown */}
91
+ <div className="relative ml-auto">
92
+ <button
93
+ onClick={() => setMenuOpen((v) => !v)}
94
+ className="flex items-center gap-2 px-3 py-1.5 text-[12px] font-medium transition-colors hover:opacity-80"
95
+ >
96
+ <div
97
+ className="w-6 h-6 flex items-center justify-center"
98
+ style={{ backgroundColor: 'var(--color-primary)', color: '#fff' }}
99
+ >
100
+ <User className="w-3 h-3" />
101
+ </div>
102
+ <span className="hidden sm:inline">{user?.name ?? 'Admin'}</span>
103
+ <ChevronDown className={`w-3 h-3 transition-transform ${menuOpen ? 'rotate-180' : ''}`} />
104
+ </button>
105
+ {menuOpen && (
106
+ <>
107
+ <div className="fixed inset-0 z-10" onClick={() => setMenuOpen(false)} />
108
+ <div
109
+ className="absolute right-0 top-full mt-1 z-20 shadow-lg py-1 min-w-[150px]"
110
+ style={{ backgroundColor: 'var(--color-card)', border: '1px solid var(--color-border)' }}
111
+ >
112
+ <div className="px-3 py-2 border-b" style={{ borderColor: 'var(--color-border)' }}>
113
+ <p className="text-[12px] font-semibold" style={{ color: 'var(--color-text)' }}>
114
+ {user?.name ?? 'Admin'}
115
+ </p>
116
+ <p className="text-[11px]" style={{ color: 'var(--color-text-muted)' }}>
117
+ {user?.email ?? ''}
118
+ </p>
119
+ </div>
120
+ <button
121
+ onClick={() => { setMenuOpen(false); handleLogout(); }}
122
+ className="w-full flex items-center gap-2 px-3 py-2 text-[12px] font-medium transition-colors"
123
+ style={{ color: 'var(--color-danger)' }}
124
+ onMouseEnter={(e) => e.target.style.backgroundColor = 'var(--color-danger)'}
125
+ onMouseLeave={(e) => e.target.style.backgroundColor = 'transparent'}
126
+ >
127
+ <LogOut className="w-3.5 h-3.5" />
128
+ Logout
129
+ </button>
130
+ </div>
131
+ </>
132
+ )}
133
+ </div>
134
+ </header>
135
+
136
+ {/* ─── MAIN CONTENT ──────────────────────────────────────────────── */}
137
+ <main
138
+ className="flex-1 overflow-y-auto"
139
+ style={{
140
+ backgroundColor: 'var(--color-surface)',
141
+ padding: '24px',
142
+ }}
143
+ >
144
+ <div className="max-w-7xl mx-auto">
145
+ <Outlet />
146
+ </div>
147
+ </main>
148
+ </div>
149
+ );
150
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * layouts/useShell.js – Shared auth logic for every layout shell.
3
+ *
4
+ * Returns { user, handleLogout } — plug into any shell component.
5
+ */
6
+
7
+ import { useEffect, useState } from 'react';
8
+ import { useNavigate } from 'react-router-dom';
9
+ import { authApi } from '../api/ApiClient';
10
+
11
+ export function useShell() {
12
+ const [user, setUser] = useState(null);
13
+ const navigate = useNavigate();
14
+
15
+ useEffect(() => {
16
+ const token = localStorage.getItem('token');
17
+ if (!token) { navigate('/'); return; }
18
+
19
+ try {
20
+ const payload = JSON.parse(atob(token.split('.')[1]));
21
+ if (payload.exp < Date.now() / 1000) {
22
+ localStorage.removeItem('token');
23
+ localStorage.removeItem('user');
24
+ navigate('/');
25
+ return;
26
+ }
27
+ } catch {
28
+ navigate('/');
29
+ return;
30
+ }
31
+
32
+ const stored = localStorage.getItem('user');
33
+ setUser(stored ? JSON.parse(stored) : {});
34
+ }, [navigate]);
35
+
36
+ const handleLogout = async () => {
37
+ try { await authApi.logout(); } catch { /* ignore */ }
38
+ localStorage.removeItem('token');
39
+ localStorage.removeItem('user');
40
+ navigate('/');
41
+ };
42
+
43
+ return { user, handleLogout };
44
+ }
@@ -0,0 +1,41 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import { createBrowserRouter , createRoutesFromElements , RouterProvider , Route } from 'react-router-dom'
5
+ import Intro from './Intro'
6
+ import Login from './Auth/Login'
7
+ import Register from './Auth/Register'
8
+ import LayOut from './LayOut'
9
+ import Home from './pages/Home'
10
+ import Employee from './pages/Employee'
11
+ import Salary from './pages/Salary'
12
+ import Department from './pages/Department'
13
+ import Reports from './pages/Reports'
14
+ import Profile from './pages/Profile'
15
+ import { ToastProvider } from './components'
16
+
17
+
18
+ const router = createBrowserRouter(
19
+ createRoutesFromElements(
20
+ <>
21
+ <Route path='/' element={<Intro />} />
22
+ <Route path='/login' element={<Login />} />
23
+ <Route path='/register' element={<Register />} />
24
+ <Route path='/dashboard' element={<LayOut />} >
25
+ <Route path='overview' element={<Home />} />
26
+ <Route path='employees' element={<Employee />} />
27
+ <Route path='salary' element={<Salary />} />
28
+ <Route path='departments' element={<Department />} />
29
+ <Route path='reports' element={<Reports />} />
30
+ <Route path='profile' element={<Profile />} />
31
+ </Route>
32
+ </>
33
+ )
34
+ )
35
+ createRoot(document.getElementById('root')).render(
36
+ <StrictMode>
37
+ <ToastProvider >
38
+ <RouterProvider router={router} />
39
+ </ToastProvider>
40
+ </StrictMode>,
41
+ )