add iam module usermanagment ui

This commit is contained in:
mengstabketemaw
2026-06-02 16:06:51 +03:00
parent df745bbc41
commit 798beb0e7a
12 changed files with 6061 additions and 62 deletions

View File

@@ -1,7 +1,17 @@
import { useEffect } from 'react';
import { configureIam } from '@tria-plc/iamui-common';
import { AppProviders } from './providers/AppProviders';
import { AppRouter } from './router';
const BASE_API_URL =
(import.meta as { env?: Record<string, string> }).env?.['VITE_BASE_API_URL'] ??
'http://localhost:3001/api';
export function App() {
useEffect(() => {
configureIam({ apiUrl: BASE_API_URL });
}, []);
return (
<AppProviders>
<AppRouter />

View File

@@ -6,13 +6,32 @@ const KEYS = {
user: 'ema-backoffice-auth-user',
} as const;
const COOKIE_ATTRS = 'path=/;max-age=86400';
function setCookie(name: string, value: string) {
document.cookie = `${name}=${encodeURIComponent(value)};${COOKIE_ATTRS}`;
}
function removeCookie(name: string) {
document.cookie = `${name}=;path=/;max-age=0`;
}
export const authStorage = {
getToken: () => localStorage.getItem(KEYS.token) ?? undefined,
setToken: (token: string) => localStorage.setItem(KEYS.token, token),
removeToken: () => localStorage.removeItem(KEYS.token),
setToken: (token: string) => {
localStorage.setItem(KEYS.token, token);
setCookie('auth-token', token);
},
removeToken: () => {
localStorage.removeItem(KEYS.token);
removeCookie('auth-token');
},
getRefreshToken: () => localStorage.getItem(KEYS.refreshToken) ?? undefined,
setRefreshToken: (token: string) => localStorage.setItem(KEYS.refreshToken, token),
setRefreshToken: (token: string) => {
localStorage.setItem(KEYS.refreshToken, token);
setCookie('refresh-token', token);
},
getUser: (): AuthUser | null => {
const raw = localStorage.getItem(KEYS.user);
@@ -24,5 +43,9 @@ export const authStorage = {
},
setUser: (user: AuthUser) => localStorage.setItem(KEYS.user, JSON.stringify(user)),
clear: () => Object.values(KEYS).forEach((k) => localStorage.removeItem(k)),
clear: () => {
Object.values(KEYS).forEach((k) => localStorage.removeItem(k));
removeCookie('auth-token');
removeCookie('refresh-token');
},
};

View File

@@ -0,0 +1,31 @@
import type { ReactNode } from 'react';
import {
AuthProvider,
PermissionProvider,
BrandingProvider,
BreadcrumbProvider,
UnitProvider,
UserProvider,
} from '@tria-plc/iamui-common';
interface IamProvidersProps {
children: ReactNode;
}
export function IamProviders({ children }: IamProvidersProps) {
return (
<AuthProvider>
<BrandingProvider>
<BreadcrumbProvider>
<PermissionProvider>
<UnitProvider>
<UserProvider>
{children}
</UserProvider>
</UnitProvider>
</PermissionProvider>
</BreadcrumbProvider>
</BrandingProvider>
</AuthProvider>
);
}

View File

@@ -0,0 +1,14 @@
import { AuditLogPage } from '@tria-plc/iamui-common';
import { IamProviders } from '../IamProviders';
export function AuditLogPageWrapper() {
return (
<IamProviders>
<AuditLogPage
moduleKey="backoffice"
title="Audit Log"
subtitle="Track all activities and changes in the backoffice"
/>
</IamProviders>
);
}

View File

@@ -1,10 +1,17 @@
import { NavLink, Stack } from '@mantine/core';
import { IconDashboard, IconBox } from '@tabler/icons-react';
import {
IconDashboard,
IconBox,
IconUsers,
IconClipboardList,
} from '@tabler/icons-react';
import { useNavigate, useLocation } from 'react-router-dom';
const NAV_ITEMS = [
{ label: 'Dashboard', icon: IconDashboard, path: '/dashboard' },
{ label: 'Items', icon: IconBox, path: '/items' },
{ label: 'User Management', icon: IconUsers, path: '/users' },
{ label: 'Audit Log', icon: IconClipboardList, path: '/audit-log' },
];
export function AppSidebar() {

View File

@@ -1,4 +1,13 @@
import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom';
import {
UserManagementLayout,
UserManagementPage,
BulkUploadPage,
ArchivedUsersPage,
PositionManagementPage,
CreatePositionPage,
EditPositionPage,
} from '@tria-plc/iamui-common';
import { ProtectedRoute } from './ProtectedRoute';
import { BackofficeLayout } from '../layouts/BackofficeLayout';
import { AuthLayout } from '../layouts/AuthLayout';
@@ -7,6 +16,8 @@ import { SignupPage } from '../features/auth/pages/SignupPage';
import { SetPasswordPage } from '../features/auth/pages/SetPasswordPage';
import { DashboardPage } from '../features/dashboard/pages/DashboardPage';
import { ItemPage } from '../features/item/pages/ItemPage';
import { AuditLogPageWrapper } from '../iam/pages/AuditLogPage';
import { IamProviders } from '../iam/IamProviders';
const router = createBrowserRouter([
{
@@ -18,6 +29,23 @@ const router = createBrowserRouter([
{ path: '/', element: <Navigate to="/dashboard" replace /> },
{ path: '/dashboard', element: <DashboardPage /> },
{ path: '/items', element: <ItemPage /> },
{
path: '/users',
element: (
<IamProviders>
<UserManagementLayout />
</IamProviders>
),
children: [
{ index: true, element: <UserManagementPage /> },
{ path: 'bulk-upload', element: <BulkUploadPage /> },
{ path: 'archived', element: <ArchivedUsersPage /> },
{ path: 'position-management', element: <PositionManagementPage /> },
{ path: 'position-management/new', element: <CreatePositionPage /> },
{ path: 'position-management/edit/:id', element: <EditPositionPage /> },
],
},
{ path: '/audit-log', element: <AuditLogPageWrapper /> },
],
},
],

View File

@@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client';
import '@mantine/core/styles.css';
import '@mantine/notifications/styles.css';
import '@mantine/dates/styles.css';
import '@tria-plc/iamui-common/styles.css';
import './styles.css';
import { App } from './app/app';

View File

@@ -1,10 +1,17 @@
import { AppProviders } from './providers/AppProviders';
// src/main.tsx or App.tsx
import { AppProviders, configureIam } from "@tria-plc/iamui-common";
import "@tria-plc/iamui-common/styles.css";
// import { AppProviders } from './providers/AppProviders';
import { AppRouter } from './router';
configureIam({ apiUrl: 'http://localhost:3001/api'});
// import './styles.css';
export function App() {
return (
// 2. Wrap with Providers so hooks like useAuthUser() work
<AppProviders>
<AppRouter />
</AppProviders>
);
}

View File

@@ -1,4 +1,4 @@
import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom';
import { createBrowserRouter, RouterProvider, Navigate, Route, Routes } from 'react-router-dom';
import type { ReactNode } from 'react';
import { PortalLayout } from './layouts/PortalLayout';
import { LoginPage } from './features/auth/pages/LoginPage';
@@ -6,6 +6,8 @@ import { SignupPage } from './features/auth/pages/SignupPage';
import { SetPasswordPage } from './features/auth/pages/SetPasswordPage';
import { DashboardPage } from './features/dashboard/pages/DashboardPage';
import { UserManagementPage, UserManagementLayout, Login} from "@tria-plc/iamui-common";
function getToken(): string | null {
return localStorage.getItem('ema-portal-auth-token');
}
@@ -16,6 +18,12 @@ function ProtectedRoute({ children }: { children: ReactNode }) {
}
const router = createBrowserRouter([
{
element: <UserManagementLayout />,
children: [
{path: '/user', element: <UserManagementPage />}
]
},
{ path: '/login', element: <LoginPage /> },
{ path: '/signup', element: <SignupPage /> },
{ path: '/set-password', element: <SetPasswordPage /> },
@@ -37,5 +45,12 @@ const router = createBrowserRouter([
]);
export function AppRouter() {
return <RouterProvider router={router} />;
return (
<Routes>
<Route path='/login' element={<Login/>}/>
<Route element={<UserManagementLayout />}>
<Route path="/users" element={<UserManagementPage />} />
</Route>
</Routes>
);
}

View File

@@ -2,7 +2,9 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import '@mantine/core/styles.css';
import '@mantine/notifications/styles.css';
import './styles.css';
import "@tria-plc/iamui-common/styles.css";
import { configureIam } from "@tria-plc/iamui-common";
import { App } from './app/app';
const root = document.getElementById('root');