This commit is contained in:
string 2025-06-16 09:50:35 +05:30
parent 5311701872
commit f3a1c75f26
6 changed files with 488 additions and 224 deletions

View File

@ -21,6 +21,7 @@ export const fetchAllReportsApi = async () => {
try { try {
const response = await apiService.get('/Rpt_builder2/Rpt_builder2'); // API call to fetch all reports const response = await apiService.get('/Rpt_builder2/Rpt_builder2'); // API call to fetch all reports
console.log("Fetch all reports response:", response.data); console.log("Fetch all reports response:", response.data);
return response.data; // Assuming response data comes in `data` field return response.data; // Assuming response data comes in `data` field
} catch (error) { } catch (error) {
console.error("Error while fetching all reports:", error); console.error("Error while fetching all reports:", error);

View File

@ -67,90 +67,90 @@ import SequenceGenerator from "components/Dashboard/sequencegenerator";
const App = () => { const App = () => {
return ( return (
<SystemParameterProvider> <SystemParameterProvider>
<div> <div>
{/* ToastContainer should be placed in the root component */} {/* ToastContainer should be placed in the root component */}
<ToastContainer <ToastContainer
position="top-right" position="top-right"
autoClose={1500} autoClose={1500}
hideProgressBar={false} hideProgressBar={false}
newestOnTop newestOnTop
closeOnClick closeOnClick
rtl={false} rtl={false}
pauseOnFocusLoss pauseOnFocusLoss
draggable draggable
pauseOnHover pauseOnHover
/> />
<BrowserRouter basename="/"> <BrowserRouter basename="/">
<Routes> <Routes>
<Route path="/" element={<Navigate to="/auth/login" replace />} /> <Route path="/" element={<Navigate to="/auth/login" replace />} />
<Route path="*" element={<Navigate to="/auth/login" replace />} /> <Route path="*" element={<Navigate to="/auth/login" replace />} />
{/* ptotecting the admin page */} {/* ptotecting the admin page */}
<Route path="/admin/*" element={ <Route path="/admin/*" element={
<ProtectedRoute> <ProtectedRoute>
<AdminLayout /> <AdminLayout />
</ProtectedRoute> </ProtectedRoute>
}> }>
<Route path="regform" element={<Regform />} /> {/* <Route path="regform" element={<Regform />} /> */}
<Route path="error404" element={<Error404 />} /> <Route path="error404" element={<Error404 />} />
<Route path="resetpassword" element={<ResetPassword />} /> <Route path="resetpassword" element={<ResetPassword />} />
<Route path="index" element={<Index />} /> <Route path="index" element={<Index/>}/>
<Route path="profile" element={<Profile />} /> <Route path="profile" element={<Profile />} />
<Route path="user-report" element={<UserDetailsView />} /> <Route path="user-report" element={<UserDetailsView />} />
<Route path="setting" element={<SetupView />} /> <Route path="setting" element={<SetupView />} />
<Route path="resetpassword" element={<ResetPassword />} /> <Route path="resetpassword" element={<ResetPassword />} />
{/* Dynamic Routes */} {/* Dynamic Routes */}
<Route path="datamanagement" element={<DataManagement />} /> <Route path="datamanagement" element={<DataManagement />} />
<Route path="validationrule" element={<ValidationRule />} /> <Route path="validationrule" element={<ValidationRule />} />
<Route path="mappingrule" element={<MappingRule />} /> <Route path="mappingrule" element={<MappingRule />} />
<Route path="multidynmicbugs" element={<MultiDynamicBugs />} /> <Route path="multidynmicbugs" element={<MultiDynamicBugs />} />
<Route path="about" element={<About />} /> <Route path="about" element={<About />} />
{/* Static Routes */} {/* Static Routes */}
<Route path="user-maintenance" element={<UserMaintenanceView />} /> <Route path="user-maintenance" element={<UserMaintenanceView />} />
<Route path="menu-access-control" element={<MenuAccessControl />} /> <Route path="menu-access-control" element={<MenuAccessControl />} />
<Route path="submenu/:menuItemId" element={<SubMenuMaintenance />} /> <Route path="submenu/:menuItemId" element={<SubMenuMaintenance />} />
<Route path="sequence-generator" element={<SequenceGenerator />} /> <Route path="sequence-generator" element={<SequenceGenerator />} />
<Route path="menu-access-control2" element={<MenuAccessControl2 />} /> <Route path="menu-access-control2" element={<MenuAccessControl2/>} />
<Route path="user-group-maintenance" element={<UserGroupMaintenance />} /> <Route path="user-group-maintenance" element={<UserGroupMaintenance />} />
<Route path="system-parameter" element={<SystemParameterForm />} /> <Route path="system-parameter" element={<SystemParameterForm />} />
<Route path="menu-maintenance" element={<MenuMaintenance />} /> <Route path="menu-maintenance" element={<MenuMaintenance />} />
<Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance />} /> <Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance/>} />
<Route path="access-type" element={<AccessTypeManagement />} /> <Route path="access-type" element={<AccessTypeManagement />} />
<Route path="api-registry" element={<APIRegistry />} /> <Route path="api-registry" element={<APIRegistry />} />
<Route path="token-registry" element={<TOKENRegistry />} /> <Route path="token-registry" element={<TOKENRegistry />} />
<Route path="dynamic-form-add" element={<DynamicFormAdd />} /> <Route path="dynamic-form-add" element={<DynamicFormAdd />} />
<Route path="reportbuild2all" element={<ReportBuild2All />} /> <Route path="reportbuild2all" element={<ReportBuild2All />} />
<Route path="reportbuild2add" element={<ReportBuild2Add />} /> <Route path="reportbuild2add" element={<ReportBuild2Add />} />
<Route path="reportbuild2edit" element={<ReportBuild2Edit />} /> <Route path="reportbuild2edit" element={<ReportBuild2Edit />} />
<Route path="reportquery" element={<ReportQuery />} /> <Route path="reportquery" element={<ReportQuery />} />
<Route path="report-runner" element={<ReportRunnerAll />} /> <Route path="report-runner" element={<ReportRunnerAll />} />
<Route path="report-runner1/:id" element={<ReportRunnerEdit />} /> <Route path="report-runner1/:id" element={<ReportRunnerEdit />} />
<Route path="report-runner2/:id" element={<ReportRunner2Edit />} /> <Route path="report-runner2/:id" element={<ReportRunner2Edit />} />
<Route path="dynamic-form" element={<DynamicForm />} /> <Route path="dynamic-form" element={<DynamicForm />} />
<Route path="dashboard-runner-all" element={<DashboardRunnerAll />} /> <Route path="dashboard-runner-all" element={<DashboardRunnerAll/>}/>
<Route path="dashboard-new-all" element={<DashboardNewAll />} /> <Route path="dashboard-new-all" element={<DashboardNewAll/>}/>
<Route path="dashboard-new-add" element={<DashboardNewAdd />} /> <Route path="dashboard-new-add" element={<DashboardNewAdd/>}/>
<Route path="dashboard-new-edit/:id" element={<DashboardNewEdit />} /> <Route path="dashboard-new-edit/:id" element={<DashboardNewEdit/>}/>
<Route path="edit-new-dash/:id" element={<EditNewDash />} /> <Route path="edit-new-dash/:id" element={<EditNewDash/>}/>
<Route path="dashrunner/:id" element={<DashboardRunner />} /> <Route path="dashrunner/:id" element={<DashboardRunner/>}/>
{/* <Route path="test" element={<Regform />} /> */}
{/* buildercomponents */}
</Route>
</Route> <Route path="/auth/*" element={<AuthLayout />}>
{/* buildercomponents */} <Route path="login" element={<Login />} />
<Route path="register" element={<Register />} />
<Route path="/auth/*" element={<AuthLayout />}> </Route>
<Route path="login" element={<Login />} /> </Routes>
<Route path="register" element={<Register />} /> </BrowserRouter>
</Route> </div>
</Routes>
</BrowserRouter>
</div>
</SystemParameterProvider> </SystemParameterProvider>
); );
}; };

View File

@ -1,10 +1,10 @@
// ProtectedRoute.js
import React from "react"; import React from "react";
import { Navigate } from "react-router-dom"; import { Navigate } from "react-router-dom";
import { getToken } from "utils/tokenService"; import { getToken } from "utils/tokenService";
const ProtectedRoute = ({ children }) => { const ProtectedRoute = ({ children }) => {
console.log(`token for checking whether authenticated: ${getToken()}`); const isAuthenticated = getToken() !== null;
const isAuthenticated = getToken() !== null; // Check if user is authenticated
return isAuthenticated ? children : <Navigate to="/auth/login" replace />; return isAuthenticated ? children : <Navigate to="/auth/login" replace />;
}; };

View File

@ -57,7 +57,7 @@ function AccessTypeManagement() {
useEffect(() => { useEffect(() => {
const fetchAccessTypes = async () => { const fetchAccessTypes = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}api/getAllAccessTypes`; const apiUrl = `${process.env.REACT_APP_API_URL}token/access_type/Accesstype`;
const token = localStorage.getItem("authToken"); const token = localStorage.getItem("authToken");
if (!token) { if (!token) {

View File

@ -20,31 +20,31 @@ function TOKENRegistry() {
id: "", id: "",
tokenName: "", tokenName: "",
tokenValue: "", tokenValue: "",
isActive: true isActive: true,
scopes: []
}); });
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10); const [recordsPerPage, setRecordsPerPage] = useState(10);
// Add to your state: const [visibleColumns, setVisibleColumns] = useState({
const [visibleColumns, setVisibleColumns] = useState({ id: true,
id: true, tokenName: true,
tokenName: true, tokenValue: true,
tokenValue: true, scopes: true,
scopes: true, isActive: true,
isActive: true, actions: true
actions: true });
});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [selectedScope, setSelectedScope] = useState("");
const [selectedScopes, setSelectedScopes] = useState([]); const [selectedScopes, setSelectedScopes] = useState([]);
const [availableScopes] = useState([ const [availableScopes] = useState([
{ value: 'read', label: 'Read Access' }, { value: 'read', label: 'Read Access' },
{ value: 'write', label: 'Write Access' }, { value: 'write', label: 'Write Access' },
{ value: 'delete', label: 'Delete Access' }, { value: 'delete', label: 'Delete Access' },
{ value: 'admin', label: 'Admin Access' }, { value: 'admin', label: 'Admin Access' },
]); ]);
useEffect(() => { useEffect(() => {
fetchTokens(); fetchTokens();
}, []); }, []);
@ -95,6 +95,7 @@ const [visibleColumns, setVisibleColumns] = useState({
setShowGenerateTokenModal(false); setShowGenerateTokenModal(false);
setGeneratedToken(""); setGeneratedToken("");
setNewTokenName(""); setNewTokenName("");
setSelectedScopes([]);
}; };
const handleRecordsPerPageChange = (number) => { const handleRecordsPerPageChange = (number) => {
@ -135,9 +136,10 @@ const [visibleColumns, setVisibleColumns] = useState({
} }
}; };
const openModal = (token = { id: "", tokenName: "", tokenValue: "", isActive: false }) => { const openModal = (token = { id: "", tokenName: "", tokenValue: "", isActive: false, scopes: [] }) => {
setIsEditing(!!token.id); setIsEditing(!!token.id);
setCurrentToken(token); setCurrentToken(token);
setSelectedScopes(token.scopes || []);
setShowAddEditModal(true); setShowAddEditModal(true);
}; };
@ -153,24 +155,35 @@ const [visibleColumns, setVisibleColumns] = useState({
} }
}; };
const generateNewToken = async () => { const addScope = () => {
if (!newTokenName.trim()) { if (selectedScope && !selectedScopes.includes(selectedScope)) {
toast.error("Please enter a token name"); setSelectedScopes([...selectedScopes, selectedScope]);
return; setSelectedScope("");
} }
};
try { const removeScope = (scopeToRemove) => {
const data = await tokenRegistryAPI.generateToken({ setSelectedScopes(selectedScopes.filter(scope => scope !== scopeToRemove));
name: newTokenName, };
scopes: selectedScopes
}); const generateNewToken = async () => {
setGeneratedToken(data.tokenValue); if (!newTokenName.trim()) {
toast.success("Token generated successfully!"); toast.error("Please enter a token name");
fetchTokens(); return;
} catch (error) { }
handleApiError(error, "generate token");
} try {
}; const data = await tokenRegistryAPI.generateToken({
name: newTokenName,
scopes: selectedScopes
});
setGeneratedToken(data.tokenValue);
toast.success("Token generated successfully!");
fetchTokens();
} catch (error) {
handleApiError(error, "generate token");
}
};
return ( return (
<div style={{ marginTop: "1rem" }}> <div style={{ marginTop: "1rem" }}>
@ -305,6 +318,21 @@ const [visibleColumns, setVisibleColumns] = useState({
> >
{token.isActive ? "Active" : "Inactive"} {token.isActive ? "Active" : "Inactive"}
</span> </span>
) : key === "scopes" ? (
<div>
{token.scopes && token.scopes.map(scope => {
const scopeInfo = availableScopes.find(s => s.value === scope);
return (
<span
key={scope}
className="badge bg-primary me-1 mb-1"
style={{ fontSize: '0.8rem', padding: '3px 6px' }}
>
{scopeInfo?.label || scope}
</span>
);
})}
</div>
) : ( ) : (
token[key] token[key]
)} )}
@ -383,93 +411,245 @@ const [visibleColumns, setVisibleColumns] = useState({
</PaginationItem> </PaginationItem>
</Pagination> </Pagination>
{/* Add/Edit Token Modal */} {/* Generate Token Modal */}
<Modal show={showGenerateTokenModal} onHide={handleClose}> <Modal show={showGenerateTokenModal} onHide={handleClose}>
<Modal.Header> <Modal.Header>
<Modal.Title>Generate New Token</Modal.Title> <Modal.Title>Generate New Token</Modal.Title>
<FontAwesomeIcon <FontAwesomeIcon
icon={faTimes} icon={faTimes}
size="lg" size="lg"
onClick={handleClose} onClick={handleClose}
style={{ style={{
position: "absolute", position: "absolute",
top: "25px", top: "25px",
right: "25px", right: "25px",
cursor: "pointer", cursor: "pointer",
}} }}
/> />
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<Form> <Form>
<Form.Group controlId="formNewTokenName" className="mb-3"> <Form.Group controlId="formNewTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label> <Form.Label>Token Name</Form.Label>
<Form.Control <Form.Control
type="text" type="text"
value={newTokenName} value={newTokenName}
onChange={(e) => setNewTokenName(e.target.value)} onChange={(e) => setNewTokenName(e.target.value)}
required required
className="custom-hover-border" className="custom-hover-border"
placeholder="Enter a name for the new token" placeholder="Enter a name for the new token"
/> />
</Form.Group> </Form.Group>
<Form.Group controlId="formTokenScopes" className="mb-3"> <Form.Group controlId="formTokenScopes" className="mb-3">
<Form.Label>Token Scopes</Form.Label> <Form.Label>Token Scopes</Form.Label>
<Form.Select <div className="d-flex">
multiple <Form.Select
value={selectedScopes} value={selectedScope}
onChange={(e) => { onChange={(e) => setSelectedScope(e.target.value)}
const options = [...e.target.options]; className="custom-hover-border me-2"
const selectedValues = options >
.filter(option => option.selected) <option value="">Select a scope</option>
.map(option => option.value); {availableScopes.map(scope => (
setSelectedScopes(selectedValues); <option key={scope.value} value={scope.value}>
}} {scope.label}
className="custom-hover-border" </option>
style={{ height: 'auto' }} ))}
> </Form.Select>
{availableScopes.map(scope => ( <Button
<option key={scope.value} value={scope.value}> variant="outline-primary"
{scope.label} onClick={addScope}
</option> disabled={!selectedScope}
))} >
</Form.Select> Add Scope
<Form.Text className="text-muted"> </Button>
Select the permissions this token should have (hold Ctrl/Cmd to select multiple) </div>
</Form.Text> <Form.Text className="text-muted">
</Form.Group> Select and add the permissions this token should have
</Form.Text>
{generatedToken && ( {/* Display selected scopes as chips */}
<Form.Group controlId="formGeneratedToken" className="mb-3"> {selectedScopes.length > 0 && (
<Form.Label>Generated Token</Form.Label> <div className="mt-2">
<Form.Control {selectedScopes.map(scope => {
as="textarea" const scopeInfo = availableScopes.find(s => s.value === scope);
rows={3} return (
value={generatedToken} <span
readOnly key={scope}
className="custom-hover-border" className="badge bg-primary me-2 mb-2"
/> style={{ fontSize: '0.9rem', padding: '5px 10px' }}
<Form.Text className="text-muted"> >
Copy this token and store it securely. You won't be able to see it again. {scopeInfo?.label || scope}
</Form.Text> <FontAwesomeIcon
</Form.Group> icon={faTimes}
)} className="ms-2"
style={{ cursor: 'pointer' }}
onClick={() => removeScope(scope)}
/>
</span>
);
})}
</div>
)}
</Form.Group>
<Modal.Footer> {generatedToken && (
<Button variant="secondary" onClick={handleClose}> <Form.Group controlId="formGeneratedToken" className="mb-3">
Close <Form.Label>Generated Token</Form.Label>
</Button> <Form.Control
<Button as="textarea"
variant="primary" rows={3}
onClick={generateNewToken} value={generatedToken}
disabled={!newTokenName.trim()} readOnly
> className="custom-hover-border"
Generate Token />
</Button> <Form.Text className="text-muted">
</Modal.Footer> Copy this token and store it securely. You won't be able to see it again.
</Form> </Form.Text>
</Modal.Body> </Form.Group>
</Modal> )}
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button
variant="primary"
onClick={generateNewToken}
disabled={!newTokenName.trim()}
>
Generate Token
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
{/* Add/Edit Token Modal */}
<Modal show={showAddEditModal} onHide={handleClose}>
<Modal.Header>
<Modal.Title>{isEditing ? "Edit Token" : "Add Token"}</Modal.Title>
<FontAwesomeIcon
icon={faTimes}
size="lg"
onClick={handleClose}
style={{
position: "absolute",
top: "25px",
right: "25px",
cursor: "pointer",
}}
/>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group controlId="formTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label>
<Form.Control
type="text"
name="tokenName"
value={currentToken.tokenName}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formTokenValue" className="mb-3">
<Form.Label>Token Value</Form.Label>
<Form.Control
type="text"
name="tokenValue"
value={currentToken.tokenValue}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formTokenScopes" className="mb-3">
<Form.Label>Token Scopes</Form.Label>
<div className="d-flex">
<Form.Select
value={selectedScope}
onChange={(e) => setSelectedScope(e.target.value)}
className="custom-hover-border me-2"
>
<option value="">Select a scope</option>
{availableScopes.map(scope => (
<option key={scope.value} value={scope.value}>
{scope.label}
</option>
))}
</Form.Select>
<Button
variant="outline-primary"
onClick={() => {
if (selectedScope && !currentToken.scopes.includes(selectedScope)) {
setCurrentToken(prev => ({
...prev,
scopes: [...prev.scopes, selectedScope]
}));
setSelectedScope("");
}
}}
disabled={!selectedScope}
>
Add Scope
</Button>
</div>
<Form.Text className="text-muted">
Select and add the permissions this token should have
</Form.Text>
{/* Display selected scopes as chips */}
{currentToken.scopes && currentToken.scopes.length > 0 && (
<div className="mt-2">
{currentToken.scopes.map(scope => {
const scopeInfo = availableScopes.find(s => s.value === scope);
return (
<span
key={scope}
className="badge bg-primary me-2 mb-2"
style={{ fontSize: '0.9rem', padding: '5px 10px' }}
>
{scopeInfo?.label || scope}
<FontAwesomeIcon
icon={faTimes}
className="ms-2"
style={{ cursor: 'pointer' }}
onClick={() => {
setCurrentToken(prev => ({
...prev,
scopes: prev.scopes.filter(s => s !== scope)
}));
}}
/>
</span>
);
})}
</div>
)}
</Form.Group>
<Form.Group controlId="formActive" className="mb-3">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentToken.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" type="submit">
{isEditing ? "Update Token" : "Add Token"}
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div> </div>
)} )}
</div> </div>

View File

@ -1,4 +1,4 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
@ -7,20 +7,86 @@ import {
MenuItem, MenuItem,
SubMenu, SubMenu,
} from "react-pro-sidebar"; } from "react-pro-sidebar";
import { FaChevronLeft, FaChevronRight, FaDatabase, FaExclamationCircle } from "react-icons/fa"; import { FaChevronLeft, FaChevronRight, FaDatabase, FaExclamationCircle, FaCircle } from "react-icons/fa";
import { fetchMenuItems, getSubmenuItems } from "../../APIServices/MenuMaintenanceAPI";
import "../Sidebar/Sidebar.css"; import "../Sidebar/Sidebar.css";
const Sidebar = (props) => { const Sidebar = (props) => {
const [collapsed, setCollapsed] = useState(true); const [collapsed, setCollapsed] = useState(true);
const [menuItems, setMenuItems] = useState([]);
const [subMenuItems, setSubMenuItems] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
const loadMenuData = async () => {
try {
const mainMenuItems = await fetchMenuItems();
setMenuItems(mainMenuItems);
const subMenuPromises = mainMenuItems.map(item =>
getSubmenuItems(item.menuItemId)
.then(subItems => subItems || [])
.catch(() => [])
);
const subMenus = await Promise.all(subMenuPromises);
const subMenuMap = {};
mainMenuItems.forEach((item, index) => {
subMenuMap[item.menuItemId] = subMenus[index];
});
setSubMenuItems(subMenuMap);
} catch (err) {
console.error("Failed to load menu data:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
loadMenuData();
}, []);
const toggleSidebar = () => { const toggleSidebar = () => {
setCollapsed(!collapsed); setCollapsed(!collapsed);
if (props.onSidebarToggle) { props.onSidebarToggle?.(!collapsed);
props.onSidebarToggle(!collapsed); };
const validatePath = (path) => {
if (!path || path === "#" || path === "null" || path === "undefined") {
return false;
}
return true;
};
const safeNavigate = (path) => {
if (!validatePath(path)) {
navigate("/admin/error404");
return;
}
// Ensure path starts with /admin/
const adminPath = path.startsWith("/admin/") ? path : `/admin/${path.replace(/^\//, '')}`;
try {
navigate(adminPath);
} catch (error) {
console.error(`Navigation failed:`, error);
navigate("/admin/error404");
} }
}; };
const getIconComponent = (iconName) => {
switch (iconName) {
case "fa-database": return <FaDatabase />;
case "fa-exclamation-circle": return <FaExclamationCircle />;
default: return <FaCircle />;
}
};
if (loading) return <div className="sidebar-wrapper">Loading...</div>;
if (error) return <div className="sidebar-wrapper">Error: {error}</div>;
return ( return (
<div className="sidebar-wrapper"> <div className="sidebar-wrapper">
<ProSidebar <ProSidebar
@ -41,21 +107,38 @@ const Sidebar = (props) => {
</div> </div>
<Menu> <Menu>
<SubMenu label="Transactions" icon={<FaExclamationCircle />}> {menuItems.map((menuItem) => {
<MenuItem onClick={() => navigate("/admin/regform")}> const subItems = subMenuItems[menuItem.menuItemId] || [];
Regform
</MenuItem>
<MenuItem onClick={() => navigate("/admin/error404")}>
Additional container
</MenuItem>
</SubMenu>
<MenuItem if (subItems.length > 0) {
icon={<FaDatabase />} return (
onClick={() => navigate("/admin/error404")} <SubMenu
> key={menuItem.menuItemId}
Masters label={menuItem.menuItemDesc}
</MenuItem> icon={getIconComponent(menuItem.main_menu_icon_name)}
>
{subItems.map((subItem) => (
<MenuItem
key={subItem.menuItemId}
onClick={() => safeNavigate(subItem.main_menu_action_name)}
>
{subItem.menuItemDesc}
</MenuItem>
))}
</SubMenu>
);
}
return (
<MenuItem
key={menuItem.menuItemId}
icon={getIconComponent(menuItem.main_menu_icon_name)}
onClick={() => safeNavigate(menuItem.main_menu_action_name)}
>
{menuItem.menuItemDesc}
</MenuItem>
);
})}
</Menu> </Menu>
</ProSidebar> </ProSidebar>
</div> </div>