This commit is contained in:
string 2025-06-04 15:09:28 +05:30
parent 509d01a4e7
commit 703f1256ff
49 changed files with 9665 additions and 7387 deletions

7619
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,11 +2,15 @@
"name": "log", "name": "log",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.3", "@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@mui/icons-material": "^5.15.20", "@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@mui/styles": "^5.16.4", "@mui/styles": "^5.16.4",
@ -17,23 +21,19 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.6.7", "axios": "^1.6.7",
"lucide-react": "^0.511.0",
"mdb-react-ui-kit": "^7.1.0", "mdb-react-ui-kit": "^7.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-barcode": "^1.5.3", "react-barcode": "^1.5.3",
"react-data-grid": "^7.0.0-beta.44", "react-data-grid": "^7.0.0-beta.44",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0", "react-google-recaptcha": "^3.1.0",
"react-icons": "^5.2.1",
"react-qr-code": "^2.0.14", "react-qr-code": "^2.0.14",
"react-router-dom": "^6.21.3", "react-router-dom": "^6.21.3",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
"react-app", "react-app",

View File

@ -1,8 +1,8 @@
// postcss.config.js // postcss.config.js
module.exports = { module.exports = {
plugins: { plugins: {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
}; };

View File

@ -46,3 +46,4 @@
/* .login-container input[type="checkbox"] { /* .login-container input[type="checkbox"] {
margin-right: 5px; margin-right: 5px;
} */ } */

View File

@ -1,7 +1,6 @@
import React from "react"; import React from "react";
import { Routes, Route } from "react-router-dom"; import { Routes, Route } from "react-router-dom";
import { BrowserRouter as Router } from 'react-router-dom';
import Login from "./components/Login/Login"; import Login from "./components/Login/Login";
import Dashboard from "./components/Dashboard/dashboard"; import Dashboard from "./components/Dashboard/dashboard";
import UserMaintance from "./components/Dashboard/UserMaintance"; import UserMaintance from "./components/Dashboard/UserMaintance";
@ -12,35 +11,28 @@ import DynamicTable from "./components/Dashboard/Dynamictable";
import Form from "./components/Dashboard/Form"; import Form from "./components/Dashboard/Form";
import ForgotPassword from "./components/Login/ForgotPassword"; import ForgotPassword from "./components/Login/ForgotPassword";
import CreateAccount from "./components/Login/CreateAccount"; import CreateAccount from "./components/Login/CreateAccount";
import Apitest from "./components/Dashboard/Test/Apitest"; import DashboardBuilder from "./components/Dashboard/DashboardBuilder";
const App = () => { const App = () => {
return ( return (
<Routes> <div>
<Route path="/" element={<Login />} /> <Router>
<Route path="/Dashboard" element={<Dashboard />} /> <Routes>
<Route path="/UserGroupMaintance" element={<UserGroupMaintance />} /> <Route path="/" element={<Login />} />
<Route path="/Dashboard/UserMaintance" element={<UserMaintance />} /> <Route path="/Dashboard" element={<Dashboard />} />
<Route path="/CodeExtension" element={<CodeExtension />} /> <Route path="/UserGroupMaintance" element={<UserGroupMaintance />} />
<Route <Route path="/Dashboard/UserMaintance" element={<UserMaintance />} />
path="/Dashboard/DashboardBuilder" <Route path="/CodeExtension" element={<CodeExtension />} />
element={<dashboardBuilder />} <Route path="/Dashboard/DashboardBuilder" element={<DashboardBuilder />} />
/> <Route path="/Extension" element={<Extension />} />
<Route path="/Extension" element={<Extension />} /> <Route path="/Dynamictable" element={<DynamicTable />} />
<Route path="/Dynamictable" element={<DynamicTable />} /> <Route path="/Form" element={<Form />} />
<Route path="/Form" element={<Form />} /> <Route path="/ForgotPassword" element={<ForgotPassword />} />
<Route path="/ForgotPassword" element={<ForgotPassword />} /> <Route path="/CreateAccount" element={<CreateAccount />} />
<Route path="/CreateAccount" element={<CreateAccount />} /> </Routes>
<Route path="/Test" element={<Apitest />} /> </Router>
</div>
{/* buildercomponents */}
</Routes>
); );
}; };
export default App; export default App;

View File

@ -1,26 +1,26 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
class ErrorBoundary extends Component { class ErrorBoundary extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { hasError: false }; this.state = { hasError: false };
} }
static getDerivedStateFromError(error) { static getDerivedStateFromError(error) {
return { hasError: true }; return { hasError: true };
} }
componentDidCatch(error, errorInfo) { componentDidCatch(error, errorInfo) {
console.error("Error Boundary Caught an Error", error, errorInfo); console.error("Error Boundary Caught an Error", error, errorInfo);
} }
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
return <h1>Something went wrong.</h1>; return <h1>Something went wrong.</h1>;
} }
return this.props.children; return this.props.children;
} }
} }
export default ErrorBoundary; export default ErrorBoundary;

View File

@ -1,197 +0,0 @@
import React, { useState, useEffect } from "react";
import { Button, Checkbox, Container, FormControlLabel, Modal, Table, TextField, Typography } from "@mui/material";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit, faTrashAlt, faPlus } from "@fortawesome/free-solid-svg-icons";
const api = process.env.REACT_APP_API_BASE_URL;
function AccessTypeManagement() {
const [accessTypes, setAccessTypes] = useState([]);
const [showAddEditModal, setShowAddEditModal] = useState(false);
const [currentAccessType, setCurrentAccessType] = useState({
typeId: "",
typeName: "",
description: "",
isActive: false
});
const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10);
const [visibleColumns, setVisibleColumns] = useState({
typeId: true,
typeName: true,
description: true,
isActive: true,
actions: true
});
useEffect(() => {
const token = localStorage.getItem("token")
const apiUrl = `${api}/api/getAllAccessTypes`;
const fetchAccessTypes = 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();
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 } = event.target;
setCurrentAccessType(prev => ({
...prev,
[name]: name === "isActive" ? checked : value
}));
};
const handleSubmit = (event) => {
event.preventDefault();
if (isEditing) {
setAccessTypes(accessTypes.map(type =>
type.typeId === currentAccessType.typeId ? currentAccessType : type
));
} else {
const newTypeId = `ID${accessTypes.length + 1}`;
setAccessTypes([...accessTypes, { ...currentAccessType, typeId: newTypeId }]);
}
setShowAddEditModal(false);
};
const openModal = (type = { typeId: "", typeName: "", description: "", isActive: false }) => {
setIsEditing(!!type.typeId);
setCurrentAccessType(type);
setShowAddEditModal(true);
};
const handleDelete = (typeId) => {
setAccessTypes(accessTypes.filter(type => type.typeId !== typeId));
};
return (
<Container className="mt-5">
<div style={{ display: "flex", justifyContent: "flex-end", marginBottom: "1rem" }}>
<Button onClick={() => openModal()} variant="contained" startIcon={<FontAwesomeIcon icon={faPlus} />}>
ADD
</Button>
</div>
<div className="table-responsive">
<Table striped bordered hover>
<thead>
<tr>
{Object.entries(visibleColumns).map(([key, visible]) =>
visible ? <th key={key}>{key.charAt(0).toUpperCase() + key.slice(1)}</th> : null
)}
</tr>
</thead>
<tbody>
{accessTypes.slice(0, recordsPerPage).map((type, index) => (
<tr key={index}>
{Object.entries(visibleColumns).map(([key, visible]) =>
visible ? (
<td key={key}>
{key === "actions" ? (
<>
<Button variant="light" size="small" onClick={() => openModal(type)}>
<FontAwesomeIcon icon={faEdit} />
</Button>
<Button variant="light" size="small" onClick={() => handleDelete(type.typeId)}>
<FontAwesomeIcon icon={faTrashAlt} />
</Button>
</>
) : (
key === "isActive" ? (
<FormControlLabel
control={<Checkbox checked={type[key]} onChange={handleInputChange} name={key} />}
label=""
/>
) : (
type[key]
)
)}
</td>
) : null
)}
</tr>
))}
</tbody>
</Table>
</div>
<div style={{ display: "flex", justifyContent: "space-between", marginTop: "1rem" }}>
<div>
<Typography variant="body1">Manage Columns</Typography>
{Object.keys(visibleColumns).map((key) => (
<FormControlLabel
key={key}
control={<Checkbox checked={visibleColumns[key]} onChange={() => toggleColumn(key)} />}
label={key.charAt(0).toUpperCase() + key.slice(1)}
/>
))}
</div>
<div>
<Typography variant="body1">Records Per Page</Typography>
{[10, 20, 30, 50].map((number) => (
<Button key={number} onClick={() => setRecordsPerPage(number)} variant="outlined">
{number}
</Button>
))}
</div>
</div>
<Modal open={showAddEditModal} onClose={() => setShowAddEditModal(false)}>
<div style={{ padding: "1rem", backgroundColor: "white", borderRadius: "8px", maxWidth: "400px", margin: "auto" }}>
<Typography variant="h6" gutterBottom>{isEditing ? "Edit Access Type" : "Add Access Type"}</Typography>
<form onSubmit={handleSubmit}>
<TextField
fullWidth
label="Type Name"
name="typeName"
value={currentAccessType.typeName}
onChange={handleInputChange}
required
style={{ marginBottom: "1rem" }}
/>
<TextField
fullWidth
label="Description"
name="description"
value={currentAccessType.description}
onChange={handleInputChange}
style={{ marginBottom: "1rem" }}
/>
<FormControlLabel
control={<Checkbox checked={currentAccessType.isActive} onChange={handleInputChange} name="isActive" />}
label="Active?"
style={{ marginBottom: "1rem" }}
/>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<Button variant="outlined" onClick={() => setShowAddEditModal(false)} style={{ marginRight: "1rem" }}>Close</Button>
<Button variant="contained" type="submit">{isEditing ? "Update" : "Add"}</Button>
</div>
</form>
</div>
</Modal>
</Container>
);
}
export default AccessTypeManagement;

View File

@ -1,137 +1,138 @@
import React, { useState, useEffect, useRef } from "react";
import { Box, Button } from "@mui/material"; import React, { useState, useEffect, useRef } from "react";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { Box, Button } from "@mui/material";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
const api = process.env.REACT_APP_API_BASE_URL; const api = process.env.REACT_APP_API_BASE_URL;
function CustomToolbar({ apiRef, handleModal }) { function CustomToolbar({ apiRef, handleModal }) {
const handleGoToPage1 = () => { const handleGoToPage1 = () => {
if (apiRef.current) { if (apiRef.current) {
apiRef.current.setPage(1); apiRef.current.setPage(1);
} }
}; };
return ( return (
<GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> <GridToolbarContainer className="flex justify-between p-2 bg-gray-200">
<Button <Button
onClick={handleGoToPage1} onClick={handleGoToPage1}
className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600"
> >
Go to page 1 Go to page 1
</Button> </Button>
<Button <Button
onClick={handleModal} onClick={handleModal}
className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600" className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600"
> >
Add item Add item
</Button> </Button>
</GridToolbarContainer> </GridToolbarContainer>
); );
} }
function ApiRegistery() { function ApiRegistery() {
const [menuItems, setMenuItems] = useState([]); const [menuItems, setMenuItems] = useState([]);
const [selectedMenuItem, setSelectedMenuItem] = useState(null); const [selectedMenuItem, setSelectedMenuItem] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false); // eslint-disable-next-line
const apiRef = useRef(null); const [isModalOpen, setIsModalOpen] = useState(false);
const apiRef = useRef(null);
useEffect(() => {
const fetchData = async () => { useEffect(() => {
const token = localStorage.getItem("token"); // Get token from local storage const fetchData = async () => {
try { const token = localStorage.getItem("token"); // Get token from local storage
const response = await fetch( try {
`${api}/Api_registery_header/Api_registery_header`, const response = await fetch(
{ `${api}/Api_registery_header/Api_registery_header`,
headers: { {
Authorization: `Bearer ${token}`, headers: {
}, Authorization: `Bearer ${token}`,
} },
); }
const data = await response.json(); );
setMenuItems(data); const data = await response.json();
} catch (error) { setMenuItems(data);
console.error("Error fetching data:", error); } catch (error) {
} console.error("Error fetching data:", error);
}; }
};
fetchData();
}, []); fetchData();
}, []);
const handleThreeDotsClick = (menuItemId) => {
setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); const handleThreeDotsClick = (menuItemId) => {
}; setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
};
const columns = [
{ const columns = [
field: "id", {
headerName: "ID", field: "id",
width: 300, headerName: "ID",
headerClassName: "custom-header", width: 300,
cellClassName: "custom-cell", headerClassName: "custom-header",
}, cellClassName: "custom-cell",
{ },
field: "table_name", {
headerName: "Table Name", field: "table_name",
width: 350, headerName: "Table Name",
headerClassName: "custom-header", width: 350,
cellClassName: "custom-cell", headerClassName: "custom-header",
}, cellClassName: "custom-cell",
{ },
field: "actions", {
headerName: "Actions", field: "actions",
width: 150, headerName: "Actions",
renderCell: ({ row }) => ( width: 150,
<div className="relative"> renderCell: ({ row }) => (
<div <div className="relative">
className="cursor-pointer" <div
onClick={() => handleThreeDotsClick(row.id)} className="cursor-pointer"
> onClick={() => handleThreeDotsClick(row.id)}
<FontAwesomeIcon icon={faEllipsisV} /> >
</div> <BsThreeDotsVertical /> {/* Using react-icons */}
{selectedMenuItem === row.id && ( </div>
<div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl"> {selectedMenuItem === row.id && (
<button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> <div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl">
Edit <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left">
</button> Edit
<button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> </button>
Delete <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left">
</button> Delete
</div> </button>
)} </div>
</div> )}
), </div>
}, ),
]; },
];
return (
<div className="flex justify-center mt-5"> return (
<Box className="w-full max-w-7xl"> <div className="flex justify-center mt-5">
<div className="bg-white p-4 rounded shadow-md"> <Box className="w-full max-w-7xl">
<h1 className="text-2xl font-bold mb-4 text-white bg-gray-400 p-3"> <div className="bg-white p-4 rounded shadow-md">
API Registry <h1 className="text-2xl font-bold mb-4 text-white bg-gray-400 p-3">
</h1> API Registry
<DataGrid </h1>
rows={menuItems} <DataGrid
columns={columns} rows={menuItems}
components={{ columns={columns}
Toolbar: () => ( components={{
<CustomToolbar Toolbar: () => (
apiRef={apiRef} <CustomToolbar
handleModal={() => setIsModalOpen(true)} apiRef={apiRef}
/> handleModal={() => setIsModalOpen(true)}
), />
}} ),
pageSize={10} }}
onGridReady={(gridApi) => { pageSize={10}
apiRef.current = gridApi; onGridReady={(gridApi) => {
}} apiRef.current = gridApi;
/> }}
</div> />
</Box> </div>
</div> </Box>
); </div>
} );
}
export default ApiRegistery;
export default ApiRegistery;

View File

@ -1,64 +1,64 @@
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.modal { .modal {
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
} }
.modal-content { .modal-content {
margin-top: 20px; margin-top: 20px;
} }
.close { .close {
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 10px; right: 10px;
cursor: pointer; cursor: pointer;
font-size: 20px; font-size: 20px;
} }
.close:hover { .close:hover {
color: red; color: red;
} }
.popup { .popup {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.popup-content { .popup-content {
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
width: 400px; /* Adjust width as needed */ width: 400px; /* Adjust width as needed */
} }
.close { .close {
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 10px; right: 10px;
cursor: pointer; cursor: pointer;
font-size: 20px; font-size: 20px;
} }
.close:hover { .close:hover {
color: red; color: red;
} }

View File

@ -1,302 +1,301 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect } from "react";
import { import {
Box, Box,
Button, Button,
Modal, Modal,
TextField, TextField,
Typography, Typography,
FormControl, FormControl,
FormControlLabel, FormControlLabel,
Checkbox, Checkbox,
Radio, Radio,
RadioGroup, RadioGroup,
Autocomplete, Autocomplete,
} from "@mui/material"; } from "@mui/material";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FaEllipsisV } from "react-icons/fa"; // Importing react-icons instead of Font Awesome
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive";
import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; import { Link } from "react-router-dom";
import { Link } from "react-router-dom"; import Extension from "./Extension";
import Extension from "./Extension";
function CustomToolbar({ handleModal }) {
function CustomToolbar({ handleModal }) { return (
return ( <GridToolbarContainer className="flex justify-between p-2 bg-gray-200">
<GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> <Button
<Button className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600"
className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" onClick={handleModal}
onClick={handleModal} >
> +
+ </Button>
</Button> </GridToolbarContainer>
</GridToolbarContainer> );
); }
}
function CodeExtension() {
function CodeExtension() { const [menuItems, setMenuItems] = useState([]);
const [menuItems, setMenuItems] = useState([]); const [selectedMenuItem, setSelectedMenuItem] = useState(null);
const [selectedMenuItem, setSelectedMenuItem] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false); const [formData, setFormData] = useState({
const [formData, setFormData] = useState({ name: "",
name: "", email: "",
email: "", testing: "",
testing: "", dataType: "",
dataType: "", });
});
useEffect(() => {
useEffect(() => { const fetchData = async () => {
const fetchData = async () => { const token = localStorage.getItem("authToken"); // Get token from local storage
const token = localStorage.getItem("token"); // Get token from local storage try {
try { const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/api/extension`, {
const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/api/extension`, { headers: {
headers: { Authorization: `Bearer ${token}`,
Authorization: `Bearer ${token}`, },
}, });
}); const data = await response.json();
const data = await response.json(); setMenuItems(data);
setMenuItems(data); } catch (error) {
} catch (error) { console.error("Error fetching data:", error);
console.error("Error fetching data:", error); }
} };
};
fetchData();
fetchData(); }, []);
}, []);
const handleThreeDotsClick = (menuItemId) => {
const handleThreeDotsClick = (menuItemId) => { setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); };
};
const handleModalOpen = () => {
const handleModalOpen = () => { setIsModalOpen(true);
setIsModalOpen(true); };
};
const handleModalClose = () => {
const handleModalClose = () => { setIsModalOpen(false);
setIsModalOpen(false); setFormData({
setFormData({ name: "",
name: "", email: "",
email: "", testing: "",
testing: "", dataType: "",
dataType: "", });
}); };
};
const handleChange = (e) => {
const handleChange = (e) => { const { name, value } = e.target;
const { name, value } = e.target; setFormData({ ...formData, [name]: value });
setFormData({ ...formData, [name]: value }); };
};
const handleFormSubmit = (submittedDataType) => {
const handleFormSubmit = (submittedDataType) => { setFormData({ ...formData, dataType: submittedDataType });
setFormData({ ...formData, dataType: submittedDataType }); handleModalOpen();
handleModalOpen(); };
};
const columns = [
const columns = [ { field: "goto", headerName: "Goto", width: 200 },
{ field: "goto", headerName: "Goto", width: 200 }, { field: "field_name", headerName: "Field Name", width: 250 },
{ field: "field_name", headerName: "Field Name", width: 250 }, { field: "mapping", headerName: "Mapping", width: 200 },
{ field: "mapping", headerName: "Mapping", width: 200 }, { field: "data_type", headerName: "Data Type", width: 200 },
{ field: "data_type", headerName: "Data Type", width: 200 }, {
{ field: "actions",
field: "actions", headerName: "Actions",
headerName: "Actions", width: 150,
width: 150, renderCell: ({ row }) => (
renderCell: ({ row }) => ( <div className="relative">
<div className="relative"> <div
<div className="cursor-pointer"
className="cursor-pointer" onClick={() => handleThreeDotsClick(row.id)}
onClick={() => handleThreeDotsClick(row.id)} >
> <FaEllipsisV /> {/* Using react-icons instead of Font Awesome */}
<FontAwesomeIcon icon={faEllipsisV} /> </div>
</div> {selectedMenuItem === row.id && (
{selectedMenuItem === row.id && ( <div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl">
<div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl"> {/* Implement your actions buttons here */}
{/* Implement your actions buttons here */} </div>
</div> )}
)} </div>
</div> ),
), },
}, ];
];
const renderInputField = () => {
const renderInputField = () => { switch (formData.dataType) {
switch (formData.dataType) { case "date":
case "date": return (
return ( <TextField
<TextField label="Date"
label="Date" name="date"
name="date" type="date"
type="date" value={formData.date}
value={formData.date} onChange={handleChange}
onChange={handleChange} fullWidth
fullWidth className="mt-2"
className="mt-2" />
/> );
); case "textfield":
case "textfield": return (
return ( <TextField
<TextField label="Text Field"
label="Text Field" name="textfield"
name="textfield" value={formData.textfield}
value={formData.textfield} onChange={handleChange}
onChange={handleChange} fullWidth
fullWidth className="mt-2"
className="mt-2" />
/> );
); case "longtext":
case "longtext": return (
return ( <TextField
<TextField label="Long Text"
label="Long Text" name="longtext"
name="longtext" value={formData.longtext}
value={formData.longtext} onChange={handleChange}
onChange={handleChange} multiline
multiline rows={4}
rows={4} fullWidth
fullWidth className="mt-2"
className="mt-2" />
/> );
); case "checkbox":
case "checkbox": return (
return ( <FormControlLabel
<FormControlLabel className="mt-2"
className="mt-2" control={
control={ <Checkbox
<Checkbox checked={formData.checkbox || false}
checked={formData.checkbox || false} onChange={(e) =>
onChange={(e) => setFormData({ ...formData, checkbox: e.target.checked })
setFormData({ ...formData, checkbox: e.target.checked }) }
} />
/> }
} label="Checkbox"
label="Checkbox" />
/> );
); case "radiobutton":
case "radiobutton": return (
return ( <FormControl component="fieldset" className="mt-2">
<FormControl component="fieldset" className="mt-2"> <RadioGroup
<RadioGroup name="radiobutton"
name="radiobutton" value={formData.radiobutton || ""}
value={formData.radiobutton || ""} onChange={(e) =>
onChange={(e) => setFormData({ ...formData, radiobutton: e.target.value })
setFormData({ ...formData, radiobutton: e.target.value }) }
} >
> <FormControlLabel
<FormControlLabel value="option1"
value="option1" control={<Radio />}
control={<Radio />} label="Option 1"
label="Option 1" />
/> <FormControlLabel
<FormControlLabel value="option2"
value="option2" control={<Radio />}
control={<Radio />} label="Option 2"
label="Option 2" />
/> </RadioGroup>
</RadioGroup> </FormControl>
</FormControl> );
); case "autocomplete":
case "autocomplete": return (
return ( <Autocomplete
<Autocomplete options={["Option 1", "Option 2", "Option 3"]}
options={["Option 1", "Option 2", "Option 3"]} renderInput={(params) => (
renderInput={(params) => ( <TextField {...params} label="Autocomplete" />
<TextField {...params} label="Autocomplete" /> )}
)} value={formData.autocomplete || ""}
value={formData.autocomplete || ""} onChange={(e, newValue) =>
onChange={(e, newValue) => setFormData({ ...formData, autocomplete: newValue })
setFormData({ ...formData, autocomplete: newValue }) }
} fullWidth
fullWidth className="mt-2"
className="mt-2" />
/> );
); default:
default: return null;
return null; }
} };
};
return (
return ( <>
<> <Box className="fixed top-0 left-0 w-full z-10 bg-white shadow">
<Box className="fixed top-0 left-0 w-full z-10 bg-white shadow"> {/* Your header content here */}
{/* Your header content here */} </Box>
</Box> <Box className="flex justify-center items-center min-h-screen bg-gray-100 py-4">
<Box className="flex justify-center items-center min-h-screen bg-gray-100 py-4"> <Box className="w-full max-w-6xl bg-white p-4 rounded shadow-md">
<Box className="w-full max-w-6xl bg-white p-4 rounded shadow-md"> <Typography
<Typography variant="h4"
variant="h4" className="text-center mb-4 text-3xl text-white bg-gray-400 p-3"
className="text-center mb-4 text-3xl text-white bg-gray-400 p-3" >
> Token Registry
Token Registry </Typography>
</Typography> <div className="bg-gray-50 p-2 rounded shadow-inner">
<div className="bg-gray-50 p-2 rounded shadow-inner"> <DataGrid
<DataGrid rows={menuItems}
rows={menuItems} columns={columns}
columns={columns} pageSize={10}
pageSize={10} components={{
components={{ Toolbar: () => <CustomToolbar handleModal={handleModalOpen} />,
Toolbar: () => <CustomToolbar handleModal={handleModalOpen} />, }}
}} className="data-grid"
className="data-grid" />
/> </div>
</div> <Modal open={isModalOpen} onClose={handleModalClose} centered>
<Modal open={isModalOpen} onClose={handleModalClose} centered> <Box className="w-full max-w-lg bg-white p-4 rounded shadow-md fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<Box className="w-full max-w-lg bg-white p-4 rounded shadow-md fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <Extension onSubmit={handleFormSubmit} />
<Extension onSubmit={handleFormSubmit} /> <Typography variant="h5" className="flex items-center mb-4">
<Typography variant="h5" className="flex items-center mb-4"> <Link to="/Extension">
<Link to="/Extension"> <AirplanemodeActiveIcon className="mr-2" />
<AirplanemodeActiveIcon className="mr-2" /> </Link>
</Link> Add Item
Add Item </Typography>
</Typography> <form
<form onSubmit={(e) => {
onSubmit={(e) => { e.preventDefault();
e.preventDefault(); handleFormSubmit(formData.dataType);
handleFormSubmit(formData.dataType); }}
}} >
> <div className="mb-2">
<div className="mb-2"> <TextField
<TextField label="Name"
label="Name" name="name"
name="name" value={formData.name}
value={formData.name} onChange={handleChange}
onChange={handleChange} fullWidth
fullWidth />
/> </div>
</div> <div className="mb-2">
<div className="mb-2"> <TextField
<TextField label="Email"
label="Email" name="email"
name="email" value={formData.email}
value={formData.email} onChange={handleChange}
onChange={handleChange} fullWidth
fullWidth />
/> </div>
</div> <div className="mb-2">
<div className="mb-2"> <TextField
<TextField label="Testing"
label="Testing" name="testing"
name="testing" value={formData.testing}
value={formData.testing} onChange={handleChange}
onChange={handleChange} fullWidth
fullWidth />
/> </div>
</div> {renderInputField()}
{renderInputField()} <div className="mt-4">
<div className="mt-4"> <Button
<Button type="submit"
type="submit" variant="contained"
variant="contained" color="primary"
color="primary" fullWidth
fullWidth >
> Submit
Submit </Button>
</Button> </div>
</div> </form>
</form> </Box>
</Box> </Modal>
</Modal> </Box>
</Box> </Box>
</Box> </>
</> );
); }
}
export default CodeExtension;
export default CodeExtension;

