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 {
const response = await apiService.get('/Rpt_builder2/Rpt_builder2'); // API call to fetch all reports
console.log("Fetch all reports response:", response.data);
return response.data; // Assuming response data comes in `data` field
} catch (error) {
console.error("Error while fetching all reports:", error);

View File

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

View File

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

View File

@ -57,7 +57,7 @@ function AccessTypeManagement() {
useEffect(() => {
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");
if (!token) {

View File

@ -20,31 +20,31 @@ function TOKENRegistry() {
id: "",
tokenName: "",
tokenValue: "",
isActive: true
isActive: true,
scopes: []
});
const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
// Add to your state:
const [visibleColumns, setVisibleColumns] = useState({
id: true,
tokenName: true,
tokenValue: true,
scopes: true,
isActive: true,
actions: true
});
const [visibleColumns, setVisibleColumns] = useState({
id: true,
tokenName: true,
tokenValue: true,
scopes: true,
isActive: true,
actions: true
});
const [loading, setLoading] = useState(true);
const [selectedScope, setSelectedScope] = useState("");
const [selectedScopes, setSelectedScopes] = useState([]);
const [availableScopes] = useState([
{ value: 'read', label: 'Read Access' },
{ value: 'write', label: 'Write Access' },
{ value: 'delete', label: 'Delete Access' },
{ value: 'admin', label: 'Admin Access' },
const [availableScopes] = useState([
{ value: 'read', label: 'Read Access' },
{ value: 'write', label: 'Write Access' },
{ value: 'delete', label: 'Delete Access' },
{ value: 'admin', label: 'Admin Access' },
]);
useEffect(() => {
fetchTokens();
}, []);
@ -95,6 +95,7 @@ const [visibleColumns, setVisibleColumns] = useState({
setShowGenerateTokenModal(false);
setGeneratedToken("");
setNewTokenName("");
setSelectedScopes([]);
};
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);
setCurrentToken(token);
setSelectedScopes(token.scopes || []);
setShowAddEditModal(true);
};
@ -153,24 +155,35 @@ const [visibleColumns, setVisibleColumns] = useState({
}
};
const generateNewToken = async () => {
if (!newTokenName.trim()) {
toast.error("Please enter a token name");
return;
}
const addScope = () => {
if (selectedScope && !selectedScopes.includes(selectedScope)) {
setSelectedScopes([...selectedScopes, selectedScope]);
setSelectedScope("");
}
};
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");
}
};
const removeScope = (scopeToRemove) => {
setSelectedScopes(selectedScopes.filter(scope => scope !== scopeToRemove));
};
const generateNewToken = async () => {
if (!newTokenName.trim()) {
toast.error("Please enter a token name");
return;
}
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 (
<div style={{ marginTop: "1rem" }}>
@ -305,6 +318,21 @@ const [visibleColumns, setVisibleColumns] = useState({
>
{token.isActive ? "Active" : "Inactive"}
</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]
)}
@ -383,93 +411,245 @@ const [visibleColumns, setVisibleColumns] = useState({
</PaginationItem>
</Pagination>
{/* Add/Edit Token Modal */}
{/* Generate Token Modal */}
<Modal show={showGenerateTokenModal} onHide={handleClose}>
<Modal.Header>
<Modal.Title>Generate New Token</Modal.Title>
<FontAwesomeIcon
icon={faTimes}
size="lg"
onClick={handleClose}
style={{
position: "absolute",
top: "25px",
right: "25px",
cursor: "pointer",
}}
/>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formNewTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label>
<Form.Control
type="text"
value={newTokenName}
onChange={(e) => setNewTokenName(e.target.value)}
required
className="custom-hover-border"
placeholder="Enter a name for the new token"
/>
</Form.Group>
<Modal.Header>
<Modal.Title>Generate New Token</Modal.Title>
<FontAwesomeIcon
icon={faTimes}
size="lg"
onClick={handleClose}
style={{
position: "absolute",
top: "25px",
right: "25px",
cursor: "pointer",
}}
/>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formNewTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label>
<Form.Control
type="text"
value={newTokenName}
onChange={(e) => setNewTokenName(e.target.value)}
required
className="custom-hover-border"
placeholder="Enter a name for the new token"
/>
</Form.Group>
<Form.Group controlId="formTokenScopes" className="mb-3">
<Form.Label>Token Scopes</Form.Label>
<Form.Select
multiple
value={selectedScopes}
onChange={(e) => {
const options = [...e.target.options];
const selectedValues = options
.filter(option => option.selected)
.map(option => option.value);
setSelectedScopes(selectedValues);
}}
className="custom-hover-border"
style={{ height: 'auto' }}
>
{availableScopes.map(scope => (
<option key={scope.value} value={scope.value}>
{scope.label}
</option>
))}
</Form.Select>
<Form.Text className="text-muted">
Select the permissions this token should have (hold Ctrl/Cmd to select multiple)
</Form.Text>
</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={addScope}
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 */}
{selectedScopes.length > 0 && (
<div className="mt-2">
{selectedScopes.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={() => removeScope(scope)}
/>
</span>
);
})}
</div>
)}
</Form.Group>
{generatedToken && (
<Form.Group controlId="formGeneratedToken" className="mb-3">
<Form.Label>Generated Token</Form.Label>
<Form.Control
as="textarea"
rows={3}
value={generatedToken}
readOnly
className="custom-hover-border"
/>
<Form.Text className="text-muted">
Copy this token and store it securely. You won't be able to see it again.
</Form.Text>
</Form.Group>
)}
<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>
{generatedToken && (
<Form.Group controlId="formGeneratedToken" className="mb-3">
<Form.Label>Generated Token</Form.Label>
<Form.Control
as="textarea"
rows={3}
value={generatedToken}
readOnly
className="custom-hover-border"
/>
<Form.Text className="text-muted">
Copy this token and store it securely. You won't be able to see it again.
</Form.Text>
</Form.Group>
)}
<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>

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
import {
@ -7,20 +7,86 @@ import {
MenuItem,
SubMenu,
} 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";
const Sidebar = (props) => {
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();
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 = () => {
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 (
<div className="sidebar-wrapper">
<ProSidebar
@ -41,21 +107,38 @@ const Sidebar = (props) => {
</div>
<Menu>
<SubMenu label="Transactions" icon={<FaExclamationCircle />}>
<MenuItem onClick={() => navigate("/admin/regform")}>
Regform
</MenuItem>
<MenuItem onClick={() => navigate("/admin/error404")}>
Additional container
</MenuItem>
</SubMenu>
<MenuItem
icon={<FaDatabase />}
onClick={() => navigate("/admin/error404")}
>
Masters
</MenuItem>
{menuItems.map((menuItem) => {
const subItems = subMenuItems[menuItem.menuItemId] || [];
if (subItems.length > 0) {
return (
<SubMenu
key={menuItem.menuItemId}
label={menuItem.menuItemDesc}
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>
</ProSidebar>
</div>
@ -71,4 +154,4 @@ Sidebar.propTypes = {
onSidebarToggle: PropTypes.func,
};
export default Sidebar;
export default Sidebar;