react
This commit is contained in:
parent
509d01a4e7
commit
703f1256ff
7619
package-lock.json
generated
7619
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -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",
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// postcss.config.js
|
// postcss.config.js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,3 +46,4 @@
|
|||||||
/* .login-container input[type="checkbox"] {
|
/* .login-container input[type="checkbox"] {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
|||||||
48
src/App.js
48
src/App.js
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
@ -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;
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
src/index.js
15
src/index.js
@ -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
23
src/utils/tokenService.js
Normal 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
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user