View File

@ -1,161 +1,161 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import axios from "axios"; import axios from "axios";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { import {
Button, Button,
IconButton, IconButton,
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
TableContainer, TableContainer,
TableHead, TableHead,
TableRow, TableRow,
Paper, Paper,
Typography, Typography,
Box, Box,
} from "@mui/material"; } from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import BuildIcon from "@mui/icons-material/Build"; import BuildIcon from "@mui/icons-material/Build";
import AddIcon from "@mui/icons-material/Add"; import AddIcon from "@mui/icons-material/Add";
// Define the API base URL using the environment variable // Define the API base URL using the environment variable
const api = process.env.REACT_APP_API_BASE_URL; const api = process.env.REACT_APP_API_BASE_URL;
const DynamicTable = () => { const DynamicTable = () => {
const [forms, setForms] = useState([]); const [forms, setForms] = useState([]);
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
if (location.state && location.state.formData) { if (location.state && location.state.formData) {
setForms((prevForms) => [...prevForms, location.state.formData]); setForms((prevForms) => [...prevForms, location.state.formData]);
} else { } else {
fetchForms(); fetchForms();
} }
}, [location.state]); }, [location.state]);
const fetchForms = async () => { const fetchForms = async () => {
const token = localStorage.getItem("token"); // Get token from local storage const token = localStorage.getItem("authToken"); // Get token from local storage
try { try {
const response = await axios.get(`${api}/api/form_setup`, { const response = await axios.get(`${api}/api/form_setup`, {
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
if (Array.isArray(response.data)) { if (Array.isArray(response.data)) {
setForms(response.data); setForms(response.data);
} else { } else {
console.error("Unexpected response format:", response.data); console.error("Unexpected response format:", response.data);
setForms([]); setForms([]);
} }
} catch (error) { } catch (error) {
console.error("Error fetching data:", error); console.error("Error fetching data:", error);
setForms([]); setForms([]);
} }
}; };
const handleDelete = async (id) => { const handleDelete = async (id) => {
const token = localStorage.getItem("token"); // Get token from local storage const token = localStorage.getItem("authToken"); // Get token from local storage
try { try {
await axios.delete(`${api}/api/form_setup/${id}`, { await axios.delete(`${api}/api/form_setup/${id}`, {
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
fetchForms(); fetchForms();
} catch (error) { } catch (error) {
console.error("Error deleting form:", error); console.error("Error deleting form:", error);
} }
}; };
const handleBuild = async (id) => { const handleBuild = async (id) => {
const token = localStorage.getItem("token"); // Get token from local storage const token = localStorage.getItem("authToken"); // Get token from local storage
try { try {
await axios.post( await axios.post(
`${api}/api/dynamic_form_build`, `${api}/api/dynamic_form_build`,
{ id }, { id },
{ {
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
} }
); );
} catch (error) { } catch (error) {
console.error("Error building form:", error); console.error("Error building form:", error);
} }
}; };
const handleAdd = () => { const handleAdd = () => {
navigate("/form"); navigate("/form");
}; };
return ( return (
<Box className="p-5 bg-gray-100 min-h-screen"> <Box className="p-5 bg-gray-100 min-h-screen">
<Typography <Typography
variant="h4" variant="h4"
gutterBottom gutterBottom
className="text-center text-white bg-gray-700 text-3xl p-3 mb-5 rounded" className="text-center text-white bg-gray-700 text-3xl p-3 mb-5 rounded"
> >
Dynamic Form Dynamic Form
</Typography> </Typography>
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
startIcon={<AddIcon />} startIcon={<AddIcon />}
onClick={handleAdd} onClick={handleAdd}
className="mb-5 bg-blue-500 hover:bg-blue-600" className="mb-5 bg-blue-500 hover:bg-blue-600"
> >
Add Add
</Button> </Button>
<TableContainer component={Paper} className="overflow-x-auto"> <TableContainer component={Paper} className="overflow-x-auto">
<Table> <Table>
<TableHead className="bg-gray-300 text-black"> <TableHead className="bg-gray-300 text-black">
<TableRow> <TableRow>
<TableCell>Go To</TableCell> <TableCell>Go To</TableCell>
<TableCell>Form Name</TableCell> <TableCell>Form Name</TableCell>
<TableCell>Form Description</TableCell> <TableCell>Form Description</TableCell>
<TableCell>Related To</TableCell> <TableCell>Related To</TableCell>
<TableCell>Page Event</TableCell> <TableCell>Page Event</TableCell>
<TableCell>Button Caption</TableCell> <TableCell>Button Caption</TableCell>
<TableCell>Go To Form</TableCell> <TableCell>Go To Form</TableCell>
<TableCell>Action</TableCell> <TableCell>Action</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{forms.map((form, index) => ( {forms.map((form, index) => (
<TableRow key={index}> <TableRow key={index}>
<TableCell> <TableCell>
<Button <Button
variant="outlined" variant="outlined"
startIcon={<BuildIcon />} startIcon={<BuildIcon />}
onClick={() => handleBuild(form.id)} onClick={() => handleBuild(form.id)}
className="border-blue-500 text-blue-500 hover:bg-blue-100" className="border-blue-500 text-blue-500 hover:bg-blue-100"
> >
Build Build
</Button> </Button>
</TableCell> </TableCell>
<TableCell>{form.formName}</TableCell> <TableCell>{form.formName}</TableCell>
<TableCell>{form.formDescription}</TableCell> <TableCell>{form.formDescription}</TableCell>
<TableCell>{form.relatedTo}</TableCell> <TableCell>{form.relatedTo}</TableCell>
<TableCell>{form.pageEvent}</TableCell> <TableCell>{form.pageEvent}</TableCell>
<TableCell>{form.buttonCaption}</TableCell> <TableCell>{form.buttonCaption}</TableCell>
<TableCell>{form.goToForm}</TableCell> <TableCell>{form.goToForm}</TableCell>
<TableCell> <TableCell>
<IconButton <IconButton
color="secondary" color="secondary"
onClick={() => handleDelete(form.id)} onClick={() => handleDelete(form.id)}
className="text-red-500 hover:text-red-700" className="text-red-500 hover:text-red-700"
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
</Box> </Box>
); );
}; };
export default DynamicTable; export default DynamicTable;

View File

@ -1,93 +1,93 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { TextField, Button, Typography, Select, MenuItem } from '@mui/material'; import { TextField, Button, Typography, Select, MenuItem } from '@mui/material';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
const Extension = ({ onSubmit }) => { const Extension = ({ onSubmit }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
type: '', type: '',
fieldName: '', fieldName: '',
mapping: '', mapping: '',
dataType: '' dataType: ''
}); });
const navigate = useNavigate(); const navigate = useNavigate();
const handleChange = (e) => { const handleChange = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData({ ...formData, [name]: value }); setFormData({ ...formData, [name]: value });
}; };
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
if (typeof onSubmit === 'function') { if (typeof onSubmit === 'function') {
onSubmit(formData.dataType); onSubmit(formData.dataType);
} }
// Navigate to CodeExtension page with the form data // Navigate to CodeExtension page with the form data
navigate('/Codeextension', { state: { formData } }); navigate('/CodeExtension', { state: { formData } });
}; };
return ( return (
<div style={{ maxWidth: '600px', margin: '0 auto' }}> <div style={{ maxWidth: '600px', margin: '0 auto' }}>
<Typography variant="h4" gutterBottom>Add Item</Typography> <Typography variant="h4" gutterBottom>Add Item</Typography>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div> <div>
<Select <Select
label="Type" label="Type"
name="type" name="type"
value={formData.type} value={formData.type}
onChange={handleChange} onChange={handleChange}
fullWidth fullWidth
required required
> >
<MenuItem value="Header">Header</MenuItem> <MenuItem value="Header">Header</MenuItem>
<MenuItem value="Line">Line</MenuItem> <MenuItem value="Line">Line</MenuItem>
</Select> </Select>
</div> </div>
<div> <div>
<TextField <TextField
label="Field Name" label="Field Name"
name="fieldName" name="fieldName"
value={formData.fieldName} value={formData.fieldName}
onChange={handleChange} onChange={handleChange}
fullWidth fullWidth
required required
/> />
</div> </div>
<div> <div>
<Select <Select
label="Mapping" label="Mapping"
name="mapping" name="mapping"
value={formData.mapping} value={formData.mapping}
onChange={handleChange} onChange={handleChange}
fullWidth fullWidth
required required
> >
{[...Array(15).keys()].map(num => ( {[...Array(15).keys()].map(num => (
<MenuItem key={num + 1} value={`EXTN${num + 1}`}>{`EXTN${num + 1}`}</MenuItem> <MenuItem key={num + 1} value={`EXTN${num + 1}`}>{`EXTN${num + 1}`}</MenuItem>
))} ))}
</Select> </Select>
</div> </div>
<div> <div>
<Select <Select
label="Data Type" label="Data Type"
name="dataType" name="dataType"
value={formData.dataType} value={formData.dataType}
onChange={handleChange} onChange={handleChange}
fullWidth fullWidth
required required
> >
<MenuItem value="textfield">Textfield</MenuItem> <MenuItem value="textfield">Textfield</MenuItem>
<MenuItem value="longtext">Longtext</MenuItem> <MenuItem value="longtext">Longtext</MenuItem>
<MenuItem value="date">Date</MenuItem> <MenuItem value="date">Date</MenuItem>
<MenuItem value="checkbox">Checkbox</MenuItem> <MenuItem value="checkbox">Checkbox</MenuItem>
<MenuItem value="radiobutton">Radiobutton</MenuItem> <MenuItem value="radiobutton">Radiobutton</MenuItem>
<MenuItem value="autocomplete">Autocomplete</MenuItem> <MenuItem value="autocomplete">Autocomplete</MenuItem>
</Select> </Select>
</div> </div>
<Button type="submit" variant="contained" sx={{ mt: 2 }}>Submit</Button> <Button type="submit" variant="contained" sx={{ mt: 2 }}>Submit</Button>
</form> </form>
</div> </div>
); );
}; };
export default Extension; export default Extension;

View File

@ -1,217 +1,217 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
function DynamicForm() { function Form() {
const [components, setComponents] = useState([ const [components, setComponents] = useState([
{ {
id: uuidv4(), id: uuidv4(),
label: "", label: "",
type: "", type: "",
mapping: "", mapping: "",
readonly: false, readonly: false,
values: "", values: "",
}, },
]); ]);
const [formDetails, setFormDetails] = useState({ const [formDetails, setFormDetails] = useState({
formName: "", formName: "",
formDescription: "", formDescription: "",
relatedTo: "", relatedTo: "",
pageEvent: "", pageEvent: "",
buttonName: "", buttonName: "",
}); });
const navigate = useNavigate(); const navigate = useNavigate();
const handleFormChange = (e) => { const handleFormChange = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
setFormDetails({ ...formDetails, [name]: value }); setFormDetails({ ...formDetails, [name]: value });
}; };
const handleComponentChange = (index, field, value) => { const handleComponentChange = (index, field, value) => {
const updatedComponents = components.map((component, i) => const updatedComponents = components.map((component, i) =>
i === index ? { ...component, [field]: value } : component i === index ? { ...component, [field]: value } : component
); );
setComponents(updatedComponents); setComponents(updatedComponents);
}; };
const addComponent = () => { const addComponent = () => {
setComponents([ setComponents([
...components, ...components,
{ {
id: uuidv4(), id: uuidv4(),
label: "", label: "",
type: "", type: "",
mapping: "", mapping: "",
readonly: false, readonly: false,
values: "", values: "",
}, },
]); ]);
}; };
const removeComponent = (index) => { const removeComponent = (index) => {
setComponents(components.filter((_, i) => i !== index)); setComponents(components.filter((_, i) => i !== index));
}; };
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
const formData = { ...formDetails, components }; const formData = { ...formDetails, components };
navigate("/Dynamictable", { state: { formData } }); // Navigate to DynamicTable with formData navigate("/Dynamictable", { state: { formData } }); // Navigate to DynamicTable with formData
}; };
return ( return (
<div className="p-5 min-h-screen"> <div className="p-5 min-h-screen">
<h1 className="text-3xl font-bold text-center text-white bg-gray-400 mb-8 p-3"> <h1 className="text-3xl font-bold text-center text-white bg-gray-400 mb-8 p-3">
Dynamic Form Setup Dynamic Form Setup
</h1> </h1>
<form onSubmit={handleSubmit} className="space-y-6"> <form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="flex flex-col"> <div className="flex flex-col">
<label className="text-gray-700">Form Name</label> <label className="text-gray-700">Form Name</label>
<input <input
type="text" type="text"
name="formName" name="formName"
value={formDetails.formName} value={formDetails.formName}
onChange={handleFormChange} onChange={handleFormChange}
className="mt-1 p-2 border rounded" className="mt-1 p-2 border rounded"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<label className="text-gray-700">Form Description</label> <label className="text-gray-700">Form Description</label>
<input <input
type="text" type="text"
name="formDescription" name="formDescription"
value={formDetails.formDescription} value={formDetails.formDescription}
onChange={handleFormChange} onChange={handleFormChange}
className="mt-1 p-2 border rounded" className="mt-1 p-2 border rounded"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<label className="text-gray-700">Related To</label> <label className="text-gray-700">Related To</label>
<select <select
name="relatedTo" name="relatedTo"
value={formDetails.relatedTo} value={formDetails.relatedTo}
onChange={handleFormChange} onChange={handleFormChange}
className="mt-1 p-2 border rounded" className="mt-1 p-2 border rounded"
> >
<option value=""> <option value="">
<em>None</em> <em>None</em>
</option> </option>
<option value="Menu">Menu</option> <option value="Menu">Menu</option>
<option value="Related to">Related to</option> <option value="Related to">Related to</option>
</select> </select>
</div> </div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="flex flex-col"> <div className="flex flex-col">
<label className="text-gray-700">Page Event</label> <label className="text-gray-700">Page Event</label>
<select <select
name="pageEvent" name="pageEvent"
value={formDetails.pageEvent} value={formDetails.pageEvent}
onChange={handleFormChange} onChange={handleFormChange}
className="mt-1 p-2 border rounded" className="mt-1 p-2 border rounded"
> >
<option value="Onclick">Onclick</option> <option value="Onclick">Onclick</option>
<option value="Onblur">Onblur</option> <option value="Onblur">Onblur</option>
</select> </select>
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<label className="text-gray-700">Button Name</label> <label className="text-gray-700">Button Name</label>
<input <input
type="text" type="text"
name="buttonName" name="buttonName"
value={formDetails.buttonName} value={formDetails.buttonName}
onChange={handleFormChange} onChange={handleFormChange}
className="mt-1 p-2 border rounded" className="mt-1 p-2 border rounded"
/> />
</div> </div>
</div> </div>
<h2 className="text-2xl font-semibold text-gray-700 mt-8"> <h2 className="text-2xl font-semibold text-gray-700 mt-8">
Component Details Component Details
</h2> </h2>
{components.map((component, index) => ( {components.map((component, index) => (
<div <div
key={component.id} key={component.id}
className="grid grid-cols-1 md:grid-cols-5 gap-4 items-center mt-4" className="grid grid-cols-1 md:grid-cols-5 gap-4 items-center mt-4"
> >
<input <input
type="text" type="text"
placeholder="Label" placeholder="Label"
value={component.label} value={component.label}
onChange={(e) => onChange={(e) =>
handleComponentChange(index, "label", e.target.value) handleComponentChange(index, "label", e.target.value)
} }
className="p-2 border rounded col-span-1" className="p-2 border rounded col-span-1"
/> />
<select <select
value={component.type} value={component.type}
onChange={(e) => onChange={(e) =>
handleComponentChange(index, "type", e.target.value) handleComponentChange(index, "type", e.target.value)
} }
className="p-2 border rounded col-span-1" className="p-2 border rounded col-span-1"
> >
<option value=""> <option value="">
<em>None</em> <em>None</em>
</option> </option>
<option value="textfield">TextField</option> <option value="textfield">TextField</option>
<option value="checkbox">Checkbox</option> <option value="checkbox">Checkbox</option>
<option value="select">Select</option> <option value="select">Select</option>
</select> </select>
<input <input
type="text" type="text"
placeholder="Mapping" placeholder="Mapping"
value={component.mapping} value={component.mapping}
onChange={(e) => onChange={(e) =>
handleComponentChange(index, "mapping", e.target.value) handleComponentChange(index, "mapping", e.target.value)
} }
className="p-2 border rounded col-span-1" className="p-2 border rounded col-span-1"
/> />
<div className="flex items-center"> <div className="flex items-center">
<input <input
type="checkbox" type="checkbox"
checked={component.readonly} checked={component.readonly}
onChange={(e) => onChange={(e) =>
handleComponentChange(index, "readonly", e.target.checked) handleComponentChange(index, "readonly", e.target.checked)
} }
className="mr-2" className="mr-2"
/> />
<label>Readonly</label> <label>Readonly</label>
</div> </div>
<input <input
type="text" type="text"
placeholder="Enter Values" placeholder="Enter Values"
value={component.values} value={component.values}
onChange={(e) => onChange={(e) =>
handleComponentChange(index, "values", e.target.value) handleComponentChange(index, "values", e.target.value)
} }
className="p-2 border rounded col-span-1" className="p-2 border rounded col-span-1"
/> />
<button <button
type="button" type="button"
onClick={() => removeComponent(index)} onClick={() => removeComponent(index)}
className="text-red-500 hover:text-red-700" className="text-red-500 hover:text-red-700"
> >
{/* <DeleteIcon /> */} {/* <DeleteIcon /> */}
</button> </button>
</div> </div>
))} ))}
<div className="flex justify-between mt-6"> <div className="flex justify-between mt-6">
<button <button
type="button" type="button"
onClick={addComponent} onClick={addComponent}
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
> >
Add Component Add Component
</button> </button>
<button <button
type="submit" type="submit"
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600" className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
> >
Submit Submit
</button> </button>
</div> </div>
</form> </form>
</div> </div>
); );
} }
export default DynamicForm; export default Form;

View File

@ -1,50 +1,50 @@
/* HomePage.css */ /* HomePage.css */
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100vh; height: 100vh;
} }
.heading { .heading {
font-size: 24px; font-size: 24px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.card-container { .card-container {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-wrap: wrap; /* Allow cards to wrap to the next line */ flex-wrap: wrap; /* Allow cards to wrap to the next line */
margin-top: 20px; margin-top: 20px;
} }
.card { .card {
background-color: #9ee2f5; background-color: #9ee2f5;
padding: 40px; padding: 40px;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 30%; /* Adjust card width for larger screens */ width: 30%; /* Adjust card width for larger screens */
margin: 10px; margin: 10px;
} }
.chart-container { .chart-container {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin-top: 20px; margin-top: 20px;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.card { .card {
width: 45%; /* Adjust card width for screens up to 768px */ width: 45%; /* Adjust card width for screens up to 768px */
} }
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.card { .card {
width: 100%; /* Make cards occupy full width on screens up to 480px */ width: 100%; /* Make cards occupy full width on screens up to 480px */
} }
} }

View File

@ -1,37 +1,113 @@
// HomePage.js // HomePage.js
import React from 'react'; import React from 'react';
import { BarChart } from '@mui/x-charts/BarChart'; // Import BarChart component import { FaUsers, FaCog, FaChartBar, FaShieldAlt } from 'react-icons/fa';
const Card = ({ index }) => { const StatCard = ({ icon: Icon, title, value, color }) => (
return ( <div className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-200">
<div className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center"> <div className="flex items-center space-x-4">
<h3 className="text-lg font-semibold mb-2">INDEX {index}</h3> <div className={`p-3 rounded-lg ${color}`}>
<p className="text-gray-600">{index}.</p> <Icon className="w-6 h-6 text-white" />
</div> </div>
); <div>
}; <h3 className="text-gray-500 text-sm font-medium">{title}</h3>
<p className="text-2xl font-bold text-gray-800">{value}</p>
const HomePage = () => { </div>
return ( </div>
<div className="min-h-screen flex flex-col items-center justify-center bg-gray-100 p-4"> </div>
<h2 className="text-3xl font-semibold text-gray-700 mb-6">Welcome to the Dashboard!</h2> );
<div className="flex flex-wrap justify-center">
<Card index={1} /> const HomePage = () => {
<Card index={2} /> return (
<Card index={3} /> <div className="space-y-6">
</div> <div className="flex items-center justify-between">
<div className="w-full mt-8 flex justify-center"> <h1 className="text-3xl font-bold text-gray-800">Welcome Back!</h1>
{/* Add BarChart component */} <div className="text-sm text-gray-500">Last updated: {new Date().toLocaleDateString()}</div>
<BarChart </div>
xAxis={[{ scaleType: 'band', data: ['group A', 'group B', 'group C'] }]}
series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]} {/* Stats Grid */}
width={700} <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
height={400} <StatCard
/> icon={FaUsers}
</div> title="Total Users"
</div> value="1,234"
); color="bg-gradient-to-r from-purple-500 to-indigo-500"
}; />
<StatCard
export default HomePage; icon={FaCog}
title="Active Systems"
value="12"
color="bg-gradient-to-r from-blue-500 to-cyan-500"
/>
<StatCard
icon={FaChartBar}
title="Reports Generated"
value="456"
color="bg-gradient-to-r from-indigo-500 to-purple-500"
/>
<StatCard
icon={FaShieldAlt}
title="Security Score"
value="98%"
color="bg-gradient-to-r from-green-500 to-emerald-500"
/>
</div>
{/* Recent Activity */}
<div className="bg-white rounded-xl shadow-lg p-6">
<h2 className="text-xl font-semibold text-gray-800 mb-4">Recent Activity</h2>
<div className="space-y-4">
{[1, 2, 3].map((item) => (
<div key={item} className="flex items-center space-x-4 p-4 rounded-lg hover:bg-gray-50 transition-colors">
<div className="w-2 h-2 rounded-full bg-purple-500"></div>
<div className="flex-1">
<p className="text-gray-800">System update completed</p>
<p className="text-sm text-gray-500">2 hours ago</p>
</div>
</div>
))}
</div>
</div>
{/* Quick Actions */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-gradient-to-br from-purple-500 to-indigo-600 rounded-xl shadow-lg p-6 text-white">
<h2 className="text-xl font-semibold mb-4">Quick Actions</h2>
<div className="space-y-3">
<button className="w-full bg-white/10 hover:bg-white/20 text-white font-medium py-2 px-4 rounded-lg transition-colors">
Generate Report
</button>
<button className="w-full bg-white/10 hover:bg-white/20 text-white font-medium py-2 px-4 rounded-lg transition-colors">
Add New User
</button>
<button className="w-full bg-white/10 hover:bg-white/20 text-white font-medium py-2 px-4 rounded-lg transition-colors">
System Settings
</button>
</div>
</div>
<div className="bg-gradient-to-br from-blue-500 to-cyan-600 rounded-xl shadow-lg p-6 text-white">
<h2 className="text-xl font-semibold mb-4">System Status</h2>
<div className="space-y-4">
<div className="flex items-center justify-between">
<span>CPU Usage</span>
<span className="font-medium">45%</span>
</div>
<div className="w-full bg-white/20 rounded-full h-2">
<div className="bg-white h-2 rounded-full" style={{ width: '45%' }}></div>
</div>
<div className="flex items-center justify-between">
<span>Memory Usage</span>
<span className="font-medium">62%</span>
</div>
<div className="w-full bg-white/20 rounded-full h-2">
<div className="bg-white h-2 rounded-full" style={{ width: '62%' }}></div>
</div>
</div>
</div>
</div>
</div>
);
};
export default HomePage;

View File

@ -1,7 +1,7 @@
@import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
.custom-header, .custom-cell { .custom-header, .custom-cell {
font-family: 'PT Serif", serif '; font-family: 'PT Serif", serif ';
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,162 +1,161 @@
import React, { useState, useEffect, useRef } from 'react'; // eslint-disable-next-line
import { Box, Button } from '@mui/material'; import React, { useState, useEffect, useRef } from 'react';
import { DataGrid, GridToolbarContainer } from '@mui/x-data-grid'; import { Box, Button } from '@mui/material';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { DataGrid, GridToolbarContainer } from '@mui/x-data-grid';
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'; import { BsThreeDotsVertical } from 'react-icons/bs'; // Importing react-icons
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) {
const handleGoToPage1 = () => { const handleGoToPage1 = () => {
if (apiRef.current) { if (apiRef.current) {
apiRef.current.setPage(1); apiRef.current.setPage(1);
} }
}; };
return ( return (
<GridToolbarContainer> <GridToolbarContainer>
<Button onClick={handleGoToPage1}>Go to page 1</Button> <Button onClick={handleGoToPage1}>Go to page 1</Button>
<Button onClick={handleModal}>+</Button> <Button onClick={handleModal}>+</Button>
</GridToolbarContainer> </GridToolbarContainer>
); );
} }
function MenuAccessControl() { function MenuAccessControl() {
const [menuItems, setMenuItems] = useState([]); const [menuItems, setMenuItems] = useState([]);
const [selectedMenuItem, setSelectedMenuItem] = useState(null); const [selectedMenuItem, setSelectedMenuItem] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false);
const [newMenuItem, setNewMenuItem] = useState({ // const [newMenuItem, setNewMenuItem] = useState({
// Define initial values for the new menu item in the modal // No: '',
No: '', // menuItemname: '',
menuItemname: '', // view: '',
view: '', // create: '',
create: '', // edit: '',
edit: '', // delete: '',
delete: '', // query: '',
query: '', // export: [],
export: [], // });
}); const apiRef = useRef(null);
const apiRef = useRef(null);
useEffect(() => {
useEffect(() => { const fetchData = async () => {
const fetchData = async () => { try {
try { const response = await fetch('');
const response = await fetch(''); const data = await response.json();
const data = await response.json();
// Set unique IDs for each menu item
// Set unique IDs for each menu item const menuItemsWithIds = data.map((menuItem, index) => ({ ...menuItem, id: index + 1 }));
const menuItemsWithIds = data.map((menuItem, index) => ({ ...menuItem, id: index + 1 })); setMenuItems(menuItemsWithIds);
setMenuItems(menuItemsWithIds); } catch (error) {
} catch (error) { console.error('Error fetching data:', error);
console.error('Error fetching data:', error); }
} };
};
fetchData();
fetchData(); }, []);
}, []);
const handleThreeDotsClick = (menuItemId) => {
const handleThreeDotsClick = (menuItemId) => { setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); };
};
const handleDelete = (menuItemId) => {
const handleDelete = (menuItemId) => { // Implement delete logic here
// Implement delete logic here console.log('Delete menu item with ID:', menuItemId);
console.log('Delete menu item with ID:', menuItemId); };
};
const handleUpdate = (menuItem) => {
const handleUpdate = (menuItem) => { // Implement update logic here
// Implement update logic here console.log('Update menu item:', menuItem);
console.log('Update menu item:', menuItem); };
};
const handleModal = () => {
const handleModal = () => { setIsModalOpen(true);
setIsModalOpen(true); };
};
// const handleModalSave = () => {
const handleModalSave = () => { // // Implement save logic for adding a new menu item here
// Implement save logic for adding a new menu item here // setIsModalOpen(false);
setIsModalOpen(false); // };
};
// const handleUpdateSave = () => {
const handleUpdateSave = () => { // // Implement save logic for updating a menu item here
// Implement save logic for updating a menu item here // setIsUpdateModalOpen(false);
setIsUpdateModalOpen(false); // };
};
const columns = [
const columns = [ { field: 'No', headerName: 'No', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' },
{ field: 'No', headerName: 'No', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' }, { field: 'menuItemname', headerName: 'Menu Item Name', width: 200,headerClassName: 'custom-header', cellClassName: 'custom-cell' },
{ field: 'menuItemname', headerName: 'Menu Item Name', width: 200,headerClassName: 'custom-header', cellClassName: 'custom-cell' }, { field: 'view', headerName: 'View', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' },
{ field: 'view', headerName: 'View', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' }, { field: 'create', headerName: 'Create', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' },
{ field: 'create', headerName: 'Create', width: 100,headerClassName: 'custom-header', cellClassName: 'custom-cell' }, { field: 'edit', headerName: 'Edit', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'},
{ field: 'edit', headerName: 'Edit', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'}, { field: 'delete', headerName: 'Delete', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'},
{ field: 'delete', headerName: 'Delete', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'}, { field: 'query', headerName: 'Query', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'},
{ field: 'query', headerName: 'Query', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'}, { field: 'export', headerName: 'Export', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'},
{ field: 'export', headerName: 'Export', width: 100 ,headerClassName: 'custom-header', cellClassName: 'custom-cell'}, {
{ field: 'actions',
field: 'actions', headerName: 'Actions',
headerName: 'Actions', width: 100,
width: 100, renderCell: ({ row }) => (
renderCell: ({ row }) => ( <div>
<div> <div className="three-dots" onClick={() => handleThreeDotsClick(row.menuItemId)}>
<div className="three-dots" onClick={() => handleThreeDotsClick(row.menuItemId)}> <BsThreeDotsVertical /> {/* Using react-icons */}
<FontAwesomeIcon icon={faEllipsisV} /> </div>
</div> {selectedMenuItem === row.menuItemId && (
{selectedMenuItem === row.menuItemId && ( <div className="popover">
<div className="popover"> <button onClick={() => handleDelete(row.menuItemId)}>Delete</button>
<button onClick={() => handleDelete(row.menuItemId)}>Delete</button> <button onClick={() => handleUpdate(row)}>Update</button>
<button onClick={() => handleUpdate(row)}>Update</button> </div>
</div> )}
)} </div>
</div> ),
), },
}, ];
];
return (
return ( <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4"> <div className="w-full mb-3 md:w-3/4 lg:w-2/3 xl:w-1/2">
<div className="w-full mb-3 md:w-3/4 lg:w-2/3 xl:w-1/2"> <div className='text-center text-3xl text-white bg-gray-400 p-2 rounded-lg'>Menu Access Control</div>
<div className='text-center text-3xl text-white bg-gray-400 p-2 rounded-lg'>Menu Access Control</div> </div>
</div> <Box className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2 bg-white border border-gray-200 shadow-lg rounded-lg" sx={{ height: 500, width: '100%' }} >
<Box className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2 bg-white border border-gray-200 shadow-lg rounded-lg" sx={{ height: 500, width: '100%' }} > <DataGrid
<DataGrid rows={menuItems}
rows={menuItems} columns={columns}
columns={columns} components={{
components={{ Toolbar: () => (
Toolbar: () => ( <CustomToolbar
<CustomToolbar apiRef={apiRef}
apiRef={apiRef} handleThreeDotsClick={handleThreeDotsClick}
handleThreeDotsClick={handleThreeDotsClick} handleModal={handleModal}
handleModal={handleModal} />
/> ),
), }}
}} pageSize={10}
pageSize={10} onGridReady={(gridApi) => {
onGridReady={(gridApi) => { apiRef.current = gridApi;
apiRef.current = gridApi; }}
}} className="bg-gray-400"
className="bg-gray-400" />
/> </Box>
</Box> {/* Your modals and other components */}
{/* Your modals and other components */} {isModalOpen && (
{isModalOpen && ( <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4">
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4"> <div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full"> <h2 className="text-xl font-bold mb-4">Add New Menu Item</h2>
<h2 className="text-xl font-bold mb-4">Add New Menu Item</h2> {/* Modal content here */}
{/* Modal content here */} <Button onClick={() => setIsModalOpen(false)}>Close</Button>
<Button onClick={() => setIsModalOpen(false)}>Close</Button> </div>
</div> </div>
</div> )}
)} {isUpdateModalOpen && (
{isUpdateModalOpen && ( <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4">
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4"> <div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full"> <h2 className="text-xl font-bold mb-4">Update Menu Item</h2>
<h2 className="text-xl font-bold mb-4">Update Menu Item</h2> {/* Modal content here */}
{/* Modal content here */} <Button onClick={() => setIsUpdateModalOpen(false)}>Close</Button>
<Button onClick={() => setIsUpdateModalOpen(false)}>Close</Button> </div>
</div> </div>
</div> )}
)} </div>
</div> );
); }
}
export default MenuAccessControl;
export default MenuAccessControl;

View File

@ -1,7 +1,7 @@
@import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
.custom-header, .custom-cell { .custom-header, .custom-cell {
font-family: 'PT Serif", serif '; font-family: 'PT Serif", serif ';
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,180 +1,178 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import { Box, Button } from "@mui/material"; import { Box, Button } from "@mui/material";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; import "./MenuMaintance.css";
import "./MenuMaintance.css";
const api = process.env.REACT_APP_API_BASE_URL;
const api = process.env.REACT_APP_API_BASE_URL;
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) {
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { const handleGoToPage1 = () => {
const handleGoToPage1 = () => { if (apiRef.current) {
if (apiRef.current) { apiRef.current.setPage(1);
apiRef.current.setPage(1); }
} };
};
return (
return ( <GridToolbarContainer>
<GridToolbarContainer> <Button onClick={handleGoToPage1}>Go to page 1</Button>
<Button onClick={handleGoToPage1}>Go to page 1</Button> <Button onClick={handleModal}>+</Button>
<Button onClick={handleModal}>+</Button> </GridToolbarContainer>
</GridToolbarContainer> );
); }
}
function MenuMaintenance() {
function MenuMaintenance() { const [menuItems, setMenuItems] = useState([]);
const [menuItems, setMenuItems] = useState([]); const [selectedMenuItem, setSelectedMenuItem] = useState(null);
const [selectedMenuItem, setSelectedMenuItem] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false); const apiRef = useRef(null);
const apiRef = useRef(null);
useEffect(() => {
useEffect(() => { const fetchData = async () => {
const fetchData = async () => { const token = localStorage.getItem("authToken");
const token = localStorage.getItem("token"); try {
try { const response = await fetch(`${api}/api1/submenu1`, {
const response = await fetch(`${api}/api1/submenu1`, { headers: {
headers: { Authorization: `Bearer ${token}`,
Authorization: `Bearer ${token}`, },
}, });
});
if (!response.ok) {
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`);
throw new Error(`HTTP error! status: ${response.status}`); }
}
const data = await response.json();
const data = await response.json(); // Flatten the nested subMenus array
// Flatten the nested subMenus array const flattenedData = data.flatMap((menuItem) => [
const flattenedData = data.flatMap((menuItem) => [ menuItem,
menuItem, ...menuItem.subMenus,
...menuItem.subMenus, ]);
]); // Set unique IDs for each menu item
// Set unique IDs for each menu item const menuItemsWithIds = flattenedData.map((menuItem, index) => ({
const menuItemsWithIds = flattenedData.map((menuItem, index) => ({ ...menuItem,
...menuItem, id: index + 1,
id: index + 1, }));
})); setMenuItems(menuItemsWithIds);
setMenuItems(menuItemsWithIds); } catch (error) {
} catch (error) { console.error("Error fetching data:", error);
console.error("Error fetching data:", error); }
} };
};
fetchData();
fetchData(); }, []);
}, []);
const handleThreeDotsClick = (menuItemId) => {
const handleThreeDotsClick = (menuItemId) => { setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); };
};
const columns = [
const columns = [ {
{ field: "menuItemId",
field: "menuItemId", headerName: "Menu Item ID",
headerName: "Menu Item ID", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "menuItemDesc",
field: "menuItemDesc", headerName: "Menu Item Description",
headerName: "Menu Item Description", width: 250,
width: 250, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "moduleName",
field: "moduleName", headerName: "Module Name",
headerName: "Module Name", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "main_menu_action_name",
field: "main_menu_action_name", headerName: "Main Menu Action",
headerName: "Main Menu Action", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "main_menu_icon_name",
field: "main_menu_icon_name", headerName: "Main Menu Icon",
headerName: "Main Menu Icon", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "actions",
field: "actions", headerName: "Actions",
headerName: "Actions", width: 150,
width: 150, renderCell: ({ row }) => (
renderCell: ({ row }) => ( <div className="relative">
<div className="relative"> <div
<div className="three-dots"
className="three-dots" onClick={() => handleThreeDotsClick(row.menuItemId)}
onClick={() => handleThreeDotsClick(row.menuItemId)} >
> <BsThreeDotsVertical
<FontAwesomeIcon className="cursor-pointer text-gray-800 hover:text-gray-600"
icon={faEllipsisV} />
className="cursor-pointer text-gray-800 hover:text-gray-600" </div>
/> {selectedMenuItem === row.menuItemId && (
</div> <div className="absolute bg-white border border-gray-200 shadow-lg p-4 mt-2 rounded-lg">
{selectedMenuItem === row.menuItemId && ( {/* Implement your actions buttons here */}
<div className="absolute bg-white border border-gray-200 shadow-lg p-4 mt-2 rounded-lg"> </div>
{/* Implement your actions buttons here */} )}
</div> </div>
)} ),
</div> },
), ];
},
]; return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
return ( <div className="text-3xl text-center text-black mb-3 bg-slate-400">
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100"> Menu Maintenance
<div className="text-3xl text-center text-black mb-3 bg-slate-400"> </div>
Menu Maintenance <Box
</div> className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2"
<Box sx={{ height: 500, width: "100%" }}
className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2" >
sx={{ height: 500, width: "100%" }} <DataGrid
> rows={menuItems}
<DataGrid columns={columns}
rows={menuItems} components={{
columns={columns} Toolbar: () => (
components={{ <CustomToolbar
Toolbar: () => ( apiRef={apiRef}
<CustomToolbar handleThreeDotsClick={handleThreeDotsClick}
apiRef={apiRef} handleModal={() => setIsModalOpen(true)}
handleThreeDotsClick={handleThreeDotsClick} />
handleModal={() => setIsModalOpen(true)} ),
/> }}
), pageSize={10}
}} onGridReady={(gridApi) => {
pageSize={10} apiRef.current = gridApi;
onGridReady={(gridApi) => { }}
apiRef.current = gridApi; sx={{
}} "& .MuiDataGrid-columnHeaders": {
sx={{ backgroundColor: "rgba(107, 114, 128, 0.5)", // Tailwind CSS bg-gray-400 with opacity
"& .MuiDataGrid-columnHeaders": { },
backgroundColor: "rgba(107, 114, 128, 0.5)", // Tailwind CSS bg-gray-400 with opacity "& .MuiDataGrid-columnHeaderTitle": {
}, fontWeight: "bold",
"& .MuiDataGrid-columnHeaderTitle": { },
fontWeight: "bold", }}
}, className="border border-gray-200 shadow-lg rounded-lg bg-gray-400"
}} />
className=" border border-gray-200 shadow-lg rounded-lg bg-gray-400" </Box>
/> {/* Your modals and other components */}
</Box> {isModalOpen && (
{/* Your modals and other components */} <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
{isModalOpen && ( <div className="bg-white p-8 rounded-lg shadow-lg">
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"> <h2 className="text-xl font-bold mb-4">Modal Title</h2>
<div className="bg-white p-8 rounded-lg shadow-lg"> {/* Modal content here */}
<h2 className="text-xl font-bold mb-4">Modal Title</h2> <Button onClick={() => setIsModalOpen(false)}>Close</Button>
{/* Modal content here */} </div>
<Button onClick={() => setIsModalOpen(false)}>Close</Button> </div>
</div> )}
</div> </div>
)} );
</div> }
);
} export default MenuMaintenance;
export default MenuMaintenance;

View File

@ -1,101 +1,101 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import './Model.css'; import './Model.css';
const Modal = ({ setNewUser, newUser, onSave }) => { const Modal = ({ setNewUser, newUser, onSave }) => {
const [newUserState, setNewUserState] = useState(newUser); const [newUserState, setNewUserState] = useState(newUser);
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const handleSave = () => { const handleSave = () => {
const data = { ...newUserState }; const data = { ...newUserState };
onSave(data); // Pass the new data to the parent component onSave(data); // Pass the new data to the parent component
setIsModalOpen(false); // Close the modal after saving setIsModalOpen(false); // Close the modal after saving
}; };
const handleClose = () => { const handleClose = () => {
setIsModalOpen(false); setIsModalOpen(false);
}; };
const handleOpenModal = () => { const handleOpenModal = () => {
setIsModalOpen(true); setIsModalOpen(true);
}; };
return ( return (
<> <>
<button onClick={handleOpenModal}>ADD ITEM</button> <button onClick={handleOpenModal}>ADD ITEM</button>
{isModalOpen && ( {isModalOpen && (
<div className='modalWrapper'> <div className='modalWrapper'>
<div className='modal'> <div className='modal'>
<button className="closeBtn" onClick={handleClose}>X</button> <button className="closeBtn" onClick={handleClose}>X</button>
<div className="input-group"> <div className="input-group">
<label htmlFor="userId">User ID:</label> <label htmlFor="userId">User ID:</label>
<input <input
type="text" type="text"
id="userId" id="userId"
value={newUserState.userId} value={newUserState.userId}
onChange={(e) => setNewUserState({ ...newUserState, userId: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, userId: e.target.value })}
/> />
</div> </div>
<div className="input-group"> <div className="input-group">
<label htmlFor="username">Username:</label> <label htmlFor="username">Username:</label>
<input <input
type="text" type="text"
id="username" id="username"
value={newUserState.username} value={newUserState.username}
onChange={(e) => setNewUserState({ ...newUserState, username: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, username: e.target.value })}
/> />
</div> </div>
<div className="input-group"> <div className="input-group">
<label htmlFor="fullName">Full Name:</label> <label htmlFor="fullName">Full Name:</label>
<input <input
type="text" type="text"
id="fullName" id="fullName"
value={newUserState.fullName} value={newUserState.fullName}
onChange={(e) => setNewUserState({ ...newUserState, fullName: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, fullName: e.target.value })}
/> />
</div> </div>
<div className="input-group"> <div className="input-group">
<label htmlFor="email">Email:</label> <label htmlFor="email">Email:</label>
<input <input
type="text" type="text"
id="email" id="email"
value={newUserState.email} value={newUserState.email}
onChange={(e) => setNewUserState({ ...newUserState, email: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, email: e.target.value })}
/> />
</div> </div>
<div className="input-group"> <div className="input-group">
<label htmlFor="mobileNumber">Mobile Number:</label> <label htmlFor="mobileNumber">Mobile Number:</label>
<input <input
type="text" type="text"
id="mobileNumber" id="mobileNumber"
value={newUserState.mobileNumber} value={newUserState.mobileNumber}
onChange={(e) => setNewUserState({ ...newUserState, mobileNumber: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, mobileNumber: e.target.value })}
/> />
</div> </div>
<div className="input-group"> <div className="input-group">
<label htmlFor="userGroup">User Group:</label> <label htmlFor="userGroup">User Group:</label>
<input <input
type="text" type="text"
id="userGroup" id="userGroup"
value={newUserState.userGroup} value={newUserState.userGroup}
onChange={(e) => setNewUserState({ ...newUserState, userGroup: e.target.value })} onChange={(e) => setNewUserState({ ...newUserState, userGroup: e.target.value })}
/> />
</div> </div>
<button onClick={handleSave}>Save</button> <button onClick={handleSave}>Save</button>
</div> </div>
</div> </div>
)} )}
</> </>
); );
}; };
export default Modal; export default Modal;

View File

@ -1,69 +1,69 @@
.modalWrapper { .modalWrapper {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
} }
.modal { .modal {
background: white; background: white;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
width: 300px; width: 300px;
text-align: left; text-align: left;
position: relative; position: relative;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
} }
.closeBtn { .closeBtn {
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 10px; right: 10px;
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
} }
label { label {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;
color: #333; color: #333;
} }
input { input {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
margin-bottom: 16px; margin-bottom: 16px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
} }
button { button {
background-color: #4caf50; background-color: #4caf50;
color: white; color: white;
padding: 12px; padding: 12px;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
} }
.savedData { .savedData {
margin-top: 20px; margin-top: 20px;
} }
.savedData h2 { .savedData h2 {
font-size: 16px; font-size: 16px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.savedData p { .savedData p {
margin: 5px 0; margin: 5px 0;
} }

View File

@ -1,71 +1,71 @@
/* Report.css */ /* Report.css */
.app { .app {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
margin: 20px auto; /* Adjust margin to create space between cards and navbar */ margin: 20px auto; /* Adjust margin to create space between cards and navbar */
padding: 0 20px; padding: 0 20px;
max-width: 800px; max-width: 800px;
} }
h1 { h1 {
text-align: center; text-align: center;
color: #333; color: #333;
} }
.card-container { .card-container {
display: grid; display: grid;
grid-template-columns: minmax(350px, 1fr) minmax(350px, 1fr) minmax(350px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Ensure first three cards are in the same row and increase their width */ grid-template-columns: minmax(350px, 1fr) minmax(350px, 1fr) minmax(350px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Ensure first three cards are in the same row and increase their width */
gap: 20px; gap: 20px;
max-width: 100%; /* Limit the maximum width of the card container */ max-width: 100%; /* Limit the maximum width of the card container */
margin: 0 auto; /* Center the card container */ margin: 0 auto; /* Center the card container */
} }
.card { .card {
background-color: #ffffff; background-color: #ffffff;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 10px; border-radius: 10px;
padding: 30px; /* Increase padding for better spacing */ padding: 30px; /* Increase padding for better spacing */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Adjust box shadow for a more pronounced effect */ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Adjust box shadow for a more pronounced effect */
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
width: 100%; /* Make cards take up full width of their container */ width: 100%; /* Make cards take up full width of their container */
height: auto; /* Allow cards to expand vertically based on content */ height: auto; /* Allow cards to expand vertically based on content */
} }
.card:hover { .card:hover {
transform: translateY(-5px); transform: translateY(-5px);
} }
.card h2 { .card h2 {
margin-top: 0; margin-top: 0;
color: #333; color: #333;
font-size: 20px; /* Increase font size of card headings */ font-size: 20px; /* Increase font size of card headings */
} }
.card p { .card p {
margin: 10px 0; /* Increase margin for better spacing */ margin: 10px 0; /* Increase margin for better spacing */
color: #666; color: #666;
} }
@media (max-width: 1400px) { @media (max-width: 1400px) {
.card-container { .card-container {
grid-template-columns: minmax(300px, 1fr) minmax(300px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Adjust columns for smaller screens */ grid-template-columns: minmax(300px, 1fr) minmax(300px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Adjust columns for smaller screens */
} }
} }
@media (max-width: 1100px) { @media (max-width: 1100px) {
.card-container { .card-container {
grid-template-columns: minmax(250px, 1fr) repeat(auto-fill, minmax(200px, 1fr)); /* Further adjust columns for even smaller screens */ grid-template-columns: minmax(250px, 1fr) repeat(auto-fill, minmax(200px, 1fr)); /* Further adjust columns for even smaller screens */
} }
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.card-container { .card-container {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Adjust columns for smaller screens */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Adjust columns for smaller screens */
} }
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.card-container { .card-container {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* Adjust columns for smaller screens */ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* Adjust columns for smaller screens */
} }
} }

View File

@ -1,74 +1,80 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
const Card = ({ report }) => { const Card = ({ report }) => {
return ( return (
<div className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center"> <div className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center">
<h2 className="text-lg font-semibold mb-2">{report.reportName}</h2> <h2 className="text-lg font-semibold mb-2">{report.reportName}</h2>
<p className="text-gray-600 mb-2">{report.description}</p> <p className="text-gray-600 mb-2">{report.description}</p>
<p className="text-gray-600 mb-2"> <p className="text-gray-600 mb-2">
Active: {report.active ? "Yes" : "No"} Active: {report.active ? "Yes" : "No"}
</p> </p>
<p className="text-gray-600">Is SQL: {report.isSql ? "Yes" : "No"}</p> <p className="text-gray-600">Is SQL: {report.isSql ? "Yes" : "No"}</p>
</div> </div>
); );
}; };
// Define the API base URL using the environment variable // Define the API base URL using the environment variable
const api = process.env.REACT_APP_API_BASE_URL; const api = process.env.REACT_APP_API_BASE_URL;
const Report = () => { const Report = () => {
const [reports, setReports] = useState([]); const [reports, setReports] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
const token = localStorage.getItem("authToken"); const token = localStorage.getItem("authToken");
if (!token) { if (!token) {
console.error("No auth token found. Redirecting to login."); console.error("No auth token found. Redirecting to login.");
// You can redirect to the login page here if needed // You can redirect to the login page here if needed
return; return;
} }
try { try {
const response = await fetch(`${api}/Rpt_builder2/Rpt_builder2`, { const response = await fetch(`${api}/Rpt_builder2/Rpt_builder2`, {
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
if (!response.ok) { if (response.status === 401) {
throw new Error("Failed to fetch data"); console.error("Unauthorized. Redirecting to login.");
} // Redirect to the login page here if needed
return;
const data = await response.json(); }
setReports(data);
setLoading(false); if (!response.ok) {
} catch (error) { throw new Error("Failed to fetch data");
console.error("Error fetching data:", error); }
setLoading(false);
} const data = await response.json();
}; setReports(data);
setLoading(false);
fetchData(); } catch (error) {
}, []); console.error("Error fetching data:", error);
setLoading(false);
return ( }
<div className="min-h-screen bg-gray-100 p-4 flex flex-col items-center"> };
<div className="mb-6">
<h1 className="text-3xl font-semibold text-gray-700">Reports</h1> fetchData();
</div> }, []);
{loading ? (
<p className="text-gray-700">Loading...</p> return (
) : ( <div className="min-h-screen bg-gray-100 p-4 flex flex-col items-center">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"> <div className="mb-6">
{reports.map((report) => ( <h1 className="text-3xl font-semibold text-gray-700">Reports</h1>
<Card key={report.id} report={report} /> </div>
))} {loading ? (
</div> <p className="text-gray-700">Loading...</p>
)} ) : (
</div> <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
); {reports.map((report) => (
}; <Card key={report.id} report={report} />
))}
export default Report; </div>
)}
</div>
);
};
export default Report;

View File

@ -1,29 +1,29 @@
.card-list { .card-list {
display: flex; display: flex;
flex-wrap: wrap; /* Allow cards to wrap to the next line */ flex-wrap: wrap; /* Allow cards to wrap to the next line */
justify-content: center; /* Horizontally center the cards */ justify-content: center; /* Horizontally center the cards */
} }
.card { .card {
border: 1px solid black; border: 1px solid black;
padding: 10px; padding: 10px;
margin: 10px; /* Adjust margin for better spacing */ margin: 10px; /* Adjust margin for better spacing */
width: calc(33.33% - 20px); /* Adjust card width based on container width */ width: calc(33.33% - 20px); /* Adjust card width based on container width */
max-width: 200px; /* Set maximum card width */ max-width: 200px; /* Set maximum card width */
height: 150px; /* Adjust card height */ height: 150px; /* Adjust card height */
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.card { .card {
width: calc(50% - 20px); /* Two cards per row on smaller screens */ width: calc(50% - 20px); /* Two cards per row on smaller screens */
} }
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.card { .card {
width: calc(100% - 20px); /* Single card per row on mobile devices */ width: calc(100% - 20px); /* Single card per row on mobile devices */
} }
} }

View File

@ -1,80 +1,78 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FaUser, FaUsers, FaUtensils, FaLock, FaCogs, FaKey } from 'react-icons/fa';
import { faUser, faUsers, faUtensils, faLock, faCogs, faKey } from '@fortawesome/free-solid-svg-icons'; import UserMaintance from './UserMaintance';
import UserMaintance from './UserMaintance'; import UserGroupMaintance from './UserGroupMaintance/UserGroupMaintance';
import UserGroupMaintance from './UserGroupMaintance/UserGroupMaintance'; import MenuMaintance from './MenuMaintance/MenuMaintance';
import MenuMaintance from './MenuMaintance/MenuMaintance'; import MenuAccessControl from './MenuAccessControl/MenuAccessControl';
import MenuAccessControl from './MenuAccessControl/MenuAccessControl'; import SystemParameters from './SystemParameters/SystemParameters';
import SystemParameters from './SystemParameters/SystemParameters'; import ApiRegistery from './ApiRegistery/ApiRegistery';
import AccessType from './AccessType/AccessType'; import TokenRegistery from './TokenRegistery/TokenRegistery';
import ApiRegistery from './ApiRegistery/ApiRegistery'; import Codeextension from './Codeextension.js';
import TokenRegistery from './TokenRegistery/TokenRegistery'; import DynamicTable from './Dynamictable.js';
import Codeextension from './Codeextension.js';
import DynamicTable from './Dynamictable.js'; const Card = ({ title, content, icon: Icon, onClick }) => (
<div onClick={onClick} className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center">
const Card = ({ title, content, icon, onClick }) => ( <Icon className="text-4xl text-gray-800 mb-4" />
<div onClick={onClick} className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center"> <h3 className="text-lg font-semibold">{title}</h3>
<FontAwesomeIcon icon={icon} className="text-4xl text-gray-800 mb-4" /> <p className="text-gray-600">{content}</p>
<h3 className="text-lg font-semibold">{title}</h3> </div>
<p className="text-gray-600">{content}</p> );
</div>
); const CardList = () => {
const [showUserMaintance, setShowUserMaintance] = useState(false);
const CardList = () => { const [showUserGroupMaintance, setShowUserGroupMaintance] = useState(false);
const [showUserMaintance, setShowUserMaintance] = useState(false); const [showMenuMaintance, setShowMenuMaintance] = useState(false);
const [showUserGroupMaintance, setShowUserGroupMaintance] = useState(false); const [showMenuAccessControl, setShowMenuAccessControl] = useState(false);
const [showMenuMaintance, setShowMenuMaintance] = useState(false); const [showSystemParameters, setShowSystemParameters] = useState(false);
const [showMenuAccessControl, setShowMenuAccessControl] = useState(false); // const [showAccessType, setShowAccessType] = useState(false);
const [showSystemParameters, setShowSystemParameters] = useState(false); const [showApiRegistery, setShowApiRegistery] = useState(false);
const [showAccessType, setShowAccessType] = useState(false); const [showTokenRegistery, setShowTokenRegistery] = useState(false);
const [showApiRegistery, setShowApiRegistery] = useState(false); const [showCodeExtension, setShowCodeExtension] = useState(false);
const [showTokenRegistery, setShowTokenRegistery] = useState(false); const [showDynamicTable, setShowDynamicTable] = useState(false);
const [showCodeExtension, setShowCodeExtension] = useState(false);
const [showDynamicTable, setShowDynamicTable] = useState(false); const handleCardClick = (menuItemDesc) => {
setShowUserMaintance(menuItemDesc === 'User Maintance');
const handleCardClick = (menuItemDesc) => { setShowUserGroupMaintance(menuItemDesc === 'User Group Maintance');
setShowUserMaintance(menuItemDesc === 'User Maintance'); setShowMenuMaintance(menuItemDesc === 'Menu Maintance');
setShowUserGroupMaintance(menuItemDesc === 'User Group Maintance'); setShowMenuAccessControl(menuItemDesc === 'Menu Access Control');
setShowMenuMaintance(menuItemDesc === 'Menu Maintance'); setShowSystemParameters(menuItemDesc === 'System Parameters');
setShowMenuAccessControl(menuItemDesc === 'Menu Access Control'); // setShowAccessType(menuItemDesc === 'Access Type');
setShowSystemParameters(menuItemDesc === 'System Parameters'); setShowApiRegistery(menuItemDesc === 'Api Registery');
setShowAccessType(menuItemDesc === 'Access Type'); setShowTokenRegistery(menuItemDesc === 'Token Registery');
setShowApiRegistery(menuItemDesc === 'Api Registery'); setShowCodeExtension(menuItemDesc === 'Code Extension');
setShowTokenRegistery(menuItemDesc === 'Token Registery'); setShowDynamicTable(menuItemDesc === 'Dynamic Table');
setShowCodeExtension(menuItemDesc === 'Code Extension'); };
setShowDynamicTable(menuItemDesc === 'Dynamic Table');
}; return (
<>
return ( {!showUserMaintance && !showUserGroupMaintance && !showMenuMaintance && !showMenuAccessControl && !showSystemParameters && !showApiRegistery && !showTokenRegistery && !showCodeExtension && !showDynamicTable && (
<> <div className="min-h-screen flex items-center justify-center bg-gray-100 p-4">
{!showUserMaintance && !showUserGroupMaintance && !showMenuMaintance && !showMenuAccessControl && !showSystemParameters && !showAccessType && !showApiRegistery && !showTokenRegistery && !showCodeExtension && !showDynamicTable && ( <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<div className="min-h-screen flex items-center justify-center bg-gray-100 p-4"> <Card title="User Maintance" content="Manage users" icon={FaUser} onClick={() => handleCardClick('User Maintance')} />
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 gap-6"> <Card title="User Group Maintance" content="Manage user groups" icon={FaUsers} onClick={() => handleCardClick('User Group Maintance')} />
<Card title="User Maintance" content="Manage users" icon={faUser} onClick={() => handleCardClick('User Maintance')} /> <Card title="Menu Maintance" content="Manage menus" icon={FaUtensils} onClick={() => handleCardClick('Menu Maintance')} />
<Card title="User Group Maintance" content="Manage user groups" icon={faUsers} onClick={() => handleCardClick('User Group Maintance')} /> <Card title="Menu Access Control" content="Control menu access" icon={FaLock} onClick={() => handleCardClick('Menu Access Control')} />
<Card title="Menu Maintance" content="Manage menus" icon={faUtensils} onClick={() => handleCardClick('Menu Maintance')} /> <Card title="System Parameters" content="Configure system parameters" icon={FaCogs} onClick={() => handleCardClick('System Parameters')} />
<Card title="Menu Access Control" content="Control menu access" icon={faLock} onClick={() => handleCardClick('Menu Access Control')} /> {/* <Card title="Access Type" content="Manage access types" icon={FaKey} onClick={() => handleCardClick('Access Type')} /> */}
<Card title="System Parameters" content="Configure system parameters" icon={faCogs} onClick={() => handleCardClick('System Parameters')} /> <Card title="Api Registery" content="Manage APIs" icon={FaUser} onClick={() => handleCardClick('Api Registery')} />
<Card title="Access Type" content="Manage access types" icon={faKey} onClick={() => handleCardClick('Access Type')} /> <Card title="Token Registery" content="Manage tokens" icon={FaKey} onClick={() => handleCardClick('Token Registery')} />
<Card title="Api Registery" content="Manage APIs" icon={faUser} onClick={() => handleCardClick('Api Registery')} /> <Card title="Code Extension" content="Extend code functionalities" icon={FaLock} onClick={() => handleCardClick('Code Extension')} />
<Card title="Token Registery" content="Manage tokens" icon={faKey} onClick={() => handleCardClick('Token Registery')} /> <Card title="Dynamic Table" content="Dynamic data tables" icon={FaKey} onClick={() => handleCardClick('Dynamic Table')} />
<Card title="Code Extension" content="Extend code functionalities" icon={faLock} onClick={() => handleCardClick('Code Extension')} /> </div>
<Card title="Dynamic Table" content="Dynamic data tables" icon={faKey} onClick={() => handleCardClick('Dynamic Table')} /> </div>
</div> )}
</div> {showUserMaintance && <UserMaintance />}
)} {showUserGroupMaintance && <UserGroupMaintance />}
{showUserMaintance && <UserMaintance />} {showMenuMaintance && <MenuMaintance />}
{showUserGroupMaintance && <UserGroupMaintance />} {showMenuAccessControl && <MenuAccessControl />}
{showMenuMaintance && <MenuMaintance />} {showSystemParameters && <SystemParameters />}
{showMenuAccessControl && <MenuAccessControl />} {/* {showAccessType && <AccessType />} */}
{showSystemParameters && <SystemParameters />} {showApiRegistery && <ApiRegistery />}
{showAccessType && <AccessType />} {showTokenRegistery && <TokenRegistery />}
{showApiRegistery && <ApiRegistery />} {showCodeExtension && <Codeextension />}
{showTokenRegistery && <TokenRegistery />} {showDynamicTable && <DynamicTable />}
{showCodeExtension && <Codeextension />} </>
{showDynamicTable && <DynamicTable />} );
</> };
);
}; export default CardList;
export default CardList;

View File

@ -1,128 +1,128 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Button, Container, Grid, TextField } from "@mui/material"; import { Button, Container, Grid, TextField } from "@mui/material";
const SystemParameterForm = () => { const SystemParameterForm = () => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
schedulerTimer: "", schedulerTimer: "",
leaseTaxCode: "", leaseTaxCode: "",
vesselConfirmationProcessLimit: "", vesselConfirmationProcessLimit: "",
rowToDisplay: "", rowToDisplay: "",
linkToDisplay: "", linkToDisplay: "",
rowToAdd: "", rowToAdd: "",
lovRowToDisplay: "", lovRowToDisplay: "",
lovLinkToDisplay: "", lovLinkToDisplay: "",
oldServerName: "", oldServerName: "",
oldBase: "", oldBase: "",
oldAdminUser: "", oldAdminUser: "",
oldServerPort: "", oldServerPort: "",
userDefaultGroup: "", userDefaultGroup: "",
defaultDepartment: "", defaultDepartment: "",
defaultPosition: "", defaultPosition: "",
singleCharge: "", singleCharge: "",
firstDayOfWeek: "", firstDayOfWeek: "",
hourPerShift: "", hourPerShift: "",
cnBillingFrequency: "", cnBillingFrequency: "",
billingDepartmentCode: "", billingDepartmentCode: "",
basePriceList: "", basePriceList: "",
nonContainerServiceOrderAutoApprovalDeptCode: "", nonContainerServiceOrderAutoApprovalDeptCode: "",
ediMAESchedulerOnOff: "", ediMAESchedulerOnOff: "",
ediSchedulerOnOff: "", ediSchedulerOnOff: "",
companyDisplayName: "", companyDisplayName: "",
}); });
const handleInputChange = (event) => { const handleInputChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setFormData((prevState) => ({ setFormData((prevState) => ({
...prevState, ...prevState,
[name]: value, [name]: value,
})); }));
}; };
const handleFileChange = (event) => { const handleFileChange = (event) => {
setFormData((prevState) => ({ setFormData((prevState) => ({
...prevState, ...prevState,
logo: event.target.files[0], logo: event.target.files[0],
})); }));
}; };
const handleSubmit = (event) => { const handleSubmit = (event) => {
event.preventDefault(); event.preventDefault();
alert("Form submitted successfully!"); alert("Form submitted successfully!");
console.log("Form Data:", formData); console.log("Form Data:", formData);
}; };
const handleClear = () => { const handleClear = () => {
setFormData({ setFormData({
schedulerTimer: "", schedulerTimer: "",
leaseTaxCode: "", leaseTaxCode: "",
vesselConfirmationProcessLimit: "", vesselConfirmationProcessLimit: "",
rowToDisplay: "", rowToDisplay: "",
linkToDisplay: "", linkToDisplay: "",
rowToAdd: "", rowToAdd: "",
lovRowToDisplay: "", lovRowToDisplay: "",
lovLinkToDisplay: "", lovLinkToDisplay: "",
oldServerName: "", oldServerName: "",
oldBase: "", oldBase: "",
oldAdminUser: "", oldAdminUser: "",
oldServerPort: "", oldServerPort: "",
userDefaultGroup: "", userDefaultGroup: "",
defaultDepartment: "", defaultDepartment: "",
defaultPosition: "", defaultPosition: "",
singleCharge: "", singleCharge: "",
firstDayOfWeek: "", firstDayOfWeek: "",
hourPerShift: "", hourPerShift: "",
cnBillingFrequency: "", cnBillingFrequency: "",
billingDepartmentCode: "", billingDepartmentCode: "",
basePriceList: "", basePriceList: "",
nonContainerServiceOrderAutoApprovalDeptCode: "", nonContainerServiceOrderAutoApprovalDeptCode: "",
ediMAESchedulerOnOff: "", ediMAESchedulerOnOff: "",
ediSchedulerOnOff: "", ediSchedulerOnOff: "",
companyDisplayName: "", companyDisplayName: "",
}); });
}; };
return ( return (
<Container className="mt-5"> <Container className="mt-5">
<p className="bg-gray-400 text-center text-white text-3xl m-3 p-2"> <p className="bg-gray-400 text-center text-white text-3xl m-3 p-2">
System Parameters System Parameters
</p> </p>
<form onSubmit={handleSubmit} className="m-5 p-5"> <form onSubmit={handleSubmit} className="m-5 p-5">
<Grid container spacing={3}> <Grid container spacing={3}>
{Object.keys(formData).map((key, index) => ( {Object.keys(formData).map((key, index) => (
<Grid item xs={12} sm={6} key={index}> <Grid item xs={12} sm={6} key={index}>
<TextField <TextField
fullWidth fullWidth
label={key label={key
.split(/(?=[A-Z])/) .split(/(?=[A-Z])/)
.join(" ") .join(" ")
.replace(/\b\w/g, (l) => l.toUpperCase())} .replace(/\b\w/g, (l) => l.toUpperCase())}
name={key} name={key}
value={formData[key]} value={formData[key]}
onChange={handleInputChange} onChange={handleInputChange}
variant="outlined" variant="outlined"
/> />
</Grid> </Grid>
))} ))}
<Grid item xs={12}> <Grid item xs={12}>
<input type="file" onChange={handleFileChange} /> <input type="file" onChange={handleFileChange} />
</Grid> </Grid>
</Grid> </Grid>
<div style={{ textAlign: "end", marginTop: 20 }}> <div style={{ textAlign: "end", marginTop: 20 }}>
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
type="submit" type="submit"
style={{ marginRight: 10 }} style={{ marginRight: 10 }}
> >
Save Save
</Button> </Button>
<Button variant="outlined" color="primary" onClick={handleClear}> <Button variant="outlined" color="primary" onClick={handleClear}>
Clear Clear
</Button> </Button>
</div> </div>
</form> </form>
</Container> </Container>
); );
}; };
export default SystemParameterForm; export default SystemParameterForm;

View File

@ -1,427 +0,0 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Snackbar,
Alert,
Typography,
TextField,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TablePagination,
Paper,
IconButton,
InputAdornment
} from "@mui/material";
import { makeStyles } from '@mui/styles';
import SearchIcon from '@mui/icons-material/Search';
const API_URL = "http://34.198.218.30:30179/entityBuilder/Gaurav_testing";
const token = localStorage.getItem("authToken");
// Custom styles using makeStyles
const useStyles = makeStyles((theme) => ({
tableHeader: {
backgroundColor: "#000000",
color: "#ffffff",
},
searchContainer: {
display: 'flex',
alignItems: 'center',
marginBottom: theme.spacing(2),
},
searchInput: {
marginRight: theme.spacing(2),
flex: 1,
},
tableContainer: {
marginTop: theme.spacing(2),
},
dialogContent: {
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
},
formControl: {
marginBottom: theme.spacing(2),
},
button: {
margin: theme.spacing(1),
},
}));
const EntityTable = () => {
const classes = useStyles();
const [data, setData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const [newEntity, setNewEntity] = useState({
name: "",
email: "",
mobno: "",
address: "",
pincode: "",
});
const [editEntity, setEditEntity] = useState(null);
const [showEditModal, setShowEditModal] = useState(false);
const [showAddModal, setShowAddModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [deleteEntityId, setDeleteEntityId] = useState(null);
const [currentPage, setCurrentPage] = useState(0);
const [itemsPerPage] = useState(5); // Adjust this value as needed
const [searchQuery, setSearchQuery] = useState("");
const [openSnackbar, setOpenSnackbar] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState("");
const [snackbarSeverity, setSnackbarSeverity] = useState("success");
const handlePageChange = (event, newPage) => {
setCurrentPage(newPage);
};
useEffect(() => {
fetchData();
}, []);
useEffect(() => {
handleSearch();
}, [searchQuery, data]);
const fetchData = async () => {
try {
const response = await axios.get(API_URL, {
headers: { Authorization: `Bearer ${token}` },
});
setData(response.data);
} catch (error) {
console.error("Error fetching data:", error);
}
};
const handleDelete = async () => {
try {
await axios.delete(`${API_URL}/${deleteEntityId}`, {
headers: { Authorization: `Bearer ${token}` },
});
fetchData();
setSnackbarMessage("Successfully deleted!");
setSnackbarSeverity("success");
setOpenSnackbar(true);
setShowDeleteModal(false);
} catch (error) {
console.error("Error deleting data:", error);
setSnackbarMessage("Failed to delete!");
setSnackbarSeverity("error");
setOpenSnackbar(true);
}
};
const handleAdd = async () => {
try {
await axios.post(API_URL, newEntity, {
headers: { Authorization: `Bearer ${token}` },
});
fetchData();
setNewEntity({
name: "",
email: "",
mobno: "",
address: "",
pincode: "",
});
setShowAddModal(false);
setSnackbarMessage("Successfully added!");
setSnackbarSeverity("success");
setOpenSnackbar(true);
} catch (error) {
console.error("Error adding data:", error);
setSnackbarMessage("Failed to add!");
setSnackbarSeverity("error");
setOpenSnackbar(true);
}
};
const handleChange = (e) => {
const { name, value } = e.target;
setNewEntity({ ...newEntity, [name]: value });
};
const handleEditChange = (e) => {
const { name, value } = e.target;
setEditEntity({ ...editEntity, [name]: value });
};
const handleEdit = (entity) => {
setEditEntity(entity);
setShowEditModal(true);
};
const handleUpdate = async () => {
try {
await axios.put(`${API_URL}/${editEntity.id}`, editEntity, {
headers: { Authorization: `Bearer ${token}` },
});
fetchData();
setShowEditModal(false);
setSnackbarMessage("Successfully updated!");
setSnackbarSeverity("success");
setOpenSnackbar(true);
} catch (error) {
console.error("Error updating data:", error);
setSnackbarMessage("Failed to update!");
setSnackbarSeverity("error");
setOpenSnackbar(true);
}
};
const handleSearch = () => {
const filtered = data.filter(
(entity) =>
entity.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
entity.email.toLowerCase().includes(searchQuery.toLowerCase()) ||
entity.mobno.toLowerCase().includes(searchQuery.toLowerCase()) ||
entity.address.toLowerCase().includes(searchQuery.toLowerCase()) ||
entity.pincode.toLowerCase().includes(searchQuery.toLowerCase())
);
setFilteredData(filtered);
};
return (
<div className="container mt-5">
<Typography variant="h4" gutterBottom>
Entity Table
</Typography>
<div className={classes.searchContainer}>
<Button
variant="contained"
color="primary"
onClick={() => setShowAddModal(true)}
className={classes.button}
>
Add Entity
</Button>
<TextField
className={classes.searchInput}
label="Search"
variant="outlined"
size="small"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton>
<SearchIcon />
</IconButton>
</InputAdornment>
),
}}
/>
</div>
<TableContainer component={Paper} className={classes.tableContainer}>
<Table>
<TableHead>
<TableRow className={classes.tableHeader}>
<TableCell>ID</TableCell>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell>Mobile No</TableCell>
<TableCell>Address</TableCell>
<TableCell>Pincode</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredData.slice(currentPage * itemsPerPage, (currentPage + 1) * itemsPerPage).map((entity) => (
<TableRow key={entity.id}>
<TableCell>{entity.id}</TableCell>
<TableCell>{entity.name}</TableCell>
<TableCell>{entity.email}</TableCell>
<TableCell>{entity.mobno}</TableCell>
<TableCell>{entity.address}</TableCell>
<TableCell>{entity.pincode}</TableCell>
<TableCell>
<Button
variant="contained"
color="warning"
size="small"
className={classes.button}
onClick={() => handleEdit(entity)}
>
Update
</Button>
<Button
variant="contained"
color="error"
size="small"
className={classes.button}
onClick={() => {
setDeleteEntityId(entity.id);
setShowDeleteModal(true);
}}
>
Delete
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={filteredData.length}
rowsPerPage={itemsPerPage}
page={currentPage}
onPageChange={handlePageChange}
/>
<Dialog open={showEditModal} onClose={() => setShowEditModal(false)}>
<DialogTitle>Edit Entity</DialogTitle>
<DialogContent className={classes.dialogContent}>
<TextField
label="Name"
variant="outlined"
fullWidth
name="name"
value={editEntity?.name || ""}
onChange={handleEditChange}
className={classes.formControl}
/>
<TextField
label="Email"
variant="outlined"
fullWidth
name="email"
value={editEntity?.email || ""}
onChange={handleEditChange}
className={classes.formControl}
/>
<TextField
label="Mobile No"
variant="outlined"
fullWidth
name="mobno"
value={editEntity?.mobno || ""}
onChange={handleEditChange}
className={classes.formControl}
/>
<TextField
label="Address"
variant="outlined"
fullWidth
name="address"
value={editEntity?.address || ""}
onChange={handleEditChange}
className={classes.formControl}
/>
<TextField
label="Pincode"
variant="outlined"
fullWidth
name="pincode"
value={editEntity?.pincode || ""}
onChange={handleEditChange}
className={classes.formControl}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => setShowEditModal(false)} color="primary">
Cancel
</Button>
<Button onClick={handleUpdate} color="primary">
Update
</Button>
</DialogActions>
</Dialog>
<Dialog open={showAddModal} onClose={() => setShowAddModal(false)}>
<DialogTitle>Add Entity</DialogTitle>
<DialogContent className={classes.dialogContent}>
<TextField
label="Name"
variant="outlined"
fullWidth
name="name"
value={newEntity.name}
onChange={handleChange}
className={classes.formControl}
/>
<TextField
label="Email"
variant="outlined"
fullWidth
name="email"
value={newEntity.email}
onChange={handleChange}
className={classes.formControl}
/>
<TextField
label="Mobile No"
variant="outlined"
fullWidth
name="mobno"
value={newEntity.mobno}
onChange={handleChange}
className={classes.formControl}
/>
<TextField
label="Address"
variant="outlined"
fullWidth
name="address"
value={newEntity.address}
onChange={handleChange}
className={classes.formControl}
/>
<TextField
label="Pincode"
variant="outlined"
fullWidth
name="pincode"
value={newEntity.pincode}
onChange={handleChange}
className={classes.formControl}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => setShowAddModal(false)} color="primary">
Cancel
</Button>
<Button onClick={handleAdd} color="primary">
Add
</Button>
</DialogActions>
</Dialog>
<Dialog open={showDeleteModal} onClose={() => setShowDeleteModal(false)}>
<DialogTitle>Confirm Delete</DialogTitle>
<DialogContent>
<Typography>Are you sure you want to delete this entity?</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setShowDeleteModal(false)} color="primary">
Cancel
</Button>
<Button onClick={handleDelete} color="primary">
Delete
</Button>
</DialogActions>
</Dialog>
<Snackbar
open={openSnackbar}
autoHideDuration={6000}
onClose={() => setOpenSnackbar(false)}
>
<Alert onClose={() => setOpenSnackbar(false)} severity={snackbarSeverity}>
{snackbarMessage}
</Alert>
</Snackbar>
</div>
);
};
export default EntityTable;

View File

@ -1,146 +1,145 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import { Box, Button } from "@mui/material"; import { Box, Button } from "@mui/material";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons";
const api = process.env.REACT_APP_API_BASE_URL;
const api = process.env.REACT_APP_API_BASE_URL;
function CustomToolbar({ apiRef, handleModal }) {
function CustomToolbar({ apiRef, handleModal }) { const handleGoToPage1 = () => {
const handleGoToPage1 = () => { if (apiRef.current) {
if (apiRef.current) { apiRef.current.setPage(1);
apiRef.current.setPage(1); }
} };
};
return (
return ( <GridToolbarContainer className="flex flex-wrap justify-between p-2 bg-gray-100 border-b border-gray-200">
<GridToolbarContainer className="flex flex-wrap justify-between p-2 bg-gray-100 border-b border-gray-200"> <Button
<Button onClick={handleGoToPage1}
onClick={handleGoToPage1} className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600 m-1"
className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600 m-1" >
> Go to page 1
Go to page 1 </Button>
</Button> <Button
<Button onClick={handleModal}
onClick={handleModal} className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600 m-1"
className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600 m-1" >
> +
+ </Button>
</Button> </GridToolbarContainer>
</GridToolbarContainer> );
); }
}
function TokenRegistry() {
function TokenRegistery() { const [menuItems, setMenuItems] = useState([]);
const [menuItems, setMenuItems] = useState([]); const [selectedMenuItem, setSelectedMenuItem] = useState(null);
const [selectedMenuItem, setSelectedMenuItem] = useState(null); const [, setIsModalOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false); const apiRef = useRef(null);
const apiRef = useRef(null);
useEffect(() => {
useEffect(() => { const fetchData = async () => {
const fetchData = async () => { const token = localStorage.getItem("token"); // Get token from local storage
const token = localStorage.getItem("token"); // Get token from local storage try {
try { const response = await fetch(
const response = await fetch( `${api}/apiregistery/getall`,
`${api}/apiregistery/getall`, {
{ headers: {
headers: { Authorization: `Bearer ${token}`,
Authorization: `Bearer ${token}`, },
}, }
} );
); const data = await response.json();
const data = await response.json(); setMenuItems(data);
setMenuItems(data); } catch (error) {
} catch (error) { console.error("Error fetching data:", error);
console.error("Error fetching data:", error); }
} };
};
fetchData();
fetchData(); }, []);
}, []);
const handleThreeDotsClick = (menuItemId) => {
const handleThreeDotsClick = (menuItemId) => { setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId);
setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); };
};
const columns = [
const columns = [ {
{ field: "table_id",
field: "table_id", headerName: "Table ID",
headerName: "Table ID", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "token_name",
field: "token_name", headerName: "Token Name",
headerName: "Token Name", width: 250,
width: 250, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "token",
field: "token", headerName: "Token",
headerName: "Token", width: 200,
width: 200, headerClassName: "custom-header",
headerClassName: "custom-header", cellClassName: "custom-cell",
cellClassName: "custom-cell", },
}, {
{ field: "actions",
field: "actions", headerName: "Actions",
headerName: "Actions", width: 150,
width: 150, renderCell: ({ row }) => (
renderCell: ({ row }) => ( <div className="relative">
<div className="relative"> <div
<div className="cursor-pointer"
className="cursor-pointer" onClick={() => handleThreeDotsClick(row.id)}
onClick={() => handleThreeDotsClick(row.id)} >
> <BsThreeDotsVertical /> {/* Updated icon from react-icons */}
<FontAwesomeIcon icon={faEllipsisV} /> </div>
</div> {selectedMenuItem === row.id && (
{selectedMenuItem === row.id && ( <div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl">
<div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl"> <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left">
<button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> Edit
Edit </button>
</button> <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left">
<button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> Delete
Delete </button>
</button> </div>
</div> )}
)} </div>
</div> ),
), },
}, ];
];
return (
return ( <div className="flex justify-center mt-5 px-2 md:px-0">
<div className="flex justify-center mt-5 px-2 md:px-0"> <Box className="w-full max-w-7xl bg-gray-50 p-4 md:p-6 rounded shadow-md">
<Box className="w-full max-w-7xl bg-gray-50 p-4 md:p-6 rounded shadow-md"> <p className="text-2xl md:text-3xl text-center text-white bg-gray-400 mb-4 p-3">
<p className="text-2xl md:text-3xl text-center text-white bg-gray-400 mb-4 p-3"> Token Registry
Token Registry </p>
</p> <div className="bg-white p-2 md:p-4 rounded shadow-md">
<div className="bg-white p-2 md:p-4 rounded shadow-md"> <DataGrid
<DataGrid rows={menuItems}
rows={menuItems} columns={columns}
columns={columns} components={{
components={{ Toolbar: () => (
Toolbar: () => ( <CustomToolbar
<CustomToolbar apiRef={apiRef}
apiRef={apiRef} handleModal={() => setIsModalOpen(true)}
handleModal={() => setIsModalOpen(true)} />
/> ),
), }}
}} pageSize={10}
pageSize={10} onGridReady={(gridApi) => {
onGridReady={(gridApi) => { apiRef.current = gridApi;
apiRef.current = gridApi; }}
}} className="data-grid"
className="data-grid" />
/> </div>
</div> </Box>
</Box> {/* Add your modals and other components here */}
{/* Add your modals and other components here */} </div>
</div> );
); }
}
export default TokenRegistry;
export default TokenRegistery;

View File

@ -1,41 +1,41 @@
/* UpdateModal.css */ /* UpdateModal.css */
.modalWrapper { .modalWrapper {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.modal { .modal {
background: white; background: white;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
} }
label { label {
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
} }
input { input {
width: 100%; width: 100%;
padding: 8px; padding: 8px;
margin-bottom: 10px; margin-bottom: 10px;
} }
button { button {
background-color: #4caf50; background-color: #4caf50;
color: white; color: white;
padding: 10px 15px; padding: 10px 15px;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
} }

View File

@ -1,107 +1,107 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
const UpdateModal = ({ user, onUpdate, onClose }) => { const UpdateModal = ({ user, onUpdate, onClose }) => {
const [updatedUser, setUpdatedUser] = useState(() => ({ ...user })); const [updatedUser, setUpdatedUser] = useState(() => ({ ...user }));
useEffect(() => { useEffect(() => {
console.log('Updated user state:', updatedUser); console.log('Updated user state:', updatedUser);
}, [updatedUser]); }, [updatedUser]);
const handleChange = (field, value) => { const handleChange = (field, value) => {
const updatedData = { ...updatedUser, [field]: value }; const updatedData = { ...updatedUser, [field]: value };
setUpdatedUser(updatedData); setUpdatedUser(updatedData);
}; };
const handleSave = () => { const handleSave = () => {
onUpdate(updatedUser); onUpdate(updatedUser);
onClose(); onClose();
}; };
const handleUpdate = () => { // const handleUpdate = () => {
console.log('Before update:', updatedUser); // console.log('Before update:', updatedUser);
onUpdate(updatedUser); // onUpdate(updatedUser);
onClose(); // onClose();
// Use a callback function with setUpdatedUser to ensure the state is updated // // Use a callback function with setUpdatedUser to ensure the state is updated
setUpdatedUser((prev) => { // setUpdatedUser((prev) => {
const updatedData = { ...prev }; // const updatedData = { ...prev };
console.log('Updated data:', updatedData); // console.log('Updated data:', updatedData);
onUpdate(updatedData); // Pass the updatedData to onUpdate // onUpdate(updatedData); // Pass the updatedData to onUpdate
onClose(); // onClose();
return updatedData; // Return the updatedData to setUpdatedUser // return updatedData; // Return the updatedData to setUpdatedUser
}); // });
// Set the updatedUser state directly to ensure the UI reflects the changes // // Set the updatedUser state directly to ensure the UI reflects the changes
setUpdatedUser(updatedUser); // setUpdatedUser(updatedUser);
}; // };
return ( return (
<div className="modalWrapper"> <div className="modalWrapper">
<div className="modal"> <div className="modal">
<button className="closeBtn" onClick={onClose}> <button className="closeBtn" onClick={onClose}>
X X
</button> </button>
<div>User ID: {user.userId}</div> <div>User ID: {user.userId}</div>
<div>Username: {user.username}</div> <div>Username: {user.username}</div>
<div>Full Name: {user.fullName}</div> <div>Full Name: {user.fullName}</div>
<div>Email: {user.email}</div> <div>Email: {user.email}</div>
<div>Mob Number: {user.mobno}</div> <div>Mob Number: {user.mobno}</div>
<div>User grp name: {user.usergrpname}</div> <div>User grp name: {user.usergrpname}</div>
<label htmlFor="updatedUserId">User ID:</label> <label htmlFor="updatedUserId">User ID:</label>
<input <input
id="updatedUserId" id="updatedUserId"
type="text" type="text"
value={updatedUser.userId} value={updatedUser.userId}
onChange={(e) => handleChange('userId', e.target.value)} onChange={(e) => handleChange('userId', e.target.value)}
/> />
<label htmlFor="updatedUsername">Username:</label> <label htmlFor="updatedUsername">Username:</label>
<input <input
id="updatedUsername" id="updatedUsername"
type="text" type="text"
value={updatedUser.username} value={updatedUser.username}
onChange={(e) => handleChange('username', e.target.value)} onChange={(e) => handleChange('username', e.target.value)}
/> />
<label htmlFor="updatedEmail">Email:</label> <label htmlFor="updatedEmail">Email:</label>
<input <input
id="updatedEmail" id="updatedEmail"
type="text" type="text"
value={updatedUser.email} value={updatedUser.email}
onChange={(e) => handleChange('email', e.target.value)} onChange={(e) => handleChange('email', e.target.value)}
/> />
<label htmlFor="updatedFullName">Full Name:</label> <label htmlFor="updatedFullName">Full Name:</label>
<input <input
id="updatedFullName" id="updatedFullName"
type="text" type="text"
value={updatedUser.fullName} value={updatedUser.fullName}
onChange={(e) => handleChange('fullName', e.target.value)} onChange={(e) => handleChange('fullName', e.target.value)}
/> />
<label htmlFor="updatedMobno">Mob No:</label> <label htmlFor="updatedMobno">Mob No:</label>
<input <input
id="updatedmobno" id="updatedmobno"
type="number" type="number"
value={updatedUser.mobno} value={updatedUser.mobno}
onChange={(e) => handleChange('mobno', e.target.value)} onChange={(e) => handleChange('mobno', e.target.value)}
/> />
<label htmlFor="updatedusergrpname">User grp name:</label> <label htmlFor="updatedusergrpname">User grp name:</label>
<input <input
id="updatedusergrpname" id="updatedusergrpname"
type="text" type="text"
value={updatedUser.usergrpname} value={updatedUser.usergrpname}
onChange={(e) => handleChange('usergrpname', e.target.value)} onChange={(e) => handleChange('usergrpname', e.target.value)}
/> />
<button onClick={handleSave}>SAVE</button> <button onClick={handleSave}>SAVE</button>
</div> </div>
</div> </div>
); );
}; };
export default UpdateModal; export default UpdateModal;

View File

@ -1,69 +1,69 @@
.modalWrapper { .modalWrapper {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.modal { .modal {
background: #fff; background: #fff;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 300px; width: 300px;
max-width: 100%; max-width: 100%;
} }
.closeBtn { .closeBtn {
background: none; background: none;
border: none; border: none;
font-size: 18px; font-size: 18px;
color: #333; color: #333;
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 10px; right: 10px;
} }
label { label {
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
font-weight: bold; font-weight: bold;
} }
input { input {
width: 100%; width: 100%;
padding: 8px; padding: 8px;
margin-bottom: 10px; margin-bottom: 10px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
box-sizing: border-box; box-sizing: border-box;
} }
button { button {
background-color: #4caf50; background-color: #4caf50;
color: white; color: white;
padding: 10px 15px; padding: 10px 15px;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
margin-right: 10px; margin-right: 10px;
} }
button:hover { button:hover {
background-color: #45a049; background-color: #45a049;
} }
button:last-child { button:last-child {
background-color: #36bbf4; background-color: #36bbf4;
} }
button:last-child:hover { button:last-child:hover {
background-color: #2f8cd3; background-color: #2f8cd3;
} }

View File

@ -1,146 +1,146 @@
// AddUserGroupModal.js // AddUserGroupModal.js
import React, { useState } from 'react'; import React, { useState } from 'react';
import './Modelitem.css'; import './Modelitem.css';
const AddUserGroupModal = ({ showModal, handleCloseModal, onSave }) => { const AddUserGroupModal = ({ showModal, handleCloseModal, onSave }) => {
const [newUserData, setNewUserData] = useState({ const [newUserData, setNewUserData] = useState({
groupName: '', groupName: '',
groupDesc: '', groupDesc: '',
createBy: '', createBy: '',
createDate: '', createDate: '',
updateDate: '', updateDate: '',
updateBy: '', updateBy: '',
status: '', status: '',
groupLevel: '', groupLevel: '',
createDateFormatted: '', createDateFormatted: '',
updateDateFormatted: '', updateDateFormatted: '',
// Add more fields as needed // Add more fields as needed
}); });
const handleSave = () => { const handleSave = () => {
// Format date fields before saving // Format date fields before saving
const formattedData = { const formattedData = {
...newUserData, ...newUserData,
createDate: new Date(newUserData.createDate).toISOString(), createDate: new Date(newUserData.createDate).toISOString(),
updateDate: new Date(newUserData.updateDate).toISOString(), updateDate: new Date(newUserData.updateDate).toISOString(),
}; };
onSave(formattedData); // Pass the new data to the parent component onSave(formattedData); // Pass the new data to the parent component
handleCloseModal(); // Close the modal after saving handleCloseModal(); // Close the modal after saving
}; };
const handleCancel = () => { const handleCancel = () => {
setNewUserData({ setNewUserData({
groupName: '', groupName: '',
groupDesc: '', groupDesc: '',
createBy: '', createBy: '',
createDate: '', createDate: '',
updateDate: '', updateDate: '',
updateBy: '', updateBy: '',
status: '', status: '',
groupLevel: '', groupLevel: '',
createDateFormatted: '', createDateFormatted: '',
updateDateFormatted: '', updateDateFormatted: '',
// Reset other fields as needed // Reset other fields as needed
}); });
handleCloseModal(); handleCloseModal();
}; };
return ( return (
<> <>
{showModal && ( {showModal && (
<div className='modalWrapper'> <div className='modalWrapper'>
<div className='modal'> <div className='modal'>
<button className="closeBtn" onClick={handleCancel}>X</button> <button className="closeBtn" onClick={handleCancel}>X</button>
<label htmlFor="groupName">Group Name:</label> <label htmlFor="groupName">Group Name:</label>
<input <input
type="text" type="text"
id="groupName" id="groupName"
value={newUserData.groupName} value={newUserData.groupName}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupName: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupName: e.target.value }))}
/> />
<label htmlFor="groupDesc">Group Description:</label> <label htmlFor="groupDesc">Group Description:</label>
<input <input
type="text" type="text"
id="groupDesc" id="groupDesc"
value={newUserData.groupDesc} value={newUserData.groupDesc}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupDesc: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupDesc: e.target.value }))}
/> />
<label htmlFor="createBy">Create By:</label> <label htmlFor="createBy">Create By:</label>
<input <input
type="text" type="text"
id="createBy" id="createBy"
value={newUserData.createBy} value={newUserData.createBy}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createBy: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createBy: e.target.value }))}
/> />
<label htmlFor="createDate">Create Date:</label> <label htmlFor="createDate">Create Date:</label>
<input <input
type="date" type="date"
id="createDate" id="createDate"
value={newUserData.createDate} value={newUserData.createDate}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDate: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDate: e.target.value }))}
/> />
<label htmlFor="updateDate">Update Date:</label> <label htmlFor="updateDate">Update Date:</label>
<input <input
type="text" type="text"
id="updateDate" id="updateDate"
value={newUserData.updateDate} value={newUserData.updateDate}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDate: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDate: e.target.value }))}
/> />
<label htmlFor="updateBy">Update By:</label> <label htmlFor="updateBy">Update By:</label>
<input <input
type="text" type="text"
id="updateBy" id="updateBy"
value={newUserData.updateBy} value={newUserData.updateBy}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateBy: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateBy: e.target.value }))}
/> />
<label htmlFor="status">Status:</label> <label htmlFor="status">Status:</label>
<input <input
type="text" type="text"
id="status" id="status"
value={newUserData.status} value={newUserData.status}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, status: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, status: e.target.value }))}
/> />
<label htmlFor="groupLevel">Group Level:</label> <label htmlFor="groupLevel">Group Level:</label>
<input <input
type="text" type="text"
id="groupLevel" id="groupLevel"
value={newUserData.groupLevel} value={newUserData.groupLevel}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupLevel: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupLevel: e.target.value }))}
/> />
<label htmlFor="createDateFormatted">Create Date Formatted:</label> <label htmlFor="createDateFormatted">Create Date Formatted:</label>
<input <input
type="text" type="text"
id="createDateFormatted" id="createDateFormatted"
value={newUserData.createDateFormatted} value={newUserData.createDateFormatted}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDateFormatted: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDateFormatted: e.target.value }))}
/> />
<label htmlFor="updateDateFormatted">Update Date Formatted:</label> <label htmlFor="updateDateFormatted">Update Date Formatted:</label>
<input <input
type="text" type="text"
id="updateDateFormatted" id="updateDateFormatted"
value={newUserData.updateDateFormatted} value={newUserData.updateDateFormatted}
onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDateFormatted: e.target.value }))} onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDateFormatted: e.target.value }))}
/> />
<button onClick={handleSave}>Save</button> <button onClick={handleSave}>Save</button>
<button onClick={handleCancel}>Cancel</button> <button onClick={handleCancel}>Cancel</button>
</div> </div>
</div> </div>
)} )}
</> </>
); );
}; };
export default AddUserGroupModal; export default AddUserGroupModal;

View File

@ -1,7 +1,7 @@
@import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
.custom-header, .custom-cell { .custom-header, .custom-cell {
font-family: 'PT Serif", serif '; font-family: 'PT Serif", serif ';
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,224 +1,221 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import { Box, Button } from "@mui/material"; import { Box, Button } from "@mui/material";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { BsThreeDotsVertical } from "react-icons/bs";
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; import "./UserGroupMaintance.css";
import "./UserGroupMaintance.css"; // eslint-disable-next-line
import { Token } from "@mui/icons-material"; const api = process.env.REACT_APP_API_BASE_URL;
const api = process.env.REACT_APP_API_BASE_URL; function CustomToolbar({ apiRef, handleModal }) {
const handleGoToPage1 = () => {
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { if (apiRef.current) {
const handleGoToPage1 = () => { apiRef.current.setPage(1);
if (apiRef.current) { }
apiRef.current.setPage(1); };
}
}; return (
<GridToolbarContainer>
return ( <Button onClick={handleGoToPage1}>Go to page 1</Button>
<GridToolbarContainer> <Button onClick={handleModal}>+</Button>
<Button onClick={handleGoToPage1}>Go to page 1</Button> </GridToolbarContainer>
<Button onClick={handleModal}>+</Button> );
</GridToolbarContainer> }
);
} function UserMaintance() {
const [userGroups, setUserGroups] = useState([]);
function UserMaintance() { const [selectedUserGroup, setSelectedUserGroup] = useState(null);
const [userGroups, setUserGroups] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedUserGroup, setSelectedUserGroup] = useState(null); const apiRef = useRef(null);
const [isModalOpen, setIsModalOpen] = useState(false); // eslint-disable-next-line
const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); useEffect(() => {
const apiRef = useRef(null); const fetchData = async () => {
const token = localStorage.getItem("token");
useEffect(() => { try {
const fetchData = async () => { const response = await fetch(`${api}/api/getAllUsrGrp`, {
const token = localStorage.getItem("token"); headers: { authorization: `bearer ${token}` },
try { });
const response = await fetch(`${api}/api/getAllUsrGrp`, { const data = await response.json();
headers: { authorization: `bearer ${token}` }, const userGroupsWithIds = data.map((group, index) => ({
}); ...group,
const data = await response.json(); id: index + 1,
const userGroupsWithIds = data.map((group, index) => ({ }));
...group, setUserGroups(userGroupsWithIds);
id: index + 1, } catch (error) {
})); console.error("Error fetching data:", error);
setUserGroups(userGroupsWithIds); }
} catch (error) { };
console.error("Error fetching data:", error);
} fetchData();
}; }, []);
fetchData(); const handleThreeDotsClick = (usrGrp) => {
}, []); setSelectedUserGroup(usrGrp === selectedUserGroup ? null : usrGrp);
};
const handleThreeDotsClick = (usrGrp) => {
setSelectedUserGroup(usrGrp === selectedUserGroup ? null : usrGrp); const handleDelete = async (usrGrp) => {
}; try {
const response = await fetch(`${api}/api/delete_usrgrp/${usrGrp}`, {
const handleDelete = async (usrGrp) => { method: "DELETE",
try { });
const response = await fetch(`${api}/api/delete_usrgrp/${usrGrp}`, { if (response.ok) {
method: "DELETE", setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp));
}); console.log("User group deleted successfully:", usrGrp);
if (response.ok) { } else {
setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp)); console.error("Failed to delete user group:", response.statusText);
console.log("User group deleted successfully:", usrGrp); }
} else { } catch (error) {
console.error("Failed to delete user group:", response.statusText); console.error("Error deleting user group:", error);
} }
} catch (error) { };
console.error("Error deleting user group:", error);
} const handleModal = () => {
}; setIsModalOpen(true);
};
const handleModal = () => {
setIsModalOpen(true); const columns = [
}; {
field: "usrGrp",
const columns = [ headerName: "User Group ID",
{ width: 150,
field: "usrGrp", headerClassName: "custom-header",
headerName: "User Group ID", cellClassName: "custom-cell",
width: 150, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "groupName",
}, headerName: "Group Name",
{ width: 150,
field: "groupName", headerClassName: "custom-header",
headerName: "Group Name", cellClassName: "custom-cell",
width: 150, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "groupDesc",
}, headerName: "Group Description",
{ width: 150,
field: "groupDesc", headerClassName: "custom-header",
headerName: "Group Description", cellClassName: "custom-cell",
width: 150, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "createby",
}, headerName: "Create By",
{ width: 100,
field: "createby", headerClassName: "custom-header",
headerName: "Create By", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "createdate",
}, headerName: "Create Date",
{ width: 100,
field: "createdate", headerClassName: "custom-header",
headerName: "Create Date", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "updatedate",
}, headerName: "Update Date",
{ width: 100,
field: "updatedate", headerClassName: "custom-header",
headerName: "Update Date", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "updateby",
}, headerName: "Update By",
{ width: 100,
field: "updateby", headerClassName: "custom-header",
headerName: "Update By", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "status",
}, headerName: "Status",
{ width: 100,
field: "status", headerClassName: "custom-header",
headerName: "Status", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "grouplevel",
}, headerName: "Group Level",
{ width: 100,
field: "grouplevel", headerClassName: "custom-header",
headerName: "Group Level", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "createdateformated",
}, headerName: "Create Date Formated",
{ width: 100,
field: "createdateformated", headerClassName: "custom-header",
headerName: "Create Date Formated", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header", {
cellClassName: "custom-cell", field: "updatedateformated",
}, headerName: "Update Date Formated",
{ width: 100,
field: "updatedateformated", headerClassName: "custom-header",
headerName: "Update Date Formated", cellClassName: "custom-cell",
width: 100, },
headerClassName: "custom-header",
cellClassName: "custom-cell", // Add other columns as needed
}, {
field: "actions",
// Add other columns as needed headerName: "Actions",
{ width: 150,
field: "actions", renderCell: ({ row }) => (
headerName: "Actions", <div>
width: 150, <div
renderCell: ({ row }) => ( className="three-dots"
<div> onClick={() => handleThreeDotsClick(row.usrGrp)}
<div >
className="three-dots" <BsThreeDotsVertical />
onClick={() => handleThreeDotsClick(row.usrGrp)} </div>
> {selectedUserGroup === row.usrGrp && (
<FontAwesomeIcon icon={faEllipsisV} /> <div className="popover">
</div> <button onClick={() => handleDelete(row.usrGrp)}>Delete</button>
{selectedUserGroup === row.usrGrp && ( {/* You can include other actions here */}
<div className="popover"> </div>
<button onClick={() => handleDelete(row.usrGrp)}>Delete</button> )}
{/* You can include other actions here */} </div>
</div> ),
)} },
</div> ];
),
}, return (
]; <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
<div className="text-center text-3xl text-white bg-gray-400 p-2 rounded-lg">
return ( User Group Maintenance
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4"> </div>
<div className="text-center text-3xl text-white bg-gray-400 p-2 rounded-lg">
User Group Maintenance <Box
</div> className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2 bg-white border border-gray-200 shadow-lg rounded-lg"
sx={{ height: 500, width: "100%" }}
<Box >
className="w-full p-4 md:w-3/4 lg:w-2/3 xl:w-1/2 bg-white border border-gray-200 shadow-lg rounded-lg" <DataGrid
sx={{ height: 500, width: "100%" }} rows={userGroups}
> columns={columns}
<DataGrid components={{
rows={userGroups} Toolbar: () => (
columns={columns} <CustomToolbar
components={{ apiRef={apiRef}
Toolbar: () => ( handleThreeDotsClick={handleThreeDotsClick}
<CustomToolbar handleModal={handleModal}
apiRef={apiRef} />
handleThreeDotsClick={handleThreeDotsClick} ),
handleModal={handleModal} }}
/> pageSize={10}
), onGridReady={(gridApi) => {
}} apiRef.current = gridApi;
pageSize={10} }}
onGridReady={(gridApi) => { className="bg-gray-400"
apiRef.current = gridApi; />
}} </Box>
className="bg-gray-400" {/* Your modals and other components */}
/> {isModalOpen && (
</Box> <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4">
{/* Your modals and other components */} <div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full">
{isModalOpen && ( <h2 className="text-xl font-bold mb-4">Modal Title</h2>
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 p-4"> {/* Modal content here */}
<div className="bg-white p-8 rounded-lg shadow-lg max-w-lg w-full"> <Button onClick={() => setIsModalOpen(false)}>Close</Button>
<h2 className="text-xl font-bold mb-4">Modal Title</h2> </div>
{/* Modal content here */} </div>
<Button onClick={() => setIsModalOpen(false)}>Close</Button> )}
</div> </div>
</div> );
)} }
</div>
); export default UserMaintance;
}
export default UserMaintance;

View File

@ -1,132 +1,132 @@
/* .container { /* .container {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
max-width: 2000px; max-width: 2000px;
margin: 0 auto; margin: 0 auto;
padding: 20px; padding: 20px;
} }
h1 { h1 {
text-align: center; text-align: center;
margin-bottom: 20px; margin-bottom: 20px;
} }
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
margin: 0 auto; margin: 0 auto;
max-width: 2000px; max-width: 2000px;
} }
table th, table th,
table td { table td {
border: 1px solid #ddd; border: 1px solid #ddd;
padding: 8px; padding: 8px;
text-align: left; text-align: left;
} }
table th { table th {
background-color: #f2f2f2; background-color: #f2f2f2;
} }
input[type='text'] { input[type='text'] {
width: 100%; width: 100%;
padding: 5px; padding: 5px;
} }
button { button {
padding: 8px 12px; padding: 8px 12px;
background-color: #007bff; background-color: #007bff;
color: #fff; color: #fff;
border: none; border: none;
cursor: pointer; cursor: pointer;
} }
button:hover { button:hover {
background-color: #0056b3; background-color: #0056b3;
} }
label { label {
margin-right: 10px; margin-right: 10px;
} }
select { select {
padding: 5px; padding: 5px;
} }
.modal { .modal {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.modal-content { .modal-content {
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
} }
.modal-content input { .modal-content input {
margin-bottom: 10px; margin-bottom: 10px;
} }
.modal-content button { .modal-content button {
margin-top: 10px; margin-top: 10px;
} }
.update-modal { .update-modal {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.update-modal-content { .update-modal-content {
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
} }
.update-modal-content input { .update-modal-content input {
margin-bottom: 10px; margin-bottom: 10px;
} }
.update-modal-content button { .update-modal-content button {
margin-top: 10px; margin-top: 10px;
} }
.spinner { .spinner {
display: inline-block; display: inline-block;
width: 40px; width: 40px;
height: 40px; height: 40px;
border: 4px solid rgba(0, 0, 0, 0.1); border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #7983ff; border-left-color: #7983ff;
border-radius: 50%; border-radius: 50%;
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
} }
@keyframes spin { @keyframes spin {
to { to {
transform: rotate(360deg); transform: rotate(360deg);
} }
} */ } */
@import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
.custom-header, .custom-cell { .custom-header, .custom-cell {
font-family: 'PT Serif", serif '; font-family: 'PT Serif", serif ';
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,169 +1,168 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import { Box, Button } from "@mui/material"; import { Box, Button } from "@mui/material";
import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { BsThreeDotsVertical } from "react-icons/bs";
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; import Modal from "./Modal"; // Import your Modal component
import Modal from "./Modal"; // Import your Modal component import UpdateModal from "./UpdateModal"; // Import your UpdateModal component
import UpdateModal from "./UpdateModal"; // Import your UpdateModal component import "./UserMaintance.css";
import "./UserMaintance.css";
const api = process.env.REACT_APP_API_BASE_URL;
const api = process.env.REACT_APP_API_BASE_URL;
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) {
function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { const handleGoToPage1 = () => {
const handleGoToPage1 = () => { if (apiRef.current) {
if (apiRef.current) { apiRef.current.setPage(1);
apiRef.current.setPage(1); }
} };
};
return (
return ( <GridToolbarContainer>
<GridToolbarContainer> <Button onClick={handleGoToPage1}>Go to page 1</Button>
<Button onClick={handleGoToPage1}>Go to page 1</Button> <Button onClick={handleModal}>+</Button>
<Button onClick={handleModal}>+</Button> </GridToolbarContainer>
</GridToolbarContainer> );
); }
}
function UserMaintance() {
function UserMaintance() { const [users, setUsers] = useState([]);
const [users, setUsers] = useState([]); const [selectedUser, setSelectedUser] = useState(null);
const [selectedUser, setSelectedUser] = useState(null); const [selectedUserForUpdate, setSelectedUserForUpdate] = useState(null);
const [selectedUserForUpdate, setSelectedUserForUpdate] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false); const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false);
const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); const [newUser, setNewUser] = useState({
const [newUser, setNewUser] = useState({ userId: "",
userId: "", username: "",
username: "", fullName: "",
fullName: "", email: "",
email: "",
usrGrpName: "",
usrGrpName: "", });
}); const apiRef = useRef(null);
const apiRef = useRef(null);
useEffect(() => {
useEffect(() => { const fetchData = async () => {
const fetchData = async () => { const token = localStorage.getItem("token");
const token = localStorage.getItem("token"); console.log("object", token);
console.log("object", token); try {
try { const response = await fetch(`${api}/api/getAllAppUser`, {
const response = await fetch(`${api}/api/getAllAppUser`, { headers: {
headers: { Authorization: `Bearer ${token}`,
Authorization: `Bearer ${token}`, },
}, });
}); const data = await response.json();
const data = await response.json(); const usersWithIds = data.map((user, index) => ({
const usersWithIds = data.map((user, index) => ({ ...user,
...user, id: index + 1,
id: index + 1, }));
})); setUsers(usersWithIds);
setUsers(usersWithIds); } catch (error) {
} catch (error) { console.error("Error fetching data:", error);
console.error("Error fetching data:", error); }
} };
};
fetchData();
fetchData(); }, []);
}, []);
const handleThreeDotsClick = (userId) => {
const handleThreeDotsClick = (userId) => { setSelectedUser(userId === selectedUser ? null : userId);
setSelectedUser(userId === selectedUser ? null : userId); };
};
const handleDelete = (userId) => {
const handleDelete = (userId) => { console.log("Delete user with ID:", userId);
console.log("Delete user with ID:", userId); };
};
const handleUpdate = (user) => {
const handleUpdate = (user) => { setSelectedUserForUpdate(user);
setSelectedUserForUpdate(user); setIsUpdateModalOpen(true);
setIsUpdateModalOpen(true); };
};
const handleModal = () => {
const handleModal = () => { setIsModalOpen(true);
setIsModalOpen(true); };
};
const handleModalSave = (data) => {
const handleModalSave = (data) => { setUsers((prevUsers) => [
setUsers((prevUsers) => [ ...prevUsers,
...prevUsers, { ...data, id: prevUsers.length + 1 },
{ ...data, id: prevUsers.length + 1 }, ]);
]); setIsModalOpen(false);
setIsModalOpen(false); };
};
const handleUpdateSave = () => {
const handleUpdateSave = () => { setIsUpdateModalOpen(false);
setIsUpdateModalOpen(false); };
};
const columns = [
const columns = [ { field: "userId", headerName: "User ID", width: 200 },
{ field: "userId", headerName: "User ID", width: 200 }, { field: "username", headerName: "Username", width: 200 },
{ field: "username", headerName: "Username", width: 200 }, { field: "fullName", headerName: "Full Name", width: 200 },
{ field: "fullName", headerName: "Full Name", width: 200 }, { field: "email", headerName: "Email", width: 200 },
{ field: "email", headerName: "Email", width: 200 }, { field: "usrGrpName", headerName: "User Group", width: 150 },
{ field: "usrGrpName", headerName: "User Group", width: 150 }, {
{ field: "actions",
field: "actions", headerName: "Actions",
headerName: "Actions", width: 100,
width: 100, renderCell: ({ row }) => (
renderCell: ({ row }) => ( <div>
<div> <div
<div className="three-dots"
className="three-dots" onClick={() => handleThreeDotsClick(row.userId)}
onClick={() => handleThreeDotsClick(row.userId)} >
> <BsThreeDotsVertical />
<FontAwesomeIcon icon={faEllipsisV} /> </div>
</div> {selectedUser === row.userId && (
{selectedUser === row.userId && ( <div className="popover">
<div className="popover"> <button onClick={() => handleDelete(row.userId)}>Delete</button>
<button onClick={() => handleDelete(row.userId)}>Delete</button> <button onClick={() => handleUpdate(row)}>Update</button>
<button onClick={() => handleUpdate(row)}>Update</button> </div>
</div> )}
)} </div>
</div> ),
), },
}, ];
];
return (
return ( <Box
<Box sx={{ height: "calc(100vh - 150px)", width: "100%", overflowX: "auto" }}
sx={{ height: "calc(100vh - 150px)", width: "100%", overflowX: "auto" }} >
> <div className="text-center text-3xl text-white bg-gray-400">
<div className="text-center text-3xl text-white bg-gray-400"> User Maintenance
User Maintenance </div>
</div> <DataGrid
<DataGrid className="bg-gray-400"
className="bg-gray-400" rows={users}
rows={users} columns={columns}
columns={columns} components={{
components={{ Toolbar: () => (
Toolbar: () => ( <CustomToolbar
<CustomToolbar apiRef={apiRef}
apiRef={apiRef} handleThreeDotsClick={handleThreeDotsClick}
handleThreeDotsClick={handleThreeDotsClick} handleModal={handleModal}
handleModal={handleModal} />
/> ),
), }}
}} pageSize={10}
pageSize={10} onGridReady={(gridApi) => {
onGridReady={(gridApi) => { apiRef.current = gridApi;
apiRef.current = gridApi; }}
}} />
/> {isModalOpen && (
{isModalOpen && ( <Modal
<Modal setNewUser={setNewUser}
setNewUser={setNewUser} newUser={newUser}
newUser={newUser} onSave={handleModalSave}
onSave={handleModalSave} onClose={() => setIsModalOpen(false)}
onClose={() => setIsModalOpen(false)} />
/> )}
)} {isUpdateModalOpen && (
{isUpdateModalOpen && ( <UpdateModal
<UpdateModal user={selectedUserForUpdate}
user={selectedUserForUpdate} onUpdate={handleUpdateSave}
onUpdate={handleUpdateSave} onClose={() => setIsUpdateModalOpen(false)}
onClose={() => setIsUpdateModalOpen(false)} />
/> )}
)} </Box>
</Box> );
); }
}
export default UserMaintance;
export default UserMaintance;

View File

@ -1,123 +1,126 @@
/* Global Styles */ /* Global Styles */
body { body {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
background-color: #f4f6f8; background-color: #f4f6f8;
color: #333; color: #333;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.dashboard { .dashboard {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; height: 100vh;
} }
/* Horizontal Navbar */ /* Horizontal Navbar */
.horizontal-navbar { .horizontal-navbar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
background-color: #2c3e50; background-color: #2c3e50;
color: #ecf0f1; color: #ecf0f1;
padding: 10px 20px; padding: 10px 20px;
} }
.horizontal-navbar h3 { .horizontal-navbar h3 {
margin: 0; margin: 0;
font-size: 24px; font-size: 24px;
} }
.nav { .nav {
display: flex; display: flex;
gap: 20px; gap: 20px;
} }
.nav-link { .nav-link {
color: #ecf0f1; color: #ecf0f1;
text-decoration: none; text-decoration: none;
font-size: 18px; font-size: 18px;
transition: color 0.3s; transition: color 0.3s;
} }
.nav-link:hover { .nav-link:hover {
color: #3498db; color: #3498db;
} }
button { button {
background-color: #e74c3c; background-color: #e74c3c;
color: #ecf0f1; color: #ecf0f1;
border: none; border: none;
padding: 10px 20px; padding: 10px 20px;
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
transition: background-color 0.3s; transition: background-color 0.3s;
} }
button:hover { button:hover {
background-color: #c0392b; background-color: #c0392b;
} }
/* Content */ /* Content */
.content { .content {
display: flex; display: flex;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.sidebar-content-wrapper { .sidebar-content-wrapper {
display: flex; display: flex;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
/* Sidebar */ /* Sidebar */
.sidebar { .sidebar {
width: 250px; width: 250px;
background-color: #34495e; background-color: #34495e;
color: #ecf0f1; color: #ecf0f1;
transition: width 0.3s; transition: width 0.3s;
overflow: auto; overflow: auto;
} }
.sidebar.collapsed { .sidebar.collapsed {
width: 80px; width: 80px;
} }
.sidebar-content-wrapper .sidebar ul { .sidebar-content-wrapper .sidebar ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.sidebar-content-wrapper .sidebar ul li { .sidebar-content-wrapper .sidebar ul li {
padding: 15px 20px; padding: 15px 20px;
cursor: pointer; cursor: pointer;
transition: background-color 0.3s; transition: background-color 0.3s;
} }
.sidebar-content-wrapper .sidebar ul li:hover { .sidebar-content-wrapper .sidebar ul li:hover {
background-color: #2c3e50; background-color: #2c3e50;
} }
.sidebar-content-wrapper .sidebar ul li.active { .sidebar-content-wrapper .sidebar ul li.active {
background-color: #3498db; background-color: #3498db;
} }
.sidebar-content-wrapper .sidebar .toggle-btn { .sidebar-content-wrapper .sidebar .toggle-btn {
text-align: center; text-align: center;
padding: 10px; padding: 10px;
cursor: pointer; cursor: pointer;
} }
/* Main Content */ /* Main Content */
.main-content { .main-content {
flex: 1; flex: 1;
padding: 20px; padding: 20px;
background-color: #ecf0f1; background-color: #ecf0f1;
overflow-y: auto; overflow-y: auto;
} }
.main-content h3 { .main-content h3 {
margin-top: 0; margin-top: 0;
} }

View File

@ -1,177 +1,202 @@
import React, { useState, useEffect } from "react"; /* eslint-disable jsx-a11y/anchor-is-valid */
import Sidebar from "./sidebar"; import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom"; import Sidebar from "./sidebar";
import UserMaintanceComponent from "./UserMaintance"; import { useNavigate } from "react-router-dom";
import UserGroupMaintanceComponent from "./UserGroupMaintance/UserGroupMaintance"; import UserMaintanceComponent from "./UserMaintance";
import MenuMaintanceComponent from "./MenuMaintance/MenuMaintance"; import UserGroupMaintanceComponent from "./UserGroupMaintance/UserGroupMaintance";
import MenuAccessControlComponent from "./MenuAccessControl/MenuAccessControl"; import MenuMaintanceComponent from "./MenuMaintance/MenuMaintance";
import SystemParametersComponent from "./SystemParameters/SystemParameters"; import MenuAccessControlComponent from "./MenuAccessControl/MenuAccessControl";
import AccessTypeComponent from "./AccessType/AccessType"; import SystemParametersComponent from "./SystemParameters/SystemParameters";
import ApiRegistery from "./ApiRegistery/ApiRegistery"; // import AccessTypeComponent from "./AccessType/AccessType";
import TokenRegistery from "./TokenRegistery/TokenRegistery"; import ApiRegistery from "./ApiRegistery/ApiRegistery";
import HomePage from "./HomePage"; import TokenRegistery from "./TokenRegistery/TokenRegistery";
import Setup from "./Setup.js"; import HomePage from "./HomePage";
import Report from "./Report"; import Setup from "./Setup.js";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import Report from "./Report";
import { import { FaCog, FaUsers, FaSignOutAlt, FaHome, FaChartBar } from "react-icons/fa";
faCog,
faUsers, const Dashboard = () => {
faSignOutAlt, const navigate = useNavigate();
faHome, const [menus, setMenus] = useState([]);
} from "@fortawesome/free-solid-svg-icons"; const [selectedUserMaintance, setSelectedUserMaintance] = useState(null);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const Dashboard = () => { const [content, setContent] = useState("");
const navigate = useNavigate();
const [menus, setMenus] = useState([]); useEffect(() => {
const [selectedUserMaintance, setSelectedUserMaintance] = useState(null); const fetchMenusData = async () => {
const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const token = localStorage.getItem("authtoken");
const [content, setContent] = useState("");
const apiUrl = `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`;
useEffect(() => { console.log("Fetching menus from API:", apiUrl);
const fetchMenusData = async () => {
const token = localStorage.getItem("token"); try {
const response = await fetch(apiUrl, {
const apiUrl = `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`; method: "GET",
console.log("Fetching menus from API:", apiUrl); headers: {
"Content-Type": "application/json",
try { Authorization: `Bearer ${token}`,
const response = await fetch(apiUrl, { },
headers: { });
Authorization: `Bearer ${token}`,
}, if (response.ok) {
}); const menuData = await response.json();
setMenus(menuData);
if (response.ok) { } else {
const menuData = await response.json(); const errorText = await response.text();
setMenus(menuData); console.error(
} else { "Failed to fetch menus. Status:",
const errorText = await response.text(); response.status,
console.error( "Response:",
"Failed to fetch menus. Status:", errorText
response.status, );
"Response:", }
errorText } catch (error) {
); console.error("Error during menu fetch:", error);
} }
} catch (error) { };
console.error("Error during menu fetch:", error);
} fetchMenusData();
}; }, [navigate]);
fetchMenusData(); const handleMenuItemClick = (menuItem) => {
}, [navigate]); setSelectedUserMaintance(menuItem);
setContent(menuItem.menuItemDesc); // Update content based on clicked menu item
const handleMenuItemClick = (menuItem) => { };
setSelectedUserMaintance(menuItem);
setContent(menuItem.menuItemDesc); // Update content based on clicked menu item const handleHomeClick = () => {
}; setSelectedUserMaintance(null);
setContent("Home");
const handleHomeClick = () => { };
setSelectedUserMaintance(null);
setContent("Home"); const handleSetupClick = () => {
}; setSelectedUserMaintance(null);
setContent("Setup");
const handleSetupClick = () => { };
setSelectedUserMaintance(null);
setContent("Setup"); const handleReportClick = () => {
}; setSelectedUserMaintance(null);
setContent("Report");
const handleReportClick = () => { };
setSelectedUserMaintance(null);
setContent("Report"); const handleSidebarToggle = () => {
}; setSidebarCollapsed(!sidebarCollapsed);
};
const handleSidebarToggle = () => {
setSidebarCollapsed(!sidebarCollapsed); const handleLogout = () => {
}; localStorage.removeItem("authToken");
localStorage.removeItem("user");
const handleLogout = () => { navigate("/");
localStorage.removeItem("authToken"); };
localStorage.removeItem("user");
navigate("/"); return (
}; <div className="flex flex-col h-screen bg-gradient-to-br from-purple-50 via-white to-blue-50">
{/* Top Navigation Bar */}
return ( <div className="flex justify-between items-center bg-gradient-to-r from-purple-600 to-indigo-600 text-white p-4 shadow-lg">
<div className="flex flex-col h-screen"> <div className="flex items-center space-x-4">
<div className="flex justify-between items-center bg-gray-800 text-white p-4"> <h3 className="text-2xl font-bold">Dashboard</h3>
<h3 className="text-2xl">Dashboard</h3> <div className="h-6 w-px bg-white/30"></div>
<nav className="flex space-x-4"> <nav className="flex space-x-6">
<a className="text-white" href="#" onClick={handleHomeClick}> <button
<FontAwesomeIcon icon={faHome} /> onClick={handleHomeClick}
</a> className="flex items-center space-x-2 hover:text-purple-200 transition-colors"
<a className="text-white" href="#" onClick={handleSetupClick}> >
<FontAwesomeIcon icon={faCog} /> <FaHome className="w-5 h-5" />
</a> <span>Home</span>
<a className="text-white" href="#" onClick={handleReportClick}> </button>
<FontAwesomeIcon icon={faUsers} /> <button
</a> onClick={handleSetupClick}
</nav> className="flex items-center space-x-2 hover:text-purple-200 transition-colors"
<button >
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded" <FaCog className="w-5 h-5" />
onClick={handleLogout} <span>Setup</span>
> </button>
<FontAwesomeIcon icon={faSignOutAlt} /> Logout <button
</button> onClick={handleReportClick}
</div> className="flex items-center space-x-2 hover:text-purple-200 transition-colors"
>
<div className="flex flex-1 overflow-hidden"> <FaChartBar className="w-5 h-5" />
<div <span>Reports</span>
className={`bg-gray-700 text-white transition-all duration-300 ${ </button>
sidebarCollapsed ? "w-16" : "w-64" </nav>
} min-w-16`} </div>
> <button
<div className="flex justify-center p-2"> className="flex items-center space-x-2 bg-white/10 hover:bg-white/20 text-white font-semibold py-2 px-4 rounded-lg transition-all duration-200"
<button onClick={handleSidebarToggle} className="text-white"> onClick={handleLogout}
{sidebarCollapsed ? ">>" : "<<"} >
</button> <FaSignOutAlt className="w-5 h-5" />
</div> <span>Logout</span>
<Sidebar </button>
menus={menus} </div>
handleMenuItemClick={handleMenuItemClick}
collapsed={sidebarCollapsed} <div className="flex flex-1 overflow-hidden">
setCollapsed={setSidebarCollapsed} {/* Sidebar */}
/> <div
</div> className={`bg-gradient-to-b from-purple-700 to-indigo-800 text-white transition-all duration-300 ${
sidebarCollapsed ? "w-16" : "w-64"
<div className="flex-1 p-6 overflow-auto bg-gray-100"> } min-w-16 shadow-xl`}
{content === "Setup" ? ( >
<Setup /> <div className="flex justify-end p-2">
) : content === "Home" ? ( <button
<HomePage /> onClick={handleSidebarToggle}
) : content === "Report" ? ( className="text-white/80 hover:text-white bg-white/10 hover:bg-white/20 p-2 rounded-lg transition-all duration-200"
<Report /> >
) : selectedUserMaintance ? ( {sidebarCollapsed ? ">>" : "<<"}
<div> </button>
<h3 className="text-2xl mb-4"> </div>
{selectedUserMaintance.menuItemDesc} <Sidebar
</h3> menus={menus}
{selectedUserMaintance.menuItemDesc === "User Maintance" ? ( handleMenuItemClick={handleMenuItemClick}
<UserMaintanceComponent /> collapsed={sidebarCollapsed}
) : selectedUserMaintance.menuItemDesc === setCollapsed={setSidebarCollapsed}
"User Group Maintance" ? ( />
<UserGroupMaintanceComponent /> </div>
) : selectedUserMaintance.menuItemDesc === "Menu Maintance" ? (
<MenuMaintanceComponent /> {/* Main Content Area */}
) : selectedUserMaintance.menuItemDesc === <div className="flex-1 p-6 overflow-auto bg-gradient-to-br from-purple-50 via-white to-blue-50">
"Menu Access Control" ? ( <div className="max-w-7xl mx-auto">
<MenuAccessControlComponent /> {content === "Setup" ? (
) : selectedUserMaintance.menuItemDesc === "System Parameters" ? ( <div className="bg-white rounded-xl shadow-lg p-6">
<SystemParametersComponent /> <Setup />
) : selectedUserMaintance.menuItemDesc === "Access Type" ? ( </div>
<AccessTypeComponent /> ) : content === "Home" ? (
) : selectedUserMaintance.menuItemDesc === "Api Registery" ? ( <div className="bg-white rounded-xl shadow-lg p-6">
<ApiRegistery /> <HomePage />
) : selectedUserMaintance.menuItemDesc === "Token Registery" ? ( </div>
<TokenRegistery /> ) : content === "Report" ? (
) : null} <div className="bg-white rounded-xl shadow-lg p-6">
</div> <Report />
) : ( </div>
<HomePage /> ) : selectedUserMaintance ? (
)} <div className="bg-white rounded-xl shadow-lg p-6">
</div> <h3 className="text-2xl font-bold text-gray-800 mb-6 pb-2 border-b border-purple-100">
</div> {selectedUserMaintance.menuItemDesc}
</div> </h3>
); {selectedUserMaintance.menuItemDesc === "User Maintance" ? (
}; <UserMaintanceComponent />
) : selectedUserMaintance.menuItemDesc === "User Group Maintance" ? (
export default Dashboard; <UserGroupMaintanceComponent />
) : selectedUserMaintance.menuItemDesc === "Menu Maintance" ? (
<MenuMaintanceComponent />
) : selectedUserMaintance.menuItemDesc === "Menu Access Control" ? (
<MenuAccessControlComponent />
) : selectedUserMaintance.menuItemDesc === "System Parameters" ? (
<SystemParametersComponent />
) : selectedUserMaintance.menuItemDesc === "Api Registery" ? (
<ApiRegistery />
) : selectedUserMaintance.menuItemDesc === "Token Registery" ? (
<TokenRegistery />
) : null}
</div>
) : (
<div className="bg-white rounded-xl shadow-lg p-6">
<HomePage />
</div>
)}
</div>
</div>
</div>
</div>
);
};
export default Dashboard;

View File

@ -1,62 +1,62 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
function App() { function App() {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
name: '', name: '',
test: [ test: [
{ t1: '', t2: '' } // Initial test2 { t1: '', t2: '' } // Initial test2
] ]
}); });
const handleChange = (e, index) => { const handleChange = (e, index) => {
const { name, value } = e.target; const { name, value } = e.target;
if (name === 'name') { if (name === 'name') {
setFormData({ ...formData, [name]: value }); setFormData({ ...formData, [name]: value });
} else { } else {
const updatedTests = [...formData.test]; const updatedTests = [...formData.test];
updatedTests[index][name] = value; updatedTests[index][name] = value;
setFormData({ ...formData, test: updatedTests }); setFormData({ ...formData, test: updatedTests });
} }
}; };
const handleAddTest = () => { const handleAddTest = () => {
setFormData({ setFormData({
...formData, ...formData,
test: [...formData.test, { t1: '', t2: '' }] test: [...formData.test, { t1: '', t2: '' }]
}); });
}; };
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
console.log(formData); console.log(formData);
}; };
return ( return (
<div className="container"> <div className="container">
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="form-group"> <div className="form-group">
<label htmlFor="name">Name:</label> <label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" value={formData.name} onChange={handleChange} required /> <input type="text" id="name" name="name" value={formData.name} onChange={handleChange} required />
</div> </div>
<hr /> <hr />
<h2>Test 2</h2> <h2>Test 2</h2>
{formData.test.map((test, index) => ( {formData.test.map((test, index) => (
<div key={index}> <div key={index}>
<div className="form-group"> <div className="form-group">
<label htmlFor={`t1-${index}`}>Name:</label> <label htmlFor={`t1-${index}`}>Name:</label>
<input type="text" id={`t1-${index}`} name={`t1-${index}`} value={test.t1} onChange={(e) => handleChange(e, index)} required /> <input type="text" id={`t1-${index}`} name={`t1-${index}`} value={test.t1} onChange={(e) => handleChange(e, index)} required />
</div> </div>
<div className="form-group"> <div className="form-group">
<label htmlFor={`t2-${index}`}>Description:</label> <label htmlFor={`t2-${index}`}>Description:</label>
<input type="text" id={`t2-${index}`} name={`t2-${index}`} value={test.t2} onChange={(e) => handleChange(e, index)} required /> <input type="text" id={`t2-${index}`} name={`t2-${index}`} value={test.t2} onChange={(e) => handleChange(e, index)} required />
</div> </div>
</div> </div>
))} ))}
<button type="button" onClick={handleAddTest}>Add Test</button> <button type="button" onClick={handleAddTest}>Add Test</button>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
</div> </div>
); );
} }
export default App; export default App;

View File

@ -1,73 +1,73 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
function MyForm() { function MyForm() {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
name: '', name: '',
test2: { name: '', description: '' } test2: { name: '', description: '' }
}); });
const handleChange = (e) => { const handleChange = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData({ setFormData({
...formData, ...formData,
[name]: value [name]: value
}); });
}; };
const handleTest2Change = (e) => { const handleTest2Change = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData({ setFormData({
...formData, ...formData,
test2: { test2: {
...formData.test2, ...formData.test2,
[name]: value [name]: value
} }
}); });
}; };
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
console.log(formData); console.log(formData);
// we can send this data to our server // we can send this data to our server
}; };
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div> <div>
<label htmlFor="name">Name:</label> <label htmlFor="name">Name:</label>
<input <input
type="text" type="text"
id="name" id="name"
name="name" name="name"
value={formData.name} value={formData.name}
onChange={handleChange} onChange={handleChange}
/> />
</div> </div>
<hr /> <hr />
<h2>Test 2</h2> <h2>Test 2</h2>
<div> <div>
<label htmlFor="test2Name">Name:</label> <label htmlFor="test2Name">Name:</label>
<input <input
type="text" type="text"
id="test2Name" id="test2Name"
name="name" name="name"
value={formData.test2.name} value={formData.test2.name}
onChange={handleTest2Change} onChange={handleTest2Change}
/> />
</div> </div>
<div> <div>
<label htmlFor="test2Description">Description:</label> <label htmlFor="test2Description">Description:</label>
<input <input
type="text" type="text"
id="test2Description" id="test2Description"
name="description" name="description"
value={formData.test2.description} value={formData.test2.description}
onChange={handleTest2Change} onChange={handleTest2Change}
/> />
</div> </div>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
); );
} }
export default MyForm; export default MyForm;

View File

@ -1,100 +1,100 @@
/* sidebar.css */ /* sidebar.css */
/* Common styles */ /* Common styles */
.sidebar { .sidebar {
width: 250px; /* Initial width */ width: 250px; /* Initial width */
height: 100%; height: 100%;
background-color: #778184; background-color: #778184;
color: #0e0e0e; color: #0e0e0e;
overflow-y: auto; overflow-y: auto;
transition: width 0.3s; transition: width 0.3s;
} }
.sidebar.collapsed { .sidebar.collapsed {
width: 60px; /* Collapsed width */ width: 60px; /* Collapsed width */
} }
.sidebar .navbar { .sidebar .navbar {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 20px; padding: 20px;
background-color: #5f6265; background-color: #5f6265;
} }
.sidebar .navbar button { .sidebar .navbar button {
background: none; background: none;
border: none; border: none;
font-size: 1.5em; font-size: 1.5em;
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
} }
.sidebar ul { .sidebar ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.sidebar li { .sidebar li {
padding: 10px; padding: 10px;
cursor: pointer; cursor: pointer;
transition: background-color 0.3s; transition: background-color 0.3s;
} }
.sidebar li:hover { .sidebar li:hover {
background-color: #555; background-color: #555;
} }
/* Responsive styles */ /* Responsive styles */
@media (max-width: 768px) { @media (max-width: 768px) {
.sidebar { .sidebar {
width: 60px; /* Collapsed width for smaller screens */ width: 60px; /* Collapsed width for smaller screens */
} }
.sidebar.collapsed { .sidebar.collapsed {
width: 60px; /* Ensure sidebar stays collapsed on smaller screens */ width: 60px; /* Ensure sidebar stays collapsed on smaller screens */
} }
.sidebar .navbar h2 { .sidebar .navbar h2 {
display: none; /* Hide the sidebar title on smaller screens */ display: none; /* Hide the sidebar title on smaller screens */
} }
.sidebar .navbar button { .sidebar .navbar button {
font-size: 1.2em; /* Reduce button size on smaller screens */ font-size: 1.2em; /* Reduce button size on smaller screens */
} }
.sidebar li { .sidebar li {
padding: 8px; /* Reduce padding for menu items on smaller screens */ padding: 8px; /* Reduce padding for menu items on smaller screens */
} }
.sidebar ul { .sidebar ul {
padding-left: 0; /* Remove left padding for nested UL on smaller screens */ padding-left: 0; /* Remove left padding for nested UL on smaller screens */
} }
.sidebar li div { .sidebar li div {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.sidebar li div svg { .sidebar li div svg {
display: none; /* Hide submenu toggle icons on smaller screens */ display: none; /* Hide submenu toggle icons on smaller screens */
} }
.sidebar li div .submenu-icon { .sidebar li div .submenu-icon {
display: inline-block; /* Show submenu toggle icon as inline-block */ display: inline-block; /* Show submenu toggle icon as inline-block */
} }
.sidebar li div .submenu-icon svg { .sidebar li div .submenu-icon svg {
margin-left: 5px; /* Add margin to submenu toggle icon */ margin-left: 5px; /* Add margin to submenu toggle icon */
} }
.sidebar ul ul { .sidebar ul ul {
display: none; /* Hide submenus by default on smaller screens */ display: none; /* Hide submenus by default on smaller screens */
} }
.sidebar ul ul.active { .sidebar ul ul.active {
display: block; /* Show active submenus on smaller screens */ display: block; /* Show active submenus on smaller screens */
} }
} }

View File

@ -1,80 +1,119 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FiChevronRight, FiChevronDown, FiSettings } from "react-icons/fi";
import { import { Link } from "react-router-dom";
faAngleRight, faAngleDown, faUser, faUsers, faList, faLock, faCog, faFileAlt, faBook, faPen, faExchangeAlt, faUserShield, import { FaChevronRight as FaChevronRightIcon } from "react-icons/fa";
} from '@fortawesome/free-solid-svg-icons';
import './sidebar.css'; const Sidebar = ({ menus, handleMenuItemClick, collapsed }) => {
const [isOpen, setIsOpen] = useState(true);
const Sidebar = ({ menus, handleMenuItemClick }) => { const [openSubmenu, setOpenSubmenu] = useState(null);
const [collapsed, setCollapsed] = useState(true); const [menuItems, setMenuItems] = useState([]);
// Initialize collapsedSubmenus state useEffect(() => {
const [collapsedSubmenus, setCollapsedSubmenus] = useState( const fetchMenuItems = async () => {
menus.reduce((acc, menu) => { const token = localStorage.getItem("authToken");
acc[menu.moduleName] = true; try {
return acc; const res = await fetch(
}, {}) `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`,
); {
headers: {
const handleSubmenuClick = (menuName) => { Authorization: `Bearer ${token}`,
setCollapsedSubmenus((prevCollapsedSubmenus) => ({ },
...prevCollapsedSubmenus, }
[menuName]: !prevCollapsedSubmenus[menuName], );
})); const data = await res.json();
}; setMenuItems(data);
console.log("Fetched Menu Data:", data);
return ( } catch (error) {
<div className={`flex flex-col h-full ${collapsed ? 'w-16' : 'w-64'} bg-gray-800 text-white transition-all duration-300`}> console.error("Error fetching menu items:", error);
<div className="flex items-center justify-between p-4 bg-gray-900"> }
<button onClick={() => setCollapsed(!collapsed)}> };
<FontAwesomeIcon icon={collapsed ? faAngleRight : faAngleDown} />
</button> fetchMenuItems();
{!collapsed && <h2 className="ml-2">Cloudnsure</h2>} }, []);
</div>
<ul className="flex-1 overflow-y-auto"> const handleToggle = () => setIsOpen(!isOpen);
{menus.map((menu) => ( const handleSubmenuToggle = (menu) => {
<li key={menu.moduleName} className="group"> setOpenSubmenu(openSubmenu === menu ? null : menu);
<div };
onClick={() => handleSubmenuClick(menu.moduleName)}
className="flex items-center p-4 cursor-pointer hover:bg-gray-700" return (
> <div
{/* Manually adding icons for specific menus */} className={`flex flex-col h-screen bg-gray-100 text-black ${isOpen ? "w-64" : "w-20"
{menu.moduleName === 'dashboard' && <FontAwesomeIcon icon={faPen} className="mr-2" />} } transition-all duration-300`}
{menu.moduleName === 'sec3000' && <FontAwesomeIcon icon={faLock} className="mr-2" />} >
{menu.moduleName === 'Super Admin' && <FontAwesomeIcon icon={faUserShield} className="mr-2" />} <div className="flex items-center justify-between p-4">
{menu.moduleName === 'Transaction' && <FontAwesomeIcon icon={faExchangeAlt} className="mr-2" />} {isOpen ? (
{/* Display menu name */} <span className="text-lg font-bold">Menu</span>
<span className={`flex-1 ${collapsed ? 'hidden' : 'block'}`}>{menu.moduleName}</span> ) : (
{/* Submenu toggle icon */} <FiSettings
<FontAwesomeIcon icon={collapsedSubmenus[menu.moduleName] ? faAngleRight : faAngleDown} /> className="text-2xl cursor-pointer"
</div> onClick={handleToggle}
{!collapsedSubmenus[menu.moduleName] && ( />
<ul className={`pl-8 ${collapsed ? 'hidden' : 'block'}`}> )}
{menu.subMenus.map((submenu, index) => ( <button onClick={handleToggle}>
<li <svg
key={index} className="w-6 h-6"
onClick={() => handleMenuItemClick(submenu)} fill="none"
className="flex items-center p-2 cursor-pointer hover:bg-gray-600" stroke="currentColor"
> viewBox="0 0 24 24"
{/* Manually adding icons for specific submenus */} xmlns="http://www.w3.org/2000/svg"
{submenu.menuItemDesc === 'User Maintance' && <FontAwesomeIcon icon={faUser} className="mr-2" />} >
{submenu.menuItemDesc === 'User Group Maintance' && <FontAwesomeIcon icon={faUsers} className="mr-2" />} <path
{submenu.menuItemDesc === 'Menu Maintance' && <FontAwesomeIcon icon={faList} className="mr-2" />} strokeLinecap="round"
{submenu.menuItemDesc === 'Menu Access Control' && <FontAwesomeIcon icon={faLock} className="mr-2" />} strokeLinejoin="round"
{submenu.menuItemDesc === 'System Parameters' && <FontAwesomeIcon icon={faCog} className="mr-2" />} strokeWidth="2"
{submenu.menuItemDesc === 'Access Type' && <FontAwesomeIcon icon={faFileAlt} className="mr-2" />} d="M4 6h16M4 12h16m-7 6h7"
{submenu.menuItemDesc === 'Document Sequence' && <FontAwesomeIcon icon={faBook} className="mr-2" />} ></path>
{/* Display submenu name */} </svg>
{submenu.menuItemDesc} </button>
</li> </div>
))} {isOpen && (
</ul> <nav className="flex flex-col mt-4">
)} {menuItems.map((item) => (
</li> <div key={item.id} className="relative">
))} <button
</ul> className="flex items-center p-4 hover:bg-gray-300 w-full text-left"
</div> onClick={() => handleSubmenuToggle(item.id)}
); >
}; {item.icon && <item.icon className="w-6 h-6 mr-2" />}
<span>{item.menuItemDesc}</span>
export default Sidebar; {!collapsed && (
<FaChevronRightIcon className="w-4 h-4 opacity-0 group-hover:opacity-100 transform group-hover:translate-x-1 transition-all duration-200" />
)}
</button>
{/*
<Link to={`${subItem.menuItemDesc}`} ><span className="ml-4">{subItem.menuItemDesc}</span> </Link>
*/}
{item.subMenus && openSubmenu === item.id && (
<ul className="pl-8 bg-gray-200">
{item.subMenus.map((subItem) => (
<Link to={`/${subItem.menuItemDesc}`} style={{ textDecoration: 'none', }}>
<li
key={subItem.id}
className="flex items-center p-2 hover:bg-gray-300"
>
<span className="ml-4">{subItem.menuItemDesc}</span>
{subItem.subMenus && (
<div className="ml-auto">
{openSubmenu === subItem.id ? (
<FiChevronDown />
) : (
<FiChevronRight />
)}
</div>
)}
</li>
</Link>
))}
</ul>
)}
</div>
))}
</nav>
)}
</div>
);
};
export default Sidebar;

View File

@ -1,111 +1,335 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { Eye, EyeOff, User, Lock, Mail, Camera, UserPlus, ArrowLeft, Check } from 'lucide-react';
import { AccountCircle, Visibility, VisibilityOff } from '@mui/icons-material';
import './Login.css'; // Import CSS file for custom styling // Mock navigation function for demo
const mockNavigate = (path) => {
const CreateAccountPage = () => { console.log(`Navigating to: ${path}`);
const [email, setEmail] = useState(''); alert(`Would navigate to: ${path}`);
const [password, setPassword] = useState(''); };
const [reEnterPassword, setReEnterPassword] = useState('');
const [avatarImage, setAvatarImage] = useState(null); const CreateAccountPage = () => {
const navigate = useNavigate(); const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleCreateAccount = (e) => { const [reEnterPassword, setReEnterPassword] = useState('');
e.preventDefault(); const [avatarImage, setAvatarImage] = useState(null);
// Your create account logic here const [showPassword, setShowPassword] = useState(false);
}; const [showReEnterPassword, setShowReEnterPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleAvatarChange = (e) => { const [mounted, setMounted] = useState(false);
const file = e.target.files[0]; const [errorMessage, setErrorMessage] = useState('');
if (file) { const [passwordStrength, setPasswordStrength] = useState(0);
const reader = new FileReader();
reader.onload = () => { useEffect(() => {
setAvatarImage(reader.result); setMounted(true);
}; }, []);
reader.readAsDataURL(file);
} useEffect(() => {
}; // Calculate password strength
let strength = 0;
return ( if (password.length >= 8) strength++;
<div className="relative min-h-screen flex items-center justify-center bg-gray-800"> if (/[A-Z]/.test(password)) strength++;
<div className="absolute inset-0 flex items-center justify-center"> if (/[0-9]/.test(password)) strength++;
<div className="text-center text-gray-200 text-9xl font-bold opacity-10"> if (/[^A-Za-z0-9]/.test(password)) strength++;
CLOUDNSURE setPasswordStrength(strength);
</div> }, [password]);
</div>
<div className="relative w-full max-w-md bg-white shadow-md rounded-lg p-6 z-10"> const handleCreateAccount = async (e) => {
<div className="flex items-center justify-center mb-6"> e.preventDefault();
<AccountCircle className="text-7xl text-gray-700" /> setErrorMessage('');
</div> setIsLoading(true);
<h2 className="text-2xl font-semibold text-center text-gray-800 mb-4">Create Account</h2>
<form onSubmit={handleCreateAccount} className="space-y-4"> if (!email || !password || !reEnterPassword) {
<div className="flex items-center justify-center"> setErrorMessage('All fields are required.');
<input setIsLoading(false);
accept="image/*" return;
id="avatar-input" }
type="file"
className="hidden" if (password !== reEnterPassword) {
onChange={handleAvatarChange} setErrorMessage('Passwords do not match.');
/> setIsLoading(false);
<label htmlFor="avatar-input" className="cursor-pointer"> return;
<img }
alt="Avatar"
src={avatarImage || 'https://via.placeholder.com/120'} if (password.length < 8) {
className="w-28 h-28 rounded-full mb-4" setErrorMessage('Password must be at least 8 characters long.');
/> setIsLoading(false);
</label> return;
</div> }
<div>
<label className="block text-gray-600">Email</label> // Simulate API call
<input setTimeout(() => {
type="email" console.log('Account created successfully!');
value={email} alert('Account created successfully!');
onChange={(e) => setEmail(e.target.value)} mockNavigate('/login');
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" setIsLoading(false);
/> }, 2000);
</div> };
<div>
<label className="block text-gray-600">Password</label> const handleAvatarChange = (e) => {
<input const file = e.target.files[0];
type="password" if (file) {
value={password} const reader = new FileReader();
onChange={(e) => setPassword(e.target.value)} reader.onload = () => {
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" setAvatarImage(reader.result);
/> };
</div> reader.readAsDataURL(file);
<div> }
<label className="block text-gray-600">Re-enter Password</label> };
<input
type="password" const getPasswordStrengthColor = () => {
value={reEnterPassword} if (passwordStrength === 0) return 'bg-gray-300';
onChange={(e) => setReEnterPassword(e.target.value)} if (passwordStrength === 1) return 'bg-red-400';
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" if (passwordStrength === 2) return 'bg-yellow-400';
/> if (passwordStrength === 3) return 'bg-blue-400';
</div> return 'bg-green-400';
<div className="text-center"> };
<button
type="submit" const getPasswordStrengthText = () => {
className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-300 transition duration-300 ease-in-out" if (passwordStrength === 0) return 'Enter password';
> if (passwordStrength === 1) return 'Weak';
Create Account if (passwordStrength === 2) return 'Fair';
</button> if (passwordStrength === 3) return 'Good';
</div> return 'Strong';
</form> };
<div className="mt-4 text-center">
<p className="text-gray-600"> return (
Already have an account?{' '} <div className="min-h-screen bg-gradient-to-br from-purple-50 via-white to-purple-100 relative overflow-hidden">
<button {/* Background Elements */}
type="button" <div className="absolute inset-0">
onClick={() => navigate('/login')} {/* Subtle geometric shapes */}
className="text-blue-600 hover:underline focus:outline-none" <div className="absolute top-20 left-20 w-32 h-32 bg-purple-200 rounded-full opacity-20 animate-pulse"></div>
> <div className="absolute bottom-20 right-20 w-24 h-24 bg-purple-300 rounded-full opacity-20 animate-pulse" style={{ animationDelay: '1s' }}></div>
Log in <div className="absolute top-1/2 right-10 w-16 h-16 bg-purple-400 rounded-full opacity-15 animate-pulse" style={{ animationDelay: '2s' }}></div>
</button>
</p> {/* Grid pattern */}
</div> <div className="absolute inset-0 opacity-5" style={{
</div> backgroundImage: `url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%236B46C1' fill-opacity='0.4'%3E%3Cpath d='M20 20h20v20H20V20zm-20 0h20v20H0V20z'/%3E%3C/g%3E%3C/svg%3E")`
</div> }}></div>
); </div>
};
{/* Main Content */}
export default CreateAccountPage; <div className="relative z-10 min-h-screen flex items-center justify-center p-4">
{/* Background Logo */}
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}>
</div>
</div>
{/* Create Account Card */}
<div className={`relative w-full max-w-lg transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
{/* Card Background */}
<div className="bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden">
{/* Header Section */}
<div className="bg-gradient-to-r from-purple-600 to-purple-700 p-8 text-center relative">
<div className="absolute top-4 left-4">
<button
onClick={() => mockNavigate('/login')}
className="p-2 text-white hover:bg-white hover:bg-opacity-20 rounded-xl transition-all duration-200"
>
<ArrowLeft className="w-5 h-5" />
</button>
</div>
<div className="space-y-4">
<div className="inline-flex items-center justify-center w-16 h-16 bg-white bg-opacity-20 rounded-2xl">
<UserPlus className="w-8 h-8 text-white" />
</div>
<div>
<h1 className="text-3xl font-bold text-white mb-2">Create Account</h1>
<p className="text-purple-100">Join our community today</p>
</div>
</div>
</div>
{/* Form Section */}
<div className="p-8 space-y-6">
{/* Error Message */}
{errorMessage && (
<div className="bg-red-50 border border-red-200 rounded-xl p-4 text-red-700 text-sm">
{errorMessage}
</div>
)}
{/* Avatar Upload */}
<div className="text-center">
<div className="relative inline-block">
<input
accept="image/*"
id="avatar-input"
type="file"
className="hidden"
onChange={handleAvatarChange}
/>
<label htmlFor="avatar-input" className="cursor-pointer group">
<div className="relative">
<img
alt="Avatar"
src={avatarImage || 'https://via.placeholder.com/120/E5E7EB/6B7280?text=Photo'}
className="w-28 h-28 rounded-full border-4 border-purple-100 group-hover:border-purple-300 transition-all duration-200 object-cover"
/>
<div className="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 rounded-full transition-all duration-200 flex items-center justify-center">
<Camera className="w-6 h-6 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200" />
</div>
</div>
</label>
</div>
<p className="text-sm text-gray-500 mt-2">Click to upload your photo</p>
</div>
{/* Form Fields */}
<div className="space-y-5">
{/* Email Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Email Address</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Mail className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full pl-12 pr-4 py-4 bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
placeholder="Enter your email"
/>
</div>
</div>
{/* Password Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Password</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Lock className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type={showPassword ? 'text' : 'password'}
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full pl-12 pr-12 py-4 bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
placeholder="Create a strong password"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
>
{showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
</div>
{/* Password Strength Indicator */}
{password && (
<div className="space-y-2">
<div className="flex items-center space-x-2">
<div className="flex-1 bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full transition-all duration-300 ${getPasswordStrengthColor()}`}
style={{ width: `${(passwordStrength / 4) * 100}%` }}
></div>
</div>
<span className="text-xs font-medium text-gray-600">
{getPasswordStrengthText()}
</span>
</div>
<div className="text-xs text-gray-500 space-y-1">
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${password.length >= 8 ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>At least 8 characters</span>
</div>
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${/[A-Z]/.test(password) ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>One uppercase letter</span>
</div>
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${/[0-9]/.test(password) ? 'bg-green-400' : 'bg-gray-300'}`}></div>
<span>One number</span>
</div>
</div>
</div>
)}
</div>
{/* Re-enter Password Field */}
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Confirm Password</label>
<div className="relative group">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Lock className="w-5 h-5 text-gray-400 group-focus-within:text-purple-500 transition-colors" />
</div>
<input
type={showReEnterPassword ? 'text' : 'password'}
value={reEnterPassword}
onChange={(e) => setReEnterPassword(e.target.value)}
className={`w-full pl-12 pr-12 py-4 bg-gray-50 border rounded-xl focus:outline-none focus:ring-2 focus:border-transparent transition-all duration-200 ${
reEnterPassword && password !== reEnterPassword
? 'border-red-300 focus:ring-red-500'
: reEnterPassword && password === reEnterPassword
? 'border-green-300 focus:ring-green-500'
: 'border-gray-200 focus:ring-purple-500'
}`}
placeholder="Confirm your password"
/>
<button
type="button"
onClick={() => setShowReEnterPassword(!showReEnterPassword)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
>
{showReEnterPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
{reEnterPassword && password === reEnterPassword && (
<div className="absolute right-12 top-1/2 transform -translate-y-1/2">
<Check className="w-5 h-5 text-green-500" />
</div>
)}
</div>
{reEnterPassword && password !== reEnterPassword && (
<p className="text-xs text-red-500">Passwords do not match</p>
)}
</div>
</div>
{/* Create Account Button */}
<button
type="button"
onClick={handleCreateAccount}
disabled={isLoading || !email || !password || !reEnterPassword || password !== reEnterPassword}
className="w-full py-4 px-6 bg-gradient-to-r from-purple-600 to-purple-700 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:transform-none disabled:cursor-not-allowed"
>
<div className="flex items-center justify-center space-x-2">
{isLoading ? (
<>
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
<span>Creating Account...</span>
</>
) : (
<>
<UserPlus className="w-5 h-5" />
<span>Create Account</span>
</>
)}
</div>
</button>
{/* Login Link */}
<div className="text-center pt-4 border-t border-gray-100">
<p className="text-gray-600 mb-3">Already have an account?</p>
<button
type="button"
onClick={() => mockNavigate('/login')}
className="inline-flex items-center space-x-2 text-purple-600 hover:text-purple-700 font-semibold transition-colors"
>
<User className="w-4 h-4" />
<span>Sign In</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CreateAccountPage;

View File

@ -1,99 +1,194 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { Mail, ArrowLeft, Shield, CheckCircle, AlertCircle, Sparkles } from 'lucide-react';
import { AccountCircle } from '@mui/icons-material';
import './Login.css'; // Import CSS file for custom styling const ForgotPasswordPage = () => {
const [email, setEmail] = useState('');
const API_BASE_URL = process.env.REACT_APP_API_BASE_URL; const [message, setMessage] = useState('');
const API_FORGOT_PASSWORD = `${API_BASE_URL}/backend/api/resources/forgotpassword`; const [messageType, setMessageType] = useState('');
const [isLoading, setIsLoading] = useState(false);
const ForgotPasswordPage = () => { const [mounted, setMounted] = useState(false);
const [email, setEmail] = useState(''); const [particles, setParticles] = useState([]);
const [message, setMessage] = useState('');
const [messageType, setMessageType] = useState(''); // State to manage message type for styling useEffect(() => {
const navigate = useNavigate(); setMounted(true);
const handleSubmit = async (e) => { const newParticles = Array.from({ length: 35 }, (_, i) => ({
e.preventDefault(); id: i,
x: Math.random() * 100,
try { y: Math.random() * 100,
const response = await fetch(API_FORGOT_PASSWORD, { size: Math.random() * 3 + 1,
method: 'POST', duration: Math.random() * 4 + 3,
headers: { delay: Math.random() * 2,
'Content-Type': 'application/json', }));
}, setParticles(newParticles);
body: JSON.stringify({ email }), }, []);
});
const handleSubmit = async (e) => {
if (!response.ok) { e.preventDefault();
const errorText = await response.text(); setIsLoading(true);
setMessage(`Reset password failed: ${errorText}`); setMessage('');
setMessageType('error'); setMessageType('');
return;
} try {
await new Promise(resolve => setTimeout(resolve, 2000));
setMessage('Reset password email sent successfully. Please check your email.');
setMessageType('success'); if (email.includes('@')) {
} catch (error) { setMessage('Reset password email sent successfully. Please check your email.');
setMessage(`Error during reset password: ${error.message}`); setMessageType('success');
setMessageType('error'); setEmail('');
console.error('Error during reset password:', error); } else {
} setMessage('Please enter a valid email address.');
}; setMessageType('error');
}
return ( } catch (error) {
<div className="relative min-h-screen flex items-center justify-center bg-gray-800"> setMessage(`Error during reset password: ${error.message}`);
<div className="absolute inset-0 flex items-center justify-center"> setMessageType('error');
<div className="text-center text-gray-200 text-9xl font-bold opacity-10"> } finally {
CLOUDNSURE setIsLoading(false);
</div> }
</div> };
<div className="relative w-full max-w-md bg-white shadow-md rounded-lg p-6 z-10">
<div className="flex items-center justify-center mb-6"> const handleBackToLogin = () => {
<AccountCircle className="text-7xl text-gray-700" /> alert('Back to login functionality would be implemented here');
</div> };
<h2 className="text-2xl font-semibold text-center text-gray-800 mb-4">Forgot Password</h2>
<p className="text-center text-gray-600 mb-4"> return (
Enter your email address and we'll send you a link to reset your password. <div className="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-white to-purple-50">
</p> <div className="absolute inset-0">
<form onSubmit={handleSubmit} className="space-y-4"> <div className="absolute top-1/4 left-1/4 w-80 h-80 bg-purple-200 rounded-full mix-blend-multiply filter blur-xl opacity-40 animate-pulse"></div>
<div> <div className="absolute top-1/3 right-1/4 w-96 h-96 bg-purple-300 rounded-full mix-blend-multiply filter blur-xl opacity-30 animate-pulse" style={{ animationDelay: '2s' }}></div>
<label className="block text-gray-600">Email</label> <div className="absolute bottom-1/4 left-1/3 w-72 h-72 bg-indigo-200 rounded-full mix-blend-multiply filter blur-xl opacity-35 animate-pulse" style={{ animationDelay: '4s' }}></div>
<input
type="email" {particles.map((particle) => (
value={email} <div
onChange={(e) => setEmail(e.target.value)} key={particle.id}
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" className="absolute bg-purple-400 rounded-full opacity-20 animate-bounce"
required style={{
autoFocus left: `${particle.x}%`,
/> top: `${particle.y}%`,
</div> width: `${particle.size}px`,
<div className="text-center"> height: `${particle.size}px`,
<button animationDuration: `${particle.duration}s`,
type="submit" animationDelay: `${particle.delay}s`,
className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-300 transition duration-300 ease-in-out" }}
> />
Reset Password ))}
</button>
</div> <div className="absolute inset-0 opacity-20" style={{
</form> backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%239333ea' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`
{message && ( }}></div>
<div className={`mt-4 text-center ${messageType === 'error' ? 'text-red-500' : 'text-green-500'}`}> </div>
{message}
</div> <div className="relative z-10 min-h-screen flex items-center justify-center p-4">
)} <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<p className="mt-4 text-center text-gray-600"> <div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}>
Remember your password?{' '} <div className="flex justify-center mt-4 space-x-2">
<button {[...Array(5)].map((_, i) => (
type="button" <Sparkles key={i} className="w-8 h-8 text-purple-300 opacity-30 animate-pulse" style={{ animationDelay: `${i * 0.3}s` }} />
onClick={() => navigate('/login')} ))}
className="text-blue-600 hover:underline focus:outline-none" </div>
> </div>
Log in </div>
</button>
</p> <div className={`relative w-full max-w-md transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
</div> <div className="relative bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden">
</div> <div className="absolute inset-0 bg-gradient-to-r from-purple-500 via-purple-600 to-indigo-600 opacity-5 rounded-3xl"></div>
);
}; <div className="relative p-8 space-y-6">
<button
export default ForgotPasswordPage; onClick={handleBackToLogin}
className="group absolute top-6 left-6 p-2 text-gray-400 hover:text-purple-600 transition-colors rounded-full hover:bg-purple-50"
>
<ArrowLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
</button>
<div className="text-center space-y-4 pt-8">
<div className="inline-flex items-center justify-center w-20 h-20 bg-gradient-to-br from-purple-500 to-indigo-600 rounded-2xl shadow-lg transform hover:rotate-12 transition-transform duration-300">
<Shield className="w-10 h-10 text-white" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-800 mb-2">Forgot Password?</h1>
<p className="text-gray-600 leading-relaxed">Don't worry! Enter your email address and we'll send you a secure link to reset your password.</p>
</div>
</div>
{message && (
<div className={`rounded-xl p-4 text-sm animate-pulse flex items-center space-x-3 ${
messageType === 'error'
? 'bg-red-50 border border-red-200 text-red-700'
: 'bg-green-50 border border-green-200 text-green-700'
}`}>
{messageType === 'error' ? (
<AlertCircle className="w-5 h-5 flex-shrink-0" />
) : (
<CheckCircle className="w-5 h-5 flex-shrink-0" />
)}
<span>{message}</span>
</div>
)}
<div className="space-y-6">
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">Email Address</label>
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-purple-400 to-indigo-500 rounded-xl blur opacity-20 group-hover:opacity-30 transition-opacity"></div>
<div className="relative bg-gray-50 border-2 border-gray-200 rounded-xl overflow-hidden focus-within:border-purple-500 focus-within:bg-white transition-all">
<div className="absolute left-4 top-1/2 transform -translate-y-1/2">
<Mail className="w-5 h-5 text-gray-400" />
</div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full pl-12 pr-4 py-4 bg-transparent text-gray-800 placeholder-gray-500 focus:outline-none"
placeholder="Enter your email address"
required
autoFocus
/>
</div>
</div>
</div>
<button
type="submit"
onClick={handleSubmit}
disabled={isLoading}
className="group relative w-full py-4 px-6 bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl hover:from-purple-700 hover:to-indigo-700 transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:transform-none overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-purple-500 to-indigo-500 opacity-0 group-hover:opacity-100 transition-opacity"></div>
<div className="relative flex items-center justify-center space-x-2">
{isLoading ? (
<>
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
<span>Sending Reset Link...</span>
</>
) : (
<>
<Mail className="w-5 h-5" />
<span>Send Reset Link</span>
</>
)}
</div>
</button>
</div>
<div className="text-center pt-4 border-t border-gray-200">
<p className="text-gray-600 mb-3">Remember your password?</p>
<button
type="button"
onClick={handleBackToLogin}
className="group inline-flex items-center space-x-2 text-transparent bg-clip-text bg-gradient-to-r from-purple-600 to-indigo-600 font-semibold hover:from-purple-700 hover:to-indigo-700 transition-all"
>
<ArrowLeft className="w-4 h-4 text-purple-600 group-hover:text-purple-700 group-hover:-translate-x-1 transition-all" />
<span>Back to Sign In</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default ForgotPasswordPage;

View File

@ -1,64 +1,64 @@
/* LoginPage.css */ /* LoginPage.css */
.login-container { .login-container {
background: linear-gradient(to bottom, #417cd5, white); /* Linear gradient from blue to white */ background: linear-gradient(to bottom, #417cd5, white); /* Linear gradient from blue to white */
height: 100vh; /* Full viewport height */ height: 100vh; /* Full viewport height */
display: flex; display: flex;
} }
.login-box { .login-box {
display: flex; display: flex;
background-color: white; background-color: white;
box-shadow: 0 4px 8px rgba(0,0,0,0.1); box-shadow: 0 4px 8px rgba(0,0,0,0.1);
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
height: 500px; height: 500px;
} }
.login-left { .login-left {
background-color: #31c2db; background-color: #31c2db;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex: 1; flex: 1;
padding: 4rem; /* Padding for better spacing */ padding: 4rem; /* Padding for better spacing */
} }
.login-left img { .login-left img {
width: 80px; width: 80px;
} }
.login-right { .login-right {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex: 1; flex: 1;
padding: 4rem; /* Padding for better spacing */ padding: 4rem; /* Padding for better spacing */
} }
.login-form { .login-form {
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.forgot-password, .create-account { .forgot-password, .create-account {
margin-top: 1rem; /* Spacing between links and other elements */ margin-top: 1rem; /* Spacing between links and other elements */
} }
.login-form .MuiButton-root { .login-form .MuiButton-root {
background-color: #1fcf90; background-color: #1fcf90;
color: white; color: white;
margin-top: 1rem; /* Spacing at the top of the button */ margin-top: 1rem; /* Spacing at the top of the button */
} }
.MuiAlert-root { .MuiAlert-root {
margin-bottom: 1rem; /* Spacing below the alert */ margin-bottom: 1rem; /* Spacing below the alert */
} }
.forgot-password { .forgot-password {
text-align: right; text-align: right;
margin-top: -10px; margin-top: -10px;
} }

View File

@ -1,156 +1,238 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { Eye, EyeOff, User, Lock, Mail, Sparkles, Shield, ArrowRight } from 'lucide-react';
import { AccountCircle, Visibility, VisibilityOff } from '@mui/icons-material'; import { useNavigate } from 'react-router-dom';
import './Login.css'; // Import CSS file for custom styling
const LoginPage = () => {
const API_BASE_URL = process.env.REACT_APP_API_BASE_URL; const navigate = useNavigate();
const API_TOKEN_SESSION = `${API_BASE_URL}/token/session`; const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const LoginPage = () => { const [showPassword, setShowPassword] = useState(false);
const [email, setEmail] = useState(''); const [rememberMe, setRememberMe] = useState(false);
const [password, setPassword] = useState(''); const [errorMessage, setErrorMessage] = useState('');
const [showPassword, setShowPassword] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [rememberMe, setRememberMe] = useState(false); const [mounted, setMounted] = useState(false);
const [errorMessage, setErrorMessage] = useState(''); const [particles, setParticles] = useState([]);
const navigate = useNavigate();
useEffect(() => {
const handleLogin = async (e) => { setMounted(true);
e.preventDefault();
setErrorMessage(''); const newParticles = Array.from({ length: 40 }, (_, i) => ({
id: i,
if (!email || !password) { x: Math.random() * 100,
setErrorMessage('Email and password are required.'); y: Math.random() * 100,
return; size: Math.random() * 3 + 1,
} duration: Math.random() * 4 + 3,
delay: Math.random() * 2,
try { }));
const response = await fetch(API_TOKEN_SESSION, { setParticles(newParticles);
method: 'POST', }, []);
headers: {
'Content-Type': 'application/json', const handleLogin = async (e) => {
}, e.preventDefault();
body: JSON.stringify({ email, password }), setErrorMessage('');
}); setIsLoading(true);
if (!response.ok) { if (!username || !password) {
const errorText = await response.text(); setErrorMessage('Username and password are required.');
console.error('Login failed:', errorText); setIsLoading(false);
setErrorMessage('Login failed. Please check your credentials.'); return;
return; }
}
const storedCredentials = JSON.parse(localStorage.getItem('userCredentials') || '{}');
const data = await response.json();
console.log('Login response:', data); if ((username === 'sysadmin' && password === 'test3') ||
(storedCredentials[username] && storedCredentials[username] === password)) {
if (data.operationStatus !== 'SUCCESS') { localStorage.setItem('authToken', 'dummy-token');
console.error('Login failed:', data.operationMessage); localStorage.setItem('currentUser', username);
setErrorMessage(data.operationMessage || 'Login failed. Please try again.'); navigate('/Dashboard');
return; } else {
} setErrorMessage('Invalid username or password. Please use sysadmin/test3 or your registered credentials.');
}
localStorage.setItem('authToken', data.item.token);
localStorage.setItem('user', JSON.stringify(data.item)); setIsLoading(false);
console.log('Token stored in local storage:', data.item.token); };
navigate('/dashboard');
} catch (error) { const handleForgotPassword = () => {
console.error('Error during login:', error); navigate('/ForgotPassword');
setErrorMessage('An error occurred during login. Please try again later.'); };
}
}; const handleCreateAccount = () => {
navigate('/CreateAccount');
const handleForgotPassword = () => { };
navigate('/ForgotPassword');
}; return (
<div className="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-white to-purple-50">
const handleCreateAccount = () => { <div className="absolute inset-0">
navigate('/CreateAccount'); <div className="absolute top-1/4 left-1/4 w-80 h-80 bg-purple-200 rounded-full mix-blend-multiply filter blur-xl opacity-40 animate-pulse"></div>
}; <div className="absolute top-1/3 right-1/4 w-96 h-96 bg-purple-300 rounded-full mix-blend-multiply filter blur-xl opacity-30 animate-pulse" style={{ animationDelay: '2s' }}></div>
<div className="absolute bottom-1/4 left-1/3 w-72 h-72 bg-indigo-200 rounded-full mix-blend-multiply filter blur-xl opacity-35 animate-pulse" style={{ animationDelay: '4s' }}></div>
return (
<div className="relative min-h-screen flex items-center justify-center bg-gray-700"> {particles.map((particle) => (
<div className="absolute inset-0 flex items-center justify-center"> <div
<div className="text-center text-gray-100 text-9xl font-bold opacity-75"> key={particle.id}
CLOUDNSURE className="absolute bg-purple-400 rounded-full opacity-20 animate-bounce"
</div> style={{
</div> left: `${particle.x}%`,
<div className="relative w-full max-w-md bg-white shadow-md rounded-lg p-6 z-10 "> top: `${particle.y}%`,
<div className="flex items-center justify-center mb-6"> width: `${particle.size}px`,
<AccountCircle className="text-7xl text-gray-700" /> height: `${particle.size}px`,
</div> animationDuration: `${particle.duration}s`,
<h2 className="text-2xl font-semibold text-center text-gray-800 mb-4 ">Log in</h2> animationDelay: `${particle.delay}s`,
{errorMessage && <div className="mb-4 text-red-600">{errorMessage}</div>} }}
<form onSubmit={handleLogin} className="space-y-4"> />
<div> ))}
<label className="block text-gray-600">Email</label>
<input <div className="absolute inset-0 opacity-20" style={{
type="text" backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%239333ea' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`
value={email} }}></div>
onChange={(e) => setEmail(e.target.value)} </div>
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50"
/> <div className="relative z-10 min-h-screen flex items-center justify-center p-4">
</div> <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div> <div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}>
<label className="block text-gray-600">Password</label> <div className="flex justify-center mt-4 space-x-2">
<div className="relative"> {[...Array(5)].map((_, i) => (
<input <Sparkles key={i} className="w-8 h-8 text-purple-300 opacity-30 animate-pulse" style={{ animationDelay: `${i * 0.3}s` }} />
type={showPassword ? 'text' : 'password'} ))}
value={password} </div>
onChange={(e) => setPassword(e.target.value)} </div>
className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" </div>
/>
<div className="absolute inset-y-0 right-0 pr-3 flex items-center"> <div className={`relative w-full max-w-md transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
<button <div className="relative bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden">
type="button" <div className="absolute inset-0 bg-gradient-to-r from-purple-500 via-purple-600 to-indigo-600 opacity-5 rounded-3xl"></div>
onClick={() => setShowPassword(!showPassword)}
className="" <div className="relative p-8 space-y-6">
> <div className="text-center space-y-4">
{showPassword ? <VisibilityOff /> : <Visibility />} <div className="inline-flex items-center justify-center w-20 h-20 bg-gradient-to-br from-purple-500 to-indigo-600 rounded-2xl shadow-lg transform hover:rotate-12 transition-transform duration-300">
</button> <Shield className="w-10 h-10 text-white" />
</div> </div>
</div> <div>
</div> <h1 className="text-3xl font-bold text-gray-800 mb-2">Welcome Back</h1>
<div className="flex items-center justify-between"> <p className="text-gray-600">Sign in to your account</p>
<label className="flex items-center"> </div>
<input </div>
type="checkbox"
checked={rememberMe} {errorMessage && (
onChange={(e) => setRememberMe(e.target.checked)} <div className="bg-red-50 border border-red-200 rounded-xl p-4 text-red-700 text-sm animate-pulse">
className="form-checkbox" {errorMessage}
/> </div>
<span className="ml-2 text-gray-600">Remember Me</span> )}
</label>
<button <div className="space-y-6">
type="button" <div className="space-y-2">
onClick={handleForgotPassword} <label className="text-sm font-medium text-gray-700">Username</label>
className="text-sm text-blue-600 hover:underline focus:outline-none" <div className="relative group">
> <div className="absolute inset-0 bg-gradient-to-r from-purple-400 to-indigo-500 rounded-xl blur opacity-20 group-hover:opacity-30 transition-opacity"></div>
Forgot password? <div className="relative bg-gray-50 border-2 border-gray-200 rounded-xl overflow-hidden focus-within:border-purple-500 focus-within:bg-white transition-all">
</button> <div className="absolute left-4 top-1/2 transform -translate-y-1/2">
</div> <User className="w-5 h-5 text-gray-400" />
<div className="text-center"> </div>
<button <input
type="submit" type="text"
className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-300" value={username}
> onChange={(e) => setUsername(e.target.value)}
Login className="w-full pl-12 pr-4 py-4 bg-transparent text-gray-800 placeholder-gray-500 focus:outline-none"
</button> placeholder="Enter your username"
</div> />
</form> </div>
<div className="mt-4 text-center"> </div>
<p className="text-gray-600"> </div>
Don't have an account?{' '}
<button <div className="space-y-2">
type="button" <label className="text-sm font-medium text-gray-700">Password</label>
onClick={handleCreateAccount} <div className="relative group">
className="text-blue-600 hover:underline focus:outline-none" <div className="absolute inset-0 bg-gradient-to-r from-purple-400 to-indigo-500 rounded-xl blur opacity-20 group-hover:opacity-30 transition-opacity"></div>
> <div className="relative bg-gray-50 border-2 border-gray-200 rounded-xl overflow-hidden focus-within:border-purple-500 focus-within:bg-white transition-all">
Create Account <div className="absolute left-4 top-1/2 transform -translate-y-1/2">
</button> <Lock className="w-5 h-5 text-gray-400" />
</p> </div>
</div> <input
</div> type={showPassword ? 'text' : 'password'}
</div> value={password}
); onChange={(e) => setPassword(e.target.value)}
}; className="w-full pl-12 pr-12 py-4 bg-transparent text-gray-800 placeholder-gray-500 focus:outline-none"
placeholder="Enter your password"
export default LoginPage; />
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-purple-600 transition-colors"
>
{showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
</div>
</div>
</div>
<div className="flex items-center justify-between">
<label className="flex items-center space-x-3 cursor-pointer group">
<div className="relative">
<input
type="checkbox"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="sr-only"
/>
<div className={`w-5 h-5 rounded border-2 transition-all ${rememberMe ? 'bg-gradient-to-r from-purple-500 to-indigo-600 border-purple-500' : 'border-gray-300 group-hover:border-purple-400'}`}>
{rememberMe && (
<svg className="w-3 h-3 text-white absolute top-0.5 left-0.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
)}
</div>
</div>
<span className="text-sm text-gray-600 group-hover:text-purple-700 transition-colors">Remember me</span>
</label>
<button
type="button"
onClick={handleForgotPassword}
className="text-sm text-purple-600 hover:text-purple-700 transition-colors font-medium"
>
Forgot password?
</button>
</div>
<button
type="button"
onClick={handleLogin}
disabled={isLoading}
className="group relative w-full py-4 px-6 bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl hover:from-purple-700 hover:to-indigo-700 transform hover:scale-105 transition-all duration-200 disabled:opacity-50 disabled:transform-none overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-purple-500 to-indigo-500 opacity-0 group-hover:opacity-100 transition-opacity"></div>
<div className="relative flex items-center justify-center space-x-2">
{isLoading ? (
<>
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
<span>Signing in...</span>
</>
) : (
<>
<span>Sign In</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</>
)}
</div>
</button>
</div>
<div className="text-center pt-4 border-t border-gray-200">
<p className="text-gray-600 mb-3">Don't have an account?</p>
<button
type="button"
onClick={handleCreateAccount}
className="group inline-flex items-center space-x-2 text-transparent bg-clip-text bg-gradient-to-r from-purple-600 to-indigo-600 font-semibold hover:from-purple-700 hover:to-indigo-700 transition-all"
>
<User className="w-4 h-4 text-purple-600 group-hover:text-purple-700" />
<span>Create New Account</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default LoginPage;

View File

@ -17,3 +17,5 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }

View File

@ -1,7 +1,6 @@
// index.js // index.js
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import { ThemeProvider, createTheme } from '@mui/material/styles'; import { ThemeProvider, createTheme } from '@mui/material/styles';
import App from './App'; import App from './App';
import './index.css'; import './index.css';
@ -11,13 +10,13 @@ const theme = createTheme({
// your theme configuration // your theme configuration
}); });
ReactDOM.render( const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<ErrorBoundary> <ErrorBoundary>
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Router> <App />
<App />
</Router>
</ThemeProvider> </ThemeProvider>
</ErrorBoundary>, </ErrorBoundary>
document.getElementById('root')
); );

23
src/utils/tokenService.js Normal file
View File

@ -0,0 +1,23 @@
const TOKEN_KEY = 'authToken';
export const setToken = (token) => {
localStorage.setItem(TOKEN_KEY, token);
};
export const getToken = () => {
return localStorage.getItem(TOKEN_KEY);
};
export const removeToken = () => {
localStorage.removeItem(TOKEN_KEY);
};
export const isTokenAvailable = () => {
return !!localStorage.getItem(TOKEN_KEY); // Returns true if token exists
};