first commit

This commit is contained in:
Harish Sargar
2025-04-01 20:28:04 +05:30
commit 0e1281aaa8
313 changed files with 85792 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,602 @@
import React, { useState, useEffect } from "react";
import {
Button,
Dropdown,
Modal,
Form,
Row,
Col,
InputGroup,
FormControl,
} from "react-bootstrap";
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 { Table, Pagination, PaginationItem, PaginationLink } from "reactstrap";
import { FaSearch, FaTimes } from "react-icons/fa";
import { BsJournals } from "react-icons/bs";
import { toast } from "react-toastify";
import Spinner from '../../UIComponants/Spinner';
import { fetchRegistry,addRegistry,updateRegistry,deleteRegistry } from "APIServices/APIRegistryApi";
import { set } from "react-hook-form";
function APIRegistry() {
const [apiEntries, setApiEntries] = useState([]);
const [showAddEditModal, setShowAddEditModal] = useState(false);
const [currentApiEntry, setCurrentApiEntry] = useState({
id: "",
table_name: "",
createdAt: "",
updatedAt: "",
isActive: false,
});
const [loading, setLoading] = useState(true);
const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [visibleColumns, setVisibleColumns] = useState({
id: true,
table_name: true,
createdAt: true,
updatedAt: true,
isActive: true,
actions: true,
});
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
fetchApiEntries();
}, []);
const fetchApiEntries = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}/Api_registery_header/Api_registery_header`;
const token = localStorage.getItem("authToken");
if (!token) {
console.error("Authorization token is missing.");
return;
}
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();
console.log("API entries:", data);
setApiEntries(data);
toast.success("API entries fetched successfully!");
} catch (error) {
console.error("Error fetching API entries:", error);
toast.error("Failed to fetch API entries.");
}
};
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const handleInputChange = (event) => {
const { name, value } = event.target;
setCurrentApiEntry((prev) => ({
...prev,
[name]: value,
}));
};
const handleSearch = (query) => {
setSearchQuery(query);
};
// const handleSubmit = async (event) => {
// event.preventDefault();
// try {
// if (isEditing) {
// // Update existing API entry
// setApiEntries(
// apiEntries.map((entry) =>
// entry.id === currentApiEntry.id ? currentApiEntry : entry
// )
// );
// toast.success("API entry updated successfully!");
// } else {
// // Add new API entry
// const newApiEntry = {
// ...currentApiEntry,
// id: `ID${apiEntries.length + 1}`, // Generate a new ID
// };
// const response = await addRegistry(newApiEntry);
// // const newId = `ID${apiEntries.length + 1}`;
// if (response) {
// setApiEntries([...apiEntries, response.data]); // Use API response data if needed
// toast.success("API added successfully!");
// } else {
// toast.error("Failed to add API entry.");
// }
// }
// setShowAddEditModal(false); // Close modal after submission
// } catch (error) {
// toast.error("There was an error while submitting the API.");
// console.error("Error in handleSubmit:", error); // Log the error for debugging
// }
// };
const handleSubmit = async (event) => {
event.preventDefault();
try {
if (isEditing) {
// Update existing API entry
const response = await updateRegistry(currentApiEntry.id, currentApiEntry);
if(response){
setApiEntries(
apiEntries.map((entry) =>
entry.id === currentApiEntry.id ? response.data : entry
)
);
toast.success("API entry updated successfully!");
} else {
toast.error("Failed to update API entry.");
}
} else {
// Add new API entry
const newApiEntry = {
...currentApiEntry,
id: `ID${apiEntries.length + 1}`, // Generate a new ID
};
const response = await addRegistry(newApiEntry);
if (response) {
setApiEntries([...apiEntries, response.data]); // Update state with API response
toast.success("API added successfully!");
} else {
toast.error("Failed to add API entry.");
}
setApiEntries([...currentApiEntry, ...apiEntries, newApiEntry]);
toast.success("API added successfully!");
}
fetchApiEntries(); // Refresh API entries after submit
setShowAddEditModal(false); // Close modal
} catch (error) {
toast.error("There was an error while submitting the API.");
console.error("Error in handleSubmit:", error); // Log the error for debugging
}
};
const openModal = (
entry = {
id: "",
table_name: "",
createdAt: "",
updatedAt: "",
isActive: false,
}
) => {
setIsEditing(!!entry.id);
setCurrentApiEntry(entry);
setShowAddEditModal(true);
};
const handleClose = () => {
setShowAddEditModal(false); // Close the modal by setting the state to false
};
const handleDelete = async (id) => {
try {
const response = await deleteRegistry(id);
if(response){
setApiEntries(apiEntries.filter((entry) => entry.id !== id));
toast.success("API is deleted successfully....");
}else{
toast.error("Failed to delete API entry.");
}
} catch (error) {
toast.error("There was an error while deleting the API.");
console.error("Error in handleDelete:", error);
}
};
const handleRecordsPerPageChange = (number) => {
setRecordsPerPage(number);
setCurrentPage(1);
};
const totalPages = Math.ceil(apiEntries.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const slicedAPIEntries = apiEntries
.filter(
(item) =>
item.table_name &&
item.table_name.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">
<h1 className="title_main">API Registry</h1>
</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={() => openModal(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
hover
responsive
align="middle"
className=" table-flush shadow-sm"
>
<thead className="custom_header">
<tr>
{Object.keys(visibleColumns)
.filter((key) => visibleColumns[key])
.map((key) => (
<th key={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</th>
))}
</tr>
</thead>
<tbody className="tbody">
{slicedAPIEntries.length === 0 ? (
<tr>
<td
colSpan={
Object.keys(visibleColumns).filter(
(key) => visibleColumns[key]
).length
}
className="text-center"
>
No Data Available
</td>
</tr>
) : slicedAPIEntries.length > 0 ? (
slicedAPIEntries.map((entry, index) => (
<tr key={index}>
{Object.keys(visibleColumns)
.filter((key) => visibleColumns[key])
.map((key) => (
<td key={key}>
{key === "actions" ? (
<div className="">
<FontAwesomeIcon
icon={faEdit}
onClick={() => openModal(entry)}
className="me-2"
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green", // edit icon color
marginRight: "15px", // space between icons
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => handleDelete(entry.id)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545", // delete icon color
}}
/>
</div>
) : key === "isActive" ? (
<span
className="status"
style={{
color: entry.isActive ? "green" : "red", // Dynamic text color
backgroundColor: entry.isActive
? "#d4f7d4"
: "#f7d4d4", // Faint green or red background
padding: "4px 8px", // Add some padding for the background effect
borderRadius: "4px", // Rounded corners
display: "inline-block", // Ensure the background only affects the text
}}
>
{entry.isActive ? "Active" : "Inactive"}
</span>
) : (
entry[key]
)}
</td>
))}
</tr>
))
) : (
<tr>
<td
colSpan={Object.keys(visibleColumns).length}
className="text-center"
>
No API entries found. Please add new entries.
</td>
</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>
<Modal show={showAddEditModal} onHide={() => setShowAddEditModal(false)}>
<Modal.Header>
<Modal.Title>
{isEditing ? "Edit API Entry" : "Add API Entry"}
</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="formTableName">
<Form.Label>Table Name</Form.Label>
<Form.Control
type="text"
name="tableName"
value={currentApiEntry.table_name}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formCreatedAt">
<Form.Label>Created At</Form.Label>
<Form.Control
type="text"
name="createdAt"
value={currentApiEntry.createdAt}
onChange={handleInputChange}
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formUpdatedAt">
<Form.Label>Updated At</Form.Label>
<Form.Control
type="text"
name="updatedAt"
value={currentApiEntry.updatedAt}
onChange={handleInputChange}
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formActive">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentApiEntry.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button
variant="primary"
className="custom_button px-4"
onClick={() => setShowAddEditModal(false)}
>
Close
</Button>
<Button
variant="primary"
className="custom_button px-4"
type="submit"
>
{isEditing ? "Update" : "Add"}
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div>
)}
</div>
);
}
export default APIRegistry;

View File

@@ -0,0 +1,496 @@
import React, { useState, useEffect } from "react";
import {
Button,
Dropdown,
Modal,
Form,
Row,
Col,
InputGroup,
FormControl,
} from "react-bootstrap";
import { Table, Pagination, PaginationItem, PaginationLink } 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 { toast } from "react-toastify";
import Spinner from '../../UIComponants/Spinner';
function AccessTypeManagement() {
const [accessTypes, setAccessTypes] = useState([]);
const [showAddEditModal, setShowAddEditModal] = useState(false);
const [currentAccessType, setCurrentAccessType] = useState({
typeId: "",
typeName: "",
description: "",
isActive: false,
});
const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [visibleColumns, setVisibleColumns] = useState({
typeId: true,
typeName: true,
description: true,
isActive: true,
actions: true,
});
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
const fetchAccessTypes = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}/api/getAllAccessTypes`;
const token = localStorage.getItem("authToken");
if (!token) {
console.error("Authorization token is missing.");
return;
}
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();
setAccessTypes(data);
} catch (error) {
console.error("Error fetching access types:", error);
}
};
fetchAccessTypes();
}, []);
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const handleInputChange = (event) => {
const { name, value, checked, type } = event.target;
setCurrentAccessType((prev) => ({
...prev,
[name]: type === "checkbox" ? checked : value,
}));
};
const handleSearch = (query) => {
setSearchQuery(query);
};
const handleSubmit = (event) => {
try {
event.preventDefault();
if (isEditing) {
setAccessTypes(
accessTypes.map((type) =>
type.typeId === currentAccessType.typeId ? currentAccessType : type
)
);
toast.success("AccessType updated successfully!");
} else {
const newTypeId = `ID${accessTypes.length + 1}`;
setAccessTypes([
...accessTypes,
{ ...currentAccessType, typeId: newTypeId },
]);
toast.success("AccessType added successfully!");
}
setShowAddEditModal(false);
} catch (error) {
toast.error("There was an error while submitting the Type.");
console.error("Error in handleSubmit:", error); // Log the error for debugging
}
};
const openModal = (
type = { typeId: "", typeName: "", description: "", isActive: false }
) => {
setIsEditing(!!type.typeId);
setCurrentAccessType(type);
setShowAddEditModal(true);
};
const handleClose = () => {
setShowAddEditModal(false); // Close the modal by setting the state to false
};
const slicedAccessTypes = accessTypes
.filter(
(item) =>
item.typeName &&
item.typeName.toLowerCase().includes(searchQuery.toLowerCase())
)
.slice((currentPage - 1) * recordsPerPage, currentPage * recordsPerPage);
const handleDelete = (typeId) => {
setAccessTypes(accessTypes.filter((type) => type.typeId !== typeId));
toast.success("Access Type Deleted ... ");
};
const handleRecordsPerPageChange = (number) => {
setRecordsPerPage(number);
setCurrentPage(1);
};
const totalPages = Math.ceil(accessTypes.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
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">
<h1 className="title_main">Access Type</h1>
</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={() => openModal(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 hover responsive 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">
{slicedAccessTypes.length === 0 ? (
<tr>
<td
colSpan={
Object.keys(visibleColumns).filter(
(key) => visibleColumns[key]
).length
}
className="text-center"
>
No Data Available
</td>
</tr>
) : (
slicedAccessTypes.map((type) => (
<tr key={type.typeId}>
{Object.entries(visibleColumns).map(([key, visible]) =>
visible ? (
<td key={key}>
{key === "actions" ? (
<div className="">
<FontAwesomeIcon
icon={faEdit}
onClick={() => openModal(type)}
className="me-2"
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green", // edit icon color
marginRight: "15px", // space between icons
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => handleDelete(type.typeId)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545", // delete icon color
}}
/>
</div>
) : key === "isActive" ? (
<span
className="status"
style={{
color: type.isActive ? "green" : "red", // Dynamic text color
backgroundColor: type.isActive
? "#d4f7d4"
: "#f7d4d4", // Faint green or red background
padding: "4px 8px", // Add some padding for the background effect
borderRadius: "4px", // Rounded corners
display: "inline-block", // Ensure the background only affects the text
}}
>
{type.isActive ? "Active" : "Inactive"}
</span>
) : (
type[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 Access Type" : "Add Access Type"}
</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="formTypeName">
<Form.Label>Type Name</Form.Label>
<Form.Control
type="text"
name="typeName"
value={currentAccessType.typeName}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formDescription">
<Form.Label>Description</Form.Label>
<Form.Control
type="text"
name="description"
value={currentAccessType.description}
onChange={handleInputChange}
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formActive">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentAccessType.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button
variant="primary"
className="custom_button px-4"
onClick={() => setShowAddEditModal(false)}
>
Close
</Button>
<Button
variant="primary"
className="custom_button px-4"
type="submit"
>
{isEditing ? "Update" : "Add"}
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div>
)}
</div>
);
}
export default AccessTypeManagement;

View File

@@ -0,0 +1,158 @@
.table-responsive{
box-shadow: 2px 2px 6px -1px grey;
border-radius: 0.8rem;
}
.thead-light{
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.tbody{
font-size: 1.0rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.sub-menu-header, .sub-menu-column {
min-width: 150px; /* Adjust the width as necessary */
}
.sub-menu-column {
text-align: center; /* Ensure the button is centered in the cell */
}
/* Datatype - 1 */
.form_body{
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
/* datatype-4 styles */
.payment_details{
font-size: 1.7rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
/* datatype-5 & datatype-6 styles,system parameter*/
.title_main{
font-size: 1.7rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
color: #0E6591;
}
.form_content{
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.heading_main{
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 700;
font-style: normal;
}
/* userdetails views */
.user-details-wrapper {
padding-top: 11rem;
padding-bottom: 5rem;/* Adjust as needed for the space between the navbar and component */
margin-top: -10rem;
}
/* user report */
table thead.custom_header th {
font-size: 0.8rem;
font-family: "Montserrat", sans-serif;
font-weight: 700;
font-style: normal;
color: #333; /* Adjust text color if needed */
/* Light background color for header */
}
.custom_button {
background-color: #0E6591 !important;
border-color: #0E6591 !important;
color: azure;
}
.custom_button:hover {
background-color: #0B4C6A !important; /* Optional: darker shade on hover */
border-color: #0B4C6A !important;
}
.custom-hover-border:focus {
border-color: #0E6591 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.custom-checkbox:checked {
border-color: #0E6591;
background-color: #0E6591;
}
.custom_manage_column_button{
color: #0E6591 !important;
border-color: #0E6591 !important;
}
.custom_manage_column_button:hover{
background-color: #0E6591 !important;
color: #fff !important; /* Changes text to white on hover */
border-color: #0E6591 !important;
}
.title_name{
color: #0E6591;
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 900;
font-style: bold;
}
/* system parameter */
.system_parameter{
border-radius: 2px;
box-shadow: 2px 2px 2px grey;
}
.table-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch; /* Smooth scrolling for touch devices */
padding: 0.5rem; /* Optional padding for better spacing */
}
.table-flush {
width: 100%;
min-width: 900px; /* Adjust based on your table's expected width */
}
.table-light.custom_header {
white-space: nowrap; /* Prevent headers from breaking into multiple lines */
}

View File

@@ -0,0 +1,513 @@
* {
padding: 0;
margin: 0;
box-sizing: border-box;
/* font-family: "Poppins", sans-serif; */
font-family: "Montserrat", sans-serif;
}
.main-side{
display: flex;
position: relative;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.topbar {
position: fixed;
top: 0;
left: 0;
right:0;
width: 100%;
height: 70px;
background-color: #0B4C6A;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 1000;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
.navbar-icons {
/* display: flex;
align-items: center;
gap: 36px;
margin-left: 10%;
color: rgb(245, 240, 240);
height: 80px;
width: 80px; */
display: flex;
align-items: center;
gap: 36px;
margin: 0 auto; /* Center the navbar icons */
color: rgb(245, 240, 240);
}
.navbar-icons i {
margin: 0 15px;
cursor: pointer;
transition: color 0.3s;
}
.navbar-icons i:hover {
color:black; /* Change to your desired hover color */
}
.navbar-avatar {
display: flex;
align-items: center;
margin-left: auto;
/* Push the avatar to the right */
}
.navbar-avatar i {
width: 60px; /* Adjust the size as needed */
height: 60px; /* Adjust the size as needed */
border-radius: 50%; /* Make it circular */
margin-left: 10px;
margin-top: 2rem;
margin-bottom: 2rem;
}
.user-Profile-Icon{
height: 2rem;
width: 2rem;
color:white;
}
.toggle-button {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
z-index: 1;
}
.toggle-button:hover {
transform: scale(1.1); /* Scale effect on hover */
}
.sidebar {
margin-top: 4rem; /* Move the sidebar container down */
}
.slider-container {
position: relative; /* Adjust to fit your design */
z-index: 10; /* Ensure it is above the sidebar */
transition: transform 0.3s ease; /* Smooth transition for sliding effect */
}
.dropdown-menu {
right: 0; /* Align dropdown to the right */
}
.Dashboard-logout {
display: flex;
background-color: #ebf0ee;
color: rgb(10, 10, 10);
border: none;
padding: 3px 10px 3px 10px;
border-radius: 5px;
cursor: pointer;
border: 2px solid black;
margin-left: auto;
align-items: center;
}
.Dashboard-logout:hover {
background-color: #4d4e4d;
color: white;
}
.user {
position: relative;
width: 50px;
height: 50px;
justify-self: right;
}
.main {
position: absolute;
top: 70px;
left: 260px;
width: calc(100% - 260px);
min-height: calc(100vh - 70px);
background: #fff;
padding: 20px;
justify-content: center;
flex-grow: 1;
transition: margin-left 00.3 ease-in-out;
}
/*
Sidebar icon container (beneath top bar) */
.sidebar-icon-container {
position: absolute;
top: 100px;
left: 0;
width:250px;
transition: margin-left 0.3s ease;
}
/* Icon color when sidebar is closed (black) */
.menu-icon {
color: black !important;
}
.sidebar {
float: left;
width: 250px;
position: absolute;
left: 0;
top: 0;
height:100vh;
bottom: 0;
background-color:#EDF5F4 !important;
color: #4A4A4A !important;
padding: 20px;
transition: transform 0.3s ease-in-out;
transform: translateX(-100%);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 100;
overflow-y: auto;
}
.sidebar.open {
/* Styles when sidebar is open */
transform: translateX(0);
}
.sidebar.closed {
/* Styles when sidebar is closed */
transform: translateX(-100%); /* or adjust to your design */
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar ul li {
margin-bottom: 10px;
padding: 10px 10px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.sidebar ul li:hover {
background-color:#2E4852;
color:black;
}
.sidebar ul li a {
text-decoration: none;
color: inherit;
}
.cards {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
margin-bottom: 20px;
align-items: center;
}
.card {
flex: 1 1 200px;
margin: 10px;
padding: 20px;
box-shadow: 0 7px 25px rgba(5, 5, 5, 0.08);
background-color: #fff;
border-radius: 10px;
transition: transform 0.3s ease;
}
.card:hover {
transform: scale(1.05);
}
.number {
font-size: 35px;
font-weight: 500;
color: #020705;
}
.card-name {
color: #0c0404;
font-weight: 600;
}
/* Card styling for SetupView */
.usercards {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
padding: 20 px;
margin-top: 30px; /* Offset for the fixed top bar */
}
.usercard {
background-color: #fff;
border-radius: 8px;
text-align: center;
justify-content: center;
border: 2px solid black;
margin-left: auto;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
padding: 20px;
width: calc(25% - 20px); /* Responsive width */
cursor: pointer;
transition: transform 0.3s ease;
}
.usercard:hover {
transform: scale(1.05);
}
.usercard i {
font-size: 20px;
color: #333;
margin-bottom: 15px;
}
.usercard h3 {
margin-bottom: 5px;
margin: auto;
}
.usercard p {
color: #666666;
}
.imgchart {
width: 100%;
height: auto;
}
.imgchart img {
width: 100%;
height: auto;
}
.main {
flex-grow: 1;
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 20px;
}
.report-card {
flex: 1 1 calc(33.333% - 40px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: start;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
border-radius: 10px;
background-color: #ffffff;
text-align: center;
width: 200px;
height: auto;
margin: 10px;
}
.report-card:hover {
box-shadow: #0c0404;
transform: scale(1.05);
}
.user-details {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 20px;
padding: 20px;
}
@media (max-width: 768px) {
.sidebar {
float: none;
transform: translateX(-100%);
}
.main {
margin-left: 0;
}
.sidebar.open {
transform: translateX(0);
}
.main {
margin-left: 0px;
}
}
@media (max-width: 768px) {
.card {
flex-basis: 90%;
margin: 5px auto;
}
}
@media (max-width: 480px) {
.card {
flex-basis: 90%;
margin: 5px auto;
}
}
.chart-container {
width: auto;
max-width: 500px;
height: auto;
aspect-ratio: 2 / 1;
margin: 20px auto;
padding: 10px;
background-color: #f0f0f0;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
}
@media (max-width: 768px) {
.chart-container {
max-width: 500px;
padding: 5px;
}
}
@media (max-width: 480px) {
.chart-container {
max-width: 50%;
aspect-ratio: 1 / 1;
}
}
@media (max-width: 972px) {
.sidebar {
position: fixed; /* Fixed positioning for small screens */
left: 0;
top: 70px;
height: 100%;
z-index: 1000; /* Ensure it's above other content */
}
.main {
margin-left: 0; /* Main content takes full width when sidebar is hidden */
}
}
/* Responsive card adjustments */
@media (max-width: 768px) {
.usercard {
align-items: center;
margin-left: auto;
width: 100%; /* Full width cards on smaller screens */
}
}
@media (max-width: 480px) {
.usercard {
margin-left: auto;
width: 100%; /* Full width cards on smaller screens */
}
}
.menu-icon{
color: aliceblue;
}
.sidebar {
flex: 0 0 200px; /* sidebar width */
height: 100vh; /* full-height sidebar */
}
.main {
flex-grow: 1; /* main content takes remaining space */
padding: 20px;
}
@media (max-width: 768px) {
.container {
flex-direction: column; /* stack vertically on smaller screens */
}
.sidebar {
/* sidebar takes full width on small screens */
height: auto;
}
.main {
width: 100%; /* main content takes full width */
}
}
.submenu {
display: block; /* Ensure submenus are visible */
padding-left: 20px; /* Add padding for nested submenu */
margin-top: 5px;
}
.submenu li {
list-style-type: none; /* Remove bullets */
padding-left: 10px; /* Add some indentation for submenu items */
}
.sidebar {
position: fixed; /* Fixes the sidebar to the left */
top: 0;
left: 0;
height: 100vh; /* Takes the full height of the viewport */
width: 250px; /* Adjust the width as needed */
background-color: #413d3d;/* Background color */
overflow-y: auto; /* Enables vertical scrolling */
overflow-x: hidden; /* Prevents horizontal scrolling */
transition: width 0.3s; /* Smooth transition when expanding/collapsing */
padding: 20px; /* Padding for content inside */
z-index: 100; /* Makes sure sidebar stays on top */
}
.sidebar.open {
width: 250px; /* Width when the sidebar is open */
}
.sidebar ul {
list-style: none; /* Removes default bullet points from list */
padding: 0; /* Removes default padding */
margin: 0; /* Removes default margin */
}
.sidebar ul li {
padding: 10px; /* Adds padding to each list item */
cursor: pointer; /* Changes cursor on hover */
transition: background-color 0.2s; /* Smooth background color change */
}
.sidebar ul li:hover {
background-color: #e2e2e2; /* Background color on hover */
}
.sidebar .submenu ul {
margin-top: 10px;
padding-left: 15px;
}
.main-side {
margin-left: 250px; /* Adjust according to the sidebar width */
padding: 20px; /* Padding for the main content area */
}
@media (max-width: 971px) {
.main-side {
margin-left: 0; /* Resets margin when the sidebar is collapsed */
}
}

View File

@@ -0,0 +1,73 @@
.container {
max-width: 800px;
}
.uploaded-file {
font-weight: bold;
text-align: center;
}
.scanned-result {
text-align: center;
font-weight: bold;
}
.barcode-scanner {
width: 100%;
height: 320px;
border: 2px solid #ccc;
border-radius: 8px;
background-color: #f8f9fa;
}
.custom-hover-border:focus {
border-color: #0E6591 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.custom-file-input ~ .custom-file-label {
background-color: white; /* Purple background */
color: black; /* White text */
border: none;
padding: 0.5rem 1rem;
cursor: pointer;
}
.custom-file-input:focus ~ .custom-file-label {
outline: none;
}
.upload-section {
background-color: #f8f9fa; /* Light background for the card */
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.custom-file-input ~ .custom-file-label {
background-color:white ;
color: black; /* White text */
border: none;
padding: 10px;
cursor: pointer;
border-radius: 4px;
text-align: center;
}
.custom-file-input:focus ~ .custom-file-label {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(111, 66, 193, 0.25);
}
.video-preview {
max-height: 300px;
border-radius: 8px;
margin-top: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

View File

@@ -0,0 +1,20 @@
.custom-radio:checked {
background-color: #0E6591;
border-color: #0E6591;
}
.custom-radio:checked + .form-check-label::before {
color: #0E6591;
border-color: #0E6591;
}
.custom-hover-border:focus {
border-color: #0E6591 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.card{
box-shadow: 2px 2px 2px 2px grey;
border-radius: 2px #0e6591;
}

View File

@@ -0,0 +1,89 @@
.table-responsive{
box-shadow: 2px 2px 6px -1px grey;
}
.thead-light{
/* <uniquifier>: Use a unique and descriptive class name
<weight>: Use a value from 100 to 900 */
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.tbody{
font-size: 1.0rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.text-primary{
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
}
.title_main{
font-size: 1.7rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
color: #0E6591;
}
table thead.custom_header th {
font-size: 0.8rem;
font-family: "Montserrat", sans-serif;
font-weight: 700;
font-style: normal;
color: #333; /* Adjust text color if needed */
/* Light background color for header */
}
.custom_button {
background-color: #0E6591 !important;
border-color: #0E6591 !important;
color: azure;
}
.custom_button:hover {
background-color: #0B4C6A !important; /* Optional: darker shade on hover */
border-color: #0B4C6A !important;
}
.custom-hover-border:focus {
border-color: #0E6591 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.custom-checkbox:checked {
border-color: #0E6591;
background-color: #0E6591;
}
.custom_manage_column_button{
color: #0E6591 !important;
border-color: #0E6591 !important;
}
.custom_manage_column_button:hover{
background-color: #0E6591 !important;
color: #fff !important; /* Changes text to white on hover */
border-color: #0E6591 !important;
}
.title_name{
color: #0E6591;
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 900;
font-style: bold;
}

View File

@@ -0,0 +1,45 @@
/* ProfileDropdown.css */
.profile-dropdown {
position: relative;
display: inline-block;
}
.profile-circle {
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
}
.profile-circle img {
width: 100%;
height: 100%;
object-fit: cover;
}
.dropdown-menu {
position: absolute;
top: 60px;
right: 0;
background-color: white;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
z-index: 1;
}
.dropdown-menu button {
display: block;
width: 100%;
padding: 10px;
border: none;
background: none;
text-align: left;
cursor: pointer;
}
.dropdown-menu button:hover {
background-color: #f1f1f1;
}

View File

@@ -0,0 +1,50 @@
.usercards{
display: grid;
grid-template-columns: repeat(4, 1fr); /* 4 columns */
gap: 15px;
margin-top:9rem;
margin-right: 2rem;
margin-left:2rem;
margin-bottom:2rem;
}
.usercard{
background-color: #f8f9fa;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
text-align: center;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.usercard i {
color:#0E6591;
}
.usercard:hover{
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.usercard h3{
color: #0E6591; /* Change the card title color to red */
font-family: 'GoogleFontName', sans-serif;
font-size: large; /* Apply the Google font */
}
@media (max-width:1200px) {
.usercards{
grid-template-columns: repeat(3,1fr);
}
}
@media (max-width:768px) {
.usercards{
grid-template-columns: repeat(2,1fr);
}
}
@media (max-width:576px) {
.usercards{
grid-template-columns: repeat(1fr);
}
}

View File

@@ -0,0 +1,106 @@
.table-responsive{
box-shadow: 2px 2px 6px -1px grey;
}
.thead-light{
/* <uniquifier>: Use a unique and descriptive class name
<weight>: Use a value from 100 to 900 */
font-size: 1.1rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.tbody{
font-size: 1.0rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
}
.sub-menu-header, .sub-menu-column {
min-width: 150px; /* Adjust the width as necessary */
}
.sub-menu-column {
text-align: center; /* Ensure the button is centered in the cell */
}
.title_main{
font-size: 1.7rem;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
color: #0E6591;
}
.custom_header{
font-size: 0.8rem;
font-family: "Montserrat", sans-serif;
font-weight: 700;
font-style: normal;
color: #333;
}
.custom-checkbox:checked{
border-color: #0E6591;
background-color: #0E6591;
}
.status{
font-weight: bold;
text-align: center; /* Ensures the text is centered */
display: inline-block; /* Keeps the background confined to the text */
padding: 4px 8px; /* Adds padding for background */
border-radius: 4px;
}
/* Custom checkbox styles */
.custom-checkbox:checked .form-check-input:checked {
background-color: #0E6591; /* Your custom color */
border-color: #0E6591; /* Custom border color */
}
.custom-checkbox .form-check-input:focus {
border-color: #0E6591; /* Focus state color */
box-shadow: 0 0 0 0.25rem rgba(14, 101, 145, 0.5); /* Focus glow effect */
}
.custom-checkbox .form-check-input {
border-radius: 0.25rem; /* Optional: To make checkbox corners rounder */
}
.custom_button {
background-color: #0E6591 !important;
border-color: #0E6591 !important;
color: azure;
}
.custom_button:hover {
background-color: #0B4C6A !important; /* Optional: darker shade on hover */
border-color: #0B4C6A !important;
}
.custom-hover-border:focus {
border-color: #0E6591 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.custom-hover-border:focus {
border-color: #0b6592 !important;
box-shadow: 0 0 5px rgba(14, 101, 145, 0.5);
}
.pagination{
display: flex;
justify-content: center;
}

View File

@@ -0,0 +1,236 @@
// import React, { useState, useEffect, useRef } from 'react';
// import { Box, Button, Modal, TextField, Typography, FormControl, FormControlLabel, Checkbox, Radio, RadioGroup, Autocomplete } from '@mui/material';
// import { DataGrid, GridToolbarContainer } from '@mui/x-data-grid';
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
// import { faEllipsisV } from '@fortawesome/free-solid-svg-icons';
// import AirplanemodeActiveIcon from '@mui/icons-material/AirplanemodeActive';
// import { Link } from 'react-router-dom';
// import Extension from './Extension';
// function CustomToolbar({ handleModal }) {
// return (
// <GridToolbarContainer>
// <Button onClick={handleModal}>+</Button>
// </GridToolbarContainer>
// );
// }
// function CodeExtension() {
// const [menuItems, setMenuItems] = useState([]);
// const [selectedMenuItem, setSelectedMenuItem] = useState(null);
// const [isModalOpen, setIsModalOpen] = useState(false);
// const [formData, setFormData] = useState({
// name: '',
// email: '',
// testing: '',
// dataType: ''
// });
// useEffect(() => {
// const fetchData = async () => {
// try {
// const response = await fetch('http://localhost:9292/api/extension');
// const data = await response.json();
// setMenuItems(data);
// } catch (error) {
// console.error('Error fetching data:', error);
// }
// };
// fetchData();
// }, []);
// const handleThreeDotsClick = (menuItemId) => {
// setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
// };
// const handleModalOpen = () => {
// setIsModalOpen(true);
// };
// const handleModalClose = () => {
// setIsModalOpen(false);
// // Reset form data after closing modal
// setFormData({
// name: '',
// email: '',
// testing: '',
// dataType: ''
// });
// };
// const handleChange = (e) => {
// const { name, value } = e.target;
// setFormData({ ...formData, [name]: value });
// };
// const handleFormSubmit = (submittedDataType) => {
// setFormData({ ...formData, dataType: submittedDataType });
// handleModalOpen();
// };
// const columns = [
// { field: 'goto', headerName: 'Goto', width: 200, headerClassName: 'custom-header', cellClassName: 'custom-cell' },
// { field: 'field_name', headerName: 'Field Name', width: 250, headerClassName: 'custom-header', cellClassName: 'custom-cell' },
// { field: 'mapping', headerName: 'Mapping', width: 200, headerClassName: 'custom-header', cellClassName: 'custom-cell' },
// { field: 'data_type', headerName: 'Data Type', width: 200, headerClassName: 'custom-header', cellClassName: 'custom-cell' },
// {
// field: 'actions',
// headerName: 'Actions',
// width: 150,
// renderCell: ({ row }) => (
// <div>
// <div className="three-dots" onClick={() => handleThreeDotsClick(row.id)}>
// <FontAwesomeIcon icon={faEllipsisV} />
// </div>
// {selectedMenuItem === row.id && (
// <div className="popover">
// {/* Implement your actions buttons here */}
// </div>
// )}
// </div>
// ),
// },
// ];
// const renderInputField = () => {
// switch (formData.dataType) {
// case 'date':
// return (
// <TextField
// label="Date"
// name="date"
// type="date"
// value={formData.date}
// onChange={handleChange}
// fullWidth
// />
// );
// case 'textfield':
// return (
// <TextField
// label="Text Field"
// name="textfield"
// value={formData.textfield}
// onChange={handleChange}
// fullWidth
// />
// );
// case 'longtext':
// return (
// <TextField
// label="Long Text"
// name="longtext"
// value={formData.longtext}
// onChange={handleChange}
// multiline
// rows={4}
// fullWidth
// />
// );
// case 'checkbox':
// return (
// <FormControlLabel
// control={
// <Checkbox
// checked={formData.checkbox || false}
// onChange={(e) => setFormData({ ...formData, checkbox: e.target.checked })}
// />
// }
// label="Checkbox"
// />
// );
// case 'radiobutton':
// return (
// <FormControl component="fieldset">
// <RadioGroup
// name="radiobutton"
// value={formData.radiobutton || ''}
// onChange={(e) => setFormData({ ...formData, radiobutton: e.target.value })}
// >
// <FormControlLabel value="option1" control={<Radio />} label="Option 1" />
// <FormControlLabel value="option2" control={<Radio />} label="Option 2" />
// </RadioGroup>
// </FormControl>
// );
// case 'autocomplete':
// return (
// <Autocomplete
// options={['Option 1', 'Option 2', 'Option 3']}
// renderInput={(params) => <TextField {...params} label="Autocomplete" />}
// value={formData.autocomplete || ''}
// onChange={(e, newValue) => setFormData({ ...formData, autocomplete: newValue })}
// fullWidth
// />
// );
// default:
// return null;
// }
// };
// return (
// <>
// <Box sx={{ position: 'fixed', top: 0, left: 0, width: '100%', zIndex: 1 }}>
// {/* Your header content here */}
// </Box>
// <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
// <Box sx={{ width: '80%', maxWidth: 1200, marginTop: '100px' }}>
// <DataGrid
// rows={menuItems}
// columns={columns}
// pageSize={10}
// components={{
// Toolbar: () => (
// <CustomToolbar
// handleModal={handleModalOpen}
// />
// ),
// }}
// />
// <Modal open={isModalOpen} onClose={handleModalClose} centered>
// <Box sx={{ width: 400, bgcolor: 'background.paper', p: 4, position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}>
// <Extension onSubmit={handleFormSubmit} />
// <Typography variant="h5" gutterBottom sx={{ display: 'flex', alignItems: 'center' }}>
// <Link to="/Extension"><AirplanemodeActiveIcon sx={{ mr: 1 }} /></Link> Add Item
// </Typography>
// <form onSubmit={(e) => { e.preventDefault(); handleFormSubmit(formData.dataType); }}>
// <div>
// <TextField
// label="Name"
// name="name"
// value={formData.name}
// onChange={handleChange}
// fullWidth
// />
// </div>
// <div>
// <TextField
// label="Email"
// name="email"
// value={formData.email}
// onChange={handleChange}
// fullWidth
// />
// </div>
// <div>
// <TextField
// label="Testing"
// name="testing"
// value={formData.testing}
// onChange={handleChange}
// fullWidth
// />
// </div>
// {renderInputField()}
// <Button type="submit" variant="contained" sx={{ mt: 2, mr: 1 }}>Submit</Button>
// <Button variant="outlined" onClick={handleModalClose} sx={{ mt: 2 }}>Cancel</Button>
// </form>
// </Box>
// </Modal>
// </Box>
// </Box>
// </>
// );
// }
// export default CodeExtension;

View File

@@ -0,0 +1,630 @@
// import React, { useState, useEffect } from "react";
// import { useNavigate, Link } from "react-router-dom";
// import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
// import {
// faHouse,
// faGear,
// faUsers,
// faBars,
// faUserCircle,
// faSignOutAlt
// } from "@fortawesome/free-solid-svg-icons";
// import "./Dashboard.css";
// import { Bar } from "react-chartjs-2";
// import Chart from "chart.js/auto";
// import SetupView from "./SetupView";
// import DashboardView from "./DashboardView";
// import UserDetailsView from "./UserDetailsView";
// import UserMaintenanceView from "./UserMaintenanceView";
// import AccessType from "./AccessType";
// import SystemParameter from "./SystemParameter";
// import MenuAccessControl from "./MenuAccessControl";
// import MenuMaintenance from "./MenuMaintenance";
// import UserGroupMaintenance from "./UserGroupMaintenance";
// import APIRegistry from "./APIRegistry";
// import TOKENRegistry from "./TOKENRegistry";
// import DataType1 from "./DataType1";
// import DataType2 from "./DataType2";
// import DataType3 from "./DataType3";
// import DataType4 from "./DataType4";
// import DataType5 from "./DataType5";
// import DataType6 from "./DataType6";
// import DynamicTable from "./DynamicTable";
// import CodeExtension from "./Codeextension";
// // import DashboardCharts from "./DashboardCharts";
// import Dropdown from "react-bootstrap/Dropdown";
// import { removeToken } from "../../utils/tokenService";
// import AccordionPage from "./UIComponents/Accordion";
// import BadgesPage from "./UIComponents/BadgesPage";
// import DashViewone from "./UIComponents/DashViewone";
// const HomeView = ({ barChartData, barChartOptions }) => (
// <div>
// <div className="cards">
// <div className="card">
// <div className="card-content">
// <div className="number">1</div>
// <div className="card-name">Index</div>
// </div>
// </div>
// <div className="card">
// <div className="card-content">
// <div className="number">2</div>
// <div className="card-name">Index</div>
// </div>
// </div>
// <div className="card">
// <div className="card-content">
// <div className="number">3</div>
// <div className="card-name">Index</div>
// </div>
// </div>
// </div>
// <div
// className="chart-container"
// style={{
// width: "100%",
// maxWidth: "700px",
// height: "400px",
// display: "flex",
// justifyContent: "center",
// marginTop: "20px",
// }}
// >
// <Bar data={barChartData} options={barChartOptions} />
// </div>
// </div>
// );
// function Dashboard() {
// const [currentView, setCurrentView] = useState("home");
// const [isSidebarOpen, setIsSidebarOpen] = useState(false);
// const [menuItems, setMenuItems] = useState([]);
// const [error, setError] = useState("");
// const navigate = useNavigate();
// useEffect(() => {
// const handleResize = () => {
// setIsSidebarOpen(window.innerWidth >= 972);
// };
// handleResize();
// window.addEventListener("resize", handleResize);
// return () => window.removeEventListener("resize", handleResize);
// }, []);
// useEffect(() => {
// const fetchMenuItems = async () => {
// const apiUrl = `${process.env.REACT_APP_API_URL}/fndMenu/menuloadbyuser`;
// const token = localStorage.getItem("authToken");
// if (!token) {
// console.error("Authorization token is missing.");
// setError("Authorization token is missing.");
// return;
// }
// try {
// const response = await fetch(apiUrl, {
// method: "GET",
// headers: {
// "Content-Type": "application/json",
// Authorization: `Bearer ${token}`,
// },
// });
// if (!response.ok) {
// throw new Error(`Error: ${response.status}`);
// }
// const data = await response.json();
// setMenuItems(data);
// } catch (error) {
// console.error("Fetching error:", error);
// setError(error.toString());
// }
// };
// fetchMenuItems();
// }, []);
// const barChartData = {
// labels: ["Label1", "Label2", "Label3"],
// datasets: [
// {
// label: "Dataset 1",
// data: [65, 59, 80],
// backgroundColor: [
// "rgba(255, 99, 132, 0.2)",
// "rgba(54, 162, 235, 0.2)",
// "rgba(255, 206, 86, 0.2)",
// ],
// borderColor: [
// "rgba(255, 99, 132, 1)",
// "rgba(54, 162, 235, 1)",
// "rgba(255, 206, 86, 1)",
// ],
// borderWidth: 1,
// },
// ],
// };
// const barChartOptions = {
// scales: {
// y: {
// beginAtZero: true,
// },
// },
// maintainAspectRatio: false,
// };
// if (error) {
// return <p>Error fetching data: {error}</p>;
// }
// const handleLogout = () => {
// removeToken();
// navigate("/#", { replace: true }); // Redirect to login page
// };
// const toggleSidebar = () => {
// setIsSidebarOpen(!isSidebarOpen);
// };
// const renderView = () => {
// // console.log("renderning")
// console.log("Current View:", currentView);
// switch (currentView) {
// // case "home":
// // return (
// // <HomeView
// // barChartData={barChartData}
// // barChartOptions={barChartOptions}
// // />
// // );
// case "home": {
// console.log("render it")
// return (
// <>
// <AccordionPage />
// <BadgesPage />
// <DashViewone/>
// </>
// );
// }
// case "setup":
// console.log("reder on");
// return (
// <SetupView
// onUserMaintenance={() => setCurrentView("userMaintenance")}
// onMenuAccessControl={() => setCurrentView("menuAccessControl")}
// onUserGroupMaintenance={() =>
// setCurrentView("userGroupMaintenance")
// }
// onSystemParameter={() => setCurrentView("systemParameter")}
// onMenuMaintenance={() => setCurrentView("menuMaintenance")}
// onAccessType={() => setCurrentView("accessType")}
// onAPIregistry={() => setCurrentView("apiRegistry")}
// onTokenregistry={() => setCurrentView("tokenRegistry")}
// onDataType1={() => setCurrentView("dataType1")}
// onDataType2={() => setCurrentView("dataType2")}
// onDataType3={() => setCurrentView("dataType3")}
// onDataType4={() => setCurrentView("dataType4")}
// onDataType5={() => setCurrentView("dataType5")}
// onDataType6={() => setCurrentView("dataType6")}
// onDynamicTable={() => setCurrentView("dynamicTable")}
// oncodeExtension={() => setCurrentView("codeExtension")}
// />
// );
// // case "dashboard":
// // return <DashboardView
// // onDashboardCharts={()=> setCurrentView("dashboardcharts")}
// // />;
// case "userdetails":
// console.log("render come")
// return <UserDetailsView />;
// case "userMaintenance":
// return <UserMaintenanceView />;
// case "accessType":
// return <AccessType />;
// case "systemParameter":
// return <SystemParameter />;
// case "menuAccessControl":
// return <MenuAccessControl />;
// case "menuMaintenance":
// return <MenuMaintenance />;
// case "userGroupMaintenance":
// return <UserGroupMaintenance />;
// case "apiRegistry":
// return <APIRegistry />;
// case "tokenRegistry":
// return <TOKENRegistry />;
// case "dataType1":
// return <DataType1 />;
// case "dataType2":
// return <DataType2 />;
// case "dataType3":
// return <DataType3 />;
// case "dataType4":
// return <DataType4 />;
// case "dataType5":
// return <DataType5 />;
// case "dataType6":
// return <DataType6 />;
// case "dashboardcharts":
// return <DashboardCharts />;
// case "dynamictable":
// return <DynamicTable />;
// case "codeextension":
// return <codeExtension />;
// default:
// return <div>Select an option from the menu</div>;
// }
// };
// return (
// <div className="container">
// {/* navbar */}
// <div className="topbar">
// <div className="navbar-icons">
// <i
// onClick={() => setCurrentView("home")}
// className="fa-solid fa-house"
// ></i>
// <i
// onClick={() => setCurrentView("dashboard")} // Ensure you have a case for "dashboard" in renderView
// className="fas fa-chart-bar"
// ></i>
// <i
// onClick={() => setCurrentView("setup")}
// className="fa-solid fa-gear"
// ></i>
// <i
// onClick={() => setCurrentView("userdetails")}
// className="fa-solid fa-users"
// ></i>
// </div>
// {/* user-profile-avatar */}
// <div>
// <Dropdown className="navbar-avatar">
// <Dropdown.Toggle variant="link" id="avatar-dropdown" bsPrefix="custom-toggle" >
// {/* <img src="/path/to/your/avatar.png" alt="User Avatar" /> */}
// <FontAwesomeIcon icon={faUserCircle} className="user-Profile-Icon text-white" />
// </Dropdown.Toggle>
// <Dropdown.Menu>
// <Dropdown.Item onClick={() => setCurrentView("profile")}>
// <FontAwesomeIcon icon={faUserCircle} /> Profile
// </Dropdown.Item>
// <Dropdown.Item onClick={handleLogout}>
// <FontAwesomeIcon icon={faSignOutAlt} /> Logout
// </Dropdown.Item>
// </Dropdown.Menu>
// </Dropdown>
// </div>
// </div>
// {/* Sidebar Icon (below the topbar) */}
// <div className="sidebar-icon-container">
// <FontAwesomeIcon
// icon={faBars}
// className="menu-icon"
// onClick={toggleSidebar}
// />
// </div>
// {/* main view */}
// <div className="main-side ">
// {/* side bar */}
// <div className={`sidebar mt-3 ${isSidebarOpen ? "open" : ""}`}>
// {
// <ul>
// {menuItems.map((item, index) => (
// <li
// key={index}
// onClick={() => setCurrentView(item.menuItemId.menuItemDesc)}
// >
// {item.menuItemId.menuItemDesc}
// </li>
// ))}
// </ul>
// }
// {
// <div>
// {menuItems.map((menu, index) => (
// <div key={index}>
// <h6>{menu.menuItemDesc}</h6>
// <ul>
// {menu.subMenus.map((subMenu, subIndex) => (
// <Link
// to={`/${subMenu.menuItemDesc}`}
// style={{ textDecoration: "none", color: "#4A4A4A" }}
// >
// <li key={subIndex}>{subMenu.menuItemDesc}</li>
// </Link>
// ))}
// </ul>
// </div>
// ))}
// </div>
// }
// </div>
// <div className="main">{renderView()}</div>
// </div>
// </div>
// );
// }
// export default Dashboard;
import React, { useState, useEffect } from "react";
import { useNavigate, Link } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faHouse,
faGear,
faUsers,
faBars,
faUserCircle,
faSignOutAlt,
} from "@fortawesome/free-solid-svg-icons";
import "./Dashboard.css";
import { Bar } from "react-chartjs-2";
import Chart from "chart.js/auto";
import SetupView from "./SetupView";
import DashboardView from "./DashboardView";
import UserDetailsView from "./UserDetailsView";
import UserMaintenanceView from "./UserMaintenanceView";
import AccessType from "./AccessType";
import SystemParameter from "./SystemParameter";
import MenuAccessControl from "./MenuAccessControl";
import MenuMaintenance from "./MenuMaintenance";
import UserGroupMaintenance from "./UserGroupMaintenance";
import APIRegistry from "./APIRegistry";
import TOKENRegistry from "./TOKENRegistry";
import DataType1 from "./DataType1";
import DataType2 from "./DataType2";
import DataType3 from "./DataType3";
import DataType4 from "./DataType4";
import DataType5 from "./DataType5";
import DataType6 from "./DataType6";
import DynamicTable from "./DynamicForm/DynamicForm2";
import CodeExtension from "./Codeextension";
import Dropdown from "react-bootstrap/Dropdown";
import { removeToken } from "../../utils/tokenService";
import AccordionPage from "./UIComponents/Accordion";
import BadgesPage from "./UIComponents/BadgesPage";
import DashViewone from "./UIComponents/DashViewone";
import Sidebar from "../Dashboard/UIComponents/Sidebar";
import Slider from "./UIComponents/Slider";
function Dashboard() {
const [currentView, setCurrentView] = useState("home"); // Initial view
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
const [menuItems, setMenuItems] = useState([]);
const [error, setError] = useState("");
const navigate = useNavigate();
useEffect(() => {
const handleResize = () => {
setIsSidebarOpen(window.innerWidth >= 972);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
useEffect(() => {
const fetchMenuItems = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}/fndMenu/menuloadbyuser`;
const token = localStorage.getItem("authToken");
if (!token) {
console.error("Authorization token is missing.");
setError("Authorization token is missing.");
return;
}
try {
const response = await fetch(apiUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
const data = await response.json();
setMenuItems(data);
} catch (error) {
console.error("Fetching error:", error);
setError(error.toString());
}
};
fetchMenuItems();
}, []);
const handleLogout = () => {
removeToken();
navigate("/#", { replace: true }); // Redirect to login page
};
const toggleSlider = () => {
setIsSidebarOpen((prev) => !prev);
};
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};
// Add main menu items here
const mainMenuItems = [
{ menuItemId: { menuItemDesc: "Home" }, subMenus: [] },
{ menuItemId: { menuItemDesc: "Transaction" }, subMenus: [] },
{ menuItemId: { menuItemDesc: "Data Management" }, subMenus: [] },
];
const renderView = () => {
switch (currentView) {
case "home":
return (
<>
<AccordionPage />
<BadgesPage />
<DashViewone />
</>
);
case "dashboard":
return <DashboardView />;
case "setup":
return (
<SetupView
onUserMaintenance={() => setCurrentView("userMaintenance")}
onMenuAccessControl={() => setCurrentView("menuAccessControl")}
onUserGroupMaintenance={() =>
setCurrentView("userGroupMaintenance")
}
onSystemParameter={() => setCurrentView("systemParameter")}
onMenuMaintenance={() => setCurrentView("menuMaintenance")}
onAccessType={() => setCurrentView("accessType")}
onAPIregistry={() => setCurrentView("apiRegistry")}
onTokenregistry={() => setCurrentView("tokenRegistry")}
onDataType1={() => setCurrentView("dataType1")}
onDataType2={() => setCurrentView("dataType2")}
onDataType3={() => setCurrentView("dataType3")}
onDataType4={() => setCurrentView("dataType4")}
onDataType5={() => setCurrentView("dataType5")}
onDataType6={() => setCurrentView("dataType6")}
onDynamicTable={() => setCurrentView("dynamicTable")}
onCodeExtension={() => setCurrentView("codeExtension")}
/>
);
case "userdetails":
return <UserDetailsView />;
case "userMaintenance":
return <UserMaintenanceView />;
case "accessType":
return <AccessType />;
case "systemParameter":
return <SystemParameter />;
case "menuAccessControl":
return <MenuAccessControl />;
case "menuMaintenance":
return <MenuMaintenance />;
case "userGroupMaintenance":
return <UserGroupMaintenance />;
case "apiRegistry":
return <APIRegistry />;
case "tokenRegistry":
return <TOKENRegistry />;
case "dataType1":
return <DataType1 />;
case "dataType2":
return <DataType2 />;
case "dataType3":
return <DataType3 />;
case "dataType4":
return <DataType4 />;
case "dataType5":
return <DataType5 />;
case "dataType6":
return <DataType6 />;
case "dynamictable":
return <DynamicTable />;
case "codeExtension":
return <CodeExtension />;
default:
return <div>Select an option from the menu</div>;
}
};
return (
<div className="container">
{/* Navbar */}
<div className="topbar">
<div className="navbar-icons">
<i
onClick={() => setCurrentView("home")}
className="fa-solid fa-house"
></i>
<i
onClick={() => setCurrentView("dashboard")}
className="fas fa-chart-bar"
></i>
<i
onClick={() => setCurrentView("setup")}
className="fa-solid fa-gear"
></i>
<i
onClick={() => setCurrentView("userdetails")}
className="fa-solid fa-users"
></i>
</div>
{/* User Profile Avatar */}
<div>
<Dropdown className="navbar-avatar">
<Dropdown.Toggle
variant="link"
id="avatar-dropdown"
bsPrefix="custom-toggle"
>
<FontAwesomeIcon
icon={faUserCircle}
className="user-Profile-Icon text-white"
/>
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => setCurrentView("profile")}>
<FontAwesomeIcon icon={faUserCircle} /> Profile
</Dropdown.Item>
<Dropdown.Item onClick={handleLogout}>
<FontAwesomeIcon icon={faSignOutAlt} /> Logout
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</div>
{/* Sidebar Icon (below the topbar) */}
{/* Sidebar Icon (below the topbar and above the sidebar) */}
<div className="sidebar-icon-container">
{/* Slider to control the sidebar */}
<Slider isOpen={isSidebarOpen} toggleSlider={toggleSlider} />
</div>
{/* Sidebar */}
<div className={`sidebar ${isSidebarOpen ? "open" : "closed"}`}>
<Sidebar
menuItems={[...mainMenuItems, ...menuItems]} // Combine main and dynamic menu items
setCurrentView={setCurrentView}
isSidebarOpen={isSidebarOpen}
/>
</div>
{/* main view */}
<div className="main-side"></div>
{/* Main content rendering based on current view */}
<div className="main">{renderView()}</div>
</div>
);
}
export default Dashboard;

View File

@@ -0,0 +1,382 @@
import React, { useState, useEffect } from "react";
import { Modal, Button, Form, Card } from "react-bootstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
function DashboardView({onDashboardCharts}) {
const [showTable, setShowTable] = useState(false);
const [dashboards, setDashboards] = useState([]);
const [showAddItemPopup, setShowAddItemPopup] = useState(false);
const [newItem, setNewItem] = useState({
dashboardName: "",
description: "",
securityProfile: "",
addToHome: "",
});
const [selectedItemIndex, setSelectedItemIndex] = useState(null);
const [columns, setColumns] = useState([
{ label: "Dashboard Name", key: "dashboardName", visible: true },
{ label: "Description", key: "description", visible: true },
{ label: "Security Profile", key: "securityProfile", visible: true },
{ label: "Add to Home", key: "addToHome", visible: true },
]);
const [showManageColumnsModal, setShowManageColumnsModal] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10); // Initial number of records per page
const [error, setError] = useState(null); // To handle error state
useEffect(() => {
if (showTable) {
fetchData();
} else {
fetchDashboardCardData();
}
}, [showTable]);
const fetchData = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}/getNotificationByUser`;
const token = localStorage.getItem("authToken");
if (!token) {
console.error("Authorization token is missing.");
setError("Authorization token is missing.");
return;
}
try {
const response = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
const data = await response.json();
setDashboards(data);
} catch (error) {
console.error("Fetching error:", error);
setError(error.toString());
}
};
const fetchDashboardCardData = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}/get_Dashboard_header`;
const token = localStorage.getItem("authToken");
if (!token) {
console.error("Authorization token is missing.");
setError("Authorization token is missing.");
return;
}
try {
const response = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
const data = await response.json();
const testingDashboard = data.find(
(dashboard) => dashboard.dashboard_name === "Testing Dashboard"
);
setDashboards(testingDashboard ? [testingDashboard] : []);
} catch (error) {
console.error("Fetching error:", error);
setError(error.toString());
}
};
const handleAddItemClick = () => {
setShowAddItemPopup(true);
};
const handleInputChange = (event) => {
const { name, value } = event.target;
setNewItem({ ...newItem, [name]: value });
};
const handleAddItem = () => {
if (selectedItemIndex !== null) {
const updatedDashboards = [...dashboards];
updatedDashboards[selectedItemIndex] = newItem;
setDashboards(updatedDashboards);
} else {
setDashboards([...dashboards, newItem]);
}
setNewItem({
dashboardName: "",
description: "",
securityProfile: "",
addToHome: "",
});
setSelectedItemIndex(null);
setShowAddItemPopup(false);
};
const handleDeleteItem = (index) => {
const updatedDashboards = [...dashboards];
updatedDashboards.splice(index, 1);
setDashboards(updatedDashboards);
};
const handleColumnVisibilityChange = (key) => {
const updatedColumns = columns.map((col) => {
if (col.key === key) {
return { ...col, visible: !col.visible };
}
return col;
});
setColumns(updatedColumns);
};
const handleRecordsPerPageChange = (value) => {
setRecordsPerPage(value);
};
return (
<div className="container mt-5">
<h4>Dashboard</h4>
{/* Header Buttons */}
<div className="text-end mb-3">
{!showTable && (
<Button
variant="secondary"
className="me-2"
onClick={() => setShowTable(true)}
>
Dashboard Builder
</Button>
)}
{showTable && (
<div className="text-end mb-3">
<Button
variant="secondary"
className="me-2"
onClick={() => setShowTable(false)}
>
Back
</Button>
<Button
variant="secondary"
className="me-2"
onClick={handleAddItemClick}
>
Add Item
</Button>
</div>
)}
</div>
{/* Render the card component only if showTable is false */}
{!showTable && dashboards.length > 0 && (
<div className="card-container">
<Card className="dashboard-card col-lg-4 col-md-6 col-sm-12 mb-4" onClick={onDashboardCharts} >
<Card.Body>
<Card.Title>{dashboards[0].dashboard_name}</Card.Title>
<Card.Text>{dashboards[0].description}</Card.Text>
</Card.Body>
</Card>
</div>
)}
{/* Table */}
{showTable && (
<div>
<table className="table table-striped">
{/* Table Header */}
<thead>
<tr>
{columns
.filter((column) => column.visible)
.map((column, index) => (
<th key={index}>{column.label}</th>
))}
<th>Action</th>
</tr>
</thead>
{/* Table Body */}
<tbody>
{dashboards.map((dashboard, index) => (
<tr key={index}>
{columns
.filter((column) => column.visible)
.map((column, columnIndex) => (
<td key={columnIndex}>{dashboard[column.key]}</td>
))}
<td>
<Button
variant="secondary"
size="sm"
className="me-2"
onClick={() => {
setShowAddItemPopup(true);
setNewItem(dashboard);
setSelectedItemIndex(index);
}}
>
<FontAwesomeIcon icon={faEdit} />
</Button>
<Button
variant="secondary"
size="sm"
onClick={() => handleDeleteItem(index)}
>
<FontAwesomeIcon icon={faTrash} />
</Button>
</td>
</tr>
))}
</tbody>
</table>
<div className="d-flex justify-content-between">
{/* Manage Columns Button */}
<div className="text-start mb-3">
<Button
variant="secondary"
className="me-2"
onClick={() => setShowManageColumnsModal(true)}
>
Manage Columns
</Button>
</div>
{/* Records per Page Dropdown */}
<div className="text-end mb-3">
<label htmlFor="recordsPerPage" className="">
Records per Page
</label>
<select
className="form-select"
value={recordsPerPage}
onChange={(e) => handleRecordsPerPageChange(e.target.value)}
>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
<option value={100}>100</option>
</select>
</div>
</div>
</div>
)}
{/* Add Item Modal */}
<Modal show={showAddItemPopup} onHide={() => setShowAddItemPopup(false)}>
<Modal.Header closeButton>
<Modal.Title>
{selectedItemIndex !== null ? "Edit Item" : "Add Item"}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
<div className="mb-3">
<label htmlFor="dashboardName" className="form-label">
Dashboard Name
</label>
<input
type="text"
className="form-control"
id="dashboardName"
name="dashboardName"
value={newItem.dashboardName}
onChange={handleInputChange}
/>
</div>
<div className="mb-3">
<label htmlFor="description" className="form-label">
Description
</label>
<input
type="text"
className="form-control"
id="description"
name="description"
value={newItem.description}
onChange={handleInputChange}
/>
</div>
<div className="mb-3">
<label htmlFor="securityProfile" className="form-label">
Security Profile
</label>
<input
type="text"
className="form-control"
id="securityProfile"
name="securityProfile"
value={newItem.securityProfile}
onChange={handleInputChange}
/>
</div>
<div className="mb-3">
<label htmlFor="addToHome" className="form-label">
Add to Home
</label>
<input
type="text"
className="form-control"
id="addToHome"
name="addToHome"
value={newItem.addToHome}
onChange={handleInputChange}
/>
</div>
</form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => setShowAddItemPopup(false)}>
Close
</Button>
<Button variant="primary" onClick={handleAddItem}>
{selectedItemIndex !== null ? "Save Changes" : "Add Item"}
</Button>
</Modal.Footer>
</Modal>
{/* Manage Columns Modal */}
<Modal
show={showManageColumnsModal}
onHide={() => setShowManageColumnsModal(false)}
>
<Modal.Header closeButton>
<Modal.Title>Manage Columns</Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
{columns.map((column, index) => (
<div key={index} className="form-check">
<input
className="form-check-input"
type="checkbox"
checked={column.visible}
onChange={() => handleColumnVisibilityChange(column.key)}
/>
<label className="form-check-label">{column.label}</label>
</div>
))}
</form>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => setShowManageColumnsModal(false)}
>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
export default DashboardView;

View File

@@ -0,0 +1,9 @@
import React from 'react'
const DataManagement = () => {
return (
<div>DataManagement</div>
)
}
export default DataManagement

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,443 @@
// import React, { useState, useEffect, useRef } from 'react';
// import QRCode from 'qrcode.react';
// import Barcode from 'react-barcode';
// import { QrReader } from 'react-qr-reader';
// import Quagga from 'quagga';
// import { QRCodeCanvas } from 'qrcode.react'; // Updated import
// import 'bootstrap/dist/css/bootstrap.min.css';
// import '../Dashboard/CSS/CSS/DataType2.css';
// const DataType2 = () => {
// const [qrInput, setQrInput] = useState('');
// const [barcodeInput, setBarcodeInput] = useState('');
// const [image, setImage] = useState(null);
// const [file, setFile] = useState(null);
// const [video, setVideo] = useState(null);
// const [audio, setAudio] = useState(null);
// const [scanResult, setScanResult] = useState('');
// const [barcodeResult, setBarcodeResult] = useState('');
// const barcodeScannerRef = useRef(null);
// const handleQrInputChange = (e) => {
// setQrInput(e.target.value);
// };
// const handleBarcodeInputChange = (e) => {
// setBarcodeInput(e.target.value);
// };
// const handleImageChange = (e) => {
// if (e.target.files[0]) {
// setImage(URL.createObjectURL(e.target.files[0]));
// }
// };
// const handleFileChange = (e) => {
// if (e.target.files[0]) {
// setFile(e.target.files[0].name);
// }
// };
// const handleVideoChange = (e) => {
// if (e.target.files[0]) {
// setVideo(URL.createObjectURL(e.target.files[0]));
// }
// };
// const handleAudioChange = (e) => {
// if (e.target.files[0]) {
// setAudio(URL.createObjectURL(e.target.files[0]));
// }
// };
// const handleScan = (data) => {
// if (data) {
// setScanResult(data);
// }
// };
// const handleError = (err) => {
// console.error(err);
// };
// useEffect(() => {
// if (barcodeScannerRef.current) {
// Quagga.init(
// {
// inputStream: {
// name: 'Live',
// type: 'LiveStream',
// target: barcodeScannerRef.current,
// constraints: {
// facingMode: 'environment',
// },
// },
// decoder: {
// readers: ['code_128_reader'],
// },
// },
// function (err) {
// if (err) {
// console.error(err);
// return;
// }
// Quagga.start();
// }
// );
// Quagga.onDetected((data) => {
// setBarcodeResult(data.codeResult.code);
// });
// return () => {
// Quagga.offDetected();
// Quagga.stop();
// };
// }
// }, []);
// return (
// <div className="container mt-5">
// <h1 className="text-center mb-4">QR Code Generator</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="text"
// className="form-control mb-4"
// placeholder="Enter text for QR code..."
// value={qrInput}
// onChange={handleQrInputChange}
// />
// <div className="d-flex justify-content-center">
// <QRCode value={qrInput ? qrInput : 'https://example.com'} />
// </div>
// </div>
// </div>
// <h1 className="text-center mb-4">Barcode Generator</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="text"
// className="form-control mb-4"
// placeholder="Enter text for barcode..."
// value={barcodeInput}
// onChange={handleBarcodeInputChange}
// />
// <div className="d-flex justify-content-center">
// <Barcode
// value={barcodeInput ? barcodeInput : '1234567890'}
// format="CODE128"
// displayValue={true}
// width={1}
// height={50}
// margin={10}
// />
// </div>
// </div>
// </div>
// <h1 className="text-center mb-4">Image Upload</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="file"
// className="form-control mb-4"
// onChange={handleImageChange}
// accept="image/*"
// />
// {image && <img src={image} alt="Uploaded" className="img-fluid rounded shadow" />}
// </div>
// </div>
// <h1 className="text-center mb-4">File Upload</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="file"
// className="form-control mb-4"
// onChange={handleFileChange}
// />
// {file && <p className="uploaded-file">Uploaded File: {file}</p>}
// </div>
// </div>
// <h1 className="text-center mb-4">Video Upload</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="file"
// className="form-control mb-4"
// onChange={handleVideoChange}
// accept="video/*"
// />
// {video && <video src={video} controls className="img-fluid rounded shadow" />}
// </div>
// </div>
// <h1 className="text-center mb-4">Audio Upload</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <input
// type="file"
// className="form-control mb-4"
// onChange={handleAudioChange}
// accept="audio/*"
// />
// {audio && <audio src={audio} controls className="w-100" />}
// </div>
// </div>
// <h1 className="text-center mb-4">QR Code Scanner</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <QrReader
// delay={300}
// onError={handleError}
// onScan={handleScan}
// style={{ width: '100%' }}
// />
// {scanResult && <p className="scanned-result">Scanned Result: {scanResult}</p>}
// </div>
// </div>
// <h1 className="text-center mb-4">Barcode Scanner</h1>
// <div className="row justify-content-center mb-5">
// <div className="col-md-6">
// <div ref={barcodeScannerRef} className="barcode-scanner"></div>
// {barcodeResult && <p className="scanned-result">Last Scanned Barcode: {barcodeResult}</p>}
// </div>
// </div>
// </div>
// );
// };
// export default DataType2;
import React, { useState, useEffect, useRef } from 'react';
import { QRCodeCanvas } from 'qrcode.react'; // Use QRCodeCanvas instead of default import
import Barcode from 'react-barcode';
import { QrReader } from 'react-qr-reader';
import Quagga from 'quagga';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../Dashboard/CSS/CSS/DataType2.css';
import { toast } from "react-toastify";
import Spinner from '../../UIComponants/Spinner';
const DataType2 = () => {
const [qrInput, setQrInput] = useState('');
const [barcodeInput, setBarcodeInput] = useState('');
const [image, setImage] = useState(null);
const [file, setFile] = useState(null);
const [video, setVideo] = useState(null);
const [audio, setAudio] = useState(null);
const [loading, setLoading] = useState(true);
const [scanResult, setScanResult] = useState('');
const [barcodeResult, setBarcodeResult] = useState('');
const barcodeScannerRef = useRef(null);
const handleQrInputChange = (e) => setQrInput(e.target.value);
const handleBarcodeInputChange = (e) => setBarcodeInput(e.target.value);
const handleScan = (data) => data && setScanResult(data);
const handleError = (err) => console.error(err);
const handleImageChange = (e) => {
if (e.target.files[0]) {
setImage(URL.createObjectURL(e.target.files[0]));
toast.success("Image uploaded successfully!");
}
};
const handleFileChange = (e) => {
if (e.target.files[0]) {
setFile(e.target.files[0].name);
toast.success("File uploaded successfully!");
}
};
const handleVideoChange = (e) => {
if (e.target.files[0]) {
setVideo(URL.createObjectURL(e.target.files[0]));
toast.success("Video uploaded successfully!");
}
};
const handleAudioChange = (e) => {
if (e.target.files[0]) {
setAudio(URL.createObjectURL(e.target.files[0]));
toast.success("Audio uploaded successfully!");
}
};
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
if (barcodeScannerRef.current) {
Quagga.init(
{
inputStream: {
name: 'Live',
type: 'LiveStream',
target: barcodeScannerRef.current,
constraints: {
facingMode: 'environment',
},
},
decoder: {
readers: ['code_128_reader'],
},
},
(err) => {
if (err) {
console.error(err);
return;
}
Quagga.start();
}
);
Quagga.onDetected((data) => {
setBarcodeResult(data.codeResult.code);
});
return () => {
Quagga.offDetected();
Quagga.stop();
};
}
}, []);
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div className="container mt-5">
<h1 className="text-center mb-4">QR Code Generator</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<input
type="text"
className="form-control mb-4 custom-hover-border"
placeholder="Enter text for QR code..."
value={qrInput}
onChange={handleQrInputChange}
/>
<div className="d-flex justify-content-center">
<QRCodeCanvas value={qrInput || 'https://example.com'} />
</div>
</div>
</div>
<h1 className="text-center mb-4">Barcode Generator</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<input
type="text"
className="form-control mb-4 custom-hover-border"
placeholder="Enter text for barcode..."
value={barcodeInput}
onChange={handleBarcodeInputChange}
/>
<div className="d-flex justify-content-center">
<Barcode
value={barcodeInput || '1234567890'}
format="CODE128"
displayValue
width={1}
height={50}
margin={10}
/>
</div>
</div>
</div>
<h1 className="text-center mb-4">Image Upload</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<input
type="file"
className="custom-file-input"
id="customFileImage"
onChange={handleImageChange}
accept="image/*"
/>
<label htmlFor="customFileImage" className="custom-file-label">
Choose File
</label>
{image && <img src={image} alt="Uploaded" className="img-fluid rounded shadow mt-3" />}
</div>
</div>
<h1 className="text-center mb-4">Video Upload</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<input
type="file"
className="custom-file-input "
id="customFileVideo"
onChange={handleVideoChange}
accept="video/*"
/>
<label htmlFor="customFileVideo" className="custom-file-label ">
Choose File
</label>
{video && <video src={video} controls className="img-fluid rounded shadow mt-3" />}
</div>
</div>
<h1 className="text-center mb-4">Audio Upload</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<input
type="file"
className="custom-file-input custom-hover-border"
id="customFileAudio"
onChange={handleAudioChange}
accept="audio/*"
/>
<label htmlFor="customFileAudio" className="custom-file-label">
Choose File
</label>
{audio && <audio src={audio} controls className="w-100 mt-3" />}
</div>
</div>
<h1 className="text-center mb-4">QR Code Scanner</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<QrReader
delay={300}
onError={handleError}
onScan={handleScan}
style={{ width: '100%' }}
/>
{scanResult && <p className="scanned-result">Scanned Result: {scanResult}</p>}
</div>
</div>
<h1 className="text-center mb-4">Barcode Scanner</h1>
<div className="row justify-content-center mb-5">
<div className="col-md-6">
<div ref={barcodeScannerRef} className="barcode-scanner"></div>
{barcodeResult && <p className="scanned-result">Last Scanned Barcode: {barcodeResult}</p>}
</div>
</div>
</div>
)}
</div>
);
};
export default DataType2;

View File

@@ -0,0 +1,76 @@
import React, { useState, useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Spinner from '../../UIComponants/Spinner';
function DataType3() {
// State for the menu items and the selected menu item
const [menuItems, setMenuItems] = useState([]);
const [selectedMenuItem, setSelectedMenuItem] = useState('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('http://localhost:9292/fndMenu/menuloadbyuser', {
method: 'GET',
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzeXNhZG1pbiIsInNjb3BlcyI6IlJPTEVfRGV2ZWxvcGVyLFJPTEVfQURNSU4iLCJpYXQiOjE3MTYzNDkyNTEsImV4cCI6MTcxODk0MTI1MX0.fLW0-Uvb6X1fLQNzdiNiYeHO3lMYa1bsFAmOJkGCdRY'
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setMenuItems(data);
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
fetchData();
}, []);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleSelectionChange = (event) => {
setSelectedMenuItem(event.target.value);
};
// if (loading) return <div className="d-flex justify-content-center"><div className="spinner-border" role="status"><span className="visually-hidden">Loading...</span></div></div>;
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div>
<h5>Select a Menu Item</h5>
<select value={selectedMenuItem} onChange={handleSelectionChange}>
<option value="">Select an Option</option>
{menuItems.map((item) => (
<option key={item.menuItemId.menuItemId} value={item.menuItemId.menuItemId}>
{item.menuItemDesc}
</option>
))}
</select>
</div>
)}
</div>
);
}
export default DataType3;

View File

@@ -0,0 +1,354 @@
// import React, { useState } from 'react';
// import 'bootstrap/dist/css/bootstrap.min.css';
// function DataType4() {
// const [paymentData, setPaymentData] = useState({
// cardNumber: '',
// cardHolder: '',
// expiryDate: '',
// cvv: ''
// });
// const handleChange = (e) => {
// const { name, value } = e.target;
// setPaymentData(prevData => ({
// ...prevData,
// [name]: value
// }));
// };
// const handleSubmit = (event) => {
// event.preventDefault();
// alert("Form submitted successfully!");
// console.log("Form Data:", paymentData);
// };
// return (
// <div className="container mt-3">
// <h2>Payment Details</h2>
// <form onSubmit={handleSubmit} className="row g-3">
// <div className="col-md-6">
// <label htmlFor="cardNumber" className="form-label">Card Number</label>
// <input
// type="text"
// className="form-control"
// id="cardNumber"
// name="cardNumber"
// value={paymentData.cardNumber}
// onChange={handleChange}
// pattern="\d{16}"
// title="Card number must be 16 digits"
// style={{ borderColor: "#343a40" }}
// required
// />
// </div>
// <div className="col-md-6">
// <label htmlFor="cardHolder" className="form-label">Card Holder's Name</label>
// <input
// type="text"
// className="form-control"
// id="cardHolder"
// name="cardHolder"
// value={paymentData.cardHolder}
// onChange={handleChange}
// style={{ borderColor: "#343a40" }}
// required
// />
// </div>
// <div className="col-md-6">
// <label htmlFor="expiryDate" className="form-label">Expiry Date</label>
// <input
// type="month"
// className="form-control"
// id="expiryDate"
// name="expiryDate"
// value={paymentData.expiryDate}
// style={{ borderColor: "#343a40" }}
// onChange={handleChange}
// required
// />
// </div>
// <div className="col-md-6">
// <label htmlFor="cvv" className="form-label">CVV</label>
// <input
// type="text"
// className="form-control"
// id="cvv"
// name="cvv"
// value={paymentData.cvv}
// onChange={handleChange}
// style={{ borderColor: "#343a40" }}
// pattern="\d{3}"
// title="CVV must be 3 digits"
// required
// />
// </div>
// <div className="col-12">
// <button type="submit" size="sm" className="btn btn-primary">Submit Payment</button>
// </div>
// </form>
// </div>
// );
// }
// export default DataType4;
// import React, { useState } from 'react';
// import 'bootstrap/dist/css/bootstrap.min.css';
// import { FaCreditCard, FaUser, FaLock } from 'react-icons/fa'; // Import specific icons
// import "../Dashboard/CSS/CSS/CommonStyle.css";
// function DataType4() {
// const [paymentData, setPaymentData] = useState({
// cardNumber: '',
// cardHolder: '',
// expiryDate: '',
// cvv: ''
// });
// const handleChange = (e) => {
// const { name, value } = e.target;
// setPaymentData(prevData => ({
// ...prevData,
// [name]: value
// }));
// };
// const handleSubmit = (event) => {
// event.preventDefault();
// alert("Form submitted successfully!");
// console.log("Form Data:", paymentData);
// };
// return (
// <div className="container mt-5">
// <div className="card p-4 shadow-sm rounded">
// <h2 className=" payment_details text-center mb-4 text-primary">Payment Details</h2>
// <form onSubmit={handleSubmit} className="row g-3">
// <div className="col-md-6">
// <label htmlFor="cardNumber" className="form-label">Card Number</label>
// <div className="input-group">
// <span className="input-group-text"><FaCreditCard /></span>
// <input
// type="text"
// className="form-control"
// id="cardNumber"
// name="cardNumber"
// value={paymentData.cardNumber}
// onChange={handleChange}
// placeholder="1234 5678 9123 4567"
// pattern="\d{16}"
// title="Card number must be 16 digits"
// required
// />
// </div>
// </div>
// <div className="col-md-6">
// <label htmlFor="cardHolder" className="form-label">Card Holder's Name</label>
// <div className="input-group">
// <span className="input-group-text"><FaUser /></span>
// <input
// type="text"
// className="form-control"
// id="cardHolder"
// name="cardHolder"
// value={paymentData.cardHolder}
// onChange={handleChange}
// placeholder="John Doe"
// required
// />
// </div>
// </div>
// <div className="col-md-6">
// <label htmlFor="expiryDate" className="form-label">Expiry Date</label>
// <input
// type="month"
// className="form-control"
// id="expiryDate"
// name="expiryDate"
// value={paymentData.expiryDate}
// onChange={handleChange}
// required
// />
// </div>
// <div className="col-md-6">
// <label htmlFor="cvv" className="form-label">CVV</label>
// <div className="input-group">
// <span className="input-group-text"><FaLock /></span>
// <input
// type="text"
// className="form-control"
// id="cvv"
// name="cvv"
// value={paymentData.cvv}
// onChange={handleChange}
// placeholder="***"
// pattern="\d{3}"
// title="CVV must be 3 digits"
// required
// />
// </div>
// </div>
// <div className="col-12 text-center">
// <button type="submit" className="btn btn-primary btn-lg">Submit Payment</button>
// </div>
// </form>
// </div>
// </div>
// );
// }
// export default DataType4;
import React, { useState,useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import { FaCreditCard, FaUser, FaLock } from 'react-icons/fa'; // Import specific icons
import "../Dashboard/CSS/CSS/CommonStyle.css";
import { toast } from "react-toastify";
import Spinner from '../../UIComponants/Spinner';
function DataType4() {
const [paymentData, setPaymentData] = useState({
cardNumber: '',
cardHolder: '',
expiryDate: '',
cvv: ''
});
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleChange = (e) => {
const { name, value } = e.target;
setPaymentData(prevData => ({
...prevData,
[name]: value
}));
};
const handleSubmit = (event) => {
event.preventDefault();
alert("Form submitted successfully!");
console.log("Form Data:", paymentData);
toast.success("Payment Details submitted....");
};
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div className="container mt-5">
<div className="card p-4 shadow-lg rounded border-0">
<h2 className="text-center mb-4 title_main" style={{ color: '#0E6591', fontWeight: 'bold' }}>
Payment Details
</h2>
<form onSubmit={handleSubmit} className="row g-4">
<div className="col-md-6">
<label htmlFor="cardNumber" className="form-label fw-semibold">
Card Number
</label>
<div className="input-group">
<span className="input-group-text bg-light text-primary">
<FaCreditCard />
</span>
<input
type="text"
className="form-control shadow-sm"
id="cardNumber"
name="cardNumber"
value={paymentData.cardNumber}
onChange={handleChange}
placeholder="1234 5678 9123 4567"
pattern="\d{16}"
title="Card number must be 16 digits"
required
/>
</div>
</div>
<div className="col-md-6">
<label htmlFor="cardHolder" className="form-label fw-semibold">
Card Holder's Name
</label>
<div className="input-group">
<span className="input-group-text bg-light text-primary">
<FaUser />
</span>
<input
type="text"
className="form-control shadow-sm"
id="cardHolder"
name="cardHolder"
value={paymentData.cardHolder}
onChange={handleChange}
placeholder="John Doe"
required
/>
</div>
</div>
<div className="col-md-6">
<label htmlFor="expiryDate" className="form-label fw-semibold">
Expiry Date
</label>
<input
type="month"
className="form-control shadow-sm"
id="expiryDate"
name="expiryDate"
value={paymentData.expiryDate}
onChange={handleChange}
required
/>
</div>
<div className="col-md-6">
<label htmlFor="cvv" className="form-label fw-semibold">
CVV
</label>
<div className="input-group">
<span className="input-group-text bg-light text-primary">
<FaLock />
</span>
<input
type="text"
className="form-control shadow-sm"
id="cvv"
name="cvv"
value={paymentData.cvv}
onChange={handleChange}
placeholder="***"
pattern="\d{3}"
title="CVV must be 3 digits"
required
/>
</div>
</div>
<div className="col-12 text-center">
<button
type="submit"
className="btn btn-primary btn-lg shadow-sm"
style={{
background: 'linear-gradient(90deg, #0E6591, #0B4C6A)',
border: 'none',
color: '#fff',
marginTop:'1rem'
}}
>
Submit Payment
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}
export default DataType4;

View File

@@ -0,0 +1,216 @@
// import React, { useState } from 'react';
// import 'bootstrap/dist/css/bootstrap.min.css';
// import "../Dashboard/CSS/CSS/CommonStyle.css";
// function DataType5() {
// const [firstName, setFirstName] = useState('');
// const [secondName, setSecondName] = useState('');
// const [description, setDescription] = useState('');
// const handleFirstNameChange = (e) => {
// setFirstName(e.target.value);
// };
// const handleSecondNameChange = (e) => {
// setSecondName(e.target.value);
// };
// const handleDescriptionChange = (e) => {
// setDescription(e.target.value);
// };
// const handleSubmit = (e) => {
// e.preventDefault();
// const formData = {
// Name: firstName,
// test2 : {Name: secondName, description: description }
// };
// console.log(JSON.stringify(formData));
// };
// return (
// <div className="container mt-4" style={{ width: '50%' }}>
// <div className='card p-4 shadow-sm rounded'>
// <form onSubmit={handleSubmit}>
// <div className="form-group">
// <label htmlFor="first-name" className="form-label"> Name:</label>
// <input
// type="text"
// id="first-name"
// name="first-name"
// className="form-control"
// value={firstName}
// onChange={handleFirstNameChange}
// placeholder="Enter your first name"
// />
// </div>
// <h2 className=" title_main mt-3 text-primary" >Test 2</h2>
// <div className="form_content">
// <div className="form-group">
// <label htmlFor="second-name" className="form-label"> Name:</label>
// <input
// type="text"
// id="second-name"
// name="second-name"
// className="form-control"
// value={secondName}
// onChange={handleSecondNameChange}
// placeholder="Enter your second name"
// />
// </div>
// <div className="mb-3">
// <label htmlFor="description" className="form-label">Description:</label>
// <textarea
// id="description"
// name="description"
// className="form-control"
// rows="4"
// value={description}
// onChange={handleDescriptionChange}
// placeholder="Describe yourself"
// ></textarea>
// </div>
// </div>
// <button type="submit" className="btn btn-primary">Submit</button>
// </form>
// </div>
// </div>
// );
// }
// export default DataType5;
import React, { useState,useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import "../Dashboard/CSS/CSS/CommonStyle.css";
import Spinner from '../../UIComponants/Spinner';
function DataType5() {
const [firstName, setFirstName] = useState('');
const [secondName, setSecondName] = useState('');
const [description, setDescription] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleFirstNameChange = (e) => {
setFirstName(e.target.value);
};
const handleSecondNameChange = (e) => {
setSecondName(e.target.value);
};
const handleDescriptionChange = (e) => {
setDescription(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
const formData = {
Name: firstName,
test2: { Name: secondName, description: description },
};
console.log(JSON.stringify(formData));
};
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div className="container mt-5 mb-5" style={{ maxWidth: '600px' }}>
<div className="card p-4 shadow-lg border-0 rounded">
<h2 className="text-center mb-4 title_main" style={{ fontWeight: 'bold' }}>
Main Details
</h2>
<form onSubmit={handleSubmit}>
{/* First Name Field */}
<div className="form-group mb-3">
<label htmlFor="first-name" className="form-label fw-semibold">
First Name:
</label>
<input
type="text"
id="first-name"
name="first-name"
className="form-control shadow-sm custom-hover-border"
value={firstName}
onChange={handleFirstNameChange}
placeholder="Enter your name"
required
/>
</div>
{/* Section Header */}
<h3 className="mt-4 mb-3 title_main" style={{ fontWeight: 'bold' }}>
Test 2
</h3>
{/* Second Name Field */}
<div className="form-group mb-3">
<label htmlFor="second-name" className="form-label fw-semibold">
Second Name:
</label>
<input
type="text"
id="second-name"
name="second-name"
className="form-control shadow-sm custom-hover-border"
value={secondName}
onChange={handleSecondNameChange}
placeholder="Enter your second name"
required
/>
</div>
{/* Description Field */}
<div className="form-group mb-4">
<label htmlFor="description" className="form-label fw-semibold">
Description:
</label>
<textarea
id="description"
name="description"
className="form-control shadow-sm custom-hover-border"
rows="4"
value={description}
onChange={handleDescriptionChange}
placeholder="Write a brief description about yourself"
required
></textarea>
</div>
{/* Submit Button */}
<div className="text-center">
<button
type="submit"
className="btn btn-primary btn-lg shadow-sm"
style={{
background: 'linear-gradient(90deg, #0E6591, #0B4C6A)',
border: 'none',
color: '#fff',
}}
>
Submit
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}
export default DataType5;

View File

@@ -0,0 +1,241 @@
// import React, { useState } from 'react';
// import 'bootstrap/dist/css/bootstrap.min.css';
// import "../Dashboard/CSS/CSS/CommonStyle.css";
// function DataType6() {
// const [firstName, setFirstName] = useState('');
// const [additionalEntries, setAdditionalEntries] = useState([]);
// const handleFirstNameChange = (e) => {
// setFirstName(e.target.value);
// };
// const handleAddFields = () => {
// setAdditionalEntries([...additionalEntries, { name: '', description: '' }]);
// };
// const handleNameChange = (index, e) => {
// const updatedEntries = [...additionalEntries];
// updatedEntries[index].name = e.target.value;
// setAdditionalEntries(updatedEntries);
// };
// const handleDescriptionChange = (index, e) => {
// const updatedEntries = [...additionalEntries];
// updatedEntries[index].description = e.target.value;
// setAdditionalEntries(updatedEntries);
// };
// const handleSubmit = (e) => {
// e.preventDefault();
// const formData = {
// Name: firstName,
// test2: additionalEntries
// };
// console.log(JSON.stringify(formData));
// };
// return (
// <div className="container mt-4" style={{ width: '50%' }}>
// <div className='card p-4 shadow-sm rounded'>
// <form onSubmit={handleSubmit}>
// <div className="form-group">
// <label htmlFor="first-name" className="form-label">Name:</label>
// <input
// type="text"
// id="first-name"
// name="First-name"
// className="form-control"
// value={firstName}
// onChange={handleFirstNameChange}
// />
// </div>
// <h2 className="title_main mt-3 text-primary">Test 2</h2>
// {additionalEntries.map((entry, index) => (
// <div className="form_content" key={index}>
// <div className="form-group">
// <label htmlFor={`additional-name-${index}`} className="form-label">Name:</label>
// <input
// type="text"
// id={`additional-name-${index}`}
// name={`additional-name-${index}`}
// className="form-control"
// value={entry.name}
// onChange={(e) => handleNameChange(index, e)}
// />
// </div>
// <div className="form-group">
// <label htmlFor={`additional-description-${index}`} className="form-label">Description:</label>
// <textarea
// id={`additional-description-${index}`}
// name={`additional-description-${index}`}
// className="form-control"
// rows="4"
// value={entry.description}
// onChange={(e) => handleDescriptionChange(index, e)}
// ></textarea>
// </div>
// </div>
// ))}
// <div className="btn-group mt-3">
// <button type="submit" className="btn btn-primary me-3">Submit</button>
// <button type="button" className="btn btn-primary" onClick={handleAddFields}>Add Test2</button>
// </div>
// </form>
// </div>
// </div>
// );
// }
// export default DataType6;
import React, { useState,useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import "../Dashboard/CSS/CSS/CommonStyle.css";
import Spinner from '../../UIComponants/Spinner';
function DataType6() {
const [firstName, setFirstName] = useState('');
const [additionalEntries, setAdditionalEntries] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleFirstNameChange = (e) => {
setFirstName(e.target.value);
};
const handleAddFields = () => {
setAdditionalEntries([...additionalEntries, { name: '', description: '' }]);
};
const handleNameChange = (index, e) => {
const updatedEntries = [...additionalEntries];
updatedEntries[index].name = e.target.value;
setAdditionalEntries(updatedEntries);
};
const handleDescriptionChange = (index, e) => {
const updatedEntries = [...additionalEntries];
updatedEntries[index].description = e.target.value;
setAdditionalEntries(updatedEntries);
};
const handleSubmit = (e) => {
e.preventDefault();
const formData = {
Name: firstName,
test2: additionalEntries,
};
console.log(JSON.stringify(formData));
};
return (
<div style={{marginTop:"11rem"}}>
{loading ? (
<Spinner/>
):(
<div className="container mt-5" style={{ maxWidth: '700px' }}>
<div className="card p-4 shadow-lg border-0 rounded">
<h2 className="text-center mb-4 title_main" style={{ fontWeight: 'bold' }}>
Test 2
</h2>
<form onSubmit={handleSubmit}>
{/* First Name Field */}
<div className="form-group mb-3">
<label htmlFor="first-name" className="form-label fw-semibold">
First Name:
</label>
<input
type="text"
id="first-name"
name="first-name"
className="form-control shadow-sm custom-hover-border"
value={firstName}
onChange={handleFirstNameChange}
placeholder="Enter your name"
required
/>
</div>
{/* Section Header */}
<h3 className="mt-4 mb-3 title_main" style={{ fontWeight: 'bold' }}>
Add Test
</h3>
{/* Dynamic Fields */}
{additionalEntries.map((entry, index) => (
<div className="p-3 mb-3 border rounded shadow-sm" key={index}>
<div className="form-group mb-3">
<label htmlFor={`additional-name-${index}`} className="form-label fw-semibold">
Name:
</label>
<input
type="text"
id={`additional-name-${index}`}
name={`additional-name-${index}`}
className="form-control shadow-sm custom-hover-border"
value={entry.name}
onChange={(e) => handleNameChange(index, e)}
placeholder="Enter additional name"
required
/>
</div>
<div className="form-group mb-3">
<label htmlFor={`additional-description-${index}`} className="form-label fw-semibold">
Description:
</label>
<textarea
id={`additional-description-${index}`}
name={`additional-description-${index}`}
className="form-control shadow-sm custom-hover-border"
rows="3"
value={entry.description}
onChange={(e) => handleDescriptionChange(index, e)}
placeholder="Enter a description"
required
></textarea>
</div>
</div>
))}
{/* Buttons */}
<div className="d-flex justify-content-between mt-4">
<button
type="submit"
className="btn btn-primary btn-lg shadow-sm"
style={{
background: 'linear-gradient(90deg, #0E6591, #0B4C6A)',
border: 'none',
color: '#fff',
}}
>
Submit
</button>
<button
type="button"
className="btn btn-outline btn-lg shadow-sm custom_manage_column_button"
onClick={handleAddFields}
>
Add Entry
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}
export default DataType6;

View File

@@ -0,0 +1,387 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useLocation, useNavigate } from "react-router-dom";
import {
Container,
Row,
Col,
Table,
Button,
Dropdown,
Form,
Pagination,
} from "react-bootstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrash, faWrench, faPlus } from "@fortawesome/free-solid-svg-icons";
import Spinner from "../../../UIComponants/Spinner";
import "../CSS/CSS/CommonStyle.css";
import { BsJournals } from "react-icons/bs";
import { fetchForms, deleteForm } from "../../../APIServices/DynamicFormAPI";
import { toast } from "react-toastify";
const DynamicForm2 = () => {
const [forms, setForms] = useState([]);
const [error, setError] = useState(null);
const [filteredForms, setFilteredForms] = useState([]);
const [visibleColumns, setVisibleColumns] = useState({
formName: true,
formDescription: true,
relatedTo: true,
pageEvent: true,
buttonCaption: true,
goToForm: true,
});
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const location = useLocation();
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 3000);
}, []);
useEffect(() => {
if (location.state && location.state.formData) {
setForms((prevForms) =>
Array.isArray(prevForms)
? [...prevForms, location.state.formData]
: [location.state.formData]
);
} else {
fetchForms();
}
}, [location.state]);
useEffect(() => {
// Check if forms is an array before attempting to filter it
if (Array.isArray(forms)) {
const filtered = forms.filter((form) =>
Object.values(form).some(
(value) =>
typeof value === "string" &&
value.toLowerCase().includes(searchQuery.toLowerCase())
)
);
setFilteredForms(filtered);
}
}, [searchQuery, forms]);
useEffect(() => {
// loadForms();
console.log("useEffect for loadForms triggered");
if (location.state && location.state.formData) {
console.log(
"Adding form data from location state:",
location.state.formData
);
setForms((prevForms) =>
Array.isArray(prevForms)
? [...prevForms, location.state.formData]
: [location.state.formData]
);
}
console.log("Calling loadForms()");
loadForms();
}, [location.state]);
const loadForms = async () => {
console.log("loadForms function is called");
try {
const formData = await fetchForms();
console.log("data fetching on form", formData);
toast.success("Successfully fetched data!");
setForms(formData);
} catch (error) {
setError("error fetching data ", error.message);
toast.error("Error fetching data!");
} finally {
setLoading(false);
}
};
const handleDelete = async (formId) => {
console.log("Deleting data with ID:", formId);
if (!formId) {
toast.error("Invalid ID. Unable to delete.");
return;
}
try {
// const apiUrl = `${process.env.REACT_APP_API_URL}/api/form_setup/${id}`;
// const token = localStorage.getItem("authToken");
// await axios.delete(apiUrl, {
// headers: {
// "Content-Type": "application/json",
// Authorization: `Bearer ${token}`,
// },
// });
const deleteFormData = await deleteForm(formId);
toast.success("Successfully deleted data!");
console.log("Deleted data:", deleteFormData);
setForms((prevForms) => {
return prevForms.filter((form) => {
return form.id !== formId;
});
});
} catch (error) {
console.error("Error deleting data:", error);
toast.error("Error deleting data!");
}
};
const handleBuild = async (id) => {
try {
const apiUrl = `${process.env.REACT_APP_API_URL}/api/dynamic_form_build`;
const token = localStorage.getItem("authToken");
await axios.post(
apiUrl,
{ id },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);
} catch (error) {
console.error("Error building form:", error);
}
};
const handleAdd = () => {
navigate("/admin/dynamic-form-add");
};
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({ ...prev, [column]: !prev[column] }));
};
const handleSearchChange = (event) => {
setSearchQuery(event.target.value);
};
const handleRecordsPerPageChange = (records) => {
setRecordsPerPage(records);
setCurrentPage(1); // Reset to the first page
};
const handlePageChange = (page) => {
setCurrentPage(page);
};
const totalPages = Math.ceil(filteredForms.length / recordsPerPage);
const currentRecords = filteredForms.slice(
(currentPage - 1) * recordsPerPage,
currentPage * recordsPerPage
);
return (
<div style={{ marginTop: "11rem" }}>
{loading ? (
<Spinner />
) : (
<Container
fluid
style={{ maxWidth: "95%", margin: "0 auto", overflowX: "hidden" }}
>
<Row>
<Col>
<h1 className="title_main">Dynamic Form</h1>
</Col>
</Row>
<Row className="mb-3">
<Col md={6}>
<Form.Control
type="text"
placeholder="Search forms..."
value={searchQuery}
onChange={handleSearchChange}
/>
</Col>
<Col md={6} className="text-end">
<Button
color="primary"
onClick={handleAdd}
className="custom_button"
>
<FontAwesomeIcon icon={faPlus} /> Add
</Button>
</Col>
</Row>
<Row>
<Col>
<div className="table-wrapper">
<Table
striped
hover
responsive
className="table-flush shadow-sm"
align="middle"
>
<thead className="table-light custom_header">
<tr>
{visibleColumns.formName && <th>Form Name</th>}
{visibleColumns.formDescription && (
<th>Form Description</th>
)}
{visibleColumns.relatedTo && <th>Related To</th>}
{visibleColumns.pageEvent && <th>Page Event</th>}
{visibleColumns.buttonCaption && <th>Button Caption</th>}
{visibleColumns.goToForm && <th>Go To Form</th>}
<th>Actions</th>
</tr>
</thead>
<tbody>
{currentRecords.length > 0 ? (
currentRecords.map((form, index) => (
<tr key={index}>
{visibleColumns.formName && <td>{form.formName}</td>}
{visibleColumns.formDescription && (
<td>{form.formDescription}</td>
)}
{visibleColumns.relatedTo && (
<td>{form.relatedTo}</td>
)}
{visibleColumns.pageEvent && (
<td>{form.pageEvent}</td>
)}
{visibleColumns.buttonCaption && (
<td>{form.buttonCaption}</td>
)}
{visibleColumns.goToForm && <td>{form.goToForm}</td>}
<td>
<FontAwesomeIcon
icon={faWrench}
color="blue"
style={{ cursor: "pointer" }}
onClick={() => handleBuild(form.id)}
/>
<FontAwesomeIcon
icon={faTrash}
color="red"
style={{ cursor: "pointer", marginLeft: "10px" }}
onClick={() => {
if (!form.id) {
console.error("Invalid form ID:", form);
toast.error("Cannot delete: Invalid ID!");
return;
}
handleDelete(form.form_id);
}}
/>
</td>
</tr>
))
) : (
<tr>
<td colSpan="8" className="text-center text-muted">
No forms available. Click "Add" to create a new one.
</td>
</tr>
)}
</tbody>
</Table>
</div>
</Col>
</Row>
<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}
checked={visibleColumns[column]}
readOnly
/>
</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 justify-content-center mt-4">
<Pagination.First
disabled={currentPage === 1}
onClick={() => handlePageChange(1)}
/>
<Pagination.Prev
disabled={currentPage === 1}
onClick={() => handlePageChange(currentPage - 1)}
/>
{[...Array(totalPages)].map((_, index) => (
<Pagination.Item
key={index + 1}
active={currentPage === index + 1}
onClick={() => handlePageChange(index + 1)}
>
{index + 1}
</Pagination.Item>
))}
<Pagination.Next
disabled={currentPage === totalPages}
onClick={() => handlePageChange(currentPage + 1)}
/>
<Pagination.Last
disabled={currentPage === totalPages}
onClick={() => handlePageChange(totalPages)}
/>
</Pagination>
</Container>
)}
</div>
);
};
export default DynamicForm2;

View File

@@ -0,0 +1,479 @@
// import React, { useState,useEffect } from 'react';
// import { Box, Button, TextField, Select, MenuItem, FormControl, InputLabel, Checkbox, IconButton, Typography, FormControlLabel } from '@mui/material';
// import DeleteIcon from '@mui/icons-material/Delete';
// import { useNavigate } from 'react-router-dom';
// import Spinner from '../../UIComponants/Spinner';
// function DynamicForm() {
// const [loading, setLoading] = useState(true);
// const [components, setComponents] = useState([{ label: '', type: '', mapping: '', readonly: false, values: '' }]);
// const [formDetails, setFormDetails] = useState({
// formName: '',
// formDescription: '',
// relatedTo: '',
// pageEvent: '',
// buttonName: '',
// });
// useEffect(() => {
// // Simulate loading data
// setTimeout(() => {
// setLoading(false);
// }, 3000); // Simulated 3 seconds loading
// }, []);
// const navigate = useNavigate();
// const handleFormChange = (e) => {
// const { name, value } = e.target;
// setFormDetails({ ...formDetails, [name]: value });
// };
// const handleComponentChange = (index, field, value) => {
// const updatedComponents = components.map((component, i) => (i === index ? { ...component, [field]: value } : component));
// setComponents(updatedComponents);
// };
// const addComponent = () => {
// setComponents([...components, { label: '', type: '', mapping: '', readonly: false, values: '' }]);
// };
// const removeComponent = (index) => {
// setComponents(components.filter((_, i) => i !== index));
// };
// const handleSubmit = (e) => {
// e.preventDefault();
// const formData = { ...formDetails, components };
// navigate('/Dynamictable', { state: { formData } }); // Navigate to DynamicTable with formData
// };
// return (
// <div>
// {loading ? (
// <Spinner/>
// ):(
// <Box sx={{ padding: '20px' }}>
// <Typography variant="h4" gutterBottom>Dynamic Form Setup</Typography>
// <form onSubmit={handleSubmit}>
// <Box sx={{ display: 'flex', gap: '20px', marginBottom: '20px' }}>
// <TextField
// label="Form Name"
// name="formName"
// value={formDetails.formName}
// onChange={handleFormChange}
// fullWidth
// />
// <TextField
// label="Form Description"
// name="formDescription"
// value={formDetails.formDescription}
// onChange={handleFormChange}
// fullWidth
// />
// <FormControl fullWidth>
// <InputLabel>Related To</InputLabel>
// <Select
// name="relatedTo"
// value={formDetails.relatedTo}
// onChange={handleFormChange}
// >
// <MenuItem value=""><em>None</em></MenuItem>
// <MenuItem value="Menu">Menu</MenuItem>
// <MenuItem value="Related to">Related to</MenuItem>
// </Select>
// </FormControl>
// </Box>
// <Box sx={{ display: 'flex', gap: '20px', marginBottom: '20px' }}>
// <FormControl fullWidth>
// <InputLabel>Page Event</InputLabel>
// <Select
// name="pageEvent"
// value={formDetails.pageEvent}
// onChange={handleFormChange}
// >
// <MenuItem value="Onclick">Onclick</MenuItem>
// <MenuItem value="Onblur">Onblur</MenuItem>
// </Select>
// </FormControl>
// <TextField
// label="Button Name"
// name="buttonName"
// value={formDetails.buttonName}
// onChange={handleFormChange}
// fullWidth
// />
// </Box>
// <Typography variant="h6" gutterBottom>Component Details</Typography>
// {components.map((component, index) => (
// <Box key={index} sx={{ display: 'flex', gap: '10px', alignItems: 'center', marginBottom: '10px' }}>
// <TextField
// label="Label"
// value={component.label}
// onChange={(e) => handleComponentChange(index, 'label', e.target.value)}
// fullWidth
// />
// <FormControl fullWidth>
// <InputLabel>Type</InputLabel>
// <Select
// value={component.type}
// onChange={(e) => handleComponentChange(index, 'type', e.target.value)}
// >
// <MenuItem value=""><em>None</em></MenuItem>
// <MenuItem value="textfield">TextField</MenuItem>
// <MenuItem value="checkbox">Checkbox</MenuItem>
// <MenuItem value="select">Select</MenuItem>
// </Select>
// </FormControl>
// <TextField
// label="Mapping"
// value={component.mapping}
// onChange={(e) => handleComponentChange(index, 'mapping', e.target.value)}
// fullWidth
// />
// <FormControlLabel
// control={
// <Checkbox
// checked={component.readonly}
// onChange={(e) => handleComponentChange(index, 'readonly', e.target.checked)}
// />
// }
// label="Readonly"
// />
// <TextField
// label="Enter Values"
// value={component.values}
// onChange={(e) => handleComponentChange(index, 'values', e.target.value)}
// fullWidth
// />
// <IconButton onClick={() => removeComponent(index)}>
// <DeleteIcon />
// </IconButton>
// </Box>
// ))}
// <Button onClick={addComponent} variant="contained" sx={{ marginBottom: '20px' }}>Add Component</Button>
// <Button type="submit" variant="contained" color="primary">Submit</Button>
// </form>
// </Box>
// )}
// </div>
// );
// }
// export default DynamicForm;
import React, { useState, useEffect } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrash } from "@fortawesome/free-solid-svg-icons";
import {
Button,
Form,
FormGroup,
Label,
Input,
FormText,
Row,
Col,
Card,
CardBody,
CardTitle,
} from "reactstrap";
import { useNavigate } from "react-router-dom";
import Spinner from "UIComponants/Spinner";
import { buildForm } from '../../../APIServices/DynamicFormAPI';
import { toast } from "react-toastify";
function DynamicFormAdd() {
const [loading, setLoading] = useState(true);
const [components, setComponents] = useState([
{ label: "", type: "", mapping: "", readonly: false, values: "" },
]);
const [formDetails, setFormDetails] = useState({
formName: "",
formDescription: "",
relatedTo: "",
pageEvent: "",
buttonName: "",
});
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const navigate = useNavigate();
const handleFormChange = (e) => {
const { name, value } = e.target;
setFormDetails({ ...formDetails, [name]: value });
};
const handleComponentChange = (index, field, value) => {
const updatedComponents = components.map((component, i) =>
i === index ? { ...component, [field]: value } : component
);
setComponents(updatedComponents);
};
const addComponent = () => {
setComponents([
...components,
{ label: "", type: "", mapping: "", readonly: false, values: "" },
]);
};
const removeComponent = (index) => {
setComponents(components.filter((_, i) => i !== index));
};
// const handleSubmit = async (id) => {
// try {
// const {status} = await buildForm(id);
// if(status >= 200 && status <= 209){
// console.log("Form built successfully");
// toast.success('Form built successfully');
// const formData = { ...formDetails, components };
// navigate("/admin/dynamic-form", { state: { formData } });
// }else{
// toast.error('Error building form');
// console.log("Error building form");
// }
// } catch (error) {
// console.error("Error saving form:", error);
// toast.error(error || 'Error saving form');
// }
// };
// const handleSubmit = async (id) => {
// try {
// console.log("Form data to be submitted:", formDetails, components);
// const { status } = await buildForm(id); // Ensure `id` is defined
// if (status >= 200 && status <= 209) {
// console.log("Form built successfully");
// toast.success("Form built successfully");
// const formData = { ...formDetails, components };
// navigate("/admin/dynamic-form", { state: { formData } });
// } else {
// toast.error("Error building form");
// console.log("Error response status:", status);
// }
// } catch (error) {
// console.error("Error submitting form:", error);
// toast.error("Error submitting form");
// }
// };
const handleSubmit = async (e) => {
e.preventDefault();
try {
// Combine formDetails and components for the API payload
const formData = {
...formDetails,
components,
};
console.log("Form data to be submitted:", formData);
const { status } = await buildForm(formData); // Pass formData to the API call
if (status >= 200 && status <= 209) {
toast.success("Form built successfully");
navigate("/admin/dynamic-form", { state: { formData } });
} else {
toast.error("Error building form");
console.log("Error response status:", status);
}
} catch (error) {
console.error("Error submitting form:", error);
toast.error("Error submitting form");
}
};
return (
<div style={{ marginTop: "11rem" }}>
{loading ? (
<Spinner/>
) : (
<Card className="p-4 mb-7">
<CardBody>
<CardTitle tag="h4">Dynamic Form Setup</CardTitle>
<Form onSubmit={handleSubmit}>
<Row className="mb-3">
<Col md={4}>
<FormGroup>
<Label for="formName">Form Name</Label>
<Input
type="text"
id="formName"
name="formName"
value={formDetails.formName}
onChange={handleFormChange}
/>
</FormGroup>
</Col>
<Col md={4}>
<FormGroup>
<Label for="formDescription">Form Description</Label>
<Input
type="text"
id="formDescription"
name="formDescription"
value={formDetails.formDescription}
onChange={handleFormChange}
/>
</FormGroup>
</Col>
<Col md={4}>
<FormGroup>
<Label for="relatedTo">Related To</Label>
<Input
type="select"
id="relatedTo"
name="relatedTo"
value={formDetails.relatedTo}
onChange={handleFormChange}
>
<option value="">Select</option>
<option value="Menu">Menu</option>
<option value="Related to">Related to</option>
</Input>
</FormGroup>
</Col>
</Row>
<Row className="mb-3">
<Col md={6}>
<FormGroup>
<Label for="pageEvent">Page Event</Label>
<Input
type="select"
id="pageEvent"
name="pageEvent"
value={formDetails.pageEvent}
onChange={handleFormChange}
>
<option value="Onclick">Onclick</option>
<option value="Onblur">Onblur</option>
</Input>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label for="buttonName">Button Name</Label>
<Input
type="text"
id="buttonName"
name="buttonName"
value={formDetails.buttonName}
onChange={handleFormChange}
/>
</FormGroup>
</Col>
</Row>
<h5>Component Details</h5>
{components.map((component, index) => (
<Row key={index} className="align-items-center mb-3">
<Col md={2}>
<FormGroup>
<Input
type="text"
placeholder="Label"
value={component.label}
onChange={(e) =>
handleComponentChange(index, "label", e.target.value)
}
/>
</FormGroup>
</Col>
<Col md={2}>
<FormGroup>
<Input
type="select"
value={component.type}
onChange={(e) =>
handleComponentChange(index, "type", e.target.value)
}
>
<option value="">Type</option>
<option value="textfield">TextField</option>
<option value="checkbox">Checkbox</option>
<option value="select">Select</option>
</Input>
</FormGroup>
</Col>
<Col md={2}>
<FormGroup>
<Input
type="text"
placeholder="Mapping"
value={component.mapping}
onChange={(e) =>
handleComponentChange(
index,
"mapping",
e.target.value
)
}
/>
</FormGroup>
</Col>
<Col md={2}>
<FormGroup check>
<Label check>
<Input
type="checkbox"
checked={component.readonly}
onChange={(e) =>
handleComponentChange(
index,
"readonly",
e.target.checked
)
}
/>{" "}
Readonly
</Label>
</FormGroup>
</Col>
<Col md={2}>
<FormGroup>
<Input
type="text"
placeholder="Values"
value={component.values}
onChange={(e) =>
handleComponentChange(index, "values", e.target.value)
}
/>
</FormGroup>
</Col>
<Col md={2}>
<FontAwesomeIcon
icon={faTrash}
className="text-danger cursor-pointer"
onClick={() => removeComponent(index)}
title="Remove"
/>
</Col>
</Row>
))}
<Button color="primary" onClick={addComponent} className="me-3">
Add Component
</Button>
<Button color="success" type="submit" onClick={handleSubmit}>
Submit
</Button>
</Form>
</CardBody>
</Card>
)}
</div>
);
}
export default DynamicFormAdd;

View File

@@ -0,0 +1,9 @@
import React from 'react'
const MappingRule = () => {
return (
<div>MappingRule</div>
)
}
export default MappingRule

View File

@@ -0,0 +1,723 @@
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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
import React from 'react'
const MultiDynamicsBugs = () => {
return (
<div>MultiDynamicsBugs</div>
)
}
export default MultiDynamicsBugs

View File

@@ -0,0 +1,936 @@
import React, { useEffect, useState } from "react";
import { fetchStandardParameters, downloadFile } from "../../../APIServices/ReportRunnerAPI";
import ReportBuilderService from "../../../APIServices/ReportBuilderService";
import { toast } from "react-toastify";
import './ReportrunnerEdit.css'
import { saveAs } from 'file-saver';
import axios from 'axios';
import { useNavigate, useParams } from 'react-router-dom';
const ReportRunner2Edit = () => {
const navigate = useNavigate();
const { id } = useParams();
// Report data state
const [reportName, setReportName] = useState("Sample Report");
const [reportId, setReportId] = useState(id || null);
// Date parameters state
const [dateParam, setDateParam] = useState(true);
const [selectDateType, setSelectDateType] = useState("");
const [fromDate, setFromDate] = useState("");
const [toDate, setToDate] = useState("");
const [fromDateQuery, setFromDateQuery] = useState("");
const [toDateQuery, setToDateQuery] = useState("");
// Standard parameters state
const [dynamicFields, setDynamicFields] = useState([]);
const [dynamicFormValues, setDynamicFormValues] = useState({});
// Adhoc parameters state
const [adhocList, setAdhocList] = useState([]);
const [adhocParams, setAdhocParams] = useState([
{ andor: "AND", fields_name: "", condition: "=", value: "" },
]);
// Condition options
const conditionOptions = ["=", "!=", "<", ">", "<=", ">=", "LIKE", "BETWEEN", "IN"];
const andOrOptions = ["AND", "OR", "NOT"];
// Results state
const [rows, setRows] = useState([]);
const [filterRows, setFilterRows] = useState([]);
const [filtered, setFiltered] = useState(false);
const [headers, setHeaders] = useState([]);
// Query state
const [SQLQuery, setSQLQuery] = useState('');
const [dateKey, setDateKey] = useState('createdat');
const [formattedAdhocParameters, setFormattedAdhocParameters] = useState('');
const [selectedValues, setSelectedValues] = useState({});
// Loading state
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
// Get today's date
const todayDate = new Date().toISOString().slice(0, 10);
// Add this at the beginning of the component with other state variables
const [showExportDropdown, setShowExportDropdown] = useState(false);
useEffect(() => {
// Fetch report details
if (reportId) {
fetchReportDetails(reportId);
}
// Set default date to today
handleDateSelect('Today');
// Run query after a delay to allow data to load
const timer = setTimeout(() => {
runQuery();
}, 2000);
return () => clearTimeout(timer);
}, [reportId]);
useEffect(() => {
// Function to handle clicks outside the dropdown
const handleClickOutside = (event) => {
// Get reference to the dropdown container
const dropdownContainer = document.getElementById('export-dropdown-container');
// Close dropdown if click is outside the container
if (dropdownContainer && !dropdownContainer.contains(event.target)) {
setShowExportDropdown(false);
}
};
// Function to handle escape key press
const handleEscapeKey = (event) => {
if (event.key === 'Escape') {
setShowExportDropdown(false);
}
};
// Add event listeners if dropdown is open
if (showExportDropdown) {
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('keydown', handleEscapeKey);
}
// Clean up event listeners when dropdown closes or component unmounts
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('keydown', handleEscapeKey);
};
}, [showExportDropdown]);
const fetchReportDetails = async (id) => {
try {
setIsLoading(true);
// Fetch report details
const response = await ReportBuilderService.getrbDetailsById(id);
const data = response?.data;
if (!data) {
throw new Error("No data received from the API");
}
console.log("Report details received:", data);
setReportName(data.reportName);
// Parse builder line data
const builderLine = data.rpt_builder2_lines?.[0];
if (builderLine) {
const lineData = JSON.parse(builderLine.model)?.[0];
console.log("lineData: ",lineData);
if (lineData) {
setAdhocList(lineData.adhoc_param_html || []);
setDateParam(lineData.date_param_req || false);
setSQLQuery(lineData.url || "");
// Set dynamic fields from standard parameters
const dynamicFields = lineData.std_param_html || [];
setDynamicFields(dynamicFields);
// Initialize dynamic form values
const initialFormValues = dynamicFields.reduce((acc, field) => {
acc[field] = "";
return acc;
}, {});
setDynamicFormValues(initialFormValues);
// Fetch data if a URL exists
if (lineData.url) {
fetchData(lineData.url);
}
}
}
} catch (error) {
console.error("Error fetching report details:", error);
setError("Error loading report details");
toast.error("Failed to load report details");
} finally {
setIsLoading(false);
}
};
const fetchData = async (url) => {
try {
const response = await ReportBuilderService.getAllDetailsByurl(url);
console.log("responce of data fetch from url:", response.data)
const data = response.data?.body ? JSON.parse(response.data.body) : [];
setRows(data);
setFilterRows(data);
// Set headers from the first row if available
if (data.length > 0) {
setHeaders(Object.keys(data[0]));
}
} catch (error) {
console.error("Error fetching data:", error);
setError("Error loading data");
}
};
// Handle changes to adhoc parameters
const handleAdhocChange = (index, field, value) => {
const updatedParams = [...adhocParams];
updatedParams[index][field] = value;
setAdhocParams(updatedParams);
};
// Add a new adhoc parameter row
const addAdhocRow = () => {
const lastRow = adhocParams[adhocParams.length - 1];
// Only add a new row if the last row has a field name
if (lastRow && lastRow.fields_name !== '') {
// Format the adhoc parameters for the query
let formattedString = '';
for (const condition of adhocParams) {
const { andor, fields_name, condition: cond, value } = condition;
formattedString += ` ${andor} ${fields_name} ${cond} '${value}' `;
}
setFormattedAdhocParameters(formattedString);
// Add a new row
setAdhocParams([
...adhocParams,
{ andor: "AND", fields_name: "", condition: "=", value: "" },
]);
// Update selected values for filtering
selectColumn(adhocParams);
}
};
// Delete an adhoc parameter row
const deleteAdhocRow = (index) => {
if (adhocParams.length > 1) {
// Get the item to be deleted
const deletedItem = adhocParams[index];
// Remove the item from the adhocParams array
const updatedParams = adhocParams.filter((_, i) => i !== index);
setAdhocParams(updatedParams);
// Update selected values
const updatedSelectedValues = { ...selectedValues };
const columnName = deletedItem.fields_name;
if (updatedSelectedValues[columnName]) {
const value = deletedItem.value;
const indexInArray = updatedSelectedValues[columnName].indexOf(value);
if (indexInArray !== -1) {
updatedSelectedValues[columnName].splice(indexInArray, 1);
// If the array is now empty, remove the property
if (updatedSelectedValues[columnName].length === 0) {
delete updatedSelectedValues[columnName];
}
}
}
setSelectedValues(updatedSelectedValues);
filterRowsBySelectedValues(updatedSelectedValues);
}
};
// Handle dynamic form values change
const handleDynamicFormChange = (field, value) => {
setDynamicFormValues({
...dynamicFormValues,
[field]: value
});
};
// Handle date type selection
const handleDateSelect = (dateType) => {
setSelectDateType(dateType);
setFromDateQuery(null);
setToDateQuery(null);
const currentDate = new Date();
let fromDateValue, toDateValue;
switch (dateType) {
case 'Today':
fromDateValue = new Date();
toDateValue = new Date();
break;
case 'This Week':
// Calculate this week (Monday to Sunday)
const dayOfWeek = currentDate.getDay();
const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
fromDateValue = new Date(currentDate);
fromDateValue.setDate(currentDate.getDate() - daysToMonday);
toDateValue = new Date(fromDateValue);
toDateValue.setDate(fromDateValue.getDate() + 6);
break;
case 'Last Week':
// Calculate last week
const lastWeekDayOfWeek = currentDate.getDay();
const lastWeekDaysToMonday = lastWeekDayOfWeek === 0 ? 6 : lastWeekDayOfWeek - 1;
fromDateValue = new Date(currentDate);
fromDateValue.setDate(currentDate.getDate() - lastWeekDaysToMonday - 7);
toDateValue = new Date(fromDateValue);
toDateValue.setDate(fromDateValue.getDate() + 6);
break;
case 'This Month':
// First day of current month
fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
// Last day of current month
toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
break;
case 'Last Month':
// First day of previous month
fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
// Last day of previous month
toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0);
break;
case 'This Year':
// First day of current year
fromDateValue = new Date(currentDate.getFullYear(), 0, 1);
// Last day of current year
toDateValue = new Date(currentDate.getFullYear(), 11, 31);
break;
case 'Last Year':
// First day of previous year
fromDateValue = new Date(currentDate.getFullYear() - 1, 0, 1);
// Last day of previous year
toDateValue = new Date(currentDate.getFullYear() - 1, 11, 31);
break;
default:
fromDateValue = null;
toDateValue = null;
}
if (fromDateValue) {
const fromDateString = fromDateValue.toISOString().substring(0, 10);
setFromDate(fromDateString);
setFromDateQuery(fromDateString);
} else {
setFromDate('');
setFromDateQuery('');
}
if (toDateValue) {
const toDateString = toDateValue.toISOString().substring(0, 10);
setToDate(toDateString);
setToDateQuery(toDateString);
} else {
setToDate('');
setToDateQuery('');
}
};
// Run the query
const runQuery = () => {
console.log("Dynamic form values:", dynamicFormValues);
console.log("Date range:", fromDate, toDate);
let query = SQLQuery || '';
// Add standard parameters to the query
if (Object.keys(dynamicFormValues).length > 0) {
Object.keys(dynamicFormValues).forEach((key) => {
if (dynamicFormValues[key] !== null && dynamicFormValues[key] !== '') {
query += ` AND ${key} = '${dynamicFormValues[key]}'`;
}
});
// Update selected values for filtering
selectColumn(dynamicFormValues);
}
// Add date range to the query if date parameter is required
if (dateParam) {
// Determine the correct date key based on adhoc list
let tempDateKey = 'createdat';
adhocList.forEach(key => {
if (key.includes('created_at')) tempDateKey = 'created_at';
if (key.includes('createdAt')) tempDateKey = 'createdAt';
});
setDateKey(tempDateKey);
if (fromDate && toDate) {
const fromDateObj = new Date(fromDate);
const toDateObj = new Date(toDate);
query += ` AND ${tempDateKey} BETWEEN '${fromDateObj.toISOString().split('T')[0]}' AND '${toDateObj.toISOString().split('T')[0]}'`;
}
}
// Format and add adhoc parameters to the query
let formattedString = '';
for (const condition of adhocParams) {
// Only add conditions that have a field name selected
if (condition.fields_name) {
const { andor, fields_name, condition: cond, value } = condition;
formattedString += ` ${andor} ${fields_name} ${cond} '${value}' `;
}
}
setFormattedAdhocParameters(formattedString);
// Add adhoc parameters to the query
if (formattedString) {
query += formattedString;
}
// Update selected values for filtering based on adhoc parameters
selectColumn(adhocParams.filter(param => param.fields_name));
console.log("Final query:", query);
// Make API request
// axios.post('/api/report-runner/run', { query })
// .then((response) => {
// const data = response.data;
// if (data && data.length > 0) {
// setRows(data);
// setFilterRows(data);
// setHeaders(Object.keys(data[0]));
// toast.success("Query executed successfully");
// } else {
// toast.warning("No data returned");
// }
// })
// .catch((error) => {
// console.error("Error running query:", error);
// toast.error("Error running the query");
// });
};
// Export file function
const exportFile = (format) => {
try {
const dataToExport = filtered ? filterRows : rows;
if (!dataToExport || dataToExport.length === 0) {
toast.warning("No data to export");
return;
}
const name = reportName.replace(/\s+/g, '_');
const timestamp = new Date().toISOString().replace(/[-:T.]/g, '_').slice(0, 17);
const fileName = `${name}_${timestamp}`;
// Show loading toast
const loadingToast = toast.info("Preparing file for export...", { autoClose: false });
// Use the imported downloadFile service
downloadFile(format, dataToExport, fileName);
// Success message
setTimeout(() => {
toast.dismiss(loadingToast);
toast.success(`File exported as ${format.toUpperCase()} successfully`);
}, 1000);
} catch (error) {
console.error("Error in export function:", error);
toast.error("Error exporting file");
}
};
// Get table headers
const getHeaders = () => {
if (!rows || rows.length === 0) return [];
const headerSet = new Set();
rows.forEach(row => {
Object.keys(row).forEach(key => headerSet.add(key));
});
return Array.from(headerSet);
};
// Get filtered table headers
const getFilteredHeaders = () => {
if (!filterRows || filterRows.length === 0) return [];
const headerSet = new Set();
filterRows.forEach(row => {
Object.keys(row).forEach(key => headerSet.add(key));
});
return Array.from(headerSet);
};
// Check if a value is a date
const isDate = (value) => {
if (!value) return false;
if (value instanceof Date) return true;
if (typeof value === 'object' &&
value.year !== undefined &&
value.monthValue !== undefined &&
value.dayOfMonth !== undefined) {
return true;
}
const date = new Date(value);
return !isNaN(date.getTime());
};
// Format a date for display
const formatDate = (value) => {
if (!value) return '';
if (typeof value === 'object' &&
value.year !== undefined &&
value.monthValue !== undefined &&
value.dayOfMonth !== undefined) {
// Handle Java-style date objects
const { year, monthValue, dayOfMonth, hour = 0, minute = 0, second = 0 } = value;
const date = new Date(year, monthValue - 1, dayOfMonth, hour, minute, second);
return date.toLocaleString();
}
// Standard JS date
return new Date(value).toLocaleString();
};
// Process data for filtering
const selectColumn = (data) => {
const newSelectedValues = { ...selectedValues };
if (Array.isArray(data)) {
// Handle array of objects (like adhoc parameters)
data.forEach(item => {
const { fields_name, value } = item;
if (fields_name && fields_name.trim() !== '') {
if (!newSelectedValues[fields_name]) {
newSelectedValues[fields_name] = [];
}
if (value !== null && value.trim() !== '') {
if (!newSelectedValues[fields_name].includes(value)) {
newSelectedValues[fields_name].push(value);
}
}
}
});
} else if (typeof data === 'object') {
// Handle object (like dynamic form values)
Object.keys(data).forEach(key => {
const value = data[key];
if (!newSelectedValues[key]) {
newSelectedValues[key] = [];
}
if (value !== null && value.trim && value.trim() !== '') {
if (!newSelectedValues[key].includes(value)) {
newSelectedValues[key].push(value);
}
}
});
}
setSelectedValues(newSelectedValues);
filterRowsBySelectedValues(newSelectedValues);
};
// Filter rows based on selected values
const filterRowsBySelectedValues = (values = selectedValues) => {
const filteredRows = [];
for (const row of rows) {
let isMatch = true;
// Check each column in the selected values
for (const columnName in values) {
if (values.hasOwnProperty(columnName) && row.hasOwnProperty(columnName)) {
const selectedValuesForColumn = values[columnName];
const rowValue = row[columnName];
if (typeof rowValue === 'boolean') {
// Handle boolean values
if (selectedValuesForColumn.length === 0) continue;
const selectedBooleanValue = selectedValuesForColumn[0] === 'true';
if (selectedBooleanValue !== rowValue) {
isMatch = false;
break;
}
} else {
// Handle other data types
const convertedValues = selectedValuesForColumn.map(value => {
if (typeof rowValue === 'number') {
return parseFloat(value);
}
return value;
});
if (!convertedValues.includes(rowValue)) {
isMatch = false;
break;
}
}
}
}
// Check date range if both dates are provided
if (fromDateQuery && toDateQuery && isMatch) {
const from = new Date(fromDateQuery);
const to = new Date(toDateQuery);
// Set hours to 0 for proper comparison
from.setHours(0, 0, 0, 0);
to.setHours(23, 59, 59, 999);
// Get the date from the row using dateKey
const rowDate = new Date(row[dateKey]);
if (rowDate < from || rowDate > to) {
isMatch = false;
}
}
if (isMatch) {
filteredRows.push(row);
}
}
setFilterRows(filteredRows);
// Determine if we are filtering or not
const isFiltering = Object.values(values).some(arr => arr.length > 0) ||
(fromDateQuery && toDateQuery);
setFiltered(isFiltering);
};
// Render date cell with formatting
const renderTableCell = (row, key) => {
const isDateField = key === 'createdat' || key === 'createdAt' ||
key === 'updated_at' || key === 'updatedAt' ||
key === 'created_at' || key === 'creat_at';
if (isDateField && row[key]) {
return formatDate(row[key]);
}
// Handle boolean values
if (typeof row[key] === 'boolean') {
return row[key] ? 'True' : 'False';
}
return row[key];
};
// Navigate back to the reports list
const goBack = () => {
navigate("/admin/report-runner");
};
// Add this function at an appropriate place in the component
const toggleExportDropdown = () => {
setShowExportDropdown(!showExportDropdown);
};
return (
<div className="container">
{/* Report Header */}
<h4 style={{ fontWeight: 300, display: "inline" }}>
<b>Report Name URL - {reportName}</b>
</h4>
<hr />
{/* Date and Standard Parameters Section */}
<div className="row">
{/* Date Parameters */}
{/* {dateParam && (
<div className="col-md-6">
<h5 style={{ fontWeight: 200, color: "black" }}>
<b>Date Range</b>
</h5>
<div className="form-group mb-3">
<label>Date Parameters</label>
<select
className="form-select"
value={selectDateType}
onChange={(e) => handleDateSelect(e.target.value)}
>
<option>--Select Particular--</option>
<option>Today</option>
<option>This Week</option>
<option>Last Week</option>
<option>This Month</option>
<option>Last Month</option>
<option>This Year</option>
<option>Last Year</option>
</select>
</div>
<div className="row">
<div className="col-md-6">
<label>From Date</label>
<input
type="date"
className="form-control"
value={fromDate}
onChange={(e) => {
setFromDate(e.target.value);
setFromDateQuery(e.target.value);
}}
/>
</div>
<div className="col-md-6">
<label>To Date</label>
<input
type="date"
className="form-control"
value={toDate}
onChange={(e) => {
setToDate(e.target.value);
setToDateQuery(e.target.value);
}}
/>
</div>
</div>
</div>
)} */}
{/* Standard Parameters */}
<div className="col-md-6">
<h5 style={{ fontWeight: 200, color: "black" }}>
<b>Standard Parameters</b>
</h5>
{dynamicFields.length === 0 ? (
<div className="text-danger">No parameter found</div>
) : (
<div className="row">
{dynamicFields.map((field, index) => (
<div key={index} className="col-md-6 mb-3">
<label>{field}</label>
<input
type="text"
className="form-control"
placeholder={`Enter ${field}`}
value={dynamicFormValues[field] || ''}
onChange={(e) => handleDynamicFormChange(field, e.target.value)}
/>
</div>
))}
</div>
)}
</div>
</div>
{/* Adhoc Parameters Section */}
<div className="row mt-4">
<div className="col-md-12">
<h5 style={{ fontWeight: 200, color: "black" }}>
<b>Adhoc Parameters</b>
</h5>
<table className="table">
<tbody>
{adhocParams.map((param, index) => (
<tr key={index}>
<td>
<select
className="form-select"
value={param.andor}
onChange={(e) =>
handleAdhocChange(index, "andor", e.target.value)
}
>
<option value="">Select Values</option>
{andOrOptions.map((option, idx) => (
<option key={idx} value={option}>
{option}
</option>
))}
</select>
</td>
<td>
<select
className="form-select"
value={param.fields_name}
onChange={(e) =>
handleAdhocChange(index, "fields_name", e.target.value)
}
>
<option value="">Select Values</option>
{adhocList.map((field, idx) => (
<option key={idx} value={field}>
{field}
</option>
))}
</select>
</td>
<td>
<select
className="form-select"
value={param.condition}
onChange={(e) =>
handleAdhocChange(index, "condition", e.target.value)
}
>
<option value="">Select Values</option>
{conditionOptions.map((condition, idx) => (
<option key={idx} value={condition}>
{condition}
</option>
))}
</select>
</td>
<td>
<input
type="text"
className="form-control"
value={param.value}
onChange={(e) =>
handleAdhocChange(index, "value", e.target.value)
}
/>
</td>
<td>
<button
className="btn btn-danger me-2"
onClick={() => deleteAdhocRow(index)}
title="Delete Row"
>
<i className="bi bi-trash"></i>
</button>
<button
className="btn btn-primary"
onClick={addAdhocRow}
title="Add Row"
>
<i className="bi bi-plus"></i>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Report Output Section */}
<div className="row mt-4">
<div className="col-md-6">
<h5 style={{ fontWeight: 300 }}>
<b>Report Output</b>
</h5>
</div>
<div className="col-md-6 text-end">
{/* Custom Export Dropdown */}
<div
id="export-dropdown-container"
className="d-inline-block me-2"
style={{ position: 'relative' }}
>
<button
type="button"
className="btn btn-outline-primary mr-3"
onClick={toggleExportDropdown}
>
<i className="bi bi-download me-1"></i> Export <i className="bi bi-caret-down-fill ms-1 small "></i>
</button>
{showExportDropdown && (
<div
className="shadow position-absolute end-0 bg-white border rounded mt-1 py-1"
style={{ zIndex: 1000, minWidth: '160px' }}
>
<button
type="button"
className="dropdown-item d-flex align-items-center px-3 py-2"
onClick={() => {
exportFile("xlsx");
setShowExportDropdown(false);
}}
>
<i className="bi bi-file-earmark-excel me-2 text-success"></i> XLSX
</button>
<button
type="button"
className="dropdown-item d-flex align-items-center px-3 py-2"
onClick={() => {
exportFile("csv");
setShowExportDropdown(false);
}}
>
<i className="bi bi-file-earmark-text me-2 text-primary"></i> CSV
</button>
<button
type="button"
className="dropdown-item d-flex align-items-center px-3 py-2"
onClick={() => {
exportFile("pdf");
setShowExportDropdown(false);
}}
>
<i className="bi bi-file-earmark-pdf me-2 text-danger"></i> PDF
</button>
</div>
)}
</div>
{/* Back and Run Buttons */}
<button className="btn btn-outline-secondary me-2" onClick={goBack}>
Back
</button>
<button className="btn btn-primary" onClick={runQuery}>
Run
</button>
</div>
</div>
<hr />
{/* Data Table */}
<div style={{ maxHeight: "500px", overflow: "auto", marginTop: "1rem" }}>
{isLoading ? (
<div className="text-center py-4">
<div className="spinner-border text-primary" role="status"></div>
<p className="mt-2">Loading data...</p>
</div>
) : error ? (
<div className="alert alert-danger">{error}</div>
) : (filtered ? filterRows : rows).length === 0 ? (
<div className="alert alert-info">No data available</div>
) : (
<table className="table table-striped">
<thead>
<tr>
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, index) => (
<th key={index}>{header}</th>
))}
</tr>
</thead>
<tbody>
{(filtered ? filterRows : rows).map((row, rowIndex) => (
<tr key={rowIndex}>
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, colIndex) => (
<td key={colIndex}>
{renderTableCell(row, header)}
</td>
))}
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
);
};
export default ReportRunner2Edit;

View File

@@ -0,0 +1,332 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { fetchAllReportsApi } from '../../../APIServices/ReportRunnerAPI';
const ReportRunnerAll = () => {
const [gridData, setGridData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");
const [rowSelected, setRowSelected] = useState(null);
const [modalDelete, setModalDelete] = useState(false);
const [reports, setReports] = useState([]);
const navigate = useNavigate();
useEffect(() => {
fetchAllReports();
}, []);
// const fetchAllReports = async () => {
// setIsLoading(true);
// try {
// const response = await fetch("/Report_builder/Report_builder"); // Replace with your API URL
// const data = await response.json();
// setGridData(data);
// setReports(data);
// if (data.length === 0) setError("No data Available");
// } catch (err) {
// console.error(err);
// setError("Error fetching data.");
// } finally {
// setIsLoading(false);
// }
// };
const fetchAllReports = async () => {
setIsLoading(true); // Set loading state to true
try {
const data = await fetchAllReportsApi(); // Call the API to fetch reports
console.log("Fetched all reports:", data);
setGridData(data); // Set the grid data state with the fetched reports
setReports(data); // Set the reports state
if (data.length === 0) {
setError("No data available");
}
} catch (error) {
console.error("Error while fetching reports:", error);
setError("Error fetching data.");
} finally {
setIsLoading(false); // Set loading state to false once the request is complete
}
};
const goToAdd = () => navigate("/admin/user-report");
const goToAdd2 = () => navigate("/admin/reportbuild2all");
const goToRunner = (report) => {
console.log("at time of navigating reportID: ",report.id, " report: ",report);
if (report.isSql) {
navigate(`/admin/report-runner1/${report.id}`,{ state: { reportId: report.id, reportData: report}});
} else {
navigate(`/admin/report-runner2/${report.id}`,{ state: { reportId: report.id, reportData: report}}); //reportRunnerEdit.js is called
}
};
const handleDelete = async (id) => {
setModalDelete(false);
try {
const response = await fetch(`/api/report-builder/${id}`, { method: "DELETE" });
if (response.ok) {
toast.success("Deleted successfully");
fetchAllReports();
} else {
toast.error("Error deleting data.");
}
} catch (err) {
console.error(err);
toast.error("Error deleting data.");
}
};
const openDeleteModal = (row) => {
setRowSelected(row);
setModalDelete(true);
};
return (
<div className="container">
{/* Header */}
<div className="row">
<div className="col-md-4">
<h3><b>All Reports</b></h3>
</div>
<div className="col-md-8 text-end">
<button className="btn btn-primary" onClick={goToAdd}>
<i className="bi bi-plus"></i> Report Builder SQL
</button>
<button className="btn btn-primary ms-2" onClick={goToAdd2}>
<i className="bi bi-plus"></i> Report Builder URL
</button>
</div>
</div>
{/* Loading Spinner */}
{isLoading && (
<div className="alert alert-info mt-3">
<div className="spinner-border text-info me-2" role="status" />
Loading...
</div>
)}
{/* Report Cards */}
{!isLoading && gridData.length > 0 && (
<div className="row mt-4">
{gridData.map((report, index) => (
<div className="col-md-6 col-lg-4 mb-4" key={index}>
<div
className="card h-100 border-0"
onClick={() => goToRunner(report)}
style={{
cursor: 'pointer',
transition: 'all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1)',
borderRadius: '16px',
overflow: 'hidden',
backgroundColor: '#ffffff',
boxShadow: '0 10px 25px rgba(0,0,0,0.05)',
}}
onMouseEnter={(e) => {
e.currentTarget.style.transform = 'translateY(-8px)';
e.currentTarget.style.boxShadow = '0 15px 30px rgba(0,0,0,0.1)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = 'translateY(0)';
e.currentTarget.style.boxShadow = '0 10px 25px rgba(0,0,0,0.05)';
}}
>
{/* Card Header with Gradient */}
<div
className="d-flex justify-content-between align-items-center p-3"
style={{
borderBottom: '1px solid rgba(0,0,0,0.05)',
background: report.isSql
? 'linear-gradient(135deg, #f5f7fa 0%,rgb(198, 218, 255) 100%)'
: 'linear-gradient(135deg, #fff9f0 0%,rgb(217, 204, 255) 100%)',
height: '50px'
}}
>
<div className="d-flex align-items-center">
<div
className="me-3 d-flex align-items-center justify-content-center"
style={{
width: '36px',
height: '36px',
borderRadius: '10px',
background: report.isSql ? 'rgba(65, 105, 225, 0.15)' : 'rgba(255, 165, 0, 0.15)'
}}
>
<i
className={`bi ${report.isSql ? 'bi-database' : 'bi-link-45deg'} fs-5`}
style={{ color: report.isSql ? '#4169E1' : '#FF8C00' }}
></i>
</div>
<span
className="fw-semibold"
style={{
color: report.isSql ? '#4169E1' : '#FF8C00',
fontSize: '0.9rem'
}}
>
{report.isSql == null ? "N/A" : report.isSql ? "SQL Report" : "URL Report"}
</span>
</div>
{/* Status Indicator */}
<div
className="d-flex align-items-center"
style={{
backgroundColor: report.active ? 'rgba(40, 167, 69, 0.1)' : 'rgba(220, 53, 69, 0.1)',
padding: '6px 12px',
borderRadius: '30px'
}}
>
<div
style={{
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: report.active ? '#28a745' : '#dc3545',
marginRight: '6px'
}}
></div>
<span
style={{
fontSize: '0.8rem',
fontWeight: '500',
color: report.active ? '#28a745' : '#dc3545'
}}
>
{report.active ? "Active" : "Inactive"}
</span>
</div>
</div>
{/* Card Body */}
<div className="card-body p-4">
<h5
className="fw-bold mb-3"
style={{
fontSize: '1.15rem',
color: '#343a40',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
title={report.reportName}
>
{report.reportName}
</h5>
<p
style={{
display: '-webkit-box',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
fontSize: '0.9rem',
lineHeight: '1.5',
color: '#6c757d',
height: '42px',
marginBottom: '0'
}}
title={report.description}
>
{report.description || "No description available"}
</p>
</div>
{/* Card Footer */}
<div
className="p-3"
style={{
borderTop: '1px solid rgba(0,0,0,0.05)',
backgroundColor: '#f8f9fa'
}}
>
<div className="d-flex justify-content-between align-items-center">
<div className="d-flex align-items-center" style={{ fontSize: '0.75rem', color: '#6c757d' }}>
<i className="bi bi-clock me-1"></i>
<span>Updated: {new Date(report.updatedAt).toLocaleDateString()}</span>
</div>
<div
className="d-flex align-items-center justify-content-center"
style={{
width: '32px',
height: '32px',
borderRadius: '8px',
backgroundColor: '#e9ecef',
transition: 'all 0.2s ease',
color: '#495057'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = '#dee2e6';
e.stopPropagation();
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = '#e9ecef';
e.stopPropagation();
}}
>
<i className="bi bi-three-dots"></i>
</div>
</div>
</div>
</div>
</div>
))}
</div>
)}
{/* Error */}
{error && <div className="alert alert-danger mt-3">{error}</div>}
{/* Delete Modal */}
{modalDelete && (
<div className="modal show d-block" tabIndex="-1" role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Delete Confirmation</h5>
<button
type="button"
className="btn-close"
onClick={() => setModalDelete(false)}
/>
</div>
<div className="modal-body">
<p>Are you sure you want to delete the report?</p>
<h2>{rowSelected?.id}</h2>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalDelete(false)}
>
Cancel
</button>
<button
type="button"
className="btn btn-primary"
onClick={() => handleDelete(rowSelected.id)}
>
Delete
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default ReportRunnerAll;

View File

@@ -0,0 +1,787 @@
import React, { useEffect, useState } from "react";
import { fetchStandardParameters, downloadFile } from "../../../APIServices/ReportRunnerAPI";
import { toast } from "react-toastify";
import './ReportrunnerEdit.css'
import axios from 'axios';
import { useNavigate, useParams } from 'react-router-dom';
const ReportRunnerEdit = () => {
const navigate = useNavigate();
const { id } = useParams();
// Report data state
const [reportName, setReportName] = useState("Sample Report");
const [reportId, setReportId] = useState(id || null);
// Date parameters state
const [dateParam, setDateParam] = useState(true);
const [selectDateType, setSelectDateType] = useState("");
const [fromDate, setFromDate] = useState("");
const [toDate, setToDate] = useState("");
const [fromDateQuery, setFromDateQuery] = useState("");
const [toDateQuery, setToDateQuery] = useState("");
// Standard parameters state
const [dynamicFields, setDynamicFields] = useState([]);
const [dynamicFormValues, setDynamicFormValues] = useState({});
// Adhoc parameters state
const [adhocList, setAdhocList] = useState([]);
const [adhocParams, setAdhocParams] = useState([
{ andor: "AND", fields_name: "", condition: "=", value: "" },
]);
// Condition options
const conditionOptions = ["=", "!=", "<", ">", "<=", ">=", "LIKE", "BETWEEN", "IN"];
const andOrOptions = ["AND", "OR", "NOT"];
// Results state
const [rows, setRows] = useState([]);
const [filterRows, setFilterRows] = useState([]);
const [filtered, setFiltered] = useState(false);
const [headers, setHeaders] = useState([]);
// Query state
const [SQLQuery, setSQLQuery] = useState('');
const [dateKey, setDateKey] = useState('createdat');
const [formattedAdhocParameters, setFormattedAdhocParameters] = useState('');
const [selectedValues, setSelectedValues] = useState({});
// Loading state
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
// Get today's date
const todayDate = new Date().toISOString().slice(0, 10);
useEffect(() => {
// Fetch report details
if (reportId) {
fetchReportDetails(reportId);
}
// Set default date to today
handleDateSelect('Today');
// Run query after a delay to allow data to load
const timer = setTimeout(() => {
runQuery();
}, 2000);
return () => clearTimeout(timer);
}, [reportId]);
const fetchReportDetails = async (id) => {
try {
setIsLoading(true);
// This API call would need to be implemented
const response = await axios.get(`/api/report-builder/${id}`);
const data = response.data;
setReportName(data.reportName);
// Parse the builder line data
const builderLine = data.rpt_builder2_lines?.[0];
if (builderLine) {
const lineData = JSON.parse(builderLine.model)[0];
setAdhocList(lineData.adhoc_param_html || []);
setDateParam(lineData.date_param_req || false);
setSQLQuery(lineData.url || '');
// Set dynamic fields from standard parameters
setDynamicFields(lineData.std_param_html || []);
// Initialize dynamic form values
const initialFormValues = {};
(lineData.std_param_html || []).forEach(field => {
initialFormValues[field] = '';
});
setDynamicFormValues(initialFormValues);
// Fetch data based on the URL
fetchData(lineData.url);
}
} catch (error) {
console.error("Error fetching report details:", error);
setError("Error loading report details");
toast.error("Failed to load report details");
} finally {
setIsLoading(false);
}
};
const fetchData = async (url) => {
try {
const response = await axios.get(url);
const data = response.data?.body ? JSON.parse(response.data.body) : [];
setRows(data);
setFilterRows(data);
// Set headers from the first row if available
if (data.length > 0) {
setHeaders(Object.keys(data[0]));
}
} catch (error) {
console.error("Error fetching data:", error);
setError("Error loading data");
}
};
// Handle changes to adhoc parameters
const handleAdhocChange = (index, field, value) => {
const updatedParams = [...adhocParams];
updatedParams[index][field] = value;
setAdhocParams(updatedParams);
};
// Add a new adhoc parameter row
const addAdhocRow = () => {
const lastRow = adhocParams[adhocParams.length - 1];
// Only add a new row if the last row has a field name
if (lastRow && lastRow.fields_name !== '') {
// Format the adhoc parameters for the query
let formattedString = '';
for (const condition of adhocParams) {
const { andor, fields_name, condition: cond, value } = condition;
formattedString += ` ${andor} ${fields_name} ${cond} '${value}' `;
}
setFormattedAdhocParameters(formattedString);
// Add a new row
setAdhocParams([
...adhocParams,
{ andor: "AND", fields_name: "", condition: "=", value: "" },
]);
// Update selected values for filtering
selectColumn(adhocParams);
}
};
// Delete an adhoc parameter row
const deleteAdhocRow = (index) => {
if (adhocParams.length > 1) {
// Get the item to be deleted
const deletedItem = adhocParams[index];
// Remove the item from the adhocParams array
const updatedParams = adhocParams.filter((_, i) => i !== index);
setAdhocParams(updatedParams);
// Update selected values
const updatedSelectedValues = { ...selectedValues };
const columnName = deletedItem.fields_name;
if (updatedSelectedValues[columnName]) {
const value = deletedItem.value;
const indexInArray = updatedSelectedValues[columnName].indexOf(value);
if (indexInArray !== -1) {
updatedSelectedValues[columnName].splice(indexInArray, 1);
// If the array is now empty, remove the property
if (updatedSelectedValues[columnName].length === 0) {
delete updatedSelectedValues[columnName];
}
}
}
setSelectedValues(updatedSelectedValues);
filterRowsBySelectedValues(updatedSelectedValues);
}
};
// Handle dynamic form values change
const handleDynamicFormChange = (field, value) => {
setDynamicFormValues({
...dynamicFormValues,
[field]: value
});
};
// Handle date type selection
const handleDateSelect = (dateType) => {
setSelectDateType(dateType);
setFromDateQuery(null);
setToDateQuery(null);
const currentDate = new Date();
let fromDateValue, toDateValue;
switch (dateType) {
case 'Today':
fromDateValue = new Date();
toDateValue = new Date();
break;
case 'This Week':
// Calculate this week (Monday to Sunday)
const dayOfWeek = currentDate.getDay();
const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
fromDateValue = new Date(currentDate);
fromDateValue.setDate(currentDate.getDate() - daysToMonday);
toDateValue = new Date(fromDateValue);
toDateValue.setDate(fromDateValue.getDate() + 6);
break;
case 'Last Week':
// Calculate last week
const lastWeekDayOfWeek = currentDate.getDay();
const lastWeekDaysToMonday = lastWeekDayOfWeek === 0 ? 6 : lastWeekDayOfWeek - 1;
fromDateValue = new Date(currentDate);
fromDateValue.setDate(currentDate.getDate() - lastWeekDaysToMonday - 7);
toDateValue = new Date(fromDateValue);
toDateValue.setDate(fromDateValue.getDate() + 6);
break;
case 'This Month':
// First day of current month
fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
// Last day of current month
toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
break;
case 'Last Month':
// First day of previous month
fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
// Last day of previous month
toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0);
break;
case 'This Year':
// First day of current year
fromDateValue = new Date(currentDate.getFullYear(), 0, 1);
// Last day of current year
toDateValue = new Date(currentDate.getFullYear(), 11, 31);
break;
case 'Last Year':
// First day of previous year
fromDateValue = new Date(currentDate.getFullYear() - 1, 0, 1);
// Last day of previous year
toDateValue = new Date(currentDate.getFullYear() - 1, 11, 31);
break;
default:
fromDateValue = null;
toDateValue = null;
}
if (fromDateValue) {
const fromDateString = fromDateValue.toISOString().substring(0, 10);
setFromDate(fromDateString);
setFromDateQuery(fromDateString);
} else {
setFromDate('');
setFromDateQuery('');
}
if (toDateValue) {
const toDateString = toDateValue.toISOString().substring(0, 10);
setToDate(toDateString);
setToDateQuery(toDateString);
} else {
setToDate('');
setToDateQuery('');
}
};
// Run the query
const runQuery = () => {
console.log("Dynamic form values:", dynamicFormValues);
console.log("Date range:", fromDate, toDate);
let query = SQLQuery || '';
// Add standard parameters to the query
if (Object.keys(dynamicFormValues).length > 0) {
Object.keys(dynamicFormValues).forEach((key) => {
if (dynamicFormValues[key] !== null && dynamicFormValues[key] !== '') {
query += ` AND ${key} = '${dynamicFormValues[key]}'`;
}
});
// Update selected values for filtering
selectColumn(dynamicFormValues);
}
// Add date range to the query if date parameter is required
if (dateParam) {
// Determine the correct date key based on adhoc list
let tempDateKey = 'createdat';
adhocList.forEach(key => {
if (key.includes('created_at')) tempDateKey = 'created_at';
if (key.includes('createdAt')) tempDateKey = 'createdAt';
});
setDateKey(tempDateKey);
if (fromDate && toDate) {
const fromDateObj = new Date(fromDate);
const toDateObj = new Date(toDate);
query += ` AND ${tempDateKey} BETWEEN '${fromDateObj.toISOString().split('T')[0]}' AND '${toDateObj.toISOString().split('T')[0]}'`;
}
}
// Add adhoc parameters to the query
if (formattedAdhocParameters) {
query += formattedAdhocParameters;
}
console.log("Final query:", query);
// Make API request
axios.post('/api/report-runner/run', { query })
.then((response) => {
const data = response.data;
if (data && data.length > 0) {
setRows(data);
setFilterRows(data);
setHeaders(Object.keys(data[0]));
toast.success("Query executed successfully");
} else {
toast.warning("No data returned");
}
})
.catch((error) => {
console.error("Error running query:", error);
toast.error("Error running the query");
});
};
// Export file function
const exportFile = (format) => {
try {
const dataToExport = filtered ? filterRows : rows;
const name = reportName.replace(/\s+/g, '_');
const timestamp = new Date().toISOString().replace(/[-:T.]/g, '_').slice(0, 17);
const fileName = `${name}_${timestamp}`;
downloadFile(format, dataToExport, fileName);
toast.success(`File exported as ${format.toUpperCase()} successfully`);
} catch (error) {
console.error("Error exporting file:", error);
toast.error("Error exporting file");
}
};
// Get table headers
const getHeaders = () => {
if (!rows || rows.length === 0) return [];
const headerSet = new Set();
rows.forEach(row => {
Object.keys(row).forEach(key => headerSet.add(key));
});
return Array.from(headerSet);
};
// Get filtered table headers
const getFilteredHeaders = () => {
if (!filterRows || filterRows.length === 0) return [];
const headerSet = new Set();
filterRows.forEach(row => {
Object.keys(row).forEach(key => headerSet.add(key));
});
return Array.from(headerSet);
};
// Check if a value is a date
const isDate = (value) => {
if (!value) return false;
if (value instanceof Date) return true;
if (typeof value === 'object' &&
value.year !== undefined &&
value.monthValue !== undefined &&
value.dayOfMonth !== undefined) {
return true;
}
const date = new Date(value);
return !isNaN(date.getTime());
};
// Format a date for display
const formatDate = (value) => {
if (!value) return '';
if (typeof value === 'object' &&
value.year !== undefined &&
value.monthValue !== undefined &&
value.dayOfMonth !== undefined) {
// Handle Java-style date objects
const { year, monthValue, dayOfMonth, hour = 0, minute = 0, second = 0 } = value;
const date = new Date(year, monthValue - 1, dayOfMonth, hour, minute, second);
return date.toLocaleString();
}
// Standard JS date
return new Date(value).toLocaleString();
};
// Process data for filtering
const selectColumn = (data) => {
const newSelectedValues = { ...selectedValues };
if (Array.isArray(data)) {
// Handle array of objects (like adhoc parameters)
data.forEach(item => {
const { fields_name, value } = item;
if (fields_name && fields_name.trim() !== '') {
if (!newSelectedValues[fields_name]) {
newSelectedValues[fields_name] = [];
}
if (value !== null && value.trim() !== '') {
if (!newSelectedValues[fields_name].includes(value)) {
newSelectedValues[fields_name].push(value);
}
}
}
});
} else if (typeof data === 'object') {
// Handle object (like dynamic form values)
Object.keys(data).forEach(key => {
const value = data[key];
if (!newSelectedValues[key]) {
newSelectedValues[key] = [];
}
if (value !== null && value.trim && value.trim() !== '') {
if (!newSelectedValues[key].includes(value)) {
newSelectedValues[key].push(value);
}
}
});
}
setSelectedValues(newSelectedValues);
filterRowsBySelectedValues(newSelectedValues);
};
// Filter rows based on selected values
const filterRowsBySelectedValues = (values = selectedValues) => {
const filteredRows = [];
for (const row of rows) {
let isMatch = true;
// Check each column in the selected values
for (const columnName in values) {
if (values.hasOwnProperty(columnName) && row.hasOwnProperty(columnName)) {
const selectedValuesForColumn = values[columnName];
const rowValue = row[columnName];
if (typeof rowValue === 'boolean') {
// Handle boolean values
if (selectedValuesForColumn.length === 0) continue;
const selectedBooleanValue = selectedValuesForColumn[0] === 'true';
if (selectedBooleanValue !== rowValue) {
isMatch = false;
break;
}
} else {
// Handle other data types
const convertedValues = selectedValuesForColumn.map(value => {
if (typeof rowValue === 'number') {
return parseFloat(value);
}
return value;
});
if (!convertedValues.includes(rowValue)) {
isMatch = false;
break;
}
}
}
}
// Check date range if both dates are provided
if (fromDateQuery && toDateQuery && isMatch) {
const from = new Date(fromDateQuery);
const to = new Date(toDateQuery);
// Set hours to 0 for proper comparison
from.setHours(0, 0, 0, 0);
to.setHours(23, 59, 59, 999);
// Get the date from the row using dateKey
const rowDate = new Date(row[dateKey]);
if (rowDate < from || rowDate > to) {
isMatch = false;
}
}
if (isMatch) {
filteredRows.push(row);
}
}
setFilterRows(filteredRows);
// Determine if we are filtering or not
const isFiltering = Object.values(values).some(arr => arr.length > 0) ||
(fromDateQuery && toDateQuery);
setFiltered(isFiltering);
};
// Render date cell with formatting
const renderTableCell = (row, key) => {
const isDateField = key === 'createdat' || key === 'createdAt' ||
key === 'updated_at' || key === 'updatedAt' ||
key === 'created_at' || key === 'creat_at';
if (isDateField && row[key]) {
return formatDate(row[key]);
}
return row[key];
};
// Navigate back to the reports list
const goBack = () => {
navigate("/admin/report-runner");
};
return (
<div className="container">
{/* Report Header */}
<h4 style={{ fontWeight: 300, display: "inline" }}>
<b>Report Name SQL - {reportName}</b>
</h4>
<hr />
{/* Date and Standard Parameters Section */}
<div className="row">
{/* Standard Parameters */}
<div className="col-md-6">
<h5 style={{ fontWeight: 200, color: "black" }}>
<b>Standard Parameters</b>
</h5>
{dynamicFields.length === 0 ? (
<div className="text-danger">No parameter found</div>
) : (
<div className="row">
{dynamicFields.map((field, index) => (
<div key={index} className="col-md-6 mb-3">
<label>{field}</label>
<input
type="text"
className="form-control"
placeholder={`Enter ${field}`}
value={dynamicFormValues[field] || ''}
onChange={(e) => handleDynamicFormChange(field, e.target.value)}
/>
</div>
))}
</div>
)}
</div>
</div>
{/* Adhoc Parameters Section */}
<div className="row mt-4">
<div className="col-md-12">
<h5 style={{ fontWeight: 200, color: "black" }}>
<b>Adhoc Parameters</b>
</h5>
<table className="table">
<tbody>
{adhocParams.map((param, index) => (
<tr key={index}>
<td>
<select
className="form-select"
value={param.andor}
onChange={(e) =>
handleAdhocChange(index, "andor", e.target.value)
}
>
<option value="">Select Values</option>
{andOrOptions.map((option, idx) => (
<option key={idx} value={option}>
{option}
</option>
))}
</select>
</td>
<td>
<select
className="form-select"
value={param.fields_name}
onChange={(e) =>
handleAdhocChange(index, "fields_name", e.target.value)
}
>
<option value="">Select Values</option>
{adhocList.map((field, idx) => (
<option key={idx} value={field}>
{field}
</option>
))}
</select>
</td>
<td>
<select
className="form-select"
value={param.condition}
onChange={(e) =>
handleAdhocChange(index, "condition", e.target.value)
}
>
<option value="">Select Values</option>
{conditionOptions.map((condition, idx) => (
<option key={idx} value={condition}>
{condition}
</option>
))}
</select>
</td>
<td>
<input
type="text"
className="form-control"
value={param.value}
onChange={(e) =>
handleAdhocChange(index, "value", e.target.value)
}
/>
</td>
<td>
<button
className="btn btn-danger me-2"
onClick={() => deleteAdhocRow(index)}
title="Delete Row"
>
<i className="bi bi-trash"></i>
</button>
<button
className="btn btn-primary"
onClick={addAdhocRow}
title="Add Row"
>
<i className="bi bi-plus"></i>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Report Output Section */}
<div className="row mt-4">
<div className="col-md-6">
<h5 style={{ fontWeight: 300 }}>
<b>Report Output</b>
</h5>
</div>
<div className="col-md-6 text-end">
{/* Export Dropdown */}
<div className="dropdown d-inline-block me-2">
<button
className="btn btn-outline-primary dropdown-toggle"
type="button"
id="exportDropdown"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i className="bi bi-download"></i> Export
</button>
<ul className="dropdown-menu" aria-labelledby="exportDropdown">
<li>
<button
className="dropdown-item"
onClick={() => exportFile("xlsx")}
>
<i className="bi bi-file-earmark-excel me-2"></i> XLSX
</button>
</li>
<li>
<button
className="dropdown-item"
onClick={() => exportFile("csv")}
>
<i className="bi bi-file-earmark-text me-2"></i> CSV
</button>
</li>
<li>
<button
className="dropdown-item"
onClick={() => exportFile("pdf")}
>
<i className="bi bi-file-earmark-pdf me-2"></i> PDF
</button>
</li>
</ul>
</div>
{/* Back and Run Buttons */}
<button className="btn btn-outline-secondary me-2" onClick={goBack}>
Back
</button>
<button className="btn btn-primary" onClick={runQuery}>
Run
</button>
</div>
</div>
<hr />
{/* Data Table */}
<div style={{ maxHeight: "500px", overflow: "auto", marginTop: "1rem" }}>
{isLoading ? (
<div className="text-center py-4">
<div className="spinner-border text-primary" role="status"></div>
<p className="mt-2">Loading data...</p>
</div>
) : error ? (
<div className="alert alert-danger">{error}</div>
) : (filtered ? filterRows : rows).length === 0 ? (
<div className="alert alert-info">No data available</div>
) : (
<table className="table table-striped">
<thead>
<tr>
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, index) => (
<th key={index}>{header}</th>
))}
</tr>
</thead>
<tbody>
{(filtered ? filterRows : rows).map((row, rowIndex) => (
<tr key={rowIndex}>
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, colIndex) => (
<td key={colIndex}>
{renderTableCell(row, header)}
</td>
))}
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
);
};
export default ReportRunnerEdit;

View File

@@ -0,0 +1,20 @@
/* Grid for dropdown content */
.dropdown-menu {
display: none;
}
.dropdown-menu.show {
display: block;
}
/* Custom grid layout inside dropdown */
.grid-template-columns-3 {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 columns */
gap: 0.5rem; /* Spacing between buttons */
}
.d-grid button {
width: 100%; /* Make buttons span the grid cell */
}

View File

@@ -0,0 +1,176 @@
import React, { useState } from 'react';
import { useForm, useFieldArray } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { Container, Row, Col, Form, Button, Card } from 'react-bootstrap';
import '../../CSS/CSS/CommonStyle.css';
import { addReport, getKeysFromUrl } from '../../../../APIServices/reportBaseUrlAddAPI';
const ReportBuild2Add = () => {
const { register, handleSubmit, control, formState: { errors } } = useForm({
defaultValues: {
reportName: '',
description: '',
active: false,
isSql: false,
Rpt_builder2_lines: [{ model: '' }],
},
});
const { fields, append } = useFieldArray({
control,
name: 'Rpt_builder2_lines',
});
const [keysFromUrl, setKeysFromUrl] = useState([]);
const navigate = useNavigate();
const handleGetKeys = async (url) => {
if (!url) {
toast.error('URL is required');
return;
}
try {
const data = await getKeysFromUrl(url);
setKeysFromUrl(data);
toast.success('Keys retrieved successfully');
} catch (error) {
toast.error(error || 'Failed to retrieve keys');
}
};
// const onSubmit = async (formData) => {
// try {
// const { status } = await addReport(formData);
// if (status >= 200 && status <= 209) {
// toast.success('Report saved successfully');
// navigate('/admin/reportbuild2all');
// } else {
// toast.error('Report save unsuccessful');
// }
// } catch (error) {
// toast.error(error || 'Error saving report');
// }
// };
const onSubmit = async (formData) => {
// Prepare the formData to match the backend API requirements
const updatedData = {
reportName: formData.reportName, // Use the correct field name
description: formData.description,
active: formData.active || false, // Ensure `active` is passed and defaults to `false`
isSql: formData.isSql || false, // Ensure `isSql` is passed and defaults to `false`
Rpt_builder2_lines: formData.Rpt_builder2_lines || [] // Default to empty array if not provided
};
try {
const { status } = await addReport(updatedData);
console.log("Report added successfully...")
if (status >= 200 && status <= 209) {
toast.success('Report saved successfully');
console.log('Report Saved successfully...')
navigate('/admin/reportbuild2all');
} else {
toast.error('Report save unsuccessful');
}
} catch (error) {
toast.error(error || 'Error saving report');
}
};
const handleCancel = () => {
navigate('/admin/reportbuild2all');
};
return (
<Container>
<Card className="shadow-sm mb-4">
<Card.Header className="d-flex justify-content-between align-items-center">
<h4 className="m-0" style={{ fontWeight: 400, color: '#0E6591' }}>
<b>Create New Report</b>
</h4>
<span className="badge bg-info">Add Mode</span>
</Card.Header>
<Card.Body>
<Form onSubmit={handleSubmit(onSubmit)}>
<Row className="mb-3">
<Col md={4} sm={12}>
<Form.Group controlId="reportName">
<Form.Label>Report Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter name"
{...register('reportName', { required: 'Report name is required' })}
isInvalid={errors.reportName}
className="custom-hover-border"
/>
<Form.Control.Feedback type="invalid">
{errors.reportName?.message}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={4} sm={12}>
<Form.Group controlId="description">
<Form.Label>Description</Form.Label>
<Form.Control
as="textarea"
rows={2}
placeholder="Enter Description"
{...register('description')}
className="custom-hover-border"
/>
</Form.Group>
</Col>
<Col md={4} sm={12}>
<Form.Group controlId="active">
<Form.Label>Active</Form.Label>
<Form.Check type="checkbox" label="Active" {...register('active')} />
</Form.Group>
</Col>
</Row>
<Row>
{fields.map((item, index) => (
<Col key={item.id} md={4} sm={12}>
{/* <Form.Group controlId={`Rpt_builder2_lines.${index}.model`}>
<Form.Label>Model</Form.Label>
<Form.Control
type="text"
placeholder="Enter model"
{...register(`Rpt_builder2_lines.${index}.model`)}
className="custom-hover-border"
/>
</Form.Group> */}
</Col>
))}
<Col md={12} className="d-flex justify-content-start mt-3">
{/* <Button
variant="outline"
onClick={() => append({ model: '' })}
className="custom_manage_column_button"
>
Add Line
</Button> */}
</Col>
</Row>
<Row className="mt-4">
<Col className="d-flex justify-content-center">
<div className="btn-group">
<Button variant="secondary" onClick={handleCancel}>
Cancel
</Button>
<Button variant="primary" type="submit" className="ms-2 custom_button" onClick={onSubmit}>
Submit
</Button>
</div>
</Col>
</Row>
</Form>
</Card.Body>
</Card>
</Container>
);
};
export default ReportBuild2Add;

View File

@@ -0,0 +1,4 @@
.content-container{
margin-top: 10rem !important;
}

View File

@@ -0,0 +1,602 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "./Report-buildall.css";
import { getReports } from "../../../../APIServices/reportBaseUrlAllAPI";
import { deleteReport } from "APIServices/reportBaseUrlDeleteAPI";
import { addReport } from "APIServices/reportBaseUrlAddAPI";
import ConfirmModal from "../../../common/ConfirmModal";
import {
Table,
Pagination,
PaginationItem,
PaginationLink,
Badge,
} from "reactstrap";
import {
Button,
Form,
Row,
Col,
InputGroup,
FormControl,
Modal,
Dropdown,
} from "react-bootstrap";
import { BsJournals } from "react-icons/bs";
import Spinner from "../../../../UIComponants/Spinner";
import "react-toastify/dist/ReactToastify.css";
import "../../../Dashboard/CSS/CSS/CommonStyle.css";
import {
faTrash,
faPlus,
faGripVertical,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { FaSearch, FaTimes } from "react-icons/fa";
const ReportBuild2All = () => {
const [gridData, setGridData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [rowSelected, setRowSelected] = useState(null);
const [visibleColumns, setVisibleColumns] = useState({
goTo: true,
reportName: true,
description: true,
active: true,
action: true,
});
const [currentPage, setCurrentPage] = useState(1);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const navigate = useNavigate();
const [searchQuery, setSearchQuery] = useState("");
// Add new state variables for modals
const [showAddModal, setShowAddModal] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [deleteItem, setDeleteItem] = useState({ id: null, reportName: "" });
// Add state for new data
const [newData, setNewData] = useState({
reportName: "",
description: "",
active: false,
isSql: false,
Rpt_builder2_lines: [{ model: "" }]
});
useEffect(() => {
getAllReports();
}, []);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
// Add custom styles to override Bootstrap's active styling
const style = document.createElement('style');
style.textContent = `
.dropdown-item-custom:active,
.dropdown-item-custom:focus,
.dropdown-item-custom.active {
background-color: white !important;
color: #333 !important;
}
.dropdown-item-custom:hover {
background-color: #f8f9fa !important;
}
`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, []);
const filteredData = gridData
.filter(
(item) =>
item.reportName &&
item.reportName.toLowerCase().includes(searchQuery.toLowerCase())
)
.slice((currentPage - 1) * recordsPerPage, currentPage * recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const totalPages = Math.ceil(gridData.length / recordsPerPage);
const handleRecordsPerPageChange = (value) => {
setRecordsPerPage(value);
setCurrentPage(1);
};
const getAllReports = async () => {
setLoading(true);
try {
const data = await getReports(); // Use the new API service
if (data.length === 0) {
setError("No data Available");
} else {
setGridData(data);
console.log("data is coming", data);
}
} catch (err) {
console.error("Error fetching reports:", err);
setError("Failed to fetch data");
} finally {
setLoading(false);
}
};
const goToRunner = () => {
navigate("/admin/report-runner");
};
const goToAdd = () => {
setShowAddModal(true);
};
const goToLines = (report) => {
console.log("Complete Report Data:", report); // Log full report data
console.log("Rpt_builder2_lines:", report?.Rpt_builder2_lines); // Log Rpt_builder2_lines specifically
navigate(`/admin/reportbuild2edit`, { state: { reportId: report.id, report: report } });
// // Check if Rpt_builder2_lines is an array and has at least one item
// if (Array.isArray(report?.Rpt_builder2_lines) && report.Rpt_builder2_lines.length > 0) {
// const firstLine = report.Rpt_builder2_lines[0];
// // Check if the model field in the first item is not empty
// if (firstLine?.model !== '') {
// navigate(`/admin/reportbuild2edit`, { state: { reportId: report.id } });
// } else {
// navigate(`/admin/reportbuild2edit`, { state: { reportId: report.id } });
// }
// } else {
// // If Rpt_builder2_lines is missing or not an array, just navigate to /admin/reportbuild2edit
// console.warn("Rpt_builder2_lines is missing or not an array. Navigating to /admin/reportbuild2edit...");
// navigate(`/admin/reportbuild2edit`, { state: { reportId: report.id } });
// }
};
const confirmDelete = (e, report) => {
e.stopPropagation(); // Prevent any parent handlers from being called
setDeleteItem({
id: report.id,
reportName: report.reportName || "this report"
});
setShowConfirmModal(true);
};
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const handleDelete = async () => {
const { id } = deleteItem;
if (!id) {
console.error("ID is undefined. Cannot delete.");
toast.error("Invalid ID. Deletion failed.");
return;
}
try {
// Call the deleteReport service
const response = await deleteReport(id);
console.log("Delete response:", response);
// Check if delete was successful
if (response && (response.status === 200 || response.status === 204)) {
toast.success("Report deleted successfully");
// Remove the deleted item from the state
setGridData(gridData.filter(item => item.id !== id));
} else {
toast.error("Error deleting data: Unexpected response");
}
// Hide the confirm modal
setShowConfirmModal(false);
} catch (err) {
console.error("Error deleting report:", err);
toast.error("Error deleting data");
setShowConfirmModal(false);
}
};
const handleAddSubmit = async () => {
try {
// Validate required fields
if (!newData.reportName.trim()) {
toast.warning("Report name is required");
return;
}
// Prepare payload for API call
const payload = {
reportName: newData.reportName,
description: newData.description,
active: newData.active,
isSql: false,
Rpt_builder2_lines: [{ model: "" }],
};
console.log("payload to be submitted for add url report: ", payload)
// Call the API to add the report
const response = await addReport(payload);
console.log("responce:",response)
// Check if we received a proper response
if (response && response.data && response.data.id) {
toast.success("Report added successfully");
// Add just the report data to the grid data (not the entire response)
setGridData([...gridData, response.data]);
// Reset form and close modal
setNewData({
reportName: "",
description: "",
active: false,
isSql: false,
Rpt_builder2_lines: [{ model: "" }]
});
setShowAddModal(false);
// Refresh the report list to ensure data consistency
getAllReports();
} else {
toast.error("Failed to add report: Unexpected response");
}
} catch (error) {
console.error("Error adding report:", error);
toast.error("Failed to add report");
}
};
const handleAddClose = () => {
setShowAddModal(false);
};
// Add custom CSS to override Bootstrap's active dropdown item styling
const dropdownItemStyle = {
backgroundColor: 'white',
color: '#333',
cursor: 'pointer',
padding: '8px 12px',
border: 'none',
outline: 'none !important'
};
return (
<div>
{loading ? (
<Spinner /> // The spinner will be centered in the viewport
) : (
<div className="content-container ">
<div className="container-fluid mb-7">
<div className="row mb-3">
<div className="col-md-4 title_name">
<h3>
<b>Report Builder2 (URL) </b>
</h3>
</div>
<div className="col-md-8 text-end">
<button className="btn btn-primary me-2" onClick={goToRunner}>
<i className="bi bi-grid-fill"></i> Report Runner
</button>
<button className="btn btn-primary" onClick={goToAdd}>
<i className="bi bi-plus-lg"></i> ADD
</button>
</div>
</div>
{/* DataGrid */}
{loading ? (
<div>Loading...</div>
) : error ? (
<div className="text-danger">{error}</div>
) : (
<Table
striped
responsive
hover
className="align-middle table-flush shadow-sm"
>
<thead className="custom_header">
<tr>
{visibleColumns.goTo && <th>Go To</th>}
{visibleColumns.reportName && <th>Report Name</th>}
{visibleColumns.description && <th>Report Description</th>}
{visibleColumns.active && <th className="text-center">Active</th>}
{visibleColumns.action && <th className="text-center">Action</th>}
</tr>
</thead>
<tbody className="tbody">
{filteredData.length === 0 ? (
<tr>
<td
colSpan={
Object.values(visibleColumns).filter(Boolean).length
}
className="text-center"
>
No data available
</td>
</tr>
) : (
filteredData.filter((user) => user.isSql === false).map((user) => (
<tr key={user.id}>
{visibleColumns.goTo && (
<td>
<Badge
color="primary"
pill
style={{
cursor: "pointer",
padding: "0.5em 1em",
fontSize: "0.9rem",
textTransform: "uppercase",
}}
onClick={() => goToLines(user)}
>
Set Up
</Badge>
</td>
)}
{visibleColumns.reportName && <td>{user.reportName}</td>}
{visibleColumns.description && <td>{user.description}</td>}
{visibleColumns.active && (
<td
style={{
fontWeight: user.active ? "bold" : "normal",
color: user.active ? "green" : "red",
backgroundColor: user.active
? "rgba(0, 128, 0, 0.1)"
: "rgba(255, 0, 0, 0.1)",
padding: "2px 4px",
display: "inline-block",
borderRadius: "4px",
textAlign: "center",
marginTop: "10px",
alignItems: "center",
justifyContent: "center",
}}
>
{user.active ? "Yes" : "No"}
</td>
)}
{visibleColumns.action && (
<td>
<FontAwesomeIcon
icon={faTrash}
onClick={(e) => confirmDelete(e, user)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "red",
marginRight: "15px",
}}
/>
</td>
)}
</tr>
))
)}
</tbody>
</Table>
)}
{/* 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>
<Dropdown.Header className="fw-bold text-dark">Toggle Column Visibility</Dropdown.Header>
<Dropdown.Divider />
{[
{ key: 'goTo', label: 'Go To' },
{ key: 'reportName', label: 'Report Name' },
{ key: 'description', label: 'Report Description' },
{ key: 'active', label: 'Active Status' },
{ key: 'action', label: 'Actions' }
].map(column => (
<Dropdown.Item
key={column.key}
onClick={() => toggleColumn(column.key)}
style={dropdownItemStyle}
className="dropdown-item-custom"
>
<Form.Check
type="checkbox"
label={column.label}
checked={visibleColumns[column.key]}
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"
>
<Dropdown.Header className="fw-bold text-dark">Records Per Page</Dropdown.Header>
<Dropdown.Divider />
{[1, 5, 10, 20, 50].map((number) => (
<Dropdown.Item
key={number}
onClick={() => handleRecordsPerPageChange(number)}
style={dropdownItemStyle}
className="dropdown-item-custom d-flex justify-content-between align-items-center"
>
<span className={recordsPerPage === number ? 'fw-bold' : ''}>{number}</span>
{recordsPerPage === number && (
<i className="fa fa-check-circle text-primary" />
)}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</Col>
</Row>
<Pagination className="pagination mt-3">
<PaginationItem disabled={currentPage === 1}>
<PaginationLink
previous
onClick={() => handlePageChange(currentPage - 1)}
/>
</PaginationItem>
{[...Array(totalPages).keys()].map((pageNumber) => (
<PaginationItem
key={pageNumber + 1}
active={currentPage === pageNumber + 1}
>
<PaginationLink
onClick={() => handlePageChange(pageNumber + 1)}
>
{pageNumber + 1}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem disabled={currentPage === totalPages}>
<PaginationLink
next
onClick={() => handlePageChange(currentPage + 1)}
/>
</PaginationItem>
</Pagination>
{/* Add Modal */}
<Modal show={showAddModal} onHide={handleAddClose} centered>
<Modal.Header>
<Modal.Title style={{ color: "#0E6591" }}>
Add New Report
</Modal.Title>
<div
onClick={handleAddClose}
style={{
cursor: "pointer",
color: "#0E6591",
fontSize: "1.5rem",
position: "absolute",
right: "15px",
top: "15px",
}}
aria-label="Close"
>
<FaTimes />
</div>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formGroupAddName" className="mb-3">
<Form.Label className="fw-bold">Report Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter report name"
value={newData.reportName}
onChange={(e) =>
setNewData({ ...newData, reportName: e.target.value })
}
className="custom-hover-border shadow-sm"
required
/>
</Form.Group>
<Form.Group
controlId="formGroupAddDescription"
className="mb-3"
>
<Form.Label className="fw-bold">Description</Form.Label>
<Form.Control
type="text"
placeholder="Enter description"
value={newData.description}
onChange={(e) =>
setNewData({ ...newData, description: e.target.value })
}
className="custom-hover-border shadow-sm"
required
/>
</Form.Group>
<Form.Group controlId="formGroupAddActive" className="mb-3">
<Form.Check
type="checkbox"
label="Active"
checked={newData.active}
onChange={(e) =>
setNewData({ ...newData, active: e.target.checked })
}
className="custom-checkbox shadow-sm"
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer className="justify-content-between">
<Button
variant="primary"
onClick={handleAddClose}
className="custom_button px-4"
>
Cancel
</Button>
<Button
variant="primary"
onClick={handleAddSubmit}
className="custom_button px-4"
>
Add Report
</Button>
</Modal.Footer>
</Modal>
{/* Confirmation Modal */}
<ConfirmModal
show={showConfirmModal}
onHide={() => setShowConfirmModal(false)}
onConfirm={handleDelete}
title="Confirm Deletion"
message={`Are you sure you want to delete "${deleteItem.reportName}"? This action cannot be undone.`}
confirmLabel="Delete"
cancelLabel="Cancel"
variant="danger"
/>
</div>
</div>
)}
</div>
);
};
export default ReportBuild2All;

View File

@@ -0,0 +1,448 @@
import React, { useState, useEffect } from "react";
import ReportBuilderService from "../../../../APIServices/ReportBuilderService";
import { toast } from "react-toastify";
import {
Container,
Row,
Col,
Form,
FormGroup,
Label,
Input,
Button,
Badge,
} from "reactstrap";
import { useNavigate, useLocation, useParams } from "react-router-dom";
import Multiselect from 'multiselect-react-dropdown';
/**
* ReportBuild2 Component
*
* This component provides an interface for editing report configurations
* that are based on URL endpoints. It allows users to:
* - Configure a URL endpoint for data
* - Set parameters for the report
* - Enable/disable date filtering
* - Save configuration changes
*/
const ReportBuild2 = () => {
// Get report ID from URL params or location state
const location = useLocation();
const params = useParams();
const reportId = params.id || location.state?.reportId;
const navigate = useNavigate();
// State for form data and related configuration
const [entryForm, setEntryForm] = useState({
id: reportId,
url: "",
date_param_req: false,
std_param_html: [],
adhoc_param_html: "",
});
// State for UI data and API responses
const [keysFromUrl, setKeysFromUrl] = useState([]); // Parameters available from URL
const [databaseList, setDatabaseList] = useState([]); // Available databases
const [lineId, setLineId] = useState(null); // ID for the report line being edited
const [builderLineData, setBuilderLineData] = useState([]); // Existing report configuration
/**
* Load report data when component mounts or reportId changes
*/
useEffect(() => {
if (reportId) {
getReportById(reportId);
}
}, [reportId]);
/**
* Fetch database list from API
* Currently not called by default but available for future use
*/
const fetchDatabaseList = async () => {
try {
const response = await ReportBuilderService.getDatabase();
if (response && response.data) {
setDatabaseList(response.data);
}
} catch (error) {
console.error("Failed to load database list:", error);
}
};
/**
* Get report details by ID and populate the form
* @param {string} id - Report ID to fetch
*/
const getReportById = async (id) => {
try {
const response = await ReportBuilderService.getrbDetailsById(id);
if (!response || !response.data) {
console.error("No report data found");
return;
}
const report = response.data;
const lineData = report.rpt_builder2_lines || [];
if (lineData.length === 0) {
console.warn("No report line data found");
return;
}
// Store line ID for update operations
setLineId(lineData[0].id);
// Parse model data if exists
if (lineData[0].model && lineData[0].model !== '') {
try {
const parsedData = JSON.parse(lineData[0].model);
setBuilderLineData(parsedData);
if (parsedData && parsedData.length > 0) {
// Handle std_param_html - ensure it's always an array
const stdParams = parsedData[0].std_param_html || [];
const stdParamsArray = Array.isArray(stdParams) ? stdParams :
(typeof stdParams === 'string' && stdParams.length > 0) ? [stdParams] : [];
// Update form with existing data
setEntryForm({
id: lineId,
std_param_html: stdParamsArray,
adhoc_param_html: parsedData[0].adhoc_param_html || "",
date_param_req: parsedData[0].date_param_req || false,
url: parsedData[0].url || "",
});
}
} catch (parseError) {
console.error("Error parsing report data:", parseError);
}
}
} catch (error) {
console.error("Failed to load report details:", error);
}
};
/**
* Handle form field changes for standard input types
* @param {Event} e - Input change event
*/
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
if (type === "select-multiple") {
// Handle multiple select inputs
const selectedOptions = Array.from(e.target.selectedOptions, option => option.value);
setEntryForm(prev => ({
...prev,
[name]: selectedOptions
}));
} else {
// Handle regular inputs and checkboxes
setEntryForm(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value,
}));
}
};
/**
* Handle Multiselect onSelect event for Standard Parameters
* @param {Array} selectedList - List of selected items
*/
const handleMultiselectSelect = (selectedList) => {
setEntryForm(prev => ({
...prev,
std_param_html: selectedList
}));
};
/**
* Handle Multiselect onRemove event for Standard Parameters
* @param {Array} selectedList - List of selected items after removal
*/
const handleMultiselectRemove = (selectedList) => {
setEntryForm(prev => ({
...prev,
std_param_html: selectedList
}));
};
/**
* Fetch column keys from provided URL
* Makes API call to getcolumnDetailsByurl to get available parameters
* @param {string} url - URL to fetch columns from
*/
const getKeys = async (url) => {
if (!url) {
toast.info("Please enter a URL");
return;
}
const loadingToastId = toast.info("Loading...");
try {
const response = await ReportBuilderService.getcolumnDetailsByurl(url);
console.log("response: ", response);
toast.dismiss(loadingToastId);
if (response && response.data) {
// Update keysFromUrl with the response data
setKeysFromUrl(response.data);
// Update adhoc_param_html in the form
setEntryForm(prev => ({
...prev,
adhoc_param_html: response.data
}));
toast.success("Success");
} else {
console.warn("No keys found in the URL response");
toast.info("No data found");
}
} catch (error) {
toast.dismiss(loadingToastId);
console.error("Failed to fetch keys:", error);
toast.error("Operation failed");
}
};
/**
* Handle form submission
* Validates input and saves report configuration
* @param {Event} e - Form submit event
*/
const handleSubmit = async (e) => {
e.preventDefault();
// Validate required fields
if (!entryForm.url) {
toast.info("URL is required");
return;
}
if (!lineId) {
console.error("Missing report line ID");
toast.error("Operation failed");
return;
}
try {
// Prepare updated builder line data
const updatedBuilderLineData = [...builderLineData];
// If no existing data, create a new entry
if (updatedBuilderLineData.length === 0) {
updatedBuilderLineData.push({});
}
// Update the first line data
updatedBuilderLineData[0] = {
std_param_html: entryForm.std_param_html,
adhoc_param_html: entryForm.adhoc_param_html,
date_param_req: entryForm.date_param_req,
url: entryForm.url,
};
// Prepare payload for API
const payload = {
model: JSON.stringify(updatedBuilderLineData)
};
// Call API to update report
await ReportBuilderService.updaterbLineData(payload, lineId);
toast.success("Report updated successfully");
// Navigate back to the list
navigate("/admin/reportbuild2all");
} catch (error) {
console.error("Failed to update the report:", error);
toast.error("Update failed");
}
};
/**
* Navigate back to the report list page
*/
const handleBack = () => {
navigate("/admin/reportbuild2all");
};
/**
* Remove a parameter from the selected parameters list
* @param {number} index - Index of parameter to remove
*/
const handleRemoveParam = (index) => {
const newParams = entryForm.std_param_html.filter((_, i) => i !== index);
setEntryForm(prev => ({
...prev,
std_param_html: newParams,
}));
};
return (
<Container
className="mt-4 p-4"
style={{
maxWidth: "900px",
backgroundColor: "#ffffff",
borderRadius: "10px",
boxShadow: "0 4px 10px rgba(0, 0, 0, 0.2)",
border: "1px solid #ddd",
marginBottom: "4rem"
}}
>
{/* Header Section */}
<h3 className="d-inline" style={{ fontWeight: 300 }}>
<strong>REPORT SET UP - Project Details Report</strong>
</h3>
<Badge color="info" className="ms-3">
Edit Mode
</Badge>
{reportId && (
<Badge color="primary" className="ms-2">
ID: {reportId}
</Badge>
)}
<hr />
{/* Form Section */}
<Form onSubmit={handleSubmit}>
<Row>
{/* URL Input Field */}
<Col md={6} sm={12} className="mb-4">
<FormGroup>
<Label htmlFor="url" className="fw-bold">
Get URL
</Label>
<div className="d-flex align-items-center">
<Input
type="text"
id="url"
name="url"
value={entryForm.url}
onChange={handleInputChange}
placeholder="Enter URL"
className="me-2"
style={{ borderColor: "#0E6591" }}
/>
<Button
color="primary"
onClick={() => getKeys(entryForm.url)}
style={{ backgroundColor: "#0E6591", borderColor: "#0E6591" }}
>
<i className="bi bi-list"></i>
</Button>
</div>
</FormGroup>
</Col>
{/* Checkbox for Date Filter */}
<Col md={6} sm={12} className="mb-4">
<FormGroup>
<Label htmlFor="date_param_req" className="fw-bold">
Include Date Filter
</Label>
<div className="d-flex align-items-center">
<Input
type="checkbox"
id="date_param_req"
name="date_param_req"
checked={entryForm.date_param_req}
onChange={handleInputChange}
className="ms-2"
/>
</div>
</FormGroup>
</Col>
{/* Standard Parameters Selection */}
<Col md={6} sm={12} className="mb-4">
<FormGroup>
<Label className="fw-bold">Standard Parameters</Label>
<div>
{/* Multiselect dropdown for parameters */}
<Multiselect
options={keysFromUrl.map(key => ({ name: key, id: key }))}
selectedValues={entryForm.std_param_html.map(param => ({ name: param, id: param }))}
onSelect={(selectedList) => handleMultiselectSelect(selectedList.map(item => item.id))}
onRemove={(selectedList) => handleMultiselectRemove(selectedList.map(item => item.id))}
displayValue="name"
placeholder="Select Parameters"
showCheckbox={true}
style={{
searchBox: {
borderRadius: '0.25rem',
border: '1px solid #0E6591'
},
chips: {
background: "#0E6591"
},
optionContainer: {
borderColor: "#0E6591"
}
}}
/>
</div>
</FormGroup>
</Col>
{/* List Dropdown */}
<Col md={6} sm={12} className="mb-4">
<FormGroup>
<Label className="fw-bold">List</Label>
<Input
type="select"
className="form-control"
style={{ borderColor: "#0E6591" }}
>
<option value="">Choose from list</option>
{databaseList.map((item, index) => (
<option key={index} value={item.name}>
{item.name}
</option>
))}
</Input>
</FormGroup>
</Col>
</Row>
{/* Action Buttons */}
<div className="text-center mt-4">
<Button
color="secondary"
outline
className="me-3"
onClick={handleBack}
style={{
borderColor: "#6c757d",
color: "#6c757d",
borderRadius: "20px",
fontWeight: "bold",
}}
type="button"
>
BACK
</Button>
<Button
type="submit"
color="primary"
style={{
backgroundColor: "#0E6591",
borderColor: "#0E6591",
borderRadius: "20px",
fontWeight: "bold",
}}
>
UPDATE
</Button>
</div>
</Form>
</Container>
);
};
export default ReportBuild2;

View File

@@ -0,0 +1,10 @@
import React from 'react';
import { render } from '@testing-library/react';
import ReportBuild2 from './ReportBuild2';
describe('ReportBuild2 Component', () => {
it('should render without crashing', () => {
const { getByText } = render(<ReportBuild2 />);
expect(getByText('Report Build 2 Component')).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,15 @@
import React, { useEffect } from 'react';
const ReportBuild2 = () => {
useEffect(() => {
// Component did mount equivalent
}, []);
return (
<div className="report-build2">
<h1>Report Build 2 Component</h1>
</div>
);
};
export default ReportBuild2;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
import React,{useState,useEffect} from "react";
import "../Dashboard/CSS/CSS/SetupView.css"; // Assuming you have a CSS file for styling
import { useNavigate } from "react-router-dom";
import Spinner from '../../UIComponants/Spinner';
function SetupView({
onUserMaintenanceClick,
onMenuAccessControl,
onUserGroupMaintenance,
onSystemParameter,
onMenuMaintenance,
onAccessType,
onAPIregistry,
onTokenregistry,
onDataType1,
onDataType2,
onDataType3,
onDataType4,
onDataType5,
onDataType6,
onDynamicTable,
oncodeExtension,
}) {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
return (
<div className="setup-view">
{loading ? (
<Spinner /> // Display the spinner while loading
) : (
<div className="usercards-container">
<div className="usercards">
<div
className="usercard"
onClick={() => {
console.log("User Maintenance card clicked");
console.log("Navigating to:", "/admin/user-maintenance");
navigate("/admin/user-maintenance");
}}
// onClick={onUserMaintenanceClick}
>
<i className="fa fa-user-cog card-icon"></i>
<h3>User Maintenance</h3>
<p>Content for Card 1</p>
</div>
<div
className="usercard"
onClick={() => {
navigate("/admin/menu-access-control");
// navigate("/admin/menu-access-control2")
}}
>
<i className="fa-solid fa-lock"></i>
<h3>Menu Access Control</h3>
<p>Content for Card 2</p>
</div>
<div className="usercard" onClick={() => {
navigate("/admin/user-Group-Maintenance");
}}>
<i className="fa-solid fa-users"></i>
<h3>User Group Maintenance</h3>
<p>Content for Card 3</p>
</div>
<div className="usercard" onClick={() => {
navigate("/admin/system-parameter");
}}>
<i className="fa-solid fa-gears"></i>
<h3>System Parameter</h3>
<p>Content for Card 4</p>
</div>
<div className="usercard" onClick={() => {
navigate("/admin/menu-maintenance");
}}>
<i className="fa-solid fa-utensils"></i>
<h3>Menu Maintenance</h3>
<p>Content for Card 5</p>
</div>
<div className="usercard" onClick={() => {
navigate("/admin/access-type");
}}>
<i className="fa-solid fa-key"></i>
<h3>Access Type</h3>
<p>Content for Card 6</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/api-registry")
}}>
<i className="fas fa-database"></i>
<h3>API Registry</h3>
<p>Content for Card 7</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/token-registry")
}}>
<i className="fas fa-key"></i>
<h3>Token Registry</h3>
<p>Content for Card 8</p>
</div>
{/* <div className="usercard" onClick={()=>{
navigate("/admin/datatype-1")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE1</h3>
<p>Content for Card 9</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/datatype-2")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE2</h3>
<p>Content for Card 10</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/datatype-3")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE3</h3>
<p>Content for Card 11</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/datatype-4")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE4</h3>
<p>Content for Card 12</p>
</div>
<div className="usercard"onClick={()=>{
navigate("/admin/datatype-5")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE5</h3>
<p>Content for Card 13</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/datatype-6")
}}>
<i className="fa fa-file"></i>
<h3>DATATYPE6</h3>
<p>Content for Card 14</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/basics-datatypes")
}}>
<i className="fa fa-file"></i>
<h3>Basics Datatypes</h3>
<p>Content for Card 15</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/advance-datatypes")
}}>
<i className="fa fa-file"></i>
<h3>Advanced Datatypes</h3>
<p>Content for Card 16</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/advance-datatypes2")
}}>
<i className="fa fa-file"></i>
<h3>Advanced Datatypes 2</h3>
<p>Content for Card 17</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/premium-datatypes")
}}>
<i className="fa fa-file"></i>
<h3>Premium Datatypes</h3>
<p>Content for Card 18</p>
</div> */}
<div className="usercard" onClick={()=>{
navigate("/admin/user-report")
}}>
<i className="fa fa-file"></i>
<h3>Reports</h3>
<p>Report Description</p>
</div>
<div className="usercard" onClick={()=>{
navigate("/admin/dynamic-form")
}}>
<i className="fa fa-file"></i>
<h3>DynamicForm</h3>
<p>Content for Card 16</p>
</div>
</div>
</div>
)}
</div>
);
}
export default SetupView;

View File

@@ -0,0 +1,548 @@
import React, { useState, useEffect } from "react";
import Spinner from "../../UIComponants/Spinner";
import "../Dashboard/CSS/CSS/MenuMaitenance.css";
import { Table, Pagination, PaginationItem, PaginationLink } from "reactstrap";
import { BsJournals } from "react-icons/bs";
import {
Button,
Dropdown,
Modal,
Form,
Row,
Col,
InputGroup,
FormControl,
OverlayTrigger,
Tooltip,
} from "react-bootstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { FaSearch } from "react-icons/fa";
import { faEdit, faTrashAlt } from "@fortawesome/free-solid-svg-icons";
import { addSubmenuItem } from "../../APIServices/MenuMaintenanceAPI";
import { toast } from "react-toastify";
const SubMenuMaintenance = ({ selectedMainMenuId }) => {
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [subMenu, setSubMenu] = useState([]);
const [modalAdd, setModalAdd] = useState(false);
const [modalDelete, setModalDelete] = useState(false);
const [modalEdit, setModalEdit] = useState(false);
const [loading, setLoading] = useState(false);
const [rowSelected, setRowSelected] = useState({});
const [entryForm, setEntryForm] = useState({
menuId: selectedMainMenuId,
menuItemDesc: "",
itemSeq: "",
moduleName: "",
status: "Enable",
main_menu_action_name: "",
});
const [data, setData] = useState([]);
const [visibleColumns, setVisibleColumns] = useState({
menu_id: true,
menuItemDesc: true,
itemSeq: true,
moduleName: true,
main_menu_action_name: true,
status: true,
});
const [isSubMenu, setIsSubMenu] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [menuItems, setMenuItems] = useState([]);
const [slicedSubMenus, setSlicedSubMenus] = useState([]);
const [currentMenuItem, setCurrentMenuItem] = useState({});
const [subMenuItems, setSubMenuItems] = useState([]);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
useEffect(() => {
if (selectedMainMenuId) {
setEntryForm((prev) => ({ ...prev, menuId: selectedMainMenuId }));
}
}, [selectedMainMenuId]);
useEffect(() => {
const filteredSubMenus = subMenu
.filter(
(submenu) =>
submenu.menuItemDesc &&
submenu.menuItemDesc.toLowerCase().includes(searchQuery.toLowerCase())
)
.slice((currentPage - 1) * recordsPerPage, currentPage * recordsPerPage);
setSlicedSubMenus(filteredSubMenus);
}, [subMenu, searchQuery, currentPage, recordsPerPage]);
const handleInputChange = (e) => {
const { name, value } = e.target;
setEntryForm((prev) => ({ ...prev, [name]: value }));
};
const handleRowChange = (e) => {
const { name, value } = e.target;
setRowSelected((prev) => ({ ...prev, [name]: value }));
};
const handleSearch = (query) => {
setSearchQuery(query);
};
// const goToAdd = () => {
// setEntryForm((prev) => ({
// ...prev,
// menuId: selectedMainMenuId, // Set the main menu ID
// }));
// setModalAdd(true);
// };
const goToAdd = () => {
console.log("selectedMainMenuId:", selectedMainMenuId); // Debugging line
if (!selectedMainMenuId) {
toast.error("Please select a main menu item first.");
return;
}
setEntryForm((prev) => ({
...prev,
menuId: selectedMainMenuId,
}));
setModalAdd(true);
};
const onSubmit = async (event) => {
event.preventDefault();
// Include menuId in the form data
const formData = {
menuItemDesc: entryForm.menuItemDesc,
};
try {
// Pass menuId as a string
const data = await addSubmenuItem(
selectedMainMenuId.toString(),
formData
);
toast.success("Submenu item added successfully!");
console.log("Submenu item added successfully:", data);
// Handle successful submission, e.g., close modal, refresh data, etc.
setModalAdd(false);
} catch (error) {
console.error("Error adding submenu item:", error);
toast.error(
"Unexpected error: " +
(error.message || "Server error occurred. Please try again.")
);
// Handle error, e.g., show a message to the user
}
};
const goToEdit = (user) => {
setRowSelected(user);
setEntryForm({
menuId: user.menuId,
menuItemDesc: user.menuItemDesc,
});
setModalEdit(true);
};
const onUpdate = (e) => {
e.preventDefault();
// Prepare the updated entry from the form
const updatedEntry = {
menuId: entryForm.menuId,
menuItemDesc: entryForm.menuItemDesc,
// Add other fields as needed
};
// Find the index of the subMenu to update
const index = slicedSubMenus.findIndex(
(subMenu) => subMenu.menuId === updatedEntry.menuId
);
if (index !== -1) {
// Update the subMenu in the state
const updatedSubMenus = [...slicedSubMenus];
updatedSubMenus[index] = updatedEntry;
// Update the state with the new subMenus list
setSlicedSubMenus(updatedSubMenus);
// Close the modal after updating
setModalEdit(false);
}
};
const onDelete = (user) => {
setRowSelected(user);
setModalDelete(true);
};
const confirmDelete = () => {
// Logic to delete
console.log("Deleted:", rowSelected);
setModalDelete(false);
};
// pagination
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const totalPages = Math.ceil(subMenu.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const handleRecordsPerPageChange = (number) => {
setRecordsPerPage(number);
};
return (
<div style={{ marginTop: "11rem" }}>
{loading ? (
<Spinner />
) : (
<div className="submenu-maintenance">
{/* Header */}
<div className="row mt-3">
<div className="col-md-8">
<h3 className=" d-inline title_main">Sub-Menu Maintenance</h3>
<span className="badge bg-primary ms-3">Sub Menu</span>
</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>
<Col xs={12} md={4} lg={6} className="d-flex justify-content-end">
<div className="col-md-4 text-end">
<button className="btn btn-primary" onClick={goToAdd}>
<i className="bi bi-plus"></i> ADD
</button>
</div>
</Col>
</Row>
<div className="table-responsive">
<Table
striped
responsive
hover
align="middle"
className="table-flush shadow-sm"
>
<thead className="custom_header">
<tr>
<th>No</th>
{Object.entries(visibleColumns).map(
([key, visible]) =>
visible && (
<th key={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</th>
)
)}
<th>Actions</th>
</tr>
</thead>
<tbody className="tbody">
{slicedSubMenus.length === 0 ? (
<tr>
<td
colSpan={
1 + // For the "No" column
Object.keys(visibleColumns).filter(
(key) => visibleColumns[key]
).length +
(isSubMenu ? 1 : 2)
}
className="text-center"
>
No menu items found. Please add new items.
</td>
</tr>
) : (
slicedSubMenus.map((subMenu, index) => (
<tr key={index}>
<td>{index + 1}</td>
{Object.keys(visibleColumns).map(
(key) =>
visibleColumns[key] && (
<td key={key}>
{key === "status" ? (
<span
className="status"
style={{
color: subMenu.status ? "green" : "red",
backgroundColor: subMenu.status
? "#d4f7d4"
: "#f7d4d4",
padding: "4px 8px",
borderRadius: "4px",
display: "inline-block",
}}
>
{subMenu.status ? "Enabled" : "Disabled"}
</span>
) : (
subMenu[key]
)}
</td>
)
)}
<td className="text-center">
<FontAwesomeIcon
icon={faEdit}
onClick={() => goToEdit(subMenu)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green",
marginRight: "15px",
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => onDelete(subMenu)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545",
}}
/>
</td>
</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>
{/* Modals */}
{modalAdd && (
<div className="modal fade show d-block" tabIndex="-1">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Add Sub-Menu</h5>
<button
type="button"
className="btn-close"
onClick={() => setModalAdd(false)}
></button>
</div>
<div className="modal-body">
<form onSubmit={onSubmit}>
<input
type="text"
className="form-control mb-2"
name="menuId"
placeholder="Menu ID"
value={entryForm.menuId || selectedMainMenuId}
onChange={handleInputChange}
readOnly
/>
<input
type="text"
className="form-control mb-2"
name="menuItemDesc"
placeholder="Menu Item Name"
value={entryForm.menuItemDesc}
onChange={handleInputChange}
/>
<button type="submit" className="btn btn-primary">
Add
</button>
</form>
</div>
</div>
</div>
</div>
)}
{modalEdit && (
<div className="modal fade show d-block" tabIndex="-1">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Edit Sub-Menu</h5>
<button
type="button"
className="btn-close"
onClick={() => setModalEdit(false)}
></button>
</div>
<div className="modal-body">
<form onSubmit={onUpdate}>
<input
type="text"
className="form-control mb-2"
name="menuId"
placeholder="Menu ID"
value={entryForm.menuId}
onChange={handleInputChange}
/>
<input
type="text"
className="form-control mb-2"
name="menuItemDesc"
placeholder="Menu Item Name"
value={entryForm.menuItemDesc}
onChange={handleInputChange}
/>
<button type="submit" className="btn btn-primary">
Update
</button>
</form>
</div>
</div>
</div>
</div>
)}
</div>
)}
</div>
);
};
export default SubMenuMaintenance;

View File

@@ -0,0 +1,354 @@
// import React, { useState } from "react";
// import { Button, Form, Container, Row, Col } from "react-bootstrap";
// import "bootstrap/dist/css/bootstrap.min.css";
// const SystemParameterForm = () => {
// const [formData, setFormData] = useState({
// schedulerTimer: "",
// leaseTaxCode: "",
// vesselConfirmationProcessLimit: "",
// rowToDisplay: "",
// linkToDisplay: "",
// rowToAdd: "",
// lovRowToDisplay: "",
// lovLinkToDisplay: "",
// oldServerName: "",
// oldBase: "",
// oldAdminUser: "",
// oldServerPort: "",
// userDefaultGroup: "",
// defaultDepartment: "",
// defaultPosition: "",
// singleCharge: "",
// firstDayOfWeek: "",
// hourPerShift: "",
// cnBillingFrequency: "",
// billingDepartmentCode: "",
// basePriceList: "",
// nonContainerServiceOrderAutoApprovalDeptCode: "",
// ediMAESchedulerOnOff: "",
// ediSchedulerOnOff: "",
// logo: null,
// companyDisplayName: "",
// });
// const handleInputChange = (event) => {
// const { name, value } = event.target;
// setFormData((prevState) => ({
// ...prevState,
// [name]: value,
// }));
// };
// const handleFileChange = (event) => {
// setFormData((prevState) => ({
// ...prevState,
// logo: event.target.files[0],
// }));
// };
// const handleSubmit = (event) => {
// event.preventDefault();
// alert("Form submitted successfully!");
// console.log("Form Data:", formData);
// };
// const handleClear = () => {
// setFormData({
// schedulerTimer: "",
// leaseTaxCode: "",
// vesselConfirmationProcessLimit: "",
// rowToDisplay: "",
// linkToDisplay: "",
// rowToAdd: "",
// lovRowToDisplay: "",
// lovLinkToDisplay: "",
// oldServerName: "",
// oldBase: "",
// oldAdminUser: "",
// oldServerPort: "",
// userDefaultGroup: "",
// defaultDepartment: "",
// defaultPosition: "",
// singleCharge: "",
// firstDayOfWeek: "",
// hourPerShift: "",
// cnBillingFrequency: "",
// billingDepartmentCode: "",
// basePriceList: "",
// nonContainerServiceOrderAutoApprovalDeptCode: "",
// ediMAESchedulerOnOff: "",
// ediSchedulerOnOff: "",
// logo: null,
// companyDisplayName: "",
// });
// };
// return (
// <Container className="mt-5">
// <Form onSubmit={handleSubmit}>
// <Row className="mb-3">
// <Col xs={6}>
// <h5>Setup Code</h5>
// </Col>
// <Col xs={6}>
// <h5>Value</h5>
// </Col>
// </Row>
// {Object.keys(formData).map((key, index) =>
// key !== "logo" ? (
// <Row className="mb-3" key={index}>
// <Col xs={6}>
// <Form.Label>
// {key
// .split(/(?=[A-Z])/)
// .join(" ")
// .replace(/\b\w/g, (l) => l.toUpperCase())}
// </Form.Label>
// </Col>
// <Col xs={6}>
// <Form.Control
// style={{ borderColor: '#343a40' }}
// type="text"
// name={key}
// value={formData[key]}
// onChange={handleInputChange}
// />
// </Col>
// </Row>
// ) : (
// <Row className="mb-3" key={index}>
// <Col xs={6}>
// <Form.Label>Upload Logo</Form.Label>
// </Col>
// <Col xs={6}>
// <Form.Control style={{ borderColor: '#343a40' }} type="file" onChange={handleFileChange} />
// </Col>
// </Row>
// )
// )}
// <div className="d-flex justify-content-end">
// <Button variant="secondary" type="submit" className="me-2">
// Save
// </Button>
// <Button variant="secondary" onClick={handleClear}>
// Clear
// </Button>
// </div>
// </Form>
// </Container>
// );
// };
// export default SystemParameterForm;
import React, { useState, useEffect } from "react";
import { Button, Form, Container, Row, Col } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import "../Dashboard/CSS/CSS/CommonStyle.css";
import { toast } from "react-toastify";
import Spinner from "../../UIComponants/Spinner";
import {getSysParameter,addSysParameter} from "../../APIServices/SystemparameterApi";
const SystemParameterForm = () => {
const [formData, setFormData] = useState({
schedulerTimer: "",
leaseTaxCode: "",
vesselConfirmationProcessLimit: "",
rowToDisplay: "",
linkToDisplay: "",
rowToAdd: "",
lovRowToDisplay: "",
lovLinkToDisplay: "",
oldServerName: "",
oldBase: "",
oldAdminUser: "",
oldServerPort: "",
userDefaultGroup: "",
defaultDepartment: "",
defaultPosition: "",
singleCharge: "",
firstDayOfWeek: "",
hourPerShift: "",
cnBillingFrequency: "",
billingDepartmentCode: "",
basePriceList: "",
nonContainerServiceOrderAutoApprovalDeptCode: "",
ediMAESchedulerOnOff: "",
ediSchedulerOnOff: "",
logo: null,
companyDisplayName: "",
});
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleInputChange = (event) => {
const { name, value } = event.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleFileChange = (event) => {
setFormData((prevState) => ({
...prevState,
logo: event.target.files[0],
}));
};
// const handleSubmit = (event) => {
// event.preventDefault();
// toast.success("Form submitted successfully!");
// // alert("Form submitted successfully!");
// console.log("Form Data:", formData);
// };
const handleSubmit = async (event) => {
event.preventDefault();
try {
const sysParamData = await addSysParameter(formData);
console.log("API Response:", sysParamData);
toast.success("Form submitted successfully!");
} catch (error) {
console.error("Error:", error.response ? error.response.data : error.message);
toast.error("Failed to submit the form. Please try again.");
}
};
const handleClear = () => {
setFormData({
schedulerTimer: "",
leaseTaxCode: "",
vesselConfirmationProcessLimit: "",
rowToDisplay: "",
linkToDisplay: "",
rowToAdd: "",
lovRowToDisplay: "",
lovLinkToDisplay: "",
oldServerName: "",
oldBase: "",
oldAdminUser: "",
oldServerPort: "",
userDefaultGroup: "",
defaultDepartment: "",
defaultPosition: "",
singleCharge: "",
firstDayOfWeek: "",
hourPerShift: "",
cnBillingFrequency: "",
billingDepartmentCode: "",
basePriceList: "",
nonContainerServiceOrderAutoApprovalDeptCode: "",
ediMAESchedulerOnOff: "",
ediSchedulerOnOff: "",
logo: null,
companyDisplayName: "",
});
};
return (
<div
style={{
marginTop: "10rem",
marginBottom: "2rem",
boxSizing: "border-box",
}}
>
{loading ? (
<Spinner />
) : (
<Container
className="system_parameter mt-5 p-4 bg-light shadow-sm rounded"
>
<h2
className="title_main text-center mb-4"
style={{ color: "#0E6591", fontWeight: "bold" }}
>
System Parameter Settings
</h2>
<Form onSubmit={handleSubmit}>
<Row className=" mb-3">
<Col xs={6}>
<h6 className="heading_main text-secondary">Setup Code</h6>
</Col>
<Col xs={6}>
<h6 className="heading_main text-secondary">Value</h6>
</Col>
</Row>
{Object.keys(formData).map((key, index) =>
key !== "logo" ? (
<Row className="mb-3" key={index}>
<Col xs={6} className="d-flex align-items-center">
<Form.Label className="mb-0">
{key
.split(/(?=[A-Z])/)
.join(" ")
.replace(/\b\w/g, (l) => l.toUpperCase())}
</Form.Label>
</Col>
<Col xs={6}>
<Form.Control
className="p-2 custom-hover-border"
style={{ borderColor: "#ced4da" }}
type="text"
name={key}
value={formData[key]}
onChange={handleInputChange}
/>
</Col>
</Row>
) : (
<Row className="mb-3" key={index}>
<Col xs={6} className="d-flex align-items-center">
<Form.Label className="mb-0">Upload Logo</Form.Label>
</Col>
<Col xs={6}>
<Form.Control
className="p-2 "
style={{ borderColor: "#ced4da" }}
type="file"
onChange={handleFileChange}
/>
</Col>
</Row>
)
)}
<div className="d-flex justify-content-end mt-4">
<Button
variant="primary"
type="submit"
className="me-2 px-4 py-2 custom_button"
>
Save
</Button>
<Button
variant="outline"
onClick={handleClear}
className="px-4 py-2 custom_button"
>
Clear
</Button>
</div>
</Form>
</Container>
)}
</div>
);
};
export default SystemParameterForm;

View File

@@ -0,0 +1,462 @@
import React, { useState, useEffect } from "react";
import { Button, Dropdown,Modal, Form ,Row,Col,InputGroup,FormControl} from "react-bootstrap";
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 { Table, Pagination, PaginationItem, PaginationLink } from "reactstrap";
import { FaSearch, FaTimes } from "react-icons/fa";
import { BsJournals } from "react-icons/bs";
import { toast } from "react-toastify";
import Spinner from '../../UIComponants/Spinner';
function TOKENRegistry() {
const initialTokens = JSON.parse(localStorage.getItem("tokens")) || [];
const [tokens, setTokens] = useState(initialTokens);
const [showAddEditModal, setShowAddEditModal] = useState(false);
const [currentToken, setCurrentToken] = useState({
tokenId: "",
tokenName: "",
tokenValue: "",
isActive: true
});
const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [visibleColumns, setVisibleColumns] = useState({
tokenId: true,
tokenName: true,
tokenValue: true,
isActive: true,
actions: true
});
const [loading, setLoading] = useState(true);
useEffect(() => {
const apiUrl = `${process.env.REACT_APP_API_URL}/apiregistery/getall`;
const token = localStorage.getItem("authToken");
const fetchTokens = 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();
setTokens(data);
localStorage.setItem("tokens", JSON.stringify(data)); // Store tokens in local storage
} catch (error) {
console.error("Error fetching tokens:", error);
}
};
fetchTokens();
}, []);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const toggleColumn = (column) => {
setVisibleColumns(prev => ({
...prev,
[column]: !prev[column],
}));
};
const handleInputChange = (event) => {
const { name, value, type, checked } = event.target;
setCurrentToken(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
};
const handleSearch = (query) => {
setSearchQuery(query);
};
const handleClose = () => {
setShowAddEditModal(false); // Close the modal by setting the state to false
};
const handleRecordsPerPageChange = (number) => {
setRecordsPerPage(number);
setCurrentPage(1);
};
const totalPages = Math.ceil(tokens.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const slicedTokens = tokens
.filter(
(item) =>
item.tokenName &&
item.tokenName.toLowerCase().includes(searchQuery.toLowerCase())
)
.slice((currentPage - 1) * recordsPerPage, currentPage * recordsPerPage);
const handleSubmit = (event) => {
event.preventDefault();
try {
if (isEditing) {
setTokens(tokens.map(token =>
token.tokenId === currentToken.tokenId ? currentToken : token
));
toast.success("Token updated successfully!");
} else {
const newTokenId = `ID${tokens.length + 1}`;
setTokens([...tokens, { ...currentToken, tokenId: newTokenId }]);
toast.success("Token added successfully!");
}
setShowAddEditModal(false);
localStorage.setItem("tokens", JSON.stringify(tokens)); // Update local storage with new tokens
} catch (error) {
toast.error("There was an error while submitting the token.");
console.error("Error in handleSubmit:", error); // Log the error for debugging
}
};
const openModal = (token = { tokenId: "", tokenName: "", tokenValue: "", isActive: false }) => {
setIsEditing(!!token.tokenId);
setCurrentToken(token);
setShowAddEditModal(true);
};
const handleDelete = (tokenId) => {
setTokens(tokens.filter(token => token.tokenId !== tokenId));
localStorage.setItem("tokens", JSON.stringify(tokens.filter(token => token.tokenId !== tokenId))); // Update local storage after deletion
toast.success('Token deleted ...');
};
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">
<h1 className="title_main">Token Registry</h1>
</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={() => openModal(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.keys(visibleColumns).filter(key => visibleColumns[key]).map(key => (
<th key={key}>{key.charAt(0).toUpperCase() + key.slice(1)}</th>
))}
</tr>
</thead>
<tbody className="tbody">
{slicedTokens.length === 0 ? (
<tr>
<td
colSpan={
Object.keys(visibleColumns).filter(
(key) => visibleColumns[key]
).length
}
className="text-center"
>
No Data Available
</td>
</tr>
) : (
slicedTokens.map((token, index) => (
<tr key={index}>
{Object.keys(visibleColumns).filter(key => visibleColumns[key]).map(key => (
<td key={key}>
{key === "actions" ? (
<>
<FontAwesomeIcon
icon={faEdit}
onClick={() => openModal(token)}
className="me-2"
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green",
marginRight: "15px",
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => handleDelete(token.tokenId)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545",
}}
/>
</>
) : key === "isActive" ? (
<span
className="status"
style={{
color: token.isActive ? "green" : "red",
backgroundColor: token.isActive
? "#d4f7d4"
: "#f7d4d4",
padding: "4px 8px",
borderRadius: "4px",
display: "inline-block",
}}
>
{token.isActive ? "Active" : "Inactive"}
</span>
) : (
token[key]
)}
</td>
))}
</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>
<Modal show={showAddEditModal} onHide={() => setShowAddEditModal(false)}>
<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">
<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">
<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="formActive">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentToken.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button variant="primary" className="custom_button px-4" onClick={() => setShowAddEditModal(false)}>Close</Button>
<Button variant="primary" className="custom_button px-4" type="submit">{isEditing ? "Update Token" : "Add Token"}</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div>
)}
</div>
);
}
export default TOKENRegistry;

View File

@@ -0,0 +1,768 @@
import React, { useState, useEffect } from "react";
import {
Button,
Dropdown,
Modal,
Form,
Row,
Col,
InputGroup,
FormControl,
} from "react-bootstrap";
import { Table, Pagination, PaginationItem, PaginationLink } from "reactstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faEdit,
faTrashAlt,
faPlus,
faBars,
faTimes,
faFileExcel,
faUpload,
faDownload,
} from "@fortawesome/free-solid-svg-icons";
import "bootstrap/dist/css/bootstrap.min.css";
import "../Dashboard/CSS/CSS/CommonStyle.css";
import { FaSearch } from "react-icons/fa";
import { BsJournals } from "react-icons/bs";
import { toast } from "react-toastify";
import Spinner from "../../UIComponants/Spinner";
import { Tooltip, OverlayTrigger } from "react-bootstrap";
import * as XLSX from "xlsx";
import { fetchUserGroups } from "../../APIServices/UserGroupMaintenanceApi";
import ExcelControlAPI from "../../APIServices/ExcelControlApi";
import { createUserGroup, deleteUserGroup, updateUserGroup} from "../../APIServices/UserGroupMaintenanceApi";
export function UserGroupMaintenance() {
const [userGroups, setUserGroups] = useState([]);
const [showAddItemPopup, setShowAddItemPopup] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState("");
const [loading, setLoading] = useState(true);
const [showModal, setShowModal] = useState(false);
const [excelData, setExcelData] = useState([]);
const [newGroupData, setNewGroupData] = useState({
usrGrp: "",
groupName: "",
groupDesc: "",
status: "",
groupLevel: "",
});
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [visibleColumns, setVisibleColumns] = useState({
usrGrp: true,
groupName: true,
groupDesc: true,
status: true,
groupLevel: true,
});
const [isEditing, setIsEditing] = useState(false);
// useEffect(() => {
// const apiUrl = `${process.env.REACT_APP_API_URL}/api/getAllUsrGrp`;
// const token = localStorage.getItem("authToken");
// const fetchUserGroups = 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();
// setUserGroups(data);
// } catch (error) {
// console.error("Fetching error:", error);
// }
// };
// fetchUserGroups();
// }, []);
useEffect(() => {
const loadUserGroups = async () => {
try {
const data = await fetchUserGroups();
setUserGroups(data);
console.log("all user group data ", data);
} catch (error) {
toast.error("Failed to load user groups.");
} finally {
setLoading(false);
}
};
loadUserGroups();
}, []);
useEffect(() => {
// Simulate loading data
setTimeout(() => {
setLoading(false);
}, 3000); // Simulated 3 seconds loading
}, []);
const handleOpenModal = () => setShowModal(true);
const handleCloseModal = () => setShowModal(false);
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
console.log("Selected file:", file.name); // For debugging or processing
}
};
const handleUpload = () => {
// Simulate file upload success
setTimeout(() => {
toast.success("File uploaded successfully!"); // Show toaster notification
setShowModal(false); // Close modal
}, 1000);
};
const exportToExcel = async (fileType) => {
try {
// Fetch binary Excel data
const response = await ExcelControlAPI.demoDownload(fileType);
// Log the response size for debugging
const dataSize = response.data?.byteLength || response.data?.length;
console.log("Response Data Size:", dataSize);
// If file is too large, show error and exit
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
if (dataSize > MAX_FILE_SIZE) {
console.error("File is too large to process");
return;
}
// Convert binary data to a Blob
const blob = new Blob([response.data], {
type: "application/vnd.ms-excel",
});
// Use FileReader to convert Blob to ArrayBuffer
const arrayBuffer = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsArrayBuffer(blob);
});
console.log("ArrayBuffer Size:", arrayBuffer.byteLength);
// Parse Excel data
const workbook = XLSX.read(arrayBuffer, { type: "array" });
console.log("workbook", workbook);
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// Convert worksheet to JSON
const jsonData = XLSX.utils.sheet_to_json(worksheet);
console.log("Parsed JSON Data:", jsonData);
// Create a new workbook and trigger download
const newWorksheet = XLSX.utils.json_to_sheet(jsonData);
const newWorkbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(newWorkbook, newWorksheet, fileType);
XLSX.writeFile(newWorkbook, `${fileType}_processed.xlsx`);
console.log("Excel file generated successfully!");
} catch (error) {
console.error("Error exporting to Excel:", error);
}
};
const toggleColumn = (column) => {
setVisibleColumns((prev) => ({
...prev,
[column]: !prev[column],
}));
};
const handleAddItem = () => {
setIsEditing(false);
setNewGroupData({
usrGrp: "",
groupName: "",
groupDesc: "",
status: "",
groupLevel: "",
});
setShowAddItemPopup(true);
};
const handleInputChange = (event) => {
const { name, value } = event.target;
setNewGroupData({ ...newGroupData, [name]: value });
};
const handleSubmit = async (event) => {
event.preventDefault();
try {
// Validate input fields
if (
!newGroupData.usrGrp ||
!newGroupData.groupName ||
!newGroupData.groupDesc ||
!newGroupData.status ||
!newGroupData.groupLevel
) {
toast.error("Please make sure all fields are filled out.");
return;
}
if (isEditing) {
// Update existing group data
setUserGroups(
userGroups.map((group) =>
group.usrGrp === newGroupData.usrGrp ? newGroupData : group
)
);
toast.success("Menu access updated successfully!");
} else {
// Make an API call to create a new user group
const newGroup = { ...newGroupData }; // Prepare data for API
const response = await createUserGroup(newGroup); // Call API function
if (response && response.data) {
// Update userGroups state with the newly created group
setUserGroups([...userGroups, response.data]);
toast.success("Menu access added successfully!");
} else {
toast.error("Failed to add menu access.");
}
}
// Close the modal and reset the form
setShowAddItemPopup(false);
setNewGroupData({
usrGrp: "",
groupName: "",
groupDesc: "",
status: "",
groupLevel: "",
});
} catch (error) {
toast.error("There was an error processing your request.");
console.error("Error in handleSubmit:", error); // Log the error for debugging
}
};
const handleSearch = (query) => {
setSearchQuery(query);
};
const handleClose = () => {
setShowAddItemPopup(false); // Close the modal by setting the state to false
};
const handleEdit = (usrGrp) => {
const groupToEdit = userGroups.find((group) => group.usrGrp === usrGrp);
setIsEditing(true);
setNewGroupData(groupToEdit);
setShowAddItemPopup(true);
};
// const handleDelete = (usrGrp) => {
// setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp));
// toast.success("Menu Access delet successfully!");
// };
const handleDelete = async (usrGrp) => {
try {
// Call API to delete the user group
const response = await deleteUserGroup(usrGrp);
if (response && response.data) {
// Update state after successful API call
setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp));
toast.success("User group deleted successfully!");
}
} catch (error) {
toast.error("Error deleting Menu Access!");
}
};
const handleRecordsPerPageChange = (number) => {
setRecordsPerPage(number);
setCurrentPage(1);
};
const totalPages = Math.ceil(userGroups.length / recordsPerPage);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const slicedUserGroup = userGroups
.filter(
(item) =>
item.groupName &&
item.groupName.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">
<h1 className="title_main">User Group Maintenance</h1>
</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">
<>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip>Add Group</Tooltip>}
>
<FontAwesomeIcon
icon={faPlus}
onClick={() => handleAddItem(true)}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
marginRight: "20px",
}}
/>
</OverlayTrigger>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip>Download template</Tooltip>}
>
<FontAwesomeIcon
icon={faDownload}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
marginRight: "20px",
}}
/>
</OverlayTrigger>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip>Import</Tooltip>}
>
<span style={{ cursor: "pointer" }}>
<FontAwesomeIcon
icon={faUpload}
style={{
fontSize: "1.5rem",
color: "#747264", // Color for the icon
marginRight: "20px",
}}
onClick={handleOpenModal} // Open modal on click
/>
</span>
</OverlayTrigger>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip>XLSX</Tooltip>}
>
<FontAwesomeIcon
icon={faFileExcel}
onClick={() => exportToExcel("customer")}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
marginRight: "20px",
}}
/>
</OverlayTrigger>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip>Menu</Tooltip>}
>
<FontAwesomeIcon
icon={faBars}
style={{
cursor: "pointer",
fontSize: "1.5rem",
color: "#747264",
}}
/>
</OverlayTrigger>
{/* Add Icon */}
</>
</Col>
</Row>
<Modal show={showModal} onHide={handleCloseModal} centered>
<Modal.Header closeButton>
<Modal.Title>Import File</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formFile" className="mb-3">
<Form.Label>Select a file to import:</Form.Label>
<Form.Control
type="file"
accept=".xlsx, .xls, .csv" // Restrict file types
onChange={handleFileChange} // Handle file selection
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleCloseModal}>
Cancel
</Button>
<Button variant="primary" onClick={handleUpload}>
Upload
</Button>
</Modal.Footer>
</Modal>
<div className="table-responsive">
<Table
striped
hover
responsive
align="middle"
className="table-flush shadow-sm"
>
<thead className="custom_header">
<tr>
{Object.keys(visibleColumns).map((key) => (
<th
key={key}
style={{ display: visibleColumns[key] ? "" : "none" }}
>
{key.charAt(0).toUpperCase() + key.slice(1).toLowerCase()}
</th>
))}
<th>Actions</th>
</tr>
</thead>
<tbody className="tbody">
{slicedUserGroup.length === 0 ? (
<tr>
<td
colSpan={
Object.keys(visibleColumns).filter(
(key) => visibleColumns[key]
).length + 1 // +1 for Actions column
}
className="text-center"
>
No data available
</td>
</tr>
) : (
slicedUserGroup.map((group, index) => (
<tr key={index}>
{Object.keys(visibleColumns).map((key) =>
visibleColumns[key] ? (
<td key={key}>
{key === "status" ? (
// Render status dynamically based on isActive or status key
<span
className="status"
style={{
color:
group.status === "Enabled"
? "green"
: "red",
backgroundColor:
group.status === "Enabled"
? "#d4f7d4"
: "#f7d4d4",
padding: "4px 8px",
borderRadius: "4px",
display: "inline-block",
}}
>
{group.status === "Enabled"
? "Active"
: "Inactive"}
</span>
) : (
group[key]
)}
</td>
) : null
)}
<td>
{/* Adding Action icons */}
<FontAwesomeIcon
icon={faEdit}
onClick={() => handleEdit(group.usrGrp)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "green",
marginRight: "15px",
}}
/>
<FontAwesomeIcon
icon={faTrashAlt}
onClick={() => handleDelete(group.usrGrp)}
style={{
cursor: "pointer",
fontSize: "1rem",
color: "#dc3545",
}}
/>
</td>
</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={showAddItemPopup}
onHide={() => setShowAddItemPopup(false)}
>
<Modal.Header>
<Modal.Title>
{isEditing ? "Edit Group" : "Add New Group"}
</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="usrGrp">
<Form.Label>User Group</Form.Label>
<Form.Control
type="text"
name="usrGrp"
value={newGroupData.usrGrp}
onChange={handleInputChange}
className="custom-hover-border"
required
/>
</Form.Group>
<Form.Group controlId="groupName">
<Form.Label>Group Name</Form.Label>
<Form.Control
type="text"
name="groupName"
value={newGroupData.groupName}
onChange={handleInputChange}
className="custom-hover-border"
required
/>
</Form.Group>
<Form.Group controlId="groupDesc">
<Form.Label>Description</Form.Label>
<Form.Control
type="text"
name="groupDesc"
value={newGroupData.groupDesc}
onChange={handleInputChange}
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="status">
<Form.Label>Status</Form.Label>
<Form.Control
as="select"
name="status"
value={newGroupData.status}
onChange={handleInputChange}
className="custom-hover-border"
>
<option value="">Select Status</option>
<option value="Enabled">Enabled</option>
<option value="Disabled">Disabled</option>
</Form.Control>
</Form.Group>
<Form.Group
controlId="groupLevel"
className="custom-hover-border"
>
<Form.Label>Group Level</Form.Label>
<Form.Control
type="number"
name="groupLevel"
value={newGroupData.groupLevel}
onChange={handleInputChange}
/>
</Form.Group>
<Modal.Footer>
<Button
variant="primary"
onClick={() => setShowAddItemPopup(false)}
className="custom_button px-4"
>
Close
</Button>
<Button
type="submit"
variant="primary"
className="custom_button px-4"
>
{isEditing ? "Update Group" : "Add Group"}{" "}
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div>
)}
</div>
);
}
export default UserGroupMaintenance;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
import React from 'react'
const ValidationRule = () => {
return (
<div>ValidationRule</div>
)
}
export default ValidationRule

View File

@@ -0,0 +1,289 @@
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom'; // Add useNavigate
import { Box, Typography, CircularProgress, Card, CardHeader, CardContent, Button } from '@mui/material';
import DashboardBuilderService from "../../../APIServices/DashboardBuilderService";
// Import chart components
import LineChartComponent from '../dashboardnew/gadgets/line-chart/LineChart';
import PieChartComponent from '../dashboardnew/gadgets/pie-chart/Piechart';
import PolarChartComponent from '../dashboardnew/gadgets/polar-chart/PolarChart';
import RadarChartComponent from '../dashboardnew/gadgets/radar-chart/RadarChart';
import BubbleChart from '../dashboardnew/gadgets/bubble-chart/BubbleChart';
import BarChart from '../dashboardnew/gadgets/bar-chart/BarChart';
import DoughnutChart from '../dashboardnew/gadgets/doughnut-charts/DoughnutChart';
import DynamicChart from '../dashboardnew/gadgets/dynamic-chart/DynamicChart';
import FinancialChart from '../dashboardnew/gadgets/financial-chart/FinancialChart';
import GridViewComponent from '../dashboardnew/gadgets/grid-view/GridView';
import ScatterChartComponent from '../dashboardnew/gadgets/scatter-chart/ScatterChart';
import ToDoChartComponent from '../dashboardnew/gadgets/to-do-chart/TodoChart';
const ViewDashboard = () => {
const { id } = useParams(); // Get dashboard ID from URL
const navigate = useNavigate(); // Use the useNavigate hook
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [dashboard, setDashboard] = useState(null);
const [layout, setLayout] = useState([]);
// Define component mapping object
const componentMap = {
'radar_chart': RadarChartComponent,
'polar_chart': PolarChartComponent,
'pie_chart': PieChartComponent,
'bar_chart': BarChart,
'bubble_chart': BubbleChart,
'line_chart': LineChartComponent,
'doughnut_chart': DoughnutChart,
'dynamic_chart': DynamicChart,
'financial_chart': FinancialChart,
'grid_view': GridViewComponent,
'scatter_chart': ScatterChartComponent,
'todo_chart': ToDoChartComponent
};
// Component name to identifier mapping for reverse lookup
const componentNameToIdentifier = {
'Radar Chart': 'radar_chart',
'Polar Chart': 'polar_chart',
'Pie Chart': 'pie_chart',
'Bar Chart': 'bar_chart',
'Bubble Chart': 'bubble_chart',
'Line Chart': 'line_chart',
'Doughnut Chart': 'doughnut_chart',
'Dynamic Chart': 'dynamic_chart',
'Financial Chart': 'financial_chart',
'Grid View': 'grid_view',
'Scatter Chart': 'scatter_chart',
'Todo Chart': 'todo_chart'
};
// Fetch dashboard data using the ID
useEffect(() => {
const fetchDashboard = async () => {
try {
setLoading(true);
const response = await DashboardBuilderService.getById(id);
console.log("Dashboard data:", response);
setDashboard({
name: response.dashboard_name,
dashboardLine: response.dashbord1_Line
});
// Parse and transform widget data
if (response.dashbord1_Line && response.dashbord1_Line[0]?.model) {
try {
const modelData = response.dashbord1_Line[0].model;
const parsedModel = JSON.parse(modelData);
if (Array.isArray(parsedModel.dashboard)) {
console.log("Dashboard widgets from API:", parsedModel.dashboard);
// Create the layout directly from the API response
const dashboardLayout = parsedModel.dashboard.map((widget, index) => {
// Get the component identifier from name
const componentName = widget.component || "Unknown";
const typeIdentifier = componentNameToIdentifier[componentName] ||
componentName.toLowerCase().replace(' ', '_');
// Get component reference
const Component = componentMap[typeIdentifier] || null;
return {
id: `widget-${index}`,
x: widget.x || 0,
y: widget.y || 0,
w: widget.cols || 6,
h: widget.rows || 8,
name: widget.name || componentName,
component: Component,
chartTitle: widget.chartTitle || widget.name || componentName,
showLegend: widget.showLegend !== undefined ? widget.showLegend : true,
showLabel: widget.showLabel !== undefined ? widget.showLabel : true,
xAxis: widget.xAxis || 'Month',
yAxis: widget.yAxis || 'Value'
};
});
console.log("Processed layout:", dashboardLayout);
setLayout(dashboardLayout);
} else {
console.warn("Dashboard data is not an array:", parsedModel.dashboard);
setLayout([]);
}
} catch (parseError) {
console.error("Error parsing dashboard model:", parseError);
setError("Failed to parse dashboard data. The dashboard may be corrupted.");
setLayout([]);
}
} else {
console.warn("No dashboard model found");
setLayout([]);
}
} catch (error) {
console.error("Error fetching dashboard:", error);
setError("Failed to load dashboard. Please try again later.");
} finally {
setLoading(false);
}
};
if (id) {
fetchDashboard();
}
}, [id]);
// Calculate absolute positioning based on grid coordinates
const getWidgetStyle = (widget) => {
const columnWidth = 100 / 6; // 12-column grid, width percentage
const rowHeight = 40; // Fixed row height in pixels
return {
position: 'absolute',
left: `${widget.x * columnWidth}%`,
top: `${widget.y * rowHeight}px`,
width: `${widget.w * columnWidth}%`,
height: `${widget.h * rowHeight}px`,
};
};
// Render loading state
if (loading) {
return (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh'
}}
>
<CircularProgress />
<Typography variant="h6" sx={{ ml: 2 }}>
Loading Dashboard...
</Typography>
</Box>
);
}
// Render error state
if (error) {
return (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
flexDirection: 'column'
}}
>
<Typography variant="h5" color="error" gutterBottom>
Error Loading Dashboard
</Typography>
<Typography variant="body1">{error}</Typography>
</Box>
);
}
return (
<Box sx={{ padding: 0 }}>
{/* Dashboard Header */}
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h2>{dashboard?.name || 'Dashboard View'}</h2>
<Button variant="contained" onClick={() => navigate(-1)}>Back</Button>
</Box>
{/* Dashboard Content */}
{layout.length === 0 ? (
<Box sx={{ textAlign: 'center', p: 5 }}>
<Typography variant="h6">No widgets found in this dashboard.</Typography>
</Box>
) : (
<Box
sx={{
position: 'relative',
minHeight: '800px' // Set a minimum height for the dashboard area
}}
>
{layout.map((widget) => {
const Component = widget.component;
const style = getWidgetStyle(widget);
return (
<Box
key={widget.id}
sx={{
...style,
padding: 1,
boxSizing: 'border-box'
}}
>
<Card sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.08)'
}}>
<CardHeader
title={widget.chartTitle}
titleTypographyProps={{ variant: 'h6' }}
sx={{
p: 2,
pb: 1,
backgroundColor: '#fafafa',
borderBottom: '1px solid #eee'
}}
/>
<CardContent sx={{
flex: 1,
display: 'flex',
flexDirection: 'column',
p: 2,
pt: 1,
overflow: 'hidden'
}}>
{Component ? (
<Box sx={{
flexGrow: 1,
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<Component
chartTitle={widget.chartTitle}
showLegend={widget.showLegend}
showLabel={widget.showLabel}
xAxis={widget.xAxis}
yAxis={widget.yAxis}
width="100%"
height="100%"
/>
</Box>
) : (
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%'
}}>
<Typography variant="body2" color="text.secondary">
Widget type "{widget.name}" not available
</Typography>
</Box>
)}
</CardContent>
</Card>
</Box>
);
})}
</Box>
)}
</Box>
);
};
export default ViewDashboard;

View File

@@ -0,0 +1,11 @@
.card:hover {
transform: scale(1.02);
transition: transform 0.2s ease-in-out;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.card-header {
border-bottom: 1px solid rgba(255, 255, 255, 0.205);
background-color: 1px solid rgba(255, 255, 255, 0.062);
}

View File

@@ -0,0 +1,198 @@
import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import moment from "moment";
import { Toaster, toast } from "react-hot-toast";
import DashboardBuilderService from "../../../../APIServices/DashboardBuilderService";
import "./dashboardRunnerAll.css";
const DashboardRunnerAll = () => {
const [addModal, setAddModal] = useState(false);
const [data, setData] = useState([]);
const [rows, setRows] = useState([]);
const [rowSelected, setRowSelected] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [projectName, setProjectName] = useState("");
const [projectId, setProjectId] = useState(null);
const [moduleId, setModuleId] = useState(null);
const [modalDelete, setModalDelete] = useState(false);
const navigate = useNavigate();
const { id } = useParams();
useEffect(() => {
setProjectId(sessionStorage.getItem("projectId"));
setModuleId(sessionStorage.getItem("moduleId"));
fetchDashboard();
fetchProjectName(sessionStorage.getItem("projectId"));
}, []);
const fetchProjectName = (id) => {
// ModuleSetupService.getProjectModules(id).then((response) => {
// setProjectName(response.items[0]?.projectName || "");
// });
};
const fetchDashboard = () => {
setLoading(true);
DashboardBuilderService.getAllDash()
.then((response) => {
setData(response);
setRows(response);
})
.catch(() => setError("No data available"))
.finally(() => setLoading(false));
};
const handleDelete = (id) => {
setModalDelete(false);
// Dashboard3Service.deleteField(id).then(() => {
// fetchDashboard();
// toast.success("Deleted successfully");
// });
};
const handleExport = () => {
// ExcelService.exportAsExcelFile(
// rows,
// "user_",
// moment().format("YYYYMMDD_HHmmss")
// );
};
const handleAdd = () => {
navigate("/admin/dashboard-new-all");
};
const handleEdit = (id) => {
navigate(`../dashrunner/${id}`);
};
return (
<div className="dashboard-runner-all">
<div className="row">
<div className="col-8">
<h3>All Dashboards</h3>
</div>
<div className="col-4 text-right">
<button className="btn btn-primary" onClick={handleAdd}>
<i className="fa fa-plus" /> Dashboard Builder
</button>
</div>
</div>
{loading && (
<div className="alert alert-info">
<i className="fa fa-spinner fa-spin"></i> Loading...
</div>
)}
{error && <div className="alert alert-danger">{error}</div>}
{/* {!loading && data && (
<div className="row">
{data.map((app, index) => (
<div key={index} className="col-auto">
<div className="card" onClick={() => handleEdit(app.id)}>
<div className="card-header">
<i className="fa fa-th" />
<b title={app.dashboard_name}>{app.dashboard_name}</b>
<p title={app.description}>{app.description}</p>
</div>
<div className="card-footer">
<button className="btn btn-sm btn-link">
Last Updated: {moment(app.updatedAt).format("DD/MM/YYYY")}
</button>
<span>
<i className="fa fa-calendar" /> {moment(app.createdAt).format("HH:mm:ss")}
</span>
</div>
</div>
</div>
))}
</div>
)} */}
{!loading && data && (
<div className="row g-4 mt-1">
{data.map((app, index) => (
<div key={index} className="col-md-4 col-sm-6">
<div
className="card h-100 shadow-md"
onClick={() => handleEdit(app.id)}
style={{ cursor: "pointer", borderRadius: "8px" }}
>
<div className="card-header text-black d-flex align-items-center justify-content-between" style={{ fontSize:"1rem"}}>
<span>
<i className="fa fa-th me-2"></i><span> </span>
<b title={app.dashboard_name} className="text-truncate">
{app.dashboard_name}
</b>
</span>
</div>
<div className="card-body">
<p title={app.description} className="text-muted mb-2 text-truncate">
{app.description || "No description available"}
</p>
</div>
<div className="card-footer d-flex justify-content-between align-items-center">
<button className="btn btn-sm btn-link text-secondary fw-bold">
<i className="fa fa-clock me-1"></i>
Last Updated: {moment(app.updatedAt).format("DD/MM/YYYY")}
</button>
<span className="text-secondary">
<i className="fa fa-calendar me-1"></i>
{moment(app.createdAt).format("HH:mm:ss")}
</span>
</div>
</div>
</div>
))}
</div>
)}
{/* Add Modal */}
{addModal && (
<div className="modal show">
<div className="modal-body">
<div className="chart-box" onClick={handleAdd}>
<img src="/assets/images/fromscratch.png" alt="From Scratch" />
<h5>Start From Scratch</h5>
</div>
</div>
</div>
)}
{/* Delete Modal */}
{modalDelete && rowSelected && (
<div className="modal show">
<div className="modal-body">
<h1>Delete Confirmation</h1>
<h2>{rowSelected.id}</h2>
<div className="modal-footer">
<button
className="btn btn-outline-secondary"
onClick={() => setModalDelete(false)}
>
Cancel
</button>
<button
className="btn btn-primary"
onClick={() => handleDelete(rowSelected.id)}
>
Delete
</button>
</div>
</div>
</div>
)}
<Toaster position="top-right" />
</div>
);
};
export default DashboardRunnerAll;

View File

@@ -0,0 +1,101 @@
import React, { useState, useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import Chart from 'chart.js/auto';
import axios from 'axios';
const BarRunnerComponent = ({ onButtonClicked }) => {
const contentContainerRef = useRef(null);
const { id: editId } = useParams();
const [barChartData, setBarChartData] = useState([]);
const [barChartLabels, setBarChartLabels] = useState([]);
const [barChartLegend, setBarChartLegend] = useState(false);
const [tableName, setTableName] = useState('');
const [xAxis, setXAxis] = useState('');
const [yAxis, setYAxis] = useState('');
const [showLabel, setShowLabel] = useState(false);
const [jsonData, setJsonData] = useState(null);
const charData = {
barChartData: [{ data: [45, 37, 60, 70, 46, 33], label: 'Best Fruits' }],
barChartLabels: ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes'],
};
useEffect(() => {
setBarChartData(charData.barChartData);
setBarChartLabels(charData.barChartLabels);
const fetchData = async () => {
try {
const response = await axios.get(`/dashboard/${editId}`);
const workflowLine = response.data.dashbord1_Line[0].model;
const dash = JSON.parse(workflowLine);
const chartObject = dash.dashboard.filter(obj => obj.name === 'Bar Chart');
for (let i = 0; i < chartObject.length; i++) {
const ids = getBarChartIds();
if (!ids.includes(chartObject[i].chartid)) {
addBarChartId(chartObject[i].chartid);
setTableName(chartObject[i].table);
setXAxis(chartObject[i].xAxis);
setYAxis(chartObject[i].yAxis);
setShowLabel(chartObject[i].showlabel);
setBarChartLegend(chartObject[i].chartlegend);
const chartData = await getChartData(
chartObject[i].table,
'Bar Chart',
chartObject[i].xAxis,
chartObject[i].yAxis
);
setJsonData(chartData);
setBarChartData(chartData.barChartData);
setBarChartLabels(chartData.barChartLabels);
break;
}
}
} catch (error) {
console.error(error);
}
};
fetchData();
}, [editId]);
const generatePDFFile = () => {
if (onButtonClicked) onButtonClicked();
const content = contentContainerRef.current;
const filename = 'barchart.pdf';
generatePDF(content, filename);
};
// Placeholder functions for service calls (replace these with actual API logic)
const getBarChartIds = () => [];
const addBarChartId = id => console.log(`Added chart id: ${id}`);
const getChartData = async (table, type, xAxis, yAxis) => {
// Replace with actual API call
console.log(`Fetching chart data for table: ${table}, type: ${type}`);
return charData;
};
const generatePDF = (content, filename) => {
console.log(`Generating PDF for ${filename} with content:`, content);
// Add logic for PDF generation
};
return (
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<canvas id="barChart"></canvas>
</div>
</div>
);
};
export default BarRunnerComponent;

View File

@@ -0,0 +1,106 @@
import React, { useEffect, useRef, useState } from "react";
import { Chart as ChartJS, BubbleController, Tooltip, Legend, Title } from "chart.js";
import { Bubble } from "react-chartjs-2";
import { useParams } from "react-router-dom";
// Register Chart.js components
ChartJS.register(BubbleController, Tooltip, Legend, Title);
const BubbleRunnerComponent = ({ dashboardService, dashtestService }) => {
const { id } = useParams(); // React Router hook to get route parameters
const contentContainerRef = useRef(null);
const [bubbleChartData, setBubbleChartData] = useState([]);
const [chartLegend, setChartLegend] = useState(false);
const [tableName, setTableName] = useState("");
const [xAxis, setXAxis] = useState("");
const [yAxis, setYAxis] = useState("");
const [jsonData, setJsonData] = useState(null);
const bubbleChartOptions = {
plugins: {
title: {
display: true,
text: "Bubble Chart",
},
},
scales: {
x: {
min: 0,
max: 30,
},
y: {
min: 0,
max: 30,
},
},
};
const fetchChartData = async (chartObject) => {
const ids = dashtestService.getbubblechart();
if (ids.includes(chartObject.chartid)) return;
dashtestService.setbubblechart(chartObject.chartid);
setTableName(chartObject.table);
setXAxis(chartObject.xAxis);
setYAxis(chartObject.yAxis);
setChartLegend(chartObject.chartlegend);
try {
const data = await dashtestService.getChartData(chartObject.table, "Bubble Chart", chartObject.xAxis, chartObject.yAxis);
setJsonData(data);
setBubbleChartData(data.bubbleChartData);
} catch (error) {
console.error("Error fetching chart data:", error);
}
};
useEffect(() => {
const fetchWorkflowData = async () => {
try {
const data = await dashboardService.getById(id);
const workflowLine = data.dashbord1_Line[0].model;
const parsedWorkflow = JSON.parse(workflowLine);
const chartObjects = parsedWorkflow.dashboard.filter((obj) => obj.name === "Bubble Chart");
chartObjects.forEach(fetchChartData);
} catch (error) {
console.error("Error fetching workflow data:", error);
}
};
fetchWorkflowData();
}, [id, dashboardService, dashtestService]);
const generatePDFFile = () => {
if (!contentContainerRef.current) return;
const content = contentContainerRef.current;
const filename = "bubblechart.pdf";
dashtestService.generatePDF(content, filename);
};
const chartData = {
datasets: bubbleChartData.map((data) => ({
data: data.data,
label: data.label,
backgroundColor: data.backgroundColor,
borderColor: data.borderColor,
hoverBackgroundColor: data.hoverBackgroundColor,
hoverBorderColor: data.hoverBorderColor,
})),
};
return (
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<Bubble data={chartData} options={bubbleChartOptions} />
</div>
</div>
);
};
export default BubbleRunnerComponent;

View File

@@ -0,0 +1,76 @@
import React, { useState, useEffect, useRef } from 'react';
const PieRunnerComponent = ({ editId, onButtonClicked, dashRunnerService, dashboardService }) => {
const contentContainerRef = useRef(null);
const [pieChartLabels, setPieChartLabels] = useState(['SciFi', 'Drama', 'Comedy']);
const [pieChartData, setPieChartData] = useState([30, 50, 20]);
const [chartLegend, setChartLegend] = useState(false);
const [tableName, setTableName] = useState('');
const [xAxis, setXAxis] = useState('');
const [yAxis, setYAxis] = useState('');
const [showLabel, setShowLabel] = useState(false);
const [jsonData, setJsonData] = useState(null);
useEffect(() => {
if (!editId) return;
dashboardService.getById(editId).then((data) => {
const workflowLine = data.dashbord1_Line[0].model;
const dash = JSON.parse(workflowLine);
const chartObject = dash.dashboard.filter((obj) => obj.name === 'Pie Chart');
chartObject.forEach((chart) => {
const ids = dashRunnerService.getPieChart();
if (ids.includes(chart.chartid)) return;
dashRunnerService.setPieChart(chart.chartid);
if (chart.chartid === ids[0]) {
setTableName(chart.table);
setXAxis(chart.xAxis);
setYAxis(chart.yAxis);
setShowLabel(chart.showlabel);
setChartLegend(chart.chartlegend);
dashRunnerService.getChartData(chart.table, 'Pie Chart', chart.xAxis, chart.yAxis).then((Ldata) => {
setJsonData(Ldata);
setPieChartLabels(Ldata.pieChartLabels);
setPieChartData(Ldata.pieChartData);
}).catch((error) => {
console.error('Error fetching chart data:', error);
});
}
});
});
}, [editId, dashRunnerService, dashboardService]);
const generatePDFFile = () => {
if (onButtonClicked) {
onButtonClicked();
}
const content = contentContainerRef.current;
const filename = 'piechart.pdf';
dashRunnerService.generatePDF(content, filename);
};
return (
<div>
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
</div>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<canvas
style={{ display: 'block', width: '238px', height: '200px' }}
>
{/* Replace with a React chart library like 'react-chartjs-2' */}
<p>Pie chart will render here using labels and data.</p>
</canvas>
</div>
</div>
);
};
export default PieRunnerComponent;

View File

@@ -0,0 +1,98 @@
import React, { useEffect, useRef, useState } from 'react';
import { PolarArea } from 'react-chartjs-2';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
import axios from 'axios';
const PolarRunnerComponent = ({ match }) => {
const [editId, setEditId] = useState(null);
const [polarAreaChartLabels, setPolarAreaChartLabels] = useState([
'Download Sales',
'In-Store Sales',
'Mail Sales',
'Telesales',
'Corporate Sales',
]);
const [polarAreaChartData, setPolarAreaChartData] = useState([300, 500, 100, 40, 120]);
const [chartLegend, setChartLegend] = useState(false);
const [tableName, setTableName] = useState('');
const [xAxis, setXAxis] = useState('');
const [yAxis, setYAxis] = useState('');
const [showLabel, setShowLabel] = useState(true);
const [jsonData, setJsonData] = useState(null);
const contentContainerRef = useRef(null);
useEffect(() => {
const id = match.params.id;
setEditId(id);
axios.get(`/api/dashboard/${id}`).then((response) => {
const data = response.data;
const workflowLine = data.dashbord1_Line[0].model;
const dash = JSON.parse(workflowLine);
const chartObject = dash.dashboard.filter((obj) => obj.name === 'Polar Area Chart');
chartObject.forEach((chart) => {
if (chart.chartid) {
setTableName(chart.table);
setXAxis(chart.xAxis);
setYAxis(chart.yAxis);
setShowLabel(chart.showlabel);
setChartLegend(chart.chartlegend);
axios
.get(`/api/chart-data`, {
params: {
tableName: chart.table,
chartType: 'PolarArea Chart',
xAxis: chart.xAxis,
yAxis: chart.yAxis,
},
})
.then((chartData) => {
setJsonData(chartData.data);
setPolarAreaChartData(chartData.data.polarAreaChartData);
setPolarAreaChartLabels(chartData.data.polarAreaChartLabels);
})
.catch((err) => console.error(err));
}
});
});
}, [match.params.id]);
const generatePDFFile = () => {
const content = contentContainerRef.current;
if (content) {
html2canvas(content).then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'PNG', 0, 0);
pdf.save('polarareachart.pdf');
});
}
};
const chartData = {
labels: polarAreaChartLabels,
datasets: [
{
data: polarAreaChartData,
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF'],
},
],
};
return (
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<PolarArea data={chartData} options={{ plugins: { legend: { display: chartLegend } } }} />
</div>
</div>
);
};
export default PolarRunnerComponent;

View File

@@ -0,0 +1,91 @@
import React, { useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import DashrunnerService from "../services/DashrunnerService";
import Dashboard3Service from "../services/Dashboard3Service";
import { Chart } from "chart.js";
const RadarRunner = () => {
const { id: editId } = useParams(); // Get 'id' from URL
const contentContainerRef = useRef(null);
const [radarChartLabels, setRadarChartLabels] = useState([
"Eating",
"Drinking",
"Sleeping",
"Designing",
"Coding",
"Cycling",
"Running",
]);
const [radarChartData, setRadarChartData] = useState([
{ data: [65, 59, 90, 81, 56, 55, 40], label: "Series A" },
{ data: [28, 48, 40, 19, 96, 27, 100], label: "Series B" },
]);
const [showLabel, setShowLabel] = useState(true);
const [lineChartNoLabels, setLineChartNoLabels] = useState([]);
const [chartLegend, setChartLegend] = useState(false);
const fetchData = async () => {
try {
const data = await Dashboard3Service.getById(editId);
const workflowLine = data.dashbord1_Line[0].model;
const parsedData = JSON.parse(workflowLine);
const chartObject = parsedData.dashboard.filter(
(obj) => obj.name === "Radar Chart"
);
for (let chart of chartObject) {
const ids = DashrunnerService.getRadarChart();
if (ids.includes(chart.chartid)) continue;
DashrunnerService.setRadarChart(chart.chartid);
if (chart.chartid === ids[0]) {
const { table, xAxis, yAxis, showlabel, chartlegend } = chart;
setChartLegend(chartlegend);
setShowLabel(showlabel);
const chartData = await DashrunnerService.getChartData(
table,
"Radar Chart",
xAxis,
yAxis
);
setRadarChartData(chartData.radarChartData);
setRadarChartLabels(chartData.radarChartLabels);
break;
}
}
} catch (error) {
console.error("Error fetching data:", error);
}
};
const generatePDFFile = () => {
const content = contentContainerRef.current;
const filename = "radarchart.pdf";
DashrunnerService.generatePDF(content, filename);
};
useEffect(() => {
fetchData();
}, [editId]);
return (
<div>
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
</div>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<canvas
id="radarChart"
style={{ display: "block", width: "238px", height: "200px" }}
></canvas>
</div>
</div>
);
};
export default RadarRunner;

View File

@@ -0,0 +1,103 @@
import React, { useEffect, useRef, useState } from 'react';
import { Chart as ChartJS, registerables } from 'chart.js';
import { Scatter } from 'react-chartjs-2';
ChartJS.register(...registerables);
const ScatterRunner = ({ dashboardService, dashrunnerService, routeParams }) => {
const contentContainerRef = useRef(null);
const [scatterChartData, setScatterChartData] = useState([]);
const [scatterChartLabels, setScatterChartLabels] = useState([]);
const [chartLegend, setChartLegend] = useState(false);
const [editId, setEditId] = useState(routeParams.id || null);
const chartOptions = {
responsive: true,
aspectRatio: 2.5,
};
const scatterChartDataTemplate = {
datasets: [
{
data: [
{ x: 1, y: 1 },
{ x: 2, y: 3 },
{ x: 3, y: -2 },
{ x: 4, y: 4 },
{ x: 5, y: -3, r: 20 },
],
label: 'Series A',
pointRadius: 10,
backgroundColor: 'red',
},
{
data: [
{ x: 2, y: 2 },
{ x: 3, y: 4 },
{ x: 4, y: -1 },
{ x: 5, y: 5 },
{ x: 6, y: -2, r: 20 },
],
label: 'Series B',
pointRadius: 10,
backgroundColor: 'blue',
},
],
};
useEffect(() => {
if (editId) {
dashboardService.getById(editId).then((data) => {
const workflowLine = data.dashbord1_Line[0]?.model;
const dash = JSON.parse(workflowLine);
const chartObject = dash.dashboard.filter((obj) => obj.name === 'Scatter Chart');
chartObject.forEach((chart) => {
const ids = dashrunnerService.getscatterchart();
if (!ids.includes(chart.chartid)) {
dashrunnerService.setscatterchart(chart.chartid);
dashrunnerService
.getChartData(chart.table, 'Scatter Chart', chart.xAxis, chart.yAxis)
.then((chartData) => {
setScatterChartData(chartData.scatterChartData);
setScatterChartLabels(chartData.scatterChartLabels);
setChartLegend(chart.chartlegend);
})
.catch((error) => console.error(error));
}
});
});
}
}, [editId, dashboardService, dashrunnerService]);
const generatePDFFile = () => {
if (contentContainerRef.current) {
const content = contentContainerRef.current;
const filename = 'scatterchart.pdf';
dashrunnerService.generatePDF(content, filename);
}
};
return (
<div>
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
</div>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<Scatter
data={{
labels: scatterChartLabels,
...scatterChartDataTemplate,
}}
options={chartOptions}
/>
</div>
</div>
);
};
export default ScatterRunner;

View File

@@ -0,0 +1,95 @@
import React, { useEffect, useState, useRef } from 'react';
import { Doughnut } from 'react-chartjs-2';
import { useParams, useNavigate } from 'react-router-dom';
import { jsPDF } from 'jspdf';
import DashrunnerService from '../services/DashrunnerService'; // Replace with actual service
import Dashboard3Service from '../services/Dashboard3Service'; // Replace with actual service
const DoughnutRunner = () => {
const { id } = useParams();
const navigate = useNavigate();
const contentContainerRef = useRef(null);
const [doughnutChartData, setDoughnutChartData] = useState([]);
const [doughnutChartLabels, setDoughnutChartLabels] = useState([]);
const [doughnutChartLegend, setDoughnutChartLegend] = useState(false);
const [showlabel, setShowlabel] = useState(true);
const [TableName, setTableName] = useState('');
const [XAxis, setXAxis] = useState('');
const [YAxis, setYAxis] = useState('');
const [workflowLine, setWorkflowLine] = useState(null);
useEffect(() => {
Dashboard3Service.getById(id).then((data) => {
const workflow = data.dashbord1_Line[0]?.model;
const parsedData = JSON.parse(workflow);
const chartObjects = parsedData.dashboard.filter(
(obj) => obj.name === 'Doughnut Chart'
);
for (let chartObject of chartObjects) {
const ids = DashrunnerService.getDoughnutChartIds();
if (ids.includes(chartObject.chartid)) continue;
DashrunnerService.setDoughnutChart(chartObject.chartid);
setTableName(chartObject.table);
setXAxis(chartObject.xAxis);
setYAxis(chartObject.yAxis);
setShowlabel(chartObject.showlabel);
setDoughnutChartLegend(chartObject.chartlegend);
DashrunnerService.getChartData(
chartObject.table,
'Doughnut Chart',
chartObject.xAxis,
chartObject.yAxis
).then((chartData) => {
setDoughnutChartData(chartData.chartData);
setDoughnutChartLabels(chartData.chartLabels);
});
break;
}
});
}, [id]);
const generatePDFFile = () => {
const content = contentContainerRef.current;
const pdf = new jsPDF();
pdf.html(content, {
callback: (doc) => {
doc.save('doughnut.pdf');
},
});
};
return (
<div>
<div style={{ textAlign: 'right' }}>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
</div>
<div className="chart-box" ref={contentContainerRef}>
<Doughnut
data={{
labels: showlabel ? doughnutChartLabels : [],
datasets: [
{
data: doughnutChartData[0] || [],
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56'],
},
],
}}
options={{
legend: {
display: doughnutChartLegend,
},
}}
/>
</div>
</div>
);
};
export default DoughnutRunner;

View File

@@ -0,0 +1,90 @@
import React, { useEffect, useState, useRef } from "react";
import { useParams } from "react-router-dom";
const GridRunnerComponent = ({ dashboardService, dashRunnerService }) => {
const { id } = useParams(); // React Router for route parameters
const contentContainerRef = useRef(null);
const [rows, setRows] = useState([]);
const [editId, setEditId] = useState(null);
const [workflowLine, setWorkflowLine] = useState(null);
const [tableName, setTableName] = useState(null);
const [xAxis, setXAxis] = useState(null);
const [yAxis, setYAxis] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
setEditId(id);
dashboardService.getById(id).then((data) => {
const lineData = data?.dashbord1_Line?.[0]?.model;
setWorkflowLine(lineData);
const dash = JSON.parse(lineData || "{}");
const chartObjects = dash.dashboard?.filter(
(obj) => obj.name === "Grid View"
) || [];
chartObjects.forEach((chartObject) => {
const ids = dashRunnerService.getGridView();
if (!ids.includes(chartObject.chartid)) {
dashRunnerService.setGridView(chartObject.chartid);
if (chartObject.chartid === ids[0]) {
setTableName(chartObject.table);
setXAxis(chartObject.xAxis);
setYAxis(chartObject.yAxis);
dashRunnerService
.getChartData(chartObject.table, "Grid View", chartObject.xAxis, chartObject.yAxis)
.then((data) => {
setRows(data);
})
.catch((error) => console.error("Error fetching chart data:", error));
}
}
});
});
}, [id, dashboardService, dashRunnerService]);
const getHeaders = () => {
if (!rows || rows.length === 0) return [];
return Object.keys(rows[0]);
};
const generatePDFFile = () => {
if (!contentContainerRef.current) return;
const content = contentContainerRef.current;
const filename = "gridview.pdf";
dashRunnerService.generatePDF(content, filename);
};
return (
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
<div style={{ maxHeight: "400px", overflow: "auto", padding: "10px" }}>
<table className="table">
<thead>
<tr>
{getHeaders().map((header, index) => (
<th key={index}>{header}</th>
))}
</tr>
</thead>
<tbody>
{rows.slice().reverse().map((row, rowIndex) => (
<tr key={rowIndex}>
{getHeaders().map((key, colIndex) => (
<td key={colIndex}>{row[key]}</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
export default GridRunnerComponent;

View File

@@ -0,0 +1,80 @@
import React, { useState, useEffect, useRef } from "react";
import { Chart } from "chart.js";
import { jsPDF } from "jspdf";
import domtoimage from "dom-to-image";
const LineRunnerComponent = ({ dashrunnerService, dashboardService }) => {
const contentContainerRef = useRef(null);
const [lineChartData, setLineChartData] = useState([]);
const [lineChartLabels, setLineChartLabels] = useState([]);
const [lineChartNoLabels] = useState([]);
const [lineChartLegend, setLineChartLegend] = useState(false);
const [workflowLine, setWorkflowLine] = useState(null);
const [tableName, setTableName] = useState(null);
const [xAxis, setXAxis] = useState(null);
const [yAxis, setYAxis] = useState(null);
const [showLabel, setShowLabel] = useState(null);
const [editId, setEditId] = useState(null);
useEffect(() => {
// Mock equivalent of Angular's ActivatedRoute for id retrieval
const idFromRoute = "mockId"; // Replace with actual route logic
setEditId(idFromRoute);
dashboardService.getById(idFromRoute).then((data) => {
const workflow = data.dashbord1_Line[0].model;
setWorkflowLine(workflow);
const parsedData = JSON.parse(workflow);
const chartObjects = parsedData.dashboard.filter(
(obj) => obj.name === "Line Chart"
);
chartObjects.forEach((chart) => {
const ids = dashrunnerService.getlinechart();
if (!ids.includes(chart.chartid)) {
dashrunnerService.setlinechart(chart.chartid);
if (chart.chartid === ids[0]) {
setTableName(chart.table);
setXAxis(chart.xAxis);
setYAxis(chart.yAxis);
setShowLabel(chart.showlabel);
setLineChartLegend(chart.chartlegend);
dashrunnerService
.getChartData(chart.table, "Line Chart", chart.xAxis, chart.yAxis)
.then((Ldata) => {
setLineChartData(Ldata.chartData);
setLineChartLabels(Ldata.chartLabels);
})
.catch((error) => console.error(error));
}
}
});
});
}, [dashrunnerService, dashboardService]);
const generatePDFFile = () => {
const content = contentContainerRef.current;
const filename = "linechart.pdf";
dashrunnerService.generatePDF(content, filename);
};
return (
<div>
<button className="btn btn-primary" onClick={generatePDFFile}>
Export
</button>
<div className="chart-box" id="contentContainer" ref={contentContainerRef}>
<canvas
id="lineChart"
style={{ display: "block" }}
></canvas>
</div>
</div>
);
};
export default LineRunnerComponent;

View File

@@ -0,0 +1,197 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, useParams,useLocation } from 'react-router-dom';
import {toast} from 'react-toastify'; // You can use a different notification system if needed
import DashboardBuilderService from "../../../../APIServices/DashboardBuilderService"; // Update with your service path
import { Badge } from "reactstrap";
const EditFormNewDash = () => {
const { id } = useParams(); // Access the id from the URL params
const navigate = useNavigate();
const location = useLocation();
const [header, setHeader] = useState({
dashboard_name: '',
secuirity_profile: '',
description: '',
add_to_home: false,
});
const [updated, setUpdated] = useState(false);
const [techStacks, setTechStacks] = useState([]);
const objectTypes = ["form", "bi", "report", "api"];
const subObjectTypes = [
"only header",
"only line",
"header line",
"header multiline",
"workflow",
"setup",
"std report",
"bi report",
"rest api",
];
// Fetch data by ID when component mounts
// useEffect(() => {
// if (id) {
// getById(id);
// }
// }, [id]);
useEffect(() => {
if (location.state?.dashboard) {
setHeader(location.state.dashboard);
} else {
// Fetch data if not passed in state
getById(id);
}
}, [id, location.state]);
// Get dashboard data by ID
// const getById = (id) => {
// DashboardService.getById(id)
// .then((data) => {
// console.log(data);
// setHeader(data);
// })
// .catch((err) => {
// console.log(err);
// });
// };
const getById = (id,data) => {
DashboardBuilderService.getById(id)
.then((data) => {
console.log("get dashbord by id: ",data);
setHeader(data);
})
.catch((err) => {
// Static error handling
console.error("Error fetching dashboard by ID:", err);
toast.error('Failed to fetch dashboard data. Please try again later.');
});
};
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
setHeader((prev) => ({
...prev,
...header,
[name]: type === 'checkbox' ? checked : value,
}));
};
const update = async () => {
console.log("Submitted Data:", header); // Log the data to verify it's correct
const staticTestData = { ...header}; // Mock updated data with additional fields if needed
console.log("Static Updated Data:", staticTestData);
toast.success('Dashboard updated successfully');
// navigate('/admin/dashboard-new-all',{ state: { updatedDashboard: staticTestData } });
try {
const updatedDashboard = await DashboardBuilderService.updateDash(header); // Await the API response
if (updatedDashboard) {
setUpdated(true);
toast.success('Dashboard updated successfully');
navigate('/admin/dashboard-new-all'); // Pass updated data to the next page
} else {
throw new Error("No response from server");
}
} catch (error) {
console.error("Error updating dashboard:", error);
toast.error('Failed to update the dashboard. Please try again later.');
}
};
// Handle form submission
const onSubmit = (e) => {
e.preventDefault();
setUpdated(true);
update();
};
// Handle the back button
const onBack = () => {
navigate('/admin/dashboard-new-all');
};
return (
<div className="container">
<h4 style={{ fontWeight: 300, display: 'inline' }}><b> Dashboard</b></h4>
<Badge
color="info" // This sets the blue color
style={{ display: "inline", marginLeft: 10 }}
>
Edit Mode
</Badge>
<hr /><br />
<form onSubmit={onSubmit}>
<div className="row">
<div className="col-md-6 col-sm-12">
<label htmlFor="dashboard_name">Dashboard Name</label>
<input
id="dashboard_name"
type="text"
name="dashboard_name"
value={header.dashboard_name || ''}
// onChange={(e) => setHeader({ ...header, dashboard_name: e.target.value })}
onChange={handleInputChange}
placeholder="Enter Dashboard Name"
className="form-control"
/>
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="secuirity_profile">Security Profile</label>
<input
id="secuirity_profile"
type="text"
name="secuirity_profile"
value={header.secuirity_profile || ''}
// onChange={(e) => setHeader({ ...header, secuirity_profile: e.target.value })}
onChange={handleInputChange}
placeholder="Enter Security Profile"
className="form-control"
/>
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="description">Description</label>
<textarea
cols="10"
rows="2"
name="description"
value={header.description || ''}
// onChange={(e) => setHeader({ ...header, description: e.target.value })}
onChange={handleInputChange}
placeholder="Enter Description"
className="form-control"
/>
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="workflow_name" style={{ marginTop: "1rem" }}>Add to Dashboard</label>
<input
type="checkbox"
name="add_to_home"
checked={header.add_to_home || ''}
// onChange={(e) => setHeader({ ...header, add_to_home: e.target.checked })}
onChange={handleInputChange}
className="form-check-input"
style={{ marginTop: "3rem", marginLeft: "-8rem" }}
/>
</div>
</div>
<br />
<div className="text-center">
<button type="button" className="btn btn-outline-secondary" onClick={onBack}>BACK</button>
<button type="submit" className="btn btn-primary">Update</button>
</div>
</form>
</div>
);
};
export default EditFormNewDash;

View File

@@ -0,0 +1,605 @@
import React, { useState, useEffect } from 'react';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { Responsive, WidthProvider } from 'react-grid-layout';
import { FormControl, Input, Select, Checkbox, Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography, Card, CardContent, MenuItem, Box } from '@mui/material';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTrash, faGripLines, faPen } from '@fortawesome/free-solid-svg-icons';
import { useNavigate, useParams } from 'react-router-dom';
import DashboardBuilderService from "../../../../APIServices/DashboardBuilderService";
// Import chart components
import LineChartComponent from '../gadgets/line-chart/LineChart';
import PieChartComponent from '../gadgets/pie-chart/Piechart';
import PolarChartComponent from '../gadgets/polar-chart/PolarChart';
import RadarChartComponent from '../gadgets/radar-chart/RadarChart';
import BubbleChart from '../gadgets/bubble-chart/BubbleChart';
import BarChart from '../gadgets/bar-chart/BarChart';
import DoughnutChart from '../gadgets/doughnut-charts/DoughnutChart';
import DynamicChart from '../gadgets/dynamic-chart/DynamicChart';
import FinancialChart from '../gadgets/financial-chart/FinancialChart';
import GridViewComponent from '../gadgets/grid-view/GridView';
import ScatterChartComponent from '../gadgets/scatter-chart/ScatterChart';
import ToDoChartComponent from '../gadgets/to-do-chart/TodoChart';
// Use WidthProvider to handle responsive behavior
const ResponsiveGridLayout = WidthProvider(Responsive);
const EditNewDash = () => {
const { id } = useParams(); // fetching id from the url
const [sidebarOpen, setSidebarOpen] = useState(false);
const [editModalOpen, setEditModalOpen] = useState(false);
const [currentEditWidget, setCurrentEditWidget] = useState({});
const [dashboardName, setDashboardName] = useState();
const [dashboardLine, setDashboardLine] = useState();
const [columnData] = useState(['Column1', 'Column2', 'Column3']);
const [dashboardWidgets, setDashboardWidgets] = useState([]);
const [dashboardlineId, setDashboardlineId]= useState();
// Define available widgets
const [availableWidgets] = useState([
{ identifier: 'radar_chart', name: 'Radar Chart' },
{ identifier: 'polar_chart', name: 'Polar Chart' },
{ identifier: 'pie_chart', name: 'Pie Chart' },
{ identifier: 'bar_chart', name: 'Bar Chart' },
{ identifier: 'bubble_chart', name: 'Bubble Chart' },
{ identifier: 'line_chart', name: 'Line Chart' },
{ identifier: 'doughnut_chart', name: 'Doughnut Chart' },
{ identifier: 'dynamic_chart', name: 'Dynamic Chart' },
{ identifier: 'financial_chart', name: 'Financial Chart' },
{ identifier: 'grid_view', name: 'Grid View' },
{ identifier: 'scatter_chart', name: 'Scatter Chart' },
{ identifier: 'todo_chart', name: 'Todo Chart' },
]);
// Define component mapping object for easier lookup
const componentMap = {
'radar_chart': RadarChartComponent,
'polar_chart': PolarChartComponent,
'pie_chart': PieChartComponent,
'bar_chart': BarChart,
'bubble_chart': BubbleChart,
'line_chart': LineChartComponent,
'doughnut_chart': DoughnutChart,
'dynamic_chart': DynamicChart,
'financial_chart': FinancialChart,
'grid_view': GridViewComponent,
'scatter_chart': ScatterChartComponent,
'todo_chart': ToDoChartComponent
};
// Component name to identifier mapping for reverse lookup
const componentNameToIdentifier = {
'Radar Chart': 'radar_chart',
'Polar Chart': 'polar_chart',
'Pie Chart': 'pie_chart',
'Bar Chart': 'bar_chart',
'Bubble Chart': 'bubble_chart',
'Line Chart': 'line_chart',
'Doughnut Chart': 'doughnut_chart',
'Dynamic Chart': 'dynamic_chart',
'Financial Chart': 'financial_chart',
'Grid View': 'grid_view',
'Scatter Chart': 'scatter_chart',
'Todo Chart': 'todo_chart'
};
// fetching dashboard data by id (id is fetched from the url)
useEffect(() => {
fetchDashboardData();
}, []);
const fetchDashboardData = async () => {
try {
const response = await DashboardBuilderService.getById(id);
console.log("Raw API response:", response);
console.log("dashboardid: ",response.dashbord1_Line[0].id)
setDashboardlineId(response.dashbord1_Line[0].id)
setDashboardName(response.dashboard_name);
setDashboardLine(response.dashbord1_Line);
if (response.dashbord1_Line && response.dashbord1_Line[0]?.model) {
try {
const modelData = response.dashbord1_Line[0].model;
console.log("Model Data:", modelData);
const parsedModel = JSON.parse(modelData);
console.log("Parsed Model:", parsedModel);
// Transform the data format to match what ResponsiveGridLayout expects
const transformedWidgets = Array.isArray(parsedModel.dashboard)
? parsedModel.dashboard.map((widget, index) => {
// Create a widget ID if not present
const widgetId = widget.i || `widget-${index}`;
// Get the component identifier from name if component is provided as a string
const typeIdentifier = widget.type ||
(widget.component && typeof widget.component === 'string'
? componentNameToIdentifier[widget.component] || widget.component.toLowerCase().replace(' ', '_')
: 'unknown');
// Get component reference from the component map
const componentRef = componentMap[typeIdentifier] || null;
// Map the widget properties to the expected format
return {
i: widgetId,
x: widget.x || 0,
y: widget.y || 0,
w: widget.cols || 6, // Convert cols to w
h: widget.rows || 8, // Convert rows to h
type: typeIdentifier,
name: widget.name || availableWidgets.find(w => w.identifier === typeIdentifier)?.name || 'Unknown Widget',
component: componentRef,
chartTitle: widget.chartTitle,
showLegend: widget.showLegend,
showLabel: widget.showLabel,
xAxis: widget.xAxis,
yAxis: widget.yAxis
};
})
: [];
console.log("Transformed widgets:", transformedWidgets);
setDashboardWidgets(transformedWidgets);
} catch (parseError) {
console.error("Error parsing dashboard model:", parseError);
setDashboardWidgets([]);
}
} else {
console.log("No valid model data, setting empty widgets.");
setDashboardWidgets([]);
}
} catch (error) {
console.error("Error fetching dashboard data:", error);
setDashboardWidgets([]);
}
};
useEffect(() => {
console.log("Updated dashboardWidgets:", dashboardWidgets);
}, [dashboardWidgets]);
const [dashboardForm, setDashboardForm] = useState({
donut: '',
chartlegend: '',
showlabel: '',
charturl: '',
chartparameter: '',
datastore: '',
table: '',
datasource: '',
charttitle: '',
id: '',
fieldName: '',
chartcolor: '',
slices: '',
yAxis: '',
xAxis: '',
});
const navigate = useNavigate();
// Handle widget drag from sidebar
const onDragStart = (e, widget) => {
e.dataTransfer.setData('widgetType', widget.identifier);
};
// Handle widget drop onto dashboard
const onDragOver = (e) => {
e.preventDefault();
};
const onDrop = (e) => {
e.preventDefault();
const widgetType = e.dataTransfer.getData('widgetType');
if (!widgetType) return;
// Calculate drop position relative to the grid
const gridRect = e.currentTarget.getBoundingClientRect();
const x = Math.floor((e.clientX - gridRect.left) / 100) * 2;
const y = Math.floor((e.clientY - gridRect.top) / 100) * 2;
// Create new widget based on type
let maxChartId = dashboardWidgets?.reduce((maxId, item) => Math.max(maxId, item.chartid || 0), 0);
console.log("maxChartId",maxChartId)
const newWidgetId = `widget-${Date.now()}`;
const componentRef = componentMap[widgetType] || null;
const widgetName = availableWidgets.find(w => w.identifier === widgetType)?.name || 'Unknown Widget';
const newWidget = {
i: newWidgetId,
x: x,
y: y,
w: 6,
h: 8,
type: widgetType,
name: widgetName,
component: componentRef, // Add the component reference here
chartTitle: widgetName, // Add default chart title
showLegend: true, // Add default values for chart config
showLabel: true,
xAxis: 'Month',
yAxis: 'Value'
};
setDashboardWidgets(prev => [...prev, newWidget]);
};
// Handle layout changes
const onLayoutChange = (layout) => {
// Update widget positions when layout changes
const updatedWidgets = dashboardWidgets.map(widget => {
const updatedPosition = layout.find(item => item.i === widget.i);
if (updatedPosition) {
return { ...widget, x: updatedPosition.x, y: updatedPosition.y, w: updatedPosition.w, h: updatedPosition.h };
}
return widget;
});
setDashboardWidgets(updatedWidgets);
};
// Remove widget
const removeWidget = (widgetId) => {
setDashboardWidgets(prev => prev.filter(widget => widget.i !== widgetId));
};
// Edit widget
const editWidget = (widget) => {
setCurrentEditWidget(widget);
setEditModalOpen(true);
};
// Save edited widget
const saveWidgetChanges = () => {
setDashboardWidgets(prev =>
prev.map(widget =>
widget.i === currentEditWidget.i ? { ...widget, ...currentEditWidget } : widget
)
);
setEditModalOpen(false);
};
// Navigate back
const goBack = () => {
navigate('/admin/dashboard-new-all');
};
const dashbord1_Line = {
model:''
}
// Save dashboard
const saveDashboard = async () => {
try {
// Ensure dashboardWidgets is not empty before saving
if (!dashboardWidgets || dashboardWidgets.length === 0) {
console.warn("No widgets to save.");
return;
}
// Prepare the dashboard data
const dashboardData = {
dashboard: dashboardWidgets.map(widget => ({
x: widget.x ?? 0, // Default values to prevent errors
y: widget.y ?? 0,
cols: widget.w ?? 1,
rows: widget.h ?? 1,
component: widget.name || "Unknown",
name: widget.name || "Unknown",
// type: widget.type || "Generic",
})),
};
console.log("Saving dashboard:", dashboardData);
console.log("Saving dashboard:", JSON.stringify(dashboardData))
dashbord1_Line.model = JSON.stringify(dashboardData)
console.log("dashbord1_Line: ", dashbord1_Line)
// Call the API to update the dashboard data
const response = await DashboardBuilderService.updateLineData(dashboardlineId, dashbord1_Line);
if (response) {
console.log("Dashboard saved successfully:", response.data);
// Optionally navigate after saving
navigate('/admin/dashboard-new-all');
} else {
console.error("Failed to save dashboard. Server response:", response);
}
} catch (error) {
console.error("Error saving dashboard:", error.message || error);
}
};
return (
<Box sx={{
display: 'flex',
flexDirection: 'column',
height: '100vh',
padding: 3
}}>
{/* Toolbar */}
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
marginBottom: 3
}}>
<Button
variant="contained"
color="primary"
onClick={() => setSidebarOpen(!sidebarOpen)}
>
{sidebarOpen ? 'Hide Components' : 'Add Components'}
</Button>
<Typography variant="h5">{dashboardName}</Typography>
<Box>
<Button
variant="outlined"
sx={{ marginRight: 1 }}
onClick={goBack}
>
Cancel
</Button>
<Button
variant="contained"
color="primary"
onClick={saveDashboard}
>
Save Dashboard
</Button>
</Box>
</Box>
{/* Main content */}
<Box sx={{
display: 'flex',
flex: 1,
width: '100%',
overflow: 'hidden'
}}>
{/* Sidebar */}
{sidebarOpen && (
<Box sx={{
width: 250,
backgroundColor: '#f5f5f5',
padding: 2,
overflowY: 'auto',
borderRight: '1px solid #e0e0e0'
}}>
<Typography variant="h6" sx={{ marginBottom: 2 }}>
Available Components
</Typography>
<Box component="ul" sx={{
listStyleType: 'none',
padding: 0,
margin: 0
}}>
{availableWidgets.map(widget => (
<Box
component="li"
key={widget.identifier}
sx={{
padding: 1.5,
marginBottom: 1,
backgroundColor: 'white',
borderRadius: 1,
cursor: 'move',
border: '1px solid #e0e0e0',
'&:hover': {
backgroundColor: '#f0f7ff'
}
}}
draggable
onDragStart={(e) => onDragStart(e, widget)}
>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<FontAwesomeIcon icon={faGripLines} style={{ marginRight: 10 }} />
{widget.name}
</Box>
</Box>
))}
</Box>
</Box>
)}
{/* Dashboard grid */}
<Box
sx={{
flex: 1,
padding: 2,
overflow: 'auto',
backgroundColor: '#fafafa'
}}
onDragOver={onDragOver}
onDrop={onDrop}
>
<ResponsiveGridLayout
className="layout"
layouts={{
lg: dashboardWidgets.map(widget => ({
i: widget.i,
x: widget.x,
y: widget.y,
w: widget.w,
h: widget.h,
minW: 3,
minH: 3
}))
}}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
rowHeight={30}
onLayoutChange={onLayoutChange}
isDraggable
isResizable
margin={[20, 20]}
>
{dashboardWidgets.map(widget => (
<Box key={widget.i} sx={{ overflow: 'hidden' }}>
<Card sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)'
}}>
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: 1,
borderBottom: '1px solid #eee'
}}>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold' }}>
{widget.name}
</Typography>
<Box>
<Button
size="small"
onClick={() => editWidget(widget)}
sx={{ minWidth: 'auto', padding: '4px' }}
>
<FontAwesomeIcon icon={faPen} />
</Button>
<Button
size="small"
color="error"
onClick={() => removeWidget(widget.i)}
sx={{ minWidth: 'auto', padding: '4px', ml: 1 }}
>
<FontAwesomeIcon icon={faTrash} />
</Button>
</Box>
</Box>
<CardContent sx={{
flex: 1,
padding: 2,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
height: 'calc(100% - 50px)' // Subtracting header height
}}>
{widget.component && (
<Box sx={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden'
}}>
<widget.component
chartTitle={widget.chartTitle || widget.name}
showLegend={widget.showLegend !== undefined ? widget.showLegend : true}
showLabel={widget.showLabel !== undefined ? widget.showLabel : true}
xAxis={widget.xAxis || 'Month'}
yAxis={widget.yAxis || 'Value'}
width="100%"
height="100%"
/>
</Box>
)}
</CardContent>
</Card>
</Box>
))}
</ResponsiveGridLayout>
</Box>
</Box>
{/* Edit widget dialog */}
<Dialog open={editModalOpen} onClose={() => setEditModalOpen(false)} maxWidth="sm" fullWidth>
<DialogTitle>Edit {currentEditWidget.name}</DialogTitle>
<DialogContent sx={{ paddingTop: 2 }}>
<FormControl fullWidth sx={{ marginBottom: 2 }}>
<Typography variant="subtitle2" sx={{ marginBottom: 1 }}>Chart Title</Typography>
<Input
value={currentEditWidget.chartTitle || ''}
onChange={(e) => setCurrentEditWidget({
...currentEditWidget,
chartTitle: e.target.value
})}
placeholder="Enter chart title"
fullWidth
/>
</FormControl>
{currentEditWidget.name !== 'Grid View' && currentEditWidget.name !== 'Todo Chart' && (
<>
<Box sx={{ display: 'flex', gap: 2, marginBottom: 2 }}>
<FormControl sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<Checkbox
checked={currentEditWidget.showLegend || false}
onChange={(e) => setCurrentEditWidget({
...currentEditWidget,
showLegend: e.target.checked
})}
/>
<Typography>Show Legend</Typography>
</FormControl>
<FormControl sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<Checkbox
checked={currentEditWidget.showLabel || false}
onChange={(e) => setCurrentEditWidget({
...currentEditWidget,
showLabel: e.target.checked
})}
/>
<Typography>Show Labels</Typography>
</FormControl>
</Box>
</>
)}
<FormControl fullWidth sx={{ marginBottom: 2 }}>
<Typography variant="subtitle2" sx={{ marginBottom: 1 }}>X-Axis</Typography>
<Select
value={currentEditWidget.xAxis || ''}
onChange={(e) => setCurrentEditWidget({
...currentEditWidget,
xAxis: e.target.value
})}
displayEmpty
>
<MenuItem value="" disabled>Select X-Axis</MenuItem>
{columnData.map((col, index) => (
<MenuItem key={index} value={col}>{col}</MenuItem>
))}
</Select>
</FormControl>
<FormControl fullWidth sx={{ marginBottom: 2 }}>
<Typography variant="subtitle2" sx={{ marginBottom: 1 }}>Y-Axis</Typography>
<Select
value={currentEditWidget.yAxis || ''}
onChange={(e) => setCurrentEditWidget({
...currentEditWidget,
yAxis: e.target.value
})}
displayEmpty
>
<MenuItem value="" disabled>Select Y-Axis</MenuItem>
{columnData.map((col, index) => (
<MenuItem key={index} value={col}>{col}</MenuItem>
))}
</Select>
</FormControl>
</DialogContent>
<DialogActions sx={{ padding: 2 }}>
<Button onClick={() => setEditModalOpen(false)} color="inherit">
Cancel
</Button>
<Button onClick={saveWidgetChanges} variant="contained" color="primary">
Save Changes
</Button>
</DialogActions>
</Dialog>
</Box>
);
};
export default EditNewDash;

View File

@@ -0,0 +1,381 @@
// import React,{useState,useEffect} from 'react'
// import { useForm, useFieldArray } from "react-hook-form";
// import { useNavigate } from "react-router-dom";
// import { toast } from "react-toastify";
// import "react-toastify/dist/ReactToastify.css";
// import { Badge } from "reactstrap";
// const DashboardbuilderAdd = () => {
// const [moduleId, setModuleId] = useState(null);
// const [techStacks, setTechStacks] = useState([]);
// const objectTypes = ["form", "bi", "report", "api"];
// const subObjectTypes = [
// "only header",
// "only line",
// "header line",
// "header multiline",
// "workflow",
// "setup",
// "std report",
// "bi report",
// "rest api",
// ];
// const fieldModels = {
// dashboard: [
// {
// cols: 4,
// rows: 5,
// x: 0,
// y: 0,
// name: "Radar Chart",
// component: "Radar Chart",
// },
// ],
// };
// const navigate = useNavigate();
// const {
// register,
// handleSubmit,
// control,
// formState: { errors },
// } = useForm({
// defaultValues: {
// dashboard_name: "",
// description: "",
// secuirity_profile: "",
// module_id: null,
// tech_Stack: "",
// object_type: "",
// sub_object_type: "",
// add_to_home: true,
// dashbord1_Line: [
// {
// model: JSON.stringify(fieldModels),
// },
// ],
// },
// });
// const { fields } = useFieldArray({
// control,
// name: "dashbord1_Line",
// });
// useEffect(() => {
// // Simulate module ID fetching logic
// setModuleId("exampleModuleId");
// }, []);
// const onSubmit = (data) => {
// console.log("Form Data:", data);
// if (!data.dashboard_name || !data.secuirity_profile || !data.description) {
// toast.error("Please fill out all required fields.");
// return;
// }
// data.module_id = moduleId;
// // DashboardService.create(data)
// // .then((response) => {
// // console.log(response);
// // toast.success("Added successfully");
// // navigate("../all");
// // })
// // .catch((error) => {
// // console.error(error);
// // toast.error("Error while adding dashboard");
// // });
// };
// const onValid = (data) => {
// console.log('Form Submitted Successfully:', data);
// };
// return (
// <div className="container">
// <h4 style={{ fontWeight: 300, display: "inline" }}>
// <b>Define Dashboard</b>
// </h4>
// <Badge
// color="info" // This sets the blue color
// style={{ display: "inline", marginLeft: 10 }}
// >
// Add Mode
// </Badge>
// <hr />
// <br />
// <form onSubmit={handleSubmit(onSubmit)}>
// <div className="row">
// <div className="col-md-6 col-sm-12">
// <label htmlFor="dashboard_name">Dashboard Name</label>
// <input
// id="dashboard_name"
// type="text"
// {...register("dashboard_name", { required: true })}
// className="form-control"
// placeholder="Enter dashboard name"
// />
// {errors.dashboard_name && <p className="text-danger">This field is required.</p>}
// </div>
// <div className="col-md-6 col-sm-12">
// <label htmlFor="secuirity_profile">Security Profile</label>
// <input
// id="secuirity_profile"
// type="text"
// {...register("secuirity_profile", { required: true })}
// className="form-control"
// placeholder="Enter security profile"
// />
// {errors.secuirity_profile && <p className="text-danger">This field is required.</p>}
// </div>
// <div className="col-md-6 col-sm-12">
// <label htmlFor="description">Description</label>
// <textarea
// id="description"
// {...register("description", { required: true })}
// className="form-control"
// placeholder="Enter description"
// />
// {errors.description && <p className="text-danger">This field is required.</p>}
// </div>
// <div className="col-md-6 col-sm-12" >
// <label htmlFor="add_to_home" style={{ marginTop: "1rem"}}>Add to Dashboard</label>
// <input
// type="checkbox"
// {...register("add_to_home")}
// className="form-check-input"
// style={{marginTop:"3rem" , marginLeft:"-8rem"}}
// />
// </div>
// </div>
// <br />
// <div className="text-center">
// <button
// type="button"
// className="btn btn-outline-secondary"
// onClick={() => navigate("/admin/dashboard-new-all")}
// >
// Back
// </button>
// <button type="submit" className="btn btn-primary" onClick={handleSubmit()}>
// Submit
// </button>
// </div>
// </form>
// </div>
// )
// }
// export default DashboardbuilderAdd
import React, { useState, useEffect } from "react";
import { useForm, useFieldArray } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { Badge } from "reactstrap";
import DashboardBuilderService from "../../../../APIServices/DashboardBuilderService";
const DashboardbuilderAdd = () => {
const [moduleId, setModuleId] = useState(null);
const [techStacks, setTechStacks] = useState([]);
const objectTypes = ["form", "bi", "report", "api"];
const subObjectTypes = [
"only header",
"only line",
"header line",
"header multiline",
"workflow",
"setup",
"std report",
"bi report",
"rest api",
];
const [dashboards, setDashboards] = useState([]);
const fieldModels = {
dashboard: [
{
cols: 4,
rows: 5,
x: 0,
y: 0,
name: "Radar Chart",
component: "Radar Chart",
},
],
};
const navigate = useNavigate();
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm({
defaultValues: {
dashboard_name: "",
description: "",
secuirity_profile: "",
module_id: null,
tech_Stack: "",
object_type: "",
sub_object_type: "",
add_to_home: true,
dashbord1_Line: [
{
model: JSON.stringify(fieldModels),
},
],
},
});
const { fields } = useFieldArray({
control,
name: "dashbord1_Line",
});
useEffect(() => {
// Simulate module ID fetching logic
setModuleId("exampleModuleId");
}, []);
// #############
const onSubmit = (data) => {
console.log("Form Data:", data);
if (!data.dashboard_name || !data.secuirity_profile || !data.description) {
toast.error("Please fill out all required fields.");
return;
}
const newDashboard = {
...data,
// module_id: Number(moduleId), // Ensure this is an integer
// id: Date.now(), // Simulate a unique ID
};
console.log("New Dashboard:", newDashboard);
const existingDashboards =
JSON.parse(localStorage.getItem("dashboards")) || [];
console.log("Existing Dashboards:", existingDashboards);
localStorage.setItem(
"dashboards",
JSON.stringify([...existingDashboards, newDashboard])
);
setDashboards((prevDashboards) => [...prevDashboards, newDashboard]);
// API call to save the new dashboard
DashboardBuilderService.create(newDashboard)
.then((response) => {
console.log(response);
toast.success("Dashboard Added successfully");
navigate("/admin/dashboard-new-all");
})
.catch((error) => {
console.error(error);
toast.error("Error while adding dashboard");
});
};
return (
<div className="container">
<h4 style={{ fontWeight: 300, display: "inline" }}>
<b>Define Dashboard</b>
</h4>
<Badge
color="info" // This sets the blue color
style={{ display: "inline", marginLeft: 10 }}
>
Add Mode
</Badge>
<hr />
<br />
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row">
<div className="col-md-6 col-sm-12">
<label htmlFor="dashboard_name">Dashboard Name</label>
<input
id="dashboard_name"
type="text"
{...register("dashboard_name", { required: true })}
className="form-control"
placeholder="Enter dashboard name"
/>
{errors.dashboard_name && (
<p className="text-danger">This field is required.</p>
)}
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="secuirity_profile">Security Profile</label>
<input
id="secuirity_profile"
type="text"
{...register("secuirity_profile", { required: true })}
className="form-control"
placeholder="Enter security profile"
/>
{errors.secuirity_profile && (
<p className="text-danger">This field is required.</p>
)}
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="description">Description</label>
<textarea
id="description"
{...register("description", { required: true })}
className="form-control"
placeholder="Enter description"
/>
{errors.description && (
<p className="text-danger">This field is required.</p>
)}
</div>
<div className="col-md-6 col-sm-12">
<label htmlFor="add_to_home" style={{ marginTop: "1rem" }}>
Add to Dashboard
</label>
<input
type="checkbox"
{...register("add_to_home")}
className="form-check-input"
style={{ marginTop: "3rem", marginLeft: "-8rem" }}
/>
</div>
</div>
<br />
<div className="text-center">
<button
type="button"
className="btn btn-outline-secondary"
onClick={() => navigate("/admin/dashboard-new-all")}
>
Back
</button>
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</form>
</div>
);
};
export default DashboardbuilderAdd;

View File

@@ -0,0 +1,441 @@
// import React, { useState } from "react";
// import {
// Button,
// Modal,
// Table,
// Form,
// Spinner,
// Tooltip,
// OverlayTrigger
// } from "react-bootstrap";
// const DashboardNewAll = () => {
// const [addModal, setAddModal] = useState(false);
// const [deleteModal, setDeleteModal] = useState(false);
// const [selectedRow, setSelectedRow] = useState(null);
// const[data,setData] = useState([]);
// const[loading,setLoading] = useState();
// const [error,setError] = useState();
// const[translate,setTranslate] = useState();
// const handleAddClick = () => setAddModal(true);
// const handleDeleteClick = (row) => {
// setSelectedRow(row);
// setDeleteModal(true);
// };
// const handleDeleteConfirm = () => {
// console.log("Deleting row: ", selectedRow.id);
// setDeleteModal(false);
// };
// return (
// <div className="dg-wrapper">
// <div className="d-flex justify-content-between align-items-center mb-3">
// <h3>{translate("Dashboard_builder")}</h3>
// <div>
// <Button variant="primary" onClick={() => console.log("Go to Runner")}>
// <i className="bi bi-grid"></i> {translate("Dashboard_runner")}
// </Button>
// <Button
// variant="outline-secondary"
// className="mx-2"
// onClick={() => console.log("Export")}
// >
// <i className="bi bi-file-earmark-excel"></i> {translate("EXPORT_XLSX")}
// </Button>
// <Button variant="primary" onClick={handleAddClick}>
// <i className="bi bi-plus"></i> {translate("ADD")}
// </Button>
// </div>
// </div>
// <Table striped bordered hover>
// <thead>
// <tr>
// <th>{translate("Go_to")}</th>
// <th>{translate("Dashboard_Name")}</th>
// <th>{translate("Description")}</th>
// <th>{translate("Security_Profile")}</th>
// <th>{translate("Add_to_home")}</th>
// <th>{translate("Action")}</th>
// </tr>
// </thead>
// <tbody>
// {loading ? (
// <tr>
// <td colSpan="6" className="text-center">
// <Spinner animation="border" /> {translate("Loading")} ......
// </td>
// </tr>
// ) : error ? (
// <tr>
// <td colSpan="6" className="text-center text-danger">
// {error}
// </td>
// </tr>
// ) : (
// data?.slice()?.reverse()?.map((user) => (
// <tr key={user.id}>
// <td>
// <span
// className="badge bg-info text-dark"
// style={{ cursor: "pointer" }}
// onClick={() => console.log("Go to Edit", user.id)}
// >
// {translate("SET_UP")}
// </span>
// </td>
// <td>{user.dashboard_name}</td>
// <td>{user.description}</td>
// <td>{user.security_profile}</td>
// <td>{user.add_to_home}</td>
// <td>
// <OverlayTrigger
// placement="top"
// overlay={<Tooltip>{translate("Delete")}</Tooltip>}
// >
// <i
// className="bi bi-trash text-danger"
// style={{ cursor: "pointer" }}
// onClick={() => handleDeleteClick(user)}
// ></i>
// </OverlayTrigger>
// <OverlayTrigger
// placement="top"
// overlay={<Tooltip>{translate("Edit")}</Tooltip>}
// >
// <i
// className="bi bi-pencil text-primary mx-2"
// style={{ cursor: "pointer" }}
// onClick={() => console.log("Edit", user.id)}
// ></i>
// </OverlayTrigger>
// </td>
// </tr>
// ))
// )}
// </tbody>
// </Table>
// {/* Add Modal */}
// <Modal show={addModal} onHide={() => setAddModal(false)} size="lg" centered>
// <Modal.Body>
// <div className="d-flex justify-content-around">
// <div
// className="chart-box text-center"
// onClick={() => console.log("Start from Scratch")}
// >
// <img
// src="/assets/images/fromscratch.png"
// alt="Start from Scratch"
// height="90"
// width="90"
// />
// <h5>{translate("Start_from_scratch")}</h5>
// </div>
// <div
// className="chart-box text-center"
// onClick={() => console.log("Import from Template")}
// >
// <img
// src="/assets/images/copytemplate.png"
// alt="Import from Template"
// height="90"
// width="90"
// />
// <h5>{translate("Import_from_template")}</h5>
// </div>
// <div
// className="chart-box text-center"
// onClick={() => console.log("Import from Public Project")}
// >
// <img
// src="/assets/images/database.png"
// alt="Import from Public Project"
// height="90"
// width="90"
// />
// <h5>{translate("Import_from_public_project")}</h5>
// </div>
// </div>
// </Modal.Body>
// </Modal>
// {/* Delete Modal */}
// <Modal show={deleteModal} onHide={() => setDeleteModal(false)} centered>
// <Modal.Body>
// <h1 className="text-danger text-center">
// {translate("Are_you_sure_want_to_delete")}
// </h1>
// <h2 className="text-center">{selectedRow?.id}</h2>
// <div className="d-flex justify-content-around mt-4">
// <Button variant="outline-secondary" onClick={() => setDeleteModal(false)}>
// {translate("Cancel")}
// </Button>
// <Button variant="primary" onClick={handleDeleteConfirm}>
// {translate("Delete")}
// </Button>
// </div>
// </Modal.Body>
// </Modal>
// </div>
// );
// };
// export default DashboardNewAll;
import React, { useState, useEffect } from "react";
import {
Button,
Modal,
Table,
Spinner,
Tooltip,
OverlayTrigger,
} from "react-bootstrap";
import { useTranslation } from "react-i18next";
import { useNavigate, useLocation } from "react-router-dom";
import * as XLSX from "xlsx";
import { toast } from "react-toastify";
import ConfirmModal from "../../../common/ConfirmModal"
import DashboardBuilderService from "../../../../APIServices/DashboardBuilderService";
const DashboardNewAll = () => {
const { t: translate } = useTranslation(); // Use `translate` as the translation function
const [addModal, setAddModal] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [deleteModal, setDeleteModal] = useState(false);
const [selectedRow, setSelectedRow] = useState(null);
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [refresh, setRefresh] = useState(false);
const [tableData, setTableData] = useState([]);
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const storedDashboards = JSON.parse(localStorage.getItem("dashboards")) || [];
setData(storedDashboards);
console.log("Stored Dashboards:", storedDashboards);
if (location.state?.updatedDashboard) {
const updatedDashboard = location.state.updatedDashboard;
setData(prevData => prevData.map(dashboard =>
dashboard.id === updatedDashboard.id ? updatedDashboard : dashboard
));
location.state.updatedDashboard = null;
}
setLoading(false);
}, [refresh, location.state?.updatedDashboard]);
const handleAddClick = () => {
navigate("/admin/dashboard-new-add");
}
const handleDeleteClick = (row) => {
setSelectedRow(row);
setShowConfirmModal(true);
};
const handleDeleteConfirm = async () => {
try {
// Call the delete API
await DashboardBuilderService.deleteField(selectedRow.id);
// Update the UI after successful deletion
setData((prevData) => prevData.filter((dashboard) => dashboard.id !== selectedRow.id));
toast.success("Dashboard deleted successfully!");
} catch (error) {
console.error("Error deleting dashboard field:", error);
toast.error("Failed to delete dashboard. Please try again.");
}
};
const handleRunner = () => {
console.log("Go to Runner");
navigate("/admin/dashboard-runner-all");
}
useEffect(() => {
fetchAllDashboards();
}, []);
const fetchAllDashboards = async () => {
try {
setLoading(true);
const dashboards = await DashboardBuilderService.getAllDash(); // Call service
console.log('Fetched Dashboards:', dashboards); // Verify data
setData(dashboards); // Update state with the array
toast.success("Dashboards fetched successfully.");
} catch (error) {
console.error('Error fetching dashboards:', error);
toast.error('Failed to fetch dashboards.');
} finally {
setLoading(false);
}
};
const handleEditClick = (dashboard) => {
navigate(`/admin/dashboard-new-edit/${dashboard.id}`, { state: { dashboard } }); // Pass the ID in the URL
}
const handleExport = () => {
console.log("Export to Excel");
// Create a new workbook and a worksheet
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.json_to_sheet(data);
// Append the worksheet to the workbook
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
// Write the workbook and download the file
XLSX.writeFile(workbook, "exported_data.xlsx");
}
const handleSetUp = (id) => {
console.log("dashboard id : ", id)
navigate(`/admin/edit-new-dash/${id}`,{dashboardId:id});
}
const refreshData = () => {
setRefresh((prev) => !prev); // Toggle the refresh state to trigger re-fetch
}
return (
<div className="dg-wrapper">
<div className="d-flex justify-content-between align-items-center mb-3">
<h3>{translate("Dashboard Builder")}</h3>
<div>
<Button variant="primary" onClick={() => handleRunner()}>
<i className="bi bi-grid"></i> {translate("Dashboard_runner")}
</Button>
<Button
variant="outline-secondary"
className="mx-2"
onClick={() => handleExport()}
>
<i className="bi bi-file-earmark-excel"></i> {translate("EXPORT_XLSX")}
</Button>
<Button variant="primary" onClick={handleAddClick}>
<i className="bi bi-plus"></i> {translate("ADD")}
</Button>
</div>
</div>
<Table striped bordered hover>
<thead>
<tr>
<th>Go To</th>
<th>Dashboard Name</th>
<th>Description</th>
<th>Security Profile</th>
<th>Add to Home</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{loading ? (
<tr>
<td colSpan="6" className="text-center">
<Spinner animation="border" /> Loading...
</td>
</tr>
) : data.length === 0 ? (
<tr>
<td colSpan="6" className="text-center">No dashboards available.</td>
</tr>
) : (
data.map((dashboard) => (
<tr key={dashboard.id}>
<td>
<span
className="badge bg-info text-dark"
style={{ cursor: "pointer" }}
onClick={() => handleSetUp(dashboard.id)}
>
SET UP
</span>
</td>
<td>{dashboard.dashboard_name}</td>
<td>{dashboard.description}</td>
<td>{dashboard.secuirity_profile}</td>
<td>{dashboard.add_to_home ? "Yes" : "No"}</td>
<td>
<i
className="bi bi-trash text-danger"
style={{ cursor: "pointer" }}
onClick={() => handleDeleteClick(dashboard)}
></i>
<i
className="bi bi-pencil text-primary mx-2"
style={{ cursor: "pointer" }}
onClick={() => handleEditClick(dashboard)}
></i>
</td>
</tr>
))
)}
</tbody>
</Table>
{/* Add Modal */}
<Modal show={addModal} onHide={() => setAddModal(false)} size="lg" centered>
<Modal.Body>
<div className="d-flex justify-content-around">
<div
className="chart-box text-center"
onClick={() => console.log("Start from Scratch")}
>
<img
src="/assets/images/fromscratch.png"
alt="Start from Scratch"
height="90"
width="90"
/>
<h5>{translate("Start_from_scratch")}</h5>
</div>
<div
className="chart-box text-center"
onClick={() => console.log("Import from Template")}
>
<img
src="/assets/images/copytemplate.png"
alt="Import from Template"
height="90"
width="90"
/>
<h5>{translate("Import_from_template")}</h5>
</div>
<div
className="chart-box text-center"
onClick={() => console.log("Import from Public Project")}
>
<img
src="/assets/images/database.png"
alt="Import from Public Project"
height="90"
width="90"
/>
<h5>{translate("Import_from_public_project")}</h5>
</div>
</div>
</Modal.Body>
</Modal>
{/* Confirmation Modal */}
<ConfirmModal
show={showConfirmModal}
onHide={() => setShowConfirmModal(false)}
onConfirm={handleDeleteConfirm}
title="Delete Dashboard"
message={`Are you sure you want to delete "${selectedRow?.dashboard_name || 'this dashboard'}"? This action cannot be undone.`}
confirmLabel="Delete"
cancelLabel="Cancel"
variant="danger"
/>
</div>
);
};
export default DashboardNewAll;

View File

@@ -0,0 +1,76 @@
import React from 'react';
import { Bar } from 'react-chartjs-2';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
const BarChart = () => {
const barChartLabels = ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes'];
const barChartData = {
labels: barChartLabels,
datasets: [
{
label: 'Best Fruits',
data: [45, 37, 60, 70, 46, 33],
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1,
},
],
};
const options = {
responsive: true,
plugins: {
legend: {
display: true,
position: 'top',
},
tooltip: {
enabled: true,
},
},
scales: {
x: {
beginAtZero: true,
},
y: {
beginAtZero: true,
},
},
};
const handleChartClick = (event, elements) => {
if (elements.length > 0) {
const { index } = elements[0];
console.log(`Clicked on ${barChartLabels[index]}`);
}
};
const handleChartHover = (event, elements) => {
if (elements.length > 0) {
console.log('Hovered on chart element:', elements);
}
};
return (
<div style={{ display: 'block', width: '600px', margin: 'auto' }}>
<Bar
data={barChartData}
options={options}
onClick={(event, elements) => handleChartClick(event, elements)}
onHover={(event, elements) => handleChartHover(event, elements)}
/>
</div>
);
};
export default BarChart;

View File

@@ -0,0 +1,92 @@
// BubbleChart.js
import React from 'react';
import { Bubble } from 'react-chartjs-2';
import {
Chart as ChartJS,
LinearScale,
PointElement,
Tooltip,
Legend,
Title,
} from 'chart.js';
// ChartJS.register(LinearScale, PointElement, Tooltip, Legend, Title);
const BubbleChart = () => {
const bubbleChartOptions = {
responsive: true,
plugins: {
title: {
display: true,
text: 'Bubble Chart',
},
},
scales: {
x: {
min: 0,
max: 30,
},
y: {
min: 0,
max: 30,
},
},
};
const bubbleChartData = {
datasets: [
{
data: [
{ x: 10, y: 10, r: 10 },
{ x: 15, y: 5, r: 15 },
{ x: 26, y: 12, r: 23 },
{ x: 7, y: 8, r: 8 },
],
label: 'Investment Equities',
backgroundColor: 'rgba(255, 0, 0, 0.6)', // Red
borderColor: 'blue',
hoverBackgroundColor: 'purple',
hoverBorderColor: 'red',
},
{
data: [
{ x: 5, y: 15, r: 12 },
{ x: 20, y: 7, r: 8 },
{ x: 12, y: 18, r: 15 },
{ x: 8, y: 6, r: 10 },
],
label: 'Investment Bonds',
backgroundColor: 'rgba(0, 255, 0, 0.6)', // Green
borderColor: 'green',
hoverBackgroundColor: 'yellow',
hoverBorderColor: 'blue',
},
],
};
const handleChartClick = (event, elements) => {
if (elements.length > 0) {
const { datasetIndex, index } = elements[0].element.$context;
console.log(`Clicked on:`, bubbleChartData.datasets[datasetIndex].data[index]);
}
};
const handleChartHover = (event, elements) => {
if (elements.length > 0) {
console.log('Hovered over:', elements);
}
};
return (
<div style={{ display: 'block', width: '600px', margin: 'auto' }}>
<Bubble
options={bubbleChartOptions}
data={bubbleChartData}
onClick={(event, elements) => handleChartClick(event, elements)}
onHover={(event, elements) => handleChartHover(event, elements)}
/>
</div>
);
};
export default BubbleChart;

View File

@@ -0,0 +1,72 @@
// DoughnutChart.js
import React from 'react';
import { Doughnut } from 'react-chartjs-2';
import {
Chart as ChartJS,
ArcElement,
Tooltip,
Legend,
} from 'chart.js';
//
const DoughnutChart = () => {
const doughnutChartData = {
labels: ["Download Sales", "In-Store Sales", "Mail-Order Sales"],
datasets: [
{
data: [350, 450, 100],
backgroundColor: [
'rgba(255, 99, 132, 0.6)',
'rgba(54, 162, 235, 0.6)',
'rgba(255, 206, 86, 0.6)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1,
},
],
};
const doughnutChartOptions = {
responsive: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Doughnut Chart',
},
},
};
const handleChartClick = (event, elements) => {
if (elements.length > 0) {
const { index } = elements[0].element.$context;
console.log(`Clicked on:`, doughnutChartData.labels[index]);
}
};
const handleChartHover = (event, elements) => {
if (elements.length > 0) {
console.log('Hovered over:', elements);
}
};
return (
<div style={{ display: 'block', width: '600px', margin: 'auto' }}>
<Doughnut
data={doughnutChartData}
options={doughnutChartOptions}
onClick={(event, elements) => handleChartClick(event, elements)}
onHover={(event, elements) => handleChartHover(event, elements)}
/>
</div>
);
};
export default DoughnutChart;

View File

@@ -0,0 +1,79 @@
// DynamicChart.js
import React, { useState } from 'react';
import { Bar } from 'react-chartjs-2';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
//
const DynamicChart = () => {
const [chartType, setChartType] = useState('bar');
const barChartOptions = {
responsive: true,
plugins: {
legend: {
display: true,
},
title: {
display: true,
text: 'Dynamic Chart',
},
},
};
const dynamicChartLabels = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
const dynamicChartData = {
labels: dynamicChartLabels,
datasets: [
{ data: [65, 59, 90, 81, 56, 55, 40], label: 'Series A', backgroundColor: 'rgba(75, 192, 192, 0.6)' },
{ data: [28, 48, 40, 19, 96, 27, 100], label: 'Series B', backgroundColor: 'rgba(153, 102, 255, 0.6)' },
],
};
const handleChartClick = (event, elements) => {
if (elements.length > 0) {
const { index } = elements[0].element.$context;
console.log(`Clicked on:`, dynamicChartLabels[index]);
}
};
const handleChartHover = (event, elements) => {
if (elements.length > 0) {
console.log('Hovered over:', elements);
}
};
const randomize = () => {
setChartType((prevType) => (prevType === 'bar' ? 'line' : 'bar'));
};
return (
<div style={{ display: 'block', width: '800px', margin: 'auto' }}>
<Bar
data={dynamicChartData}
options={barChartOptions}
type={chartType}
onClick={(event, elements) => handleChartClick(event, elements)}
onHover={(event, elements) => handleChartHover(event, elements)}
/>
<button
className="btn btn-primary"
style={{ marginTop: '20px' }}
onClick={randomize}
>
Update
</button>
</div>
);
};
export default DynamicChart;

View File

@@ -0,0 +1,78 @@
import React from 'react';
import { Line } from 'react-chartjs-2';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
// ✅ Register Chart.js components
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
// ✅ Default stock data (used if no data is passed)
const defaultStockData = [
{ date: '2024-03-01', price: 120 },
{ date: '2024-03-02', price: 125 },
{ date: '2024-03-03', price: 130 },
{ date: '2024-03-04', price: 128 },
{ date: '2024-03-05', price: 135 },
];
const FinancialChart = ({ data }) => {
// ✅ Use default data if no data is provided
const stockData = data && data.length > 0 ? data : defaultStockData;
const chartData = {
labels: stockData.map(item => item.date), // X-axis labels (dates)
datasets: [
{
label: 'Stock Price',
data: stockData.map(item => item.price), // Y-axis values (prices)
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
fill: true,
},
],
};
const chartOptions = {
responsive: true,
plugins: {
title: {
display: true,
text: 'Financial Data Chart',
},
tooltip: {
callbacks: {
label: (tooltipItem) => `$${tooltipItem.raw.toFixed(2)}`,
},
},
},
scales: {
x: {
title: {
display: true,
text: 'Date',
},
},
y: {
title: {
display: true,
text: 'Price (USD)',
},
ticks: {
callback: (value) => `$${value.toFixed(2)}`,
},
},
},
};
return <Line data={chartData} options={chartOptions} />;
};
export default FinancialChart;

View File

@@ -0,0 +1,102 @@
import React, { useState, useEffect } from "react";
import { Table, Spinner, Pagination, Form } from "react-bootstrap";
import {toast} from "react-toastify"; // if you want to use Toast notifications, or use a React version of it
import moment from "moment";
// import { ExcelService } from "src/app/services/excel.service";
// import { UsergrpmaintainceService } from "src/app/services/admin/usergrpmaintaince.service";
// import { MenuGroupService } from "src/app/services/admin/menu-group.service";
const GridViewComponent = () => {
const [loading, setLoading] = useState(false);
const [givendata, setGivendata] = useState([]);
const [error, setError] = useState(null);
const [modalAdd, setModalAdd] = useState(false);
const [modalEdit, setModalEdit] = useState(false);
const [modalDelete, setModalDelete] = useState(false);
const [rowSelected, setRowSelected] = useState({});
const [orders, setOrders] = useState([]);
const [submitted, setSubmitted] = useState(false);
// useEffect(() => {
// // Fetching the data on component mount
// setLoading(true);
// UsergrpmaintainceService.getAll()
// .then((data) => {
// setLoading(false);
// setGivendata(data);
// if (data.length === 0) {
// setError("No data Available");
// }
// })
// .catch((err) => {
// setLoading(false);
// setError("Server Error");
// });
// }, []);
const handleRowSelect = (row) => {
setRowSelected(row);
};
const handlePagination = (page) => {
// Handle pagination logic here
};
return (
<div style={{ display: "block" }}>
<div className="dg-wrapper">
<div className="clr-row">
<div className="clr-col-8">
<h3>User Group Maintenance</h3>
</div>
</div>
<div>
{loading ? (
<div>
<Spinner animation="border" /> Loading...
</div>
) : error ? (
<div>{error}</div>
) : (
<Table striped bordered hover>
<thead>
<tr>
<th>User Group No</th>
<th>Group Name</th>
<th>Description</th>
<th>Group Level</th>
<th>Status</th>
<th>Updated Date</th>
</tr>
</thead>
<tbody>
{givendata.reverse().map((user, index) => (
<tr key={index} onClick={() => handleRowSelect(user)}>
<td>{user.usrGrp}</td>
<td>{user.groupName}</td>
<td>{user.groupDesc}</td>
<td>{user.groupLevel}</td>
<td>{user.status}</td>
<td>{user.updateDateFormated}</td>
</tr>
))}
</tbody>
</Table>
)}
</div>
<div>
{/* Pagination logic */}
<Pagination>
{/* Add pagination items here */}
<Pagination.Item onClick={() => handlePagination(1)}>1</Pagination.Item>
<Pagination.Item onClick={() => handlePagination(2)}>2</Pagination.Item>
{/* Pagination logic based on the fetched data */}
</Pagination>
</div>
</div>
</div>
);
};
export default GridViewComponent;

View File

@@ -0,0 +1,236 @@
// import React, { useState, useEffect } from 'react';
// import { Line } from 'react-chartjs-2'; // Assuming you're using react-chartjs-2 for the chart rendering
// import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from 'chart.js';
// //
// const LineChartComponent = () => {
// const [lineChartData, setLineChartData] = useState([
// { data: [65, 59, 80, 81, 56, 55, 40], label: 'Series A' },
// { data: [28, 48, 40, 19, 86, 27, 90], label: 'Series B' },
// { data: [18, 48, 77, 9, 100, 27, 40], label: 'Series C' },
// ]);
// const [lineChartLabels] = useState(['January', 'February', 'March', 'April', 'May', 'June', 'July']);
// const [lineChartOptions] = useState({
// responsive: true,
// });
// const [lineChartColors] = useState([
// {
// backgroundColor: 'rgba(148,159,177,0.2)',
// borderColor: 'rgba(148,159,177,1)',
// pointBackgroundColor: 'rgba(148,159,177,1)',
// pointBorderColor: '#fff',
// pointHoverBackgroundColor: '#fff',
// pointHoverBorderColor: 'rgba(148,159,177,0.8)',
// },
// {
// backgroundColor: 'rgba(77,83,96,0.2)',
// borderColor: 'rgba(77,83,96,1)',
// pointBackgroundColor: 'rgba(77,83,96,1)',
// pointBorderColor: '#fff',
// pointHoverBackgroundColor: '#fff',
// pointHoverBorderColor: 'rgba(77,83,96,1)',
// },
// {
// backgroundColor: 'rgba(148,159,177,0.2)',
// borderColor: 'rgba(148,159,177,1)',
// pointBackgroundColor: 'rgba(148,159,177,1)',
// pointBorderColor: '#fff',
// pointHoverBackgroundColor: '#fff',
// pointHoverBorderColor: 'rgba(148,159,177,0.8)',
// },
// ]);
// const [lineChartLegend] = useState(true);
// const [lineChartType] = useState('line');
// // Function to randomize chart data
// const randomize = () => {
// const _lineChartData = lineChartData.map((series) => ({
// ...series,
// data: series.data.map(() => Math.floor(Math.random() * 100) + 1),
// }));
// setLineChartData(_lineChartData);
// };
// // Chart hover and click events
// const chartClicked = (e) => {
// console.log(e);
// };
// const chartHovered = (e) => {
// console.log(e);
// };
// return (
// <div style={{ display: 'block' }}>
// <Line
// data={{
// labels: lineChartLabels,
// datasets: lineChartData,
// }}
// options={lineChartOptions}
// legend={lineChartLegend}
// type={lineChartType}
// onHover={chartHovered}
// onClick={chartClicked}
// />
// {/* You can add a button here to call randomize() */}
// <button onClick={randomize}>Randomize Data</button>
// </div>
// );
// };
// export default LineChartComponent;
import React, { useState } from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
} from 'chart.js';
import { Line } from 'react-chartjs-2';
import { Box, Button } from '@mui/material';
// Register Chart.js components
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
const LineChartComponent = ({
chartTitle = 'Line Chart',
showLegend = true,
showLabel = true,
xAxis = 'Category',
yAxis = 'Value',
width = '100%',
height = '100%'
}) => {
const [lineChartData, setLineChartData] = useState({
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'Series A',
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(75, 192, 192, 1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(75, 192, 192, 1)',
tension: 0.1
},
{
label: 'Series B',
data: [28, 48, 40, 19, 86, 27, 90],
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(54, 162, 235, 1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(54, 162, 235, 1)',
tension: 0.1
},
{
label: 'Series C',
data: [18, 48, 77, 9, 100, 27, 40],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(255, 99, 132, 1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(255, 99, 132, 1)',
tension: 0.1
},
]
});
// Options for the chart
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: showLegend,
},
title: {
display: true,
text: chartTitle,
},
tooltip: {
enabled: true,
}
},
scales: {
x: {
title: {
display: showLabel,
text: xAxis
}
},
y: {
title: {
display: showLabel,
text: yAxis
}
}
}
};
// Function to randomize chart data
const randomize = () => {
setLineChartData(prevData => ({
...prevData,
datasets: prevData.datasets.map(dataset => ({
...dataset,
data: Array.from({ length: 7 }, () => Math.floor(Math.random() * 100) + 1)
}))
}));
};
return (
<Box sx={{
width,
height,
display: 'flex',
flexDirection: 'column',
position: 'relative'
}}>
<Box sx={{ flex: 1, minHeight: 0 }}>
<Line data={lineChartData} options={options} />
</Box>
<Box sx={{
display: 'flex',
justifyContent: 'center',
pt: 1
}}>
<Button
variant="outlined"
size="small"
onClick={randomize}
sx={{ fontSize: '0.75rem' }}
>
Randomize Data
</Button>
</Box>
</Box>
);
};
export default LineChartComponent;

View File

@@ -0,0 +1,42 @@
import React, { useState } from 'react';
import { Pie } from 'react-chartjs-2'; // Import Pie chart from react-chartjs-2
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
// Register required elements for Pie chart
const PieChartComponent = () => {
// Define pie chart data and labels
const [pieChartData] = useState([30, 50, 20]);
const [pieChartLabels] = useState(['SciFi', 'Drama', 'Comedy']);
const [pieChartType] = useState('pie');
// Handle chart hover and click events
const chartClicked = (e) => {
console.log(e);
};
const chartHovered = (e) => {
console.log(e);
};
return (
<div style={{ display: 'block' }}>
<Pie
data={{
labels: pieChartLabels,
datasets: [
{
data: pieChartData,
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56'], // Customize the colors
},
],
}}
type={pieChartType}
onHover={chartHovered}
onClick={chartClicked}
/>
</div>
);
};
export default PieChartComponent;

View File

@@ -0,0 +1,125 @@
// import React, { useState } from 'react';
// import { Polar } from 'react-chartjs-2'; // Import PolarArea chart from react-chartjs-2
// import { Chart as ChartJS, PolarAreaElement, Tooltip, Legend } from 'chart.js';
// ChartJS.register(PolarAreaElement, Tooltip, Legend); // Register the required elements for Polar Area chart
// const PolarChartComponent = () => {
// // Define polar area chart data, labels, and type
// const [polarAreaChartLabels] = useState([
// 'Download Sales',
// 'In-Store Sales',
// 'Mail Sales',
// 'Telesales',
// 'Corporate Sales'
// ]);
// const [polarAreaChartData] = useState([
// { data: [300, 500, 100, 40, 120], label: 'Series 1' }
// ]);
// const [polarAreaChartType] = useState('polarArea');
// // Handle chart hover and click events
// const chartClicked = (e) => {
// console.log(e);
// };
// const chartHovered = (e) => {
// console.log(e);
// };
// return (
// <div style={{ display: 'block' }}>
// <Polar
// data={{
// labels: polarAreaChartLabels,
// datasets: polarAreaChartData,
// }}
// type={polarAreaChartType}
// onHover={chartHovered}
// onClick={chartClicked}
// />
// </div>
// );
// };
// export default PolarChartComponent;
import React from 'react';
import { PolarArea as Polar } from 'react-chartjs-2';
import {
Chart as ChartJS,
RadialLinearScale,
ArcElement,
Tooltip,
Legend,
} from 'chart.js';
// Register required Chart.js components
const PolarChartComponent = () => {
// Chart data
const data = {
labels: [
'Download Sales',
'In-Store Sales',
'Mail Sales',
'Telesales',
'Corporate Sales',
],
datasets: [
{
data: [300, 500, 100, 40, 120],
backgroundColor: [
'rgba(255, 99, 132, 0.6)',
'rgba(54, 162, 235, 0.6)',
'rgba(255, 206, 86, 0.6)',
'rgba(75, 192, 192, 0.6)',
'rgba(153, 102, 255, 0.6)',
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
],
borderWidth: 1,
},
],
};
// Chart options
const options = {
responsive: true,
plugins: {
legend: {
position: 'top',
},
tooltip: {
callbacks: {
label: (tooltipItem) => {
return `${tooltipItem.label}: ${tooltipItem.raw}`;
},
},
},
},
onClick: (event, elements) => {
if (elements.length > 0) {
const datasetIndex = elements[0].datasetIndex;
const dataIndex = elements[0].index;
console.log(
`Clicked on dataset ${datasetIndex}, data index ${dataIndex}`
);
}
},
};
return (
<div style={{ width: '50%', margin: 'auto' }}>
<Polar data={data} options={options} />
</div>
);
};
export default PolarChartComponent;

View File

@@ -0,0 +1,44 @@
import React, { useState } from 'react';
import { Radar } from 'react-chartjs-2'; // Import Radar chart from react-chartjs-2
import { Chart as ChartJS, RadarElement, Tooltip, Legend, PointElement, LineElement } from 'chart.js';
// ChartJS.register(RadarElement, Tooltip, Legend, PointElement, LineElement); // Register required chart elements for Radar chart
const RadarChartComponent = () => {
// Define radar chart data, labels, and type
const [radarChartLabels] = useState([
'Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'
]);
const [radarChartData] = useState([
{ data: [65, 59, 90, 81, 56, 55, 40], label: 'Series A' },
{ data: [28, 48, 40, 19, 96, 27, 100], label: 'Series B' }
]);
const [radarChartType] = useState('radar');
// Handle chart hover and click events
const chartClicked = (e) => {
console.log(e);
};
const chartHovered = (e) => {
console.log(e);
};
return (
<div style={{ display: 'block' }}>
<Radar
data={{
labels: radarChartLabels,
datasets: radarChartData,
}}
type={radarChartType}
onHover={chartHovered}
onClick={chartClicked}
/>
</div>
);
};
export default RadarChartComponent;

View File

@@ -0,0 +1,55 @@
import React, { useState } from 'react';
import { Scatter } from 'react-chartjs-2'; // Import Scatter chart from react-chartjs-2
import { Chart as ChartJS, Tooltip, Legend, ScatterElement, PointElement } from 'chart.js';
// ChartJS.register(Tooltip, Legend, ScatterElement, PointElement); // Register required chart elements for scatter chart
const ScatterChartComponent = () => {
// Define scatter chart data, labels, and type
const [scatterChartLabels] = useState([
'Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'
]);
const [scatterChartData] = useState([
{
data: [
{ x: 1, y: 1 },
{ x: 2, y: 3 },
{ x: 3, y: -2 },
{ x: 4, y: 4 },
{ x: 5, y: -3, r: 20 },
],
label: 'Series A',
pointRadius: 10,
backgroundColor: [
'red', 'green', 'blue', 'purple', 'yellow', 'brown', 'magenta', 'cyan', 'orange', 'pink'
]
},
]);
const [scatterChartType] = useState('scatter');
// Handle chart hover and click events
const chartClicked = (e) => {
console.log(e);
};
const chartHovered = (e) => {
console.log(e);
};
return (
<div style={{ display: 'block' }}>
<Scatter
data={{
datasets: scatterChartData,
}}
type={scatterChartType}
onHover={chartHovered}
onClick={chartClicked}
/>
</div>
);
};
export default ScatterChartComponent;

View File

@@ -0,0 +1,70 @@
import React, { useState } from 'react';
const ToDoChartComponent = () => {
// State to store todo list and current todo input value
const [todo, setTodo] = useState('');
const [todoList, setTodoList] = useState(['todo 1']);
// Add a new todo to the list
const addTodo = (newTodo) => {
if (newTodo.trim()) {
setTodoList([...todoList, newTodo]);
setTodo(''); // Clear the input field after adding
}
};
// Remove a todo from the list by index
const removeTodo = (index) => {
const updatedTodoList = todoList.filter((_, i) => i !== index);
setTodoList(updatedTodoList);
};
return (
<table className="table">
<thead>
<tr>
<th className="c-col">#</th>
<th>Item</th>
<th></th>
</tr>
</thead>
<tbody>
{todoList.map((todoItem, index) => (
<tr className="ui basic segment" key={index}>
<td className="c-col">{index + 1}</td>
<td>{todoItem}</td>
<td style={{ textAlign: 'right' }}>
<button
onClick={() => removeTodo(index)}
style={{ background: 'none', border: 'none' }}
>
<i className="clr-icon times"></i>
</button>
</td>
</tr>
))}
<tr>
<td></td>
<td>
<input
value={todo}
onChange={(e) => setTodo(e.target.value)}
placeholder="Add Todo"
className="clr-input"
/>
</td>
<td style={{ textAlign: 'right' }}>
<button
onClick={() => addTodo(todo)}
style={{ background: 'none', border: 'none' }}
>
<i className="clr-icon plus"></i>
</button>
</td>
</tr>
</tbody>
</table>
);
};
export default ToDoChartComponent;

View File

@@ -0,0 +1,11 @@
import React from 'react';
const ScheduleComponent = () => {
return (
<div>
<p>Schedule works!</p>
</div>
);
};
export default ScheduleComponent;

View File

@@ -0,0 +1,89 @@
/*!
=========================================================
* Argon Dashboard React - v1.2.4
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard-react
* Copyright 2024 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
* Coded by Creative Tim
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/*eslint-disable*/
// reactstrap components
import { Container, Row, Col, Nav, NavItem, NavLink } from "reactstrap";
const Footer = () => {
return (
<footer className="footer">
<Row className="align-items-center justify-content-xl-between">
<Col xl="6">
<div className="copyright text-center text-xl-left text-muted">
© {new Date().getFullYear()}{" "}
<a
className="font-weight-bold ml-1"
href="https://www.creative-tim.com?ref=adr-admin-footer"
rel="noopener noreferrer"
target="_blank"
>
Creative Tim
</a>
</div>
</Col>
<Col xl="6">
<Nav className="nav-footer justify-content-center justify-content-xl-end">
<NavItem>
<NavLink
href="https://www.creative-tim.com?ref=adr-admin-footer"
rel="noopener noreferrer"
target="_blank"
>
Creative Tim
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="https://www.creative-tim.com/presentation?ref=adr-admin-footer"
rel="noopener noreferrer"
target="_blank"
>
About Us
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="http://blog.creative-tim.com?ref=adr-admin-footer"
rel="noopener noreferrer"
target="_blank"
>
Blog
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="https://github.com/creativetimofficial/argon-dashboard/blob/master/LICENSE.md?ref=adr-admin-footer"
rel="noopener noreferrer"
target="_blank"
>
MIT License
</NavLink>
</NavItem>
</Nav>
</Col>
</Row>
</footer>
);
};
export default Footer;

View File

@@ -0,0 +1,84 @@
/*!
=========================================================
* Argon Dashboard React - v1.2.4
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard-react
* Copyright 2024 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
* Coded by Creative Tim
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/*eslint-disable*/
// reactstrap components
import { NavItem, NavLink, Nav, Container, Row, Col } from "reactstrap";
const Login = () => {
return (
<>
<footer className="py-5">
<Container>
<Row className="align-items-center justify-content-xl-between">
<Col xl="6">
<div className="copyright text-center text-xl-left text-muted">
© {new Date().getFullYear()}{" "}
<a
className="font-weight-bold ml-1"
href="https://www.creative-tim.com?ref=adr-auth-footer"
target="_blank"
>
Creative Tim
</a>
</div>
</Col>
<Col xl="6">
<Nav className="nav-footer justify-content-center justify-content-xl-end">
<NavItem>
<NavLink
href="https://www.creative-tim.com?ref=adr-auth-footer"
target="_blank"
>
Creative Tim
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="https://www.creative-tim.com/presentation?ref=adr-auth-footer"
target="_blank"
>
About Us
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="http://blog.creative-tim.com?ref=adr-auth-footer"
target="_blank"
>
Blog
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="https://github.com/creativetimofficial/argon-dashboard/blob/master/LICENSE.md?ref=adr-auth-footer"
target="_blank"
>
MIT License
</NavLink>
</NavItem>
</Nav>
</Col>
</Row>
</Container>
</footer>
</>
);
};
export default Login;

View File

@@ -0,0 +1,291 @@
/*!
=========================================================
* Argon Dashboard React - v1.2.4
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard-react
* Copyright 2024 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
* Coded by Creative Tim
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
// reactstrap components
// import { Card, CardBody, CardTitle, Container, Row, Col } from "reactstrap";
// const Header = () => {
// return (
// <>
// <div className="header bg-gradient-info pb-8 pt-5 pt-md-10">
// <Container fluid>
// <div className="header-body">
// {/* Card stats */}
// <Row >
// <Col lg="6" xl="3" className="d-flex align-items-stretch">
// <Card className="card-stats mb-4 mb-xl-0 w-100">
// <CardBody>
// <Row>
// <div className="col">
// <CardTitle
// tag="h5"
// className="text-uppercase text-muted mb-0"
// >
// Traffic
// </CardTitle>
// <span className="h2 font-weight-bold mb-0">
// 350,897
// </span>
// </div>
// <Col className="col-auto">
// <div className="icon icon-shape bg-danger text-white rounded-circle shadow">
// <i className="fas fa-chart-bar" />
// </div>
// </Col>
// </Row>
// <p className="mt-3 mb-0 text-muted text-sm">
// <span className="text-success mr-2">
// <i className="fa fa-arrow-up" /> 3.48%
// </span>{" "}
// <span className="text-nowrap">Since last month</span>
// </p>
// </CardBody>
// </Card>
// </Col>
// <Col lg="6" xl="3">
// <Card className="card-stats mb-4 mb-xl-0">
// <CardBody>
// <Row>
// <div className="col">
// <CardTitle
// tag="h5"
// className="text-uppercase text-muted mb-0"
// >
// New users
// </CardTitle>
// <span className="h2 font-weight-bold mb-0">2,356</span>
// </div>
// <Col className="col-auto">
// <div className="icon icon-shape bg-warning text-white rounded-circle shadow">
// <i className="fas fa-chart-pie" />
// </div>
// </Col>
// </Row>
// <p className="mt-3 mb-0 text-muted text-sm">
// <span className="text-danger mr-2">
// <i className="fas fa-arrow-down" /> 3.48%
// </span>{" "}
// <span className="text-nowrap">Since last week</span>
// </p>
// </CardBody>
// </Card>
// </Col>
// <Col lg="6" xl="3">
// <Card className="card-stats mb-4 mb-xl-0">
// <CardBody>
// <Row>
// <div className="col">
// <CardTitle
// tag="h5"
// className="text-uppercase text-muted mb-0"
// >
// Sales
// </CardTitle>
// <span className="h2 font-weight-bold mb-0">924</span>
// </div>
// <Col className="col-auto">
// <div className="icon icon-shape bg-yellow text-white rounded-circle shadow">
// <i className="fas fa-users" />
// </div>
// </Col>
// </Row>
// <p className="mt-3 mb-0 text-muted text-sm">
// <span className="text-warning mr-2">
// <i className="fas fa-arrow-down" /> 1.10%
// </span>{" "}
// <span className="text-nowrap">Since yesterday</span>
// </p>
// </CardBody>
// </Card>
// </Col>
// <Col lg="6" xl="3">
// <Card className="card-stats mb-4 mb-xl-0">
// <CardBody>
// <Row>
// <div className="col">
// <CardTitle
// tag="h5"
// className="text-uppercase text-muted mb-0"
// >
// Performance
// </CardTitle>
// <span className="h2 font-weight-bold mb-0">49,65%</span>
// </div>
// <Col className="col-auto">
// <div className="icon icon-shape bg-info text-white rounded-circle shadow">
// <i className="fas fa-percent" />
// </div>
// </Col>
// </Row>
// <p className="mt-3 mb-0 text-muted text-sm">
// <span className="text-success mr-2">
// <i className="fas fa-arrow-up" /> 12%
// </span>{" "}
// <span className="text-nowrap">Since last month</span>
// </p>
// </CardBody>
// </Card>
// </Col>
// </Row>
// </div>
// </Container>
// </div>
// </>
// );
// };
// export default Header;
import { Card, CardBody, CardTitle, Container, Row, Col } from "reactstrap";
const Header = () => {
return (
<>
<div
className="header bg-gradient-info pb-8 pt-7 pt-md-12"
style={{ marginTop: "6rem" }}
>
{" "}
{/* Adjust pt-md-10 to add more space from top */}
<Container fluid>
<div className="header-body">
{/* Card stats */}
<Row className="d-flex">
<Col lg="6" xl="3" className="d-flex align-items-stretch">
<Card className="card-stats mb-4 mb-xl-0 w-100">
<CardBody>
<Row>
<div className="col">
<CardTitle
tag="h5"
className="text-uppercase text-muted mb-0"
>
Traffic
</CardTitle>
<span className="h2 font-weight-bold mb-0">
350,897
</span>
</div>
<Col className="col-auto">
<div className="icon icon-shape bg-danger text-white rounded-circle shadow">
<i className="fas fa-chart-bar" />
</div>
</Col>
</Row>
<p className="mt-3 mb-0 text-muted text-sm">
<span className="text-success mr-2">
<i className="fa fa-arrow-up" /> 3.48%
</span>{" "}
<span className="text-nowrap">Since last month</span>
</p>
</CardBody>
</Card>
</Col>
<Col lg="6" xl="3" className="d-flex align-items-stretch">
<Card className="card-stats mb-4 mb-xl-0 w-100">
<CardBody>
<Row>
<div className="col">
<CardTitle
tag="h5"
className="text-uppercase text-muted mb-0"
>
New users
</CardTitle>
<span className="h2 font-weight-bold mb-0">2,356</span>
</div>
<Col className="col-auto">
<div className="icon icon-shape bg-warning text-white rounded-circle shadow">
<i className="fas fa-chart-pie" />
</div>
</Col>
</Row>
<p className="mt-3 mb-0 text-muted text-sm">
<span className="text-danger mr-2">
<i className="fas fa-arrow-down" /> 3.48%
</span>{" "}
<span className="text-nowrap">Since last week</span>
</p>
</CardBody>
</Card>
</Col>
<Col lg="6" xl="3" className="d-flex align-items-stretch">
<Card className="card-stats mb-4 mb-xl-0 w-100">
<CardBody>
<Row>
<div className="col">
<CardTitle
tag="h5"
className="text-uppercase text-muted mb-0"
>
Sales
</CardTitle>
<span className="h2 font-weight-bold mb-0">924</span>
</div>
<Col className="col-auto">
<div className="icon icon-shape bg-yellow text-white rounded-circle shadow">
<i className="fas fa-users" />
</div>
</Col>
</Row>
<p className="mt-3 mb-0 text-muted text-sm">
<span className="text-warning mr-2">
<i className="fas fa-arrow-down" /> 1.10%
</span>{" "}
<span className="text-nowrap">Since yesterday</span>
</p>
</CardBody>
</Card>
</Col>
<Col lg="6" xl="3" className="d-flex align-items-stretch">
<Card className="card-stats mb-4 mb-xl-0 w-100">
<CardBody>
<Row>
<div className="col">
<CardTitle
tag="h5"
className="text-uppercase text-muted mb-0"
>
Performance
</CardTitle>
<span className="h2 font-weight-bold mb-0">49,65%</span>
</div>
<Col className="col-auto">
<div className="icon icon-shape bg-info text-white rounded-circle shadow">
<i className="fas fa-percent" />
</div>
</Col>
</Row>
<p className="mt-3 mb-0 text-muted text-sm">
<span className="text-success mr-2">
<i className="fas fa-arrow-up" /> 12%
</span>{" "}
<span className="text-nowrap">Since last month</span>
</p>
</CardBody>
</Card>
</Col>
</Row>
</div>
</Container>
</div>
</>
);
};
export default Header;

View File

@@ -0,0 +1,61 @@
/*!
=========================================================
* Argon Dashboard React - v1.2.4
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard-react
* Copyright 2024 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
* Coded by Creative Tim
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
// reactstrap components
import { Button, Container, Row, Col } from "reactstrap";
const UserHeader = () => {
return (
<>
<div
className="header pb-8 pt-5 pt-lg-8 d-flex align-items-center"
style={{
minHeight: "600px",
backgroundImage:
"url(" + require("../../assets/img/theme/profile-cover.jpg") + ")",
backgroundSize: "cover",
backgroundPosition: "center top",
}}
>
{/* Mask */}
<span className="mask bg-gradient-default opacity-8" />
{/* Header container */}
<Container className="d-flex align-items-center" fluid>
<Row>
<Col lg="7" md="10">
<h1 className="display-2 text-white">Hello Jesse</h1>
<p className="text-white mt-0 mb-5">
This is your profile page. You can see the progress you've made
with your work and manage your projects or assigned tasks
</p>
<Button
color="info"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
Edit profile
</Button>
</Col>
</Row>
</Container>
</div>
</>
);
};
export default UserHeader;

View File

@@ -0,0 +1,173 @@
/* Navbar */
#navbar-main {
background: linear-gradient(90deg, #0e6591 0%, #1a8bc5 100%);
padding: 0.5rem 1rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
width: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 1030;
}
/* Container */
.navbar-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
width: 100%;
}
/* Brand */
.brand_name {
color: #fff;
font-weight: 700;
font-size: 1.6rem;
text-transform: uppercase;
letter-spacing: 2px;
transition: color 0.3s ease, transform 0.3s ease;
}
.brand_name:hover {
color: #ffd700;
transform: scale(1.05);
}
/* Navigation Icons */
.nav-icons {
gap: 1.5rem;
}
.nav-icon {
display: flex;
align-items: center;
justify-content: center;
color: #fff;
transition: color 0.3s ease, transform 0.3s ease;
}
.nav-icon i {
font-size: 1.5rem;
}
.nav-icon:hover {
color: #ffd700;
transform: scale(1.15);
}
/* Search Bar */
.search-input-group {
border-radius: 30px;
background-color: #fff;
border: none;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.search-input-group:hover,
.search-input-group:focus-within {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
transform: translateY(-1px);
}
.search-icon {
background-color: #0078b9;
color: #fff;
border-radius: 50%;
padding: 0.5rem;
transition: background-color 0.3s ease;
}
.search-icon:hover {
background-color: #005579;
}
.search-input {
border: none;
border-radius: 30px;
padding: 0.75rem 1rem;
font-size: 0.95rem;
background-color: transparent;
}
.search-input:focus {
outline: none;
box-shadow: none;
}
/* Profile Dropdown */
.nav-right {
gap: 1rem;
}
.avatar {
border: 3px solid #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: transform 0.3s ease;
}
.avatar:hover {
transform: scale(1.1);
}
.dropdown-menu {
border-radius: 10px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
animation: slideDown 0.2s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dropdown-item {
font-size: 0.9rem;
padding: 0.5rem 1rem;
color: #333;
transition: all 0.3s ease;
}
.dropdown-item:hover {
background-color: #f1f5f9;
color: #0078b9;
}
.dropdown-item:last-child {
color: #dc3545;
}
.dropdown-item:last-child:hover {
background-color: #fef2f2;
}
/* Body Adjustment */
body {
padding-top: 60px;
}
/* Responsive */
@media (max-width: 768px) {
.navbar-container {
flex-direction: column;
padding: 0.5rem;
gap: 1rem;
}
.nav-icons {
justify-content: center;
gap: 1rem;
}
.search-input-group {
width: 100%;
max-width: 300px;
}
}

View File

@@ -0,0 +1,121 @@
import { useNavigate, Link } from "react-router-dom";
import {
DropdownMenu,
DropdownItem,
UncontrolledDropdown,
DropdownToggle,
Form,
FormGroup,
InputGroupAddon,
InputGroupText,
Input,
InputGroup,
Navbar,
Nav,
Media,
} from "reactstrap";
import "./AdminNavbar.css";
import "bootstrap-icons/font/bootstrap-icons.css";
const AdminNavbar = ({ brandText }) => {
const navigate = useNavigate();
const handleLogout = () => {
// localStorage.removeItem("authToken"); // Uncomment if needed
navigate("/login");
};
return (
<Navbar className="navbar-top navbar-dark" expand="lg" id="navbar-main">
<div className="navbar-container container-fluid">
{/* Brand */}
<Link className="brand_name h4 mb-0 text-white text-uppercase" to="/">
{brandText}
</Link>
{/* Navigation Icons */}
<div className="nav-icons d-flex align-items-center">
<Link to="/admin/index" className="nav-icon">
<i className="fas fa-home" />
</Link>
<Link to="/admin/setting" className="nav-icon">
<i className="ni ni-settings-gear-65" />
</Link>
<Link to="/admin/dashboard-runner-all" className="nav-icon">
<i className="bi bi-grid" />
</Link>
<Link to="/admin/report-runner" className="nav-icon">
<i className="ni ni-chart-bar-32" />
</Link>
<Link to="/admin/user-report" className="nav-icon">
<i className="ni ni-grid" />
</Link>
</div>
{/* Search and Profile */}
<div className="nav-right d-flex align-items-center">
<Form className="navbar-search navbar-search-dark form-inline">
<FormGroup className="mb-0">
<InputGroup className="input-group-alternative search-input-group">
<InputGroupAddon addonType="prepend">
<InputGroupText className="search-icon">
<i className="fas fa-search" />
</InputGroupText>
</InputGroupAddon>
<Input placeholder="Search" type="text" className="search-input" />
</InputGroup>
</FormGroup>
</Form>
<Nav className="align-items-center" navbar>
<UncontrolledDropdown nav>
<DropdownToggle className="pr-0" nav>
<Media className="align-items-center">
<span className="avatar avatar-sm rounded-circle">
<img
alt="Profile"
src={require("../../assets/img/theme/team-4-800x800.jpg")}
/>
</span>
<Media className="ml-2 d-none d-lg-block">
<span className="brand_name mb-0 text-sm font-weight-bold text-white-50">
Jessica Jones
</span>
</Media>
</Media>
</DropdownToggle>
<DropdownMenu className="dropdown-menu-arrow" right>
<DropdownItem className="noti-title" header tag="div">
<h6 className="text-overflow m-0">Welcome!</h6>
</DropdownItem>
<DropdownItem to="/admin/user-profile" tag={Link}>
<i className="ni ni-single-02" />
<span>My profile</span>
</DropdownItem>
<DropdownItem to="/admin/user-profile" tag={Link}>
<i className="ni ni-settings-gear-65" />
<span>Settings</span>
</DropdownItem>
<DropdownItem to="/admin/user-profile" tag={Link}>
<i className="ni ni-calendar-grid-58" />
<span>Activity</span>
</DropdownItem>
<DropdownItem to="/admin/user-profile" tag={Link}>
<i className="ni ni-support-16" />
<span>Support</span>
</DropdownItem>
<DropdownItem divider />
<DropdownItem onClick={handleLogout}>
<i className="ni ni-user-run" />
<span>Logout</span>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
</div>
</div>
</Navbar>
);
};
export default AdminNavbar;

View File

@@ -0,0 +1,90 @@
import { Link } from "react-router-dom";
// reactstrap components
import {
UncontrolledCollapse,
NavbarBrand,
Navbar,
NavItem,
NavLink,
Nav,
Container,
Row,
Col,
} from "reactstrap";
const AdminNavbar = () => {
return (
<>
<Navbar className="navbar-top navbar-horizontal navbar-dark" expand="md">
<Container className="px-4">
<NavbarBrand to="/" tag={Link}>
<img
alt="..."
src={require("../../assets/img/brand/argon-react-white.png")}
/>
</NavbarBrand>
<button className="navbar-toggler" id="navbar-collapse-main">
<span className="navbar-toggler-icon" />
</button>
<UncontrolledCollapse navbar toggler="#navbar-collapse-main">
<div className="navbar-collapse-header d-md-none">
<Row>
<Col className="collapse-brand" xs="6">
<Link to="/">
<img
alt="..."
src={require("../../assets/img/brand/argon-react.png")}
/>
</Link>
</Col>
<Col className="collapse-close" xs="6">
<button className="navbar-toggler" id="navbar-collapse-main">
<span />
<span />
</button>
</Col>
</Row>
</div>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink className="nav-link-icon" to="/" tag={Link}>
<i className="ni ni-planet" />
<span className="nav-link-inner--text">Dashboard</span>
</NavLink>
</NavItem>
<NavItem>
<NavLink
className="nav-link-icon"
to="/auth/register"
tag={Link}
>
<i className="ni ni-circle-08" />
<span className="nav-link-inner--text">Register</span>
</NavLink>
</NavItem>
<NavItem>
<NavLink className="nav-link-icon" to="/auth/login" tag={Link}>
<i className="ni ni-key-25" />
<span className="nav-link-inner--text">Login</span>
</NavLink>
</NavItem>
<NavItem>
<NavLink
className="nav-link-icon"
to="/admin/user-profile"
tag={Link}
>
<i className="ni ni-single-02" />
<span className="nav-link-inner--text">Profile</span>
</NavLink>
</NavItem>
</Nav>
</UncontrolledCollapse>
</Container>
</Navbar>
</>
);
};
export default AdminNavbar;

View File

@@ -0,0 +1,86 @@
.sidebar-wrapper {
height: calc(100vh - 70px);
position: fixed;
top: 70px;
left: 0;
z-index: 1000;
}
.app-sidebar {
border-right: 1px solid #e9ecef;
height: 100%;
}
.sidebar-header {
padding: 1rem;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e9ecef;
}
.logo-container {
display: flex;
align-items: center;
}
/*
.navbar-brand-img {
height: 40px;
width: auto;
} */
.sidebar-toggle-btn {
background: none;
border: none;
color: #5e72e4;
cursor: pointer;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0.5rem;
margin-left: -1rem;
transition: margin-left 0.3s ease;
}
/* .sidebar-collapsed .sidebar-toggle-btn {
margin-left: -1rem;
} */
.sidebar-toggle-btn:hover {
color: #233dd2;
}
/* Pro Sidebar Custom Styles */
.ps-menu-button {
padding: 0.75rem 2rem !important;
}
.ps-menu-button:hover {
background-color: #f6f9fc !important;
}
.ps-menu-button.ps-active {
background-color: #5e72e4 !important;
color: white !important;
}
.ps-submenu-content {
background-color: #f8f9fe !important;
}
.ps-menu-icon {
font-size: 1.1rem !important;
width: 35px !important;
min-width: 35px !important;
margin-right: 0.5rem !important;
}
/* Adjust main content margin when sidebar is expanded/collapsed */
.main-content {
margin-left: 250px;
transition: margin-left 0.3s ease;
}
.main-content.sidebar-collapsed-main {
margin-left: 50px;
}

View File

@@ -0,0 +1,140 @@
import { useState, useEffect } from "react";
import { Link, useLocation } from "react-router-dom";
import PropTypes from "prop-types";
import { Sidebar as ProSidebar, Menu, MenuItem, SubMenu } from "react-pro-sidebar";
import { fetchMenuItems } from "../../APIServices/MenuAPI";
import routes from "routes.js";
import "../Sidebar/Sidebar.css";
const Sidebar = (props) => {
const [menuItems, setMenuItems] = useState([]);
const [collapsed, setCollapsed] = useState(false);
const [error, setError] = useState("");
const location = useLocation();
useEffect(() => {
loadMenuItems();
}, []);
const loadMenuItems = async () => {
try {
const respdata = await fetchMenuItems();
const data = respdata.data;
if (Array.isArray(data)) {
const dynamicRoutes = mapMenuToRoutes(data);
setMenuItems(dynamicRoutes);
} else if (data && typeof data === "object") {
const dynamicRoutes = mapMenuToRoutes([data]);
setMenuItems(dynamicRoutes);
} else {
console.error("Invalid menu data format:", data);
setError("Invalid menu data format.");
}
} catch (err) {
console.error("Error fetching menu items:", err);
setError(err.message || "Failed to fetch menu items.");
}
};
const mapMenuToRoutes = (menuArray) => {
if (!Array.isArray(menuArray)) {
console.error('Expected an array for menuArray, received:', menuArray);
return [];
}
return menuArray.map(menu => ({
path: menu.path || '#',
name: menu.name || menu.menuName || '',
icon: menu.icon || 'bi bi-grid',
submenu: Array.isArray(menu.submenu) ? mapMenuToRoutes(menu.submenu) : []
}));
};
const toggleSidebar = () => {
setCollapsed(!collapsed);
if (props.onSidebarToggle) {
props.onSidebarToggle(!collapsed);
}
};
const renderMenuItems = () => {
const allRoutes = [...routes, ...menuItems];
return allRoutes.map((route, key) => {
if (route.submenu && route.submenu.length > 0) {
return (
<SubMenu
key={key}
label={route.name}
icon={<i className={route.icon} />}
>
{route.submenu.map((submenu, subKey) => (
<MenuItem
key={`${key}-${subKey}`}
component={<Link to={submenu.path} />}
icon={<i className={submenu.icon || "bi bi-grid"} />}
>
{submenu.name}
</MenuItem>
))}
</SubMenu>
);
}
return (
<MenuItem
key={key}
component={<Link to={route.path} />}
icon={<i className={route.icon || "bi bi-grid"} />}
>
{route.name}
</MenuItem>
);
});
};
const { logo } = props;
return (
<div className="sidebar-wrapper">
<ProSidebar
collapsed={collapsed}
className="app-sidebar"
backgroundColor="white"
width="220px"
collapsedWidth="30px"
>
<div className="sidebar-header">
{/* {logo && (
<Link to={logo.innerLink} className="logo-container">
<img alt={logo.imgAlt} className="navbar-brand-img" src={logo.imgSrc} />
</Link>
)} */}
<button
className="sidebar-toggle-btn"
type="button"
onClick={toggleSidebar}
title={collapsed ? "Expand sidebar" : "Collapse sidebar"}
>
<i className={`bi ${collapsed ? "bi-chevron-right" : "bi-chevron-left"}`} />
</button>
</div>
<Menu>
{renderMenuItems()}
</Menu>
</ProSidebar>
</div>
);
};
Sidebar.defaultProps = {
logo: {},
};
Sidebar.propTypes = {
logo: PropTypes.object,
onSidebarToggle: PropTypes.func,
};
export default Sidebar;

View File

@@ -0,0 +1,74 @@
import React from 'react';
import { Modal, Button } from 'react-bootstrap';
import { FaTimes } from 'react-icons/fa';
/**
* A reusable confirmation modal component
* @param {Object} props - Component props
* @param {boolean} props.show - Controls modal visibility
* @param {Function} props.onHide - Function to call when modal is closed
* @param {Function} props.onConfirm - Function to call when action is confirmed
* @param {string} props.title - Modal title
* @param {string} props.message - Confirmation message
* @param {string} props.confirmLabel - Label for the confirm button
* @param {string} props.cancelLabel - Label for the cancel button
* @param {string} props.variant - Bootstrap color variant for the confirm button
*/
const ConfirmModal = ({
show,
onHide,
onConfirm,
title = "Confirm Action",
message = "Are you sure you want to proceed?",
confirmLabel = "Confirm",
cancelLabel = "Cancel",
variant = "danger"
}) => {
return (
<Modal show={show} onHide={onHide} centered>
<Modal.Header>
<Modal.Title style={{ color: "#0E6591" }}>
{title}
</Modal.Title>
<div
onClick={onHide}
style={{
cursor: "pointer",
color: "#0E6591",
fontSize: "1.5rem",
position: "absolute",
right: "15px",
top: "15px",
}}
aria-label="Close"
>
<FaTimes />
</div>
</Modal.Header>
<Modal.Body>
<p>{message}</p>
</Modal.Body>
<Modal.Footer className="justify-content-between">
<Button
variant="outline-secondary"
onClick={onHide}
className="px-4"
>
{cancelLabel}
</Button>
<Button
variant={variant}
onClick={() => {
onConfirm();
onHide();
}}
className="px-4"
>
{confirmLabel}
</Button>
</Modal.Footer>
</Modal>
);
};
export default ConfirmModal;