Files
authsec_reactbootstrapnew/src/components/Dashboard/MenuAccessControl.js

724 lines
21 KiB
JavaScript
Raw Normal View History

2025-04-01 20:28:04 +05:30
import React, { useState, useEffect } from "react";
import { Button, Dropdown, Modal, Form,Row,Col,InputGroup,
FormControl,
} from "react-bootstrap";
import { Table ,Pagination,
PaginationItem,
PaginationLink,Input,Label} from 'reactstrap';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit, faTrashAlt, faPlus, faBars,
faTimes } from "@fortawesome/free-solid-svg-icons";
import "bootstrap/dist/css/bootstrap.min.css";
import "../Dashboard/CSS/CSS/CommonStyle.css";
import { FaSearch, FaTimes } from "react-icons/fa";
import { BsJournals } from "react-icons/bs";
import Spinner from '../../UIComponants/Spinner';
import { getByUsrGrpId } from "APIServices/MenuAccessControlAPI";
import { toast } from "react-toastify";
function MenuAccessControl({ selected,Sync}) {
const [loading, setLoading] = useState(true);
const [menuItems, setMenuItems] = useState([]);
const [menus,setMenus] = useState([]);
const [showAddEditModal, setShowAddEditModal] = useState(false);
const [selectedMenuId, setSelectedMenuId] = useState(null);
const [usrgrp, setUsrgrp] = useState('DefaultGroup');
const [allData, setAllData] = useState([]);
const [currentMenuItem, setCurrentMenuItem] = useState({
menuId: "",
menuItemName: "",
accessLevel: "",
isActive: false,
view: false, // For View checkbox
create: false, // For Create checkbox
edit: false, // For Edit checkbox
delete: false, // For Delete checkbox
query: false, // For Query checkbox
export: false, // For Export checkbox
});
const [alldata, setAlldata] = useState([]);
// const [slicedMenus, setSlicedMenus] = useState([]);
const [toggle, setToggle] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [searchQuery, setSearchQuery] = useState("");
let [slicedMenus, setSlicedMenus] = useState([
{
menuId: 1,
view: false,
create: false,
edit: false,
delete: false,
query: false,
export: false,
isActive: true,
},
{
menuId: 2,
view: false,
create: false,
edit: false,
delete: false,
query: false,
export: false,
isActive: false,
},
]);
const [visibleColumns, setVisibleColumns] = useState({
No:true,
menuId: true,
menuItemName: true,
view:true,
create:true,
edit:true,
delete:true,
query:true,
export:true,
isActive: true,
actions: true
});
const [newItemData, setNewItemData] = useState({
menuId: "",
menuItemName: "",
view:"",
create:"",
edit:"",
delete:"",
query:"",
export:"",
isActive: true,
});
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
// Simulate fetching or setting a default value
// const defaultGroup = 'Admin'; // Replace with fetched or derived value
setUsrgrp();
}, []);
useEffect(() => {
const apiUrl = `${process.env.REACT_APP_API_URL}/api/getAllMenuItems`;
const token = localStorage.getItem("authToken");
const fetchMenuItems = async () => {
try {
const response = await fetch(apiUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setMenuItems(data);
} catch (error) {
console.error("Error fetching menu items:", error);
}
};
fetchMenuItems();
}, []);
useEffect(() => {
fetchData();
}, []);
// const fetchData = async () => {
// try {
// const data = await getByUsrGrpId(usrgrp);
// console.log("Data fetched successfully:", data);
// setAlldata(data); // Update the state with fetched data
// toast.success("Data fetched successfully!");
// } catch (error) {
// console.error('Error fetching data:', error);
// toast.error("Failed to fetch data.");
// }
// };
// const fetchData = async () => {
// try {
// console.log("Fetching data for usrgrp:", usrgrp);
// const data = await getByUsrGrpId(usrgrp);
// if (!data) {
// console.error("Received undefined data");
// toast.error("Failed to fetch data.");
// return;
// }
// console.log("Data fetched successfully:", data);
// setAlldata(data);
// toast.success("Data fetched successfully!");
// } catch (error) {
// console.error("Error fetching data:", error);
// toast.error("Failed to fetch data.");
// }
// };
const fetchData = async () => {
try {
console.log("Fetching data for usrgrp:", usrgrp);
const data = await getByUsrGrpId(usrgrp);
if (!data) {
console.error("Received undefined data");
toast.error("Failed to fetch data.");
return;
}
console.log("Data fetched successfully:", data);
setAlldata(data);
toast.success("Data fetched successfully!");
} catch (error) {
console.error("Error fetching data:", error.message || error);
toast.error("Failed to fetch data.");
}
};
const idselected = (value) => {
setSelectedMenuId(value);
};
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const handleInputChange = (event,menuId) => {
const { name, value, checked, type } = event.target;
setCurrentMenuItem(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
setSlicedMenus((prevMenus) =>
prevMenus.map((menu) =>
menu.menuId === currentMenuItem.menuId // Identify the correct menu item
? { ...menu, [name]: value } // Update the specific field
: menu
)
);
};
const handleSearch = (query) => {
setSearchQuery(query);
};
const handleAddItem = () => {
setIsEditing(false);
setNewItemData({
menuId: "",
menuItemName: "",
isActive: true,
});
setShowAddEditModal(true)
};
const handleClose = () => {
setShowAddEditModal(false); // Close the modal by setting the state to false
};
const handleSubmit = (event) => {
event.preventDefault();
if (isEditing) {
setMenuItems(menuItems.map(item =>
item.menuId === currentMenuItem.menuId ? currentMenuItem : item
));
} else {
const newMenuId = `ID${menuItems.length + 1}`;
setMenuItems([...menuItems, { ...currentMenuItem, menuId: newMenuId }]);
}
setShowAddEditModal(false);
};
const openModal = (item = { menuId: "", menuName: "", accessLevel: "", isActive: false }) => {
setIsEditing(!!item.menuId);
setCurrentMenuItem(item);
setShowAddEditModal(true);
};
const handleDelete = (menuId) => {
setMenuItems(menuItems.filter(item => item.menuId !== menuId));
};
const handleRecordsPerPageChange=(number) =>{
setRecordsPerPage(number);
setCurrentPage(1);
}
const totalPages = Math.ceil(menuItems.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const handleSelectChange = (value) => {
console.log(value);
setUsrgrp(value);
};
const handleToggleCheckbox = () => {
setToggle(!toggle);
};
slicedMenus = menuItems
.filter((item) =>
item.menuName && item.menuName.toLowerCase().includes(searchQuery.toLowerCase())
)
.slice((currentPage - 1) * recordsPerPage, currentPage * recordsPerPage);
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div className="container-fluid mt-5">
<div
className="d-flex justify-content-between align-items-center mb-4"
style={{ gap: "15px" }}
>
{/* Left Side */}
<div className="d-flex align-items-center" style={{ gap: "15px" }}>
<h1 className="title_main mb-0">Menu Access Control</h1>
<span
className="badge bg-info text-white"
style={{ fontSize: "14px", padding: "5px 10px", lineHeight: "1" }}
>
Edit Mode
</span>
</div>
{/* Right Side */}
<div className="d-flex align-items-center" style={{ gap: "15px" }}>
<span>For</span>
<select
className="form-select"
style={{ width: "150px", height: "40px" }}
onChange={(e) => handleSelectChange(e.target.value)}
>
{alldata.map((sub) => (
<option
key={sub.usrGrp}
value={sub.usrGrp}
selected={sub.usrGrp === 40}
>
{sub.groupName}
</option>
))}
</select>
<Button
variant="primary"
className="ml-3"
style={{ height: "40px", lineHeight: "1.2" }}
onClick={() => fetchData()}
>
Reload
</Button>
<span style={{ fontWeight: "500" }}>
{toggle ? "Only Main Menu" : "Show All"}
</span>
<div className="form-check form-switch">
<input
className="form-check-input"
type="checkbox"
id="toggleSwitch"
checked={toggle}
onChange={handleToggleCheckbox}
/>
<label className="form-check-label" htmlFor="toggleSwitch">
Toggle
</label>
</div>
</div>
</div>
<Row className="align-items-center my-3">
{/* Left: Search Bar */}
<Col
xs={12}
md={8}
lg={6}
className="d-flex justify-content-center my-3"
>
<InputGroup
className="search-bar"
style={{
borderRadius: "10px",
overflow: "hidden",
boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)",
width: "100%",
maxWidth: "528px", // Set max-width to limit overall width
paddingRight: "-15px", // Increase padding on the right side
}}
>
<InputGroup.Text
style={{
backgroundColor: "#0E6591",
color: "#fff",
padding: "10px 15px",
}}
>
<FaSearch />
</InputGroup.Text>
<FormControl
placeholder="Search"
value={searchQuery}
onChange={(e) => handleSearch(e.target.value)}
style={{
padding: "10px",
border: "none",
paddingRight: "5px", // More space on the right side of input field
}}
/>
</InputGroup>
</Col>
{/*Add Icons */}
<Col xs={12} md={4} lg={6} className="d-flex justify-content-end">
<>
{/* Add Icon */}
<FontAwesomeIcon
icon={faPlus}
onClick={() => handleAddItem(true)}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
marginRight: "20px",
}}
/>
<FontAwesomeIcon
icon={faBars}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
}}
/>
</>
</Col>
</Row>
<div className="table-responsive">
<Table striped responsive hover align="middle" className=" table-flush shadow-sm">
<thead className="custom_header">
<tr>
{Object.entries(visibleColumns).map(([key, visible]) =>
visible ? <th key={key}>{key.charAt(0).toUpperCase() + key.slice(1)}</th> : null
)}
</tr>
</thead>
<tbody className="tbody">
{slicedMenus.length === 0 ? (
<tr>
<td
colSpan={
Object.keys(visibleColumns).filter((key) => visibleColumns[key])
.length
}
className="text-center"
>
No items found. Please add new items.
</td>
</tr>
) : (
slicedMenus.map((item, index) => (
<tr key={index}>
{Object.entries(visibleColumns).map(([key, visible]) =>
visible ? (
<td key={key}>
{key === "actions" ? (
<>
<FontAwesomeIcon
icon={faEdit}
onClick={() => openModal(item)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green",
marginRight: "15px",
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => handleDelete(item.menuId)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545",
}}
/>
</>
) :["view", "create", "edit", "delete", "query", "export"].includes(key) ? (
<Input
type="checkbox"
checked={item[key]}
// onChange={(e) =>
// handleInputChange({
// target: {
// name: key,
// value: e.target.checked,
// },
// })
onChange={(e) => handleInputChange(e, item.menuId)}
disabled={false}
/>
): key === "isActive" ? (
<span
className="status"
style={{
color: item.isActive ? "green" : "red",
backgroundColor: item.isActive
? "#d4f7d4"
: "#f7d4d4",
padding: "4px 8px",
borderRadius: "4px",
display: "inline-block",
}}
>
{item.isActive ? "Active" : "Inactive"}
</span>
) : (
item[key]
)}
</td>
) : null
)}
</tr>
))
)}
</tbody>
</Table>
</div>
{/* Manage Columns & Records Per Page */}
<Row className="mt-4">
<Col md={6} className="d-flex justify-content-start">
<Dropdown>
<Dropdown.Toggle
variant="outline-primary"
className="custom_manage_column_button"
>
Manage Columns
</Dropdown.Toggle>
<Dropdown.Menu>
{Object.keys(visibleColumns).map((column) => (
<Dropdown.Item
key={column}
onClick={() => toggleColumn(column)}
>
<Form.Check
type="checkbox"
label={
column.charAt(0).toUpperCase() +
column.slice(1).toLowerCase()
}
checked={visibleColumns[column]}
readOnly
className="custom-checkbox"
/>
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</Col>
<Col md={6} className="d-flex justify-content-end">
<Dropdown>
<Dropdown.Toggle
variant="outline-primary"
className="custom_manage_column_button px-4 py-2 border-2 rounded-3 shadow-sm"
id="dropdown-custom-components"
>
<BsJournals />
</Dropdown.Toggle>
<Dropdown.Menu className="border-0 rounded-3 shadow-lg" align="end">
{[1, 5, 10, 20, 50].map((number) => (
<Dropdown.Item
key={number}
onClick={() => handleRecordsPerPageChange(number)}
className="text-dark d-flex justify-content-between align-items-center"
>
<span>{number}</span>
<i
className="fa fa-check-circle"
style={{
display: recordsPerPage === number ? "inline" : "none",
}}
/>
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</Col>
</Row>
<Pagination className="pagination">
<PaginationItem disabled={currentPage === 1}>
<PaginationLink previous onClick={() => handlePageChange(currentPage - 1)} />
</PaginationItem>
{[...Array(totalPages)].map((_, index) => (
<PaginationItem key={index} active={index + 1 === currentPage}>
<PaginationLink onClick={() => handlePageChange(index + 1)} style={{ color: '#0b6592' }}>
{index + 1}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem disabled={currentPage === totalPages}>
<PaginationLink next onClick={() => handlePageChange(currentPage + 1)} />
</PaginationItem>
</Pagination>
{/* Add/Edit Model */}
{/* <Modal show={showAddEditModal} onHide={() => setShowAddEditModal(false)}>
<Modal.Header >
<Modal.Title>{isEditing ? "Edit Menu Access" : "Add Menu Access"}</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="formMenuName">
<Form.Label>Menu Name</Form.Label>
<Form.Control
type="text"
name="menuName"
value={currentMenuItem.menuName}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group>
<Label for="name">Menu Name<span className="required-field">*</span></Label>
<Input type="select" style={{ width: '100%', padding: '5px', border: '1px solid #ccc', borderRadius: '4px' }} onChange={(e) => idselected(e.target.value)}>
{menus.map((sub) => (
<option key={sub.menuItemId} value={sub.menuItemId}>{sub.menuItemDesc}</option>
))}
</Input>
</Form.Group>
<Form.Group controlId="formActive">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentMenuItem.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button variant="primary" type="submit" className="custom_button px-4">{isEditing ? "Update" : "Add"}</Button>
<Button variant="secondary" onClick={handleClose} className="custom_button px-4">
Cancel
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal> */}
<Modal show={showAddEditModal} onHide={() => setShowAddEditModal(false)}>
<Modal.Header>
<Modal.Title>{isEditing ? "Edit Menu Access" : "Add Menu Access"}</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}>
{/* Menu Name Input */}
<Form.Group controlId="formMenuName">
<Form.Label>Menu Items Name</Form.Label>
<Form.Control
type="text"
name="menuName"
value={currentMenuItem.menuName}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
{/* Select Menu Item */}
<Form.Group>
<Label for="name">Menu Item<span className="required-field">*</span></Label>
<Input
type="select"
style={{ width: '100%', padding: '5px', border: '1px solid #ccc', borderRadius: '4px' }}
onChange={(e) => idselected(e.target.value)}
>
{menus.map((sub) => (
<option key={sub.menuItemId} value={sub.menuItemId}>
{sub.menuItemDesc}
</option>
))}
</Input>
</Form.Group>
{/* Active Checkbox */}
<Form.Group controlId="formActive">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentMenuItem.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
{/* Modal Footer with buttons */}
<Modal.Footer>
<Button variant="primary" type="submit" className="custom_button px-4">
{isEditing ? "Update" : "Add"}
</Button>
<Button variant="secondary" onClick={handleClose} className="custom_button px-4">
Cancel
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div>
)}
</div>
);
}
export default MenuAccessControl;